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 Deathlink v0.10.2
plugins/Deathlink.dll
Decompiled 2 weeks 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.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Versioning; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using AlmanacClasses.API; using AzuExtendedPlayerInventory; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Deathlink.Common; using Deathlink.Death; using Deathlink.external; using HarmonyLib; using JetBrains.Annotations; using Jotunn; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using SimpleJson; using Splatform; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; using YamlDotNet.Serialization; using YamlDotNet.Serialization.NamingConventions; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("ValRougelike")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ValRougelike")] [assembly: AssemblyCopyright("Copyright © 2021")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")] [assembly: AssemblyFileVersion("0.0.1.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.1.0")] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace Backpacks { [PublicAPI] public static class API { public static EpicMMOSystem_API.API_State state; private static MethodInfo eCountItemsInBackpacks; private static MethodInfo eAddItemToBackpack; private static MethodInfo eDeleteItemsFromBackpacks; private static MethodInfo eGetEquippedBackpackInventory; private static MethodInfo eGetAllBackpackInventories; public static int CountItemsInBackpacks(Inventory inventory, string name, bool onlyRemoveable = true) { return (int)eCountItemsInBackpacks?.Invoke(null, new object[3] { inventory, name, onlyRemoveable }); } public static bool IsItemInBackpacks(Inventory inventory, string name) { return CountItemsInBackpacks(inventory, name) > 0; } public static bool AddItemToBackpack(ItemData backpack, ItemData item) { return (bool)eAddItemToBackpack?.Invoke(null, new object[2] { backpack, item }); } public static bool DeleteItemsFromBackpacks(Inventory inventory, string name, int count = 1) { return (bool)eDeleteItemsFromBackpacks?.Invoke(null, new object[3] { inventory, name, count }); } public static Inventory? GetEquippedBackpackInventory() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown return (Inventory)(eGetEquippedBackpackInventory?.Invoke(null, new object[0])); } public static List<Inventory> GetAllBackpackInventories(Inventory inventory) { return (List<Inventory>)(eGetAllBackpackInventories?.Invoke(null, new object[1] { inventory })); } public static void Init() { EpicMMOSystem_API.API_State aPI_State = state; if ((uint)(aPI_State - 1) > 1u) { if (Type.GetType("Backpacks.API, Backpacks") == null) { state = EpicMMOSystem_API.API_State.NotInstalled; return; } state = EpicMMOSystem_API.API_State.Ready; Type? type = Type.GetType("Backpacks.API, Backpacks"); eCountItemsInBackpacks = type.GetMethod("CountItemsInBackpacks", BindingFlags.Static | BindingFlags.Public); eAddItemToBackpack = type.GetMethod("AddItemToBackpack", BindingFlags.Static | BindingFlags.Public); eDeleteItemsFromBackpacks = type.GetMethod("DeleteItemsFromBackpacks", BindingFlags.Static | BindingFlags.Public); eGetEquippedBackpackInventory = type.GetMethod("GetEquippedBackpackInventory", BindingFlags.Static | BindingFlags.Public); eGetAllBackpackInventories = type.GetMethod("GetAllBackpackInventories", BindingFlags.Static | BindingFlags.Public); } } } } namespace AzuExtendedPlayerInventory { [PublicAPI] public class API { public delegate void SlotAddedHandler(string slotName); public delegate void SlotRemovedHandler(string slotName); public static event Action<Hud>? OnHudAwake; public static event Action<Hud>? OnHudAwakeComplete; public static event Action<Hud>? OnHudUpdate; public static event Action<Hud>? OnHudUpdateComplete; public static event SlotAddedHandler? SlotAdded; public static event SlotRemovedHandler? SlotRemoved; public static bool IsLoaded() { return false; } public static bool AddSlot(string slotName, Func<Player, ItemData?> getItem, Func<ItemData, bool> isValid, int index = -1) { return false; } public static bool RemoveSlot(string slotName) { return false; } public static SlotInfo GetSlots() { return new SlotInfo(); } public static SlotInfo GetQuickSlots() { return new SlotInfo(); } public static List<ItemData> GetQuickSlotsItems() { return new List<ItemData>(); } public static int GetAddedRows(int width) { return 0; } } [PublicAPI] public class SlotInfo { public string[] SlotNames { get; set; } = new string[0]; public Vector2[] SlotPositions { get; set; } = (Vector2[])(object)new Vector2[0]; public Func<Player, ItemData?>?[] GetItemFuncs { get; set; } = new Func<Player, ItemData>[0]; public Func<ItemData, bool>?[] IsValidFuncs { get; set; } = new Func<ItemData, bool>[0]; } } namespace AlmanacClasses.API { public static class ClassesAPI { private static readonly MethodInfo? API_AddExperience; private static readonly MethodInfo? API_GetLevel; private static readonly MethodInfo? API_GetCharacteristic; public static void AddEXP(int amount) { API_AddExperience?.Invoke(null, new object[1] { amount }); } public static int GetLevel() { return (int)(API_GetLevel?.Invoke(null, null) ?? ((object)0)); } public static int GetCharacteristic(string type) { return (int)(API_GetCharacteristic?.Invoke(null, new object[1] { type }) ?? ((object)0)); } public static int GetConstitution() { return GetCharacteristic("Constitution"); } public static int GetDexterity() { return GetCharacteristic("Dexterity"); } public static int GetStrength() { return GetCharacteristic("Strength"); } public static int GetIntelligence() { return GetCharacteristic("Intelligence"); } public static int GetWisdom() { return GetCharacteristic("Wisdom"); } static ClassesAPI() { Type type = Type.GetType("AlmanacClasses.API.API, AlmanacClasses"); if ((object)type != null) { API_AddExperience = type.GetMethod("AddExperience", BindingFlags.Static | BindingFlags.Public); API_GetLevel = type.GetMethod("GetLevel", BindingFlags.Static | BindingFlags.Public); API_GetCharacteristic = type.GetMethod("GetCharacteristic", BindingFlags.Static | BindingFlags.Public); } } } } namespace Deathlink { internal class Logger { public static LogLevel Level = (LogLevel)16; public static void enableDebugLogging(object sender, EventArgs e) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (ValConfig.EnableDebugMode.Value) { Level = (LogLevel)32; } else { Level = (LogLevel)16; } } public static void CheckEnableDebugLogging() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (ValConfig.EnableDebugMode.Value) { Level = (LogLevel)32; } else { Level = (LogLevel)16; } } public static void LogDebug(string message) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 if ((int)Level >= 32) { Deathlink.Log.LogInfo((object)message); } } public static void LogInfo(string message) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 if ((int)Level >= 16) { Deathlink.Log.LogInfo((object)message); } } public static void LogWarning(string message) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 if ((int)Level >= 4) { Deathlink.Log.LogWarning((object)message); } } public static void LogError(string message) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 if ((int)Level >= 2) { Deathlink.Log.LogError((object)message); } } } public static class Extensions { private static readonly List<ItemType> EquipmentTypes = new List<ItemType> { (ItemType)7, (ItemType)12, (ItemType)6, (ItemType)11, (ItemType)4, (ItemType)5, (ItemType)19, (ItemType)17, (ItemType)18, (ItemType)3, (ItemType)14, (ItemType)22, (ItemType)20, (ItemType)24 }; public static List<ItemData> GetEquipment(this List<ItemData> list) { return list.Where((ItemData x) => EquipmentTypes.Contains(x.m_shared.m_itemType)).ToList(); } public static List<ItemData> GetNotEquipment(this List<ItemData> list) { return list.Where((ItemData x) => !EquipmentTypes.Contains(x.m_shared.m_itemType)).ToList(); } public static bool IsEquipment(this ItemData item) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) if (EquipmentTypes.Contains(item.m_shared.m_itemType)) { return true; } return false; } } [BepInPlugin("MidnightsFX.Deathlink", "Deathlink", "0.10.2")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] internal class Deathlink : BaseUnityPlugin { public const string PluginGUID = "MidnightsFX.Deathlink"; public const string PluginName = "Deathlink"; public const string PluginVersion = "0.10.2"; public ValConfig cfg; internal static AssetBundle EmbeddedResourceBundle; internal static bool AzuEPILoaded = false; internal static bool RustyAlmanacClassesLoaded = false; internal static bool WackyMMOLoaded = false; public static CustomLocalization Localization = LocalizationManager.Instance.GetLocalization(); public static ManualLogSource Log; public void Awake() { Log = ((BaseUnityPlugin)this).Logger; cfg = new ValConfig(((BaseUnityPlugin)this).Config); AddLocalizations(); EmbeddedResourceBundle = AssetUtils.LoadAssetBundleFromResources("Deathlink.AssetsEmbedded.deathless", typeof(Deathlink).Assembly); DeathProgressionSkill.SetupDeathSkill(); if (API.IsLoaded()) { AzuEPILoaded = true; } if (Enumerable.Contains(BepInExUtils.GetPlugins(false).Keys, "WackyMole.EpicMMOSystem")) { EpicMMOSystem_API.Init(); if (EpicMMOSystem_API.state == EpicMMOSystem_API.API_State.Ready) { WackyMMOLoaded = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)"WackMMO API loaded."); } else { ((BaseUnityPlugin)this).Logger.LogInfo((object)"WackMMO API installed but API not ready."); } } if (Enumerable.Contains(BepInExUtils.GetPlugins(false).Keys, "RustyMods.AlmanacClasses")) { RustyAlmanacClassesLoaded = true; } Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), (string)null); DeathConfigurationData.Init(); LeaderboardData.Init(); ((MonoBehaviour)this).StartCoroutine(LeaderboardData.SyncLoop()); TerminalCommands.AddCommands(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Death is not the end."); } public static DataObjects.DeathChoiceLevel pcfg() { return DeathConfigurationData.playerDeathConfiguration; } private void AddLocalizations() { Localization = LocalizationManager.Instance.GetLocalization(); string text = Path.Combine(Paths.ConfigPath, "Deathlink", "localizations"); Directory.CreateDirectory(text); string[] manifestResourceNames = typeof(Deathlink).Assembly.GetManifestResourceNames(); foreach (string text2 in manifestResourceNames) { if (!text2.Contains("Localizations")) { continue; } string text3 = Regex.Replace(ReadEmbeddedResourceFile(text2), "\\/\\/.*", ""); Dictionary<string, string> internal_localization = SimpleJson.DeserializeObject<Dictionary<string, string>>(text3); string[] array = text2.Split(new char[1] { '.' }); if (File.Exists(text + "/" + array[2] + ".json")) { string text4 = File.ReadAllText(text + "/" + array[2] + ".json"); try { Dictionary<string, string> dictionary = SimpleJson.DeserializeObject<Dictionary<string, string>>(text4); UpdateLocalizationWithMissingKeys(internal_localization, dictionary); ((BaseUnityPlugin)this).Logger.LogDebug((object)("Reading " + text + "/" + array[2] + ".json")); File.WriteAllText(text + "/" + array[2] + ".json", SimpleJson.SerializeObject((object)dictionary)); string text5 = File.ReadAllText(text + "/" + array[2] + ".json"); Localization.AddJsonFile(array[2], text5); } catch { File.WriteAllText(text + "/" + array[2] + ".json", text3); ((BaseUnityPlugin)this).Logger.LogDebug((object)("Reading " + text2)); Localization.AddJsonFile(array[2], text3); } } else { File.WriteAllText(text + "/" + array[2] + ".json", text3); ((BaseUnityPlugin)this).Logger.LogDebug((object)("Reading " + text2)); Localization.AddJsonFile(array[2], text3); } ((BaseUnityPlugin)this).Logger.LogDebug((object)("Added localization: '" + array[2] + "'")); } } private void UpdateLocalizationWithMissingKeys(Dictionary<string, string> internal_localization, Dictionary<string, string> cached_localization) { if (internal_localization.Keys.Count == cached_localization.Keys.Count) { return; } ((BaseUnityPlugin)this).Logger.LogDebug((object)"Cached localization was missing some entries. They will be added."); foreach (KeyValuePair<string, string> item in internal_localization) { if (!cached_localization.ContainsKey(item.Key)) { cached_localization.Add(item.Key, item.Value); } } } private string ReadEmbeddedResourceFile(string filename) { using Stream stream = typeof(Deathlink).Assembly.GetManifestResourceStream(filename); using StreamReader streamReader = new StreamReader(stream); return streamReader.ReadToEnd(); } public static List<T> shuffleList<T>(List<T> inputList) { int i = 0; int count = inputList.Count; int num = 0; T val = default(T); List<T> list = new List<T>(); list.AddRange(inputList); for (; i < count; i++) { num = Random.Range(i, list.Count); val = list[i]; list[i] = list[num]; list[num] = val; } return list; } } } namespace Deathlink.external { public static class EpicMMOSystem_API { public enum API_State { NotReady, NotInstalled, Ready } public enum Attribut { Strength, Agility, Intellect, Body, Vigour, Special } public static API_State state; private static MethodInfo eGetLevel; private static MethodInfo eAddExp; private static MethodInfo eGetAttribute; private static MethodInfo eGetAttributeRusty; private static MethodInfo eSetSingleRate; public static int GetLevel() { int result = 0; Init(); if (eGetLevel != null) { result = (int)eGetLevel.Invoke(null, null); } return result; } public static int GetAttribute(Attribut attribute) { int result = 0; Init(); if (eGetAttribute != null) { result = (int)eGetAttribute.Invoke(null, new object[1] { attribute }); } return result; } public static int GetAttributeRusty(string attribute) { int result = 0; Init(); if (eGetAttributeRusty != null) { result = (int)eGetAttributeRusty.Invoke(null, new object[1] { attribute }); } return result; } public static void AddExp(int value) { Init(); eAddExp?.Invoke(null, new object[1] { value }); } public static void SetSingleRate(float rate) { Init(); eSetSingleRate?.Invoke(null, new object[1] { rate }); } public static void Init() { API_State aPI_State = state; if ((uint)(aPI_State - 1) > 1u) { if (Type.GetType("EpicMMOSystem.EpicMMOSystem, EpicMMOSystem") == null) { state = API_State.NotInstalled; return; } state = API_State.Ready; Type? type = Type.GetType("API.EMMOS_API, EpicMMOSystem"); eGetLevel = type.GetMethod("GetLevel", BindingFlags.Static | BindingFlags.Public); eAddExp = type.GetMethod("AddExp", BindingFlags.Static | BindingFlags.Public); eGetAttribute = type.GetMethod("GetAttribute", BindingFlags.Static | BindingFlags.Public); eGetAttributeRusty = type.GetMethod("GetAttribute", BindingFlags.Static | BindingFlags.Public); eSetSingleRate = type.GetMethod("SetSingleRate", BindingFlags.Static | BindingFlags.Public); } } } } namespace Deathlink.Death { public static class Compendium { [HarmonyPatch(typeof(TextsDialog), "UpdateTextsList")] public static class TextsDialog_UpdateTextsList_Patch { public static void Postfix(TextsDialog __instance) { AddDeathLinkExplanationPage(__instance); } private static void AddDeathLinkExplanationPage(TextsDialog textsDialog) { //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Expected O, but got Unknown DataObjects.DeathChoiceLevel playerDeathConfiguration = DeathConfigurationData.playerDeathConfiguration; StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("<size=48>" + Localization.instance.Localize("$comp_header") + ": <color=" + specialColor + ">" + playerDeathConfiguration.DisplayName + "</color></size>"); stringBuilder.AppendLine(); stringBuilder.AppendLine("<size=30><b>Death Effects</b></size>"); stringBuilder.AppendLine(playerDeathConfiguration.GetDeathStyleDescription()); stringBuilder.AppendLine(); if (playerDeathConfiguration.DamageTakenModifier != 1f || playerDeathConfiguration.DamageDoneModifier != 1f) { stringBuilder.AppendLine("<size=30><b>Combat Modifiers</b></size>"); stringBuilder.AppendLine(playerDeathConfiguration.GetDamageModifierDescription()); stringBuilder.AppendLine(); } if (playerDeathConfiguration.SkillModifiers != null && playerDeathConfiguration.SkillModifiers.Count > 0) { stringBuilder.AppendLine("<size=30><b>Skill Modifiers</b></size>"); stringBuilder.AppendLine(playerDeathConfiguration.GetSkillModiferDescription()); stringBuilder.AppendLine(); } if (playerDeathConfiguration.ResourceModifiers != null && playerDeathConfiguration.ResourceModifiers.Count > 0) { stringBuilder.AppendLine("<size=30><b>Resource Modifiers</b></size>"); stringBuilder.AppendLine(playerDeathConfiguration.GetResourceModiferDescription()); stringBuilder.AppendLine(); } if (playerDeathConfiguration.DeathLootModifiers != null && playerDeathConfiguration.DeathLootModifiers.Count > 0) { stringBuilder.AppendLine("<size=30><b>Loot Modifiers</b></size>"); stringBuilder.AppendLine(playerDeathConfiguration.GetLootModifiersDescription()); stringBuilder.AppendLine(); } textsDialog.m_texts.Insert(0, new TextInfo(Localization.instance.Localize("$deathlink_settings"), Localization.instance.Localize(stringBuilder.ToString()))); } } [HarmonyPatch(typeof(TextsDialog), "ShowText", new Type[] { typeof(TextInfo) })] public static class TextsDialog_ShowText_Patch { public static void Postfix(TextsDialog __instance, TextInfo text) { bool flag = text != null && text.m_topic == Localization.instance.Localize("$deathlink_settings"); bool flag2 = flag && DeathConfigurationData.PlayerCanChangeChoice(Player.m_localPlayer); Logger.LogDebug($"TextsDialog.ShowText topic='{text?.m_topic}' isDeathlinkPage={flag} canChange={flag2}"); if (!flag2) { if ((Object)(object)changeChoiceButton != (Object)null) { changeChoiceButton.SetActive(false); } return; } EnsureChangeChoiceButton(__instance); if ((Object)(object)changeChoiceButton != (Object)null) { changeChoiceButton.SetActive(true); changeChoiceButton.transform.SetAsLastSibling(); } } private static void EnsureChangeChoiceButton(TextsDialog dialog) { //IL_0062: 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_0080: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Expected O, but got Unknown if ((Object)(object)changeChoiceButton != (Object)null) { return; } if (GUIManager.Instance == null) { Logger.LogWarning("GUIManager not setup, skipping death choice change button creation."); return; } Transform val = ((Component)dialog).transform.Find("Texts_frame/Closebutton"); changeChoiceButton = GUIManager.Instance.CreateButton(Localization.instance.Localize("$comp_change_choice"), val, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(300f, 0f), 200f, 40f); ((UnityEvent)changeChoiceButton.GetComponent<Button>().onClick).AddListener((UnityAction)delegate { dialog.OnClose(); DeathChoices.DeathChoiceUI.Instance.ShowForChange(); }); } private static RectTransform FindCloseButton(TextsDialog dialog) { Button val = null; Button[] componentsInChildren = ((Component)dialog).GetComponentsInChildren<Button>(true); foreach (Button val2 in componentsInChildren) { if ((Object)(object)((Component)val2).gameObject == (Object)(object)changeChoiceButton) { continue; } for (int j = 0; j < ((UnityEventBase)val2.onClick).GetPersistentEventCount(); j++) { if (((UnityEventBase)val2.onClick).GetPersistentMethodName(j) == "OnClose") { return ((Component)val2).GetComponent<RectTransform>(); } } if ((Object)(object)val == (Object)null && ((Object)val2).name.IndexOf("close", StringComparison.OrdinalIgnoreCase) >= 0) { val = val2; } } if (!((Object)(object)val != (Object)null)) { return null; } return ((Component)val).GetComponent<RectTransform>(); } } private static string specialColor = "#ffa64d"; private static GameObject changeChoiceButton; } public static class DamageModifiers { [HarmonyPatch(typeof(Character), "RPC_Damage")] public static class DamageModifierPatch { private static void Prefix(Character __instance, HitData hit) { if (hit == null) { return; } if (__instance is Player) { float storedModifier = GetStoredModifier(__instance, DataObjects.DamageTakenModifierKey); if (storedModifier != 1f) { hit.ApplyModifier(storedModifier); } } Character attacker = hit.GetAttacker(); Player val = (Player)(object)((attacker is Player) ? attacker : null); if (val != null) { float storedModifier2 = GetStoredModifier((Character)(object)val, DataObjects.DamageDoneModifierKey); if (storedModifier2 != 1f) { hit.ApplyModifier(storedModifier2); } } } private static float GetStoredModifier(Character character, string key) { if ((Object)(object)character == (Object)null) { return 1f; } ZNetView nview = character.m_nview; if ((Object)(object)nview == (Object)null || !nview.IsValid()) { return 1f; } ZDO zDO = nview.GetZDO(); if (zDO == null) { return 1f; } return zDO.GetFloat(key, 1f); } } } public static class DeathChoiceEnable { [HarmonyPatch(typeof(InventoryGui), "Show")] public static class ShowDeathChoiceUI { public static void Postfix(InventoryGui __instance) { if (ValConfig.UsePrivateKeysForDeathChoice.Value) { if ((Object)(object)Player.m_localPlayer != (Object)null && Player.m_localPlayer.PlayerHasUniqueKey(DataObjects.DeathChoiceKey)) { return; } } else if ((Object)(object)Player.m_localPlayer != (Object)null && DeathConfigurationData.playerSettings.ContainsKey(Player.m_localPlayer.GetPlayerID())) { return; } DeathChoices.DeathChoiceUI.Instance.Show(); } } [HarmonyPatch(typeof(InventoryGui), "Hide")] public static class HideDeathChoiceUI { public static void Postfix(InventoryGui __instance) { if (DeathChoices.DeathChoiceUI.IsInitialized) { DeathChoices.DeathChoiceUI.Instance.Hide(); } } } } public class DeathChoices { public class DeathChoiceUI : MonoBehaviour { private static DeathChoiceUI _instance; private static GameObject DeathChoicePanel; private static GameObject ChoicesScrollView; private static GameObject ChoicesContent; private static GameObject ChoicesContainer; private static GameObject manualCloseButton; private static GameObject selectChoiceButton; private static Text DeathPenaltyDescription; private static Text CombatModifiersDescription; private static Text XPModifiersDescription; private static Text LootModifersDescription; private static Text HarvestModifiersDescription; private static List<Toggle> difficultyToggles = new List<Toggle>(); private static ToggleGroup choiceGroup; private static string selectedDeathChoice = "none"; private static bool isChangeMode = false; public static DeathChoiceUI Instance { get { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown if ((Object)(object)_instance == (Object)null) { GameObject val = new GameObject("DeathlinkDeathChoiceUI"); Object.DontDestroyOnLoad((Object)val); _instance = val.AddComponent<DeathChoiceUI>(); } return _instance; } } public static bool IsInitialized => (Object)(object)_instance != (Object)null; public void Awake() { _instance = this; CreateStaticUIObjects(); SetChoiceList(); } public void Show() { if ((Object)(object)DeathChoicePanel == (Object)null) { CreateStaticUIObjects(); SetChoiceList(); } DeathChoicePanel.SetActive(true); } public void ShowForChange() { isChangeMode = true; Show(); } public void Hide() { if ((Object)(object)DeathChoicePanel != (Object)null) { DeathChoicePanel.SetActive(false); } isChangeMode = false; GUIManager.BlockInput(false); } public void MakePlayerDeathSelection() { if ((Object)(object)Player.m_localPlayer == (Object)null) { Logger.LogWarning("Player not set, ensure the local player is set."); return; } if (selectedDeathChoice == "none") { Logger.LogWarning("No death type selected"); return; } Logger.LogDebug("Player selected death type " + selectedDeathChoice); long playerID = Player.m_localPlayer.GetPlayerID(); if (DeathConfigurationData.playerSettings.ContainsKey(playerID)) { DeathConfigurationData.playerSettings[playerID].DeathChoiceLevel = selectedDeathChoice; } else { DeathConfigurationData.playerSettings.Add(playerID, new DataObjects.DeathConfiguration { DeathChoiceLevel = selectedDeathChoice }); } Player.m_localPlayer.PlayerRemoveUniqueKey(DataObjects.DeathChoiceKey); Player.m_localPlayer.AddUniqueKeyValue(DataObjects.DeathChoiceKey, selectedDeathChoice); if (isChangeMode) { DeathConfigurationData.IncrementPlayerChangesUsed(Player.m_localPlayer); } DeathConfigurationData.CheckAndSetPlayerDeathConfig(Player.m_localPlayer); DeathConfigurationData.WritePlayerChoices(); Hide(); } private void SetChoiceList() { //IL_0018: 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_013e: Unknown result type (might be due to invalid IL or missing references) foreach (Transform item in ChoicesContent.transform) { Object.Destroy((Object)(object)((Component)item).gameObject); } difficultyToggles.Clear(); int num = -75; foreach (KeyValuePair<string, DataObjects.DeathChoiceLevel> entry in DeathConfigurationData.DeathLevels) { GameObject obj = Object.Instantiate<GameObject>(ChoicesContainer, ChoicesContent.transform); Transform val = obj.transform.Find("selecter"); ((Component)val.Find("Label")).GetComponent<Text>().text = entry.Key; ((Component)obj.transform.Find("ChoiceName")).GetComponent<Text>().text = entry.Value.DisplayName; Toggle component = ((Component)val).GetComponent<Toggle>(); component.group = choiceGroup; ((UnityEvent<bool>)(object)component.onValueChanged).AddListener((UnityAction<bool>)delegate(bool isOn) { if (isOn) { ((Component)DeathPenaltyDescription).GetComponent<Text>().text = entry.Value.GetDeathStyleDescription(); ((Component)CombatModifiersDescription).GetComponent<Text>().text = entry.Value.GetDamageModifierDescription(); ((Component)XPModifiersDescription).GetComponent<Text>().text = entry.Value.GetSkillModiferDescription(); ((Component)LootModifersDescription).GetComponent<Text>().text = entry.Value.GetLootModifiersDescription(); ((Component)HarvestModifiersDescription).GetComponent<Text>().text = entry.Value.GetResourceModiferDescription(); selectedDeathChoice = entry.Key; } }); obj.SetActive(true); obj.transform.localPosition = new Vector3 { x = 5f, y = num }; difficultyToggles.Add(component); num -= 50; } } private void CreateStaticUIObjects() { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_005e: 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_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_014a: 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_016a: 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) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: 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) //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Expected O, but got Unknown //IL_0258: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Unknown result type (might be due to invalid IL or missing references) //IL_0292: Unknown result type (might be due to invalid IL or missing references) //IL_02d9: Unknown result type (might be due to invalid IL or missing references) //IL_02e8: Unknown result type (might be due to invalid IL or missing references) //IL_02f7: 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_030e: Unknown result type (might be due to invalid IL or missing references) //IL_0377: Unknown result type (might be due to invalid IL or missing references) //IL_0386: Unknown result type (might be due to invalid IL or missing references) //IL_0395: Unknown result type (might be due to invalid IL or missing references) //IL_03ab: 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_03f8: Unknown result type (might be due to invalid IL or missing references) //IL_0407: Unknown result type (might be due to invalid IL or missing references) //IL_0416: Unknown result type (might be due to invalid IL or missing references) //IL_0427: Unknown result type (might be due to invalid IL or missing references) //IL_042d: Unknown result type (might be due to invalid IL or missing references) //IL_0496: Unknown result type (might be due to invalid IL or missing references) //IL_04a5: Unknown result type (might be due to invalid IL or missing references) //IL_04b4: Unknown result type (might be due to invalid IL or missing references) //IL_04ca: Unknown result type (might be due to invalid IL or missing references) //IL_04d0: Unknown result type (might be due to invalid IL or missing references) //IL_0517: Unknown result type (might be due to invalid IL or missing references) //IL_0526: Unknown result type (might be due to invalid IL or missing references) //IL_0535: Unknown result type (might be due to invalid IL or missing references) //IL_0546: Unknown result type (might be due to invalid IL or missing references) //IL_054c: Unknown result type (might be due to invalid IL or missing references) //IL_05b5: Unknown result type (might be due to invalid IL or missing references) //IL_05c4: Unknown result type (might be due to invalid IL or missing references) //IL_05d3: Unknown result type (might be due to invalid IL or missing references) //IL_05e9: Unknown result type (might be due to invalid IL or missing references) //IL_05ef: Unknown result type (might be due to invalid IL or missing references) //IL_0636: Unknown result type (might be due to invalid IL or missing references) //IL_0645: Unknown result type (might be due to invalid IL or missing references) //IL_0654: Unknown result type (might be due to invalid IL or missing references) //IL_0665: Unknown result type (might be due to invalid IL or missing references) //IL_066b: Unknown result type (might be due to invalid IL or missing references) //IL_06d4: Unknown result type (might be due to invalid IL or missing references) //IL_06e3: Unknown result type (might be due to invalid IL or missing references) //IL_06f2: Unknown result type (might be due to invalid IL or missing references) //IL_0708: Unknown result type (might be due to invalid IL or missing references) //IL_070e: Unknown result type (might be due to invalid IL or missing references) //IL_0755: Unknown result type (might be due to invalid IL or missing references) //IL_0764: Unknown result type (might be due to invalid IL or missing references) //IL_0773: Unknown result type (might be due to invalid IL or missing references) //IL_0784: Unknown result type (might be due to invalid IL or missing references) //IL_078a: Unknown result type (might be due to invalid IL or missing references) //IL_07f3: Unknown result type (might be due to invalid IL or missing references) //IL_0802: Unknown result type (might be due to invalid IL or missing references) //IL_0811: Unknown result type (might be due to invalid IL or missing references) //IL_0840: Unknown result type (might be due to invalid IL or missing references) //IL_084a: Expected O, but got Unknown //IL_0874: Unknown result type (might be due to invalid IL or missing references) //IL_0879: Unknown result type (might be due to invalid IL or missing references) //IL_089e: Unknown result type (might be due to invalid IL or missing references) //IL_08bc: Unknown result type (might be due to invalid IL or missing references) //IL_08bd: Unknown result type (might be due to invalid IL or missing references) //IL_090d: Unknown result type (might be due to invalid IL or missing references) //IL_0921: Expected O, but got Unknown //IL_0952: Unknown result type (might be due to invalid IL or missing references) //IL_09a9: Unknown result type (might be due to invalid IL or missing references) //IL_09ae: Unknown result type (might be due to invalid IL or missing references) //IL_0a07: Unknown result type (might be due to invalid IL or missing references) //IL_0a16: Unknown result type (might be due to invalid IL or missing references) //IL_0a25: Unknown result type (might be due to invalid IL or missing references) //IL_0a3b: Unknown result type (might be due to invalid IL or missing references) //IL_0a41: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)DeathChoicePanel != (Object)null)) { if (GUIManager.Instance == null || !Object.op_Implicit((Object)(object)GUIManager.CustomGUIFront)) { Logger.LogWarning("GUIManager not setup, skipping static object creation."); return; } Logger.LogDebug("Creating static UI"); DeathChoicePanel = GUIManager.Instance.CreateWoodpanel(GUIManager.CustomGUIFront.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, 0f), 800f, 960f, true); DeathChoicePanel.SetActive(false); ((Object)GUIManager.Instance.CreateText(Localization.instance.Localize("$selection_header"), DeathChoicePanel.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(50f, 430f), GUIManager.Instance.AveriaSerifBold, 30, GUIManager.Instance.ValheimOrange, true, Color.black, 350f, 40f, false)).name = "DLHeader"; Text component = GUIManager.Instance.CreateText(Localization.instance.Localize("$selection_description"), DeathChoicePanel.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, 380f), GUIManager.Instance.AveriaSerif, 20, Color.white, true, Color.black, 560f, 60f, false).GetComponent<Text>(); component.resizeTextForBestFit = true; component.resizeTextMaxSize = 20; component.alignment = (TextAnchor)4; manualCloseButton = GUIManager.Instance.CreateButton(Localization.instance.Localize("$close"), DeathChoicePanel.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(360f, 430f), 60f, 60f); Button component2 = manualCloseButton.GetComponent<Button>(); ((Selectable)component2).interactable = true; ((UnityEvent)component2.onClick).AddListener(new UnityAction(Hide)); manualCloseButton.SetActive(true); ((Object)GUIManager.Instance.CreateText(Localization.instance.Localize("$death_penalty_header"), DeathChoicePanel.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(100f, 330f), GUIManager.Instance.AveriaSerifBold, 22, GUIManager.Instance.ValheimOrange, true, Color.black, 400f, 40f, false)).name = "DeathPenaltyTitle"; GameObject obj = GUIManager.Instance.CreateText(Localization.instance.Localize("$death_penalty_description"), DeathChoicePanel.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(147f, 240f), GUIManager.Instance.AveriaSerifBold, 18, Color.white, true, Color.black, 490f, 160f, false); ((Object)obj).name = "DeathPenaltyDesc"; DeathPenaltyDescription = obj.GetComponent<Text>(); DeathPenaltyDescription.resizeTextForBestFit = true; DeathPenaltyDescription.resizeTextMaxSize = 18; ((Object)GUIManager.Instance.CreateText(Localization.instance.Localize("$combat_header"), DeathChoicePanel.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(100f, 150f), GUIManager.Instance.AveriaSerifBold, 22, GUIManager.Instance.ValheimOrange, true, Color.black, 400f, 40f, false)).name = "combatModifiersTitle"; GameObject obj2 = GUIManager.Instance.CreateText(Localization.instance.Localize("$combat_modifier_description"), DeathChoicePanel.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(150f, 80f), GUIManager.Instance.AveriaSerifBold, 16, Color.white, true, Color.black, 500f, 100f, false); ((Object)obj2).name = "combatModifiersDesc"; CombatModifiersDescription = obj2.GetComponent<Text>(); CombatModifiersDescription.resizeTextForBestFit = true; CombatModifiersDescription.resizeTextMaxSize = 18; ((Object)GUIManager.Instance.CreateText(Localization.instance.Localize("$xp_header"), DeathChoicePanel.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(100f, 30f), GUIManager.Instance.AveriaSerifBold, 22, GUIManager.Instance.ValheimOrange, true, Color.black, 400f, 40f, false)).name = "xpModifiersTitle"; GameObject obj3 = GUIManager.Instance.CreateText(Localization.instance.Localize("$xp_mod_description"), DeathChoicePanel.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(150f, -80f), GUIManager.Instance.AveriaSerifBold, 16, Color.white, true, Color.black, 500f, 200f, false); ((Object)obj3).name = "xpModifiersDesc"; XPModifiersDescription = obj3.GetComponent<Text>(); XPModifiersDescription.resizeTextForBestFit = true; XPModifiersDescription.resizeTextMaxSize = 18; ((Object)GUIManager.Instance.CreateText(Localization.instance.Localize("$loot_header"), DeathChoicePanel.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(100f, -130f), GUIManager.Instance.AveriaSerifBold, 22, GUIManager.Instance.ValheimOrange, true, Color.black, 400f, 40f, false)).name = "lootModifiersTitle"; GameObject obj4 = GUIManager.Instance.CreateText(Localization.instance.Localize("$loot_modifier_description"), DeathChoicePanel.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(150f, -240f), GUIManager.Instance.AveriaSerifBold, 16, Color.white, true, Color.black, 500f, 200f, false); ((Object)obj4).name = "lootModifersDesc"; LootModifersDescription = obj4.GetComponent<Text>(); LootModifersDescription.resizeTextForBestFit = true; LootModifersDescription.resizeTextMaxSize = 18; ((Object)GUIManager.Instance.CreateText(Localization.instance.Localize("$harvest_header"), DeathChoicePanel.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(100f, -260f), GUIManager.Instance.AveriaSerifBold, 22, GUIManager.Instance.ValheimOrange, true, Color.black, 400f, 40f, false)).name = "harvestModifiersTitle"; GameObject obj5 = GUIManager.Instance.CreateText(Localization.instance.Localize("$harvest_modifier_description"), DeathChoicePanel.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(150f, -370f), GUIManager.Instance.AveriaSerifBold, 16, Color.white, true, Color.black, 500f, 200f, false); ((Object)obj5).name = "harvestModifersDesc"; HarvestModifiersDescription = obj5.GetComponent<Text>(); HarvestModifiersDescription.resizeTextForBestFit = true; HarvestModifiersDescription.resizeTextMaxSize = 18; selectChoiceButton = GUIManager.Instance.CreateButton(Localization.instance.Localize("$deathchoice_select"), DeathChoicePanel.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(-240f, -290f), 200f, 80f); ((UnityEvent)selectChoiceButton.GetComponent<Button>().onClick).AddListener(new UnityAction(MakePlayerDeathSelection)); Logger.LogDebug("Setting up scroll entry"); ChoicesScrollView = GUIManager.Instance.CreateScrollView(DeathChoicePanel.transform, false, true, 10f, 10f, GUIManager.Instance.ValheimScrollbarHandleColorBlock, Color.grey, 250f, 400f); ChoicesScrollView.transform.localPosition = Vector2.op_Implicit(new Vector2 { x = -260f, y = -30f }); ChoicesContent = ((Component)ChoicesScrollView.GetComponentInChildren<ContentSizeFitter>()).gameObject; ChoicesScrollView.GetComponentInChildren<ScrollRect>().scrollSensitivity = 200f; choiceGroup = ChoicesContent.AddComponent<ToggleGroup>(); Logger.LogDebug("Setting up death choice template entry"); ChoicesContainer = Object.Instantiate<GameObject>(new GameObject("DeathChoice"), DeathChoicePanel.transform); RectTransform obj6 = ChoicesContainer.AddComponent<RectTransform>(); obj6.SetSizeWithCurrentAnchors((Axis)0, 100f); obj6.SetSizeWithCurrentAnchors((Axis)1, 50f); ((Transform)obj6).position = new Vector3(0f, 0f); ChoicesContainer.AddComponent<LayoutElement>().minHeight = 50f; ChoicesContainer.SetActive(false); GameObject obj7 = GUIManager.Instance.CreateToggle(ChoicesContainer.transform, 40f, 40f); obj7.transform.localPosition = Vector2.op_Implicit(new Vector2(10f, 0f)); ((Object)obj7).name = "selecter"; ((Component)obj7.transform.Find("Label")).gameObject.SetActive(false); obj7.GetComponent<Toggle>().isOn = false; ((Object)GUIManager.Instance.CreateText("Name", ChoicesContainer.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(200f, 0f), GUIManager.Instance.AveriaSerifBold, 20, GUIManager.Instance.ValheimYellow, true, Color.black, 350f, 40f, false)).name = "ChoiceName"; } } } } public static class DeathProgressionSkill { [HarmonyPatch(typeof(Player), "RaiseSkill")] public class Deathskill_EXP_Patch { public static void Postfix(Player __instance) { //IL_03b9: Unknown result type (might be due to invalid IL or missing references) timeSinceGameStart += Time.deltaTime; if (lastSkillIncreaseTickTime == 0f) { lastSkillIncreaseTickTime = timeSinceGameStart + ValConfig.SkillProgressUpdateCheckInterval.Value; PlayerProfile playerProfile = Game.instance.GetPlayerProfile(); _bossKills = playerProfile.m_playerStats.m_stats[(PlayerStatType)85]; _enemykills = playerProfile.m_playerStats.m_stats[(PlayerStatType)6]; _piecesBuilt = playerProfile.m_playerStats.m_stats[(PlayerStatType)2]; _treesChopped = playerProfile.m_playerStats.m_stats[(PlayerStatType)27]; _mineAmount = playerProfile.m_playerStats.m_stats[(PlayerStatType)38]; _craftAndUpgrades = playerProfile.m_playerStats.m_stats[(PlayerStatType)1]; } if (timeSinceGameStart > lastSkillIncreaseTickTime) { lastSkillIncreaseTickTime = timeSinceGameStart + ValConfig.SkillProgressUpdateCheckInterval.Value; PlayerProfile playerProfile2 = Game.instance.GetPlayerProfile(); float num = playerProfile2.m_playerStats.m_stats[(PlayerStatType)85]; float num2 = playerProfile2.m_playerStats.m_stats[(PlayerStatType)6]; float num3 = playerProfile2.m_playerStats.m_stats[(PlayerStatType)2]; float num4 = playerProfile2.m_playerStats.m_stats[(PlayerStatType)27]; float num5 = playerProfile2.m_playerStats.m_stats[(PlayerStatType)38]; float num6 = playerProfile2.m_playerStats.m_stats[(PlayerStatType)1]; float num7 = 0f; float num8 = 0f; float num9 = 0f; float num10 = 0f; float num11 = 0f; float num12 = 0f; if (num > _bossKills || num2 > _enemykills) { num12 = (num - _bossKills) * ValConfig.SkillGainOnBossKills.Value; num11 = (num2 - _enemykills) * ValConfig.SkillGainOnKills.Value; Logger.LogDebug($"DeathProgression kill skill bosskill: {num12} kill: {num11}"); _bossKills = num; _enemykills = num2; } if (num3 > _piecesBuilt) { num10 = (num3 - _piecesBuilt) * ValConfig.SkillGainOnBuilding.Value; Logger.LogDebug($"DeathProgression building skill: {num10}"); _piecesBuilt = num3; } if (num4 > _treesChopped || num5 > _mineAmount) { num9 = (num4 - _treesChopped) * ValConfig.SkillGainOnResourceGathering.Value; num8 = (num5 - _mineAmount) * ValConfig.SkillGainOnResourceGathering.Value; Logger.LogDebug($"DeathProgression harvesting skill tree_harvest: {num9} mining: {num8}"); _treesChopped = num4; _mineAmount = num5; } if (num6 > _craftAndUpgrades) { num7 = (num6 - _craftAndUpgrades) * ValConfig.SkillGainOnCrafts.Value; Logger.LogDebug($"DeathProgression crafting skill crafting: {num7}"); _craftAndUpgrades = num6; } float num13 = num12 + num11 + num10 + num9 + num8 + num7; float num14 = Mathf.Max(0f, (float)Math.Log(__instance.m_timeSinceDeath) / 5f * 0.5f); float num15 = num14 * num13; if (Deathlink.RustyAlmanacClassesLoaded) { int num16 = Mathf.RoundToInt(num15 * ValConfig.AlmanacClassesXPGainScale.Value); Logger.LogDebug($"Almanac XP Gain {num16}"); ClassesAPI.AddEXP(num16); } if (Deathlink.WackyMMOLoaded) { int num17 = Mathf.RoundToInt(num15 * ValConfig.WackyMMOXPGainScale.Value); Logger.LogDebug($"WackyMMO XP Gain {num17}"); EpicMMOSystem_API.AddExp(num17); } Logger.LogDebug($"DeathProgression skill bonus from survival (survive time: {__instance.m_timeSinceDeath}) {num14} x {num13} = {num15}"); ((Character)Player.m_localPlayer).RaiseSkill(DeathSkill, num15); } } } public static SkillType DeathSkill; private static float lastSkillIncreaseTickTime; private static float timeSinceGameStart; private static float _bossKills; private static float _enemykills; private static float _piecesBuilt; private static float _mineAmount; private static float _treesChopped; private static float _craftAndUpgrades; public static void SetupDeathSkill() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) SkillConfig val = new SkillConfig(); val.Name = LocalizationManager.Instance.TryTranslate("$death_skill"); val.Description = LocalizationManager.Instance.TryTranslate("$death_skill_description"); val.Icon = Deathlink.EmbeddedResourceBundle.LoadAsset<Sprite>("Assets/Custom/Icons/death_skill.png"); val.Identifier = "midnightsfx.deathskill"; val.IncreaseStep = 0.1f; DeathSkill = SkillManager.Instance.AddSkill(val); if (!SkillsChanges.skills_to_avoid_standard_death_penalty.Contains(DeathSkill)) { SkillsChanges.skills_to_avoid_standard_death_penalty.Add(DeathSkill); } } public static float DeathSkillCalculatePercentWithBonus(float bonus = 0f, float min = 0.01f, float max = 1f) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) float num = 0f; if ((Object)(object)Player.m_localPlayer != (Object)null) { float skillFactor = ((Character)Player.m_localPlayer).GetSkillFactor(DeathSkill); num += skillFactor; } num += bonus; if (num < min) { num = min; } if (num > max) { num = max; } return num; } } internal static class DeathSavingOptions { [HarmonyPatch(typeof(Player), "OnSpawned")] public static class Player_OnSpawned_Patch { public static void Postfix(Player __instance) { if (pendingChoice && !((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { ((Character)__instance).Message((MessageType)2, Localization.instance.Localize("$dso_spawn_message"), 0, (Sprite)null); } } } [HarmonyPatch(typeof(InventoryGui), "Show")] public static class ShowSaveChoiceUI { public static void Postfix() { if (pendingChoice) { SaveChoiceUI.Instance.Show(new List<ItemData>(deathItems), totalToSave, maxChoices); } } } [HarmonyPatch(typeof(InventoryGui), "Hide")] public static class HideSaveChoiceUI { public static void Postfix() { if (SaveChoiceUI.IsInitialized) { SaveChoiceUI.Instance.Hide(); } } } public class SaveChoiceUI : MonoBehaviour { private static SaveChoiceUI _instance; private const int GridWidth = 8; private static GameObject panel; private static Text counterText; private static InventoryGrid grid; private static RectTransform gridRoot; private static Inventory tempInv; private static bool selectionWired; private static readonly HashSet<ItemData> selected = new HashSet<ItemData>(); private static int keepBudget = 0; private static int pickLimit = 0; public static SaveChoiceUI Instance { get { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown if ((Object)(object)_instance == (Object)null) { GameObject val = new GameObject("DeathlinkSaveChoiceUI"); Object.DontDestroyOnLoad((Object)val); _instance = val.AddComponent<SaveChoiceUI>(); } return _instance; } } public static bool IsInitialized => (Object)(object)_instance != (Object)null; public void Awake() { _instance = this; } public void Update() { if (!((Object)(object)panel == (Object)null) && panel.activeSelf && !((Object)(object)grid == (Object)null) && tempInv != null) { grid.UpdateInventory(tempInv, (Player)null, (ItemData)null); } } public void Show(List<ItemData> items, int totalKept, int choiceCount) { //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) if (EnsurePanel() && EnsureGrid()) { keepBudget = totalKept; pickLimit = choiceCount; selected.Clear(); BuildInventory(items); grid.UpdateInventory(tempInv, (Player)null, (ItemData)null); grid.ResetView(); string text = $"SaveChoiceUI grid: {tempInv.GetWidth()}x{tempInv.GetHeight()}, "; string text2 = $"slot elements={(((Object)(object)gridRoot != (Object)null) ? ((Transform)gridRoot).childCount : (-1))}, "; Rect rect = ((RectTransform)((Component)grid).transform).rect; Logger.LogDebug(text + text2 + $"gridRect={((Rect)(ref rect)).size}"); ClearHighlights(); UpdateCounter(); panel.SetActive(true); } } public void Hide() { if ((Object)(object)panel != (Object)null) { panel.SetActive(false); } } private void Confirm() { List<ItemData> picked = selected.ToList(); Hide(); selected.Clear(); ApplySelection(picked); } private bool EnsurePanel() { //IL_0047: 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_0065: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0148: 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_015f: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_0229: 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_0247: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Expected O, but got Unknown if ((Object)(object)panel != (Object)null) { return true; } if (GUIManager.Instance == null || !Object.op_Implicit((Object)(object)GUIManager.CustomGUIFront)) { Logger.LogWarning("GUIManager not setup, skipping death saving panel creation."); return false; } panel = GUIManager.Instance.CreateWoodpanel(GUIManager.CustomGUIFront.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, 0f), 700f, 640f, true); panel.SetActive(false); GUIManager.Instance.CreateText(Localization.instance.Localize("$dso_header"), panel.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, 270f), GUIManager.Instance.AveriaSerifBold, 30, GUIManager.Instance.ValheimOrange, true, Color.black, 620f, 40f, false); GUIManager.Instance.CreateText(Localization.instance.Localize("$dso_description"), panel.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, 225f), GUIManager.Instance.AveriaSerif, 18, Color.white, true, Color.black, 620f, 50f, false).GetComponent<Text>().alignment = (TextAnchor)4; counterText = GUIManager.Instance.CreateText("", panel.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, 180f), GUIManager.Instance.AveriaSerifBold, 18, GUIManager.Instance.ValheimYellow, true, Color.black, 620f, 40f, false).GetComponent<Text>(); counterText.alignment = (TextAnchor)4; ((UnityEvent)GUIManager.Instance.CreateButton(Localization.instance.Localize("$dso_confirm"), panel.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, -270f), 250f, 60f).GetComponent<Button>().onClick).AddListener(new UnityAction(Confirm)); return true; } private bool EnsureGrid() { //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) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Expected O, but got Unknown //IL_0083: 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_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_011e: 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) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012a: 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) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_014a: 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)(object)grid != (Object)null) { return true; } if ((Object)(object)InventoryGui.instance == (Object)null || (Object)(object)InventoryGui.instance.ContainerGrid == (Object)null) { Logger.LogWarning("InventoryGui not ready, cannot build death saving grid."); return false; } GameObject val = new GameObject("DL_GridHolder", new Type[1] { typeof(RectTransform) }); val.transform.SetParent(panel.transform, false); RectTransform val2 = (RectTransform)val.transform; val2.anchorMin = new Vector2(0.5f, 0.5f); val2.anchorMax = new Vector2(0.5f, 0.5f); val2.pivot = new Vector2(0.5f, 0.5f); val2.sizeDelta = new Vector2(600f, 380f); val2.anchoredPosition = new Vector2(0f, -40f); GameObject obj = Object.Instantiate<GameObject>(((Component)InventoryGui.instance.ContainerGrid).gameObject, (Transform)(object)val2); ((Object)obj).name = "DL_SaveGrid"; obj.SetActive(true); RectTransform val3 = (RectTransform)obj.transform; ((Transform)val3).localScale = Vector3.one; ((Transform)val3).localRotation = Quaternion.identity; val3.anchorMin = Vector2.zero; val3.anchorMax = Vector2.one; val3.offsetMin = Vector2.zero; val3.offsetMax = Vector2.zero; grid = obj.GetComponent<InventoryGrid>(); gridRoot = grid.m_gridRoot; if ((Object)(object)gridRoot != (Object)null) { ((Component)gridRoot).gameObject.SetActive(true); } if ((Object)(object)gridRoot != (Object)null) { foreach (Transform item in (Transform)gridRoot) { Object.Destroy((Object)(object)((Component)item).gameObject); } } grid.m_width = 0; grid.m_height = 0; if (!selectionWired) { InventoryGrid obj2 = grid; obj2.m_onSelected = (Action<InventoryGrid, ItemData, Vector2i, Modifier>)Delegate.Combine(obj2.m_onSelected, (Action<InventoryGrid, ItemData, Vector2i, Modifier>)delegate(InventoryGrid g, ItemData item, Vector2i pos, Modifier mod) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) OnItemClicked(item, pos); }); InventoryGrid obj3 = grid; obj3.m_onRightClick = (Action<InventoryGrid, ItemData, Vector2i>)Delegate.Combine(obj3.m_onRightClick, (Action<InventoryGrid, ItemData, Vector2i>)delegate { }); selectionWired = true; } return true; } private void BuildInventory(List<ItemData> items) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) int num = Mathf.Max(1, items.Count); int num2 = Mathf.Max(1, Mathf.CeilToInt((float)num / 8f)); tempInv = new Inventory("DL_SaveChoice", (Sprite)null, 8, num2); tempInv.m_inventory.Clear(); int num3 = 0; foreach (ItemData item in items) { item.m_gridPos = new Vector2i(num3 % 8, num3 / 8); tempInv.m_inventory.Add(item); num3++; } tempInv.Changed(); } private void OnItemClicked(ItemData item, Vector2i pos) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) if (item == null) { return; } if (selected.Contains(item)) { selected.Remove(item); SetHighlight(pos, on: false); } else { if (selected.Count >= pickLimit) { return; } selected.Add(item); SetHighlight(pos, on: true); } UpdateCounter(); } private void SetHighlight(Vector2i pos, bool on) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: 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_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: 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_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)gridRoot == (Object)null) { return; } int num = pos.y * 8 + pos.x; if (num >= 0 && num < ((Transform)gridRoot).childCount) { Transform child = ((Transform)gridRoot).GetChild(num); Transform val = child.Find("dl_highlight"); if ((Object)(object)val == (Object)null) { GameObject val2 = new GameObject("dl_highlight", new Type[2] { typeof(RectTransform), typeof(Image) }); val2.transform.SetParent(child, false); RectTransform val3 = (RectTransform)val2.transform; val3.anchorMin = Vector2.zero; val3.anchorMax = Vector2.one; val3.offsetMin = Vector2.zero; val3.offsetMax = Vector2.zero; Image component = val2.GetComponent<Image>(); ((Graphic)component).color = new Color(1f, 0.82f, 0.2f, 0.4f); ((Graphic)component).raycastTarget = false; val = val2.transform; } ((Component)val).gameObject.SetActive(on); } } private void ClearHighlights() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)gridRoot == (Object)null) { return; } foreach (Transform item in (Transform)gridRoot) { Transform val = item.Find("dl_highlight"); if ((Object)(object)val != (Object)null) { ((Component)val).gameObject.SetActive(false); } } } private void UpdateCounter() { if (!((Object)(object)counterText == (Object)null)) { string text = string.Format(Localization.instance.Localize("$dso_selected"), selected.Count, pickLimit); int num = Mathf.Max(0, keepBudget - selected.Count); if (num > 0) { text = text + " - " + string.Format(Localization.instance.Localize("$dso_random_note"), num); } counterText.text = text; } } } private static readonly List<ItemData> deathItems = new List<ItemData>(); private static int totalToSave = 0; private static int maxChoices = 0; private static bool pendingChoice = false; public static void CaptureDeathChoice(List<ItemData> candidateItems, int totalKept, int choiceCount) { deathItems.Clear(); deathItems.AddRange(candidateItems); totalToSave = Mathf.Max(0, totalKept); maxChoices = Mathf.Clamp(choiceCount, 0, totalToSave); pendingChoice = true; Logger.LogDebug($"Captured {deathItems.Count} death items for choice, keep {totalToSave}, pick up to {maxChoices}."); } private static void ApplySelection(List<ItemData> picked) { Player localPlayer = Player.m_localPlayer; List<ItemData> saved = new List<ItemData>(); if (picked != null) { foreach (ItemData item in picked) { if (deathItems.Contains(item) && !saved.Contains(item)) { saved.Add(item); } } } if (saved.Count < totalToSave) { foreach (ItemData item2 in Deathlink.shuffleList(deathItems.Where((ItemData i) => !saved.Contains(i)).ToList())) { if (saved.Count >= totalToSave) { break; } saved.Add(item2); } } if ((Object)(object)localPlayer != (Object)null) { foreach (ItemData item3 in saved) { item3.m_equipped = false; ((Humanoid)localPlayer).m_inventory.AddItem(item3); } Logger.LogDebug($"Returned {saved.Count} items to the player after death choice."); } else { Logger.LogWarning("Local player missing while applying death choice, saved items were lost."); } deathItems.Clear(); totalToSave = 0; maxChoices = 0; pendingChoice = false; } } public static class HarvestModifiers { [HarmonyPatch(typeof(DropTable), "GetDropList", new Type[] { })] public static class ScaleHarvestDropList { private static void Postfix(List<GameObject> __result) { if (ScalingActive && HasResourceModifiers()) { ScaleDropListInPlace(__result); } } } [HarmonyPatch(typeof(TreeLog), "Destroy")] public static class TreeLogHarvestScale { private static void Prefix(HitData hitData, out bool __state) { __state = false; if (!ScalingActive && ShouldScaleHarvest(hitData)) { ScalingActive = true; __state = true; } } private static void Finalizer(TreeLog __instance, bool __state) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (__state) { ScalingActive = false; SpawnHarvestBonusLoot(((Component)__instance).transform.position); } } } [HarmonyPatch(typeof(Destructible), "Destroy")] public static class DestructibleHarvestScale { private static void Prefix(Destructible __instance, HitData hit, out bool __state) { __state = false; if (!((Object)(object)__instance.m_spawnWhenDestroyed != (Object)null)) { DropOnDestroyed component = ((Component)__instance).GetComponent<DropOnDestroyed>(); if (!((Object)(object)component == (Object)null) && component.m_dropWhenDestroyed != null && !component.m_dropWhenDestroyed.IsEmpty() && !ScalingActive && ShouldScaleHarvest(hit)) { ScalingActive = true; __state = true; } } } private static void Finalizer(Destructible __instance, bool __state) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (__state) { ScalingActive = false; SpawnHarvestBonusLoot(((Component)__instance).transform.position); } } } [HarmonyPatch(typeof(MineRock5), "DamageArea")] public static class MineRockHarvestScale { private static void Prefix(HitData hit, out bool __state) { __state = false; if (!ScalingActive && ShouldScaleHarvest(hit)) { ScalingActive = true; __state = true; } } private static void Finalizer(MineRock5 __instance, bool __state, bool __result) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) if (__state) { ScalingActive = false; if (__result) { SpawnHarvestBonusLoot(((Component)__instance).transform.position); } } } } [HarmonyPatch(typeof(Pickable), "Drop")] public static class ScalePickableDrop { private static bool Prefix(GameObject prefab, ref int stack) { if ((Object)(object)Player.m_localPlayer == (Object)null || !HasResourceModifiers() || (Object)(object)prefab == (Object)null) { return true; } float resouceEarlyCache = Deathlink.pcfg().GetResouceEarlyCache(prefab); if (resouceEarlyCache == 1f) { return true; } int num = ScaleCount(stack, resouceEarlyCache); if (num <= 0) { return false; } stack = num; return true; } } internal static bool ScalingActive; private static bool HasResourceModifiers() { DataObjects.DeathChoiceLevel deathChoiceLevel = Deathlink.pcfg(); if (deathChoiceLevel.ResourceModifiers != null) { return deathChoiceLevel.ResourceModifiers.Count > 0; } return false; } private static bool ShouldScaleHarvest(HitData hit) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Player.m_localPlayer == (Object)null) { return false; } if (!HasResourceModifiers()) { return false; } if (hit == null) { return false; } return hit.m_attacker == ((Character)Player.m_localPlayer).GetZDOID(); } public static int ScaleCount(int baseCount, float m) { if (baseCount <= 0) { return 0; } float num = (float)baseCount * m; int num2 = Mathf.FloorToInt(num); float num3 = num - (float)num2; if (num3 > 0f && Random.value < num3) { num2++; } return num2; } public static void ScaleDropListInPlace(List<GameObject> drops) { if (drops == null || drops.Count == 0) { return; } Dictionary<GameObject, int> dictionary = new Dictionary<GameObject, int>(); List<GameObject> list = new List<GameObject>(); foreach (GameObject drop in drops) { if (!((Object)(object)drop == (Object)null)) { if (dictionary.TryGetValue(drop, out var value)) { dictionary[drop] = value + 1; continue; } dictionary[drop] = 1; list.Add(drop); } } drops.Clear(); foreach (GameObject item in list) { float resouceEarlyCache = Deathlink.pcfg().GetResouceEarlyCache(item); int num = ((resouceEarlyCache == 1f) ? dictionary[item] : ScaleCount(dictionary[item], resouceEarlyCache)); if (num != dictionary[item]) { Logger.LogDebug($"Scaling harvest drop {((Object)item).name}: {dictionary[item]} -> {num} (x{resouceEarlyCache})"); } for (int i = 0; i < num; i++) { drops.Add(item); } } } private static void SpawnHarvestBonusLoot(Vector3 position) { //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_004d: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) List<KeyValuePair<GameObject, int>> list = Deathlink.pcfg().RollHarvestLoot(); if (list.Count == 0) { return; } foreach (KeyValuePair<GameObject, int> item in list) { for (int i = 0; i < item.Value; i++) { Quaternion val = Quaternion.Euler(0f, (float)Random.Range(0, 360), 0f); Object.Instantiate<GameObject>(item.Key, position, val); } } } } internal static class LeaderboardData { [HarmonyPatch(typeof(Player), "OnDeath")] public static class Leaderboard_OnDeath_Patch { [HarmonyPrefix] public static void Prefix(Player __instance) { if (ValConfig.EnableLeaderboard.Value && !((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { long num = (long)Mathf.Max(0f, __instance.m_timeSinceDeath); long longKey = GetLongKey(__instance, DataObjects.LeaderboardDeathCountKey); long longKey2 = GetLongKey(__instance, DataObjects.LeaderboardTotalLifeKey); long longKey3 = GetLongKey(__instance, DataObjects.LeaderboardLongestLifeKey); if (longKey == 0L) { SetLongKey(__instance, DataObjects.LeaderboardFirstLifeKey, num); } SetLongKey(__instance, DataObjects.LeaderboardDeathCountKey, longKey + 1); SetLongKey(__instance, DataObjects.LeaderboardTotalLifeKey, longKey2 + num); if (num > longKey3) { SetLongKey(__instance, DataObjects.LeaderboardLongestLifeKey, num); } } } } [HarmonyPatch(typeof(Character), "Damage")] public static class Leaderboard_Damage_Patch { [HarmonyPostfix] public static void Postfix(Character __instance, HitData hit) { if (ValConfig.EnableLeaderboard.Value && hit != null && !((Object)(object)Player.m_localPlayer == (Object)null) && !(__instance is Player) && !((Object)(object)hit.GetAttacker() != (Object)(object)Player.m_localPlayer)) { long num = (long)Mathf.Max(0f, hit.GetTotalDamage()); if (num > 0) { sessionDamage += num; } } } } [HarmonyPatch(typeof(Player), "OnSpawned")] public static class Leaderboard_OnSpawned_Patch { [HarmonyPostfix] public static void Postfix(Player __instance) { if (!ValConfig.EnableLeaderboard.Value || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || initialReportSent) { return; } initialReportSent = true; try { SendLocalSnapshotToServer(); } catch (Exception arg) { Logger.LogWarning($"Initial leaderboard report failed: {arg}"); } } } [HarmonyPatch(typeof(Game), "Shutdown")] public static class Leaderboard_Shutdown_Patch { [HarmonyPrefix] public static void Prefix() { if (ValConfig.EnableLeaderboard.Value) { try { FlushLocalSnapshotToServer(); } catch (Exception arg) { Logger.LogWarning($"Leaderboard disconnect flush failed: {arg}"); } } initialReportSent = false; sessionDamage = 0L; } } public static Dictionary<long, DataObjects.LeaderboardEntry> leaderboard = new Dictionary<long, DataObjects.LeaderboardEntry>(); private static CustomRPC leaderboardRPC; private static long sessionDamage = 0L; private static bool initialReportSent = false; internal static void Init() { try { if (File.Exists(ValConfig.leaderboardPath)) { UpdateLeaderboardFromYaml(File.ReadAllText(ValConfig.leaderboardPath)); } } catch (Exception arg) { Logger.LogWarning($"Failed to load leaderboard data, starting empty. Exception: {arg}"); } } public static void Write() { try { File.WriteAllText(ValConfig.leaderboardPath, DataObjects.yamlserializer.Serialize((object)leaderboard)); } catch (Exception arg) { Logger.LogWarning($"Failed to write leaderboard data. Exception: {arg}"); } } public static void UpdateLeaderboardFromYaml(string rawyaml) { if (!string.IsNullOrWhiteSpace(rawyaml)) { Dictionary<long, DataObjects.LeaderboardEntry> dictionary = DataObjects.leaderboardDeserializer.Deserialize<Dictionary<long, DataObjects.LeaderboardEntry>>(rawyaml); if (dictionary != null) { leaderboard = dictionary; } } } public static void MergeSnapshot(DataObjects.LeaderboardEntry entry) { if (entry != null && entry.PlayerID != 0L) { leaderboard[entry.PlayerID] = entry; Write(); } } public static void SetupRPC() { //IL_0011: 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_0027: Expected O, but got Unknown //IL_0027: Expected O, but got Unknown leaderboardRPC = NetworkManager.Instance.AddRPC("DEATHLK_LB", new CoroutineHandler(OnServerReceiveSnapshot), new CoroutineHandler(OnClientReceiveBoard)); SynchronizationManager.Instance.AddInitialSynchronization(leaderboardRPC, (Func<ZPackage>)SendFullBoardPackage); } private static IEnumerator OnServerReceiveSnapshot(long sender, ZPackage package) { try { bool num = package.ReadBool(); string text = package.ReadString(); MergeSnapshot(DataObjects.leaderboardDeserializer.Deserialize<DataObjects.LeaderboardEntry>(text)); if (num && leaderboardRPC != null) { leaderboardRPC.SendPackage(sender, SendFullBoardPackage()); } } catch (Exception arg) { Logger.LogWarning($"Failed to parse leaderboard snapshot from {sender}. Exception: {arg}"); } yield return null; } private static IEnumerator OnClientReceiveBoard(long sender, ZPackage package) { string rawyaml = package.ReadString(); try { UpdateLeaderboardFromYaml(rawyaml); LeaderboardUI.RefreshIfVisible(); } catch (Exception arg) { Logger.LogWarning($"Failed to parse leaderboard board. Exception: {arg}"); } yield return null; } private static ZPackage SendFullBoardPackage() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write(DataObjects.yamlserializer.Serialize((object)leaderboard)); return val; } public static void BroadcastFullBoard() { if (!((Object)(object)ZNet.instance == (Object)null) && leaderboardRPC != null) { leaderboardRPC.SendPackage(ZNet.instance.m_peers, SendFullBoardPackage()); } } public static void SendLocalSnapshotToServer(bool requestBoard = false) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown DataObjects.LeaderboardEntry leaderboardEntry = BuildLocalSnapshot(); if (leaderboardEntry == null) { return; } if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { MergeSnapshot(leaderboardEntry); if (requestBoard) { LeaderboardUI.RefreshIfVisible(); } } else if (leaderboardRPC != null && ZRoutedRpc.instance != null) { ZPackage val = new ZPackage(); val.Write(requestBoard); val.Write(DataObjects.yamlserializer.Serialize((object)leaderboardEntry)); leaderboardRPC.SendPackage(ZRoutedRpc.instance.GetServerPeerID(), val); } } public static void RequestDashboardSync() { if (!ValConfig.EnableLeaderboard.Value || (Object)(object)ZNet.instance == (Object)null) { return; } try { SendLocalSnapshotToServer(requestBoard: true); } catch (Exception arg) { Logger.LogWarning($"Leaderboard dashboard sync failed: {arg}"); } } public static void FlushLocalSnapshotToServer() { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected O, but got Unknown if ((Object)(object)ZNet.instance == (Object)null) { return; } if (ZNet.instance.IsServer()) { if ((Object)(object)Player.m_localPlayer != (Object)null) { DataObjects.LeaderboardEntry leaderboardEntry = BuildLocalSnapshot(); if (leaderboardEntry != null) { MergeSnapshot(leaderboardEntry); } } } else { if ((Object)(object)Player.m_localPlayer == (Object)null || leaderboardRPC == null) { return; } ZNetPeer serverPeer = ZNet.instance.GetServerPeer(); if (serverPeer == null) { return; } DataObjects.LeaderboardEntry leaderboardEntry2 = BuildLocalSnapshot(); if (leaderboardEntry2 != null) { ZPackage val = new ZPackage(); val.Write(false); val.Write(DataObjects.yamlserializer.Serialize((object)leaderboardEntry2)); IEnumerator enumerator = leaderboardRPC.SendPackageRoutine(new List<ZNetPeer> { serverPeer }, val); while (enumerator.MoveNext()) { } } } } public static DataObjects.LeaderboardEntry BuildLocalSnapshot() { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return null; } PlayerProfile val = (((Object)(object)Game.instance != (Object)null) ? Game.instance.GetPlayerProfile() : null); if (val == null || val.m_playerStats == null) { return null; } Dictionary<PlayerStatType, float> stats = val.m_playerStats.m_stats; long num = GetLongKey(localPlayer, DataObjects.LeaderboardDamageKey); if (sessionDamage > 0) { num += sessionDamage; SetLongKey(localPlayer, DataObjects.LeaderboardDamageKey, num); sessionDamage = 0L; } return new DataObjects.LeaderboardEntry { PlayerID = localPlayer.GetPlayerID(), PlayerName = val.GetName(), DeathChoice = (DeathConfigurationData.playerDeathConfiguration?.DisplayName ?? ""), FirstLifeSeconds = GetLongKey(localPlayer, DataObjects.LeaderboardFirstLifeKey), LongestLifeSeconds = GetLongKey(localPlayer, DataObjects.LeaderboardLongestLifeKey), TotalLifeSeconds = GetLongKey(localPlayer, DataObjects.LeaderboardTotalLifeKey), DeathCount = (int)GetLongKey(localPlayer, DataObjects.LeaderboardDeathCountKey), TotalDamage = num, BossKills = (int)stats[(PlayerStatType)85], TreeChops = (int)stats[(PlayerStatType)27], Mines = (int)stats[(PlayerStatType)38], CraftsAndBuilds = (int)(stats[(PlayerStatType)1] + stats[(PlayerStatType)2]) }; } public static IEnumerator SyncLoop() { yield return (object)new WaitForSeconds(60f); while (true) { float num = Mathf.Max(60f, ValConfig.LeaderboardSyncInterval.Value * 60f); if (ValConfig.EnableLeaderboard.Value && (Object)(object)ZNet.instance != (Object)null) { try { if (ZNet.instance.IsServer()) { if ((Object)(object)Player.m_localPlayer != (Object)null) { SendLocalSnapshotToServer(); } BroadcastFullBoard(); } else if ((Object)(object)Player.m_localPlayer != (Object)null) { SendLocalSnapshotToServer(); } } catch (Exception arg) { Logger.LogWarning($"Leaderboard sync tick failed: {arg}"); } } yield return (object)new WaitForSeconds(num); } } private static long GetLongKey(Player player, string key) { string s = default(string); if (player.TryGetUniqueKeyValue(key, ref s) && long.TryParse(s, out var result)) { return result; } return 0L; } private static void SetLongKey(Player player, string key, long value) { player.PlayerRemoveUniqueKey(key); player.AddUniqueKeyValue(key, value.ToString()); } } public static class LeaderboardUI { [HarmonyPatch(typeof(TextsDialog), "ShowText", new Type[] { typeof(TextInfo) })] public static class TextsDialog_ShowText_Leaderboard_Patch { public static void Postfix(TextsDialog __instance, TextInfo text) { bool flag = text != null && text.m_topic == DeathlinkSettingsTopic; if (!ValConfig.EnableLeaderboard.Value || !flag) { if ((Object)(object)leaderboardButton != (Object)null) { leaderboardButton.SetActive(false); } return; } EnsureLeaderboardButton(__instance); if ((Object)(object)leaderboardButton != (Object)null) { leaderboardButton.SetActive(true); leaderboardButton.transform.SetAsLastSibling(); } } private static void EnsureLeaderboardButton(TextsDialog dialog) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Expected O, but got Unknown if ((Object)(object)leaderboardButton != (Object)null) { return; } if (GUIManager.Instance == null) { Logger.LogWarning("GUIManager not setup, skipping leaderboard button creation."); return; } Transform val = ((Component)dialog).transform.Find("Texts_frame/Closebutton"); if (!((Object)(object)val == (Object)null)) { leaderboardButton = GUIManager.Instance.CreateButton(Localization.instance.Localize("$leaderboard"), val, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(-250f, 0f), 200f, 40f); ((UnityEvent)leaderboardButton.GetComponent<Button>().onClick).AddListener(new UnityAction(Show)); } } } [HarmonyPatch(typeof(TextsDialog), "OnClose")] public static class TextsDialog_OnClose_Leaderboard_Patch { public static void Postfix() { Hide(); } } [HarmonyPatch(typeof(InventoryGui), "Hide")] public static class InventoryGui_Hide_Leaderboard_Patch { public static void Postfix() { Hide(); } } private const int ViewSurvival = 0; private const int ViewCombat = 1; private const int ViewGathering = 2; private static GameObject panel; private static GameObject content; private static readonly List<GameObject> rows = new List<GameObject>(); private static readonly Text[] headerCols = (Text[])(object)new Text[5]; private static int currentView = 0; private const float RowWidth = 820f; private const float RowHeight = 30f; private static readonly (float x, float w)[] columns = new(float, float)[5] { (-310f, 200f), (-135f, 150f), (25f, 150f), (185f, 150f), (340f, 140f) }; private static GameObject leaderboardButton; public static bool IsVisible { get { if ((Object)(object)panel != (Object)null) { return panel.activeSelf; } return false; } } private static string DeathlinkSettingsTopic => Localization.instance.Localize("$deathlink_settings"); public static void Show() { if (EnsurePanel()) { panel.SetActive(true); PopulateView(currentView); LeaderboardData.RequestDashboardSync(); } } public static void Hide() { if ((Object)(object)panel != (Object)null) { panel.SetActive(false); } } public static void RefreshIfVisible() { if (IsVisible) { PopulateView(currentView); } } private static bool EnsurePanel() { //IL_0047: 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_0065: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Expected O, but got Unknown //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_024e: 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) if ((Object)(object)panel != (Object)null) { return true; } if (GUIManager.Instance == null || !Object.op_Implicit((Object)(object)GUIManager.CustomGUIFront)) { Logger.LogWarning("GUIManager not setup, skipping leaderboard panel creation."); return false; } panel = GUIManager.Instance.CreateWoodpanel(GUIManager.CustomGUIFront.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, 0f), 900f, 680f, true); panel.SetActive(false); GUIManager.Instance.CreateText(Localization.instance.Localize("$leaderboard"), panel.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, 290f), GUIManager.Instance.AveriaSerifBold, 30, GUIManager.Instance.ValheimOrange, true, Color.black, 500f, 40f, false); ((UnityEvent)GUIManager.Instance.CreateButton(Localization.instance.Localize("$close"), panel.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(420f, 300f), 50f, 50f).GetComponent<Button>().onClick).AddListener(new UnityAction(Hide)); CreateViewButton("$leaderboard_survival", -230f, 0); CreateViewButton("$leaderboard_combat", 0f, 1); CreateViewButton("$leaderboard_gathering", 230f, 2); for (int i = 0; i < headerCols.Length; i++) { headerCols[i] = CreateText(panel, new Vector2(columns[i].x, 200f), columns[i].w, "", GUIManager.Instance.ValheimOrange, 18); } GameObject obj = GUIManager.Instance.CreateScrollView(panel.transform, false, true, 10f, 10f, GUIManager.Instance.ValheimScrollbarHandleColorBlock, Color.grey, 860f, 440f); obj.transform.localPosition = Vector2.op_Implicit(new Vector2(0f, -70f)); obj.GetComponentInChildren<ScrollRect>().scrollSensitivity = 200f; content = ((Component)obj.GetComponentInChildren<ContentSizeFitter>()).gameObject; VerticalLayoutGroup val = content.GetComponent<VerticalLayoutGroup>(); if ((Object)(object)val == (Object)null) { val = content.AddComponent<VerticalLayoutGroup>(); } ((LayoutGroup)val).childAlignment = (TextAnchor)1; ((HorizontalOrVerticalLayoutGroup)val).childControlWidth = false; ((HorizontalOrVerticalLayoutGroup)val).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)val).childForceExpandWidth = false; ((HorizontalOrVerticalLayoutGroup)val).childForceExpandHeight = false; ((HorizontalOrVerticalLayoutGroup)val).spacing = 2f; return true; } private static void CreateViewButton(string locKey, float x, int view) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Expected O, but got Unknown ((UnityEvent)GUIManager.Instance.CreateButton(Localization.instance.Localize(locKey), panel.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(x, 240f), 200f, 44f).GetComponent<Button>().onClick).AddListener((UnityAction)delegate { PopulateView(view); }); } public static void PopulateView(int view) { currentView = view; if (!EnsurePanel()) { return; } foreach (GameObject row in rows) { if ((Object)(object)row != (Object)null) { Object.Destroy((Object)(object)row); } } rows.Clear(); SetHeaderLabels(view); foreach (DataObjects.LeaderboardEntry item in view switch { 1 => from e in LeaderboardData.leaderboard.Values orderby e.BossKills descending, e.TotalDamage descending select e, 2 => LeaderboardData.leaderboard.Values.OrderByDescending((DataObjects.LeaderboardEntry e) => e.TreeChops + e.Mines + e.CraftsAndBuilds), _ => LeaderboardData.leaderboard.Values.OrderByDescending((DataObjects.LeaderboardEntry e) => e.LongestLifeSeconds), }) { rows.Add(CreateRow(item, view)); } } private static void SetHeaderLabels(int view) { string[] array = view switch { 1 => new string[5] { "$lb_col_player", "$lb_col_choice", "$lb_damage", "$lb_bosses", "" }, 2 => new string[5] { "$lb_col_player", "$lb_col_choice", "$lb_trees", "$lb_mining", "$lb_crafts" }, _ => new string[5] { "$lb_col_player", "$lb_col_choice", "$lb_first", "$lb_longest", "$lb_average" }, }; for (int i = 0; i < headerCols.Length; i++) { headerCols[i].text = (string.IsNullOrEmpty(array[i]) ? "" : Localization.instance.Localize(array[i])); } } private static GameObject CreateRow(DataObjects.LeaderboardEntry entry, int view) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown //IL_0047: 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_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_013f: 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_018f: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_0220: 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_0266: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_02d1: Unknown result type (might be due to invalid IL or missing references) //IL_02f4: Unknown result type (might be due to invalid IL or missing references) //IL_0314: Unknown result type (might be due to invalid IL or missing references) //IL_0337: 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) GameObject val = new GameObject("LBRow", new Type[2] { typeof(RectTransform), typeof(LayoutElement) }); val.transform.SetParent(content.transform, false); ((RectTransform)val.transform).sizeDelta = new Vector2(820f, 30f); LayoutElement component = val.GetComponent<LayoutElement>(); component.preferredHeight = 30f; component.minHeight = 30f; component.preferredWidth = 820f; CreateText(val, new Vector2(columns[0].x, 0f), columns[0].w, entry.PlayerName ?? "", GUIManager.Instance.ValheimYellow, 16); CreateText(val, new Vector2(columns[1].x, 0f), columns[1].w, entry.DeathChoice ?? "", Color.white, 16); switch (view) { case 1: CreateText(val, new Vector2(columns[2].x, 0f), columns[2].w, Mathf.RoundToInt(entry.TotalDamage).ToString("N0"), Color.white, 16); CreateText(val, new Vector2(columns[3].x, 0f), columns[3].w, entry.BossKills.ToString(), Color.white, 16); break; case 2: CreateText(val, new Vector2(columns[2].x, 0f), columns[2].w, entry.TreeChops.ToString(), Color.white, 16); CreateText(val, new Vector2(columns[3].x, 0f), columns[3].w, entry.Mines.ToString(), Color.white, 16); CreateText(val, new Vector2(columns[4].x, 0f), columns[4].w, entry.CraftsAndBuilds.ToString(), Color.white, 16); break; default: CreateText(val, new Vector2(columns[2].x, 0f), columns[2].w, FormatMinutes(entry.FirstLifeSeconds), Color.white, 16); CreateText(val, new Vector2(columns[3].x, 0f), columns[3].w, FormatMinutes(entry.LongestLif