Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ReviveAllies v0.3.4
ReviveAllies.dll
Decompiled 2 months agousing 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<ReviveModeType> ReviveModeCfg; internal static ConfigEntry<float> ReviveHoldTimeCfg; internal static ConfigEntry<float> 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<ReviveModeType> 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<ReviveModeType>("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<float>("Revive", "HoldTimeSeconds", 4f, new ConfigDescription("How long the interact key must be held to complete a revive (Hold mode).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 60f), Array.Empty<object>())); ReviveWindowCfg = ((BaseUnityPlugin)this).Config.Bind<float>("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<float>(5f, 600f), Array.Empty<object>())); 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<DownedStateMachine>() == (Object)null) { return true; } if (!val.IsDowned()) { val.EnterDownedState(); return false; } if (!((Component)val).GetComponent<ChannelSignal>().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<float, float, int>("ReviveAllies_Config", (Action<long, float, float, int>)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<GiveUp>() == (Object)null) { ((Component)__instance).gameObject.AddComponent<GiveUp>(); } if ((Object)(object)((Component)__instance).GetComponent<ChannelSignal>() == (Object)null) { ((Component)__instance).gameObject.AddComponent<ChannelSignal>(); } if ((Object)(object)((Component)__instance).GetComponent<DownedStateMachine>() == (Object)null) { ((Component)__instance).gameObject.AddComponent<DownedStateMachine>(); } if ((Object)(object)((Component)__instance).GetComponent<ReviveRequest>() == (Object)null) { ((Component)__instance).gameObject.AddComponent<ReviveRequest>(); } if ((Object)(object)((Component)__instance).GetComponent<ReviverStateMachine>() == (Object)null) { ((Component)__instance).gameObject.AddComponent<ReviverStateMachine>(); } if ((Object)(object)((Component)__instance).GetComponent<ReconnectDeathCheck>() == (Object)null) { ((Component)__instance).gameObject.AddComponent<ReconnectDeathCheck>(); } if ((Object)(object)((Component)__instance).GetComponent<DownedView>() == (Object)null) { ((Component)__instance).gameObject.AddComponent<DownedView>(); } } } [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<Rigidbody>(); 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<TintedMaterial> m_tinted = new List<TintedMaterial>(); 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<ZNetView>() : 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<TombStone>() : 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<ZNetView>(); 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<TMP_Text>(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<Light>(true); foreach (Light val in componentsInChildren) { m_lights.Add((val, val.color)); } Renderer[] componentsInChildren2 = ((Component)this).GetComponentsInChildren<Renderer>(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<TombStone>(); 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<Renderer>(); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].enabled = false; } Collider[] componentsInChildren2 = ((Component)this).GetComponentsInChildren<Collider>(); for (int i = 0; i < componentsInChildren2.Length; i++) { componentsInChildren2[i].enabled = false; } Light[] componentsInChildren3 = ((Component)this).GetComponentsInChildren<Light>(); 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<int, int> 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<ZNetView>(); m_nview.Register<bool, ZDOID>("RevivalRevived_Channel", (Action<long, bool, ZDOID>)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<ZNetView>(); base.Awake(); } protected override IState CreateInitialState() { return new AliveState(((Component)this).GetComponent<Player>()); } 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<int, int> 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<Player>(); } 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<Player>(); m_nview = ((Component)this).GetComponent<ZNetView>(); } 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<object>()).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<Player>(); m_nview = ((Component)this).GetComponent<ZNetView>(); } 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<GameObject>(val, s_prefabHolder.transform); ((Object)obj).name = "RevivalRevived_DownedMarker"; TombStone component = obj.GetComponent<TombStone>(); if ((Object)(object)component != (Object)null) { Object.DestroyImmediate((Object)(object)component); } Container component2 = obj.GetComponent<Container>(); if ((Object)(object)component2 != (Object)null) { Object.DestroyImmediate((Object)(object)component2); } RemoveGraveEffects(obj); obj.AddComponent<DownedMarker>(); obj.AddComponent<ReviveChannelDecayingProgress>(); obj.AddComponent<Revivable>(); 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<TombStone>() != (Object)null) { return prefab; } foreach (GameObject prefab2 in scene.m_prefabs) { if ((Object)(object)prefab2 != (Object)null && (Object)(object)prefab2.GetComponent<TombStone>() != (Object)null) { return prefab2; } } return null; } private static void RemoveGraveEffects(GameObject template) { ParticleSystem[] componentsInChildren = template.GetComponentsInChildren<ParticleSystem>(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<Transform>(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<GameObject>(val, ((Character)player).GetCenterPoint(), ((Component)player).transform.rotation); ZNetView component = val2.GetComponent<ZNetView>(); 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<Rigidbody>(); 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<DownedMarker>(); foreach (DownedMarker downedMarker in array) { ZNetView component = ((Component)downedMarker).GetComponent<ZNetView>(); 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<ZNetView>() : 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<ReviveChannelDecayingProgress>() : 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 [<color=#ff5555><b>$KEY_Use</b></color>] 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<Ragdoll>() : 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<Ragdoll>(); 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>(); 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<Canvas>(); 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<Image>(); 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<ZNetView>(); } 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<Player>() : 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 += $"[<color=yellow><b>{arg}$KEY_Use</b></color>] 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<ReviveRequest>()?.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<ReviveRequest>()?.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<ZNetView>(); } 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<Player>(); } } 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<ZNetView>(); 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<ReviveChannelDecayingProgress>() : 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<Player>()); } 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<GiveUp>().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<GiveUp>(); } 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<GiveUp>(); _channel = ((Component)p).GetComponent<ChannelSignal>(); } 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<ReviveChannelDecayingProgress>(); } } 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<GiveUp>(); _channel = ((Component)p).GetComponent<ChannelSignal>(); } 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<ReviveRequest>(); } 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<ReviveRequest>(); } 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) { } } }