using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using ReviveAllies.Components; using ReviveAllies.Components.States; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("assembly_guiutils")] [assembly: IgnoresAccessChecksTo("assembly_utils")] [assembly: IgnoresAccessChecksTo("assembly_valheim")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("ReviveAllies")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.3.4.0")] [assembly: AssemblyInformationalVersion("0.3.4+e5f9cf9ebafdce444fe892cec020973613a84e61")] [assembly: AssemblyProduct("ReviveAllies")] [assembly: AssemblyTitle("ReviveAllies")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.3.4.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ReviveAllies { public enum ReviveModeType { Hold, Press } [BepInPlugin("com.andres.reviveallies", "ReviveAllies", "0.3.4")] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "com.andres.reviveallies"; public const string PluginName = "ReviveAllies"; public const string PluginVersion = "0.3.4"; internal static ConfigEntry ReviveModeCfg; internal static ConfigEntry ReviveHoldTimeCfg; internal static ConfigEntry ReviveWindowCfg; internal const string RpcConfig = "ReviveAllies_Config"; private static bool s_hasServerConfig; private static float s_srvWindow; private static float s_srvHoldTime; private static bool s_srvPressMode; public const float ReviveHealthFraction = 0.25f; private Harmony? _harmony; internal static ManualLogSource Logger { get; private set; } private static bool UseServerConfig { get { if (s_hasServerConfig && (Object)(object)ZNet.instance != (Object)null) { return !ZNet.instance.IsServer(); } return false; } } public static float ReviveWindow { get { if (!UseServerConfig) { return ReviveWindowCfg?.Value ?? 30f; } return s_srvWindow; } } public static float ReviveDuration => Mathf.Max(0.1f, UseServerConfig ? s_srvHoldTime : (ReviveHoldTimeCfg?.Value ?? 4f)); public static bool RevivePressMode { get { if (!UseServerConfig) { if (ReviveModeCfg != null) { return ReviveModeCfg.Value == ReviveModeType.Press; } return false; } return s_srvPressMode; } } internal static void ApplyServerConfig(float window, float holdTime, bool pressMode) { s_srvWindow = window; s_srvHoldTime = holdTime; s_srvPressMode = pressMode; s_hasServerConfig = true; Logger.LogInfo((object)$"Adopted server revive config: window={window:F0}s hold={holdTime:F1}s press={pressMode}"); } internal static void ResetServerConfig() { s_hasServerConfig = false; } internal static void BroadcastConfig() { if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer() && ZRoutedRpc.instance != null) { ZRoutedRpc instance = ZRoutedRpc.instance; long everybody = ZRoutedRpc.Everybody; object[] obj = new object[3] { ReviveWindowCfg?.Value ?? 30f, Mathf.Max(0.1f, ReviveHoldTimeCfg?.Value ?? 4f), null }; ConfigEntry reviveModeCfg = ReviveModeCfg; obj[2] = ((reviveModeCfg != null && reviveModeCfg.Value == ReviveModeType.Press) ? 1 : 0); instance.InvokeRoutedRPC(everybody, "ReviveAllies_Config", obj); } } private void Awake() { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Expected O, but got Unknown //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Expected O, but got Unknown Logger = ((BaseUnityPlugin)this).Logger; Logger.LogInfo((object)"ReviveAllies v0.3.4 loaded!"); ReviveModeCfg = ((BaseUnityPlugin)this).Config.Bind("Revive", "Mode", ReviveModeType.Hold, "Hold: the interact key must be held for HoldTimeSeconds to revive. Press: a single press revives instantly."); ReviveHoldTimeCfg = ((BaseUnityPlugin)this).Config.Bind("Revive", "HoldTimeSeconds", 4f, new ConfigDescription("How long the interact key must be held to complete a revive (Hold mode).", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 60f), Array.Empty())); ReviveWindowCfg = ((BaseUnityPlugin)this).Config.Bind("Revive", "WindowSeconds", 30f, new ConfigDescription("How long a downed player can be revived before dying for real. Server-authoritative: the host's value governs everyone.", (AcceptableValueBase)(object)new AcceptableValueRange(5f, 600f), Array.Empty())); ReviveModeCfg.SettingChanged += delegate { BroadcastConfig(); }; ReviveHoldTimeCfg.SettingChanged += delegate { BroadcastConfig(); }; ReviveWindowCfg.SettingChanged += delegate { BroadcastConfig(); }; _harmony = Harmony.CreateAndPatchAll(typeof(Plugin).Assembly, "com.andres.reviveallies"); } private void OnDestroy() { Harmony? harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } } namespace ReviveAllies.Patches { [HarmonyPatch(typeof(Character), "CheckDeath")] internal static class CheckDeathPatch { private static bool Prefix(Character __instance) { //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Expected O, but got Unknown Player val = (Player)(object)((__instance is Player) ? __instance : null); if (val == null) { return true; } if (!((Character)val).m_nview.IsOwner()) { return true; } if (((Character)val).IsDead()) { return true; } if (((Character)val).GetHealth() > 0f) { return true; } if ((Object)(object)((Component)val).GetComponent() == (Object)null) { return true; } if (!val.IsDowned()) { val.EnterDownedState(); return false; } if (!((Component)val).GetComponent().IsChanneling && val.IsReviveWindowExpired()) { if (((Character)val).m_lastHit == null) { ((Character)val).m_lastHit = new HitData { m_hitType = (HitType)14 }; } val.ExpireDownedState(); return true; } return false; } } [HarmonyPatch(typeof(ZNet), "Awake")] internal static class ZNetAwakeConfigSyncPatch { private static void Postfix() { Plugin.ResetServerConfig(); ZRoutedRpc instance = ZRoutedRpc.instance; if (instance == null) { return; } instance.Register("ReviveAllies_Config", (Action)delegate(long sender, float window, float holdTime, int mode) { if (!((Object)(object)ZNet.instance != (Object)null) || !ZNet.instance.IsServer()) { Plugin.ApplyServerConfig(window, holdTime, mode != 0); } }); } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] internal static class ZNetPeerInfoConfigSyncPatch { private static void Postfix(ZNet __instance) { if (__instance.IsServer()) { Plugin.BroadcastConfig(); } } } [HarmonyPatch(typeof(BaseAI), "IsEnemy", new Type[] { typeof(Character), typeof(Character) })] internal static class BaseAIIgnoreDownedPatch { private static void Postfix(Character a, Character b, ref bool __result) { if (__result && (IsDownedPlayer(a) || IsDownedPlayer(b))) { __result = false; } } private static bool IsDownedPlayer(Character c) { return ((Player?)(object)((c is Player) ? c : null))?.IsDowned() ?? false; } } [HarmonyPatch(typeof(Player), "Awake")] internal static class PlayerAwakePatch { private static void Postfix(Player __instance) { if ((Object)(object)((Component)__instance).GetComponent() == (Object)null) { ((Component)__instance).gameObject.AddComponent(); } if ((Object)(object)((Component)__instance).GetComponent() == (Object)null) { ((Component)__instance).gameObject.AddComponent(); } if ((Object)(object)((Component)__instance).GetComponent() == (Object)null) { ((Component)__instance).gameObject.AddComponent(); } if ((Object)(object)((Component)__instance).GetComponent() == (Object)null) { ((Component)__instance).gameObject.AddComponent(); } if ((Object)(object)((Component)__instance).GetComponent() == (Object)null) { ((Component)__instance).gameObject.AddComponent(); } if ((Object)(object)((Component)__instance).GetComponent() == (Object)null) { ((Component)__instance).gameObject.AddComponent(); } if ((Object)(object)((Component)__instance).GetComponent() == (Object)null) { ((Component)__instance).gameObject.AddComponent(); } } } [HarmonyPatch(typeof(Player), "CanMove")] internal static class PlayerCanMovePatch { private static void Postfix(Player __instance, ref bool __result) { if (__result && __instance.IsDowned()) { __result = false; } } } [HarmonyPatch(typeof(Character), "UpdateMotion")] internal static class CharacterUpdateMotionPatch { private static bool Prefix(Character __instance) { Player val = (Player)(object)((__instance is Player) ? __instance : null); if (val != null && val.IsDowned()) { return false; } return true; } } [HarmonyPatch(typeof(Player), "LateUpdate")] internal static class PlayerLateUpdatePatch { private static void Postfix(Player __instance) { if (((Character)__instance).IsDead()) { if ((Object)(object)((Character)__instance).m_collider != (Object)null && ((Collider)((Character)__instance).m_collider).enabled) { ((Collider)((Character)__instance).m_collider).enabled = false; } if ((Object)(object)((Character)__instance).m_nview != (Object)null && ((Character)__instance).m_nview.IsValid() && ((Character)__instance).m_nview.IsOwner() && (Object)(object)((Character)__instance).m_body != (Object)null && !((Character)__instance).m_body.isKinematic) { ((Character)__instance).m_body.isKinematic = true; } } } } [HarmonyPatch(typeof(Player), "UpdateHover")] internal static class PlayerUpdateHoverPatch { private static bool Prefix(Player __instance) { if (__instance.IsDowned()) { return false; } return true; } } [HarmonyPatch(typeof(Player), "OnRespawn")] internal static class PlayerOnRespawnPatch { private static bool Prefix(Player __instance) { if (__instance.IsDowned()) { return false; } return true; } } [HarmonyPatch(typeof(EnemyHud), "TestShow")] internal static class EnemyHudHideDownedPatch { private static void Postfix(Character c, ref bool __result) { if (__result) { Player val = (Player)(object)((c is Player) ? c : null); if (val != null && (val.IsDowned() || ((Character)val).IsDead())) { __result = false; } } } } [HarmonyPatch(typeof(ZNetScene), "Awake")] internal static class ZNetSceneAwakeRegisterPrefabsPatch { private static void Postfix(ZNetScene __instance) { MarkerPrefab.RegisterPrefab(__instance); } } [HarmonyPatch(typeof(TombStone), "Setup")] internal static class TombStoneSetupReplacePatch { private static void Postfix(TombStone __instance, long ownerUID) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)((Character)localPlayer).m_nview == (Object)null || !((Character)localPlayer).m_nview.IsValid() || ownerUID != localPlayer.GetPlayerID()) { return; } GraveReplaceView graveReplaceView = localPlayer.GraveReplace(); if (graveReplaceView.Pending) { graveReplaceView.Pending = false; Vector3 val = graveReplaceView.Pos; if (val == Vector3.zero) { val = ((Component)__instance).transform.position; } ((Component)__instance).transform.position = val; Rigidbody component = ((Component)__instance).GetComponent(); if ((Object)(object)component != (Object)null) { component.position = val; component.linearVelocity = Vector3.zero; } DownedMarker.MarkReplaced(localPlayer.FindDownedMarker() ?? MarkerPrefab.FindFor(localPlayer.GetPlayerID())); DownedStateMachineView downedStateMachineView = localPlayer.State(); downedStateMachineView.Marker = ZDOID.None; } } } [HarmonyPatch(typeof(Player), "OnDeath")] internal static class PlayerOnDeathMarkerCrumblePatch { private static void Postfix(Player __instance) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) ZNetView nview = ((Character)__instance).m_nview; if (!((Object)(object)nview == (Object)null) && nview.IsValid() && nview.IsOwner()) { GraveReplaceView graveReplaceView = __instance.GraveReplace(); if (graveReplaceView.Pending) { graveReplaceView.Pending = false; GameObject? marker = __instance.FindDownedMarker() ?? MarkerPrefab.FindFor(__instance.GetPlayerID()); DownedStateMachineView downedStateMachineView = __instance.State(); downedStateMachineView.Marker = ZDOID.None; DownedMarker.Crumble(marker); Plugin.Logger.LogInfo((object)(__instance.GetPlayerName() + " died with no grave to drop; marker crumbled")); } } } } [HarmonyPatch(typeof(Player), "CreateDeathEffects")] internal static class SuppressPlayerRagdollPatch { private static bool Prefix() { return false; } } } namespace ReviveAllies.Components { public static class DownedKeys { public const string RpcChannel = "RevivalRevived_Channel"; } public class DownedMarker : MonoBehaviour { private struct TintedMaterial { public Material Mat; public bool HasEmission; public Color OrigEmission; public float EmissionIntensity; public bool HasColor; public Color OrigColor; } public static readonly Color ReviveGreen = new Color(0.25f, 1f, 0.35f); private static EffectList? s_crumbleEffect; private static readonly int EmissionColorId = Shader.PropertyToID("_EmissionColor"); private static readonly int ColorId = Shader.PropertyToID("_Color"); private readonly List m_tinted = new List(); private readonly List<(Light light, Color orig)> m_lights = new List<(Light, Color)>(); private ZNetView? m_nview; private float m_replacedSince = -1f; private bool m_hiddenForReplace; private const float ReplaceHideTimeout = 4f; private const float ReplaceDestroyDelay = 5f; private const float ReplaceDestroyFailsafe = 10f; public static int LastCrumbleEffectCount { get; private set; } public static int CrumbleEvents { get; private set; } public int TintedLights => m_lights.Count; public int TintedMaterials => m_tinted.Count; public float CurrentBlend { get; private set; } public bool HiddenForReplace => m_hiddenForReplace; public static void MarkReplaced(GameObject? marker) { ZNetView val = Owned(marker); if (!((Object)(object)val == (Object)null)) { DownedMarkerView downedMarkerView = new DownedMarkerView(val); downedMarkerView.ReplacedByGrave = true; } } public static void Crumble(GameObject? marker) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)marker == (Object)null)) { EffectList val = GraveCrumbleEffect(); if (val != null) { GameObject[] array = val.Create(marker.transform.position, marker.transform.rotation, (Transform)null, 1f, -1); LastCrumbleEffectCount = ((array != null) ? array.Length : 0); CrumbleEvents++; } DestroyMarker(marker); } } public static void CrumbleLinked(ZNetView playerNview) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) ZDOID marker = new DownedStateMachineView(playerNview).Marker; if (!(marker == ZDOID.None)) { DownedStateMachineView downedStateMachineView = new DownedStateMachineView(playerNview); downedStateMachineView.Marker = ZDOID.None; Crumble(ZNetScene.instance.FindInstance(marker)); } } public static void DestroyMarker(GameObject? marker) { ZNetView? obj = Owned(marker); if (obj != null) { obj.Destroy(); } } private static ZNetView? Owned(GameObject? marker) { ZNetView val = (((Object)(object)marker != (Object)null) ? marker.GetComponent() : null); if ((Object)(object)val == (Object)null || !val.IsValid()) { return null; } if (!val.IsOwner()) { val.ClaimOwnership(); } return val; } private static EffectList? GraveCrumbleEffect() { if (s_crumbleEffect != null) { return s_crumbleEffect; } GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? MarkerPrefab.FindTombstonePrefab(ZNetScene.instance) : null); TombStone val2 = (((Object)(object)val != (Object)null) ? val.GetComponent() : null); if ((Object)(object)val2 != (Object)null && val2.m_removeEffect != null && val2.m_removeEffect.m_effectPrefabs.Length != 0) { s_crumbleEffect = val2.m_removeEffect; } else { Plugin.Logger.LogWarning((object)"DownedMarker: no grave crumble effect found"); } return s_crumbleEffect; } private void Awake() { m_nview = ((Component)this).GetComponent(); CaptureAccents(); ApplyBlend(0f); } private void Start() { if ((Object)(object)m_nview == (Object)null || !m_nview.IsValid()) { return; } string ownerName = new DownedMarkerView(m_nview).OwnerName; if (!string.IsNullOrEmpty(ownerName)) { TMP_Text componentInChildren = ((Component)this).GetComponentInChildren(true); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.text = ownerName; } } } private void Update() { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)m_nview == (Object)null) && m_nview.IsValid()) { DownedMarkerView downedMarkerView = new DownedMarkerView(m_nview); if (downedMarkerView.ReplacedByGrave) { UpdateReplaced(); return; } ZDOID linkedPlayer = downedMarkerView.LinkedPlayer; ZDO val = ((linkedPlayer != ZDOID.None) ? ZDOMan.instance.GetZDO(linkedPlayer) : null); float num = ((val != null) ? new DownedStateMachineView(val).DownedTime : downedMarkerView.DownedTime); float num2 = (float)ZNet.instance.GetTimeSeconds() - num; ApplyBlend(Mathf.Clamp01(num2 / Plugin.ReviveWindow)); } } private void CaptureAccents() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) Light[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); foreach (Light val in componentsInChildren) { m_lights.Add((val, val.color)); } Renderer[] componentsInChildren2 = ((Component)this).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren2.Length; i++) { Material[] materials = componentsInChildren2[i].materials; foreach (Material val2 in materials) { TintedMaterial item = new TintedMaterial { Mat = val2 }; if (val2.HasProperty(EmissionColorId)) { Color color = val2.GetColor(EmissionColorId); if (((Color)(ref color)).maxColorComponent > 0.05f) { item.HasEmission = true; item.OrigEmission = color; item.EmissionIntensity = ((Color)(ref color)).maxColorComponent; } } if (val2.HasProperty(ColorId)) { Color color2 = val2.GetColor(ColorId); if (color2.r > 0.4f && color2.r > color2.g * 1.5f && color2.r > color2.b * 1.5f) { item.HasColor = true; item.OrigColor = color2; } } if (item.HasEmission || item.HasColor) { m_tinted.Add(item); } } } } private void ApplyBlend(float blend) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) CurrentBlend = blend; foreach (TintedMaterial item in m_tinted) { if (!((Object)(object)item.Mat == (Object)null)) { if (item.HasEmission) { Color val = ReviveGreen * item.EmissionIntensity; item.Mat.SetColor(EmissionColorId, Color.Lerp(val, item.OrigEmission, blend)); item.Mat.EnableKeyword("_EMISSION"); } if (item.HasColor) { item.Mat.SetColor(ColorId, Color.Lerp(ReviveGreen, item.OrigColor, blend)); } } } foreach (var (val2, val3) in m_lights) { if ((Object)(object)val2 != (Object)null) { val2.color = Color.Lerp(ReviveGreen, val3, blend); } } } public bool IsGreen() { if (TintedLights > 0 || TintedMaterials > 0) { return CurrentBlend < 0.5f; } return false; } private void UpdateReplaced() { if (m_replacedSince < 0f) { m_replacedSince = Time.time; } float num = Time.time - m_replacedSince; if (!m_hiddenForReplace && (num > 4f || GraveNearby())) { HideLocally(); } if (m_nview.IsOwner()) { if (num > 5f) { m_nview.Destroy(); } } else if (num > 10f) { m_nview.ClaimOwnership(); m_nview.Destroy(); } } private bool GraveNearby() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) TombStone[] array = Object.FindObjectsOfType(); for (int i = 0; i < array.Length; i++) { Vector3 val = ((Component)array[i]).transform.position - ((Component)this).transform.position; if (((Vector3)(ref val)).sqrMagnitude < 9f) { return true; } } return false; } private void HideLocally() { m_hiddenForReplace = true; Renderer[] componentsInChildren = ((Component)this).GetComponentsInChildren(); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].enabled = false; } Collider[] componentsInChildren2 = ((Component)this).GetComponentsInChildren(); for (int i = 0; i < componentsInChildren2.Length; i++) { componentsInChildren2[i].enabled = false; } Light[] componentsInChildren3 = ((Component)this).GetComponentsInChildren(); for (int i = 0; i < componentsInChildren3.Length; i++) { ((Behaviour)componentsInChildren3[i]).enabled = false; } } } public struct DownedMarkerView { private static readonly int kIsMarker = StringExtensionMethods.GetStableHashCode("RevivalRevived_isDownedMarker"); private static readonly int kOwnerPlayerId = StringExtensionMethods.GetStableHashCode("RevivalRevived_ownerPlayerID"); private static readonly int kReplacedByGrave = StringExtensionMethods.GetStableHashCode("RevivalRevived_replacedByGrave"); private static readonly int kDownedTime = StringExtensionMethods.GetStableHashCode("RevivalRevived_downedTime"); private static readonly int kOwnerName = ZDOVars.s_ownerName; private static readonly KeyValuePair kPlayer = ZDO.GetHashZDOID("RevivalRevived_playerZDOID"); private readonly ZDO _z; public bool IsMarker { get { return _z.GetBool(kIsMarker, false); } set { _z.Set(kIsMarker, value); } } public string OwnerName { get { return _z.GetString(kOwnerName, ""); } set { _z.Set(kOwnerName, value); } } public long OwnerPlayerId { get { return _z.GetLong(kOwnerPlayerId, 0L); } set { _z.Set(kOwnerPlayerId, value); } } public ZDOID LinkedPlayer { get { //IL_000b: Unknown result type (might be due to invalid IL or missing references) return _z.GetZDOID(kPlayer); } set { //IL_000b: Unknown result type (might be due to invalid IL or missing references) _z.Set(kPlayer, value); } } public float DownedTime { get { return _z.GetFloat(kDownedTime, 0f); } set { _z.Set(kDownedTime, value); } } public bool ReplacedByGrave { get { return _z.GetBool(kReplacedByGrave, false); } set { _z.Set(kReplacedByGrave, value); } } public DownedMarkerView(ZNetView nview) : this(nview.GetZDO()) { } public DownedMarkerView(ZDO zdo) { _z = zdo; } } public class ChannelSignal : MonoBehaviour { private ZNetView m_nview; private bool m_channeling; private long m_channeler; private ZDOID m_channelerZdo = ZDOID.None; public bool IsChanneling { get { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) if (m_channeling && m_channelerZdo != ZDOID.None && ZDOMan.instance != null) { return ZDOMan.instance.GetZDO(m_channelerZdo) != null; } return false; } } public long LastChanneler => m_channeler; private void Awake() { m_nview = ((Component)this).GetComponent(); m_nview.Register("RevivalRevived_Channel", (Action)delegate(long sender, bool channeling, ZDOID channelerZdo) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) if (m_nview.IsOwner() && (channeling || !(channelerZdo != m_channelerZdo))) { m_channeler = sender; m_channelerZdo = channelerZdo; m_channeling = channeling; } }); } } public class DownedStateMachine : StateMachine { private ZNetView m_nview; protected override void Awake() { m_nview = ((Component)this).GetComponent(); base.Awake(); } protected override IState CreateInitialState() { return new AliveState(((Component)this).GetComponent()); } private void Update() { if (m_nview.IsValid() && m_nview.IsOwner()) { Tick(); } } } public struct DownedStateMachineView { private static readonly int kDowned = StringExtensionMethods.GetStableHashCode("RevivalRevived_downed"); private static readonly int kDownedTime = StringExtensionMethods.GetStableHashCode("RevivalRevived_downedTime"); private static readonly KeyValuePair kMarker = ZDO.GetHashZDOID("RevivalRevived_markerZDOID"); private readonly ZDO _z; public bool Downed { get { return _z.GetBool(kDowned, false); } set { _z.Set(kDowned, value); } } public float DownedTime { get { return _z.GetFloat(kDownedTime, 0f); } set { _z.Set(kDownedTime, value); } } public ZDOID Marker { get { //IL_000b: Unknown result type (might be due to invalid IL or missing references) return _z.GetZDOID(kMarker); } set { //IL_000b: Unknown result type (might be due to invalid IL or missing references) _z.Set(kMarker, value); } } public DownedStateMachineView(ZNetView nview) : this(nview.GetZDO()) { } public DownedStateMachineView(ZDO zdo) { _z = zdo; } } public class GiveUp : MonoBehaviour { public const float Duration = 2f; private Player m_player; private readonly GiveUpDecayingProgress m_timer = new GiveUpDecayingProgress(); private ProgressUI? m_ui; private bool m_simulate; public static float LocalFraction { get; private set; } private void Awake() { m_player = ((Component)this).GetComponent(); } private void OnDestroy() { m_ui?.Close(); if ((Object)(object)m_player == (Object)(object)Player.m_localPlayer) { LocalFraction = 0f; } } public bool Held() { if (m_simulate) { m_simulate = false; return true; } if ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus()) { return false; } if (Console.IsVisible() || Menu.IsVisible() || InventoryGui.IsVisible() || TextInput.IsVisible()) { return false; } if (!ZInput.GetButton("Use")) { return ZInput.GetButton("JoyUse"); } return true; } public void SimulateHold() { m_simulate = true; } public void ShowUI() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)m_ui == (Object)null) { m_ui = ProgressUI.Create(m_timer, ProgressUI.GiveUpRed, isGiveUp: true); } } public bool Channel(float dt) { m_timer.Channel(dt); Mirror(); return m_timer.Full; } public void Decay(float dt) { m_timer.Decay(dt); Mirror(); } public void Reset() { m_timer.Reset(); Mirror(); } private void Mirror() { if ((Object)(object)m_player == (Object)(object)Player.m_localPlayer) { LocalFraction = m_timer.Fraction; } } } public struct GraveReplaceView { private static readonly int kPending = StringExtensionMethods.GetStableHashCode("RevivalRevived_graveReplacePending"); private static readonly int kPos = StringExtensionMethods.GetStableHashCode("RevivalRevived_graveReplacePos"); private readonly ZDO _z; public bool Pending { get { return _z.GetBool(kPending, false); } set { _z.Set(kPending, value); } } public Vector3 Pos { get { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) return _z.GetVec3(kPos, Vector3.zero); } set { //IL_000b: Unknown result type (might be due to invalid IL or missing references) _z.Set(kPos, value); } } public GraveReplaceView(ZNetView nview) : this(nview.GetZDO()) { } public GraveReplaceView(ZDO zdo) { _z = zdo; } } public class ReconnectDeathCheck : MonoBehaviour { private Player m_player; private ZNetView m_nview; private void Awake() { m_player = ((Component)this).GetComponent(); m_nview = ((Component)this).GetComponent(); } private void Start() { if (m_nview.IsValid() && m_nview.IsOwner()) { ((MonoBehaviour)this).StartCoroutine(Check()); } } public void RunReconnectCheck() { ((MonoBehaviour)this).StartCoroutine(Check()); } private IEnumerator Check() { long pid = m_player.GetPlayerID(); float t = 0f; while (t < 12f && !((Object)(object)m_player == (Object)null) && m_nview.IsValid() && !m_player.IsDowned()) { if ((Object)(object)MarkerPrefab.FindFor(pid) != (Object)null) { Plugin.Logger.LogInfo((object)(m_player.GetPlayerName() + " reconnected with an orphaned downed marker -> dying")); Kill(); break; } t += 0.5f; yield return (object)new WaitForSecondsRealtime(0.5f); } } private void Kill() { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Expected O, but got Unknown if (m_nview.IsValid() && m_nview.IsOwner()) { DownedStateMachineView downedStateMachineView = m_player.State(); downedStateMachineView.Downed = false; GameObject val = MarkerPrefab.FindFor(m_player.GetPlayerID()); GameObject val2 = m_player.FindDownedMarker(); Vector3? val3 = (((Object)(object)val != (Object)null) ? new Vector3?(val.transform.position) : (((Object)(object)val2 != (Object)null) ? new Vector3?(val2.transform.position) : ((Vector3?)null))); if (val3.HasValue) { GraveReplaceView graveReplaceView = m_player.GraveReplace(); graveReplaceView.Pending = true; graveReplaceView.Pos = val3.Value; } if (((Character)m_player).m_lastHit == null) { ((Character)m_player).m_lastHit = new HitData { m_hitType = (HitType)14 }; } ((Character)m_player).SetHealth(0f); Traverse.Create((object)m_player).Method("OnDeath", Array.Empty()).GetValue(); Plugin.Logger.LogInfo((object)(m_player.GetPlayerName() + " died from being downed at disconnect")); } } } public class DownedView : MonoBehaviour { private Player m_player; private ZNetView m_nview; private bool m_wasDowned; private void Awake() { m_player = ((Component)this).GetComponent(); m_nview = ((Component)this).GetComponent(); } private void Start() { m_wasDowned = m_player.IsDowned(); } private void Update() { if (!m_nview.IsValid()) { return; } bool flag = m_player.IsDowned(); if (flag) { if (!m_wasDowned) { m_player.PlayDownedPoof(); } if ((Object)(object)((Character)m_player).m_visual != (Object)null && ((Character)m_player).m_visual.activeSelf) { ((Character)m_player).m_visual.SetActive(false); } if ((Object)(object)((Character)m_player).m_collider != (Object)null && ((Collider)((Character)m_player).m_collider).enabled) { ((Collider)((Character)m_player).m_collider).enabled = false; } if (m_nview.IsOwner() && (Object)(object)((Character)m_player).m_body != (Object)null) { ((Character)m_player).m_body.isKinematic = true; } } else if (m_wasDowned) { Restore(); } m_wasDowned = flag; } private void Restore() { if (!((Character)m_player).IsDead()) { if ((Object)(object)((Character)m_player).m_visual != (Object)null) { ((Character)m_player).m_visual.SetActive(true); } if ((Object)(object)((Character)m_player).m_collider != (Object)null) { ((Collider)((Character)m_player).m_collider).enabled = true; } if (m_nview.IsOwner() && (Object)(object)((Character)m_player).m_body != (Object)null) { ((Character)m_player).m_body.isKinematic = false; } } } } public class GiveUpDecayingProgress : IDecayingProgress { private const float DecayRate = 2f; private float m_seconds; private bool m_active; public float Fraction => Mathf.Clamp01(m_seconds / 2f); public bool Full => m_seconds >= 2f; public event Action? Finished; public void Channel(float dt) { m_seconds += dt; if (m_seconds > 0.01f) { m_active = true; } } public void Decay(float dt) { if (!(m_seconds <= 0f)) { m_seconds = Mathf.Max(0f, m_seconds - dt * 2f); if (m_seconds <= 0f) { Empty(); } } } public void Reset() { m_seconds = 0f; m_active = false; this.Finished?.Invoke(); } private void Empty() { if (m_active) { m_active = false; this.Finished?.Invoke(); } } } public interface IDecayingProgress { float Fraction { get; } event Action Finished; } public static class MarkerPrefab { public const string PrefabName = "RevivalRevived_DownedMarker"; private static GameObject? s_prefabHolder; private static GameObject? s_prefabTemplate; public static int TemplateEffectsRemoved { get; private set; } public static float LastPopVelY { get; private set; } public static void RegisterPrefab(ZNetScene scene) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown if ((Object)(object)s_prefabTemplate == (Object)null) { GameObject val = FindTombstonePrefab(scene); if ((Object)(object)val == (Object)null) { Plugin.Logger.LogError((object)"MarkerPrefab: no TombStone prefab found to derive the marker from"); return; } s_prefabHolder = new GameObject("RevivalRevived_Prefabs"); s_prefabHolder.SetActive(false); Object.DontDestroyOnLoad((Object)(object)s_prefabHolder); GameObject obj = Object.Instantiate(val, s_prefabHolder.transform); ((Object)obj).name = "RevivalRevived_DownedMarker"; TombStone component = obj.GetComponent(); if ((Object)(object)component != (Object)null) { Object.DestroyImmediate((Object)(object)component); } Container component2 = obj.GetComponent(); if ((Object)(object)component2 != (Object)null) { Object.DestroyImmediate((Object)(object)component2); } RemoveGraveEffects(obj); obj.AddComponent(); obj.AddComponent(); obj.AddComponent(); s_prefabTemplate = obj; Plugin.Logger.LogInfo((object)("MarkerPrefab: built prefab 'RevivalRevived_DownedMarker' from '" + ((Object)val).name + "'")); } int stableHashCode = StringExtensionMethods.GetStableHashCode("RevivalRevived_DownedMarker"); if (!scene.m_namedPrefabs.ContainsKey(stableHashCode)) { scene.m_prefabs.Add(s_prefabTemplate); scene.m_namedPrefabs.Add(stableHashCode, s_prefabTemplate); Plugin.Logger.LogInfo((object)"MarkerPrefab: registered prefab 'RevivalRevived_DownedMarker' with ZNetScene"); } } internal static GameObject? FindTombstonePrefab(ZNetScene scene) { GameObject prefab = scene.GetPrefab("Player_tombstone"); if ((Object)(object)prefab != (Object)null && (Object)(object)prefab.GetComponent() != (Object)null) { return prefab; } foreach (GameObject prefab2 in scene.m_prefabs) { if ((Object)(object)prefab2 != (Object)null && (Object)(object)prefab2.GetComponent() != (Object)null) { return prefab2; } } return null; } private static void RemoveGraveEffects(GameObject template) { ParticleSystem[] componentsInChildren = template.GetComponentsInChildren(true); foreach (ParticleSystem val in componentsInChildren) { if ((Object)(object)val != (Object)null && (Object)(object)((Component)val).gameObject != (Object)(object)template) { Object.DestroyImmediate((Object)(object)((Component)val).gameObject); TemplateEffectsRemoved++; } } Transform[] componentsInChildren2 = template.GetComponentsInChildren(true); foreach (Transform val2 in componentsInChildren2) { if (!((Object)(object)val2 == (Object)null) && !((Object)(object)((Component)val2).gameObject == (Object)(object)template)) { string text = ((Object)val2).name.ToLowerInvariant(); if (text.Contains("flare") || text.Contains("glow")) { Object.DestroyImmediate((Object)(object)((Component)val2).gameObject); TemplateEffectsRemoved++; } } } } public static void Spawn(Player player) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab("RevivalRevived_DownedMarker") : null); if ((Object)(object)val == (Object)null) { Plugin.Logger.LogError((object)"MarkerPrefab.Spawn: prefab 'RevivalRevived_DownedMarker' is not registered"); return; } GameObject val2 = Object.Instantiate(val, ((Character)player).GetCenterPoint(), ((Component)player).transform.rotation); ZNetView component = val2.GetComponent(); if ((Object)(object)component == (Object)null || !component.IsValid()) { Plugin.Logger.LogError((object)"MarkerPrefab.Spawn: marker has no valid ZNetView"); return; } DownedMarkerView downedMarkerView = new DownedMarkerView(component); downedMarkerView.IsMarker = true; downedMarkerView.LinkedPlayer = ((Character)player).m_nview.GetZDO().m_uid; downedMarkerView.OwnerPlayerId = player.GetPlayerID(); downedMarkerView.OwnerName = player.GetPlayerName(); downedMarkerView.DownedTime = (float)ZNet.instance.GetTimeSeconds(); DownedStateMachineView downedStateMachineView = new DownedStateMachineView(((Character)player).m_nview); downedStateMachineView.Marker = component.GetZDO().m_uid; Rigidbody component2 = val2.GetComponent(); if ((Object)(object)component2 != (Object)null) { component2.linearVelocity = new Vector3(0f, 5f, 0f); } LastPopVelY = (((Object)(object)component2 != (Object)null) ? component2.linearVelocity.y : 0f); Plugin.Logger.LogInfo((object)$"Spawned downed marker for {player.GetPlayerName()}, ZDOID {component.GetZDO().m_uid}"); } public static GameObject? FindFor(long playerId) { if (playerId == 0L) { return null; } DownedMarker[] array = Object.FindObjectsOfType(); foreach (DownedMarker downedMarker in array) { ZNetView component = ((Component)downedMarker).GetComponent(); if (!((Object)(object)component == (Object)null) && component.IsValid()) { DownedMarkerView downedMarkerView = new DownedMarkerView(component); if (!downedMarkerView.ReplacedByGrave && downedMarkerView.OwnerPlayerId == playerId) { return ((Component)downedMarker).gameObject; } } } return null; } } public static class PlayerDownedExtensions { private static EffectList? s_cachedRemoveEffect; private static bool s_removeEffectSearched; public static int LastPoofCount { get; private set; } public static string LastPoofSourceName { get; private set; } = ""; public static DownedStateMachineView State(this Player player) { return new DownedStateMachineView(((Character)player).m_nview); } public static GraveReplaceView GraveReplace(this Player player) { return new GraveReplaceView(((Character)player).m_nview); } public static bool TryState(this Player? player, out DownedStateMachineView state) { ZNetView val = ((Character)(player?)).m_nview; if ((Object)(object)val == (Object)null || !val.IsValid()) { state = default(DownedStateMachineView); return false; } state = new DownedStateMachineView(val); return true; } public static bool IsDowned(this Player? player) { if (player.TryState(out var state)) { return state.Downed; } return false; } public static bool IsReviveWindowExpired(this Player player) { return player.NonChanneledDownedElapsed() > Plugin.ReviveWindow; } public static float GetDownedRemainingTime(this Player? player) { if (!player.TryState(out var _)) { return 0f; } return Mathf.Max(0f, Plugin.ReviveWindow - player.NonChanneledDownedElapsed()); } private static float NonChanneledDownedElapsed(this Player? player) { if (!player.TryState(out var state)) { return 0f; } float num = (float)ZNet.instance.GetTimeSeconds() - state.DownedTime; return Mathf.Max(0f, num - player.OpenChannelSeconds()); } private static float OpenChannelSeconds(this Player? player) { GameObject val = player.FindDownedMarker(); ZNetView val2 = (((Object)(object)val != (Object)null) ? val.GetComponent() : null); if ((Object)(object)val2 == (Object)null || !val2.IsValid()) { return 0f; } ReviveChannelDecayingProgressView reviveChannelDecayingProgressView = new ReviveChannelDecayingProgressView(val2); if (!reviveChannelDecayingProgressView.Channeling) { return 0f; } return Mathf.Max(0f, (float)ZNet.instance.GetTimeSeconds() - reviveChannelDecayingProgressView.AnchorTime); } public static float GetReviveProgress(this Player? player) { GameObject val = player.FindDownedMarker(); ReviveChannelDecayingProgress reviveChannelDecayingProgress = (((Object)(object)val != (Object)null) ? val.GetComponent() : null); if (!((Object)(object)reviveChannelDecayingProgress != (Object)null)) { return 0f; } return reviveChannelDecayingProgress.Fraction; } public static GameObject? FindDownedMarker(this Player? player) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) if (!player.TryState(out var state) || state.Marker == ZDOID.None) { return null; } return ZNetScene.instance.FindInstance(state.Marker); } public static void EnterDownedState(this Player player) { GraveReplaceView graveReplaceView = player.GraveReplace(); graveReplaceView.Pending = false; DownedStateMachineView downedStateMachineView = player.State(); downedStateMachineView.Downed = true; downedStateMachineView.DownedTime = (float)ZNet.instance.GetTimeSeconds(); MarkerPrefab.Spawn(player); ((Character)player).Message((MessageType)2, Localization.instance.Localize("You are downed!\nHold [$KEY_Use] to give up"), 0, (Sprite)null); Plugin.Logger.LogInfo((object)(player.GetPlayerName() + " entered downed state (owner)")); } public static void ReviveFromDowned(this Player player, long reviverId = 0L) { if (!((Object)(object)player == (Object)null) && ((Character)player).m_nview.IsValid()) { if (!((Character)player).m_nview.IsOwner()) { Plugin.Logger.LogWarning((object)"ReviveFromDowned called on non-owner; ignoring"); return; } DownedStateMachineView downedStateMachineView = player.State(); downedStateMachineView.Downed = false; ((Character)player).SetHealth(Mathf.Max(((Character)player).GetMaxHealth() * 0.25f, 1f)); DownedMarker.CrumbleLinked(((Character)player).m_nview); ((Character)player).Message((MessageType)2, "You have been revived!", 0, (Sprite)null); Plugin.Logger.LogInfo((object)(player.GetPlayerName() + " was revived by " + ReviverName(reviverId))); } } public static void ExpireDownedState(this Player player) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)player == (Object)null) && ((Character)player).m_nview.IsValid()) { DownedStateMachineView downedStateMachineView = player.State(); downedStateMachineView.Downed = false; GameObject val = player.FindDownedMarker(); if ((Object)(object)val != (Object)null) { GraveReplaceView graveReplaceView = player.GraveReplace(); graveReplaceView.Pending = true; graveReplaceView.Pos = val.transform.position; } Plugin.Logger.LogInfo((object)(player.GetPlayerName() + " revive window expired, proceeding to death")); } } private static string ReviverName(long reviverId) { if (reviverId == 0L) { return "someone"; } Player player = Player.GetPlayer(reviverId); if (!((Object)(object)player != (Object)null)) { return reviverId.ToString(); } return player.GetPlayerName(); } public static int PlayDownedPoof(this Player player) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) EffectList val = FindRagdollRemoveEffect(); if (val == null) { LastPoofCount = 0; return 0; } GameObject[] array = val.Create(((Character)player).GetCenterPoint(), Quaternion.identity, (Transform)null, 1f, -1); LastPoofCount = ((array != null) ? array.Length : 0); return LastPoofCount; } private static EffectList? FindRagdollRemoveEffect() { if (s_removeEffectSearched) { return s_cachedRemoveEffect; } if ((Object)(object)ZNetScene.instance == (Object)null) { return null; } s_removeEffectSearched = true; string[] array = new string[2] { "Greyling_ragdoll", "Greydwarf_ragdoll" }; foreach (string text in array) { GameObject prefab = ZNetScene.instance.GetPrefab(text); Ragdoll val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent() : null); if ((Object)(object)val != (Object)null && val.m_removeEffect != null && val.m_removeEffect.m_effectPrefabs.Length != 0) { s_cachedRemoveEffect = val.m_removeEffect; LastPoofSourceName = ((Object)prefab).name; Plugin.Logger.LogInfo((object)("Downed poof: using remove-effect from '" + ((Object)prefab).name + "'")); return s_cachedRemoveEffect; } } foreach (GameObject prefab2 in ZNetScene.instance.m_prefabs) { if (!((Object)(object)prefab2 == (Object)null)) { Ragdoll component = prefab2.GetComponent(); if ((Object)(object)component != (Object)null && component.m_removeEffect != null && component.m_removeEffect.m_effectPrefabs.Length != 0) { s_cachedRemoveEffect = component.m_removeEffect; LastPoofSourceName = ((Object)prefab2).name; Plugin.Logger.LogInfo((object)("Downed poof: using remove-effect from '" + ((Object)prefab2).name + "' (fallback)")); break; } } } if (s_cachedRemoveEffect == null) { Plugin.Logger.LogWarning((object)"Downed poof: no ragdoll prefab with a remove-effect found"); } return s_cachedRemoveEffect; } } public class ProgressUI : MonoBehaviour { public static readonly Color GiveUpRed = new Color(0.9f, 0.15f, 0.15f); private const float IdleTimeout = 0.5f; private IDecayingProgress? m_source; private Color m_color; private bool m_isGiveUp; private float m_idle; private GameObject? m_root; private Image? m_fillImg; public static bool Visible { get; private set; } public static float Fill { get; private set; } public static bool GivingUp { get; private set; } public static ProgressUI Create(IDecayingProgress source, Color color, bool isGiveUp) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("ReviveAllies_ProgressUI"); Object.DontDestroyOnLoad((Object)val); ProgressUI progressUI = val.AddComponent(); progressUI.m_source = source; progressUI.m_color = color; progressUI.m_isGiveUp = isGiveUp; source.Finished += progressUI.OnFinished; return progressUI; } private void OnFinished() { Close(); } public void Close() { if ((Object)(object)this != (Object)null) { Object.Destroy((Object)(object)((Component)this).gameObject); } } private void Awake() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("Canvas"); val.transform.SetParent(((Component)this).transform, false); Canvas obj = val.AddComponent(); obj.renderMode = (RenderMode)0; obj.sortingOrder = 5000; Sprite sprite = MakeDiscSprite(); MakeImage(val.transform, "bg", sprite, new Color(0f, 0f, 0f, 0.55f), 84f); m_fillImg = MakeImage(val.transform, "fill", sprite, Color.white, 72f); m_fillImg.type = (Type)3; m_fillImg.fillMethod = (FillMethod)4; m_fillImg.fillOrigin = 2; m_fillImg.fillClockwise = true; m_fillImg.fillAmount = 0f; m_root = val; m_root.SetActive(false); } private void Update() { //IL_0090: Unknown result type (might be due to invalid IL or missing references) IDecayingProgress? source = m_source; Object val = (Object)((source is Object) ? source : null); if (val != null && val == (Object)null) { Close(); return; } float num = Mathf.Clamp01(m_source?.Fraction ?? 0f); bool flag = num > 0.01f; if ((Object)(object)m_root != (Object)null && m_root.activeSelf != flag) { m_root.SetActive(flag); } if (flag && (Object)(object)m_fillImg != (Object)null) { m_fillImg.fillAmount = num; ((Graphic)m_fillImg).color = m_color; } Visible = flag; Fill = (flag ? num : 0f); GivingUp = flag && m_isGiveUp; if (flag) { m_idle = 0f; return; } m_idle += Time.unscaledDeltaTime; if (m_idle >= 0.5f) { Close(); } } private void OnDestroy() { if (m_source != null) { m_source.Finished -= OnFinished; } Visible = false; Fill = 0f; GivingUp = false; } private static Image MakeImage(Transform parent, string name, Sprite sprite, Color color, float size) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name); val.transform.SetParent(parent, false); Image obj = val.AddComponent(); obj.sprite = sprite; ((Graphic)obj).color = color; RectTransform rectTransform = ((Graphic)obj).rectTransform; Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(0.5f, 0.5f); rectTransform.anchorMax = val2; rectTransform.anchorMin = val2; rectTransform.anchoredPosition = new Vector2(0f, -110f); rectTransform.sizeDelta = new Vector2(size, size); return obj; } private static Sprite MakeDiscSprite() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(64, 64, (TextureFormat)5, false); float num = 32f; for (int i = 0; i < 64; i++) { for (int j = 0; j < 64; j++) { float num2 = Vector2.Distance(new Vector2((float)j + 0.5f, (float)i + 0.5f), new Vector2(num, num)); float num3 = Mathf.Clamp01((num - 1f - num2) / 2f); val.SetPixel(j, i, new Color(1f, 1f, 1f, num3)); } } val.Apply(); return Sprite.Create(val, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f)); } } public class Revivable : MonoBehaviour, Hoverable, Interactable { private ZNetView? m_nview; private void Awake() { m_nview = ((Component)this).GetComponentInParent(); } private ZDOID LinkedPlayerZdoId() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)m_nview != (Object)null) || !m_nview.IsValid()) { return ZDOID.None; } return new DownedMarkerView(m_nview).LinkedPlayer; } private Player? FindDownedPlayer() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) ZDOID val = LinkedPlayerZdoId(); if (val == ZDOID.None) { return null; } ZDO zDO = ZDOMan.instance.GetZDO(val); if (zDO == null) { return null; } ZNetView val2 = ZNetScene.instance.FindInstance(zDO); Player val3 = (((Object)(object)val2 != (Object)null) ? ((Component)val2).GetComponent() : null); if (!((Object)(object)val3 != (Object)null) || !val3.IsDowned()) { return null; } return val3; } private bool LinkedPlayerDisconnected() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) ZDOID val = LinkedPlayerZdoId(); if (val == ZDOID.None) { return false; } return ZDOMan.instance.GetZDO(val) == null; } private string OwnerName() { if ((Object)(object)m_nview == (Object)null || !m_nview.IsValid()) { return "Viking"; } string ownerName = new DownedMarkerView(m_nview).OwnerName; if (!string.IsNullOrEmpty(ownerName)) { return ownerName; } return "Viking"; } public string GetHoverText() { Player val = FindDownedPlayer(); if ((Object)(object)val == (Object)null) { if (LinkedPlayerDisconnected()) { return Localization.instance.Localize(OwnerName() + " (disconnected)"); } return ""; } string text = OwnerName(); string arg = (Plugin.RevivePressMode ? "" : "Hold "); string text2 = text + " (downed)\n"; text2 += $"[{arg}$KEY_Use] Revive ({val.GetDownedRemainingTime():F0}s)"; return Localization.instance.Localize(text2); } public string GetHoverName() { if ((Object)(object)m_nview == (Object)null || !m_nview.IsValid()) { return ""; } if ((Object)(object)FindDownedPlayer() != (Object)null || LinkedPlayerDisconnected()) { return OwnerName(); } return ""; } public bool Interact(Humanoid user, bool hold, bool alt) { if (!hold && !Plugin.RevivePressMode) { return false; } Player val = (Player)(object)((user is Player) ? user : null); if (val == null) { return false; } Player val2 = FindDownedPlayer(); if ((Object)(object)val2 == (Object)null || (Object)(object)val == (Object)(object)val2) { return false; } ((Component)val).GetComponent()?.Request(val2); return true; } public void SimulateHold() { Player val = FindDownedPlayer(); Player localPlayer = Player.m_localPlayer; if ((Object)(object)val != (Object)null && (Object)(object)localPlayer != (Object)null) { ((Component)localPlayer).GetComponent()?.Request(val); } } public bool UseItem(Humanoid user, ItemData item) { return false; } } public class ReviveChannelDecayingProgress : MonoBehaviour, IDecayingProgress { private const float DecayRate = 2f; private ZNetView m_nview; private long m_channeler; private float m_channelStart = -1f; private bool m_active; private bool Owner { get { if ((Object)(object)m_nview != (Object)null && m_nview.IsValid()) { return m_nview.IsOwner(); } return false; } } private float Now => (float)ZNet.instance.GetTimeSeconds(); private ReviveChannelDecayingProgressView View => new ReviveChannelDecayingProgressView(m_nview); public float Fraction => Mathf.Clamp01(Seconds() / Plugin.ReviveDuration); public bool Acked { get { if ((Object)(object)m_nview != (Object)null && m_nview.IsValid()) { return View.Channeling; } return false; } } public event Action? Finished; private void Awake() { m_nview = ((Component)this).GetComponent(); } private float Seconds() { if ((Object)(object)m_nview == (Object)null || !m_nview.IsValid()) { return 0f; } ReviveChannelDecayingProgressView view = View; float num = Now - view.AnchorTime; if (!view.Channeling) { return Mathf.Max(0f, view.AnchorSeconds - num * 2f); } return view.AnchorSeconds + num; } public void Begin(long channeler) { if (Owner) { m_channeler = channeler; m_channelStart = Now; ReviveChannelDecayingProgressView view = View; view.AnchorSeconds = Seconds(); view.AnchorTime = Now; view.Channeling = true; } } public void End() { if (Owner) { ReviveChannelDecayingProgressView view = View; view.AnchorSeconds = Seconds(); view.AnchorTime = Now; view.Channeling = false; if (m_channelStart >= 0f) { PauseWindow(Now - m_channelStart); } m_channelStart = -1f; } } private void Update() { if (Owner) { ReviveChannelDecayingProgressView view = View; if (view.Channeling && (Plugin.RevivePressMode || Seconds() >= Plugin.ReviveDuration)) { view.Channeling = false; view.AnchorSeconds = 0f; view.AnchorTime = Now; LinkedPlayer()?.ReviveFromDowned(m_channeler); return; } } if (Fraction > 0.01f) { m_active = true; } else if (m_active) { m_active = false; this.Finished?.Invoke(); } } private void OnDestroy() { if (m_active) { m_active = false; this.Finished?.Invoke(); } } private void PauseWindow(float seconds) { if (!(seconds <= 0f)) { Player val = LinkedPlayer(); if (!((Object)(object)val == (Object)null) && ((Character)val).m_nview.IsValid() && ((Character)val).m_nview.IsOwner()) { DownedStateMachineView downedStateMachineView = new DownedStateMachineView(((Character)val).m_nview); downedStateMachineView.DownedTime += seconds; } } } private Player? LinkedPlayer() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)m_nview == (Object)null || !m_nview.IsValid()) { return null; } ZDOID linkedPlayer = new DownedMarkerView(m_nview).LinkedPlayer; if (linkedPlayer == ZDOID.None) { return null; } ZDO zDO = ZDOMan.instance.GetZDO(linkedPlayer); ZNetView val = ((zDO != null) ? ZNetScene.instance.FindInstance(zDO) : null); if (!((Object)(object)val != (Object)null)) { return null; } return ((Component)val).GetComponent(); } } public struct ReviveChannelDecayingProgressView { private static readonly int kAnchorTime = StringExtensionMethods.GetStableHashCode("RevivalRevived_reviveAnchorTime"); private static readonly int kAnchorSeconds = StringExtensionMethods.GetStableHashCode("RevivalRevived_reviveAnchorSeconds"); private static readonly int kChanneling = StringExtensionMethods.GetStableHashCode("RevivalRevived_reviveChanneling"); private readonly ZDO _z; public float AnchorTime { get { return _z.GetFloat(kAnchorTime, 0f); } set { _z.Set(kAnchorTime, value); } } public float AnchorSeconds { get { return _z.GetFloat(kAnchorSeconds, 0f); } set { _z.Set(kAnchorSeconds, value); } } public bool Channeling { get { return _z.GetBool(kChanneling, false); } set { _z.Set(kChanneling, value); } } public ReviveChannelDecayingProgressView(ZNetView nview) : this(nview.GetZDO()) { } public ReviveChannelDecayingProgressView(ZDO zdo) { _z = zdo; } } public class ReviveRequest : MonoBehaviour { private const float RequestTimeout = 0.5f; private Player? m_target; private float m_lastRequest = -999f; private ProgressUI? m_ui; public bool WantsToChannel => Time.time - m_lastRequest < 0.5f; public Player? Target { get { if (!((Object)(object)m_target != (Object)null) || !m_target.IsDowned()) { return null; } return m_target; } } public void Request(Player downed) { m_target = downed; m_lastRequest = Time.time; } public void SendBegin() { SendChannelEdge(channeling: true); } public void SendEnd() { SendChannelEdge(channeling: false); } private void SendChannelEdge(bool channeling) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) ZNetView component = ((Component)this).GetComponent(); if (!((Object)(object)m_target == (Object)null) && ((Character)m_target).m_nview.IsValid() && component.IsValid()) { ((Character)m_target).m_nview.InvokeRPC("RevivalRevived_Channel", new object[2] { channeling, component.GetZDO().m_uid }); } } public void ShowUI() { //IL_0041: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)m_ui != (Object)null)) { Player? target = Target; object obj; if (target == null) { obj = null; } else { GameObject? obj2 = target.FindDownedMarker(); obj = ((obj2 != null) ? obj2.GetComponent() : null); } ReviveChannelDecayingProgress reviveChannelDecayingProgress = (ReviveChannelDecayingProgress)obj; if ((Object)(object)reviveChannelDecayingProgress != (Object)null && reviveChannelDecayingProgress.Acked) { m_ui = ProgressUI.Create(reviveChannelDecayingProgress, DownedMarker.ReviveGreen, isGiveUp: false); } } } public void CloseUI() { m_ui?.Close(); m_ui = null; } } public class ReviverStateMachine : StateMachine { protected override IState CreateInitialState() { return new ReviverIdleState(((Component)this).GetComponent()); } private void Update() { Tick(); } } public interface IState { void Enter(); IState? Tick(); void Exit(); } public abstract class StateMachine : MonoBehaviour { public IState? Current { get; private set; } protected abstract IState CreateInitialState(); protected virtual void Awake() { Change(CreateInitialState()); } private void Change(IState? next) { if (Current != next) { Current?.Exit(); Current = next; Current?.Enter(); } } protected void Tick() { IState state = Current?.Tick(); if (state != null && state != Current) { Change(state); } } } } namespace ReviveAllies.Components.States { public sealed class AliveState : IState { private readonly Player _p; public AliveState(Player p) { _p = p; } public void Enter() { ((Component)_p).GetComponent().Reset(); } public IState? Tick() { if (!_p.IsDowned()) { return null; } return new WaitingState(_p); } public void Exit() { } } public sealed class GivingUpState : IState { private readonly Player _p; private readonly GiveUp _giveUp; public GivingUpState(Player p) { _p = p; _giveUp = ((Component)p).GetComponent(); } public void Enter() { _giveUp.ShowUI(); } public void Exit() { } public IState? Tick() { if (!_p.IsDowned()) { return new AliveState(_p); } if (!_giveUp.Held()) { return new WaitingState(_p); } if (_giveUp.Channel(Time.deltaTime)) { DownedStateMachineView downedStateMachineView = _p.State(); downedStateMachineView.DownedTime = (float)ZNet.instance.GetTimeSeconds() - Plugin.ReviveWindow - 1f; if (((Character)_p).GetHealth() > 0f) { ((Character)_p).SetHealth(0f); } _giveUp.Reset(); Plugin.Logger.LogInfo((object)(_p.GetPlayerName() + " gave up")); } return null; } } public sealed class RevivingState : IState { private readonly Player _p; private readonly GiveUp _giveUp; private readonly ChannelSignal _channel; public RevivingState(Player p) { _p = p; _giveUp = ((Component)p).GetComponent(); _channel = ((Component)p).GetComponent(); } public void Enter() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) ReviveChannelDecayingProgress reviveChannelDecayingProgress = Timer(); reviveChannelDecayingProgress?.Begin(_channel.LastChanneler); if ((Object)(object)reviveChannelDecayingProgress != (Object)null) { ProgressUI.Create(reviveChannelDecayingProgress, DownedMarker.ReviveGreen, isGiveUp: false); } } public void Exit() { Timer()?.End(); } public IState? Tick() { if (!_p.IsDowned()) { return new AliveState(_p); } if (_giveUp.Held()) { return new GivingUpState(_p); } if (!_channel.IsChanneling) { return new WaitingState(_p); } return null; } private ReviveChannelDecayingProgress? Timer() { GameObject? obj = _p.FindDownedMarker(); if (obj == null) { return null; } return obj.GetComponent(); } } public sealed class WaitingState : IState { private readonly Player _p; private readonly GiveUp _giveUp; private readonly ChannelSignal _channel; public WaitingState(Player p) { _p = p; _giveUp = ((Component)p).GetComponent(); _channel = ((Component)p).GetComponent(); } public void Enter() { } public void Exit() { } public IState? Tick() { if (!_p.IsDowned()) { return new AliveState(_p); } if (_giveUp.Held()) { return new GivingUpState(_p); } if (_channel.IsChanneling) { return new RevivingState(_p); } if (_p.IsReviveWindowExpired() && ((Character)_p).GetHealth() > 0f) { ((Character)_p).SetHealth(0f); } _giveUp.Decay(Time.deltaTime); return null; } } public sealed class ReviverChannelingState : IState { private readonly Player _p; private readonly ReviveRequest _req; public ReviverChannelingState(Player p) { _p = p; _req = ((Component)p).GetComponent(); } public void Enter() { _req.SendBegin(); } public void Exit() { _req.SendEnd(); _req.CloseUI(); } public IState? Tick() { if (!_req.WantsToChannel || (Object)(object)_req.Target == (Object)null) { return new ReviverIdleState(_p); } _req.ShowUI(); return null; } } public sealed class ReviverIdleState : IState { private readonly Player _p; private readonly ReviveRequest _req; public ReviverIdleState(Player p) { _p = p; _req = ((Component)p).GetComponent(); } public void Enter() { } public void Exit() { } public IState? Tick() { if (!_req.WantsToChannel || !((Object)(object)_req.Target != (Object)null)) { return null; } return new ReviverChannelingState(_p); } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }