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 SoulAnchor v1.0.0
SoulAnchor.dll
Decompiled 4 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Extensions; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using Splatform; using UnityEngine; using UnityEngine.Networking; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("xNeliox")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © xNeliox 2026")] [assembly: AssemblyDescription("Configurable self and ally revival for Valheim.")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("Soul Anchor")] [assembly: AssemblyTitle("SoulAnchor")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [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 Seelenanker { [BepInPlugin("xNeliox.valheim.soulanchor", "Soul Anchor", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { public const string Id = "xNeliox.valheim.soulanchor"; public const string Totem = "SoulAnchor"; public const string BrokenTotem = "BrokenSoulAnchor"; public const string Potion = "EirsBreath"; public const string MeadBase = "EirsBrew"; internal static Plugin Instance; private Harmony harmony; private CustomItem totemItem; private CustomItem brokenTotemItem; private CustomItem meadItem; private CustomItemConversion fermenterConversion; private ItemConversion runtimeFermenterConversion; private string appliedRecipeSettings; private void Awake() { //IL_03f7: Unknown result type (might be due to invalid IL or missing references) //IL_0401: Expected O, but got Unknown Instance = this; ModSettings.Bind(((BaseUnityPlugin)this).Config); CustomLocalization localization = LocalizationManager.Instance.GetLocalization(); string text = "English"; localization.AddTranslation(ref text, new Dictionary<string, string> { { "sa_totem", "Soul Anchor" }, { "sa_totem_desc", "An old wooden anchor marked with a soul sign. Breaks on a lethal blow and calls you back to life." }, { "sa_broken_totem", "Broken Soul Anchor" }, { "sa_broken_totem_desc", "A Soul Anchor split by the force of revival. It can be reforged at a black forge." }, { "sa_potion", "Eir's Breath" }, { "sa_potion_desc", "A potent draught carrying Eir's breath. Use it from the hotbar on a nearby downed ally to call them back to life." }, { "sa_base", "Mead mixture: Eir's Brew" }, { "sa_base_desc", "A rich mead mixture prepared at the mead ketill. Ferments into Eir's Breath." }, { "sa_downed", "Downed – {0} s left to be rescued" }, { "sa_giveup_progress", "Giving up: {0}%" }, { "sa_downed_cooldown", "Revival available again in {0} s" }, { "sa_cooldown", "Eir's call is not ready yet ({0} s)." }, { "sa_hint", "Use Eir's Breath from your hotbar (max. 3 m)" }, { "sa_giveup_hint", "Give up: [R] / {0}, or hold Interact for 2 s" }, { "sa_rescued", "Revived! Protected for {0} seconds. Revival cooldown: {1} seconds." }, { "sa_totem_used", "Your Soul Anchor breaks and saves you! Protected for {0} seconds; revival cooldown: {1} seconds." }, { "sa_invalid", "Aim at a downed ally within 3 metres." }, { "sa_sent", "Confirming rescue …" }, { "sa_success", "Ally revived!" }, { "sa_refund", "Rescue unavailable. Potion refunded." }, { "sa_pending", "The previous rescue is still awaiting the other player's reply." }, { "sa_grace", "Back among the living" }, { "sa_grace_desc", "Protected from damage after revival." }, { "sa_totem_grace", "Soul Anchor's Aegis" }, { "sa_totem_grace_desc", "The Soul Anchor shields you from damage after pulling you back to life." }, { "sa_revival_cooldown", "Revival Exhaustion" }, { "sa_revival_cooldown_desc", "You cannot be revived again until this countdown ends." }, { "sa_warning", "Only {0} seconds remain!" }, { "sa_last_death", "Last final death" } }); text = "German"; localization.AddTranslation(ref text, new Dictionary<string, string> { { "sa_totem", "Seelenanker" }, { "sa_totem_desc", "Ein mit einem Seelenzeichen versehener Anker aus altem Holz. Zerbricht bei einem tödlichen Treffer und ruft dich ins Leben zurück." }, { "sa_broken_totem", "Gebrochener Seelenanker" }, { "sa_broken_totem_desc", "Ein von der Kraft der Wiederbelebung gespaltener Seelenanker. Er kann an einer Schwarzschmiede neu gebunden werden." }, { "sa_potion", "Eirs Atem" }, { "sa_potion_desc", "Ein kräftiger Trank mit dem Atem Eirs. Benutze ihn aus der Schnellleiste auf einen kampfunfähigen Verbündeten in Reichweite, um ihn ins Leben zurückzurufen." }, { "sa_base", "Metmischung: Eirs Sud" }, { "sa_base_desc", "Eine süße, kräftige Metmischung aus dem Metkocher. Im Gärer entsteht daraus Eirs Atem." }, { "sa_downed", "Kampfunfähig – Rettung noch {0} s möglich" }, { "sa_giveup_hint", "Aufgeben: [R] / {0} oder Interagieren 2 s halten" }, { "sa_giveup_progress", "Aufgeben: {0}%" }, { "sa_downed_cooldown", "Wiederbelebung wieder möglich in {0} s" }, { "sa_cooldown", "Eirs Ruf ist noch nicht bereit ({0} s)." }, { "sa_hint", "Eirs Atem aus der Schnellleiste anwenden (max. 3 m)" }, { "sa_rescued", "Wiederbelebt! {0} Sekunden Schutz. Erneute Wiederbelebung in {1} Sekunden möglich." }, { "sa_totem_used", "Dein Seelenanker zerbricht und rettet dich! {0} Sekunden Schutz; {1} Sekunden Abklingzeit." }, { "sa_invalid", "Sieh einen kampfunfähigen Gefährten aus höchstens 3 Metern an." }, { "sa_sent", "Rettung wird bestätigt …" }, { "sa_success", "Gefährte gerettet!" }, { "sa_refund", "Rettung nicht mehr möglich. Trank zurückerstattet." }, { "sa_pending", "Die vorherige Rettung wartet noch auf die Antwort des Mitspielers." }, { "sa_grace", "Zurück im Leben" }, { "sa_grace_desc", "Nach der Wiederbelebung vor Schaden geschützt." }, { "sa_totem_grace", "Schutz des Seelenankers" }, { "sa_totem_grace_desc", "Der Seelenanker schützt dich vor Schaden, nachdem er dich ins Leben zurückgerufen hat." }, { "sa_revival_cooldown", "Wiederbelebungs-Erschöpfung" }, { "sa_revival_cooldown_desc", "Bis dieser Countdown endet, kannst du nicht erneut wiederbelebt werden." }, { "sa_warning", "Nur noch {0} Sekunden!" }, { "sa_last_death", "Letzter endgültiger Tod" } }); PrefabManager.OnVanillaPrefabsAvailable += RegisterItems; harmony = new Harmony("xNeliox.valheim.soulanchor"); harmony.PatchAll(); ((MonoBehaviour)this).StartCoroutine(RevivalEffects.LoadAudio()); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Soul Anchor 1.0.0 by xNeliox loaded. Rescue window: {LifeWindow.RescueSeconds}s; revival cooldown: {LifeWindow.RevivalCooldownSeconds}s; synchronized server config enabled."); } private void Update() { ModSettings.ApplyRuntime(); RescueNetwork.EnsureRegistered(); DownedSignals.EnsureRegistered(); DownedSignals.Tick(); ApplyRecipeSettings(); } private void OnDestroy() { PrefabManager.OnVanillaPrefabsAvailable -= RegisterItems; Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } private static Sprite Icon(string name) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected O, but got Unknown //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Seelenanker." + name + ".png"); if (stream == null) { throw new InvalidOperationException("Missing embedded icon: " + name); } byte[] array = new byte[stream.Length]; int num; for (int i = 0; i < array.Length; i += num) { num = stream.Read(array, i, array.Length - i); if (num == 0) { throw new EndOfStreamException(); } } Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); if (!ImageConversion.LoadImage(val, array)) { throw new InvalidOperationException("Invalid icon: " + name); } ((Object)val).name = "SA_" + name; ((Texture)val).filterMode = (FilterMode)1; return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f)); } private static CustomItem Item(string id, string clone, ItemConfig config, int stack) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Expected O, but got Unknown //IL_002e: Unknown result type (might be due to invalid IL or missing references) CustomItem val = new CustomItem(id, clone, config); SharedData shared = val.ItemPrefab.GetComponent<ItemDrop>().m_itemData.m_shared; shared.m_maxStackSize = stack; shared.m_maxQuality = 1; shared.m_itemType = (ItemType)1; shared.m_consumeStatusEffect = null; shared.m_food = 0f; shared.m_foodStamina = 0f; shared.m_foodEitr = 0f; shared.m_questItem = false; shared.m_teleportable = true; switch (id) { case "SoulAnchor": case "BrokenSoulAnchor": case "EirsBreath": case "EirsBrew": ItemModels.Apply(val.ItemPrefab, id == "SoulAnchor" || id == "BrokenSoulAnchor", id == "EirsBrew", id == "BrokenSoulAnchor"); break; } if (!ItemManager.Instance.AddItem(val)) { throw new InvalidOperationException("Item registration failed: " + id); } return val; } private void RegisterItems() { //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_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Expected O, but got Unknown //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Expected O, but got Unknown //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Expected O, but got Unknown //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_0243: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_0280: Unknown result type (might be due to invalid IL or missing references) //IL_02a1: Expected O, but got Unknown //IL_02a7: Unknown result type (might be due to invalid IL or missing references) //IL_02ac: Unknown result type (might be due to invalid IL or missing references) //IL_02b7: Unknown result type (might be due to invalid IL or missing references) //IL_02c2: Unknown result type (might be due to invalid IL or missing references) //IL_02cd: Unknown result type (might be due to invalid IL or missing references) //IL_02e2: Expected O, but got Unknown //IL_02dd: Unknown result type (might be due to invalid IL or missing references) //IL_02e7: Expected O, but got Unknown Sprite val = Icon("totem_buff"); try { RevivalEffects.Register(Icon("potion"), val, Icon("cooldown")); RevivalUi.Register(val); } catch (Exception ex) { Log("Optional revival effect registration failed: " + ex.Message); } totemItem = Item("SoulAnchor", "TrophyGreydwarfShaman", new ItemConfig { Name = "$sa_totem", Description = "$sa_totem_desc", Icon = Icon("totem"), Weight = 1f, CraftingStation = "blackforge", MinStationLevel = 1, Enabled = ModSettings.TotemEnabled.Value, Amount = ModSettings.TotemCraftAmount.Value, Requirements = ModSettings.ParseRecipe(ModSettings.TotemRecipe.Value, "TrophyGreydwarfShaman:1,TrophyWolf:1,TrophyLox:1,FineWood:10") }, 1); ItemDrop component = totemItem.ItemPrefab.GetComponent<ItemDrop>(); component.m_itemData.m_shared.m_useDurability = true; component.m_itemData.m_shared.m_maxDurability = 100f; component.m_itemData.m_shared.m_canBeReparied = false; component.m_itemData.m_durability = 100f; brokenTotemItem = Item("BrokenSoulAnchor", "TrophyGreydwarfShaman", new ItemConfig { Name = "$sa_broken_totem", Description = "$sa_broken_totem_desc", Icon = Icon("broken_totem"), Weight = 1f }, 1); ItemDrop component2 = brokenTotemItem.ItemPrefab.GetComponent<ItemDrop>(); component2.m_itemData.m_shared.m_useDurability = true; component2.m_itemData.m_shared.m_maxDurability = 100f; component2.m_itemData.m_shared.m_canBeReparied = true; component2.m_itemData.m_durability = 0f; Item("EirsBreath", "MeadHealthMedium", new ItemConfig { Name = "$sa_potion", Description = "$sa_potion_desc", Icon = Icon("potion"), Weight = 0.5f }, 10); meadItem = Item("EirsBrew", "MeadBaseHealthMedium", new ItemConfig { Name = "$sa_base", Description = "$sa_base_desc", Icon = Icon("base"), Weight = 1f, CraftingStation = "piece_MeadCauldron", MinStationLevel = 1, Enabled = ModSettings.PotionEnabled.Value, Requirements = ModSettings.ParseRecipe(ModSettings.MeadRecipe.Value, "Honey:20,Cloudberry:20,Bloodbag:10,FreezeGland:5,Thistle:10") }, 10); fermenterConversion = new CustomItemConversion((ConversionConfig)new FermenterConversionConfig { FromItem = "EirsBrew", ToItem = "EirsBreath", Station = "fermenter", ProducedItems = ModSettings.FermenterYield.Value }); ItemManager.Instance.AddItemConversion(fermenterConversion); appliedRecipeSettings = null; PrefabManager.OnVanillaPrefabsAvailable -= RegisterItems; ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Registered 4 items, configurable recipes, and fermentation output of {ModSettings.FermenterYield.Value} potions."); } private void ApplyRecipeSettings() { CustomItem obj = totemItem; object obj2; if (obj == null) { obj2 = null; } else { CustomRecipe recipe = obj.Recipe; obj2 = ((recipe != null) ? recipe.Recipe : null); } if ((Object)obj2 == (Object)null) { return; } CustomItem obj3 = meadItem; object obj4; if (obj3 == null) { obj4 = null; } else { CustomRecipe recipe2 = obj3.Recipe; obj4 = ((recipe2 != null) ? recipe2.Recipe : null); } if ((Object)obj4 == (Object)null || fermenterConversion == null || !Object.op_Implicit((Object)(object)ObjectDB.instance)) { return; } string text = string.Join("|", ModSettings.TotemEnabled.Value, ModSettings.PotionEnabled.Value, ModSettings.TotemRecipe.Value, ModSettings.TotemCraftAmount.Value, ModSettings.MeadRecipe.Value, ModSettings.FermenterYield.Value); if (text == appliedRecipeSettings) { return; } ApplyRecipe(totemItem.Recipe.Recipe, ModSettings.TotemEnabled.Value, ModSettings.TotemCraftAmount.Value, ModSettings.ParseRecipe(ModSettings.TotemRecipe.Value, "TrophyGreydwarfShaman:1,TrophyWolf:1,TrophyLox:1,FineWood:10")); ApplyRecipe(meadItem.Recipe.Recipe, ModSettings.PotionEnabled.Value, 1, ModSettings.ParseRecipe(ModSettings.MeadRecipe.Value, "Honey:20,Cloudberry:20,Bloodbag:10,FreezeGland:5,Thistle:10")); GameObject prefab = PrefabManager.Instance.GetPrefab("fermenter"); Fermenter val = ((prefab != null) ? prefab.GetComponent<Fermenter>() : null); if ((Object)(object)val != (Object)null) { if (runtimeFermenterConversion == null) { foreach (ItemConversion item in val.m_conversion) { if (Object.op_Implicit((Object)(object)item.m_from) && ((Object)((Component)item.m_from).gameObject).name == "EirsBrew") { runtimeFermenterConversion = item; break; } } } if (runtimeFermenterConversion != null) { runtimeFermenterConversion.m_producedItems = ModSettings.FermenterYield.Value; val.m_conversion.RemoveAll((ItemConversion x) => (Object)(object)x.m_from == (Object)(object)runtimeFermenterConversion.m_from); if (ModSettings.PotionEnabled.Value) { val.m_conversion.Add(runtimeFermenterConversion); } } } if (runtimeFermenterConversion != null) { appliedRecipeSettings = text; if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { AccessTools.Method(typeof(Player), "UpdateKnownRecipesList", (Type[])null, (Type[])null)?.Invoke(Player.m_localPlayer, null); } ((BaseUnityPlugin)this).Logger.LogInfo((object)"Applied synchronized Soul Anchor recipe settings."); } } private static void ApplyRecipe(Recipe recipe, bool enabled, int amount, RequirementConfig[] configured) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Expected O, but got Unknown recipe.m_enabled = enabled; recipe.m_amount = amount; List<Requirement> list = new List<Requirement>(); foreach (RequirementConfig val in configured) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(val.Item); ItemDrop val2 = (Object.op_Implicit((Object)(object)itemPrefab) ? itemPrefab.GetComponent<ItemDrop>() : null); if (!Object.op_Implicit((Object)(object)val2)) { Log("Unknown recipe item ignored: " + val.Item); continue; } list.Add(new Requirement { m_resItem = val2, m_amount = val.Amount, m_amountPerLevel = val.AmountPerLevel }); } if (list.Count > 0) { recipe.m_resources = list.ToArray(); } } internal static void GiveBrokenTotem(Player player) { //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) GameObject val = (Object.op_Implicit((Object)(object)ObjectDB.instance) ? ObjectDB.instance.GetItemPrefab("BrokenSoulAnchor") : null); if (!Object.op_Implicit((Object)(object)player) || !Object.op_Implicit((Object)(object)val)) { Log("Broken Soul Anchor could not be created."); return; } ItemData val2 = val.GetComponent<ItemDrop>().m_itemData.Clone(); val2.m_dropPrefab = val; val2.m_stack = 1; val2.m_worldLevel = (byte)Game.m_worldLevel; val2.m_durability = 0f; if (!((Humanoid)player).GetInventory().AddItem(val2)) { GameObject obj = Object.Instantiate<GameObject>(val, ((Component)player).transform.position + Vector3.up, Quaternion.identity); obj.GetComponent<ItemDrop>().m_itemData.m_stack = 1; obj.GetComponent<ItemDrop>().m_itemData.m_durability = 0f; } } internal static void NormalizeBrokenTotems(Player player) { if (!Object.op_Implicit((Object)(object)player)) { return; } foreach (ItemData allItem in ((Humanoid)player).GetInventory().GetAllItems()) { if (Object.op_Implicit((Object)(object)allItem?.m_dropPrefab) && ((Object)allItem.m_dropPrefab).name == "BrokenSoulAnchor") { allItem.m_durability = 0f; } } } internal static bool TryRepairBrokenTotem() { //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: 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_00da: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; CraftingStation val = (Object.op_Implicit((Object)(object)localPlayer) ? localPlayer.GetCurrentCraftingStation() : null); if (!Object.op_Implicit((Object)(object)localPlayer) || !IsBlackForge(val)) { return false; } ItemData val2 = ((IEnumerable<ItemData>)((Humanoid)localPlayer).GetInventory().GetAllItems()).FirstOrDefault((Func<ItemData, bool>)((ItemData i) => Object.op_Implicit((Object)(object)i?.m_dropPrefab) && ((Object)i.m_dropPrefab).name == "BrokenSoulAnchor" && i.m_durability < i.GetMaxDurability())); if (val2 == null) { return false; } ((Humanoid)localPlayer).GetInventory().RemoveItem(val2, 1); GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("SoulAnchor"); if (Object.op_Implicit((Object)(object)itemPrefab) && !((Humanoid)localPlayer).GetInventory().AddItem(itemPrefab, 1)) { Object.Instantiate<GameObject>(itemPrefab, ((Component)localPlayer).transform.position + Vector3.up, Quaternion.identity); } val.m_repairItemDoneEffects.Create(((Component)val).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID)); ((Character)localPlayer).Message((MessageType)2, Localization.instance.Localize("$msg_repaired", new string[1] { "$sa_totem" }), 0, (Sprite)null, false); return true; } internal static bool IsBlackForge(CraftingStation station) { if (Object.op_Implicit((Object)(object)station)) { if (!((Object)station).name.StartsWith("blackforge", StringComparison.OrdinalIgnoreCase) && !((Object)station).name.StartsWith("piece_blackforge", StringComparison.OrdinalIgnoreCase)) { return station.m_name == "$piece_blackforge"; } return true; } return false; } internal static void Log(string text) { ((BaseUnityPlugin)Instance).Logger.LogWarning((object)text); } internal static void LogInfo(string text) { ((BaseUnityPlugin)Instance).Logger.LogInfo((object)text); } internal static void Say(Player player, string key) { string text = Localization.instance.Localize(key); if (key == "$sa_rescued" || key == "$sa_totem_used") { text = string.Format(text, LifeWindow.GraceSeconds, LifeWindow.RevivalCooldownSeconds); } ((Character)player).Message((MessageType)2, text, 0, (Sprite)null, false); } } internal static class ModSettings { internal static ConfigEntry<float> RescueTime; internal static ConfigEntry<float> Cooldown; internal static ConfigEntry<float> RestoredHealth; internal static ConfigEntry<float> ProtectionTime; internal static ConfigEntry<float> RevivalDuration; internal static ConfigEntry<bool> TotemEnabled; internal static ConfigEntry<bool> PotionEnabled; internal static ConfigEntry<bool> SkillLossOnFinalDeath; internal static ConfigEntry<float> EffectVolume; internal static ConfigEntry<float> EffectStrength; internal static ConfigEntry<string> TotemRecipe; internal static ConfigEntry<int> TotemCraftAmount; internal static ConfigEntry<string> MeadRecipe; internal static ConfigEntry<int> FermenterYield; internal static void Bind(ConfigFile config) { AcceptableValueBase val = (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 600f); RescueTime = ConfigFileExtensions.BindConfig<float>(config, "Gameplay", "Rescue time (seconds)", 60f, "How long a downed player can be rescued.", true, (int?)null, val, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); val = (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 600f); Cooldown = ConfigFileExtensions.BindConfig<float>(config, "Gameplay", "Revival cooldown (seconds)", 30f, "Minimum time before the same player can be revived again.", true, (int?)null, val, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); val = (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f); RestoredHealth = ConfigFileExtensions.BindConfig<float>(config, "Gameplay", "Restored health (percent)", 40f, "Percentage of maximum health restored by either revival method.", true, (int?)null, val, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); val = (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 60f); ProtectionTime = ConfigFileExtensions.BindConfig<float>(config, "Gameplay", "Protection duration (seconds)", 5f, "Damage immunity and revival-effect duration after revival.", true, (int?)null, val, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); val = (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 10f); RevivalDuration = ConfigFileExtensions.BindConfig<float>(config, "Gameplay", "Ally revival duration (seconds)", 1.5f, "How long Eir's Breath must be applied before the rescue request is sent.", true, (int?)null, val, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); SkillLossOnFinalDeath = ConfigFileExtensions.BindConfig<bool>(config, "Gameplay", "Skill loss on final death", true, "If disabled, final death still creates a tombstone but does not lower skills.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); TotemEnabled = ConfigFileExtensions.BindConfig<bool>(config, "Items", "Enable Soul Anchor", true, "Enables automatic self-revival and its crafting recipe.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); PotionEnabled = ConfigFileExtensions.BindConfig<bool>(config, "Items", "Enable Eirs Breath", true, "Enables ally revival and the mead-mixture recipe.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); TotemRecipe = ConfigFileExtensions.BindConfig<string>(config, "Recipes", "Soul Anchor ingredients", "TrophyGreydwarfShaman:1,TrophyWolf:1,TrophyLox:1,FineWood:10", "Comma-separated prefab names and amounts, for example FineWood:10.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); val = (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100); TotemCraftAmount = ConfigFileExtensions.BindConfig<int>(config, "Recipes", "Soul Anchor crafted amount", 1, "Number of Soul Anchors created per craft.", true, (int?)null, val, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); MeadRecipe = ConfigFileExtensions.BindConfig<string>(config, "Recipes", "Eirs Brew ingredients", "Honey:20,Cloudberry:20,Bloodbag:10,FreezeGland:5,Thistle:10", "Comma-separated prefab names and amounts used at the mead ketill.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); val = (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100); FermenterYield = ConfigFileExtensions.BindConfig<int>(config, "Recipes", "Eirs Breath fermenter yield", 6, "Number of Eir's Breath potions produced from one mixture.", true, (int?)null, val, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); val = (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f); EffectVolume = ConfigFileExtensions.BindConfig<float>(config, "Effects", "Revival effect volume", 1f, "Volume multiplier for revival sounds. 0 is silent.", true, (int?)null, val, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); val = (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f); EffectStrength = ConfigFileExtensions.BindConfig<float>(config, "Effects", "Revival effect strength", 1f, "Multiplier for particles and revival light. 0 disables the visual burst and sparks.", true, (int?)null, val, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); ApplyRuntime(); } internal static void ApplyRuntime() { LifeWindow.RescueSeconds = RescueTime.Value; LifeWindow.RevivalCooldownSeconds = Cooldown.Value; LifeWindow.RestoredHealthFraction = RestoredHealth.Value / 100f; LifeWindow.GraceSeconds = ProtectionTime.Value; LifeWindow.TotemEnabled = TotemEnabled.Value; LifeWindow.PotionEnabled = PotionEnabled.Value; LifeWindow.SkillLossOnFinalDeath = SkillLossOnFinalDeath.Value; } internal static RequirementConfig[] ParseRecipe(string text, string fallback) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown List<RequirementConfig> list = new List<RequirementConfig>(); string[] array = (string.IsNullOrWhiteSpace(text) ? fallback : text).Split(','); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Trim().Split(':'); if (array2.Length == 2 && array2[0].Length > 0 && int.TryParse(array2[1], out var result) && result > 0) { list.Add(new RequirementConfig(array2[0].Trim(), result, 0, true)); } } if (list.Count == 0 && text != fallback) { return ParseRecipe(fallback, fallback); } return list.ToArray(); } } public static class LifeWindow { public const float RescueDistance = 3f; public static double RescueSeconds { get; internal set; } = 60.0; public static double GraceSeconds { get; internal set; } = 5.0; public static double RevivalCooldownSeconds { get; internal set; } = 30.0; public static float RestoredHealthFraction { get; internal set; } = 0.4f; public static bool TotemEnabled { get; internal set; } = true; public static bool PotionEnabled { get; internal set; } = true; public static bool SkillLossOnFinalDeath { get; internal set; } = true; public static bool CanRescue(double deadline, double now, float distance, bool rescuerAlive) { return deadline > now && distance <= 3f && rescuerAlive; } public static bool Expired(double deadline, double now) { if (deadline > 0.0) { return now >= deadline; } return false; } public static int Remaining(double deadline, double now) { return Math.Max(0, (int)Math.Ceiling(deadline - now)); } } public sealed class RevivalState : MonoBehaviour { internal const string DeadlineKey = "SA_deadline_v1"; internal const string ZdoDeadline = "SA_deadline"; internal const string EpochKey = "SA_epoch_v1"; internal const string CooldownKey = "SA_cooldown_v1"; internal const string ZdoCooldown = "SA_cooldown"; internal Player Player; internal ZNetView View; internal double Deadline; internal double GraceUntil; internal double CooldownUntil; internal bool Finalizing; internal double GiveUpHoldStarted; private bool restored; private int lastSecond = -1; private int lastGiveUpProgress = -1; private bool cooldownStatusApplied; private double nextSignalBroadcast; internal const double GiveUpHoldSeconds = 2.0; internal static double Now => (double)DateTime.UtcNow.Ticks / 10000000.0; internal bool Owned { get { if (Object.op_Implicit((Object)(object)View) && View.IsValid()) { return View.IsOwner(); } return false; } } internal bool Downed { get { if (!Finalizing) { if (!(Deadline > 0.0)) { if ((Object)(object)Player != (Object)null) { return Player.m_customData.ContainsKey("SA_deadline_v1"); } return false; } return true; } return false; } } internal bool Protected { get { if (!Downed) { return Now < GraceUntil; } return true; } } internal bool RevivalReady => Now >= CooldownUntil; internal static RevivalState Of(Character p) { if (!Object.op_Implicit((Object)(object)p)) { return null; } return ((Component)p).GetComponent<RevivalState>(); } internal static bool IsDown(Character p) { RevivalState revivalState = Of(p); if (revivalState != null && revivalState.Downed) { return true; } Player val = (Player)(object)((p is Player) ? p : null); if (Object.op_Implicit((Object)(object)val)) { return RemoteDeadline(val) > Now; } return false; } internal void RestoreAfterLoad() { restored = false; Deadline = 0.0; GraceUntil = 0.0; CooldownUntil = 0.0; Finalizing = false; GiveUpHoldStarted = 0.0; lastSecond = -1; lastGiveUpProgress = -1; cooldownStatusApplied = false; nextSignalBroadcast = 0.0; Restore(); } private void Awake() { Player = ((Component)this).GetComponent<Player>(); View = ((Component)this).GetComponent<ZNetView>(); } private void Restore() { if (restored || !Owned || (Object)(object)Player != (Object)(object)Player.m_localPlayer) { return; } restored = true; if (Player.m_customData.TryGetValue("SA_cooldown_v1", out var value) && double.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && !double.IsNaN(result) && !double.IsInfinity(result) && result > Now && result <= Now + LifeWindow.RevivalCooldownSeconds) { CooldownUntil = result; } else { Player.m_customData.Remove("SA_cooldown_v1"); } if (CooldownUntil > Now) { cooldownStatusApplied = RevivalEffects.PlayCooldown(Player, CooldownUntil - Now); } if (Player.m_customData.TryGetValue("SA_deadline_v1", out var value2)) { if (!double.TryParse(value2, NumberStyles.Float, CultureInfo.InvariantCulture, out Deadline) || double.IsNaN(Deadline) || double.IsInfinity(Deadline) || Deadline <= 0.0 || Deadline > Now + LifeWindow.RescueSeconds) { Deadline = Now - 1.0; } Publish(); ((Character)Player).SetHealth(1f); StopActions(); Pose(); } } private void Update() { //IL_023a: Unknown result type (might be due to invalid IL or missing references) Restore(); ((Character)Player).m_aiSkipTarget = IsDown((Character)(object)Player); if (!Owned || (Object)(object)Player != (Object)(object)Player.m_localPlayer) { return; } RescueNetwork.Retry(Player); if (CooldownUntil > Now && !cooldownStatusApplied) { cooldownStatusApplied = RevivalEffects.PlayCooldown(Player, CooldownUntil - Now); } if (GraceUntil > 0.0 && Now >= GraceUntil) { GraceUntil = 0.0; RevivalEffects.Stop(Player); Plugin.LogInfo("Revival protection ended and its effects were removed."); } if (CooldownUntil > 0.0 && Now >= CooldownUntil) { CooldownUntil = 0.0; cooldownStatusApplied = false; Player.m_customData.Remove("SA_cooldown_v1"); RevivalEffects.StopCooldown(Player); Publish(); } if (!Downed || Finalizing) { return; } if (Now >= nextSignalBroadcast) { nextSignalBroadcast = Now + 5.0; DownedSignals.Broadcast(Player, active: true, Math.Max(0.0, Deadline - Now)); } if (ZInput.GetKeyDown((KeyCode)114, true) || ZInput.GetButtonDown("JoyButtonY")) { FinalDeath(); return; } if (ZInput.GetButton("Use") || ZInput.GetButton("JoyUse")) { if (GiveUpHoldStarted <= 0.0) { GiveUpHoldStarted = Now; } if (Now - GiveUpHoldStarted >= 2.0) { FinalDeath(); return; } } else if (GiveUpHoldStarted > 0.0) { GiveUpHoldStarted = 0.0; lastGiveUpProgress = -1; } if (LifeWindow.Expired(Deadline, Now)) { FinalDeath(); } else { if (LifeWindow.TotemEnabled && RevivalReady && TryConsumeTotem()) { return; } ((Character)Player).SetMoveDir(Vector3.zero); int num = LifeWindow.Remaining(Deadline, Now); int num2 = ((GiveUpHoldStarted > 0.0) ? Math.Min(99, (int)((Now - GiveUpHoldStarted) / 2.0 * 100.0)) : (-1)); if (num != lastSecond || num2 != lastGiveUpProgress) { lastSecond = num; lastGiveUpProgress = num2; if (!((Character)Player).InEmote()) { Pose(); } string text = string.Format(Localization.instance.Localize("$sa_downed"), num); text = text + "\n" + RevivalUi.GiveUpHint(); if (num2 >= 0) { text = text + "\n" + string.Format(Localization.instance.Localize("$sa_giveup_progress"), num2); } int num3 = Math.Max(0, (int)Math.Ceiling(CooldownUntil - Now)); if (num3 > 0) { text = text + "\n" + string.Format(Localization.instance.Localize("$sa_downed_cooldown"), num3); } ((Character)Player).Message((MessageType)2, text, 0, (Sprite)null, false); if (num == 10 || num == 5 || num == 3) { RevivalUi.Warning(Player, num); } } } } internal bool InterceptDeath() { if (!Owned || Finalizing) { return false; } Restore(); if (Downed) { AccessTools.Field(typeof(Character), "m_isDead").SetValue(Player, false); return true; } if (Now < GraceUntil) { ((Character)Player).SetHealth(Mathf.Max(1f, ((Character)Player).GetHealth())); return true; } if (LifeWindow.TotemEnabled && RevivalReady && TryConsumeTotem()) { return true; } Deadline = Now + LifeWindow.RescueSeconds; Player.m_customData["SA_epoch_v1"] = Guid.NewGuid().ToString("N"); Player.m_customData["SA_deadline_v1"] = Deadline.ToString("R", CultureInfo.InvariantCulture); Publish(); ((Character)Player).SetHealth(1f); lastSecond = -1; lastGiveUpProgress = -1; GiveUpHoldStarted = 0.0; StopActions(); ((Character)Player).m_aiSkipTarget = true; Pose(); DownedSignals.Broadcast(Player, active: true, LifeWindow.RescueSeconds); nextSignalBroadcast = Now + 5.0; return true; } private bool TryConsumeTotem() { ItemData val = ((IEnumerable<ItemData>)((Humanoid)Player).GetInventory().GetAllItems()).FirstOrDefault((Func<ItemData, bool>)((ItemData i) => Object.op_Implicit((Object)(object)i.m_dropPrefab) && ((Object)i.m_dropPrefab).name == "SoulAnchor")); if (val == null || !((Humanoid)Player).GetInventory().RemoveItem(val, 1)) { return false; } Plugin.GiveBrokenTotem(Player); Revive(fromTotem: true); Plugin.Say(Player, "$sa_totem_used"); return true; } private void StopActions() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) ((Character)Player).SetMoveDir(Vector3.zero); AccessTools.Field(typeof(Player), "m_autoRun").SetValue(Player, false); AccessTools.Field(typeof(Character), "m_isDead").SetValue(Player, false); ((Character)Player).m_aiSkipTarget = true; FieldInfo fieldInfo = AccessTools.Field(typeof(Humanoid), "m_currentAttack"); object? value = fieldInfo.GetValue(Player); object? obj = ((value is Attack) ? value : null); if (obj != null) { ((Attack)obj).Stop(); } fieldInfo.SetValue(Player, null); string[] array = new string[6] { "m_attack", "m_attackHold", "m_secondaryAttack", "m_secondaryAttackHold", "m_blocking", "m_run" }; foreach (string text in array) { AccessTools.Field(typeof(Character), text).SetValue(Player, false); } AccessTools.Field(typeof(Humanoid), "m_attackDrawTime").SetValue(Player, 0f); AccessTools.Field(typeof(Player), "m_queuedDodgeTimer").SetValue(Player, 0f); Player.StopDoodadControl(); ((Character)Player).AttachStop(); if (Object.op_Implicit((Object)(object)InventoryGui.instance)) { InventoryGui.instance.Hide(); } } private void Pose() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) ((Character)Player).SetMoveDir(Vector3.zero); Player.StartEmote("sit", false); } private void Publish() { if (Owned) { double num = ((Deadline > 0.0) ? (ZNet.instance.GetTimeSeconds() + Math.Max(0.0, Deadline - Now)) : 0.0); View.GetZDO().Set("SA_deadline", (long)(num * 10000000.0)); double num2 = ((CooldownUntil > 0.0) ? (ZNet.instance.GetTimeSeconds() + Math.Max(0.0, CooldownUntil - Now)) : 0.0); View.GetZDO().Set("SA_cooldown", (long)(num2 * 10000000.0)); if (Player.m_customData.TryGetValue("SA_epoch_v1", out var value)) { View.GetZDO().Set("SA_epoch_v1", value); } } } internal void Revive(bool fromTotem = false) { GiveUpHoldStarted = 0.0; lastGiveUpProgress = -1; Deadline = 0.0; Player.m_customData.Remove("SA_deadline_v1"); Publish(); GraceUntil = Now + LifeWindow.GraceSeconds; CooldownUntil = Now + LifeWindow.RevivalCooldownSeconds; Player.m_customData["SA_cooldown_v1"] = CooldownUntil.ToString("R", CultureInfo.InvariantCulture); Publish(); AccessTools.Field(typeof(Character), "m_isDead").SetValue(Player, false); AccessTools.Method(typeof(Player), "StopEmote", (Type[])null, (Type[])null).Invoke(Player, null); ((Character)Player).m_aiSkipTarget = false; ((Character)Player).SetHealth(Mathf.Max(1f, ((Character)Player).GetMaxHealth() * LifeWindow.RestoredHealthFraction)); RevivalEffects.Play(Player, fromTotem); cooldownStatusApplied = RevivalEffects.PlayCooldown(Player, LifeWindow.RevivalCooldownSeconds); DownedSignals.Broadcast(Player, active: false, 0.0); Plugin.LogInfo($"Revival protection started for {LifeWindow.GraceSeconds:0.##} seconds; health restored to {((Character)Player).GetHealth():0.##}."); Plugin.Say(Player, "$sa_rescued"); } private void FinalDeath() { //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Expected O, but got Unknown Finalizing = true; GiveUpHoldStarted = 0.0; lastGiveUpProgress = -1; Deadline = 0.0; Player.m_customData.Remove("SA_deadline_v1"); Publish(); AccessTools.Method(typeof(Player), "StopEmote", (Type[])null, (Type[])null).Invoke(Player, null); ((Character)Player).m_aiSkipTarget = false; DownedSignals.Broadcast(Player, active: false, 0.0); RevivalUi.MarkLastDeath(Player); ((Character)Player).SetHealth(0f); AccessTools.Field(typeof(Character), "m_isDead").SetValue(Player, true); FieldInfo fieldInfo = AccessTools.Field(typeof(Character), "m_lastHit"); if (fieldInfo.GetValue(Player) == null) { fieldInfo.SetValue(Player, (object?)new HitData()); } OptionalSkillLoss.Suppress = !LifeWindow.SkillLossOnFinalDeath; try { ((Character)Player).OnDeath(); } finally { OptionalSkillLoss.Suppress = false; } } internal static double RemoteDeadline(Player p) { ZNetView val = (Object.op_Implicit((Object)(object)p) ? ((Component)p).GetComponent<ZNetView>() : null); if (!Object.op_Implicit((Object)(object)val) || !val.IsValid() || !Object.op_Implicit((Object)(object)ZNet.instance)) { return 0.0; } long num = val.GetZDO().GetLong("SA_deadline", 0L); if (num <= 0) { return 0.0; } return Now + (double)num / 10000000.0 - ZNet.instance.GetTimeSeconds(); } internal static double RemoteCooldown(Player p) { ZNetView val = (Object.op_Implicit((Object)(object)p) ? ((Component)p).GetComponent<ZNetView>() : null); if (!Object.op_Implicit((Object)(object)val) || !val.IsValid() || !Object.op_Implicit((Object)(object)ZNet.instance)) { return 0.0; } long num = val.GetZDO().GetLong("SA_cooldown", 0L); if (num <= 0) { return 0.0; } return Now + (double)num / 10000000.0 - ZNet.instance.GetTimeSeconds(); } } internal static class RescueNetwork { private const string Rpc = "SA_Rescue_v1"; private const string PendingKey = "SA_pending_v1"; private const string ReceiptPrefix = "SA_receipt_v1_"; private static ZRoutedRpc registered; private static double nextRetry; internal static void EnsureRegistered() { if (ZRoutedRpc.instance != null && registered != ZRoutedRpc.instance) { registered = ZRoutedRpc.instance; registered.Register<ZPackage>("SA_Rescue_v1", (Action<long, ZPackage>)Receive); } } internal static void Begin(Player user, Player target, ItemData item) { if (!LifeWindow.PotionEnabled) { return; } EnsureRegistered(); if (registered == null) { return; } if (user.m_customData.ContainsKey("SA_pending_v1")) { Plugin.Say(user, "$sa_pending"); return; } string text = ((Component)target).GetComponent<ZNetView>().GetZDO().GetString("SA_epoch_v1", ""); if (text.Length != 32) { Plugin.Say(user, "$sa_invalid"); return; } string text2 = Guid.NewGuid().ToString("N"); if (((Humanoid)user).GetInventory().RemoveItem(item, 1)) { user.m_customData["SA_pending_v1"] = target.GetPlayerID().ToString(CultureInfo.InvariantCulture) + "|" + ((Character)target).GetOwner().ToString(CultureInfo.InvariantCulture) + "|" + text2 + "|" + text; Plugin.Say(user, "$sa_sent"); nextRetry = 0.0; Retry(user); } } internal static void Retry(Player user) { //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Expected O, but got Unknown //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) if (!user.m_customData.TryGetValue("SA_pending_v1", out var value) || registered == null) { return; } if (value == "refund") { if (((Character)user).IsDead()) { return; } GameObject val = (Object.op_Implicit((Object)(object)ObjectDB.instance) ? ObjectDB.instance.GetItemPrefab("EirsBreath") : null); if (Object.op_Implicit((Object)(object)val)) { if (!((Humanoid)user).GetInventory().AddItem(val, 1)) { Object.Instantiate<GameObject>(val, ((Component)user).transform.position + Vector3.up, Quaternion.identity).GetComponent<ItemDrop>().m_itemData.m_stack = 1; } user.m_customData.Remove("SA_pending_v1"); Plugin.Say(user, "$sa_refund"); } } else { if (RevivalState.Now < nextRetry) { return; } nextRetry = RevivalState.Now + 2.0; string[] array = value.Split('|'); if (array.Length == 4 && long.TryParse(array[0], out var result)) { Player player = Player.GetPlayer(result); if (Object.op_Implicit((Object)(object)player)) { long owner = ((Character)player).GetOwner(); array[1] = owner.ToString(CultureInfo.InvariantCulture); user.m_customData["SA_pending_v1"] = string.Join("|", array); ZPackage val2 = new ZPackage(); val2.Write(0); val2.Write(result); val2.Write(user.GetPlayerID()); val2.Write(array[2]); val2.Write(array[3]); registered.InvokeRoutedRPC(owner, "SA_Rescue_v1", new object[1] { val2 }); } } } } private static void Reply(long peer, long targetId, string token, bool accepted) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write(1); val.Write(targetId); val.Write(token); val.Write(accepted); registered.InvokeRoutedRPC(peer, "SA_Rescue_v1", new object[1] { val }); } private static void Receive(long sender, ZPackage pkg) { //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer)) { return; } try { switch (pkg.ReadInt()) { case 0: { long num2 = pkg.ReadLong(); long num3 = pkg.ReadLong(); string text2 = pkg.ReadString(); string text3 = pkg.ReadString(); if (num2 != localPlayer.GetPlayerID() || text2.Length != 32 || text3.Length != 32 || !Guid.TryParseExact(text2, "N", out var result) || !Guid.TryParseExact(text3, "N", out result)) { break; } Player player = Player.GetPlayer(num3); if (!Object.op_Implicit((Object)(object)player) || (Object)(object)player == (Object)(object)localPlayer || ((Character)player).GetOwner() != sender) { break; } string key = "SA_receipt_v1_" + num3.ToString(CultureInfo.InvariantCulture) + "_" + text2; if (localPlayer.m_customData.TryGetValue(key, out var value2)) { Reply(sender, num2, text2, value2 == "1"); break; } RevivalState revivalState = RevivalState.Of((Character)(object)localPlayer); string value3; bool flag2 = LifeWindow.PotionEnabled && (Object)(object)revivalState != (Object)null && revivalState.Owned && revivalState.Downed && revivalState.RevivalReady && localPlayer.m_customData.TryGetValue("SA_epoch_v1", out value3) && value3 == text3 && LifeWindow.CanRescue(revivalState.Deadline, RevivalState.Now, Vector3.Distance(((Component)localPlayer).transform.position, ((Component)player).transform.position), !((Character)player).IsDead() && RevivalState.RemoteDeadline(player) <= 0.0) && HasLineOfSight(player, localPlayer); localPlayer.m_customData[key] = (flag2 ? "1" : "0"); if (flag2) { revivalState.Revive(); } Reply(sender, num2, text2, flag2); break; } case 1: { long num = pkg.ReadLong(); string text = pkg.ReadString(); bool flag = pkg.ReadBool(); if (!localPlayer.m_customData.TryGetValue("SA_pending_v1", out var value)) { break; } string[] array = value.Split('|'); if (array.Length == 4 && !(array[0] != num.ToString(CultureInfo.InvariantCulture)) && !(array[1] != sender.ToString(CultureInfo.InvariantCulture)) && !(array[2] != text)) { if (flag) { localPlayer.m_customData.Remove("SA_pending_v1"); RevivalEffects.PlayApplication(localPlayer, Player.GetPlayer(num)); Plugin.Say(localPlayer, "$sa_success"); } else { localPlayer.m_customData["SA_pending_v1"] = "refund"; Retry(localPlayer); } } break; } } } catch (Exception ex) { Plugin.Log("Rejected rescue message: " + ex.Message); } } private static bool HasLineOfSight(Player from, Player to) { //IL_003a: 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_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004f: 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_0059: Unknown result type (might be due to invalid IL or missing references) int mask = LayerMask.GetMask(new string[5] { "Default", "static_solid", "Default_small", "piece", "terrain" }); return !Physics.Linecast(((Component)from).transform.position + Vector3.up, ((Component)to).transform.position + Vector3.up, mask, (QueryTriggerInteraction)1); } } [HarmonyPatch(typeof(Player), "Awake")] internal static class PlayerSetup { private static void Postfix(Player __instance) { if (!Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<RevivalState>())) { ((Component)__instance).gameObject.AddComponent<RevivalState>(); } if (!Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<DownedIndicator>())) { ((Component)__instance).gameObject.AddComponent<DownedIndicator>(); } if (!Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<RescueChannel>())) { ((Component)__instance).gameObject.AddComponent<RescueChannel>(); } } } [HarmonyPatch(typeof(Player), "Load")] internal static class LoadedPlayer { private static void Postfix(Player __instance) { RevivalState.Of((Character)(object)__instance)?.RestoreAfterLoad(); Plugin.NormalizeBrokenTotems(__instance); } } [HarmonyPatch(typeof(Character), "CheckDeath")] internal static class CheckDeath { [HarmonyPriority(800)] private static bool Prefix(Character __instance) { RevivalState revivalState = RevivalState.Of(__instance); if (!((Object)(object)revivalState == (Object)null) && !revivalState.Finalizing && !(__instance.GetHealth() > 0f)) { return !revivalState.InterceptDeath(); } return true; } } [HarmonyPatch(typeof(Player), "OnDeath")] internal static class DirectDeath { [HarmonyPriority(800)] private static bool Prefix(Player __instance) { RevivalState revivalState = RevivalState.Of((Character)(object)__instance); if (revivalState == null) { return true; } return !revivalState.InterceptDeath(); } } [HarmonyPatch(typeof(Character), "SetHealth")] internal static class HealthGuard { private static void Prefix(Character __instance, ref float health) { RevivalState revivalState = RevivalState.Of(__instance); if (!((Object)(object)revivalState == (Object)null) && !revivalState.Finalizing && revivalState.Owned) { if (revivalState.Downed) { health = 1f; } else if (revivalState.Protected) { health = Mathf.Max(new float[3] { health, __instance.GetHealth(), 1f }); } } } } [HarmonyPatch(typeof(Character), "RPC_Damage")] internal static class DamageGuard { private static bool Prefix(Character __instance) { RevivalState revivalState = RevivalState.Of(__instance); if (revivalState == null) { return true; } return !revivalState.Protected; } } [HarmonyPatch(typeof(Character), "ApplyDamage")] internal static class DirectDamageGuard { private static bool Prefix(Character __instance) { RevivalState revivalState = RevivalState.Of(__instance); if (revivalState == null) { return true; } return !revivalState.Protected; } } [HarmonyPatch(typeof(Skills), "OnDeath")] internal static class OptionalSkillLoss { internal static bool Suppress; private static bool Prefix() { if (!Suppress) { return LifeWindow.SkillLossOnFinalDeath; } return false; } } [HarmonyPatch(typeof(Skills), "Clear")] internal static class OptionalFullSkillReset { private static bool Prefix() { return !OptionalSkillLoss.Suppress; } } [HarmonyPatch(typeof(Player), "SetControls")] internal static class Controls { private static bool Prefix(Player __instance) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) if (!RevivalState.IsDown((Character)(object)__instance)) { return true; } ((Character)__instance).SetMoveDir(Vector3.zero); return false; } } [HarmonyPatch(typeof(Player), "TakeInput")] internal static class InputGuard { private static void Postfix(Player __instance, ref bool __result) { if (RevivalState.IsDown((Character)(object)__instance)) { __result = false; } } } [HarmonyPatch(typeof(Humanoid), "StartAttack")] internal static class AttackGuard { private static bool Prefix(Humanoid __instance, ref bool __result) { if (!RevivalState.IsDown((Character)(object)__instance)) { return true; } __result = false; return false; } } [HarmonyPatch(typeof(Player), "Interact")] internal static class InteractGuard { private static bool Prefix(Player __instance) { return !RevivalState.IsDown((Character)(object)__instance); } } [HarmonyPatch(typeof(Player), "AutoPickup")] internal static class PickupGuard { private static bool Prefix(Player __instance) { return !RevivalState.IsDown((Character)(object)__instance); } } [HarmonyPatch(typeof(MonsterAI), "UpdateAI")] internal static class DownedTargetGuard { private static void Prefix(MonsterAI __instance) { FieldInfo fieldInfo = AccessTools.Field(typeof(MonsterAI), "m_targetCreature"); object? value = fieldInfo.GetValue(__instance); if (RevivalState.IsDown((Character)((value is Character) ? value : null))) { fieldInfo.SetValue(__instance, null); } } } [HarmonyPatch(typeof(Player), "InGhostMode")] internal static class DownedHuntTargetGuard { private static void Postfix(Player __instance, ref bool __result) { if (RevivalState.IsDown((Character)(object)__instance)) { __result = true; } } } [HarmonyPatch(typeof(Player), "StartGuardianPower")] internal static class PowerStartGuard { private static bool Prefix(Player __instance, ref bool __result) { if (!RevivalState.IsDown((Character)(object)__instance)) { return true; } __result = false; return false; } } [HarmonyPatch(typeof(Player), "ActivateGuardianPower")] internal static class PowerActivationGuard { private static bool Prefix(Player __instance, ref bool __result) { if (!RevivalState.IsDown((Character)(object)__instance)) { return true; } __result = false; return false; } } [HarmonyPatch(typeof(Player), "TeleportTo")] internal static class TeleportGuard { private static bool Prefix(Player __instance, ref bool __result) { if (!RevivalState.IsDown((Character)(object)__instance)) { return true; } __result = false; return false; } } [HarmonyPatch(typeof(InventoryGui), "Show")] internal static class InventoryGuard { private static bool Prefix() { if (RevivalState.IsDown((Character)(object)Player.m_localPlayer)) { return false; } Plugin.NormalizeBrokenTotems(Player.m_localPlayer); return true; } } [HarmonyPatch(typeof(InventoryGui), "CanRepair")] internal static class BrokenAnchorRepairEligibility { private static void Postfix(ItemData item, ref bool __result) { if (Object.op_Implicit((Object)(object)item?.m_dropPrefab) && ((Object)item.m_dropPrefab).name == "BrokenSoulAnchor") { Player localPlayer = Player.m_localPlayer; if (Plugin.IsBlackForge((localPlayer != null) ? localPlayer.GetCurrentCraftingStation() : null)) { __result = true; } } } } [HarmonyPatch(typeof(InventoryGui), "RepairOneItem")] internal static class BrokenAnchorRepairAction { private static bool Prefix() { return !Plugin.TryRepairBrokenTotem(); } } [HarmonyPatch(typeof(Player), "GetHoverText")] internal static class Hover { private static void Postfix(Player __instance, ref string __result) { double num = RevivalState.RemoteDeadline(__instance); if (!(num <= 0.0)) { __result = __instance.GetPlayerName() + "\n<color=#70e4cb>" + string.Format(Localization.instance.Localize("$sa_downed"), LifeWindow.Remaining(num, RevivalState.Now)) + "</color>\n" + Localization.instance.Localize("$sa_hint"); } } } [HarmonyPatch(typeof(Humanoid), "UseItem")] internal static class PotionUse { private static bool Prefix(Humanoid __instance, Inventory inventory, ItemData item, bool fromInventoryGui) { //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) if (RevivalState.IsDown((Character)(object)__instance)) { return false; } if (item == null || !Object.op_Implicit((Object)(object)item.m_dropPrefab) || ((Object)item.m_dropPrefab).name != "EirsBreath") { return true; } if (!LifeWindow.PotionEnabled) { return false; } Player val = (Player)(object)((__instance is Player) ? __instance : null); if (!Object.op_Implicit((Object)(object)val) || (Object)(object)val != (Object)(object)Player.m_localPlayer || ((Character)val).IsDead()) { return false; } GameObject hoverObject = ((Humanoid)val).GetHoverObject(); Player val2 = (Object.op_Implicit((Object)(object)hoverObject) ? hoverObject.GetComponentInParent<Player>() : null); double num = (Object.op_Implicit((Object)(object)val2) ? RevivalState.RemoteCooldown(val2) : 0.0); if (num > RevivalState.Now) { ((Character)val).Message((MessageType)2, string.Format(Localization.instance.Localize("$sa_cooldown"), Math.Max(1, (int)Math.Ceiling(num - RevivalState.Now))), 0, (Sprite)null, false); return false; } if (fromInventoryGui || !Object.op_Implicit((Object)(object)val2) || (Object)(object)val2 == (Object)(object)val || (inventory != null && inventory != ((Humanoid)val).GetInventory()) || !((Humanoid)val).GetInventory().ContainsItem(item) || !LifeWindow.CanRescue(RevivalState.RemoteDeadline(val2), RevivalState.Now, Vector3.Distance(((Component)val).transform.position, ((Component)val2).transform.position), !((Character)val).IsDead())) { Plugin.Say(val, "$sa_invalid"); return false; } ((Component)val).GetComponent<RescueChannel>().Begin(val2, item, inventory); return false; } } internal static class RevivalEffects { internal const string StatusName = "SA_RevivalGlow"; internal const string TotemStatusName = "SA_TotemRevivalGlow"; internal const string CooldownStatusName = "SA_RevivalCooldown"; private static Material sparkMaterial; private static StatusEffect glowEffect; private static StatusEffect totemGlowEffect; private static StatusEffect cooldownEffect; private static AudioClip revivalClip; internal static AudioClip RevivalAudioClip => revivalClip; internal static IEnumerator LoadAudio() { string text = Path.Combine(Paths.CachePath, "SoulAnchor"); string text2 = Path.Combine(text, "elemental-magic-spell-cast-d-228349.mp3"); try { Directory.CreateDirectory(text); using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Seelenanker.revival_sound.mp3"); if (stream == null) { throw new InvalidOperationException("Embedded revival sound is missing."); } using FileStream destination = File.Create(text2); stream.CopyTo(destination); } catch (Exception ex) { Plugin.Log("Revival sound extraction failed: " + ex.Message); yield break; } UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(new Uri(text2).AbsoluteUri, (AudioType)13); try { yield return request.SendWebRequest(); if ((int)request.result != 1) { Plugin.Log("Revival sound loading failed: " + request.error); yield break; } revivalClip = DownloadHandlerAudioClip.GetContent(request); if (Object.op_Implicit((Object)(object)revivalClip)) { ((Object)revivalClip).name = "SoulAnchor_ElementalMagicSpellCastD"; } } finally { ((IDisposable)request)?.Dispose(); } } internal static void Register(Sprite potionIcon, Sprite totemIcon, Sprite cooldownIcon) { glowEffect = CreateStatus("SA_RevivalGlow", "$sa_grace", "$sa_grace_desc", potionIcon, (float)LifeWindow.GraceSeconds); totemGlowEffect = CreateStatus("SA_TotemRevivalGlow", "$sa_totem_grace", "$sa_totem_grace_desc", totemIcon, (float)LifeWindow.GraceSeconds); cooldownEffect = CreateStatus("SA_RevivalCooldown", "$sa_revival_cooldown", "$sa_revival_cooldown_desc", cooldownIcon, (float)LifeWindow.RevivalCooldownSeconds); } private static StatusEffect CreateStatus(string id, string name, string tooltip, Sprite icon, float duration) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown StatusEffect val = ScriptableObject.CreateInstance<StatusEffect>(); ((Object)val).name = id; val.m_name = name; val.m_tooltip = tooltip; val.m_icon = icon; val.m_ttl = duration; val.m_cooldownIcon = id == "SA_RevivalCooldown"; if (!ItemManager.Instance.AddStatusEffect(new CustomStatusEffect(val, false))) { Plugin.Log("Could not register status " + id + ". Gameplay remains functional."); } return val; } internal static void Play(Player player, bool fromTotem) { if (!Object.op_Implicit((Object)(object)player)) { return; } try { StatusEffect val = (fromTotem ? totemGlowEffect : glowEffect); if (Object.op_Implicit((Object)(object)val) && LifeWindow.GraceSeconds > 0.0) { val.m_ttl = (float)LifeWindow.GraceSeconds; ((Character)player).GetSEMan().RemoveStatusEffect(val, true); ((Character)player).GetSEMan().AddStatusEffect(val, true, 0, 0f, (short)(-1)); StatusEffect statusEffect = ((Character)player).GetSEMan().GetStatusEffect(val.NameHash()); Plugin.LogInfo(string.Format("Revival status active={0}, icon={1}.", (Object)(object)statusEffect != (Object)null, (Object.op_Implicit((Object)(object)statusEffect) && Object.op_Implicit((Object)(object)statusEffect.m_icon)) ? "ready" : "missing")); } else { Plugin.Log("Revival status object is unavailable; protection remains active."); } } catch (Exception ex) { Plugin.Log("Revival status icon skipped: " + ex); } try { RevivalSparkController revivalSparkController = ((Component)player).GetComponent<RevivalSparkController>(); if (!Object.op_Implicit((Object)(object)revivalSparkController)) { revivalSparkController = ((Component)player).gameObject.AddComponent<RevivalSparkController>(); } revivalSparkController.Begin(LifeWindow.GraceSeconds, ResolveSparkMaterial(), ModSettings.EffectStrength.Value, ModSettings.EffectVolume.Value, fromTotem); } catch (Exception ex2) { Plugin.Log("Revival visual skipped: " + ex2); } } internal static bool PlayCooldown(Player player, double seconds) { if (!Object.op_Implicit((Object)(object)player) || !Object.op_Implicit((Object)(object)cooldownEffect) || seconds <= 0.0) { return false; } try { cooldownEffect.m_ttl = (float)seconds; ((Character)player).GetSEMan().RemoveStatusEffect(cooldownEffect, true); ((Character)player).GetSEMan().AddStatusEffect(cooldownEffect, true, 0, 0f, (short)(-1)); return (Object)(object)((Character)player).GetSEMan().GetStatusEffect(cooldownEffect.NameHash()) != (Object)null; } catch (Exception ex) { Plugin.Log("Cooldown status skipped: " + ex.Message); return false; } } internal static void StopCooldown(Player player) { if (!Object.op_Implicit((Object)(object)player)) { return; } try { ((Character)player).GetSEMan().RemoveStatusEffect(StringExtensionMethods.GetStableHashCode("SA_RevivalCooldown"), true); } catch (Exception ex) { Plugin.Log("Cooldown icon cleanup skipped: " + ex.Message); } } internal static void Stop(Player player) { if (!Object.op_Implicit((Object)(object)player)) { return; } try { ((Character)player).GetSEMan().RemoveStatusEffect(StringExtensionMethods.GetStableHashCode("SA_RevivalGlow"), true); ((Character)player).GetSEMan().RemoveStatusEffect(StringExtensionMethods.GetStableHashCode("SA_TotemRevivalGlow"), true); } catch (Exception ex) { Plugin.Log("Revival icon cleanup skipped: " + ex.Message); } try { ((Component)player).GetComponent<RevivalSparkController>()?.Finish(); } catch (Exception ex2) { Plugin.Log("Revival spark cleanup skipped: " + ex2.Message); } } private static Material ResolveSparkMaterial() { if (Object.op_Implicit((Object)(object)sparkMaterial)) { return sparkMaterial; } string[] array = new string[4] { "fx_chainlightning_hit", "ChainLightning", "ChainLightningRed", "vfx_Potion_health_medium" }; foreach (string text in array) { GameObject prefab = PrefabManager.Instance.GetPrefab(text); ParticleSystemRenderer val = (Object.op_Implicit((Object)(object)prefab) ? prefab.GetComponentInChildren<ParticleSystemRenderer>(true) : null); if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)((Renderer)val).sharedMaterial)) { sparkMaterial = ((Renderer)val).sharedMaterial; return sparkMaterial; } } array = new string[2] { "Lightning", "MeadHealthMedium" }; foreach (string text2 in array) { object obj; if (!(text2 == "Lightning")) { GameObject prefab2 = PrefabManager.Instance.GetPrefab(text2); obj = ((prefab2 == null) ? null : prefab2.GetComponent<ItemDrop>()?.m_itemData.m_shared.m_consumeStatusEffect); } else { ObjectDB instance = ObjectDB.instance; obj = ((instance != null) ? instance.GetStatusEffect(StringExtensionMethods.GetStableHashCode(text2)) : null); } StatusEffect val2 = (StatusEffect)obj; if (val2?.m_startEffects?.m_effectPrefabs == null) { continue; } EffectData[] effectPrefabs = val2.m_startEffects.m_effectPrefabs; foreach (EffectData val3 in effectPrefabs) { ParticleSystemRenderer val4 = (Object.op_Implicit((Object)(object)val3.m_prefab) ? val3.m_prefab.GetComponentInChildren<ParticleSystemRenderer>(true) : null); if (Object.op_Implicit((Object)(object)val4) && Object.op_Implicit((Object)(object)((Renderer)val4).sharedMaterial)) { sparkMaterial = ((Renderer)val4).sharedMaterial; return sparkMaterial; } } } return null; } internal static void PlayApplication(Player helper, Player target) { try { if (Object.op_Implicit((Object)(object)helper) && Object.op_Implicit((Object)(object)target) && !((Character)helper).IsDead() && !RevivalState.IsDown((Character)(object)helper) && !((Character)helper).InAttack() && !((Character)helper).InDodge()) { AccessTools.Method(typeof(Humanoid), "DoInteractAnimation", (Type[])null, (Type[])null).Invoke(helper, new object[1] { ((Component)target).gameObject }); } } catch (Exception ex) { Plugin.Log("Revival gesture skipped: " + ex.Message); } } } public sealed class RevivalSparkController : MonoBehaviour { private GameObject holder; private readonly List<LineRenderer> bolts = new List<LineRenderer>(); private Light aura; private ParticleSystem auraParticles; private double end; private float nextFlash; private float strength; internal void Begin(double seconds, Material material, float effectStrength, float volume, bool fromTotem) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: 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_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0258: Unknown result type (might be due to invalid IL or missing references) //IL_02a1: Unknown result type (might be due to invalid IL or missing references) //IL_02a7: Expected O, but got Unknown //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_02d5: Unknown result type (might be due to invalid IL or missing references) //IL_02f2: Unknown result type (might be due to invalid IL or missing references) //IL_0308: Unknown result type (might be due to invalid IL or missing references) //IL_031e: Unknown result type (might be due to invalid IL or missing references) //IL_033e: Unknown result type (might be due to invalid IL or missing references) //IL_0357: Unknown result type (might be due to invalid IL or missing references) //IL_035c: Unknown result type (might be due to invalid IL or missing references) //IL_0393: Unknown result type (might be due to invalid IL or missing references) //IL_0398: Unknown result type (might be due to invalid IL or missing references) //IL_03b1: Unknown result type (might be due to invalid IL or missing references) //IL_03c1: Unknown result type (might be due to invalid IL or missing references) //IL_03c6: Unknown result type (might be due to invalid IL or missing references) //IL_03f9: Unknown result type (might be due to invalid IL or missing references) //IL_0409: Unknown result type (might be due to invalid IL or missing references) //IL_040e: Unknown result type (might be due to invalid IL or missing references) //IL_042c: Unknown result type (might be due to invalid IL or missing references) //IL_043c: Unknown result type (might be due to invalid IL or missing references) //IL_0441: Unknown result type (might be due to invalid IL or missing references) //IL_044b: Unknown result type (might be due to invalid IL or missing references) //IL_0452: Expected O, but got Unknown //IL_046b: Unknown result type (might be due to invalid IL or missing references) //IL_0475: Unknown result type (might be due to invalid IL or missing references) //IL_047a: Unknown result type (might be due to invalid IL or missing references) //IL_0490: Unknown result type (might be due to invalid IL or missing references) //IL_049a: Unknown result type (might be due to invalid IL or missing references) //IL_049f: Unknown result type (might be due to invalid IL or missing references) //IL_04b5: Unknown result type (might be due to invalid IL or missing references) //IL_04bf: Unknown result type (might be due to invalid IL or missing references) //IL_04c4: Unknown result type (might be due to invalid IL or missing references) //IL_04db: Unknown result type (might be due to invalid IL or missing references) //IL_04e0: Unknown result type (might be due to invalid IL or missing references) //IL_04f1: Unknown result type (might be due to invalid IL or missing references) //IL_04f6: Unknown result type (might be due to invalid IL or missing references) //IL_0507: Unknown result type (might be due to invalid IL or missing references) //IL_050c: Unknown result type (might be due to invalid IL or missing references) //IL_051d: Unknown result type (might be due to invalid IL or missing references) //IL_0522: Unknown result type (might be due to invalid IL or missing references) //IL_0530: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Expected O, but got Unknown //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) Finish(); end = RevivalState.Now + seconds; strength = effectStrength; holder = new GameObject("SA_RevivalSparks"); holder.layer = 0; holder.transform.position = ((Component)this).transform.position + Vector3.up * 0.9f; PlayRevivalSound(fromTotem, volume); int num = Mathf.Max(1, Mathf.RoundToInt(11f * strength)); for (int i = 0; i < num; i++) { if (!(strength > 0f)) { break; } GameObject val = new GameObject("SA_BodyLightning") { layer = 0 }; val.transform.SetParent(holder.transform, false); LineRenderer val2 = val.AddComponent<LineRenderer>(); val2.useWorldSpace = false; val2.positionCount = 5; val2.alignment = (LineAlignment)0; val2.numCapVertices = 2; val2.widthMultiplier = Mathf.Lerp(0.007f, 0.018f, Mathf.Clamp01(strength / 3f)); val2.textureMode = (LineTextureMode)0; if (Object.op_Implicit((Object)(object)material)) { ((Renderer)val2).sharedMaterial = material; } Gradient val3 = new Gradient(); val3.SetKeys((GradientColorKey[])(object)new GradientColorKey[3] { new GradientColorKey(new Color(0.65f, 0.4f, 1f), 0f), new GradientColorKey(new Color(0.96f, 0.88f, 1f), 0.4f), new GradientColorKey(Color.white, 1f) }, (GradientAlphaKey[])(object)new GradientAlphaKey[4] { new GradientAlphaKey(0.35f, 0f), new GradientAlphaKey(1f, 0.12f), new GradientAlphaKey(1f, 0.86f), new GradientAlphaKey(0.1f, 1f) }); val2.colorGradient = val3; bolts.Add(val2); } RefreshBolts(); aura = holder.AddComponent<Light>(); aura.type = (LightType)2; aura.color = new Color(0.68f, 0.42f, 1f); aura.range = 2.9f * strength; aura.intensity = 1.8f * strength; aura.shadows = (LightShadows)0; GameObject val4 = new GameObject("SA_RevivalAura"); val4.transform.SetParent(holder.transform, false); auraParticles = val4.AddComponent<ParticleSystem>(); MainModule main = auraParticles.main; ((MainModule)(ref main)).loop = true; ((MainModule)(ref main)).playOnAwake = false; ((MainModule)(ref main)).startLifetime = new MinMaxCurve(0.9f, 1.55f); ((MainModule)(ref main)).startSpeed = new MinMaxCurve(0.045f, 0.15f); ((MainModule)(ref main)).startSize = new MinMaxCurve(0.085f, 0.19f); ((MainModule)(ref main)).startColor = new MinMaxGradient(new Color(0.6f, 0.34f, 1f, 0.24f), new Color(1f, 0.92f, 1f, 0.58f)); ((MainModule)(ref main)).maxParticles = Mathf.Max(18, Mathf.RoundToInt(42f * strength)); ((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)0; EmissionModule emission = auraParticles.emission; ((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(Mathf.Max(9f, 23f * strength)); ShapeModule shape = auraParticles.shape; ((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)0; ((ShapeModule)(ref shape)).radius = 0.72f; ((ShapeModule)(ref shape)).radiusThickness = 0.12f; ((ShapeModule)(ref shape)).scale = new Vector3(0.82f, 1.48f, 0.72f); VelocityOverLifetimeModule velocityOverLifetime = auraParticles.velocityOverLifetime; ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).enabled = true; ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).space = (ParticleSystemSimulationSpace)0; ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).y = new MinMaxCurve(0.11f, 0.28f); ColorOverLifetimeModule colorOverLifetime = auraParticles.colorOverLifetime; ((ColorOverLifetimeModule)(ref colorOverLifetime)).enabled = true; Gradient val5 = new Gradient(); val5.SetKeys((GradientColorKey[])(object)new GradientColorKey[3] { new GradientColorKey(new Color(0.62f, 0.38f, 1f), 0f), new GradientColorKey(new Color(0.96f, 0.88f, 1f), 0.55f), new GradientColorKey(new Color(0.58f, 0.3f, 1f), 1f) }, (GradientAlphaKey[])(object)new GradientAlphaKey[4] { new GradientAlphaKey(0f, 0f), new GradientAlphaKey(0.62f, 0.18f), new GradientAlphaKey(0.38f, 0.72f), new GradientAlphaKey(0f, 1f) }); ((ColorOverLifetimeModule)(ref colorOverLifetime)).color = MinMaxGradient.op_Implicit(val5); ParticleSystemRenderer component = ((Component)auraParticles).GetComponent<ParticleSystemRenderer>(); component.renderMode = (ParticleSystemRenderMode)0; ((Renderer)component).sortingOrder = 2; if (Object.op_Implicit((Object)(object)material)) { ((Renderer)component).sharedMaterial = material; } auraParticles.Play(); } private void PlayRevivalSound(bool fromTotem, float volume) { //IL_0025: 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) if (!(volume <= 0f)) { if (!Object.op_Implicit((Object)(object)RevivalEffects.RevivalAudioClip)) { Plugin.Log("Revival sound is not loaded yet."); return; } GameObject val = new GameObject("SA_RevivalAudio"); val.transform.SetParent(holder.transform, false); AudioSource obj = val.AddComponent<AudioSource>(); obj.clip = RevivalEffects.RevivalAudioClip; obj.spatialBlend = 0.82f; obj.rolloffMode = (AudioRolloffMode)1; obj.minDistance = 1.5f; obj.maxDistance = 24f; obj.volume = Mathf.Clamp01(0.5f * volume); obj.Play(); } } private static Vector3 BodyPoint() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) float num = Random.Range(0f, MathF.PI * 2f); float num2 = Random.Range(0.12f, 0.62f); return new Vector3(Mathf.Cos(num) * num2, Random.Range(-0.98f, 1.02f), Mathf.Sin(num) * num2); } private void RefreshBolts() { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0051: 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_006c: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: 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_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) nextFlash = Time.time + Random.Range(0.045f, 0.11f); foreach (LineRenderer bolt in bolts) { if (!(((Renderer)bolt).enabled = Random.value > 0.18f)) { continue; } Vector3 val = BodyPoint(); Vector3 val2 = BodyPoint(); for (int i = 0; i < bolt.positionCount; i++) { float num = (float)i / (float)(bolt.positionCount - 1); Vector3 val3 = Vector3.Lerp(val, val2, num); if (i > 0 && i < bolt.positionCount - 1) { val3 += Random.insideUnitSphere * 0.13f; } bolt.SetPosition(i, val3); } } } private void Update() { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: 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_0057: Unknown result type (might be due to invalid IL or missing references) if (end > 0.0 && RevivalState.Now >= end) { Finish(); return; } if (Object.op_Implicit((Object)(object)holder)) { holder.transform.position = ((Component)this).transform.position + Vector3.up * 0.9f; } if (Time.time >= nextFlash) { RefreshBolts(); } if (Object.op_Implicit((Object)(object)aura)) { aura.intensity = (1.15f + Mathf.Abs(Mathf.Sin(Time.time * 18f)) * 1.25f) * strength; } } internal void Finish() { end = 0.0; bolts.Clear(); aura = null; auraParticles = null; if (Object.op_Implicit((Object)(object)holder)) { Object.Destroy((Object)(object)holder); } holder = null; } private void OnDestroy() { Finish(); } } internal static class RevivalUi { private static Sprite circleSprite; private static AudioClip warningClip; internal static Sprite SoulIcon { get; private set; } internal static void Register(Sprite soulIcon) { SoulIcon = soulIcon; } internal static string GiveUpHint() { string text = ((ZInput.instance != null) ? ZInput.instance.GetBoundKeyString("JoyButtonY", false) : ""); if (string.IsNullOrWhiteSpace(text)) { text = Localization.instance.Localize("$settings_none"); } return string.Format(Localization.instance.Localize("$sa_giveup_hint"), text); } internal static Sprite CircleSprite() { //IL_0018: 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_0029: Expected O, but got Unknown //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)circleSprite)) { return circleSprite; } Texture2D val = new Texture2D(96, 96, (TextureFormat)4, false) { name = "SA_ProgressCircle" }; Color32[] array = (Color32[])(object)new Color32[9216]; for (int i = 0; i < 96; i++) { for (int j = 0; j < 96; j++) { float num = ((float)j + 0.5f) / 96f * 2f - 1f; float num2 = ((float)i + 0.5f) / 96f * 2f - 1f; float num3 = Mathf.Sqrt(num * num + num2 * num2); byte b = (byte)((num3 <= 1f && num3 >= 0.68f) ? byte.MaxValue : 0); array[i * 96 + j] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, b); } } val.SetPixels32(array); val.Apply(false, true); circleSprite = Sprite.Create(val, new Rect(0f, 0f, 96f, 96f), new Vector2(0.5f, 0.5f)); return circleSprite; } internal static void Warning(Player player, int seconds) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)player) && !((Object)(object)player != (Object)(object)Player.m_localPlayer)) { ((Character)player).Message((MessageType)2, string.Format(Localization.instance.Localize("$sa_warning"), seconds), 0, (Sprite)null, false); if (!Object.op_Implicit((Object)(object)warningClip)) { warningClip = CreateWarningClip(); } AudioSource.PlayClipAtPoint(warningClip, ((Component)player).transform.position, Mathf.Clamp01(ModSettings.EffectVolume.Value)); } } private static AudioClip CreateWarningClip() { int num = Mathf.CeilToInt(4851f); float[] array = new float[num]; for (int i = 0; i < num; i++) { float num2 = (float)i / 22050f; float num3 = Mathf.Clamp01(num2 / 0.012f) * Mathf.Clamp01((0.22f - num2) / 0.09f); array[i] = Mathf.Sin(MathF.PI * 2f * (680f + num2 * 520f) * num2) * num3 * 0.42f; } AudioClip obj = AudioClip.Create("SoulAnchor_RescueWarning", num, 1, 22050, false); obj.SetData(array, 0); return obj; } internal static void MarkLastDeath(Player player) { //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)player) || (Object)(object)player != (Object)(object)Player.m_localPlayer || !Object.op_Implicit((Object)(object)Minimap.instance)) { return; } try { if (AccessTools.Field(typeof(Minimap), "m_pins").GetValue(Minimap.instance) is List<PinData> collection) { foreach (PinData item in new List<PinData>(collection)) { if (item.m_name == "$sa_last_death") { Minimap.instance.RemovePin(item); } } } PinData obj = Minimap.instance.AddPin(((Component)player).transform.position, (PinType)4, "$sa_last_death", true, false, player.GetPlayerID(), default(PlatformUserID)); obj.m_doubleSize = false; obj.m_animate = false; } catch (Exception ex) { Plugin.Log("Last-death marker skipped: " + ex.Message); } } } public sealed class DownedIndicator : MonoBehaviour { private Player player; private GameObject marker; private SpriteRenderer icon; private TextMesh label; private void Awake() { player = ((Component)this).GetComponent<Player>(); } private void Update() { //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)player) || (Object)(object)player == (Object)(object)Player.m_localPlayer) { Hide(); return; } double num = RevivalState.RemoteDeadline(player); if (num <= RevivalState.Now) { Hide(); return; } Ensure(); if (!Object.op_Implicit((Object)(object)icon.sprite)) { icon.sprite = RevivalUi.SoulIcon; } marker.SetActive(true); marker.transform.position = ((Component)player).transform.position + Vector3.up * 2.35f; if (Object.op_Implicit((Object)(object)Camera.main)) { marker.transform.rotation = Quaternion.LookRotation(marker.transform.position - ((Component)Camera.main).transform.position); } int num2 = LifeWindow.Remaining(num, RevivalState.Now); int num3 = (Object.op_Implicit((Object)(object)Player.m_localPlayer) ? Mathf.CeilToInt(Vector3.Distance(((Component)Player.m_localPlayer).transform.position, ((Component)player).transform.position)) : 0); label.text = ((num3 > 0) ? (num2 + " s • " + num3 + " m") : (num2 + " s")); float num4 = 0.78f + Mathf.Abs(Mathf.Sin(Time.time * 4.5f)) * 0.22f; icon.color = new Color(0.78f, 0.52f, 1f, num4); } private void Ensure() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006a: 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_00a8: Expected O, but got Unknown //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)marker)) { marker = new GameObject("SA_DownedSoulMarker"); GameObject val = new GameObject("Soul"); val.transform.SetParent(marker.transform, false); val.transform.localPosition = Vector3.up * 0.26f; val.transform.localScale = Vector3.one * 0.34f; icon = val.AddComponent<SpriteRenderer>(); icon.sprite = RevivalUi.SoulIcon; ((Renderer)icon).sortingOrder = 80; GameObject val2 = new GameObject("RescueTimeDistance"); val2.transform.SetParent(marker.transform, false); val2.transform.localPosition = Vector3.down * 0.16f; label = val2.AddComponent<TextMesh>(); label.anchor = (TextAnchor)4; label.alignment = (TextAlignment)1; label.characterSize = 0.027f; label.fontSize = 42; label.color = new Color(0.84f, 0.72f, 1f, 1f); label.text = ""; } } private void Hide() { if (Object.op_Implicit((Object)(object)marker)) { marker.SetActive(false); } } private void OnDestroy() { if (Object.op_Implicit((Object)(object)marker)) { Object.Destroy((Object)(object)marker); } } } public sealed class RescueChannel : MonoBehaviour { private Player user; private Player target; private ItemData item; private Inventory inventory; private double started; private GameObject canvasObject; private Image fill; private void Awake() { user = ((Component)this).GetComponent<Player>(); } internal void Begin(Player rescueTarget, ItemData potion, Inventory source) { if (Object.op_Implicit((Object)(object)user) && !((Object)(object)user != (Object)(object)Player.m_localPlayer) && !Object.op_Implicit((Object)(object)target)) { target = rescueTarget; item = potion; inventory = source; started = RevivalState.Now; RevivalEffects.PlayApplication(user, target); ShowProgress(); } } private void Update() { //IL_0078: 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) if (!Object.op_Implicit((Object)(object)target)) { return; } double deadline = RevivalState.RemoteDeadline(target); if (!Object.op_Implicit((Object)(object)user) || ((Character)user).IsDead() || RevivalState.IsDown((Character)(object)user) || inventory != ((Humanoid)user).GetInventory() || !inventory.ContainsItem(item) || !LifeWindow.CanRescue(deadline, RevivalState.Now, Vector3.Distance(((Component)user).transform.position, ((Component)target).transform.position), rescuerAlive: true) || ZInput.GetKeyDown((KeyCode)27, true)) { Cancel(); return; } float num = Mathf.Clamp01((float)((RevivalState.Now - started) / (double)ModSettings.RevivalDuration.Value)); if (Object.op_Implicit((Object)(object)fill)) { fill.fillAmount = num; } if (!(num < 1f)) { Player val = target; ItemData val2 = item; Cancel(); RescueNetwork.Begin(user, val, val2); } } private void ShowProgress() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) canvasObject = new GameObject("SA_RevivalProgress"); Canvas obj = canvasObject.AddComponent<Canvas>(); obj.renderMode = (RenderMode)0; obj.sortingOrder = 400; canvasObject.AddComponent<CanvasScaler>(); CreateCircle("Background", new Color(0.05f, 0.03f, 0.09f, 0.72f)); fill = CreateCircle("Progress", new Color(0.76f, 0.48f, 1f, 0.95f)); fill.type = (Type)3; fill.fillMethod = (FillMethod)4; fill.fillOrigin = 2; fill.fillClockwise = true; fill.fillAmount = 0f; } private Image CreateCircle(string name, Color color) { //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_002e: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0053: 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) //IL_0078: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name); val.transform.SetParent(canvasObject.transform, false); Image obj = val.AddComponent<Image>(); obj.sprite = RevivalUi.CircleSprite(); ((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.sizeDelta = new Vector2(84f, 84f); rectTransform.anchoredPosition = new Vector2(0f, -72f); return obj; } private void Cancel() { target = null; item = null; inventory = null; if (Object.op_Implicit((Object)(object)canvasObject)) { Object.Destroy((Object)(object)canvasObject); } canvasObject = null; fill = null; } private void OnDestroy() { Cancel(); } } internal static class DownedSignals { private sealed class Signal { internal string Name; internal Vector3 Position; internal double Deadline; internal PinData Pin; } private const string Rpc = "SA_DownedSignal_v1"; private static ZRoutedRpc registered; private static readonly Dictionary<long, Signal> signals = new Dictionary<long, Signal>(); internal static void EnsureRegistered() { if (ZRoutedRpc.instance != null && registered != ZRoutedRpc.instance) { registered = ZRoutedRpc.instance; registered.Register<ZPackage>("SA_DownedSignal_v1", (Action<long, ZPackage>)Receive); signals.Clear(); } } internal static void Broadcast(Player player, bool active, double seconds) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_0041: 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_006d: Unknown result type (might be due to invalid IL or missing references) EnsureRegistered(); if (registered != null && Object.op_Implicit((Object)(object)player)) { ZPackage val = new ZPackage(); val.Write(player.GetPlayerID()); val.Write(active); val.Write(player.GetPlayerName()); val.Write(((Component)player).transform.position.x); val.Write(((Component)player).transform.position.y); val.Write(((Component)player).transform.position.z); val.Write(Math.Max(0.0, Math.Min(seconds, LifeWindow.RescueSeconds))); registered.InvokeRoutedRPC(0L, "SA_DownedSignal_v1", new object[1] { val }); } } private static void Receive(long sender, ZPackage package) { //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) try { long num = package.ReadLong(); bool flag =