using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Dynamic; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Linq.Expressions; using System.Net; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using System.Xml.Serialization; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using ItemDataManager; using JetBrains.Annotations; using Jewelcrafting; using LocalizationManager; using Microsoft.CodeAnalysis; using PieceManager; using ServerSync; using SkillManager; using TMPro; using UnityEngine; using UnityEngine.Audio; using UnityEngine.Events; using UnityEngine.UI; using YamlDotNet.Core; using YamlDotNet.Core.Events; using YamlDotNet.Core.ObjectPool; using YamlDotNet.Core.Tokens; using YamlDotNet.Helpers; using YamlDotNet.Serialization; using YamlDotNet.Serialization.BufferedDeserialization; using YamlDotNet.Serialization.BufferedDeserialization.TypeDiscriminators; using YamlDotNet.Serialization.Callbacks; using YamlDotNet.Serialization.Converters; using YamlDotNet.Serialization.EventEmitters; using YamlDotNet.Serialization.NamingConventions; using YamlDotNet.Serialization.NodeDeserializers; using YamlDotNet.Serialization.NodeTypeResolvers; using YamlDotNet.Serialization.ObjectFactories; using YamlDotNet.Serialization.ObjectGraphTraversalStrategies; using YamlDotNet.Serialization.ObjectGraphVisitors; using YamlDotNet.Serialization.Schemas; using YamlDotNet.Serialization.TypeInspectors; using YamlDotNet.Serialization.TypeResolvers; using YamlDotNet.Serialization.Utilities; using YamlDotNet.Serialization.ValueDeserializers; using fastJSON; using kg.ValheimEnchantmentSystem; using kg.ValheimEnchantmentSystem.Configs; using kg.ValheimEnchantmentSystem.Integrations; using kg.ValheimEnchantmentSystem.Items_Structures; using kg.ValheimEnchantmentSystem.Misc; using kg.ValheimEnchantmentSystem.Platform; using kg.ValheimEnchantmentSystem.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("ValheimEnchantmentSystem")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ValheimEnchantmentSystem")] [assembly: AssemblyCopyright("Copyright © 2023")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("02E7D016-77BE-40E0-9D13-8656CD0A4FD3")] [assembly: AssemblyFileVersion("1.9.8.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.9.8.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } public static class AnimationSpeedManager { public delegate double Handler(Character character, double speed); private static readonly Harmony Harmony = new Harmony("kg.ValheimEnchantmentSystem.AnimationSpeedManager"); private static readonly MethodInfo TargetMethod = AccessTools.DeclaredMethod(typeof(CharacterAnimEvent), "CustomFixedUpdate", (Type[])null, (Type[])null); private static readonly Dictionary> HandlersByPriority = new Dictionary>(); private static Handler[][] _handlers = Array.Empty(); private static bool _markerPatchInstalled; private static bool _wrapperInstalled; private static int _handlerIndex; private static bool _changed; [PublicAPI] public static void Add(Handler handler, int priority = 400) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Expected O, but got Unknown if (!_markerPatchInstalled) { Harmony.Patch((MethodBase)TargetMethod, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(AnimationSpeedManager), "MarkerPatch", (Type[])null, (Type[])null)), (HarmonyMethod)null); _markerPatchInstalled = true; } if (!HandlersByPriority.TryGetValue(priority, out List value)) { value = new List(); HandlersByPriority.Add(priority, value); } if (!_wrapperInstalled) { Harmony.Patch((MethodBase)TargetMethod, (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(AnimationSpeedManager), "Wrapper", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _wrapperInstalled = true; } value.Add(handler); _handlers = (from pair in HandlersByPriority orderby pair.Key select pair.Value.ToArray()).ToArray(); } private static void Wrapper(Character ___m_character, Animator ___m_animator) { Character ___m_character2 = ___m_character; double num = (double)___m_animator.speed * 10000000.0 % 100.0; if ((!(num > 10.0) || !(num < 30.0)) && !(___m_animator.speed <= 0.001f)) { double num2 = ___m_animator.speed; double num3 = _handlers[_handlerIndex++].Aggregate(num2, (double current, Handler handler) => handler(___m_character2, current)); if (Math.Abs(num3 - num2) > double.Epsilon) { ___m_animator.speed = (float)(num3 - num3 % 1E-05); _changed = true; } } } private static void MarkerPatch(Animator ___m_animator) { if (_changed) { float speed = ___m_animator.speed; double num = (double)speed * 10000000.0 % 100.0; if ((num < 10.0 || num > 30.0) ? true : false) { ___m_animator.speed += 1.9E-06f; } _changed = false; } _handlerIndex = 0; } } namespace PieceManager { [PublicAPI] public enum CraftingTable { None, [InternalName("piece_workbench")] Workbench, [InternalName("piece_cauldron")] Cauldron, [InternalName("forge")] Forge, [InternalName("piece_artisanstation")] ArtisanTable, [InternalName("piece_stonecutter")] StoneCutter, [InternalName("piece_magetable")] MageTable, [InternalName("blackforge")] BlackForge, [InternalName("piece_preptable")] FoodPreparationTable, [InternalName("piece_MeadCauldron")] MeadKetill, Custom } public class InternalName : Attribute { public readonly string internalName; public InternalName(string internalName) { this.internalName = internalName; } } [PublicAPI] public enum BuildPieceCategory { Misc = 0, Crafting = 1, BuildingWorkbench = 2, BuildingStonecutter = 3, Furniture = 4, All = 100, Custom = 99 } public struct Requirement { public string itemName; public int amount; public bool recover; } [PublicAPI] public class RequiredResourcesList { public readonly List Requirements = new List(); public void Add(string item, int amount, bool recover) { Requirements.Add(new Requirement { itemName = item, amount = amount, recover = recover }); } } public struct CraftingStationConfig { public CraftingTable Table; public string? custom; } [PublicAPI] public class CraftingStationList { public readonly List Stations = new List(); public void Set(CraftingTable table) { Stations.Add(new CraftingStationConfig { Table = table }); } public void Set(string customTable) { Stations.Add(new CraftingStationConfig { Table = CraftingTable.Custom, custom = customTable }); } } [PublicAPI] public class BuildingPieceCategory { public BuildPieceCategory Category; public string custom = ""; public void Set(BuildPieceCategory category) { Category = category; } public void Set(string customCategory) { Category = BuildPieceCategory.Custom; custom = customCategory; } } [PublicAPI] public class PieceTool { public readonly HashSet Tools = new HashSet(); public void Add(string tool) { Tools.Add(tool); } } [PublicAPI] public class BuildPiece { private sealed class PieceConfig { public ConfigEntry? craft; } private static class SerializedRequirements { public static string Serialize(IEnumerable requirements) { return string.Join(",", requirements.Select((Requirement requirement) => $"{requirement.itemName}:{requirement.amount}:{requirement.recover}")); } public static Requirement[] ToPieceReqs(ObjectDB objectDb, IEnumerable requirements) { ObjectDB objectDb2 = objectDb; return (from requirement in requirements.Where((Requirement requirement) => !string.IsNullOrWhiteSpace(requirement.itemName)).Select((Func)delegate(Requirement requirement) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown GameObject itemPrefab = objectDb2.GetItemPrefab(requirement.itemName); ItemDrop val = ((itemPrefab != null) ? itemPrefab.GetComponent() : null); if (!((Object)(object)val == (Object)null)) { return new Requirement { m_resItem = val, m_amount = requirement.amount, m_recover = requirement.recover }; } Debug.LogWarning((object)(Plugin.Info.Metadata.GUID + ": required build piece item '" + requirement.itemName + "' does not exist.")); return null; }) where requirement != null select requirement).ToArray(); } public static Requirement[] ToPieceReqs(ObjectDB objectDb, string serialized) { return ToPieceReqs(objectDb, serialized.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(delegate(string entry) { string[] array = entry.Split(new char[1] { ':' }); Requirement result = default(Requirement); result.itemName = array[0]; result.amount = ((array.Length <= 1 || !int.TryParse(array[1], out var result2)) ? 1 : result2); bool result3 = default(bool); result.recover = array.Length <= 2 || !bool.TryParse(array[2], out result3) || result3; return result; })); } } private static readonly Harmony Harmony; internal static readonly List registeredPieces; private static readonly Dictionary pieceConfigs; private static bool configBindingsInitialized; [Description("Disables generation of configs for registered pieces.")] public static bool ConfigurationEnabled; public readonly GameObject Prefab; public readonly RequiredResourcesList RequiredItems = new RequiredResourcesList(); public readonly BuildingPieceCategory Category = new BuildingPieceCategory(); public readonly PieceTool Tool = new PieceTool(); public CraftingStationList Crafting = new CraftingStationList(); public ConfigEntryBase? RecipeIsActive; private static BaseUnityPlugin? _plugin; private static BaseUnityPlugin Plugin { get { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown object obj = _plugin; if (obj == null) { BaseUnityPlugin val = (BaseUnityPlugin)Chainloader.ManagerObject.GetComponent((Type)Assembly.GetExecutingAssembly().DefinedTypes.First((TypeInfo t) => t.IsClass && typeof(BaseUnityPlugin).IsAssignableFrom(t))); _plugin = val; obj = (object)val; } return (BaseUnityPlugin)obj; } } static BuildPiece() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected O, but got Unknown //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Expected O, but got Unknown //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Expected O, but got Unknown //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Expected O, but got Unknown Harmony = new Harmony("kg.ValheimEnchantmentSystem.ThinPieceManager"); registeredPieces = new List(); pieceConfigs = new Dictionary(); ConfigurationEnabled = true; Harmony.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(FejdStartup), "Awake", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(BuildPiece), "Patch_FejdStartup", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Harmony.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(ObjectDB), "Awake", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(BuildPiece), "Patch_ObjectDBInit", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Harmony.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(ObjectDB), "CopyOtherDB", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(BuildPiece), "Patch_ObjectDBInit", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Harmony.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(ZNetScene), "Awake", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(BuildPiece), "Patch_ZNetSceneAwake", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } public BuildPiece(AssetBundle bundle, string prefabName) { Prefab = bundle.LoadAsset(prefabName) ?? throw new InvalidOperationException("Could not load piece prefab '" + prefabName + "' from asset bundle."); ((Object)Prefab).name = prefabName; ApplyStaticDefaults(this); registeredPieces.Add(this); } private static void Patch_FejdStartup() { EnsureConfigBindings(); } internal static void Patch_ObjectDBInit(ObjectDB __instance) { EnsureConfigBindings(); if ((Object)(object)__instance.GetItemPrefab("Hammer") == (Object)null) { return; } foreach (BuildPiece registeredPiece in registeredPieces) { ApplyRuntimeConfiguration(registeredPiece, __instance, ZNetScene.instance); } } internal static void Patch_ZNetSceneAwake(ZNetScene __instance) { foreach (BuildPiece registeredPiece in registeredPieces) { if (!__instance.m_prefabs.Contains(registeredPiece.Prefab)) { __instance.m_prefabs.Add(registeredPiece.Prefab); } int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)registeredPiece.Prefab).name); if (!__instance.m_namedPrefabs.ContainsKey(stableHashCode)) { __instance.m_namedPrefabs.Add(stableHashCode, registeredPiece.Prefab); } } } internal static void EnsureConfigBindings() { //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Expected O, but got Unknown if (configBindingsInitialized) { return; } foreach (BuildPiece piece in registeredPieces) { ApplyStaticDefaults(piece); if (ConfigurationEnabled) { string token = piece.Prefab.GetComponent()?.m_name ?? ((Object)piece.Prefab).name; string localizedDisplayName = GetLocalizedDisplayName(token, ((Object)piece.Prefab).name); string text = SharedLocalizationCache.LocalizeForConfig(token); string group = (string.IsNullOrWhiteSpace(text) ? localizedDisplayName : text); PieceConfig pieceConfig2 = (pieceConfigs[piece] = new PieceConfig()); PieceConfig pieceConfig3 = pieceConfig2; pieceConfig3.craft = Config(group, "Crafting Costs", SerializedRequirements.Serialize(piece.RequiredItems.Requirements), new ConfigDescription("Item costs to craft " + localizedDisplayName + ".", (AcceptableValueBase)null, Array.Empty())); pieceConfig3.craft.SettingChanged += delegate { ReapplyRuntimeConfiguration(piece); }; } } configBindingsInitialized = true; } private static void ReapplyRuntimeConfiguration(BuildPiece piece) { if (!((Object)(object)ObjectDB.instance == (Object)null)) { ApplyRuntimeConfiguration(piece, ObjectDB.instance, ZNetScene.instance); } } private static void ApplyStaticDefaults(BuildPiece piece) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) Piece component = piece.Prefab.GetComponent(); if (!((Object)(object)component == (Object)null)) { component.m_category = (PieceCategory)((piece.Category.Category == BuildPieceCategory.Custom) ? BuildPieceCategory.Crafting : piece.Category.Category); } } private static void ApplyRuntimeConfiguration(BuildPiece piece, ObjectDB objectDb, ZNetScene? scene) { Piece component = piece.Prefab.GetComponent(); if ((Object)(object)component == (Object)null) { return; } if (pieceConfigs.TryGetValue(piece, out PieceConfig value)) { ConfigEntry craft = value.craft; if (craft != null) { component.m_resources = SerializedRequirements.ToPieceReqs(objectDb, craft.Value); goto IL_005a; } } component.m_resources = SerializedRequirements.ToPieceReqs(objectDb, piece.RequiredItems.Requirements); goto IL_005a; IL_005a: ApplyCraftingStation(piece, component, scene); ApplyToolRegistration(piece, objectDb); ConfigEntryBase recipeIsActive = piece.RecipeIsActive; if (recipeIsActive != null) { component.m_enabled = Convert.ToInt32(recipeIsActive.BoxedValue) != 0; } } private static void ApplyCraftingStation(BuildPiece piece, Piece pieceComponent, ZNetScene? scene) { if (piece.Crafting.Stations.Count == 0 || (Object)(object)scene == (Object)null) { pieceComponent.m_craftingStation = null; return; } CraftingStationConfig craftingStationConfig = piece.Crafting.Stations.First(); switch (craftingStationConfig.Table) { case CraftingTable.None: pieceComponent.m_craftingStation = null; break; case CraftingTable.Custom: { GameObject prefab2 = scene.GetPrefab(craftingStationConfig.custom); pieceComponent.m_craftingStation = ((prefab2 != null) ? prefab2.GetComponent() : null); break; } default: { GameObject prefab = scene.GetPrefab(GetInternalName(craftingStationConfig.Table)); pieceComponent.m_craftingStation = ((prefab != null) ? prefab.GetComponent() : null); break; } } } private static void ApplyToolRegistration(BuildPiece piece, ObjectDB objectDb) { foreach (GameObject item in objectDb.m_items) { (item.GetComponent()?.m_itemData?.m_shared?.m_buildPieces)?.m_pieces.Remove(piece.Prefab); } IEnumerable enumerable = piece.Tool.Tools.DefaultIfEmpty("Hammer"); foreach (string item2 in enumerable) { GameObject itemPrefab = objectDb.GetItemPrefab(item2); if (Object.op_Implicit((Object)(object)itemPrefab)) { PieceTable val = itemPrefab.GetComponent()?.m_itemData?.m_shared?.m_buildPieces; if ((Object)(object)val != (Object)null && !val.m_pieces.Contains(piece.Prefab)) { val.m_pieces.Add(piece.Prefab); } } } } private static string GetLocalizedDisplayName(string? token, string fallback) { if (string.IsNullOrWhiteSpace(token) || Localization.instance == null) { return fallback; } string text = Localization.instance.Localize(token).Trim(); if (!string.IsNullOrWhiteSpace(text) && !string.Equals(text, token, StringComparison.Ordinal)) { return text; } return fallback; } private static string GetInternalName(CraftingTable value) { return ((InternalName)typeof(CraftingTable).GetMember(value.ToString())[0].GetCustomAttributes(typeof(InternalName), inherit: false).First()).internalName; } private static ConfigEntry Config(string group, string name, T value, ConfigDescription description) { return ValheimEnchantmentSystem.config(group, name, value, description); } } } namespace SkillManager { [PublicAPI] public class Skill { private readonly struct SavedSkillState { public readonly float Level; public readonly float Accumulator; public SavedSkillState(float level, float accumulator) { Level = level; Accumulator = accumulator; } } public static class LocalizationCache { internal static void LocalizationPostfix(Localization __instance, string language) { SharedLocalizationCache.Track(__instance, language); } public static Localization ForLanguage(string? language = null) { return SharedLocalizationCache.ForLanguage(language); } public static string LocalizeForConfig(string token, string preferredLanguage = "English") { return SharedLocalizationCache.LocalizeForConfig(token, preferredLanguage); } } [PublicAPI] public class LocalizeKey { private static readonly List keys = new List(); public readonly string Key; public readonly Dictionary Localizations = new Dictionary(); public LocalizeKey(string key) { Key = key.Replace("$", ""); keys.Add(this); } public void Alias(string alias) { Localizations.Clear(); if (!alias.Contains("$")) { alias = "$" + alias; } Localizations["alias"] = alias; if (Localization.m_instance != null) { Localization.instance.AddWord(Key, Localization.instance.Localize(alias)); } } public LocalizeKey English(string key) { return addForLang("English", key); } public LocalizeKey Swedish(string key) { return addForLang("Swedish", key); } public LocalizeKey French(string key) { return addForLang("French", key); } public LocalizeKey Italian(string key) { return addForLang("Italian", key); } public LocalizeKey German(string key) { return addForLang("German", key); } public LocalizeKey Spanish(string key) { return addForLang("Spanish", key); } public LocalizeKey Russian(string key) { return addForLang("Russian", key); } public LocalizeKey Romanian(string key) { return addForLang("Romanian", key); } public LocalizeKey Bulgarian(string key) { return addForLang("Bulgarian", key); } public LocalizeKey Macedonian(string key) { return addForLang("Macedonian", key); } public LocalizeKey Finnish(string key) { return addForLang("Finnish", key); } public LocalizeKey Danish(string key) { return addForLang("Danish", key); } public LocalizeKey Norwegian(string key) { return addForLang("Norwegian", key); } public LocalizeKey Icelandic(string key) { return addForLang("Icelandic", key); } public LocalizeKey Turkish(string key) { return addForLang("Turkish", key); } public LocalizeKey Lithuanian(string key) { return addForLang("Lithuanian", key); } public LocalizeKey Czech(string key) { return addForLang("Czech", key); } public LocalizeKey Hungarian(string key) { return addForLang("Hungarian", key); } public LocalizeKey Slovak(string key) { return addForLang("Slovak", key); } public LocalizeKey Polish(string key) { return addForLang("Polish", key); } public LocalizeKey Dutch(string key) { return addForLang("Dutch", key); } public LocalizeKey Portuguese_European(string key) { return addForLang("Portuguese_European", key); } public LocalizeKey Portuguese_Brazilian(string key) { return addForLang("Portuguese_Brazilian", key); } public LocalizeKey Chinese(string key) { return addForLang("Chinese", key); } public LocalizeKey Japanese(string key) { return addForLang("Japanese", key); } public LocalizeKey Korean(string key) { return addForLang("Korean", key); } public LocalizeKey Hindi(string key) { return addForLang("Hindi", key); } public LocalizeKey Thai(string key) { return addForLang("Thai", key); } public LocalizeKey Abenaki(string key) { return addForLang("Abenaki", key); } public LocalizeKey Croatian(string key) { return addForLang("Croatian", key); } public LocalizeKey Georgian(string key) { return addForLang("Georgian", key); } public LocalizeKey Greek(string key) { return addForLang("Greek", key); } public LocalizeKey Serbian(string key) { return addForLang("Serbian", key); } public LocalizeKey Ukrainian(string key) { return addForLang("Ukrainian", key); } private LocalizeKey addForLang(string lang, string value) { Localizations[lang] = value; if (Localization.m_instance != null) { if (Localization.instance.GetSelectedLanguage() == lang) { Localization.instance.AddWord(Key, value); } else if (lang == "English" && !Localization.instance.m_translations.ContainsKey(Key)) { Localization.instance.AddWord(Key, value); } } return this; } [HarmonyPriority(300)] internal static void AddLocalizedKeys(Localization __instance, string language) { foreach (LocalizeKey key in keys) { string value2; if (key.Localizations.TryGetValue(language, out string value) || key.Localizations.TryGetValue("English", out value)) { __instance.AddWord(key.Key, value); } else if (key.Localizations.TryGetValue("alias", out value2)) { __instance.AddWord(key.Key, Localization.instance.Localize(value2)); } } } } private class ConfigurationManagerAttributes { [UsedImplicitly] public string? Category; } private static readonly Dictionary skills; internal static readonly Dictionary skillByName; private readonly string skillName; private readonly string internalSkillName; private readonly SkillDef skillDef; public readonly LocalizeKey Name; public readonly LocalizeKey Description; private float skillEffectFactor = 1f; private int skillLoss = 5; public bool Configurable; private static bool configBindingsInitialized; private const string RequiredExperienceFormulaDescription = "Required EXP per level follows: ((current level + 1)^1.5) / 2 + 0.5."; private static bool InitializedTerminal; private static BaseUnityPlugin? _plugin; public float SkillGainFactor { get { return skillDef.m_increseStep; } set { skillDef.m_increseStep = value; this.SkillGainFactorChanged?.Invoke(value); } } public float SkillEffectFactor { get { return skillEffectFactor; } set { skillEffectFactor = value; this.SkillEffectFactorChanged?.Invoke(value); } } public int SkillLoss { get { return skillLoss; } set { skillLoss = value; this.SkillLossChanged?.Invoke(value); } } private static BaseUnityPlugin plugin { get { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown object obj = _plugin; if (obj == null) { BaseUnityPlugin val = (BaseUnityPlugin)Chainloader.ManagerObject.GetComponent((Type)Assembly.GetExecutingAssembly().DefinedTypes.First((TypeInfo t) => t.IsClass && typeof(BaseUnityPlugin).IsAssignableFrom(t))); _plugin = val; obj = (object)val; } return (BaseUnityPlugin)obj; } } public event Action? SkillGainFactorChanged; public event Action? SkillEffectFactorChanged; public event Action? SkillLossChanged; public Skill(string englishName, string icon) : this(englishName, loadSprite(icon, 64, 64)) { } public Skill(string englishName, Sprite icon) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_003a: 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) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0077: 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_0082: Expected O, but got Unknown SkillType val = fromName(englishName); string text = new Regex("[^a-zA-Z]").Replace(englishName, "_"); skills[val] = this; skillByName[englishName] = this; skillDef = new SkillDef { m_description = "$skilldesc_" + text, m_icon = icon, m_increseStep = 1f, m_skill = val }; internalSkillName = text; skillName = englishName; Name = new LocalizeKey("skill_" + ((object)(SkillType)(ref val)).ToString()).English(englishName); Description = new LocalizeKey("skilldesc_" + text); } public static SkillType fromName(string englishName) { return (SkillType)Math.Abs(StringExtensionMethods.GetStableHashCode(englishName)); } static Skill() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Expected O, but got Unknown //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Expected O, but got Unknown //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Expected O, but got Unknown //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Expected O, but got Unknown //IL_016a: Expected O, but got Unknown //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Expected O, but got Unknown //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Expected O, but got Unknown //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Expected O, but got Unknown //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Expected O, but got Unknown //IL_0288: Unknown result type (might be due to invalid IL or missing references) //IL_02a3: Unknown result type (might be due to invalid IL or missing references) //IL_02b0: Expected O, but got Unknown //IL_02b0: Expected O, but got Unknown //IL_02de: Unknown result type (might be due to invalid IL or missing references) //IL_02fb: Unknown result type (might be due to invalid IL or missing references) //IL_0306: Expected O, but got Unknown //IL_0306: Expected O, but got Unknown skills = new Dictionary(); skillByName = new Dictionary(); InitializedTerminal = false; Harmony val = new Harmony("org.bepinex.helpers.skillmanager"); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(FejdStartup), "Awake", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_FejdStartup", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(ZNet), "Awake", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_ZNet_Awake", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Skills), "Awake", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Skills_Awake", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Skills), "GetSkillDef", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Skills_GetSkillDef", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Skills), "Load", (Type[])null, (Type[])null), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Skills_Load_Prefix", (Type[])null, (Type[])null)), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Skills_Load_Postfix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Skills), "IsSkillValid", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Skills_IsSkillValid", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Skills), "CheatRaiseSkill", (Type[])null, (Type[])null), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Skills_CheatRaiseskill", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Skills), "CheatResetSkill", (Type[])null, (Type[])null), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Skills_CheatResetSkill", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Localization), "LoadCSV", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(LocalizeKey), "AddLocalizedKeys", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Terminal), "InitTerminal", (Type[])null, (Type[])null), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Terminal_InitTerminal_Prefix", (Type[])null, (Type[])null)), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Terminal_InitTerminal", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Skills), "OnDeath", (Type[])null, (Type[])null), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Skills_OnDeath_Prefix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Skills_OnDeath_Finalizer", (Type[])null, (Type[])null)), (HarmonyMethod)null); } private static bool IsEnchantmentSkill(Skill skill) { return string.Equals(skill.internalSkillName, "kg_Enchantment", StringComparison.Ordinal); } private static string GetConfigGroup(Skill skill) { if (!IsEnchantmentSkill(skill)) { return skill.internalSkillName; } return "Enchantment"; } private static string GetConfigCategory(Skill skill, string localizedName) { if (!IsEnchantmentSkill(skill)) { return localizedName; } return "Enchantment"; } private static string GetSkillKeyDescription(string skillKey) { return "Skill key: " + skillKey + "."; } private static string GetLocalizedDisplayName(string token, string fallback) { if (Localization.instance == null) { return fallback; } string text = Localization.instance.Localize(token).Trim(); if (!string.IsNullOrWhiteSpace(text)) { return text; } return fallback; } private static void Patch_FejdStartup() { EnsureConfigBindings(); } private static void Patch_ZNet_Awake() { EnsureConfigBindings(); } private static void Patch_Skills_Awake(Skills __instance) { EnsureSkillDefinitions(__instance); } private static void EnsureSkillDefinitions(Skills? skillComponent) { if ((Object)(object)skillComponent == (Object)null) { return; } foreach (Skill customSkill in skills.Values) { if (!skillComponent.m_skills.Any((SkillDef skillDef) => skillDef?.m_skill == (SkillType?)customSkill.skillDef.m_skill)) { skillComponent.m_skills.Add(customSkill.skillDef); } } } private static Dictionary? CaptureCustomSkillStates(ZPackage? pkg) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) if (pkg == null || skills.Count == 0) { return null; } try { ZPackage val = new ZPackage(pkg.GetArray()); val.SetPos(pkg.GetPos()); int num = val.ReadInt(); int num2 = val.ReadInt(); Dictionary dictionary = null; for (int i = 0; i < num2; i++) { SkillType key = (SkillType)val.ReadInt(); float level = val.ReadSingle(); float accumulator = ((num >= 2) ? val.ReadSingle() : 0f); if (skills.ContainsKey(key)) { if (dictionary == null) { dictionary = new Dictionary(); } dictionary[key] = new SavedSkillState(level, accumulator); } } return dictionary; } catch { return null; } } private static void RestoreCustomSkillStates(Skills? skillComponent, Dictionary? capturedStates) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)skillComponent == (Object)null || capturedStates == null || capturedStates.Count == 0) { return; } EnsureSkillDefinitions(skillComponent); foreach (KeyValuePair capturedState in capturedStates) { Skill skill = skillComponent.GetSkill(capturedState.Key); skill.m_level = capturedState.Value.Level; skill.m_accumulator = capturedState.Value.Accumulator; } } private static void Patch_Skills_Load_Prefix(Skills __instance, ZPackage pkg, out Dictionary? __state) { EnsureSkillDefinitions(__instance); __state = CaptureCustomSkillStates(pkg); } private static void Patch_Skills_Load_Postfix(Skills __instance, Dictionary? __state) { RestoreCustomSkillStates(__instance, __state); } private static void EnsureConfigBindings() { //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Expected O, but got Unknown //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Expected O, but got Unknown //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Expected O, but got Unknown if (configBindingsInitialized) { return; } foreach (Skill skill in skills.Values) { if (!skill.Configurable) { continue; } string key = skill.Name.Key; string fallback = new Regex("['[\"\\]]").Replace(LocalizationCache.LocalizeForConfig(key), "").Trim(); string localizedDisplayName = GetLocalizedDisplayName(key, fallback); string configGroup = GetConfigGroup(skill); string configCategory = GetConfigCategory(skill, localizedDisplayName); ConfigEntry skillGain = config(configGroup, "Skill gain factor", skill.SkillGainFactor, new ConfigDescription("The rate at which you gain experience for the skill. " + GetSkillKeyDescription(key) + " Required EXP per level follows: ((current level + 1)^1.5) / 2 + 0.5.", (AcceptableValueBase)(object)new AcceptableValueRange(0.01f, 5f), new object[1] { new ConfigurationManagerAttributes { Category = configCategory } })); skill.SkillGainFactor = skillGain.Value; skillGain.SettingChanged += delegate { skill.SkillGainFactor = skillGain.Value; }; if (!IsEnchantmentSkill(skill)) { ConfigEntry skillEffect = config(configGroup, "Skill effect factor", skill.SkillEffectFactor, new ConfigDescription("The power of the skill, based on the default power.", (AcceptableValueBase)(object)new AcceptableValueRange(0.01f, 5f), new object[1] { new ConfigurationManagerAttributes { Category = configCategory } })); skill.SkillEffectFactor = skillEffect.Value; skillEffect.SettingChanged += delegate { skill.SkillEffectFactor = skillEffect.Value; }; } ConfigEntry skillLoss = config(configGroup, "Skill loss", skill.skillLoss, new ConfigDescription("How much experience to lose on death. " + GetSkillKeyDescription(key) + " Required EXP per level follows: ((current level + 1)^1.5) / 2 + 0.5.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 100), new object[1] { new ConfigurationManagerAttributes { Category = configCategory } })); skill.skillLoss = skillLoss.Value; skillLoss.SettingChanged += delegate { skill.skillLoss = skillLoss.Value; }; } configBindingsInitialized = true; } private static void Patch_Skills_GetSkillDef(ref SkillDef? __result, List ___m_skills, SkillType type) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) if (__result == null) { SkillDef val = GetSkillDef(type); if (val != null) { ___m_skills.Add(val); __result = val; } } } private static bool Patch_Skills_CheatRaiseskill(Skills __instance, string name, float value, Player ___m_player) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) foreach (SkillType key in skills.Keys) { SkillType current = key; Skill skill = skills[current]; if (string.Equals(skill.internalSkillName, name, StringComparison.CurrentCultureIgnoreCase)) { Skill skill2 = __instance.GetSkill(current); skill2.m_level += value; skill2.m_level = Mathf.Clamp(skill2.m_level, 0f, 100f); ((Character)___m_player).Message((MessageType)1, "Skill increased " + Localization.instance.Localize("$skill_" + ((object)(SkillType)(ref current)).ToString()) + ": " + (int)skill2.m_level, 0, skill2.m_info.m_icon); Console.instance.Print("Skill " + skill.internalSkillName + " = " + skill2.m_level); return false; } } return true; } private static bool Patch_Skills_CheatResetSkill(Skills __instance, string name) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) foreach (SkillType key in skills.Keys) { Skill skill = skills[key]; if (string.Equals(skill.internalSkillName, name, StringComparison.CurrentCultureIgnoreCase)) { __instance.ResetSkill(key); Console.instance.Print("Skill " + skill.internalSkillName + " reset"); return false; } } return true; } private static void Patch_Skills_OnDeath_Prefix(Skills __instance, ref Dictionary? __state) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_003d: 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) if (__state == null) { __state = new Dictionary(); } foreach (KeyValuePair skill in skills) { if (__instance.m_skillData.TryGetValue(skill.Key, out var value)) { __state[skill.Key] = value; if (skill.Value.skillLoss > 0) { Skill obj = value; obj.m_level -= value.m_level * (float)skill.Value.SkillLoss / 100f; value.m_accumulator = 0f; } __instance.m_skillData.Remove(skill.Key); } } } private static void Patch_Skills_OnDeath_Finalizer(Skills __instance, ref Dictionary? __state) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) if (__state == null) { return; } foreach (KeyValuePair item in __state) { __instance.m_skillData[item.Key] = item.Value; } __state = null; } private static void Patch_Terminal_InitTerminal_Prefix() { InitializedTerminal = Terminal.m_terminalInitialized; } private static void Patch_Terminal_InitTerminal() { if (!InitializedTerminal) { AddSkill(Terminal.commands["raiseskill"]); AddSkill(Terminal.commands["resetskill"]); } static void AddSkill(ConsoleCommand command) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown ConsoleOptionsFetcher fetcher = command.m_tabOptionsFetcher; command.m_tabOptionsFetcher = (ConsoleOptionsFetcher)delegate { List list = fetcher.Invoke(); list.AddRange(skills.Values.Select((Skill skill) => skill.internalSkillName)); return list; }; } } private static SkillDef? GetSkillDef(SkillType skillType) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) if (!skills.ContainsKey(skillType)) { return null; } Skill skill = skills[skillType]; return skill.skillDef; } private static void Patch_Skills_IsSkillValid(SkillType type, ref bool __result) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) if (!__result && skills.ContainsKey(type)) { __result = true; } } private static byte[] ReadEmbeddedFileBytes(string name) { using MemoryStream memoryStream = new MemoryStream(); Assembly.GetExecutingAssembly().GetManifestResourceStream(Assembly.GetExecutingAssembly().GetName().Name + "." + name).CopyTo(memoryStream); return memoryStream.ToArray(); } private static Texture2D loadTexture(string name) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown Texture2D val = new Texture2D(0, 0); ImageConversion.LoadImage(val, ReadEmbeddedFileBytes("icons." + name)); return val; } private static Sprite loadSprite(string name, int width, int height) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) return Sprite.Create(loadTexture(name), new Rect(0f, 0f, (float)width, (float)height), Vector2.zero); } private static ConfigEntry config(string group, string name, T value, ConfigDescription description) { return ValheimEnchantmentSystem.config(group, name, value, description); } private static ConfigEntry config(string group, string name, T value, string description) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Expected O, but got Unknown return config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty())); } } public static class SkillManagerVersion { public const string Version = "1.7.0"; } [PublicAPI] public static class SkillExtensions { public static float GetSkillFactor(this Character character, string name) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) return character.GetSkillFactor(Skill.fromName(name)) * Skill.skillByName[name].SkillEffectFactor; } public static float GetSkillFactor(this Skills skills, string name) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) return skills.GetSkillFactor(Skill.fromName(name)) * Skill.skillByName[name].SkillEffectFactor; } public static void RaiseSkill(this Character character, string name, float value = 1f) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) character.RaiseSkill(Skill.fromName(name), value); } public static void RaiseSkill(this Skills skill, string name, float value = 1f) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) skill.RaiseSkill(Skill.fromName(name), value); } public static void LowerSkill(this Character character, string name, float factor = 1f) { character.GetSkills().LowerSkill(name, factor); } public static void LowerSkill(this Skills skills, string name, float factor) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (factor > 0f && skills.m_skillData.TryGetValue(Skill.fromName(name), out var value)) { Skill obj = value; obj.m_level -= value.m_level * factor; value.m_accumulator = 0f; } } } } namespace LocalizationManager { [PublicAPI] public static class SharedLocalizationCache { private static readonly Dictionary> Localizations = new Dictionary>(); private static readonly object CacheLock = new object(); public static void Track(Localization localization, string language) { Localization localization2 = localization; lock (CacheLock) { Localization target; string key = Localizations.FirstOrDefault>>((KeyValuePair> pair) => pair.Value.TryGetTarget(out target) && target == localization2).Key; if (key != null) { Localizations.Remove(key); } Localizations[language] = new WeakReference(localization2); } } public static Localization ForLanguage(string? language = null) { bool flag = language != null; string text = language ?? PlayerPrefs.GetString("language", "English"); lock (CacheLock) { if (Localizations.TryGetValue(text, out WeakReference value) && value.TryGetTarget(out var target)) { return target; } } if (Localization.m_instance != null) { Localization instance = Localization.instance; string selectedLanguage = instance.GetSelectedLanguage(); Track(instance, selectedLanguage); if (!flag || string.Equals(selectedLanguage, text, StringComparison.OrdinalIgnoreCase)) { return instance; } throw new InvalidOperationException("Requested localization '" + text + "' is not cached. Active language is '" + selectedLanguage + "'."); } throw new InvalidOperationException("No localization instance is available for language '" + text + "'."); } public static string LocalizeForConfig(string token, string preferredLanguage = "English") { if (string.IsNullOrWhiteSpace(token)) { return string.Empty; } string text = (token.StartsWith("$", StringComparison.Ordinal) ? token : ("$" + token)); string key = text.TrimStart(new char[1] { '$' }); if (Localizer.TryGetConfigText(preferredLanguage, key, out string text2)) { return text2; } try { string text3 = ForLanguage(preferredLanguage).Localize(text).Trim(); if (!string.IsNullOrWhiteSpace(text3) && !string.Equals(text3, text, StringComparison.Ordinal)) { return text3; } } catch { } string text4 = text.TrimStart(new char[1] { '$' }).Replace('_', ' ').Trim(); if (text4.Length != 0) { return text4; } return text; } } [PublicAPI] public class Localizer { private static readonly Dictionary>> PlaceholderProcessors; private static readonly Dictionary> LoadedTexts; private static readonly object LoadedTextsLock; private static readonly ConditionalWeakTable LocalizationLanguage; private static readonly List> LocalizationObjects; private static readonly List FileExtensions; private static BaseUnityPlugin? _plugin; private static readonly object ExternalLocalizationFilesLock; private static Dictionary? _externalLocalizationFiles; private static BaseUnityPlugin plugin { get { //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Expected O, but got Unknown if (_plugin == null) { IEnumerable source; try { source = Assembly.GetExecutingAssembly().DefinedTypes.ToList(); } catch (ReflectionTypeLoadException ex) { source = from t in ex.Types where t != null select t.GetTypeInfo(); } _plugin = (BaseUnityPlugin)Chainloader.ManagerObject.GetComponent((Type)source.First((TypeInfo t) => t.IsClass && typeof(BaseUnityPlugin).IsAssignableFrom(t))); } return _plugin; } } public static event Action? OnLocalizationComplete; private static string? TryParseLanguageFromExternalFile(string filePath) { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(filePath); string text = plugin.Info.Metadata.GUID + "."; if (!fileNameWithoutExtension.StartsWith(text, StringComparison.OrdinalIgnoreCase)) { return null; } string text2 = fileNameWithoutExtension.Substring(text.Length); if (!string.IsNullOrWhiteSpace(text2)) { return text2; } return null; } private static bool HasSupportedExtension(string filePath) { return FileExtensions.Contains(Path.GetExtension(filePath), StringComparer.OrdinalIgnoreCase); } private static Dictionary BuildExternalLocalizationFiles() { Dictionary dictionary = new Dictionary(); string directoryName = Path.GetDirectoryName(Paths.PluginPath); foreach (string item in Directory.GetFiles(directoryName, plugin.Info.Metadata.GUID + ".*", SearchOption.AllDirectories).Where(HasSupportedExtension)) { string text = TryParseLanguageFromExternalFile(item); if (text != null) { if (dictionary.ContainsKey(text)) { Debug.LogWarning((object)("Duplicate key " + text + " found for " + plugin.Info.Metadata.GUID + ". The duplicate file found at " + item + " will be skipped.")); } else { dictionary[text] = item; } } } return dictionary; } private static Dictionary GetExternalLocalizationFiles() { lock (ExternalLocalizationFilesLock) { if (_externalLocalizationFiles == null) { _externalLocalizationFiles = BuildExternalLocalizationFiles(); } return _externalLocalizationFiles; } } private static void UpdatePlaceholderText(Localization localization, string key) { if (!LocalizationLanguage.TryGetValue(localization, out string value) || !LoadedTexts.TryGetValue(value, out Dictionary value2) || !value2.TryGetValue(key, out var value3)) { return; } if (PlaceholderProcessors.TryGetValue(key, out Dictionary> value4)) { value3 = value4.Aggregate(value3, (string current, KeyValuePair> kv) => current.Replace("{" + kv.Key + "}", kv.Value())); } localization.AddWord(key, value3); } public static void AddPlaceholder(string key, string placeholder, ConfigEntry config, Func? convertConfigValue = null) where T : notnull { string key2 = key; string placeholder2 = placeholder; Func convertConfigValue2 = convertConfigValue; ConfigEntry config2 = config; if (convertConfigValue2 == null) { convertConfigValue2 = (T val) => val.ToString(); } if (!PlaceholderProcessors.ContainsKey(key2)) { PlaceholderProcessors[key2] = new Dictionary>(); } config2.SettingChanged += delegate { UpdatePlaceholder(); }; if (Localization.instance != null && LoadedTexts.ContainsKey(Localization.instance.GetSelectedLanguage())) { UpdatePlaceholder(); } void UpdatePlaceholder() { if (Localization.instance != null) { PlaceholderProcessors[key2][placeholder2] = () => convertConfigValue2(config2.Value); UpdatePlaceholderText(Localization.instance, key2); } } } public static void AddText(string key, string text) { List> list = new List>(); foreach (WeakReference localizationObject in LocalizationObjects) { if (localizationObject.TryGetTarget(out var target)) { string orCreateValue = LocalizationLanguage.GetOrCreateValue(target); if (!LoadedTexts.TryGetValue(orCreateValue, out Dictionary value)) { value = new Dictionary(); LoadedTexts[orCreateValue] = value; } if (!target.m_translations.ContainsKey(key)) { value[key] = text; target.AddWord(key, text); } } else { list.Add(localizationObject); } } foreach (WeakReference item in list) { LocalizationObjects.Remove(item); } } public static bool TryGetConfigText(string language, string key, out string text) { text = string.Empty; if (string.IsNullOrWhiteSpace(language) || string.IsNullOrWhiteSpace(key)) { return false; } Dictionary dictionary = EnsureConfigTextsLoaded(language); if (dictionary == null || !dictionary.TryGetValue(key, out var value) || string.IsNullOrWhiteSpace(value)) { return false; } text = value.Trim(); return text.Length > 0; } public static void Load() { _ = plugin; } public static void LoadLocalizationLater(Localization __instance) { LoadLocalization(Localization.instance, __instance.GetSelectedLanguage()); } public static void SafeCallLocalizeComplete() { Localizer.OnLocalizationComplete?.Invoke(); } private static void LoadLocalization(Localization __instance, string language) { if (!LocalizationLanguage.Remove(__instance)) { LocalizationObjects.Add(new WeakReference(__instance)); } LocalizationLanguage.Add(__instance, language); SharedLocalizationCache.Track(__instance, language); Dictionary externalLocalizationFiles = GetExternalLocalizationFiles(); byte[] array = LoadTranslationFromAssembly("English"); if (array == null) { throw new Exception("Found no English localizations in mod " + plugin.Info.Metadata.Name + ". Expected an embedded resource translations/English.json or translations/English.yml."); } Dictionary dictionary = new DeserializerBuilder().IgnoreFields().Build().Deserialize>(Encoding.UTF8.GetString(array)); if (dictionary == null) { throw new Exception("Localization for mod " + plugin.Info.Metadata.Name + " failed: Localization file was empty."); } string text = null; if (language != "English") { if (externalLocalizationFiles.TryGetValue(language, out var value)) { text = File.ReadAllText(value); } else { byte[] array2 = LoadTranslationFromAssembly(language); if (array2 != null) { text = Encoding.UTF8.GetString(array2); } } } if (text == null && externalLocalizationFiles.TryGetValue("English", out var value2)) { text = File.ReadAllText(value2); } if (text != null) { foreach (KeyValuePair item in new DeserializerBuilder().IgnoreFields().Build().Deserialize>(text) ?? new Dictionary()) { dictionary[item.Key] = item.Value; } } LoadedTexts[language] = dictionary; foreach (KeyValuePair item2 in dictionary) { UpdatePlaceholderText(__instance, item2.Key); } } static Localizer() { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Expected O, but got Unknown //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Expected O, but got Unknown //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Expected O, but got Unknown PlaceholderProcessors = new Dictionary>>(); LoadedTexts = new Dictionary>(); LoadedTextsLock = new object(); LocalizationLanguage = new ConditionalWeakTable(); LocalizationObjects = new List>(); FileExtensions = new List(2) { ".json", ".yml" }; ExternalLocalizationFilesLock = new object(); Harmony val = new Harmony("org.bepinex.helpers.LocalizationManager"); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Localization), "SetupLanguage", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "LoadLocalization", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(FejdStartup), "SetupGui", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "LoadLocalizationLater", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(FejdStartup), "Start", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "SafeCallLocalizeComplete", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } private static byte[]? LoadTranslationFromAssembly(string language) { Assembly assembly = typeof(Localizer).Assembly; foreach (string fileExtension in FileExtensions) { byte[] array = ReadEmbeddedFileBytes("translations." + language + fileExtension, assembly); if (array != null) { return array; } } return null; } private static Dictionary? EnsureConfigTextsLoaded(string language) { lock (LoadedTextsLock) { if (LoadedTexts.TryGetValue(language, out Dictionary value)) { return value; } Dictionary externalLocalizationFiles = GetExternalLocalizationFiles(); string text = null; if (externalLocalizationFiles.TryGetValue(language, out var value2)) { text = File.ReadAllText(value2); } else { byte[] array = LoadTranslationFromAssembly(language); if (array != null) { text = Encoding.UTF8.GetString(array); } } if (text == null) { return null; } Dictionary dictionary = new DeserializerBuilder().IgnoreFields().Build().Deserialize>(text); if (dictionary == null) { return null; } LoadedTexts[language] = dictionary; return dictionary; } } public static byte[]? ReadEmbeddedFileBytes(string resourceFileName, Assembly? containingAssembly = null) { string resourceFileName2 = resourceFileName; using MemoryStream memoryStream = new MemoryStream(); if ((object)containingAssembly == null) { containingAssembly = Assembly.GetCallingAssembly(); } string text = containingAssembly.GetManifestResourceNames().FirstOrDefault((string str) => str.EndsWith(resourceFileName2, StringComparison.Ordinal)); if (text != null) { containingAssembly.GetManifestResourceStream(text)?.CopyTo(memoryStream); } return (memoryStream.Length == 0L) ? null : memoryStream.ToArray(); } } public static class LocalizationManagerVersion { public const string Version = "1.4.2"; } } namespace ItemDataManager { [PublicAPI] public abstract class ItemData { internal static WeakReference constructingInfo = null; internal WeakReference? info; private static readonly FieldInfo parameterInfoClassImpl = AccessTools.DeclaredField(typeof(ParameterInfo), "ClassImpl"); private static Dictionary> serializedFields = new Dictionary>(); public string CustomDataKey { get; internal set; } protected virtual bool AllowStackingIdenticalValues { get; set; } public string Value { get { if (!Item.m_customData.TryGetValue(CustomDataKey, out var value)) { return ""; } return value; } set { Item.m_customData[CustomDataKey] = value; } } public string Key { get; internal set; } public bool IsCloned => Info.isCloned.Contains(CustomDataKey); public bool IsAlive { get { ItemInfo target; return (info ?? constructingInfo).TryGetTarget(out target); } } public ItemData Item => Info.ItemData; public ItemInfo Info { get { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown if (!(info ?? constructingInfo).TryGetTarget(out ItemInfo target)) { return new ItemInfo(new ItemData()); } return target; } } public virtual void FirstLoad() { } public virtual void Load() { //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown Dictionary dictionary = fetchSerializedFields(); if (dictionary == null || dictionary.Count <= 0 || Value == "") { return; } List list = new List(); string[] array = Value.Split(new char[1] { '|' }); foreach (string text in array) { string[] array2 = text.Split(new char[1] { ':' }); if (array2.Length == 2 && dictionary.TryGetValue(array2[0], out var value)) { ZPackage val = new ZPackage(array2[1]); ParameterInfo parameterInfo = (ParameterInfo)FormatterServices.GetUninitializedObject(typeof(ParameterInfo)); parameterInfoClassImpl.SetValue(parameterInfo, value.FieldType); list.Clear(); ZRpc.Deserialize(new ParameterInfo[2] { null, parameterInfo }, val, ref list); if (list.Count > 0) { value.SetValue(this, list[0]); } } } } public virtual void Save() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown Dictionary dictionary = fetchSerializedFields(); if (dictionary == null || dictionary.Count <= 0) { return; } StringBuilder stringBuilder = new StringBuilder(); foreach (FieldInfo value in dictionary.Values) { ZPackage val = new ZPackage(); ZRpc.Serialize(new object[1] { value.GetValue(this) }, ref val); stringBuilder.Append(value.Name); stringBuilder.Append(':'); stringBuilder.Append(val.GetBase64()); stringBuilder.Append('|'); } int length = stringBuilder.Length - 1; stringBuilder.Length = length; Value = stringBuilder.ToString(); } public virtual void Unload() { } public virtual void Upgraded() { } public virtual string? TryStack(ItemData? data) { if (!AllowStackingIdenticalValues || !(data?.Value == Value)) { return null; } return Value; } private Dictionary fetchSerializedFields() { Type type = GetType(); if (serializedFields.TryGetValue(type, out Dictionary value)) { return value; } return serializedFields[type] = (from f in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) where f.GetCustomAttributes(typeof(SerializeField), inherit: true).Length != 0 select f).ToDictionary((FieldInfo f) => f.Name, (FieldInfo f) => f); } } public sealed class StringItemData : ItemData { } [PublicAPI] public class ItemInfo : IEnumerable, IEnumerable { [CompilerGenerated] private sealed class <>c__DisplayClass57_0 { public Label target; public CodeInstruction targetedInstr; internal bool b__1(CodeInstruction i) { return i.labels.Contains(target); } internal bool b__2(CodeInstruction i) { Label? label = default(Label?); if (CodeInstructionExtensions.Branches(i, ref label)) { return targetedInstr.labels.Contains(label.Value); } return false; } } [CompilerGenerated] private sealed class d__57 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private CodeInstruction <>2__current; private int <>l__initialThreadId; private IEnumerable instructionsEnumerable; public IEnumerable <>3__instructionsEnumerable; private <>c__DisplayClass57_0 <>8__1; private CodeInstruction[] 5__2; private CodeInstruction 5__3; private CodeInstruction 5__4; private int 5__5; CodeInstruction IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__57(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>8__1 = null; 5__2 = null; 5__3 = null; 5__4 = null; <>1__state = -2; } private bool MoveNext() { //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Expected O, but got Unknown //IL_0272: Unknown result type (might be due to invalid IL or missing references) //IL_027c: Expected O, but got Unknown //IL_02a2: Unknown result type (might be due to invalid IL or missing references) //IL_02ac: Expected O, but got Unknown int num; switch (<>1__state) { default: return false; case 0: { <>1__state = -1; <>8__1 = new <>c__DisplayClass57_0(); 5__2 = instructionsEnumerable.ToArray(); <>8__1.target = (Label)5__2.First((CodeInstruction i) => i.opcode == OpCodes.Br || i.opcode == OpCodes.Br_S).operand; <>8__1.targetedInstr = 5__2.First((CodeInstruction i) => i.labels.Contains(<>8__1.target)); Label? label = default(Label?); 5__3 = 5__2.Reverse().First((CodeInstruction i) => CodeInstructionExtensions.Branches(i, ref label) && <>8__1.targetedInstr.labels.Contains(label.Value)); 5__4 = null; 5__5 = 0; break; } case 1: <>1__state = -1; if (5__4 == null && 5__2[5__5].opcode == OpCodes.Call && ((MethodInfo)5__2[5__5].operand).Name == "get_Current") { 5__4 = 5__2[5__5 + 1].Clone(); 5__4.opcode = new Dictionary { { OpCodes.Stloc_0, OpCodes.Ldloc_0 }, { OpCodes.Stloc_1, OpCodes.Ldloc_1 }, { OpCodes.Stloc_2, OpCodes.Ldloc_2 }, { OpCodes.Stloc_3, OpCodes.Ldloc_3 }, { OpCodes.Stloc_S, OpCodes.Ldloc_S } }[5__4.opcode]; } if (5__2[5__5] == 5__3) { <>2__current = 5__4; <>1__state = 2; return true; } goto IL_02bc; case 2: <>1__state = -1; <>2__current = new CodeInstruction(OpCodes.Ldsfld, (object)AccessTools.DeclaredField(typeof(ItemInfo), "checkingForStackableItemData")); <>1__state = 3; return true; case 3: <>1__state = -1; <>2__current = new CodeInstruction(OpCodes.Call, (object)AccessTools.DeclaredMethod(typeof(ItemInfo), "CheckItemDataIsStackableFindFree", (Type[])null, (Type[])null)); <>1__state = 4; return true; case 4: <>1__state = -1; <>2__current = new CodeInstruction(OpCodes.Brfalse, (object)<>8__1.target); <>1__state = 5; return true; case 5: { <>1__state = -1; goto IL_02bc; } IL_02bc: num = 5__5 + 1; 5__5 = num; break; } if (5__5 < 5__2.Length) { <>2__current = 5__2[5__5]; <>1__state = 1; return true; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__57 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__57(0); } d__.instructionsEnumerable = <>3__instructionsEnumerable; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__71 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private CodeInstruction <>2__current; private int <>l__initialThreadId; private IEnumerable instructionList; public IEnumerable <>3__instructionList; private List.Enumerator <>7__wrap1; private CodeInstruction 5__3; CodeInstruction IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__71(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || (uint)(num - 1) <= 2u) { try { } finally { <>m__Finally1(); } } <>7__wrap1 = default(List.Enumerator); 5__3 = null; <>1__state = -2; } private bool MoveNext() { //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Expected O, but got Unknown //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Expected O, but got Unknown try { switch (<>1__state) { default: return false; case 0: { <>1__state = -1; List list = instructionList.ToList(); <>7__wrap1 = list.GetEnumerator(); <>1__state = -3; break; } case 1: <>1__state = -3; if (5__3.opcode == OpCodes.Stfld && CodeInstructionExtensions.OperandIs(5__3, (MemberInfo)AccessTools.DeclaredField(typeof(ItemData), "m_dropPrefab"))) { <>2__current = new CodeInstruction(OpCodes.Ldarg_0, (object)null); <>1__state = 2; return true; } goto IL_0118; case 2: <>1__state = -3; <>2__current = new CodeInstruction(OpCodes.Call, (object)AccessTools.DeclaredMethod(typeof(ItemInfo), "CopyCustomDataFromUpgradedItem", (Type[])null, (Type[])null)); <>1__state = 3; return true; case 3: { <>1__state = -3; goto IL_0118; } IL_0118: 5__3 = null; break; } if (<>7__wrap1.MoveNext()) { 5__3 = <>7__wrap1.Current; <>2__current = 5__3; <>1__state = 1; return true; } <>m__Finally1(); <>7__wrap1 = default(List.Enumerator); return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; ((IDisposable)<>7__wrap1).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__71 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__71(0); } d__.instructionList = <>3__instructionList; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__68 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private CodeInstruction <>2__current; private int <>l__initialThreadId; private IEnumerable instructions; public IEnumerable <>3__instructions; private MethodInfo 5__2; private IEnumerator <>7__wrap2; private CodeInstruction 5__4; CodeInstruction IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__68(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || (uint)(num - 1) <= 2u) { try { } finally { <>m__Finally1(); } } 5__2 = null; <>7__wrap2 = null; 5__4 = null; <>1__state = -2; } private bool MoveNext() { //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Expected O, but got Unknown //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Expected O, but got Unknown try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; 5__2 = AccessTools.DeclaredMethod(typeof(Inventory), "RemoveItem", new Type[1] { typeof(ItemData) }, (Type[])null); <>7__wrap2 = instructions.GetEnumerator(); <>1__state = -3; goto IL_0136; case 1: <>1__state = -3; <>2__current = new CodeInstruction(OpCodes.Stsfld, (object)AccessTools.DeclaredField(typeof(ItemInfo), "currentlyUpgradingItem")); <>1__state = 2; return true; case 2: <>1__state = -3; goto IL_0110; case 3: { <>1__state = -3; 5__4 = null; goto IL_0136; } IL_0136: if (<>7__wrap2.MoveNext()) { 5__4 = <>7__wrap2.Current; if (5__4.opcode == OpCodes.Callvirt && CodeInstructionExtensions.OperandIs(5__4, (MemberInfo)5__2)) { <>2__current = new CodeInstruction(OpCodes.Dup, (object)null); <>1__state = 1; return true; } goto IL_0110; } <>m__Finally1(); <>7__wrap2 = null; return false; IL_0110: <>2__current = 5__4; <>1__state = 3; return true; } } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<>7__wrap2 != null) { <>7__wrap2.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__68 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__68(0); } d__.instructions = <>3__instructions; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } public static HashSet ForceLoadTypes; internal static string? _modGuid; private static Dictionary> typeInheritorsCache; private static HashSet knownTypes; private Dictionary data = new Dictionary(); private WeakReference? selfReference; internal HashSet isCloned = new HashSet(); private static ItemData? awakeningItem; private static Assembly primaryAssembly; private static Dictionary assemblyNameCache; private static Dictionary classKeyCache; private HashSet fetchedClassKeys = new HashSet(); private static MethodInfo removeMethod; private static ItemData? checkingForStackableItemData; private static Dictionary? newValuesOnStackable; private static ItemData? currentlyUpgradingItem; internal static string modGuid => _modGuid ?? (_modGuid = ((Func)delegate { //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Expected O, but got Unknown IEnumerable source; try { source = Assembly.GetExecutingAssembly().DefinedTypes.ToList(); } catch (ReflectionTypeLoadException ex) { source = from t in ex.Types where t != null select t.GetTypeInfo(); } BaseUnityPlugin val = (BaseUnityPlugin)Chainloader.ManagerObject.GetComponent((Type)source.First((TypeInfo t) => t.IsClass && typeof(BaseUnityPlugin).IsAssignableFrom(t))); return val.Info.Metadata.GUID; })()); public string Mod => modGuid; public ItemData ItemData { get; private set; } public string? this[string key] { get { return Get(key)?.Value; } set { GetOrCreate(key).Value = value ?? ""; } } internal static void addTypeToInheritorsCache(Type type, string typeKey) { Type type2 = type; if (!knownTypes.Contains(typeKey)) { knownTypes.Add(typeKey); Type type3 = type2; while ((object)type3 != null) { AddInterfaces(type3); type3 = type3.BaseType; } } void AddInterfaces(Type baseType) { if (!typeInheritorsCache.TryGetValue(baseType, out HashSet value)) { HashSet hashSet2 = (typeInheritorsCache[baseType] = new HashSet()); value = hashSet2; } value.Add(type2); Type[] interfaces = baseType.GetInterfaces(); foreach (Type baseType2 in interfaces) { AddInterfaces(baseType2); } } } private static string cachedAssemblyName(Assembly assembly) { if (assemblyNameCache.TryGetValue(assembly, out string value)) { return value; } return assemblyNameCache[assembly] = assembly.GetName().Name; } internal static string classKey(Type type, string key) { if (!classKeyCache.TryGetValue(type, out string value)) { value = type.FullName + ((type.Assembly != primaryAssembly) ? ("," + cachedAssemblyName(type.Assembly)) : ""); addTypeToInheritorsCache(type, value); } if (key == "") { return value; } return value + "#" + key; } internal static string dataKey(string key) { return modGuid + "#" + key; } internal ItemInfo(ItemData itemData) { ItemData = itemData; string text = dataKey(""); List list = ItemData.m_customData.Keys.ToList(); foreach (string item in list) { if (!item.StartsWith(text)) { continue; } string text2 = item.Substring(text.Length); string[] array = text2.Split(new char[1] { '#' }, 2); if (!knownTypes.Contains(array[0])) { Type type = Type.GetType(array[0]); if ((object)type != null && typeof(ItemData).IsAssignableFrom(type)) { addTypeToInheritorsCache(type, array[0]); } } } } public T GetOrCreate(string key = "") where T : ItemData, new() { return Add(key) ?? Get(key); } public T? Add(string key = "") where T : ItemData, new() { string text = classKey(typeof(T), key); if (fetchedClassKeys.Contains(text) && data.ContainsKey(text)) { return null; } string text2 = dataKey(text); if (ItemData.m_customData.ContainsKey(text2) || (awakeningItem != ItemData && data.ContainsKey(text))) { return null; } ItemData.m_customData[text2] = ""; ItemDataManager.ItemData.constructingInfo = selfReference ?? (selfReference = new WeakReference(this)); T val = new T { info = selfReference, Key = key, CustomDataKey = text2 }; data[text] = val; val.Value = ""; val.FirstLoad(); return val; } public T? Get(string key = "") where T : class { if (!typeInheritorsCache.TryGetValue(typeof(T), out HashSet value)) { if (!typeof(ItemData).IsAssignableFrom(typeof(T)) || typeof(T) == typeof(ItemData)) { throw new Exception("Trying to get value from ItemDataManager for class not inheriting from ItemData"); } return null; } foreach (Type item in value) { string text = classKey(item, key); if (data.TryGetValue(text, out ItemData value2)) { return (T)(object)value2; } if (!fetchedClassKeys.Contains(text) && awakeningItem != ItemData) { string text2 = dataKey(text); fetchedClassKeys.Add(text); if (ItemData.m_customData.ContainsKey(text2)) { return (T)(object)constructDataObj(text2, text); } } } return null; } public Dictionary GetAll() where T : ItemData { LoadAll(); return data.Values.Where((ItemData o) => o is T).ToDictionary((ItemData o) => o.Key, (ItemData o) => (T)o); } public bool Remove(string key = "") { return Remove(key); } public bool Remove(string key = "") where T : ItemData { string key2 = classKey(typeof(T), key); string key3 = dataKey(key2); if (ItemData.m_customData.Remove(key3)) { if (data.TryGetValue(key2, out ItemData value)) { value.Unload(); data.Remove(key2); } return true; } return false; } public bool Remove(T itemData) where T : ItemData { if (typeof(T) == itemData.GetType()) { return Remove(itemData.Key); } return (bool)removeMethod.MakeGenericMethod(itemData.GetType()).Invoke(this, new object[1] { itemData.Key }); } private ItemData? constructDataObj(string fullkey, string key) { string[] array = key.Split(new char[1] { '#' }, 2); Type type = Type.GetType(array[0]); if ((object)type == null || !typeof(ItemData).IsAssignableFrom(type)) { return null; } ItemDataManager.ItemData.constructingInfo = selfReference ?? (selfReference = new WeakReference(this)); ItemData itemData = (ItemData)Activator.CreateInstance(type); data[key] = itemData; itemData.info = selfReference; itemData.Key = ((array.Length > 1) ? array[1] : ""); itemData.CustomDataKey = fullkey; itemData.Load(); return itemData; } public void Save() { foreach (ItemData value in data.Values) { value.Save(); } } public void LoadAll() { if (awakeningItem == ItemData) { return; } string text = dataKey(""); List list = ItemData.m_customData.Keys.ToList(); foreach (string item in list) { if (item.StartsWith(text)) { string key = item.Substring(text.Length); if (!data.ContainsKey(key)) { constructDataObj(item, key); } } } } public IEnumerator GetEnumerator() { LoadAll(); return data.Values.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } private static void SavePrefix(ItemData __instance) { SaveItem(__instance); } private static void SaveInventoryPrefix(Inventory __instance) { foreach (ItemData item in __instance.m_inventory) { SaveItem(item); } } private static void SaveItem(ItemData item) { if (ItemExtensions.itemInfo.TryGetValue(item, out ItemInfo value)) { value.Save(); } } public Dictionary? IsStackableWithOtherInfo(ItemInfo? info) { LoadAll(); Dictionary dictionary = new Dictionary(); if (info != null) { info.LoadAll(); HashSet hashSet = new HashSet(info.data.Keys.Intersect(data.Keys)); foreach (string item in hashSet) { string text = data[item].TryStack(info.data[item]); if (text == null) { return null; } dictionary[item] = text; } foreach (KeyValuePair datum in info.data) { if (!dictionary.ContainsKey(datum.Key)) { string text2 = info.data[datum.Key].TryStack(null); if (text2 == null) { return null; } dictionary[datum.Key] = text2; } } } foreach (KeyValuePair datum2 in data) { if (!dictionary.ContainsKey(datum2.Key)) { string text3 = data[datum2.Key].TryStack(null); if (text3 == null) { return null; } dictionary[datum2.Key] = text3; } } return dictionary.ToDictionary((KeyValuePair kv) => dataKey(kv.Key), (KeyValuePair kv) => kv.Value); } private static void RegisterForceLoadedTypesAddItem(ItemData? __result) { awakeningItem = null; if (__result != null) { RegisterForceLoadedTypes(__result); } } private static void RegisterForceLoadedTypes(ItemData itemData) { foreach (Type forceLoadType in ForceLoadTypes) { string key = classKey(forceLoadType, ""); string text = dataKey(key); if (itemData.m_customData.ContainsKey(text)) { itemData.Data().constructDataObj(text, key); } } } private static void ItemDropAwake(ItemDrop __instance) { GameObject dropPrefab = __instance.m_itemData.m_dropPrefab; if (dropPrefab != null && ItemExtensions.itemInfo.TryGetValue(dropPrefab.GetComponent().m_itemData, out ItemInfo value)) { __instance.m_itemData.Data().isCloned = new HashSet(value.data.Values.Select((ItemData i) => i.CustomDataKey)); } } private static void ItemDropAwakeDelayed(ItemDrop __instance) { if (!ZNetView.m_forceDisableInit) { RegisterForceLoadedTypes(__instance.m_itemData); } } private static void ItemDataClonePrefix(ItemData __instance, ItemData __result) { SaveItem(__instance); } private static void ItemDataClonePostfix(ItemData __instance, ItemData __result) { if (ItemExtensions.itemInfo.TryGetValue(__instance, out ItemInfo value)) { __result.Data().isCloned = new HashSet(value.data.Values.Select((ItemData i) => i.CustomDataKey)); } } private static void ItemDataClonePostfixDelayed(ItemData __result) { RegisterForceLoadedTypes(__result); } private static void RegisterForceLoadedTypesOnPlayerLoaded(Player __instance) { foreach (Food food in __instance.m_foods) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(food.m_name); if (itemPrefab.GetComponent().m_itemData == food.m_item) { food.m_item = food.m_item.Clone(); food.m_item.m_dropPrefab = itemPrefab; } RegisterForceLoadedTypes(food.m_item); } } private static void SaveCheckingForStackableItemData(ItemData item) { checkingForStackableItemData = item; } private static void ResetCheckingForStackableItemData() { checkingForStackableItemData = null; } [IteratorStateMachine(typeof(d__57))] private static IEnumerable CheckStackableInFindFreeStackMethods(IEnumerable instructionsEnumerable) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__57(-2) { <>3__instructionsEnumerable = instructionsEnumerable }; } private static bool CheckItemDataIsStackableFindFree(ItemData item, ItemData? target) { if (target == null) { return true; } Dictionary dictionary = IsStackable(item, target); if (dictionary != null) { newValuesOnStackable = dictionary; return true; } return false; } private static void ResetNewValuesOnStackable() { newValuesOnStackable = null; } private static void ApplyNewValuesOnStackable(ItemData? __result) { if (__result == null || newValuesOnStackable == null) { return; } foreach (KeyValuePair item in newValuesOnStackable) { __result.m_customData[item.Key] = item.Value; } } private static Dictionary? IsStackable(ItemData a, ItemData b) { ItemInfo itemInfo = a.Data(); if (itemInfo != null) { return itemInfo.IsStackableWithOtherInfo(b.Data()); } ItemInfo itemInfo2 = b.Data(); if (itemInfo2 != null) { return itemInfo2.IsStackableWithOtherInfo(null); } return new Dictionary(); } private static bool CheckItemDataStackableAddItem(Inventory __instance, ItemData item, int x, int y, ref Dictionary? __state, ref bool __result) { ItemData itemAt = __instance.GetItemAt(x, y); if (itemAt != null) { Dictionary dictionary = IsStackable(item, itemAt); if (dictionary == null) { __result = false; return false; } __state = dictionary; } return true; } private static void ApplyCustomItemDataStackableAddItem(Inventory __instance, int x, int y, Dictionary? __state, bool __result) { if (!__result || __state == null) { return; } foreach (KeyValuePair item in __state) { __instance.GetItemAt(x, y).m_customData[item.Key] = item.Value; } } private static void ApplyCustomItemDataStackableAutoStack(ItemDrop item, Dictionary customData) { item.m_itemData.m_customData = customData; } private static Dictionary? IsStackableItemDrop(ItemDrop drop, ItemData item) { return IsStackable(drop.m_itemData, item); } private static IEnumerable HandleAutostackableItems(IEnumerable instructionList, ILGenerator ilg) { //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Expected O, but got Unknown //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Expected O, but got Unknown //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Expected O, but got Unknown //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Expected O, but got Unknown //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Expected O, but got Unknown //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Expected O, but got Unknown //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Expected O, but got Unknown //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Expected O, but got Unknown //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Expected O, but got Unknown //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Expected O, but got Unknown //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Expected O, but got Unknown List list = instructionList.ToList(); FieldInfo fieldInfo = AccessTools.DeclaredField(typeof(ItemData), "m_stack"); FieldInfo fieldInfo2 = AccessTools.DeclaredField(typeof(ItemDrop), "m_itemData"); Label? label = default(Label?); for (int i = 0; i < list.Count; i++) { if (!CodeInstructionExtensions.StoresField(list[i], fieldInfo)) { continue; } for (int num = i; num > 0; num--) { if (CodeInstructionExtensions.Branches(list[num], ref label)) { for (int num2 = num; num2 > 0; num2--) { if (CodeInstructionExtensions.LoadsField(list[num2], fieldInfo2, false)) { LocalBuilder localBuilder = ilg.DeclareLocal(typeof(Dictionary)); LocalBuilder localBuilder2 = ilg.DeclareLocal(typeof(ItemData)); list.Insert(i + 1, new CodeInstruction(OpCodes.Call, (object)AccessTools.DeclaredMethod(typeof(ItemInfo), "ApplyCustomItemDataStackableAutoStack", (Type[])null, (Type[])null))); list.Insert(i + 1, new CodeInstruction(OpCodes.Ldloc, (object)localBuilder.LocalIndex)); list.Insert(i + 1, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); list.Insert(num + 1, new CodeInstruction(OpCodes.Brfalse, (object)label)); list.Insert(num + 1, new CodeInstruction(OpCodes.Stloc, (object)localBuilder.LocalIndex)); list.Insert(num + 1, new CodeInstruction(OpCodes.Dup, (object)localBuilder.LocalIndex)); list.Insert(num + 1, new CodeInstruction(OpCodes.Call, (object)AccessTools.DeclaredMethod(typeof(ItemInfo), "IsStackableItemDrop", (Type[])null, (Type[])null))); list.Insert(num + 1, new CodeInstruction(OpCodes.Ldloc, (object)localBuilder2.LocalIndex)); list.Insert(num + 1, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); list.Insert(num2 + 1, new CodeInstruction(OpCodes.Stloc, (object)localBuilder2.LocalIndex)); list.Insert(num2 + 1, new CodeInstruction(OpCodes.Dup, (object)null)); return list; } } } } } throw new Exception("Found no stack store in a branch"); } [IteratorStateMachine(typeof(d__68))] private static IEnumerable TransferCustomItemDataOnUpgrade(IEnumerable instructions, ILGenerator ilg) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__68(-2) { <>3__instructions = instructions }; } private static void ResetCurrentlyUpgradingItem() { currentlyUpgradingItem = null; } private static void CopyCustomDataFromUpgradedItem(ItemDrop item) { if (currentlyUpgradingItem != null) { item.m_itemData.m_customData = currentlyUpgradingItem.m_customData; ItemInfo itemInfo = currentlyUpgradingItem.Data(); ItemExtensions.itemInfo.Remove(currentlyUpgradingItem); ItemExtensions.itemInfo.Add(item.m_itemData, itemInfo); item.m_itemData.m_quality = currentlyUpgradingItem.m_quality + 1; item.m_itemData.m_variant = currentlyUpgradingItem.m_variant; itemInfo.ItemData = item.m_itemData; itemInfo.LoadAll(); foreach (ItemData value in itemInfo.data.Values) { value.Upgraded(); } currentlyUpgradingItem = null; awakeningItem = null; return; } GameObject dropPrefab = item.m_itemData.m_dropPrefab; if (dropPrefab == null || item.m_itemData.m_customData.Count != 0) { return; } ZNetView component = ((Component)item).GetComponent(); ZDO val = ((Object.op_Implicit((Object)(object)component) && component.IsValid()) ? component.GetZDO() : null); if (val != null && val.GetInt(ZDOVars.s_dataCount, -1) != -1) { return; } item.m_itemData.m_customData = new Dictionary(dropPrefab.GetComponent().m_itemData.m_customData); if (val == null) { return; } int num = 0; val.Set(ZDOVars.s_dataCount, item.m_itemData.m_customData.Count, false); foreach (KeyValuePair customDatum in item.m_itemData.m_customData) { val.Set($"data_{num}", customDatum.Key); val.Set($"data__{num++}", customDatum.Value); } } [IteratorStateMachine(typeof(d__71))] private static IEnumerable ImportCustomDataOnUpgrade(IEnumerable instructionList) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__71(-2) { <>3__instructionList = instructionList }; } private static void TrackAwakeningItem(ItemDrop __instance) { if (ZNetView.m_forceDisableInit) { awakeningItem = __instance.m_itemData; } } static ItemInfo() { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Expected O, but got Unknown //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Expected O, but got Unknown //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Expected O, but got Unknown //IL_01d0: Expected O, but got Unknown //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Expected O, but got Unknown //IL_023f: Expected O, but got Unknown //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_02a1: Expected O, but got Unknown //IL_02a1: Expected O, but got Unknown //IL_02d1: Unknown result type (might be due to invalid IL or missing references) //IL_02dd: Expected O, but got Unknown //IL_030b: Unknown result type (might be due to invalid IL or missing references) //IL_0312: Expected O, but got Unknown //IL_0328: Unknown result type (might be due to invalid IL or missing references) //IL_0343: Unknown result type (might be due to invalid IL or missing references) //IL_0351: Expected O, but got Unknown //IL_0351: Expected O, but got Unknown //IL_0381: Unknown result type (might be due to invalid IL or missing references) //IL_038d: Expected O, but got Unknown //IL_03bd: Unknown result type (might be due to invalid IL or missing references) //IL_03d8: Unknown result type (might be due to invalid IL or missing references) //IL_03e3: Expected O, but got Unknown //IL_03e3: Expected O, but got Unknown //IL_0436: Unknown result type (might be due to invalid IL or missing references) //IL_0443: Expected O, but got Unknown //IL_0499: Unknown result type (might be due to invalid IL or missing references) //IL_04a6: Expected O, but got Unknown //IL_0552: Unknown result type (might be due to invalid IL or missing references) //IL_055f: Expected O, but got Unknown //IL_058d: Unknown result type (might be due to invalid IL or missing references) //IL_05b8: Unknown result type (might be due to invalid IL or missing references) //IL_05bf: Expected O, but got Unknown //IL_05e5: Unknown result type (might be due to invalid IL or missing references) //IL_05f3: Expected O, but got Unknown //IL_05f3: Expected O, but got Unknown //IL_0632: Unknown result type (might be due to invalid IL or missing references) //IL_063f: Expected O, but got Unknown //IL_066d: Unknown result type (might be due to invalid IL or missing references) //IL_0698: Unknown result type (might be due to invalid IL or missing references) //IL_06a5: Expected O, but got Unknown //IL_06a5: Expected O, but got Unknown //IL_06e4: Unknown result type (might be due to invalid IL or missing references) //IL_06f1: Expected O, but got Unknown ForceLoadTypes = new HashSet(); typeInheritorsCache = new Dictionary>(); knownTypes = new HashSet(); awakeningItem = null; primaryAssembly = Assembly.GetExecutingAssembly(); assemblyNameCache = new Dictionary(); classKeyCache = new Dictionary(); removeMethod = typeof(ItemInfo).GetMethods().Single((MethodInfo m) => m.Name == "Remove" && m.IsGenericMethod && m.GetParameters()[0].ParameterType == typeof(string)); Harmony val = new Harmony("org.bepinex.helpers.ItemDataManager"); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Inventory), "Save", (Type[])null, (Type[])null), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(ItemInfo), "SaveInventoryPrefix", (Type[])null, (Type[])null), 800, (string[])null, (string[])null, (bool?)null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); foreach (MethodInfo item in from m in typeof(ItemData).GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) where m.Name == "SaveToZDO" select m) { val.Patch((MethodBase)item, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(ItemInfo), "SavePrefix", (Type[])null, (Type[])null), 800, (string[])null, (string[])null, (bool?)null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Inventory), "AddItem", new Type[4] { typeof(ItemData), typeof(int), typeof(int), typeof(int) }, (Type[])null), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(ItemInfo), "CheckItemDataStackableAddItem", (Type[])null, (Type[])null)), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(ItemInfo), "ApplyCustomItemDataStackableAddItem", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Inventory), "CanAddItem", new Type[2] { typeof(ItemData), typeof(int) }, (Type[])null), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(ItemInfo), "SaveCheckingForStackableItemData", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(ItemInfo), "ResetCheckingForStackableItemData", (Type[])null), (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Inventory), "AddItem", new Type[1] { typeof(ItemData) }, (Type[])null), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(ItemInfo), "SaveCheckingForStackableItemData", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(ItemInfo), "ResetCheckingForStackableItemData", (Type[])null), (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Inventory), "FindFreeStackSpace", (Type[])null, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(ItemInfo), "CheckStackableInFindFreeStackMethods", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null); MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(Inventory), "FindFreeStackItem", (Type[])null, (Type[])null); HarmonyMethod val2 = new HarmonyMethod(AccessTools.DeclaredMethod(typeof(ItemInfo), "CheckStackableInFindFreeStackMethods", (Type[])null, (Type[])null)); val.Patch((MethodBase)methodInfo, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(ItemInfo), "ResetNewValuesOnStackable", (Type[])null, (Type[])null)), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(ItemInfo), "ApplyNewValuesOnStackable", (Type[])null, (Type[])null)), val2, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(ItemDrop), "AutoStackItems", (Type[])null, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(ItemInfo), "HandleAutostackableItems", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(InventoryGui), "DoCrafting", (Type[])null, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(ItemInfo), "TransferCustomItemDataOnUpgrade", (Type[])null, (Type[])null)), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(ItemInfo), "ResetCurrentlyUpgradingItem", (Type[])null, (Type[])null)), (HarmonyMethod)null); foreach (MethodInfo item2 in from m in typeof(ItemData).GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) where m.Name == "LoadFromZDO" select m) { val.Patch((MethodBase)item2, (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(ItemInfo), "RegisterForceLoadedTypes", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Player), "Load", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(ItemInfo), "RegisterForceLoadedTypesOnPlayerLoaded", (Type[])null, (Type[])null), 700, (string[])null, (string[])null, (bool?)null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Inventory), "AddItem", new Type[8] { typeof(string), typeof(int), typeof(int), typeof(int), typeof(long), typeof(string), typeof(Vector2i), typeof(bool) }, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(ItemInfo), "RegisterForceLoadedTypesAddItem", (Type[])null, (Type[])null), 800, (string[])null, (string[])null, (bool?)null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); MethodInfo methodInfo2 = AccessTools.DeclaredMethod(typeof(ItemDrop), "Awake", (Type[])null, (Type[])null); HarmonyMethod val3 = new HarmonyMethod(AccessTools.DeclaredMethod(typeof(ItemInfo), "TrackAwakeningItem", (Type[])null, (Type[])null)); val2 = new HarmonyMethod(AccessTools.DeclaredMethod(typeof(ItemInfo), "ImportCustomDataOnUpgrade", (Type[])null, (Type[])null), 800, (string[])null, (string[])null, (bool?)null); val.Patch((MethodBase)methodInfo2, val3, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(ItemInfo), "ItemDropAwake", (Type[])null, (Type[])null), 800, (string[])null, (string[])null, (bool?)null), val2, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(ItemDrop), "Awake", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(ItemInfo), "ItemDropAwakeDelayed", (Type[])null, (Type[])null), 799, (string[])null, (string[])null, (bool?)null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(ItemData), "Clone", (Type[])null, (Type[])null), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(ItemInfo), "ItemDataClonePrefix", (Type[])null, (Type[])null)), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(ItemInfo), "ItemDataClonePostfix", (Type[])null, (Type[])null), 500, (string[])null, (string[])null, (bool?)null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(ItemData), "Clone", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(ItemInfo), "ItemDataClonePostfixDelayed", (Type[])null, (Type[])null), 499, (string[])null, (string[])null, (bool?)null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } [PublicAPI] public class ForeignItemInfo : IEnumerable, IEnumerable { private readonly object foreignItemInfo; public string Mod => ((string)foreignItemInfo.GetType().GetProperty("Mod")?.GetValue(foreignItemInfo)) ?? ""; public ItemData ItemData { get; private set; } public string? this[string key] { get { object obj = foreignItemInfo.GetType().InvokeMember("Item", BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty, null, foreignItemInfo, new object[1] { key }); if (obj != null) { return (string)obj.GetType().GetProperty("Value")?.GetValue(obj); } return null; } set { foreignItemInfo.GetType().GetMethod("set_Item", BindingFlags.Instance | BindingFlags.Public)?.Invoke(foreignItemInfo, new object[2] { key, value }); } } internal ForeignItemInfo(ItemData itemData, object foreignItemInfo) { ItemData = itemData; this.foreignItemInfo = foreignItemInfo; } public T GetOrCreate(string key = "") where T : class, new() { return Add(key) ?? Get(key); } private object? call(string name, object?[] values, Type?[] args, Type? generic = null) { MethodInfo[] methods = foreignItemInfo.GetType().GetMethods(); foreach (MethodInfo methodInfo in methods) { if (methodInfo.Name == name && (from p in methodInfo.GetParameters() select (!p.ParameterType.IsGenericParameter) ? p.ParameterType : null).SequenceEqual(args) && (object)generic != null == methodInfo.IsGenericMethod) { MethodInfo methodInfo2 = methodInfo; if ((object)generic != null) { methodInfo2 = methodInfo2.MakeGenericMethod(generic); } return methodInfo2.Invoke(foreignItemInfo, values); } } return null; } public T? Add(string key = "") where T : class, new() { return call("Add", new object[1] { key }, new Type[1] { typeof(string) }, typeof(T)) as T; } public T? Get(string key = "") where T : class { return call("Get", new object[1] { key }, new Type[1] { typeof(string) }, typeof(T)) as T; } public Dictionary GetAll() where T : class { return ((call("GetAll", Array.Empty(), Array.Empty(), typeof(T)) as T) as Dictionary) ?? new Dictionary(); } public bool Remove(string key = "") { return (call("Add", new object[1] { key }, new Type[1] { typeof(string) }) as bool?).GetValueOrDefault(); } public bool Remove(string key = "") where T : class { return (call("Remove", new object[1] { key }, new Type[1] { typeof(string) }, typeof(T)) as bool?).GetValueOrDefault(); } public bool Remove(T itemData) where T : class { return (call("Remove", new object[1] { itemData }, new Type[1], typeof(T)) as bool?).GetValueOrDefault(); } public void Save() { call("Save", Array.Empty(), Array.Empty()); } public void LoadAll() { call("LoadAll", Array.Empty(), Array.Empty()); } public IEnumerator GetEnumerator() { return (IEnumerator)((call("GetEnumerator", Array.Empty(), Array.Empty()) as IEnumerator) ?? ((object)new List().GetEnumerator())); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } [PublicAPI] public static class ItemExtensions { private const string className = "ItemDataManager.ItemExtensions"; internal static readonly ConditionalWeakTable itemInfo = new ConditionalWeakTable(); private static readonly ConditionalWeakTable> foreignItemInfo = new ConditionalWeakTable>(); public static ItemInfo Data(this ItemData item) { if (itemInfo.TryGetValue(item, out ItemInfo value)) { return value; } itemInfo.Add(item, value = new ItemInfo(item)); return value; } public static ForeignItemInfo? Data(this ItemData item, string mod) { Dictionary orCreateValue = ItemExtensions.foreignItemInfo.GetOrCreateValue(item); if (orCreateValue.TryGetValue(mod, out var value)) { return value; } if (!Chainloader.PluginInfos.TryGetValue(mod, out var value2)) { return null; } object obj = ((object)value2.Instance).GetType().Assembly.GetType("ItemDataManager.ItemExtensions")?.GetMethod("Data", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(ItemData) }, Array.Empty())?.Invoke(null, new object[1] { item }); if (obj != null) { return orCreateValue[mod] = new ForeignItemInfo(item, obj); } Debug.LogWarning((object)("Mod " + mod + " has an ItemDataManager.ItemExtensions class, but no Data(ItemDrop.ItemData) method could be called on it.")); return orCreateValue[mod] = null; } } } namespace kg.ValheimEnchantmentSystem { [VES_Autoload(VES_Autoload.Priority.Last, "OnInit", new Type[] { typeof(SyncedData), typeof(Enchantment_Skill), typeof(IntegrationRegistry), typeof(Notifications_UI), typeof(Enchantment_VFX) })] public static class Enchantment_Core { public class Enchanted : ItemData { public int level; public SyncedData.Stat_Data Stats => SyncedData.GetStatIncrease(this); public override void Save() { base.Value = level.ToString(); } public override void Load() { if (!string.IsNullOrEmpty(base.Value)) { level = (int.TryParse(base.Value, out var result) ? result : 0); } } public override void Upgraded() { EnchantmentSideEffects.HandleUpgrade(this); } public float GetEnchantmentChance() { return SyncedData.GetEnchantmentChance(this).success; } public EnchantmentResult Enchant(Player player, bool useBlessedScroll, bool blessedScrollPreventsBreak) { return EnchantmentService.Execute(this, player, useBlessedScroll, blessedScrollPreventsBreak); } public static implicit operator bool(Enchanted en) { return en != null; } } [HarmonyPatch(typeof(InventoryGrid), "CreateItemTooltip")] [ClientOnlyPatch] private static class InventoryGrid_CreateItemTooltip_Patch { [UsedImplicitly] private static void Prefix(InventoryGrid __instance, ItemData item, out string __state) { __state = null; Enchanted enchanted = item?.Data().Get(); if (enchanted != null && enchanted.level > 0) { __state = item.m_shared.m_name; int variant; string arg = SyncedData.GetColor(enchanted, out variant, trimApha: true).IncreaseColorLight(); SharedData shared = item.m_shared; shared.m_name += $" (+{enchanted.level})"; } } [UsedImplicitly] private static void Postfix(InventoryGrid __instance, ItemData item, string __state) { if (__state != null) { item.m_shared.m_name = __state; } } } [HarmonyPatch(typeof(ItemDrop), "GetHoverText")] [ClientOnlyPatch] private static class ItemDrop_GetHoverText_Patch { [UsedImplicitly] private static void Prefix(ItemDrop __instance, out string __state) { __state = null; Enchanted enchanted = __instance.m_itemData?.Data().Get(); if (enchanted != null && enchanted.level > 0) { __state = __instance.m_itemData.m_shared.m_name; int variant; string arg = SyncedData.GetColor(enchanted, out variant, trimApha: true).IncreaseColorLight(); SharedData shared = __instance.m_itemData.m_shared; shared.m_name += $" (+{enchanted.level})"; } } [UsedImplicitly] private static void Postfix(ItemDrop __instance, string __state) { if (__state != null) { __instance.m_itemData.m_shared.m_name = __state; } } } [HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[] { typeof(ItemData), typeof(int), typeof(bool), typeof(float), typeof(int) })] [ClientOnlyPatch] public class TooltipPatch { [UsedImplicitly] public static void Postfix(ItemData item, bool crafting, int qualityLevel, ref string __result) { //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_029a: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Unknown result type (might be due to invalid IL or missing references) //IL_02f0: 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_0346: Unknown result type (might be due to invalid IL or missing references) //IL_0364: Unknown result type (might be due to invalid IL or missing references) //IL_039c: Unknown result type (might be due to invalid IL or missing references) //IL_03ba: Unknown result type (might be due to invalid IL or missing references) //IL_03f2: Unknown result type (might be due to invalid IL or missing references) //IL_0410: Unknown result type (might be due to invalid IL or missing references) Enchanted enchanted = item.Data().Get(); int num = (enchanted ? enchanted.level : 0); string text = (Object.op_Implicit((Object)(object)item.m_dropPrefab) ? ((Object)item.m_dropPrefab).name : Utils.GetPrefabNameByItemName(item.m_shared.m_name)); SyncedData.EnchantmentReqs reqs = SyncedData.GetReqs(text); string text2 = BuildTooltipStatusLine(reqs, text, num, item); if (num > 0) { SyncedData.Stat_Data statIncrease = SyncedData.GetStatIncrease(enchanted); int variant; string text3 = SyncedData.GetColor(enchanted, out variant, trimApha: true).IncreaseColorLight(); if (statIncrease != null) { int damage_percentage = statIncrease.damage_percentage; if (statIncrease.durability > 0) { __result = ItemDurabilityRegex.Replace(__result, $"$1 (+{statIncrease.durability})"); } if (statIncrease.durability_percentage > 0) { __result = ItemDurabilityRegex.Replace(__result, $"$1 (+{statIncrease.durability_percentage}%)"); } __result += "\n"; if (damage_percentage > 0) { float num2 = default(float); float num3 = default(float); ((Character)Player.m_localPlayer).GetSkills().GetRandomSkillRange(ref num2, ref num3, item.m_shared.m_skillType); DamageTypes damage = item.GetDamage(qualityLevel, (float)item.m_worldLevel); __result = InventoryDamageRegex.Replace(__result, $"$1 (+{(damage.m_damage * (float)damage_percentage / 100f * num2).RoundOne()} - {(damage.m_damage * (float)damage_percentage / 100f * num3).RoundOne()})"); __result = InventoryBluntRegex.Replace(__result, $"$1 (+{(damage.m_blunt * (float)damage_percentage / 100f * num2).RoundOne()} - {(damage.m_blunt * (float)damage_percentage / 100f * num3).RoundOne()})"); __result = InventorySlashRegex.Replace(__result, $"$1 (+{(damage.m_slash * (float)damage_percentage / 100f * num2).RoundOne()} - {(damage.m_slash * (float)damage_percentage / 100f * num3).RoundOne()})"); __result = InventoryPierceRegex.Replace(__result, $"$1 (+{(damage.m_pierce * (float)damage_percentage / 100f * num2).RoundOne()} - {(damage.m_pierce * (float)damage_percentage / 100f * num3).RoundOne()})"); __result = InventoryFireRegex.Replace(__result, $"$1 (+{(damage.m_fire * (float)damage_percentage / 100f * num2).RoundOne()} - {(damage.m_fire * (float)damage_percentage / 100f * num3).RoundOne()})"); __result = InventoryFrostRegex.Replace(__result, $"$1 (+{(damage.m_frost * (float)damage_percentage / 100f * num2).RoundOne()} - {(damage.m_frost * (float)damage_percentage / 100f * num3).RoundOne()})"); __result = InventoryLightningRegex.Replace(__result, $"$1 (+{(damage.m_lightning * (float)damage_percentage / 100f * num2).RoundOne()} - {(damage.m_lightning * (float)damage_percentage / 100f * num3).RoundOne()})"); __result = InventoryPoisonRegex.Replace(__result, $"$1 (+{(damage.m_poison * (float)damage_percentage / 100f * num2).RoundOne()} - {(damage.m_poison * (float)damage_percentage / 100f * num3).RoundOne()})"); __result = InventorySpiritRegex.Replace(__result, $"$1 (+{(damage.m_spirit * (float)damage_percentage / 100f * num2).RoundOne()} - {(damage.m_spirit * (float)damage_percentage / 100f * num3).RoundOne()})"); __result += $"\n• $enchantment_bonusespercentdamage (+{damage_percentage}%)"; } float armor_percentage = statIncrease.armor_percentage; if (armor_percentage > 0f) { __result = ItemBlockArmorRegex.Replace(__result, $"$1 (+{(item.GetBaseBlockPower(qualityLevel) * armor_percentage / 100f).RoundOne()}({armor_percentage}%))"); __result = ItemArmorRegex.Replace(__result, $"$1 (+{(item.GetArmor(qualityLevel, (float)item.m_worldLevel) * armor_percentage / 100f).RoundOne()}({armor_percentage}%))"); __result += $"\n• $enchantment_bonusespercentarmor (+{armor_percentage}%)"; } float armor = statIncrease.armor; if (armor > 0f) { __result = ItemBlockArmorRegex.Replace(__result, $"$1 (+{statIncrease.armor})"); __result = ItemArmorRegex.Replace(__result, $"$1 (+{statIncrease.armor})"); } __result += EnchantmentStatFormatter.BuildAdditionalStats(statIncrease, text3); if (!string.IsNullOrWhiteSpace(text2)) { __result += text2; } } } if (num <= 0 && !string.IsNullOrWhiteSpace(text2)) { __result = __result + "\n" + text2; } } } [HarmonyPatch(typeof(InventoryGui), "UpdateRecipe")] [ClientOnlyPatch] private static class InventoryGui_UpdateRecipe_Patch { [UsedImplicitly] private static void Postfix(InventoryGui __instance) { Enchanted enchanted = ((RecipeDataPair)(ref __instance.m_selectedRecipe)).ItemData?.Data().Get(); if ((bool)enchanted) { int variant; string arg = SyncedData.GetColor(enchanted, out variant, trimApha: true).IncreaseColorLight(); TMP_Text recipeName = __instance.m_recipeName; recipeName.text += $" (+{enchanted.level})"; } } } [HarmonyPatch(typeof(InventoryGui), "AddRecipeToList")] [ClientOnlyPatch] private static class InventoryGui_AddRecipeToList_Patch { private static void Modify(ref string text, ItemData item) { Enchanted enchanted = item?.Data().Get(); if ((bool)enchanted) { int variant; string arg = SyncedData.GetColor(enchanted, out variant, trimApha: true).IncreaseColorLight(); text += $" (+{enchanted.level})"; } } [UsedImplicitly] private static IEnumerable Transpiler(IEnumerable code) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Expected O, but got Unknown CodeMatcher val = new CodeMatcher(code, (ILGenerator)null); val.MatchForward(false, (CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((OpCode?)OpCodes.Stloc_2, (object)null, (string)null) }); if (val.IsInvalid) { return val.InstructionEnumeration(); } MethodInfo methodInfo = AccessTools.Method(typeof(InventoryGui_AddRecipeToList_Patch), "Modify", (Type[])null, (Type[])null); val.Advance(1).InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Ldloca_S, (object)2) }).InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Ldarg_3, (object)null) }) .InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Call, (object)methodInfo) }); return val.InstructionEnumeration(); } } [HarmonyPatch(typeof(ItemData), "GetBlockPower", new Type[] { typeof(float) })] [ClientOnlyPatch] private static class ModifyBlockPower { [UsedImplicitly] private static void Postfix(ItemData __instance, ref float __result) { Enchanted enchanted = __instance.Data().Get(); if (enchanted != null && enchanted.level > 0) { SyncedData.Stat_Data statIncrease = SyncedData.GetStatIncrease(enchanted); if (statIncrease != null) { __result *= 1f + statIncrease.armor_percentage / 100f; __result += statIncrease.armor; } } } } [HarmonyPatch] [ClientOnlyPatch] private static class ModifyArmor { [UsedImplicitly] private static MethodInfo TargetMethod() { return AccessTools.Method(typeof(ItemData), "GetArmor", (Type[])null, (Type[])null); } [UsedImplicitly] private static void Postfix(ItemData __instance, ref float __result) { Enchanted enchanted = __instance.Data().Get(); if (enchanted != null && enchanted.level > 0) { SyncedData.Stat_Data statIncrease = SyncedData.GetStatIncrease(enchanted); if (statIncrease != null) { __result *= 1f + statIncrease.armor_percentage / 100f; __result += statIncrease.armor; } } } } [HarmonyPatch] [ClientOnlyPatch] private static class ModifyDamage { [UsedImplicitly] private static MethodInfo TargetMethod() { return AccessTools.Method(typeof(ItemData), "GetDamage", (Type[])null, (Type[])null); } [UsedImplicitly] private static void Postfix(ItemData __instance, ref DamageTypes __result) { Enchanted enchanted = __instance.Data().Get(); if (enchanted != null && enchanted.level > 0) { SyncedData.Stat_Data statIncrease = SyncedData.GetStatIncrease(enchanted); if (statIncrease != null) { ((DamageTypes)(ref __result)).Modify(1f + (float)statIncrease.damage_percentage / 100f); __result.m_blunt += statIncrease.damage_blunt; __result.m_slash += statIncrease.damage_slash; __result.m_pierce += statIncrease.damage_pierce; __result.m_fire += statIncrease.damage_fire; __result.m_frost += statIncrease.damage_frost; __result.m_lightning += statIncrease.damage_lightning; __result.m_poison += statIncrease.damage_poison; __result.m_spirit += statIncrease.damage_spirit; __result.m_damage += statIncrease.damage_true; __result.m_chop += statIncrease.damage_chop; __result.m_pickaxe += statIncrease.damage_pickaxe; } } } } [HarmonyPatch(typeof(Player), "ApplyArmorDamageMods")] [ClientOnlyPatch] private static class Player_ApplyArmorDamageMods_Patch { [UsedImplicitly] private static void Postfix(Player __instance, ref DamageModifiers mods) { EquippedEnchantmentSnapshotService.Snapshot snapshot = EquippedEnchantmentSnapshotService.GetSnapshot(__instance); if (snapshot.ResistancePairs.Count > 0) { ((DamageModifiers)(ref mods)).Apply(snapshot.ResistancePairs); } } } [HarmonyPatch(typeof(Character), "SetMaxHealth")] [ClientOnlyPatch] private static class Character_SetMaxHealth_Patch { [UsedImplicitly] private static void Prefix(Character __instance, ref float health) { Player val = (Player)(object)((__instance is Player) ? __instance : null); if (val != null) { health += EquippedEnchantmentSnapshotService.GetSnapshot(val).MaxHealthBonus; } } } [HarmonyPatch(typeof(Player), "SetMaxStamina")] [ClientOnlyPatch] private static class Player_SetMaxStamina_Patch { [UsedImplicitly] private static void Prefix(Player __instance, ref float stamina) { stamina += EquippedEnchantmentSnapshotService.GetSnapshot(__instance).MaxStaminaBonus; } } [HarmonyPatch(typeof(Player), "GetEquipmentMovementModifier")] [ClientOnlyPatch] private static class Player_UpdateMovementModifier_Patch { [UsedImplicitly] private static void Postfix(Player __instance, ref float __result) { __result += EquippedEnchantmentSnapshotService.GetSnapshot(__instance).MovementModifier; } } [HarmonyPatch(typeof(ItemData), "GetMaxDurability", new Type[] { typeof(int) })] [ClientOnlyPatch] public class ApplySkillToDurability { [UsedImplicitly] private static void Postfix(ItemData __instance, ref float __result) { Enchanted enchanted = __instance.Data().Get(); if (enchanted != null && enchanted.level > 0) { SyncedData.Stat_Data statIncrease = SyncedData.GetStatIncrease(enchanted); if (statIncrease != null) { __result *= 1f + (float)statIncrease.durability_percentage / 100f; __result += statIncrease.durability; } } } } [HarmonyPatch(typeof(Player), "FixedUpdate")] [ClientOnlyPatch] public static class Player_FixedUpdate_Patch { [UsedImplicitly] private static void Postfix(Player __instance) { if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer && !((Character)__instance).IsDead()) { float fixedDeltaTime = Time.fixedDeltaTime; __instance.UpdateEnchantmentRegen(fixedDeltaTime); } } } [HarmonyPatch(typeof(Player), "UpdateStats", new Type[] { typeof(float) })] [ClientOnlyPatch] public static class Player_UpdateStats_Patch { private static readonly FieldInfo CharacterNViewField = AccessTools.Field(typeof(Character), "m_nview"); private static readonly MethodInfo ZNetViewGetZdoMethod = AccessTools.Method(typeof(ZNetView), "GetZDO", (Type[])null, (Type[])null); private static readonly FieldInfo ZdoVarsStaminaField = AccessTools.Field(typeof(ZDOVars), "s_stamina"); private static readonly FieldInfo PlayerStaminaField = AccessTools.Field(typeof(Player), "m_stamina"); private static readonly MethodInfo ZdoSetFloatMethod = AccessTools.Method(typeof(ZDO), "Set", new Type[2] { typeof(int), typeof(float) }, (Type[])null); private static readonly MethodInfo ApplyEnchantmentStaminaRegenMethod = AccessTools.DeclaredMethod(typeof(PlayerExtensions), "UpdateEnchantmentStaminaRegen", (Type[])null, (Type[])null); [UsedImplicitly] private static IEnumerable Transpiler(IEnumerable instructions) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected O, but got Unknown //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Expected O, but got Unknown //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Expected O, but got Unknown //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Expected O, but got Unknown //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Expected O, but got Unknown //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Expected O, but got Unknown //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Expected O, but got Unknown CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null); val.MatchForward(false, (CodeMatch[])(object)new CodeMatch[7] { new CodeMatch((OpCode?)OpCodes.Ldarg_0, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldfld, (object)CharacterNViewField, (string)null), new CodeMatch((OpCode?)OpCodes.Callvirt, (object)ZNetViewGetZdoMethod, (string)null), new CodeMatch((OpCode?)OpCodes.Ldsfld, (object)ZdoVarsStaminaField, (string)null), new CodeMatch((OpCode?)OpCodes.Ldarg_0, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldfld, (object)PlayerStaminaField, (string)null), new CodeMatch((OpCode?)OpCodes.Callvirt, (object)ZdoSetFloatMethod, (string)null) }); if (val.IsInvalid) { Utils.print("Failed to inject enchantment stamina regen into Player.UpdateStats; using vanilla stamina regen only.", ConsoleColor.Yellow); return instructions; } val.Insert((CodeInstruction[])(object)new CodeInstruction[3] { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Ldarg_1, (object)null), new CodeInstruction(OpCodes.Call, (object)ApplyEnchantmentStaminaRegenMethod) }); return val.InstructionEnumeration(); } } [CompilerGenerated] private sealed class d__13 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public ItemData weapon; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__13(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Expected O, but got Unknown //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Expected O, but got Unknown //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Expected O, but got Unknown //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Expected O, but got Unknown //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Expected O, but got Unknown //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (!((Humanoid)Player.m_localPlayer).IsItemEquiped(weapon) || !weapon.IsWeapon()) { return false; } ((Humanoid)Player.m_localPlayer).UnequipItem(weapon, true); <>2__current = (object)new WaitForEndOfFrame(); <>1__state = 1; return true; case 1: <>1__state = -1; <>2__current = (object)new WaitForEndOfFrame(); <>1__state = 2; return true; case 2: <>1__state = -1; <>2__current = (object)new WaitForEndOfFrame(); <>1__state = 3; return true; case 3: <>1__state = -1; <>2__current = (object)new WaitForEndOfFrame(); <>1__state = 4; return true; case 4: <>1__state = -1; <>2__current = (object)new WaitForEndOfFrame(); <>1__state = 5; return true; case 5: <>1__state = -1; <>2__current = (object)new WaitForEndOfFrame(); <>1__state = 6; return true; case 6: <>1__state = -1; if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && ((Humanoid)Player.m_localPlayer).m_inventory.ContainsItem(weapon)) { Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Humanoid)localPlayer).EquipItem(weapon, true); } } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static readonly Regex ItemDurabilityRegex = new Regex("(\\$item_durability.*)", RegexOptions.Compiled); private static readonly Regex InventoryDamageRegex = new Regex("(\\$inventory_damage.*)", RegexOptions.Compiled); private static readonly Regex InventoryBluntRegex = new Regex("(\\$inventory_blunt.*)", RegexOptions.Compiled); private static readonly Regex InventorySlashRegex = new Regex("(\\$inventory_slash.*)", RegexOptions.Compiled); private static readonly Regex InventoryPierceRegex = new Regex("(\\$inventory_pierce.*)", RegexOptions.Compiled); private static readonly Regex InventoryFireRegex = new Regex("(\\$inventory_fire.*)", RegexOptions.Compiled); private static readonly Regex InventoryFrostRegex = new Regex("(\\$inventory_frost.*)", RegexOptions.Compiled); private static readonly Regex InventoryLightningRegex = new Regex("(\\$inventory_lightning.*)", RegexOptions.Compiled); private static readonly Regex InventoryPoisonRegex = new Regex("(\\$inventory_poison.*)", RegexOptions.Compiled); private static readonly Regex InventorySpiritRegex = new Regex("(\\$inventory_spirit.*)", RegexOptions.Compiled); private static readonly Regex ItemBlockArmorRegex = new Regex("(\\$item_blockarmor.*)", RegexOptions.Compiled); private static readonly Regex ItemArmorRegex = new Regex("(\\$item_armor.*)", RegexOptions.Compiled); [UsedImplicitly] private static void OnInit() { if (!ValheimEnchantmentSystem.NoGraphics) { AnimationSpeedManager.Add(ModifyAttackSpeed); } } [IteratorStateMachine(typeof(d__13))] public static IEnumerator FrameSkipEquip(ItemData weapon) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__13(0) { weapon = weapon }; } private static string BuildTooltipStatusLine(SyncedData.EnchantmentReqs reqs, string dropName, int currentLevel, ItemData item) { if (reqs == null || item == null) { return string.Empty; } int variant; string text = SyncedData.GetColor(dropName, currentLevel, out variant, trimApha: true).IncreaseColorLight(); if (currentLevel == 0) { text = "white"; } if (!SyncedData.IsLevelEnchantable(dropName, currentLevel, item.IsWeapon())) { return ("• $enchantment_maxedout").Localize(); } string text2 = ResolveTooltipScrollName(reqs.enchant_prefab); if (string.IsNullOrWhiteSpace(text2)) { text2 = ResolveTooltipScrollName(reqs.blessed_enchant_prefab); } if (!string.IsNullOrWhiteSpace(text2)) { return ("• $enchantment_canbeenchantedwith " + text2 + "").Localize(); } return string.Empty; } private static string ResolveTooltipScrollName(SyncedData.SingleReq requirement) { if (requirement == null || !requirement.IsValid()) { return string.Empty; } ZNetScene instance = ZNetScene.instance; object obj; if (instance == null) { obj = null; } else { GameObject prefab = instance.GetPrefab(requirement.prefab); obj = ((prefab == null) ? null : prefab.GetComponent()?.m_itemData?.m_shared?.m_name); } if (obj == null) { obj = string.Empty; } return (string)obj; } private static double ModifyAttackSpeed(Character c, double speed) { if ((Object)(object)c != (Object)(object)Player.m_localPlayer || !c.InAttack()) { return speed; } ItemData currentWeapon = ((Humanoid)Player.m_localPlayer).GetCurrentWeapon(); if (currentWeapon == null) { return speed; } Enchanted enchanted = currentWeapon.Data().Get(); if (enchanted != null && enchanted.level > 0) { SyncedData.Stat_Data statIncrease = SyncedData.GetStatIncrease(enchanted); if (statIncrease != null && statIncrease.attack_speed > 0) { return speed * (double)(1f + (float)statIncrease.attack_speed / 100f); } } return speed; } } public static class PlayerExtensions { private static float enchantmentRegenTimer; public static void UpdateEnchantmentRegen(this Player player, float dt) { enchantmentRegenTimer += dt; if (enchantmentRegenTimer >= 10f) { enchantmentRegenTimer = 0f; float healthRegen = EquippedEnchantmentSnapshotService.GetSnapshot(player).HealthRegen; if (healthRegen > 0f) { ((Character)player).Heal(healthRegen, true); } } } public static void UpdateEnchantmentStaminaRegen(this Player player, float dt) { if (!((Object)(object)player != (Object)(object)Player.m_localPlayer) && !((Character)player).IsDead()) { bool flag = ((Character)player).IsEncumbered(); float maxStamina = ((Character)player).GetMaxStamina(); float num = 1f; if (((Character)player).IsBlocking()) { num *= 0.8f; } if ((((Character)player).IsSwimming() && !((Character)player).IsOnGround()) || ((Character)player).InAttack() || ((Character)player).InDodge() || ((Character)player).m_wallRunning || flag) { num = 0f; } float staminaRegen = EquippedEnchantmentSnapshotService.GetSnapshot(player).StaminaRegen; if (staminaRegen > 0f) { float num2 = 1f; ((Character)player).m_seman.ModifyStaminaRegen(ref num2); float num3 = staminaRegen * num2 * num * dt; player.m_stamina = Mathf.Min(maxStamina, player.m_stamina + num3 * Game.m_staminaRegenRate); } } } } [VES_Autoload(VES_Autoload.Priority.Last, "OnInit", new Type[] { })] public static class Enchantment_Skill { public static SkillType SkillType_Enchantment; [UsedImplicitly] private static void OnInit() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) SkillType_Enchantment = SkillRegistrationService.RegisterConfigurableSkill("kg_Enchantment", "enchantment.png"); } } [VES_Autoload(VES_Autoload.Priority.Normal, "OnInit", new Type[] { typeof(SyncedData) })] public static class Enchantment_VFX { private sealed class ManagedMeshEffectState : MonoBehaviour { public RendererEntry[] Entries = Array.Empty(); public Light? ManagedLight; public Color LastColor = Color.clear; public int LastVariant = -1; public int LastConfigRevision = -1; public bool LastEnabled; public bool LastIsArmor = true; } private sealed class RendererEntry { public Renderer? Renderer; public int RendererInstanceId; public int ManagedMaterialIndex = -1; public GameObject? ParticleRoot; public ParticleSystem[] ParticleSystems = Array.Empty(); public float[] BaseStartSizeMultipliers = Array.Empty(); public RendererEntry(Renderer renderer) { Renderer = renderer; RendererInstanceId = ((Object)renderer).GetInstanceID(); } } private class ConfigurationManagerAttributes { [UsedImplicitly] public int? Order; } private static readonly int TintColor = Shader.PropertyToID("_TintColor"); private const int MainVfxParticleBrightnessOrder = 98; private const int MainVfxLightIntensityOrder = 99; private const int MainVfxTintIntensityOrder = 100; private const int ArmorVfxTintIntensityOrder = 101; private const int EnableWeaponVfxOrder = 102; private const int EnableArmorVfxOrder = 103; private const string ManagedLightName = "VES_Light"; private const string MeshParticleEffectPrefix = "VES_MPE_"; private static readonly MaterialPropertyBlock PropertyBlock = new MaterialPropertyBlock(); private static GameObject VES_MPE; private static readonly float[] VariantTintMultipliers = new float[4] { 1f, 0.65f, 1.8f, 0.35f }; public static readonly List VFXs = new List(); public static ConfigEntry _enableWeaponVFX; public static ConfigEntry _enableArmorVFX; public static ConfigEntry _mainVfxTintIntensity; public static ConfigEntry _mainVfxLightIntensity; public static ConfigEntry _mainVfxParticleBrightness; public static ConfigEntry _armorVfxTintIntensity; private static int _visualConfigRevision; private static bool _sceneVisualRefreshScheduled; private static bool IsManagedVfxMaterial(Material? material) { if ((Object)(object)material != (Object)null) { if (!VFXs.Contains(material)) { return ((Object)material).name.IndexOf("Enchantment_VFX_Mat", StringComparison.Ordinal) >= 0; } return true; } return false; } private static int FindManagedMaterialIndex(Material[] materials) { for (int i = 0; i < materials.Length; i++) { if (IsManagedVfxMaterial(materials[i])) { return i; } } return -1; } private static int EnsureRendererVfxMaterial(RendererEntry entry, int variant) { if ((Object)(object)entry.Renderer == (Object)null) { entry.ManagedMaterialIndex = -1; return -1; } Material[] array = entry.Renderer.sharedMaterials ?? Array.Empty(); int num = entry.ManagedMaterialIndex; if (num < 0 || num >= array.Length || !IsManagedVfxMaterial(array[num])) { num = FindManagedMaterialIndex(array); } if (num >= 0) { if ((Object)(object)array[num] != (Object)(object)VFXs[variant]) { Material[] array2 = (Material[])array.Clone(); array2[num] = VFXs[variant]; entry.Renderer.sharedMaterials = array2; } entry.ManagedMaterialIndex = num; return num; } Material[] array3 = (Material[])(object)new Material[array.Length + 1]; if (array.Length != 0) { Array.Copy(array, array3, array.Length); } array3[array.Length] = VFXs[variant]; entry.Renderer.sharedMaterials = array3; entry.ManagedMaterialIndex = array.Length; return entry.ManagedMaterialIndex; } private static void RemoveRendererVfxMaterial(RendererEntry entry) { if ((Object)(object)entry.Renderer == (Object)null) { entry.ManagedMaterialIndex = -1; return; } Material[] array = entry.Renderer.sharedMaterials ?? Array.Empty(); if (array.Length == 0) { entry.ManagedMaterialIndex = -1; return; } int num = entry.ManagedMaterialIndex; if (num < 0 || num >= array.Length || !IsManagedVfxMaterial(array[num])) { num = FindManagedMaterialIndex(array); } if (num < 0) { entry.ManagedMaterialIndex = -1; return; } if (array.Length == 1) { entry.Renderer.sharedMaterials = Array.Empty(); } else { Material[] array2 = (Material[])(object)new Material[array.Length - 1]; if (num > 0) { Array.Copy(array, 0, array2, 0, num); } if (num < array.Length - 1) { Array.Copy(array, num + 1, array2, num, array.Length - num - 1); } entry.Renderer.sharedMaterials = array2; } PropertyBlock.Clear(); entry.Renderer.SetPropertyBlock(PropertyBlock); entry.ManagedMaterialIndex = -1; } private static void SetRendererTint(Renderer renderer, Color tint) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) PropertyBlock.Clear(); renderer.GetPropertyBlock(PropertyBlock); PropertyBlock.SetColor(TintColor, tint); renderer.SetPropertyBlock(PropertyBlock); } private static GameObject GetOrCreateMeshParticleEffect(GameObject item, Renderer renderer) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) string text = "VES_MPE_" + ((Object)renderer).GetInstanceID(); Transform val = item.transform.Find(text); if ((Object)(object)val != (Object)null) { return ((Component)val).gameObject; } GameObject val2 = Object.Instantiate(VES_MPE, item.transform); ((Object)val2).name = text; val2.transform.localPosition = Vector3.zero; val2.transform.localRotation = Quaternion.identity; val2.transform.localScale = Vector3.one; return val2; } private static Light GetOrCreateManagedLight(GameObject item) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown Transform val = item.transform.Find("VES_Light"); GameObject val2; if ((Object)(object)val != (Object)null) { val2 = ((Component)val).gameObject; } else { val2 = new GameObject("VES_Light"); val2.transform.SetParent(item.transform, false); } return val2.GetComponent() ?? val2.AddComponent(); } private static IEnumerable EnumerateEffectRenderers(GameObject item) { return item.GetComponentsInChildren(true).Cast().Concat((IEnumerable)(object)item.GetComponentsInChildren(true)); } private static ManagedMeshEffectState GetOrCreateManagedMeshEffectState(GameObject item) { ManagedMeshEffectState component = item.GetComponent(); if (!((Object)(object)component != (Object)null)) { return item.AddComponent(); } return component; } private static void EnsureParticleSystems(GameObject item, RendererEntry entry, Renderer renderer) { //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)entry.ParticleRoot == (Object)null) { entry.ParticleRoot = GetOrCreateMeshParticleEffect(item, renderer); } if (entry.ParticleSystems.Length == 0 || !entry.ParticleSystems.All((ParticleSystem ps) => (Object)(object)ps != (Object)null)) { entry.ParticleSystems = entry.ParticleRoot.GetComponentsInChildren(true); entry.BaseStartSizeMultipliers = new float[entry.ParticleSystems.Length]; for (int i = 0; i < entry.ParticleSystems.Length; i++) { float[] baseStartSizeMultipliers = entry.BaseStartSizeMultipliers; int num = i; MainModule main = entry.ParticleSystems[i].main; baseStartSizeMultipliers[num] = ((MainModule)(ref main)).startSizeMultiplier; } } } private static void SetParticleRootActive(RendererEntry entry, bool active) { if ((Object)(object)entry.ParticleRoot != (Object)null && entry.ParticleRoot.activeSelf != active) { entry.ParticleRoot.SetActive(active); } } private static bool TryConfigureParticleEffects(GameObject item, RendererEntry entry, Renderer renderer, Color color) { //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0092: 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_00a7: 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_00c8: 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_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: 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_0139: Unknown result type (might be due to invalid IL or missing references) bool flag = renderer is SkinnedMeshRenderer; if (flag) { SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((renderer is SkinnedMeshRenderer) ? renderer : null); if ((Object)(object)((val != null) ? val.sharedMesh : null) == (Object)null || !val.sharedMesh.isReadable) { SetParticleRootActive(entry, active: false); return false; } } else { MeshFilter component = ((Component)renderer).GetComponent(); if (!Object.op_Implicit((Object)(object)component) || (Object)(object)component.sharedMesh == (Object)null || !component.sharedMesh.isReadable) { SetParticleRootActive(entry, active: false); return false; } } EnsureParticleSystems(item, entry, renderer); SetParticleRootActive(entry, active: true); Bounds bounds = renderer.bounds; Vector3 val2 = ((Bounds)(ref bounds)).size; float magnitude = ((Vector3)(ref val2)).magnitude; val2 = item.transform.lossyScale; float num = ((Vector3)(ref val2)).magnitude; if (num <= 0f) { num = 1f; } float num2 = magnitude / num; Color particleColor = GetParticleColor(color); for (int i = 0; i < entry.ParticleSystems.Length; i++) { ParticleSystem val3 = entry.ParticleSystems[i]; if (!((Object)(object)val3 == (Object)null)) { MainModule main = val3.main; ((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(particleColor); float num3 = ((i < entry.BaseStartSizeMultipliers.Length) ? entry.BaseStartSizeMultipliers[i] : ((MainModule)(ref main)).startSizeMultiplier); ((MainModule)(ref main)).startSizeMultiplier = num3 * num2; ShapeModule shape = val3.shape; ((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)(flag ? 14 : 13); if (flag) { ((ShapeModule)(ref shape)).skinnedMeshRenderer = (SkinnedMeshRenderer)(object)((renderer is SkinnedMeshRenderer) ? renderer : null); ((ShapeModule)(ref shape)).meshRenderer = null; } else { ((ShapeModule)(ref shape)).skinnedMeshRenderer = null; ((ShapeModule)(ref shape)).meshRenderer = (MeshRenderer)(object)((renderer is MeshRenderer) ? renderer : null); } ((Component)val3).gameObject.SetActive(true); } } return true; } private static void DestroyRendererEntry(RendererEntry entry) { if ((Object)(object)entry.ParticleRoot != (Object)null) { Object.Destroy((Object)(object)entry.ParticleRoot); } } private static void RebuildRendererEntries(ManagedMeshEffectState state, bool includeParticles) { GameObject gameObject = ((Component)state).gameObject; Dictionary dictionary = new Dictionary(); RendererEntry[] entries = state.Entries; foreach (RendererEntry rendererEntry in entries) { if ((Object)(object)rendererEntry.Renderer != (Object)null) { dictionary[rendererEntry.RendererInstanceId] = rendererEntry; } else { DestroyRendererEntry(rendererEntry); } } Renderer[] array = (from renderer in EnumerateEffectRenderers(gameObject) where (Object)(object)renderer != (Object)null select renderer).ToArray(); RendererEntry[] array2 = new RendererEntry[array.Length]; for (int j = 0; j < array.Length; j++) { Renderer val = array[j]; int instanceID = ((Object)val).GetInstanceID(); if (!dictionary.TryGetValue(instanceID, out var value)) { value = new RendererEntry(val); } else { dictionary.Remove(instanceID); value.Renderer = val; } value.ManagedMaterialIndex = -1; if (!includeParticles) { SetParticleRootActive(value, active: false); } array2[j] = value; } foreach (RendererEntry value2 in dictionary.Values) { DestroyRendererEntry(value2); } state.Entries = array2; } private static void DisableManagedMeshEffect(ManagedMeshEffectState state) { if ((Object)(object)state.ManagedLight != (Object)null) { ((Behaviour)state.ManagedLight).enabled = false; ((Component)state.ManagedLight).gameObject.SetActive(false); } RendererEntry[] entries = state.Entries; foreach (RendererEntry entry in entries) { RemoveRendererVfxMaterial(entry); SetParticleRootActive(entry, active: false); } } private static void ApplyManagedMeshEffect(ManagedMeshEffectState state, Color color, int variant, bool isArmor) { //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: 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_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) if (state.Entries.Length == 0 || state.LastIsArmor != isArmor || state.Entries.Any((RendererEntry entry) => (Object)(object)entry.Renderer == (Object)null)) { RebuildRendererEntries(state, !isArmor); } if (!isArmor) { Light val = (state.ManagedLight = (Light?)(((Object)(object)state.ManagedLight != (Object)null) ? ((object)state.ManagedLight) : ((object)GetOrCreateManagedLight(((Component)state).gameObject)))); ((Component)val).gameObject.SetActive(true); ((Behaviour)val).enabled = true; val.type = (LightType)2; val.color = color; val.intensity = _mainVfxLightIntensity.Value * color.a; val.range = 9f; } else if ((Object)(object)state.ManagedLight != (Object)null) { ((Behaviour)state.ManagedLight).enabled = false; ((Component)state.ManagedLight).gameObject.SetActive(false); } Color tint = (isArmor ? (color * GetArmorTintIntensity(variant)) : (color * GetTintIntensity(variant))); RendererEntry[] entries = state.Entries; foreach (RendererEntry rendererEntry in entries) { Renderer renderer = rendererEntry.Renderer; if (!((Object)(object)renderer == (Object)null)) { EnsureRendererVfxMaterial(rendererEntry, variant); SetRendererTint(renderer, tint); if (isArmor) { SetParticleRootActive(rendererEntry, active: false); } else { TryConfigureParticleEffects(((Component)state).gameObject, rendererEntry, renderer, color); } } } } private static void SetMeshEffectState(GameObject item, bool enabled, Color color, int variant, bool isArmor) { //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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) if (!Object.op_Implicit((Object)(object)item)) { return; } ManagedMeshEffectState managedMeshEffectState = item.GetComponent(); if (!enabled || VFXs.Count <= 0 || !IsEffectEnabledForClass(isArmor)) { if (!((Object)(object)managedMeshEffectState == (Object)null)) { if (managedMeshEffectState.LastEnabled || managedMeshEffectState.LastConfigRevision != _visualConfigRevision) { DisableManagedMeshEffect(managedMeshEffectState); } managedMeshEffectState.LastEnabled = false; managedMeshEffectState.LastColor = color; managedMeshEffectState.LastVariant = variant; managedMeshEffectState.LastIsArmor = isArmor; managedMeshEffectState.LastConfigRevision = _visualConfigRevision; } return; } if (managedMeshEffectState == null) { managedMeshEffectState = GetOrCreateManagedMeshEffectState(item); } variant = Mathf.Clamp(variant, 0, VFXs.Count - 1); if (!managedMeshEffectState.LastEnabled || managedMeshEffectState.LastVariant != variant || managedMeshEffectState.LastIsArmor != isArmor || managedMeshEffectState.LastConfigRevision != _visualConfigRevision || !((Color)(ref managedMeshEffectState.LastColor)).Equals(color)) { ApplyManagedMeshEffect(managedMeshEffectState, color, variant, isArmor); managedMeshEffectState.LastEnabled = true; managedMeshEffectState.LastColor = color; managedMeshEffectState.LastVariant = variant; managedMeshEffectState.LastIsArmor = isArmor; managedMeshEffectState.LastConfigRevision = _visualConfigRevision; } } internal static void RemoveMeshEffects(GameObject item) { if (!Object.op_Implicit((Object)(object)item)) { return; } ManagedMeshEffectState component = item.GetComponent(); if (component != null) { DisableManagedMeshEffect(component); RendererEntry[] entries = component.Entries; foreach (RendererEntry entry in entries) { DestroyRendererEntry(entry); } if ((Object)(object)component.ManagedLight != (Object)null) { Object.Destroy((Object)(object)((Component)component.ManagedLight).gameObject); } Object.Destroy((Object)(object)component); } Transform[] array = (from Transform child in (IEnumerable)item.transform where ((Object)child).name == "VES_Light" || ((Object)child).name.StartsWith("VES_MPE_", StringComparison.Ordinal) select child).ToArray(); foreach (Transform val in array) { Object.Destroy((Object)(object)((Component)val).gameObject); } foreach (Renderer item2 in EnumerateEffectRenderers(item)) { Material[] array2 = item2.sharedMaterials ?? Array.Empty(); int num = FindManagedMaterialIndex(array2); if (num >= 0) { Material[] array3 = (Material[])(object)new Material[array2.Length - 1]; if (num > 0) { Array.Copy(array2, 0, array3, 0, num); } if (num < array2.Length - 1) { Array.Copy(array2, num + 1, array3, num, array2.Length - num - 1); } item2.sharedMaterials = array3; PropertyBlock.Clear(); item2.SetPropertyBlock(PropertyBlock); } } } private static ConfigDescription OrderedDescription(string description, int order) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown return new ConfigDescription(description, (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = order } }); } private static ConfigDescription OrderedRangeDescription(string description, int order, float min, float max) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown return new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange(min, max), new object[1] { new ConfigurationManagerAttributes { Order = order } }); } [UsedImplicitly] private static void OnInit() { if (!ValheimEnchantmentSystem.NoGraphics) { VFXs.Add(ValheimEnchantmentSystem._asset.LoadAsset("Enchantment_VFX_Mat1")); VFXs.Add(ValheimEnchantmentSystem._asset.LoadAsset("Enchantment_VFX_Mat2")); VFXs.Add(ValheimEnchantmentSystem._asset.LoadAsset("Enchantment_VFX_Mat3")); VFXs.Add(ValheimEnchantmentSystem._asset.LoadAsset("Enchantment_VFX_Mat4")); VES_MPE = ValheimEnchantmentSystem._asset.LoadAsset("VES_MPE"); _mainVfxParticleBrightness = ValheimEnchantmentSystem.ClientConfig("", "MainVFXParticleBrightness", 1.5f, OrderedRangeDescription("Brightness of weapon/world/stand particle VFX.", 98, 0f, 5f)); _mainVfxLightIntensity = ValheimEnchantmentSystem.ClientConfig("", "MainVFXLightIntensity", 1f, OrderedRangeDescription("Light intensity added by weapon/world/stand VFX.", 99, 0f, 5f)); _mainVfxTintIntensity = ValheimEnchantmentSystem.ClientConfig("", "MainVFXTintIntensity", 8f, OrderedRangeDescription("Emission intensity of weapon/world/stand VFX materials.", 100, 0f, 50f)); _armorVfxTintIntensity = ValheimEnchantmentSystem.ClientConfig("", "ArmorVFXTintIntensity", 2f, OrderedRangeDescription("Emission intensity of armor/cape/utility VFX materials.", 101, 0f, 20f)); _enableWeaponVFX = ValheimEnchantmentSystem.ClientConfig("", "EnableWeaponVFX", value: true, OrderedDescription("Enable enchantment VFX for held items like weapons, shields, tools, torches, and their stands.", 102)); _enableArmorVFX = ValheimEnchantmentSystem.ClientConfig("", "EnableArmorVFX", value: true, OrderedDescription("Enable enchantment VFX for worn items like armor, capes, utility items, and their stands.", 103)); _enableWeaponVFX.SettingChanged += delegate { OnEquipmentVisualSettingChanged(); }; _enableArmorVFX.SettingChanged += delegate { OnEquipmentVisualSettingChanged(); }; _mainVfxParticleBrightness.SettingChanged += delegate { OnEquipmentVisualSettingChanged(); }; _mainVfxLightIntensity.SettingChanged += delegate { OnEquipmentVisualSettingChanged(); }; _mainVfxTintIntensity.SettingChanged += delegate { OnEquipmentVisualSettingChanged(); }; _armorVfxTintIntensity.SettingChanged += delegate { OnEquipmentVisualSettingChanged(); }; } } private static void OnEquipmentVisualSettingChanged() { _visualConfigRevision++; RequestSceneVisualRefresh(); } internal static void RequestSceneVisualRefresh() { if (ValheimEnchantmentSystem.NoGraphics) { return; } if ((Object)(object)ValheimEnchantmentSystem._thistype == (Object)null) { RefreshSceneVisuals(); } else if (!_sceneVisualRefreshScheduled) { _sceneVisualRefreshScheduled = true; ((MonoBehaviour)(object)ValheimEnchantmentSystem._thistype).DelayedInvoke(delegate { _sceneVisualRefreshScheduled = false; RefreshSceneVisuals(); }, 1); } } internal static bool IsWeaponVfxEnabled() { return _enableWeaponVFX.Value; } internal static bool IsArmorVfxEnabled() { return _enableArmorVFX.Value; } internal static bool IsEffectEnabledForClass(bool isArmor) { if (!isArmor) { return IsWeaponVfxEnabled(); } return IsArmorVfxEnabled(); } internal static void InsertColor(ZDO zdo, string key, string color, int variant) { if (zdo != null) { if (color == null) { color = string.Empty; } variant = Mathf.Max(0, variant); if (!string.Equals(zdo.GetString(key, ""), color, StringComparison.Ordinal)) { zdo.Set(key, color); } string text = key + "_variant"; if (zdo.GetInt(text, 0) != variant) { zdo.Set(text, variant); } } } internal static string GetItemEnchantmentColor(ItemData item, out int variant, bool trimAlpha = false) { variant = 0; Enchantment_Core.Enchanted enchanted = item?.Data().Get(); if (enchanted != null && enchanted.level > 0) { return SyncedData.GetColor(enchanted, out variant, trimAlpha); } return string.Empty; } internal static bool TryGetVisSlotColorKey(VisSlot slot, out string colorKey, out bool isArmor) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected I4, but got Unknown switch ((int)slot) { case 0: colorKey = "VES_leftitemColor"; isArmor = false; return true; case 1: colorKey = "VES_rightitemColor"; isArmor = false; return true; case 2: colorKey = "VES_leftbackitemColor"; isArmor = false; return true; case 3: colorKey = "VES_rightbackitemColor"; isArmor = false; return true; case 4: colorKey = "VES_chestitemColor"; isArmor = true; return true; case 5: colorKey = "VES_legsitemColor"; isArmor = true; return true; case 6: colorKey = "VES_helmetitemColor"; isArmor = true; return true; case 7: colorKey = "VES_shoulderitemColor"; isArmor = true; return true; default: colorKey = string.Empty; isArmor = true; return false; } } internal static bool IsArmorVisual(ItemData itemData) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected I4, but got Unknown if (itemData == null) { return true; } ItemType itemType = itemData.m_shared.m_itemType; return (itemType - 3) switch { 16 => false, 12 => false, 0 => false, 2 => false, 1 => false, 11 => false, 19 => false, 3 => true, 4 => true, 8 => true, 14 => true, 15 => true, _ => !itemData.IsWeapon(), }; } private static float GetTintIntensity(int variant) { variant = Mathf.Clamp(variant, 0, VariantTintMultipliers.Length - 1); return _mainVfxTintIntensity.Value * VariantTintMultipliers[variant]; } private static float GetArmorTintIntensity(int variant) { variant = Mathf.Clamp(variant, 0, VariantTintMultipliers.Length - 1); return _armorVfxTintIntensity.Value * VariantTintMultipliers[variant]; } private static Color GetParticleColor(Color color) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) float num = default(float); float num2 = default(float); float num3 = default(float); Color.RGBToHSV(color, ref num, ref num2, ref num3); float num4 = Mathf.Clamp01(num3 * _mainVfxParticleBrightness.Value); Color result = Color.HSVToRGB(num, num2, num4, false); result.a = color.a; return result; } public static void RefreshEquipmentVisuals() { if (!ValheimEnchantmentSystem.NoGraphics) { ArmorStandVfx.RefreshAllArmorStandVisuals(); EquipmentWorldVfx.RefreshEquipmentVisuals(); } } public static void RefreshArmorStandVisuals(ArmorStand armorStand) { if (!ValheimEnchantmentSystem.NoGraphics) { ArmorStandVfx.RefreshArmorStandVisuals(armorStand); } } public static void RefreshWorldItemVisuals() { if (!ValheimEnchantmentSystem.NoGraphics) { EquipmentWorldVfx.RefreshWorldItemVisuals(); } } public static void RefreshSceneVisuals() { if (!ValheimEnchantmentSystem.NoGraphics) { RefreshEquipmentVisuals(); RefreshWorldItemVisuals(); } } public static void RefreshLiveVisuals() { if (!ValheimEnchantmentSystem.NoGraphics) { UpdateGrid(); RefreshSceneVisuals(); } } public static void AttachMeshEffect(GameObject item, Color c, int variant, bool isArmor = false) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) SetMeshEffectState(item, enabled: true, c, variant, isArmor); } internal static void DisableMeshEffect(GameObject item, bool isArmor = false) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) SetMeshEffectState(item, enabled: false, Color.clear, 0, isArmor); } public static void UpdateGrid() { InventoryOverlayVfx.UpdateGrid(); } } internal static class ArmorStandVfx { [HarmonyPatch(typeof(ArmorStand), "UpdateVisual")] [ClientOnlyPatch] private static class ArmorStand_UpdateVisual_Patch { [UsedImplicitly] private static void Prefix(ArmorStand __instance) { if (!((Object)(object)__instance == (Object)null)) { ArmorStandBatchRefreshes.Add(((Object)__instance).GetInstanceID()); } } [UsedImplicitly] private static void Postfix(ArmorStand __instance) { if (!((Object)(object)__instance == (Object)null)) { ArmorStandBatchRefreshes.Remove(((Object)__instance).GetInstanceID()); RefreshArmorStandVisuals(__instance); } } } [HarmonyPatch(typeof(ArmorStand), "SetVisualItem", new Type[] { typeof(int), typeof(string), typeof(int) })] [ClientOnlyPatch] private static class ArmorStand_SetVisualItem_Patch { [UsedImplicitly] private static void Postfix(ArmorStand __instance, int index) { if (!((Object)(object)__instance != (Object)null) || !ArmorStandBatchRefreshes.Contains(((Object)__instance).GetInstanceID())) { RefreshArmorStandVisuals(__instance); } } } [HarmonyPatch(typeof(ArmorStand), "Awake")] [ClientOnlyPatch] private static class ArmorStand_Awake_Patch { [UsedImplicitly] private static void Postfix(ArmorStand __instance) { ArmorStand __instance2 = __instance; if (!((Object)(object)ValheimEnchantmentSystem._thistype == (Object)null) && !((Object)(object)__instance2 == (Object)null)) { ((MonoBehaviour)(object)ValheimEnchantmentSystem._thistype).DelayedInvoke(delegate { ForceInitialArmorStandRefresh(__instance2); }, 1); ((MonoBehaviour)(object)ValheimEnchantmentSystem._thistype).DelayedInvoke(delegate { ForceInitialArmorStandRefresh(__instance2); }, 30); } } } private static readonly MethodInfo ArmorStandUpdateVisualMethod = AccessTools.Method(typeof(ArmorStand), "UpdateVisual", (Type[])null, (Type[])null); private static readonly HashSet ArmorStandBatchRefreshes = new HashSet(); private static void RefreshArmorStandSlotVisual(ArmorStand armorStand, ZDO armorStandZdo, ZDO visEquipmentZdo, int slotIndex, bool writeMetadata) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) if (armorStand.m_slots == null || slotIndex < 0 || slotIndex >= armorStand.m_slots.Count || !Enchantment_VFX.TryGetVisSlotColorKey(armorStand.m_slots[slotIndex].m_slot, out string colorKey, out bool _)) { return; } string visualName = armorStand.m_slots[slotIndex].m_visualName; if (string.IsNullOrEmpty(visualName)) { if (writeMetadata) { Enchantment_VFX.InsertColor(visEquipmentZdo, colorKey, string.Empty, 0); } return; } GameObject val = (Object.op_Implicit((Object)(object)ObjectDB.instance) ? ObjectDB.instance.GetItemPrefab(visualName) : null); if (!Object.op_Implicit((Object)(object)val)) { return; } ItemDrop component = val.GetComponent(); if (!((Object)(object)component == (Object)null)) { ItemData val2 = component.m_itemData.Clone(); if (armorStandZdo != null) { ItemDrop.LoadFromZDO(slotIndex, val2, armorStandZdo); } else { val2.m_variant = armorStand.m_slots[slotIndex].m_visualVariant; } int variant; string itemEnchantmentColor = Enchantment_VFX.GetItemEnchantmentColor(val2, out variant); if (writeMetadata) { Enchantment_VFX.InsertColor(visEquipmentZdo, colorKey, itemEnchantmentColor, variant); } } } public static void RefreshArmorStandVisuals(ArmorStand armorStand) { if ((Object)(object)armorStand == (Object)null || (Object)(object)armorStand.m_visEquipment == (Object)null) { return; } ZNetView nview = armorStand.m_visEquipment.m_nview; ZDO val = ((nview != null) ? nview.GetZDO() : null); if (val == null) { return; } ZNetView nview2 = armorStand.m_nview; ZDO armorStandZdo = ((nview2 != null) ? nview2.GetZDO() : null); bool writeMetadata = (Object)(object)armorStand.m_visEquipment.m_nview != (Object)null && armorStand.m_visEquipment.m_nview.IsValid() && armorStand.m_visEquipment.m_nview.IsOwner(); if (armorStand.m_slots != null) { for (int i = 0; i < armorStand.m_slots.Count; i++) { RefreshArmorStandSlotVisual(armorStand, armorStandZdo, val, i, writeMetadata); } } EquipmentWorldVfx.RefreshVisEquipment(armorStand.m_visEquipment); } public static void RefreshAllArmorStandVisuals() { if (ValheimEnchantmentSystem.NoGraphics) { return; } foreach (ArmorStand item in VfxInstanceRegistry.EnumerateArmorStands()) { RefreshArmorStandVisuals(item); } } private static void ForceInitialArmorStandRefresh(ArmorStand armorStand) { if ((Object)(object)armorStand == (Object)null || (Object)(object)armorStand.m_nview == (Object)null || !armorStand.m_nview.IsValid()) { return; } try { ArmorStandUpdateVisualMethod?.Invoke(armorStand, null); } catch { } } } internal static class BloodMagicSummonEnchantmentService { [HarmonyPatch(typeof(SpawnAbility), "SetupAoe")] private static class SpawnAbility_SetupAoe_Patch { [UsedImplicitly] private static void Prefix(SpawnAbility __instance, Character owner) { if (Object.op_Implicit((Object)(object)owner) && Object.op_Implicit((Object)(object)owner.m_nview) && owner.m_nview.IsValid() && TryGetSourceEnchantment(__instance.m_weapon, out string sourcePrefab, out int sourceLevel)) { ZDO zDO = owner.m_nview.GetZDO(); if (zDO != null) { zDO.Set(SourcePrefabHash, sourcePrefab); zDO.Set(SourceLevelHash, sourceLevel, false); } } } } [HarmonyPatch(typeof(Character), "RPC_Damage")] private static class Character_RPC_Damage_Patch { [UsedImplicitly] private static void Prefix(HitData hit) { if (hit != null) { Character attacker = hit.GetAttacker(); if (TryGetSummonDamageStats(attacker, out SyncedData.Stat_Data stats)) { ApplyDamageStats(hit, stats); } } } } private static readonly int SourcePrefabHash = StringExtensionMethods.GetStableHashCode("VES_BloodMagicSummonSourcePrefab"); private static readonly int SourceLevelHash = StringExtensionMethods.GetStableHashCode("VES_BloodMagicSummonSourceLevel"); private static bool TryGetSourceEnchantment(ItemData weapon, out string sourcePrefab, out int sourceLevel) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Invalid comparison between Unknown and I4 sourcePrefab = string.Empty; sourceLevel = 0; if (weapon == null || (int)weapon.m_shared.m_skillType != 10) { return false; } Enchantment_Core.Enchanted enchanted = weapon.Data().Get(); if (enchanted == null || enchanted.level <= 0) { return false; } sourcePrefab = EnchantmentDomainHelper.ResolveItemPrefabName(weapon); if (string.IsNullOrWhiteSpace(sourcePrefab)) { return false; } SyncedData.Stat_Data statIncrease = SyncedData.GetStatIncrease(sourcePrefab, enchanted.level, isWeapon: true); if (!HasDamageStats(statIncrease)) { return false; } sourceLevel = enchanted.level; return true; } private static bool TryGetSummonDamageStats(Character attacker, out SyncedData.Stat_Data stats) { stats = null; if (!Object.op_Implicit((Object)(object)attacker) || !Object.op_Implicit((Object)(object)attacker.m_nview) || !attacker.m_nview.IsValid()) { return false; } ZDO zDO = attacker.m_nview.GetZDO(); if (zDO == null) { return false; } string @string = zDO.GetString(SourcePrefabHash, ""); int @int = zDO.GetInt(SourceLevelHash, 0); if (string.IsNullOrWhiteSpace(@string) || @int <= 0) { return false; } stats = SyncedData.GetStatIncrease(@string, @int, isWeapon: true); return HasDamageStats(stats); } private static bool HasDamageStats(SyncedData.Stat_Data stats) { if (stats != null) { if (stats.damage_percentage == 0 && stats.damage_true == 0 && stats.damage_blunt == 0 && stats.damage_slash == 0 && stats.damage_pierce == 0 && stats.damage_chop == 0 && stats.damage_pickaxe == 0 && stats.damage_fire == 0 && stats.damage_frost == 0 && stats.damage_lightning == 0 && stats.damage_poison == 0) { return stats.damage_spirit != 0; } return true; } return false; } private static void ApplyDamageStats(HitData hit, SyncedData.Stat_Data stats) { ((DamageTypes)(ref hit.m_damage)).Modify(1f + (float)stats.damage_percentage / 100f); hit.m_damage.m_blunt += stats.damage_blunt; hit.m_damage.m_slash += stats.damage_slash; hit.m_damage.m_pierce += stats.damage_pierce; hit.m_damage.m_fire += stats.damage_fire; hit.m_damage.m_frost += stats.damage_frost; hit.m_damage.m_lightning += stats.damage_lightning; hit.m_damage.m_poison += stats.damage_poison; hit.m_damage.m_spirit += stats.damage_spirit; hit.m_damage.m_damage += stats.damage_true; hit.m_damage.m_chop += stats.damage_chop; hit.m_damage.m_pickaxe += stats.damage_pickaxe; } } internal static class EnchantmentDomainHelper { public static bool CanEnchant(ItemData item, int currentLevel, string itemPrefabName) { if (item == null || string.IsNullOrWhiteSpace(itemPrefabName)) { return false; } if (!SyncedData.IsLevelEnchantable(itemPrefabName, currentLevel, item.IsWeapon())) { return false; } return SyncedData.GetReqs(itemPrefabName) != null; } public static string ResolveItemPrefabName(ItemData item) { if (Object.op_Implicit((Object)(object)item?.m_dropPrefab)) { return ((Object)item.m_dropPrefab).name; } return Utils.GetPrefabNameByItemName(item?.m_shared?.m_name); } } public readonly struct EnchantmentAttemptSummary { public readonly double FinalChancePercent; public readonly string ChanceBreakdownText; public readonly string FailureBreakdownText; public EnchantmentAttemptSummary(double finalChancePercent, string chanceBreakdownText, string failureBreakdownText) { FinalChancePercent = finalChancePercent; ChanceBreakdownText = chanceBreakdownText; FailureBreakdownText = failureBreakdownText; } } public sealed class EnchantmentPreview { public ItemData Item; public string ItemDisplayName = string.Empty; public string ItemLabel = string.Empty; public string BlockedMessage = string.Empty; public Sprite RequirementIcon; public bool UseBlessedScroll; public bool CanSelect; public bool CanAttempt; public bool IsMaxedOut; public bool HasRequirementDefinition; public bool HasRequiredItems; public Color TrailColor = new Color(1f, 1f, 1f, 0.8f); public string RequirementStatusText = string.Empty; public EnchantmentAttemptSummary AttemptSummary; public string NextStatsTooltipText = string.Empty; } public static class EnchantmentPreviewService { private static readonly Color DefaultTrailColor = new Color(1f, 1f, 1f, 0.8f); public static EnchantmentPreview GetPreview(ItemData item, bool useBlessedScroll) { //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) EnchantmentPreview enchantmentPreview = new EnchantmentPreview { Item = item, UseBlessedScroll = useBlessedScroll, ItemDisplayName = (item?.m_shared?.m_name?.Localize() ?? string.Empty), RequirementStatusText = "$enchantment_noenchantitems".Localize() }; int num = (item?.Data().Get())?.level ?? 0; string text = EnchantmentDomainHelper.ResolveItemPrefabName(item); string text2 = ResolveDisplayColor(text, num); enchantmentPreview.ItemLabel = BuildItemLabel(enchantmentPreview.ItemDisplayName, num, text2); enchantmentPreview.TrailColor = ((num == 0) ? DefaultTrailColor : text2.ToColorAlpha()); if (item == null || string.IsNullOrWhiteSpace(text)) { return enchantmentPreview; } if (!IntegrationRegistry.CanEnchant(item, out string message)) { enchantmentPreview.BlockedMessage = (string.IsNullOrWhiteSpace(message) ? "$enchantment_cannotbe".Localize() : message); return enchantmentPreview; } if (SyncedData.GetReqs(text) == null) { enchantmentPreview.BlockedMessage = "$enchantment_cannotbe".Localize(); return enchantmentPreview; } if (!SyncedData.IsLevelEnchantable(text, num, item.IsWeapon())) { enchantmentPreview.CanSelect = true; enchantmentPreview.IsMaxedOut = true; enchantmentPreview.BlockedMessage = "$enchantment_maxedout".Localize(); enchantmentPreview.RequirementStatusText = enchantmentPreview.BlockedMessage; return enchantmentPreview; } if (!EnchantmentDomainHelper.CanEnchant(item, num, text)) { enchantmentPreview.BlockedMessage = ResolveBlockedMessage(item, text, num); return enchantmentPreview; } enchantmentPreview.CanSelect = true; enchantmentPreview.AttemptSummary = BuildAttemptSummary(item, text, num, useBlessedScroll); PopulateRequirementPreview(enchantmentPreview, text); PopulateNextStatsPreview(enchantmentPreview, text, num); enchantmentPreview.CanAttempt = enchantmentPreview.CanSelect && enchantmentPreview.HasRequirementDefinition && enchantmentPreview.HasRequiredItems; return enchantmentPreview; } private static void PopulateRequirementPreview(EnchantmentPreview preview, string itemPrefabName) { if (preview.Item == null || string.IsNullOrWhiteSpace(itemPrefabName)) { return; } SyncedData.EnchantmentReqs reqs = SyncedData.GetReqs(itemPrefabName); if (reqs == null) { return; } SyncedData.SingleReq singleReq = (preview.UseBlessedScroll ? reqs.blessed_enchant_prefab : reqs.enchant_prefab); if (singleReq != null && singleReq.IsValid()) { ZNetScene instance = ZNetScene.instance; GameObject val = ((instance != null) ? instance.GetPrefab(singleReq.prefab) : null); ItemDrop val2 = ((val != null) ? val.GetComponent() : null); if (val2 != null) { preview.HasRequirementDefinition = true; preview.RequirementIcon = val2.m_itemData.GetIcon(); string requirementDisplayName = val2.m_itemData.m_shared.m_name.Localize(); int num = 1; int num2 = Utils.CustomCountItemsNoLevel(singleReq.prefab); preview.HasRequiredItems = num2 >= num; preview.RequirementStatusText = BuildRequirementStatusText(requirementDisplayName, num2, num); } } } private static EnchantmentAttemptSummary BuildAttemptSummary(ItemData item, string itemPrefabName, int currentLevel, bool useBlessedScroll) { if (item == null || string.IsNullOrWhiteSpace(itemPrefabName)) { return default(EnchantmentAttemptSummary); } EnchantmentRulePreview enchantmentRulePreview = EnchantmentRules.BuildPreview(item, itemPrefabName, currentLevel, Player.m_localPlayer, useBlessedScroll, SyncedData.BlessedScrollsPreventBreak.Value); double baseChancePercent = RoundChance(enchantmentRulePreview.BaseChance); double skillBonusChancePercent = RoundChance(enchantmentRulePreview.SkillBonus); double blessBonusChancePercent = RoundChance(enchantmentRulePreview.BlessBonus); double finalChancePercent = RoundChance(enchantmentRulePreview.FinalChance); double destroyChancePercent = RoundChance(enchantmentRulePreview.DestroyChance); return new EnchantmentAttemptSummary(finalChancePercent, BuildChanceBreakdownText(baseChancePercent, skillBonusChancePercent, blessBonusChancePercent, finalChancePercent), BuildFailureBreakdownText(finalChancePercent, destroyChancePercent, enchantmentRulePreview.CanBreak, enchantmentRulePreview.BlessPreventsBreak, enchantmentRulePreview.FailureType)); } private static void PopulateNextStatsPreview(EnchantmentPreview preview, string itemPrefabName, int currentLevel) { if (preview.Item != null && !string.IsNullOrWhiteSpace(itemPrefabName)) { bool isWeapon = preview.Item.IsWeapon(); SyncedData.Stat_Data statIncrease = SyncedData.GetStatIncrease(itemPrefabName, currentLevel, isWeapon); SyncedData.Stat_Data statIncrease2 = SyncedData.GetStatIncrease(itemPrefabName, currentLevel + 1, isWeapon); string text = EnchantmentStatFormatter.BuildTransitionDescription(statIncrease, statIncrease2); if (!string.IsNullOrWhiteSpace(text)) { preview.NextStatsTooltipText = $"+{currentLevel} > +{currentLevel + 1}\n{text}"; } } } private static string ResolveDisplayColor(string itemPrefabName, int currentLevel) { if (string.IsNullOrWhiteSpace(itemPrefabName)) { return "white"; } int variant; return SyncedData.GetColor(itemPrefabName, currentLevel, out variant, trimApha: true).IncreaseColorLight(); } private static string BuildItemLabel(string itemDisplayName, int currentLevel, string displayColor) { return $"{itemDisplayName} (+{currentLevel})"; } private static string ResolveBlockedMessage(ItemData item, string itemPrefabName, int currentLevel) { if (item == null || string.IsNullOrWhiteSpace(itemPrefabName)) { return string.Empty; } if (SyncedData.GetReqs(itemPrefabName) == null) { return "$enchantment_cannotbe".Localize(); } if (SyncedData.IsLevelEnchantable(itemPrefabName, currentLevel, item.IsWeapon())) { return "$enchantment_cannotbe".Localize(); } return "$enchantment_maxedout".Localize(); } private static string BuildRequirementStatusText(string requirementDisplayName, int requirementCount, int requirementNeededCount) { return string.Format("{0}: {1} {2}/{3}", "$enchantment_rule_material".Localize(), requirementDisplayName, requirementCount, requirementNeededCount); } private static string BuildChanceBreakdownText(double baseChancePercent, double skillBonusChancePercent, double blessBonusChancePercent, double finalChancePercent) { List list = new List { FormatPercent(baseChancePercent) + "%" }; if (skillBonusChancePercent > 0.0) { list.Add("$enchantment_rule_skill".Localize() + FormatPercent(skillBonusChancePercent) + "%"); } if (blessBonusChancePercent > 0.0) { list.Add("$enchantment_rule_bless".Localize() + FormatPercent(blessBonusChancePercent) + "%"); } return FormatPercent(finalChancePercent) + "% (" + string.Join(" + ", list) + ")"; } private static string BuildFailureBreakdownText(double finalChancePercent, double destroyChancePercent, bool canBreak, bool blessPreventsBreak, SyncedData.ItemDesctructionTypeEnum failureType) { List list = new List(); double num = 100.0 - finalChancePercent; int levelDecrease = Mathf.Clamp(SyncedData.FailedEnchantLevelDecrease.Value, 1, 100); if (RoundChance(num) <= 0.0) { return string.Empty; } if (blessPreventsBreak || !canBreak) { AppendFailureChancePart(list, "stay", num); return string.Join("\n", list); } switch (failureType) { case SyncedData.ItemDesctructionTypeEnum.Destroy: AppendFailureChancePart(list, "break", num); break; case SyncedData.ItemDesctructionTypeEnum.Combined: AppendFailureChancePart(list, "decrease", num * ((100.0 - destroyChancePercent) / 100.0), levelDecrease); AppendFailureChancePart(list, "break", num * (destroyChancePercent / 100.0)); break; case SyncedData.ItemDesctructionTypeEnum.CombinedEasy: AppendFailureChancePart(list, "stay", num * ((100.0 - destroyChancePercent) / 100.0)); AppendFailureChancePart(list, "decrease", num * (destroyChancePercent / 100.0), levelDecrease); break; default: AppendFailureChancePart(list, "decrease", num, levelDecrease); break; } return string.Join("\n", list); } private static double RoundChance(double value) { return Math.Round(value, 2, MidpointRounding.AwayFromZero); } private static string FormatPercent(double value) { return value.ToString("0.00", CultureInfo.InvariantCulture); } private static void AppendFailureChancePart(List parts, string label, double value, int levelDecrease = 0) { double num = RoundChance(value); if (!(num <= 0.0)) { string text = ResolveFailureOutcomeLabel(label); if (label == "decrease" && levelDecrease > 0) { text = $"{text} -{levelDecrease}"; } parts.Add(FormatPercent(num) + "% (" + text + ")"); } } private static string ResolveFailureOutcomeLabel(string label) { return label switch { "stay" => "$enchantment_preview_stay".Localize(), "decrease" => "$enchantment_preview_decrease".Localize(), "break" => "$enchantment_preview_break".Localize(), _ => label, }; } } public sealed class EnchantmentResult { public Enchantment_Core.Enchanted Enchantment; public Player Player; public string ItemPrefabName = string.Empty; public string Message = string.Empty; public int PreviousLevel; public int CurrentLevel; public float SkillExpGranted; public bool Success; public bool Destroyed; public bool ConsumedRequirement; public bool LevelChanged; public Notifications_UI.NotificationItemResult? NotificationType; } internal enum EnchantmentOutcome { Success, LevelDecrease, Destroyed, NoChange } internal readonly struct EnchantmentDecision { public readonly EnchantmentOutcome Outcome; public readonly int NewLevel; public readonly Notifications_UI.NotificationItemResult NotificationType; public EnchantmentDecision(EnchantmentOutcome outcome, int newLevel, Notifications_UI.NotificationItemResult notificationType) { Outcome = outcome; NewLevel = newLevel; NotificationType = notificationType; } } internal readonly struct EnchantmentRulePreview { public readonly double BaseChance; public readonly double SkillBonus; public readonly double BlessBonus; public readonly double FinalChance; public readonly double DestroyChance; public readonly bool CanBreak; public readonly bool BlessPreventsBreak; public readonly SyncedData.ItemDesctructionTypeEnum FailureType; public EnchantmentRulePreview(double baseChance, double skillBonus, double blessBonus, double finalChance, double destroyChance, bool canBreak, bool blessPreventsBreak, SyncedData.ItemDesctructionTypeEnum failureType) { BaseChance = baseChance; SkillBonus = skillBonus; BlessBonus = blessBonus; FinalChance = finalChance; DestroyChance = destroyChance; CanBreak = canBreak; BlessPreventsBreak = blessPreventsBreak; FailureType = failureType; } } public static class EnchantmentService { public static EnchantmentResult Execute(Enchantment_Core.Enchanted enchantment, Player player, bool useBlessedScroll, bool blessedScrollPreventsBreak) { EnchantmentResult enchantmentResult = CreateResult(enchantment, player); if (enchantment?.Item == null || (Object)(object)player == (Object)null) { enchantmentResult.Message = "$enchantment_cannotbe".Localize(); return enchantmentResult; } ItemData item = enchantment.Item; if (!IntegrationRegistry.CanEnchant(item, out string message)) { enchantmentResult.Message = (string.IsNullOrWhiteSpace(message) ? "$enchantment_cannotbe".Localize() : message); return enchantmentResult; } if (!EnchantmentDomainHelper.CanEnchant(item, enchantment.level, enchantmentResult.ItemPrefabName)) { enchantmentResult.Message = "$enchantment_cannotbe".Localize(); return enchantmentResult; } if (!TryResolveRequirement(item, enchantmentResult.ItemPrefabName, useBlessedScroll, out SyncedData.EnchantmentReqs reqs, out GameObject requirementPrefab)) { enchantmentResult.Message = "$enchantment_nomaterials".Localize(); return enchantmentResult; } if (!TryConsumeRequirement(((Object)requirementPrefab).name)) { enchantmentResult.Message = "$enchantment_nomaterials".Localize(); return enchantmentResult; } enchantmentResult.ConsumedRequirement = true; float skillExp = GetSkillExp(reqs); EnchantmentDecision decision = EnchantmentRules.Decide(enchantment, player, useBlessedScroll, blessedScrollPreventsBreak); ApplyDecision(enchantment, player, decision, enchantmentResult); enchantmentResult.SkillExpGranted = GetGrantedSkillExp(skillExp, enchantmentResult.Success); enchantmentResult.Message = BuildMessage(decision.Outcome, item.m_shared.m_name.Localize(), enchantmentResult.PreviousLevel, enchantmentResult.CurrentLevel); return enchantmentResult; } private static EnchantmentResult CreateResult(Enchantment_Core.Enchanted enchantment, Player player) { int num = enchantment?.level ?? 0; return new EnchantmentResult { Enchantment = enchantment, Player = player, ItemPrefabName = EnchantmentDomainHelper.ResolveItemPrefabName(enchantment?.Item), PreviousLevel = num, CurrentLevel = num }; } private static bool TryResolveRequirement(ItemData item, string itemPrefabName, bool useBlessedScroll, out SyncedData.EnchantmentReqs reqs, out GameObject requirementPrefab) { reqs = null; requirementPrefab = null; if (item == null || string.IsNullOrWhiteSpace(itemPrefabName)) { return false; } reqs = SyncedData.GetReqs(itemPrefabName); if (reqs == null) { return false; } SyncedData.SingleReq singleReq = (useBlessedScroll ? reqs.blessed_enchant_prefab : reqs.enchant_prefab); if (singleReq == null || !singleReq.IsValid()) { return false; } ZNetScene instance = ZNetScene.instance; requirementPrefab = ((instance != null) ? instance.GetPrefab(singleReq.prefab) : null); return (Object)(object)requirementPrefab != (Object)null; } private static bool TryConsumeRequirement(string requirementPrefabName) { if (string.IsNullOrWhiteSpace(requirementPrefabName)) { return false; } if (Utils.CustomCountItemsNoLevel(requirementPrefabName) < 1) { return false; } Utils.CustomRemoveItemsNoLevel(requirementPrefabName, 1); return true; } private static float GetSkillExp(SyncedData.EnchantmentReqs reqs) { if (reqs?.enchant_prefab == null || !reqs.enchant_prefab.IsValid()) { return 0f; } return EnchantmentTierCatalog.GetEnchantSkillExp(reqs.enchant_prefab.prefab); } private static float GetGrantedSkillExp(float successfulAttemptSkillExp, bool success) { if (successfulAttemptSkillExp <= 0f) { return 0f; } if (success) { return successfulAttemptSkillExp; } float num = Mathf.Clamp(SyncedData.FailedEnchantSkillExpMultiplier.Value, 0f, 2f); return successfulAttemptSkillExp * num; } private static void ApplyDecision(Enchantment_Core.Enchanted enchantment, Player player, EnchantmentDecision decision, EnchantmentResult result) { result.Success = decision.Outcome == EnchantmentOutcome.Success; result.Destroyed = decision.Outcome == EnchantmentOutcome.Destroyed; result.NotificationType = decision.NotificationType; if (decision.Outcome == EnchantmentOutcome.Destroyed) { if ((Object)(object)player != (Object)null) { ((Humanoid)player).UnequipItem(enchantment.Item, true); ((Humanoid)player).m_inventory.RemoveItem(enchantment.Item); } result.CurrentLevel = result.PreviousLevel; } else { enchantment.level = decision.NewLevel; enchantment.Save(); result.CurrentLevel = enchantment.level; result.LevelChanged = result.CurrentLevel != result.PreviousLevel; } } private static string BuildMessage(EnchantmentOutcome outcome, string itemName, int previousLevel, int currentLevel) { return outcome switch { EnchantmentOutcome.Success => "$enchantment_success".Localize(itemName, previousLevel.ToString(), currentLevel.ToString()), EnchantmentOutcome.LevelDecrease => "$enchantment_fail_leveldown".Localize(itemName, previousLevel.ToString(), currentLevel.ToString()), EnchantmentOutcome.Destroyed => "$enchantment_fail_destroyed".Localize(itemName), _ => "$enchantment_fail_nochange".Localize(itemName, currentLevel.ToString()), }; } } internal static class EnchantmentRules { public static EnchantmentRulePreview BuildPreview(ItemData item, string itemPrefabName, int currentLevel, Player player, bool useBlessedScroll, bool blessedScrollPreventsBreak) { SyncedData.ItemDesctructionTypeEnum value = SyncedData.ItemFailureType.Value; if (item == null || string.IsNullOrWhiteSpace(itemPrefabName)) { return new EnchantmentRulePreview(0.0, 0.0, 0.0, 0.0, 0.0, canBreak: false, blessPreventsBreak: false, value); } SyncedData.Chance_Data enchantmentChance = SyncedData.GetEnchantmentChance(itemPrefabName, currentLevel, item.IsWeapon()); double num = enchantmentChance.success; double num2 = EnchantmentSkillBonusService.GetAdditionalEnchantmentChance(player); double num3 = ((useBlessedScroll && !blessedScrollPreventsBreak) ? ((double)SyncedData.BlessedScrollsAdditionalChance.Value) : 0.0); double finalChance = NormalizePercentChance(num + num2 + num3); bool flag = useBlessedScroll && blessedScrollPreventsBreak && SyncedData.SafetyLevel.Value <= currentLevel; bool flag2 = SyncedData.SafetyLevel.Value <= currentLevel && !flag; double destroyChance = (flag2 ? NormalizePercentChance(ResolveDestroyChance(enchantmentChance, useBlessedScroll, value)) : 0.0); return new EnchantmentRulePreview(num, num2, num3, finalChance, destroyChance, flag2, flag, value); } public static EnchantmentDecision Decide(Enchantment_Core.Enchanted enchantment, Player player, bool useBlessedScroll, bool blessedScrollPreventsBreak) { int level = enchantment.level; EnchantmentRulePreview enchantmentRulePreview = BuildPreview(enchantment.Item, EnchantmentDomainHelper.ResolveItemPrefabName(enchantment.Item), level, player, useBlessedScroll, blessedScrollPreventsBreak); bool flag = RollPercent(enchantmentRulePreview.DestroyChance); if (RollPercent(enchantmentRulePreview.FinalChance)) { return new EnchantmentDecision(EnchantmentOutcome.Success, level + 1, Notifications_UI.NotificationItemResult.Success); } if (!enchantmentRulePreview.CanBreak) { return new EnchantmentDecision(EnchantmentOutcome.NoChange, level, Notifications_UI.NotificationItemResult.LevelDecrease); } return enchantmentRulePreview.FailureType switch { SyncedData.ItemDesctructionTypeEnum.Destroy => new EnchantmentDecision(EnchantmentOutcome.Destroyed, level, Notifications_UI.NotificationItemResult.Destroyed), SyncedData.ItemDesctructionTypeEnum.Combined => flag ? new EnchantmentDecision(EnchantmentOutcome.Destroyed, level, Notifications_UI.NotificationItemResult.Destroyed) : CreateLevelDecreaseDecision(level), SyncedData.ItemDesctructionTypeEnum.CombinedEasy => flag ? CreateLevelDecreaseDecision(level) : new EnchantmentDecision(EnchantmentOutcome.NoChange, level, Notifications_UI.NotificationItemResult.LevelDecrease), _ => CreateLevelDecreaseDecision(level), }; } private static EnchantmentDecision CreateLevelDecreaseDecision(int currentLevel) { int num = Mathf.Clamp(SyncedData.FailedEnchantLevelDecrease.Value, 1, 100); return new EnchantmentDecision(EnchantmentOutcome.LevelDecrease, Mathf.Max(0, currentLevel - num), Notifications_UI.NotificationItemResult.LevelDecrease); } private static double ResolveDestroyChance(SyncedData.Chance_Data chanceData, bool useBlessedScroll, SyncedData.ItemDesctructionTypeEnum failureType) { return failureType switch { SyncedData.ItemDesctructionTypeEnum.Destroy => 100.0, SyncedData.ItemDesctructionTypeEnum.Combined => Math.Min(100.0, Math.Max(0.0, chanceData.destroy - (float)(useBlessedScroll ? SyncedData.BlessedScrollsAdditionalChance.Value : 0))), SyncedData.ItemDesctructionTypeEnum.CombinedEasy => Math.Min(100.0, Math.Max(0.0, chanceData.destroy - (float)(useBlessedScroll ? SyncedData.BlessedScrollsAdditionalChance.Value : 0))), _ => 0.0, }; } private static double NormalizePercentChance(double chance) { return Math.Round(Math.Min(100.0, Math.Max(0.0, chance)), 2, MidpointRounding.AwayFromZero); } private static bool RollPercent(double chance) { double num = NormalizePercentChance(chance); if (num <= 0.0) { return false; } if (num >= 100.0) { return true; } return (double)Random.Range(0f, 100f) < num; } } public static class EnchantmentSideEffects { public static void ApplyAttemptResult(EnchantmentResult result) { //IL_006d: Unknown result type (might be due to invalid IL or missing references) if (result == null) { return; } Enchantment_VFX.UpdateGrid(); if (result.LevelChanged && !result.Destroyed) { IntegrationRegistry.ApplyEnchantState(result.Enchantment); if ((Object)(object)ValheimEnchantmentSystem._thistype != (Object)null && result.Enchantment?.Item != null) { ((MonoBehaviour)ValheimEnchantmentSystem._thistype).StartCoroutine(Enchantment_Core.FrameSkipEquip(result.Enchantment.Item)); } } if (result.SkillExpGranted > 0f) { Utils.IncreaseSkillEXP(Enchantment_Skill.SkillType_Enchantment, result.SkillExpGranted); } if (result.NotificationType.HasValue && SyncedData.EnchantmentEnableNotifications.Value && SyncedData.EnchantmentNotificationMinLevel.Value <= result.CurrentLevel) { string playerName = (((Object)(object)result.Player != (Object)null) ? result.Player.GetPlayerName() : "No Name"); Notifications_UI.AddNotification(playerName, result.ItemPrefabName, (int)result.NotificationType.Value, result.PreviousLevel, result.CurrentLevel); } } public static void HandleUpgrade(Enchantment_Core.Enchanted enchantment) { Enchantment_Core.Enchanted enchantment2 = enchantment; if ((Object)(object)ValheimEnchantmentSystem._thistype == (Object)null || enchantment2 == null) { return; } ((MonoBehaviour)(object)ValheimEnchantmentSystem._thistype).DelayedInvoke(delegate { if (SyncedData.DropEnchantmentOnUpgrade.Value) { enchantment2.Item?.Data().Remove(); Enchantment_VFX.UpdateGrid(); } else { IntegrationRegistry.ApplyEnchantUpgradedState(enchantment2); Enchantment_VFX.UpdateGrid(); } }, 1); } public static void ApplyStateChanged(Enchantment_Core.Enchanted enchantment, bool refreshEquipment) { if (enchantment != null) { IntegrationRegistry.ApplyEnchantState(enchantment); Enchantment_VFX.UpdateGrid(); if (refreshEquipment && (Object)(object)ValheimEnchantmentSystem._thistype != (Object)null && enchantment.Item != null) { ((MonoBehaviour)ValheimEnchantmentSystem._thistype).StartCoroutine(Enchantment_Core.FrameSkipEquip(enchantment.Item)); } } } } public static class EnchantmentSkillBonusService { public static float GetAdditionalEnchantmentChance(Player player = null) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) Player val = (Player)(Object.op_Implicit((Object)(object)player) ? ((object)player) : ((object)Player.m_localPlayer)); if (!Object.op_Implicit((Object)(object)val)) { return 0f; } float skillLevel = ((Character)val).GetSkillLevel(Enchantment_Skill.SkillType_Enchantment); return skillLevel * SyncedData.AdditionalEnchantmentChancePerLevel.Value; } } internal static class EngineEvents { [HarmonyPatch(typeof(Inventory), "Changed")] [ClientOnlyPatch] private static class Inventory_Changed_Patch { [UsedImplicitly] private static void Postfix(Inventory __instance) { EngineEvents.InventoryChanged?.Invoke(__instance); } } [HarmonyPatch] [ClientOnlyPatch] private static class Humanoid_EquipState_Patch { [CompilerGenerated] private sealed class d__0 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private MethodInfo <>2__current; private int <>l__initialThreadId; MethodInfo IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__0(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = AccessTools.Method(typeof(Humanoid), "EquipItem", (Type[])null, (Type[])null); <>1__state = 1; return true; case 1: <>1__state = -1; <>2__current = AccessTools.Method(typeof(Humanoid), "UnequipItem", (Type[])null, (Type[])null); <>1__state = 2; return true; case 2: <>1__state = -1; return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new d__0(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [IteratorStateMachine(typeof(d__0))] [UsedImplicitly] private static IEnumerable TargetMethods() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__0(-2); } [UsedImplicitly] private static void Postfix(Humanoid __instance) { Player val = (Player)(object)((__instance is Player) ? __instance : null); if (val != null) { EngineEvents.EquipmentChanged?.Invoke(val); } } } [HarmonyPatch(typeof(InventoryGui), "Show")] [ClientOnlyPatch] private static class InventoryGui_Show_Patch { [UsedImplicitly] private static void Postfix() { EngineEvents.InventoryGuiShown?.Invoke(); } } [HarmonyPatch(typeof(FejdStartup), "Awake")] [ClientOnlyPatch] private static class FejdStartup_Awake_Patch { [UsedImplicitly] private static void Postfix(FejdStartup __instance) { EngineEvents.MainMenuAwake?.Invoke(__instance); } } [HarmonyPatch(typeof(ZNetScene), "Awake")] [ClientOnlyPatch] private static class ZNetScene_Awake_Patch { [UsedImplicitly] private static void Postfix() { EngineEvents.WorldAwake?.Invoke(); } } public static event Action? InventoryChanged; public static event Action? EquipmentChanged; public static event Action? InventoryGuiShown; public static event Action? MainMenuAwake; public static event Action? WorldAwake; } internal static class EquipmentWorldVfx { [HarmonyPatch(typeof(Humanoid), "SetupVisEquipment")] [ClientOnlyPatch] [HarmonyPriority(-10000)] private static class Humanoid_SetupVisEquipment_Patch { [UsedImplicitly] [HarmonyPriority(-6000)] private static void Postfix(Humanoid __instance, VisEquipment visEq, bool isRagdoll) { Player val = (Player)(Object.op_Implicit((Object)(object)ZNetScene.instance) ? ((object)Player.m_localPlayer) : ((object)((__instance is Player) ? __instance : null))); if (!((Object)(object)__instance != (Object)(object)val || isRagdoll) && Object.op_Implicit((Object)(object)ZNetScene.instance) && Object.op_Implicit((Object)(object)((Character)val).m_nview) && ((Character)val).m_nview.IsValid() && ((Character)val).m_nview.IsOwner()) { Enchantment_VFX.InsertColor(((Character)val).m_nview.m_zdo, "VES_leftitemColor", Enchantment_VFX.GetItemEnchantmentColor(((Humanoid)val).m_leftItem, out var variant), variant); Enchantment_VFX.InsertColor(((Character)val).m_nview.m_zdo, "VES_rightitemColor", Enchantment_VFX.GetItemEnchantmentColor(((Humanoid)val).m_rightItem, out var variant2), variant2); Enchantment_VFX.InsertColor(((Character)val).m_nview.m_zdo, "VES_leftbackitemColor", Enchantment_VFX.GetItemEnchantmentColor(((Humanoid)val).m_hiddenLeftItem, out var variant3), variant3); Enchantment_VFX.InsertColor(((Character)val).m_nview.m_zdo, "VES_rightbackitemColor", Enchantment_VFX.GetItemEnchantmentColor(((Humanoid)val).m_hiddenRightItem, out var variant4), variant4); Enchantment_VFX.InsertColor(((Character)val).m_nview.m_zdo, "VES_chestitemColor", Enchantment_VFX.GetItemEnchantmentColor(((Humanoid)val).m_chestItem, out var variant5), variant5); Enchantment_VFX.InsertColor(((Character)val).m_nview.m_zdo, "VES_legsitemColor", Enchantment_VFX.GetItemEnchantmentColor(((Humanoid)val).m_legItem, out var variant6), variant6); Enchantment_VFX.InsertColor(((Character)val).m_nview.m_zdo, "VES_helmetitemColor", Enchantment_VFX.GetItemEnchantmentColor(((Humanoid)val).m_helmetItem, out var variant7), variant7); Enchantment_VFX.InsertColor(((Character)val).m_nview.m_zdo, "VES_shoulderitemColor", Enchantment_VFX.GetItemEnchantmentColor(((Humanoid)val).m_shoulderItem, out var variant8), variant8); } } } [HarmonyPatch(typeof(VisEquipment), "SetLeftHandEquipped")] [ClientOnlyPatch] private static class VisEquipment_SetLeftHandEquipped_Patch { private static readonly HashSet PendingInstances = new HashSet(); [UsedImplicitly] private static void Prefix(VisEquipment __instance, int hash) { if (__instance.m_currentLeftItemHash != hash) { PendingInstances.Add(((Object)__instance).GetInstanceID()); } } [UsedImplicitly] private static void Postfix(VisEquipment __instance) { if (PendingInstances.Remove(((Object)__instance).GetInstanceID()) && Object.op_Implicit((Object)(object)__instance.m_nview) && __instance.m_nview.m_zdo != null) { ScheduleVisEquipmentRefresh(__instance); } } } [HarmonyPatch(typeof(VisEquipment), "SetRightHandEquipped")] [ClientOnlyPatch] private static class VisEquipment_SetRightHandEquipped_Patch { private static readonly HashSet PendingInstances = new HashSet(); [UsedImplicitly] private static void Prefix(VisEquipment __instance, int hash) { if (__instance.m_currentRightItemHash != hash) { PendingInstances.Add(((Object)__instance).GetInstanceID()); } } [UsedImplicitly] private static void Postfix(VisEquipment __instance) { if (PendingInstances.Remove(((Object)__instance).GetInstanceID()) && Object.op_Implicit((Object)(object)__instance.m_nview) && __instance.m_nview.m_zdo != null) { ScheduleVisEquipmentRefresh(__instance); } } } [HarmonyPatch(typeof(VisEquipment), "SetBackEquipped")] [ClientOnlyPatch] private static class VisEquipment_SetBackEquipped_Patch { private static readonly HashSet PendingInstances = new HashSet(); [UsedImplicitly] private static void Prefix(VisEquipment __instance, int leftItem, int rightItem, int leftVariant) { if (__instance.m_currentLeftBackItemHash != leftItem || __instance.m_currentRightBackItemHash != rightItem) { PendingInstances.Add(((Object)__instance).GetInstanceID()); } } [UsedImplicitly] private static void Postfix(VisEquipment __instance) { if (PendingInstances.Remove(((Object)__instance).GetInstanceID()) && Object.op_Implicit((Object)(object)__instance.m_nview) && __instance.m_nview.m_zdo != null) { ScheduleVisEquipmentRefresh(__instance); } } } [HarmonyPatch(typeof(VisEquipment), "SetChestEquipped")] [ClientOnlyPatch] private static class VisEquipment_SetChestEquipped_Patch { private static readonly HashSet PendingInstances = new HashSet(); [UsedImplicitly] private static void Prefix(VisEquipment __instance, int hash) { if (__instance.m_currentChestItemHash != hash && Enchantment_VFX.IsArmorVfxEnabled()) { PendingInstances.Add(((Object)__instance).GetInstanceID()); } } [UsedImplicitly] private static void Postfix(VisEquipment __instance) { if (PendingInstances.Remove(((Object)__instance).GetInstanceID()) && Object.op_Implicit((Object)(object)__instance.m_nview) && __instance.m_nview.m_zdo != null) { ScheduleVisEquipmentRefresh(__instance); } } } [HarmonyPatch(typeof(VisEquipment), "SetLegEquipped")] [ClientOnlyPatch] private static class VisEquipment_SetLegEquipped_Patch { private static readonly HashSet PendingInstances = new HashSet(); [UsedImplicitly] private static void Prefix(VisEquipment __instance, int hash) { if (__instance.m_currentLegItemHash != hash && Enchantment_VFX.IsArmorVfxEnabled()) { PendingInstances.Add(((Object)__instance).GetInstanceID()); } } [UsedImplicitly] private static void Postfix(VisEquipment __instance) { if (PendingInstances.Remove(((Object)__instance).GetInstanceID()) && Object.op_Implicit((Object)(object)__instance.m_nview) && __instance.m_nview.m_zdo != null) { ScheduleVisEquipmentRefresh(__instance); } } } [HarmonyPatch(typeof(VisEquipment), "SetShoulderEquipped")] [ClientOnlyPatch] private static class VisEquipment_SetShoulderEquipped_Patch { private static readonly HashSet PendingInstances = new HashSet(); [UsedImplicitly] private static void Prefix(VisEquipment __instance, int hash) { if (__instance.m_currentShoulderItemHash != hash && Enchantment_VFX.IsArmorVfxEnabled()) { PendingInstances.Add(((Object)__instance).GetInstanceID()); } } [UsedImplicitly] private static void Postfix(VisEquipment __instance) { if (PendingInstances.Remove(((Object)__instance).GetInstanceID()) && Object.op_Implicit((Object)(object)__instance.m_nview) && __instance.m_nview.m_zdo != null) { ScheduleVisEquipmentRefresh(__instance); } } } [HarmonyPatch(typeof(VisEquipment), "SetHelmetEquipped")] [ClientOnlyPatch] private static class VisEquipment_SetHelmetEquipped_Patch { private static readonly HashSet PendingInstances = new HashSet(); [UsedImplicitly] private static void Prefix(VisEquipment __instance, int hash) { if (__instance.m_currentHelmetItemHash != hash && Enchantment_VFX.IsArmorVfxEnabled()) { PendingInstances.Add(((Object)__instance).GetInstanceID()); } } [UsedImplicitly] private static void Postfix(VisEquipment __instance) { if (PendingInstances.Remove(((Object)__instance).GetInstanceID()) && Object.op_Implicit((Object)(object)__instance.m_nview) && __instance.m_nview.m_zdo != null) { ScheduleVisEquipmentRefresh(__instance); } } } [HarmonyPatch(typeof(ItemDrop), "Start")] [ClientOnlyPatch] private static class ItemDrop_Start_Patch { [UsedImplicitly] private static void Postfix(ItemDrop __instance) { RefreshItemDropVisual(__instance); } } [HarmonyPatch(typeof(ItemStand), "SetVisualItem")] [ClientOnlyPatch] private static class ItemStand_SetVisualItem_Patch { [UsedImplicitly] private static void Prefix(ItemStand __instance, out bool __state, string itemName, int variant) { __state = __instance.m_visualName != itemName || __instance.m_visualVariant != variant; } [UsedImplicitly] private static void Postfix(ItemStand __instance, bool __state) { if (__state) { RefreshItemStandVisual(__instance); } } } private static readonly HashSet ScheduledVisEquipmentRefreshes = new HashSet(); private static void RefreshEquipmentInstance(GameObject itemInstance, ZDO zdo, string colorKey, bool isArmor) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)itemInstance)) { string text = ((zdo != null) ? zdo.GetString(colorKey, "") : null) ?? string.Empty; int variant = ((zdo != null) ? zdo.GetInt(colorKey + "_variant", 0) : 0); if (!Enchantment_VFX.IsEffectEnabledForClass(isArmor) || string.IsNullOrEmpty(text)) { Enchantment_VFX.DisableMeshEffect(itemInstance, isArmor); } else { Enchantment_VFX.AttachMeshEffect(itemInstance, text.ToColorAlpha(), variant, isArmor); } } } private static void RefreshEquipmentInstances(IEnumerable itemInstances, ZDO zdo, string colorKey, bool isArmor) { if (itemInstances == null) { return; } foreach (GameObject itemInstance in itemInstances) { RefreshEquipmentInstance(itemInstance, zdo, colorKey, isArmor); } } private static void ScheduleVisEquipmentRefresh(VisEquipment visEquipment) { VisEquipment visEquipment2 = visEquipment; if (!Object.op_Implicit((Object)(object)visEquipment2)) { return; } if ((Object)(object)ValheimEnchantmentSystem._thistype == (Object)null) { RefreshVisEquipment(visEquipment2); return; } int instanceId = ((Object)visEquipment2).GetInstanceID(); if (!ScheduledVisEquipmentRefreshes.Add(instanceId)) { return; } ((MonoBehaviour)(object)ValheimEnchantmentSystem._thistype).DelayedInvoke(delegate { ScheduledVisEquipmentRefreshes.Remove(instanceId); if (Object.op_Implicit((Object)(object)visEquipment2)) { RefreshVisEquipment(visEquipment2); } }, 1); } internal static void RefreshVisEquipment(VisEquipment visEquipment) { if (Object.op_Implicit((Object)(object)visEquipment)) { ZDO zdo = visEquipment.m_nview?.m_zdo; RefreshEquipmentInstance(visEquipment.m_leftItemInstance, zdo, "VES_leftitemColor", isArmor: false); RefreshEquipmentInstance(visEquipment.m_rightItemInstance, zdo, "VES_rightitemColor", isArmor: false); RefreshEquipmentInstance(visEquipment.m_leftBackItemInstance, zdo, "VES_leftbackitemColor", isArmor: false); RefreshEquipmentInstance(visEquipment.m_rightBackItemInstance, zdo, "VES_rightbackitemColor", isArmor: false); RefreshEquipmentInstances(visEquipment.m_chestItemInstances, zdo, "VES_chestitemColor", isArmor: true); RefreshEquipmentInstances(visEquipment.m_legItemInstances, zdo, "VES_legsitemColor", isArmor: true); RefreshEquipmentInstances(visEquipment.m_shoulderItemInstances, zdo, "VES_shoulderitemColor", isArmor: true); RefreshEquipmentInstance(visEquipment.m_helmetItemInstance, zdo, "VES_helmetitemColor", isArmor: true); } } public static void RefreshItemDropVisual(ItemDrop itemDrop) { //IL_009a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)itemDrop == (Object)null) { return; } Enchantment_Core.Enchanted enchanted = itemDrop.m_itemData?.Data()?.Get(); if (enchanted == null || enchanted.level <= 0) { Enchantment_VFX.DisableMeshEffect(((Component)itemDrop).gameObject, Enchantment_VFX.IsArmorVisual(itemDrop.m_itemData)); return; } bool isArmor = Enchantment_VFX.IsArmorVisual(itemDrop.m_itemData); if (!Enchantment_VFX.IsEffectEnabledForClass(isArmor)) { Enchantment_VFX.DisableMeshEffect(((Component)itemDrop).gameObject, isArmor); return; } string prefabName = Utils.GetPrefabName(((Component)itemDrop).gameObject); int variant; string color = SyncedData.GetColor(prefabName, enchanted.level, out variant, trimApha: false); Enchantment_VFX.AttachMeshEffect(((Component)itemDrop).gameObject, color.ToColorAlpha(), variant, isArmor); } public static void RefreshItemStandVisual(ItemStand itemStand) { //IL_018a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)itemStand == (Object)null) { return; } if ((Object)(object)itemStand.m_nview == (Object)null || !itemStand.m_nview.IsValid() || !Object.op_Implicit((Object)(object)itemStand.m_visualItem)) { if (Object.op_Implicit((Object)(object)itemStand.m_visualItem)) { Enchantment_VFX.DisableMeshEffect(itemStand.m_visualItem); } return; } ZDO zDO = itemStand.m_nview.GetZDO(); if (zDO == null) { Enchantment_VFX.DisableMeshEffect(itemStand.m_visualItem); return; } string @string = zDO.GetString(ZDOVars.s_item, ""); if (string.IsNullOrEmpty(@string)) { Enchantment_VFX.DisableMeshEffect(itemStand.m_visualItem); return; } GameObject val = (Object.op_Implicit((Object)(object)ObjectDB.instance) ? ObjectDB.instance.GetItemPrefab(@string) : null); if (!Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)ZNetScene.instance)) { val = ZNetScene.instance.GetPrefab(@string); } if (!Object.op_Implicit((Object)(object)val)) { Enchantment_VFX.DisableMeshEffect(itemStand.m_visualItem); return; } ItemDrop component = val.GetComponent(); if ((Object)(object)component == (Object)null) { Enchantment_VFX.DisableMeshEffect(itemStand.m_visualItem); return; } ItemData val2 = component.m_itemData.Clone(); ItemDrop.LoadFromZDO(val2, zDO); Enchantment_Core.Enchanted enchanted = val2.Data()?.Get(); if (enchanted == null || enchanted.level <= 0) { Enchantment_VFX.DisableMeshEffect(itemStand.m_visualItem, Enchantment_VFX.IsArmorVisual(val2)); return; } bool isArmor = Enchantment_VFX.IsArmorVisual(val2); if (!Enchantment_VFX.IsEffectEnabledForClass(isArmor)) { Enchantment_VFX.DisableMeshEffect(itemStand.m_visualItem, isArmor); return; } int variant; string color = SyncedData.GetColor(@string, enchanted.level, out variant, trimApha: false); Enchantment_VFX.AttachMeshEffect(itemStand.m_visualItem, color.ToColorAlpha(), variant, isArmor); } public static void RefreshEquipmentVisuals() { if (ValheimEnchantmentSystem.NoGraphics) { return; } foreach (VisEquipment item in VfxInstanceRegistry.EnumerateVisEquipments()) { if (!((Object)(object)((Component)item).GetComponentInParent() != (Object)null)) { RefreshVisEquipment(item); } } } public static void RefreshWorldItemVisuals() { if (ValheimEnchantmentSystem.NoGraphics) { return; } foreach (ItemDrop item in VfxInstanceRegistry.EnumerateItemDrops()) { RefreshItemDropVisual(item); } foreach (ItemStand item2 in VfxInstanceRegistry.EnumerateItemStands()) { RefreshItemStandVisual(item2); } } } [VES_Autoload(VES_Autoload.Priority.Normal, "OnInit", new Type[] { typeof(SyncedData) })] internal static class EquippedEnchantmentSnapshotService { internal sealed class Snapshot { public int MaxHealthBonus; public int MaxStaminaBonus; public float MovementModifier; public float HealthRegen; public float StaminaRegen; public readonly List ResistancePairs = new List(); public void Reset() { MaxHealthBonus = 0; MaxStaminaBonus = 0; MovementModifier = 0f; HealthRegen = 0f; StaminaRegen = 0f; ResistancePairs.Clear(); } } private sealed class CacheEntry { public readonly WeakReference PlayerRef; public readonly Snapshot Snapshot = new Snapshot(); public Inventory? Inventory; public bool Dirty = true; public int Revision = -1; public CacheEntry(Player player) { PlayerRef = new WeakReference(player); Inventory = ((Humanoid)player).m_inventory; } } private sealed class ReferenceComparer : IEqualityComparer where T : class { public static readonly ReferenceComparer Instance = new ReferenceComparer(); public bool Equals(T? x, T? y) { return x == y; } public int GetHashCode(T obj) { return RuntimeHelpers.GetHashCode(obj); } } [HarmonyPatch(typeof(Player), "OnDestroy")] [ClientOnlyPatch] private static class Player_OnDestroy_Patch { [UsedImplicitly] private static void Prefix(Player __instance) { Unregister(__instance); } } private static readonly Snapshot EmptySnapshot = new Snapshot(); private static readonly Dictionary EntriesByPlayerId = new Dictionary(); private static readonly Dictionary> PlayerIdsByInventory = new Dictionary>(ReferenceComparer.Instance); private static int _globalRevision; private static bool _initialized; private static void OnInit() { if (!_initialized) { _initialized = true; SyncedData.Synced_EnchantmentStats_Weapons.ValueChanged += InvalidateAll; SyncedData.Synced_EnchantmentStats_Armor.ValueChanged += InvalidateAll; SyncedData.Overrides_EnchantmentStats.ValueChanged += InvalidateAll; EngineEvents.InventoryChanged += MarkDirty; EngineEvents.EquipmentChanged += MarkDirty; EngineEvents.MainMenuAwake += OnMainMenuAwake; } } internal static Snapshot GetSnapshot(Player? player) { if ((Object)(object)player == (Object)null || !Object.op_Implicit((Object)(object)player) || ((Humanoid)player).m_inventory == null) { return EmptySnapshot; } CacheEntry orCreateEntry = GetOrCreateEntry(player); if (orCreateEntry.Dirty || orCreateEntry.Revision != _globalRevision) { RebuildSnapshot(player, orCreateEntry); } return orCreateEntry.Snapshot; } internal static void MarkDirty(Player? player) { if (!((Object)(object)player == (Object)null)) { CacheEntry orCreateEntry = GetOrCreateEntry(player); orCreateEntry.Dirty = true; } } internal static void MarkDirty(Inventory? inventory) { if (inventory == null || !PlayerIdsByInventory.TryGetValue(inventory, out HashSet value)) { return; } int[] array = value.ToArray(); foreach (int num in array) { Player player; if (!EntriesByPlayerId.TryGetValue(num, out CacheEntry value2)) { value.Remove(num); } else if (!TryGetAlivePlayer(value2, out player)) { RemoveEntry(num, value2); value.Remove(num); } else { value2.Dirty = true; } } if (value.Count == 0) { PlayerIdsByInventory.Remove(inventory); } } internal static void InvalidateAll() { _globalRevision++; PruneDeadEntries(); } internal static void Unregister(Player? player) { if (!((Object)(object)player == (Object)null)) { int instanceID = ((Object)player).GetInstanceID(); if (EntriesByPlayerId.TryGetValue(instanceID, out CacheEntry value)) { RemoveEntry(instanceID, value); } } } private static CacheEntry GetOrCreateEntry(Player player) { int instanceID = ((Object)player).GetInstanceID(); if (!EntriesByPlayerId.TryGetValue(instanceID, out CacheEntry value)) { value = new CacheEntry(player); EntriesByPlayerId[instanceID] = value; BindInventory(instanceID, ((Humanoid)player).m_inventory); return value; } Inventory inventory = ((Humanoid)player).m_inventory; if (value.Inventory != inventory) { UnbindInventory(instanceID, value.Inventory); value.Inventory = inventory; BindInventory(instanceID, inventory); value.Dirty = true; } return value; } private static void RebuildSnapshot(Player player, CacheEntry entry) { //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0107: 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_0111: Unknown result type (might be due to invalid IL or missing references) Snapshot snapshot = entry.Snapshot; snapshot.Reset(); foreach (ItemData equippedItem in ((Humanoid)player).m_inventory.GetEquippedItems()) { Enchantment_Core.Enchanted enchanted = equippedItem?.Data().Get(); if (enchanted == null || enchanted.level <= 0) { continue; } SyncedData.Stat_Data stats = enchanted.Stats; if (stats == null) { continue; } snapshot.MaxHealthBonus += stats.max_hp; snapshot.MaxStaminaBonus += stats.max_stamina; snapshot.MovementModifier += (float)stats.movement_speed / 100f; snapshot.HealthRegen += stats.hp_regen; snapshot.StaminaRegen += stats.stamina_regen; foreach (DamageModPair resistancePair in stats.GetResistancePairs()) { snapshot.ResistancePairs.Add(new DamageModPair { m_type = resistancePair.m_type, m_modifier = resistancePair.m_modifier }); } } entry.Dirty = false; entry.Revision = _globalRevision; } private static void BindInventory(int playerId, Inventory? inventory) { if (inventory != null) { if (!PlayerIdsByInventory.TryGetValue(inventory, out HashSet value)) { value = new HashSet(); PlayerIdsByInventory[inventory] = value; } value.Add(playerId); } } private static void UnbindInventory(int playerId, Inventory? inventory) { if (inventory != null && PlayerIdsByInventory.TryGetValue(inventory, out HashSet value)) { value.Remove(playerId); if (value.Count == 0) { PlayerIdsByInventory.Remove(inventory); } } } private static bool TryGetAlivePlayer(CacheEntry entry, out Player? player) { if (!entry.PlayerRef.TryGetTarget(out player) || !Object.op_Implicit((Object)(object)player)) { player = null; return false; } return true; } private static void PruneDeadEntries() { KeyValuePair[] array = EntriesByPlayerId.ToArray(); for (int i = 0; i < array.Length; i++) { KeyValuePair keyValuePair = array[i]; if (!TryGetAlivePlayer(keyValuePair.Value, out Player _)) { RemoveEntry(keyValuePair.Key, keyValuePair.Value); } } } private static void RemoveEntry(int playerId, CacheEntry entry) { UnbindInventory(playerId, entry.Inventory); EntriesByPlayerId.Remove(playerId); } private static void ClearAll() { EntriesByPlayerId.Clear(); PlayerIdsByInventory.Clear(); } private static void OnMainMenuAwake(FejdStartup _) { ClearAll(); } } [VES_Autoload(VES_Autoload.Priority.Normal, "OnInit", new Type[] { })] internal static class VfxInstanceRegistry { [HarmonyPatch(typeof(VisEquipment), "Awake")] [ClientOnlyPatch] private static class VisEquipment_Awake_Patch { [UsedImplicitly] private static void Postfix(VisEquipment __instance) { Register(__instance); } } [HarmonyPatch(typeof(ItemStand), "Awake")] [ClientOnlyPatch] private static class ItemStand_Awake_Patch { [UsedImplicitly] private static void Postfix(ItemStand __instance) { Register(__instance); } } [HarmonyPatch(typeof(ItemDrop), "Start")] [ClientOnlyPatch] private static class ItemDrop_Start_Patch { [UsedImplicitly] private static void Postfix(ItemDrop __instance) { Register(__instance); } } [HarmonyPatch(typeof(ArmorStand), "Awake")] [ClientOnlyPatch] private static class ArmorStand_Awake_Patch { [UsedImplicitly] private static void Postfix(ArmorStand __instance) { Register(__instance); } } [HarmonyPatch] [ClientOnlyPatch] private static class VisEquipment_Unregister_Patch { private static readonly MethodBase? LifecycleMethod = FindUnregisterLifecycleMethod(typeof(VisEquipment)); [UsedImplicitly] private static MethodBase? TargetMethod() { return LifecycleMethod; } [UsedImplicitly] private static bool Prepare() { return LifecycleMethod != null; } [UsedImplicitly] private static void Prefix(VisEquipment __instance) { Unregister(__instance); } } [HarmonyPatch] [ClientOnlyPatch] private static class ItemDrop_Unregister_Patch { private static readonly MethodBase? LifecycleMethod = FindUnregisterLifecycleMethod(typeof(ItemDrop)); [UsedImplicitly] private static MethodBase? TargetMethod() { return LifecycleMethod; } [UsedImplicitly] private static bool Prepare() { return LifecycleMethod != null; } [UsedImplicitly] private static void Prefix(ItemDrop __instance) { Unregister(__instance); } } [HarmonyPatch] [ClientOnlyPatch] private static class ItemStand_Unregister_Patch { private static readonly MethodBase? LifecycleMethod = FindUnregisterLifecycleMethod(typeof(ItemStand)); [UsedImplicitly] private static MethodBase? TargetMethod() { return LifecycleMethod; } [UsedImplicitly] private static bool Prepare() { return LifecycleMethod != null; } [UsedImplicitly] private static void Prefix(ItemStand __instance) { Unregister(__instance); } } [HarmonyPatch] [ClientOnlyPatch] private static class ArmorStand_Unregister_Patch { private static readonly MethodBase? LifecycleMethod = FindUnregisterLifecycleMethod(typeof(ArmorStand)); [UsedImplicitly] private static MethodBase? TargetMethod() { return LifecycleMethod; } [UsedImplicitly] private static bool Prepare() { return LifecycleMethod != null; } [UsedImplicitly] private static void Prefix(ArmorStand __instance) { Unregister(__instance); } } [CompilerGenerated] private sealed class d__21 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator where T : notnull, Component { private int <>1__state; private T <>2__current; private int <>l__initialThreadId; private Dictionary instances; public Dictionary <>3__instances; private KeyValuePair[] <>7__wrap1; private int <>7__wrap2; T IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__21(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>7__wrap1 = null; <>1__state = -2; } private bool MoveNext() { int num = <>1__state; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; goto IL_0099; } <>1__state = -1; <>7__wrap1 = instances.ToArray(); <>7__wrap2 = 0; goto IL_00a7; IL_0099: <>7__wrap2++; goto IL_00a7; IL_00a7: if (<>7__wrap2 < <>7__wrap1.Length) { KeyValuePair keyValuePair = <>7__wrap1[<>7__wrap2]; T value = keyValuePair.Value; if (!Object.op_Implicit((Object)(object)value)) { instances.Remove(keyValuePair.Key); } else if (((Component)value).gameObject.activeInHierarchy) { <>2__current = value; <>1__state = 1; return true; } goto IL_0099; } <>7__wrap1 = null; return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__21 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__21(0); } d__.instances = <>3__instances; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } private static readonly Dictionary VisEquipments = new Dictionary(); private static readonly Dictionary ItemDrops = new Dictionary(); private static readonly Dictionary ItemStands = new Dictionary(); private static readonly Dictionary ArmorStands = new Dictionary(); private static bool _initialized; private static void OnInit() { if (!_initialized) { _initialized = true; EngineEvents.MainMenuAwake += OnMainMenuAwake; EngineEvents.WorldAwake += ClearAll; } } public static void Register(VisEquipment? visEquipment) { RegisterInstance(VisEquipments, visEquipment); } public static void Register(ItemDrop? itemDrop) { RegisterInstance(ItemDrops, itemDrop); } public static void Register(ItemStand? itemStand) { RegisterInstance(ItemStands, itemStand); } public static void Register(ArmorStand? armorStand) { RegisterInstance(ArmorStands, armorStand); } public static void Unregister(VisEquipment? visEquipment) { UnregisterInstance(VisEquipments, visEquipment); } public static void Unregister(ItemDrop? itemDrop) { UnregisterInstance(ItemDrops, itemDrop); } public static void Unregister(ItemStand? itemStand) { UnregisterInstance(ItemStands, itemStand); } public static void Unregister(ArmorStand? armorStand) { UnregisterInstance(ArmorStands, armorStand); } public static IEnumerable EnumerateVisEquipments() { return EnumerateLiveInstances(VisEquipments); } public static IEnumerable EnumerateItemDrops() { return EnumerateLiveInstances(ItemDrops); } public static IEnumerable EnumerateItemStands() { return EnumerateLiveInstances(ItemStands); } public static IEnumerable EnumerateArmorStands() { return EnumerateLiveInstances(ArmorStands); } public static void ClearAll() { VisEquipments.Clear(); ItemDrops.Clear(); ItemStands.Clear(); ArmorStands.Clear(); } private static void RegisterInstance(Dictionary instances, T? instance) where T : Component { if (Object.op_Implicit((Object)(object)instance)) { instances[((Object)(object)instance).GetInstanceID()] = instance; } } private static void UnregisterInstance(Dictionary instances, T? instance) where T : Component { if (Object.op_Implicit((Object)(object)instance)) { instances.Remove(((Object)(object)instance).GetInstanceID()); } } [IteratorStateMachine(typeof(d__21<>))] private static IEnumerable EnumerateLiveInstances(Dictionary instances) where T : Component { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__21(-2) { <>3__instances = instances }; } private static void OnMainMenuAwake(FejdStartup _) { ClearAll(); } private static MethodInfo? FindDeclaredLifecycleMethod(Type componentType, string methodName) { return componentType.GetMethod(methodName, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); } private static MethodBase? FindUnregisterLifecycleMethod(Type componentType) { return FindDeclaredLifecycleMethod(componentType, "OnDestroy") ?? FindDeclaredLifecycleMethod(componentType, "OnDisable"); } } internal static class PatchRegistry { private sealed class PatchDescriptor { public readonly string Name; public readonly Type RootType; public readonly IReadOnlyList PatchTypes; public readonly string[] RequiredPlugins; public PatchDescriptor(Type rootType, IReadOnlyList patchTypes, string[] requiredPlugins) { RootType = rootType; PatchTypes = patchTypes; RequiredPlugins = requiredPlugins ?? Array.Empty(); Name = rootType.FullName ?? rootType.Name; } } [CompilerGenerated] private sealed class d__2 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private PatchDescriptor <>2__current; private int <>l__initialThreadId; private IEnumerator <>7__wrap1; PatchDescriptor IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__2(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <>7__wrap1 = null; <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: { <>1__state = -1; IEnumerable enumerable = ValheimEnchantmentSystem.GetAssemblyTypes().Select(ValheimEnchantmentSystem.GetTopLevelDeclaringType).Distinct() .OrderBy((Type rootType) => rootType.FullName, StringComparer.Ordinal); <>7__wrap1 = enumerable.GetEnumerator(); <>1__state = -3; break; } case 1: <>1__state = -3; break; } while (<>7__wrap1.MoveNext()) { Type current = <>7__wrap1.Current; List list = (from type in EnumerateTypeTree(current) where type.GetCustomAttributes(typeof(HarmonyPatch), inherit: false).Length != 0 select type).OrderBy((Type type) => type.FullName, StringComparer.Ordinal).ToList(); if (list.Count != 0) { string[] requiredPlugins = (from VES_RequiresPlugin attribute in current.GetCustomAttributes(typeof(VES_RequiresPlugin), inherit: false) select attribute.PluginGuid into pluginGuid where !string.IsNullOrWhiteSpace(pluginGuid) select pluginGuid).Distinct(StringComparer.Ordinal).ToArray(); <>2__current = new PatchDescriptor(current, list, requiredPlugins); <>1__state = 1; return true; } } <>m__Finally1(); <>7__wrap1 = null; return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<>7__wrap1 != null) { <>7__wrap1.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new d__2(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__3 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private Type <>2__current; private int <>l__initialThreadId; private Type type; public Type <>3__type; private Type[] <>7__wrap1; private int <>7__wrap2; private IEnumerator <>7__wrap3; Type IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__3(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 2) { try { } finally { <>m__Finally1(); } } <>7__wrap1 = null; <>7__wrap3 = null; <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = this.type; <>1__state = 1; return true; case 1: <>1__state = -1; <>7__wrap1 = this.type.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic); <>7__wrap2 = 0; goto IL_00db; case 2: { <>1__state = -3; goto IL_00b3; } IL_00db: if (<>7__wrap2 < <>7__wrap1.Length) { Type type = <>7__wrap1[<>7__wrap2]; <>7__wrap3 = EnumerateTypeTree(type).GetEnumerator(); <>1__state = -3; goto IL_00b3; } <>7__wrap1 = null; return false; IL_00b3: if (<>7__wrap3.MoveNext()) { Type current = <>7__wrap3.Current; <>2__current = current; <>1__state = 2; return true; } <>m__Finally1(); <>7__wrap3 = null; <>7__wrap2++; goto IL_00db; } } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<>7__wrap3 != null) { <>7__wrap3.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__3 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__3(0); } d__.type = <>3__type; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } public static void Apply(Harmony harmony, ManualLogSource logger, bool isServerRuntime, ISet failedAutoloadTypes) { HashSet hashSet = new HashSet(); int num = 0; int num2 = 0; int num3 = 0; foreach (PatchDescriptor item in DiscoverPatchDescriptors()) { if (ValheimEnchantmentSystem.IsTypeBlockedByAutoloadFailure(item.RootType, failedAutoloadTypes)) { num2 += item.PatchTypes.Count; continue; } string[] array = item.RequiredPlugins.Where((string pluginGuid) => !Chainloader.PluginInfos.ContainsKey(pluginGuid)).ToArray(); if (array.Length != 0) { num2 += item.PatchTypes.Count; logger.LogDebug((object)("Skipped Harmony patch root '" + item.Name + "': missing plugin(s) " + string.Join(", ", array))); continue; } foreach (Type patchType in item.PatchTypes) { if (!hashSet.Add(patchType)) { continue; } if (isServerRuntime && patchType.GetCustomAttribute() != null) { num2++; continue; } if (!isServerRuntime && patchType.GetCustomAttribute() != null) { num2++; continue; } try { harmony.CreateClassProcessor(patchType).Patch(); num++; } catch (Exception ex) { num3++; logger.LogWarning((object)("Skipped Harmony patch '" + patchType.FullName + "' in root '" + item.Name + "': " + ex.Message)); logger.LogDebug((object)ex); } } } logger.LogInfo((object)$"Harmony patch discovery applied. patched={num}, skipped={num2}, failed={num3}"); } [IteratorStateMachine(typeof(d__2))] private static IEnumerable DiscoverPatchDescriptors() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__2(-2); } [IteratorStateMachine(typeof(d__3))] private static IEnumerable EnumerateTypeTree(Type type) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__3(-2) { <>3__type = type }; } } [VES_Autoload(VES_Autoload.Priority.Normal, "OnInit", new Type[] { typeof(SyncedData) })] internal static class InventoryOverlayVfx { private class ConfigurationManagerAttributes { [UsedImplicitly] public int? Order; } [HarmonyPatch(typeof(InventoryGrid), "Awake")] [ClientOnlyPatch] private static class InventoryGrid_Awake_Patch { [UsedImplicitly] private static void Postfix(InventoryGrid __instance) { EnsureOverlayTemplate(__instance.m_elementPrefab); BindScrollVisibilityUpdates(__instance); } } [HarmonyPatch(typeof(Hud), "Awake")] [ClientOnlyPatch] private static class Hud_Awake_Patch { internal static HotkeyBar? BarRef; [UsedImplicitly] private static void Postfix(Hud __instance) { Transform obj = __instance.m_rootObject.transform.Find("HotKeyBar"); BarRef = ((obj != null) ? ((Component)obj).GetComponent() : null); if (!((Object)(object)BarRef == (Object)null)) { EnsureOverlayTemplate(BarRef.m_elementPrefab); } } } [HarmonyPatch(typeof(HotkeyBar), "UpdateIcons")] [ClientOnlyPatch] private static class HotkeyBar_UpdateIcons_Patch { internal static int _needUpdateFrame = -1; [UsedImplicitly] private static void Postfix(HotkeyBar __instance) { //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance != (Object)(object)Hud_Awake_Patch.BarRef || !Object.op_Implicit((Object)(object)Player.m_localPlayer) || ((Character)Player.m_localPlayer).IsDead() || _needUpdateFrame != Time.frameCount) { return; } foreach (ElementData item in __instance.m_elements.Where((ElementData element) => !element.m_used)) { ((Component)item.m_go.transform.Find("VES_Level")).gameObject.SetActive(false); } foreach (ItemData item2 in __instance.m_items) { ElementData val = __instance.m_elements[item2.m_gridPos.x]; Transform val2 = val.m_go.transform.Find("VES_Level"); Enchantment_Core.Enchanted enchanted = item2.Data().Get(); if ((bool)enchanted && enchanted.level > 0) { ((Component)val2).gameObject.SetActive(true); int variant; Color color = SyncedData.GetColor(enchanted, out variant, trimApha: true).ToColorAlpha().IncreaseColorLight(); ((Component)((Component)val2).transform.GetChild(0)).GetComponent().text = "+" + enchanted.level; ((Graphic)((Component)((Component)val2).transform.GetChild(0)).GetComponent()).color = color; ((Graphic)((Component)((Component)val2).transform.GetChild(1)).GetComponent()).color = color; ((Component)((Component)val2).transform.GetChild(1)).gameObject.SetActive(IsInventoryVisualEnabled()); } else { ((Component)val2).gameObject.SetActive(false); } } } } [HarmonyPatch(typeof(InventoryGrid), "UpdateGui")] [ClientOnlyPatch] private static class InventoryGrid_UpdateGui_Patch { internal static int _needUpdateFrame = -1; [UsedImplicitly] private static void Postfix(InventoryGrid __instance) { if (_needUpdateFrame == Time.frameCount) { ApplyInventoryGridVisuals(__instance, updateContent: true); } } } private const int EnableInventoryVisualOrder = 104; private static readonly HashSet InitializedElementPrefabs = new HashSet(); private static readonly HashSet BoundScrollGrids = new HashSet(); private static GameObject? _hotbarPartPrefab; private static ConfigEntry? _enableInventoryVisual; private static bool _menuFontConfigured; private static ConfigDescription OrderedDescription(string description, int order) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown return new ConfigDescription(description, (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = order } }); } [UsedImplicitly] private static void OnInit() { if (!ValheimEnchantmentSystem.NoGraphics) { _hotbarPartPrefab = ValheimEnchantmentSystem._asset.LoadAsset("Enchantment_HotbarPart"); _enableInventoryVisual = ValheimEnchantmentSystem.ClientConfig("", "EnableInventoryVisual", value: true, OrderedDescription("Enable inventory and hotbar enchant visuals.", 104)); _enableInventoryVisual.SettingChanged += delegate { UpdateGrid(); }; EngineEvents.InventoryChanged += OnInventoryChanged; EngineEvents.EquipmentChanged += OnEquipmentChanged; EngineEvents.InventoryGuiShown += UpdateGrid; EngineEvents.MainMenuAwake += OnMainMenuAwake; } } private static bool IsInventoryVisualEnabled() { return _enableInventoryVisual?.Value ?? true; } private static RectTransform? GetInventoryViewport(InventoryGrid grid) { if (!Object.op_Implicit((Object)(object)grid)) { return null; } ScrollRect componentInParent = ((Component)grid).GetComponentInParent(); if (!Object.op_Implicit((Object)(object)componentInParent)) { return null; } if (!Object.op_Implicit((Object)(object)componentInParent.viewport)) { return ((Component)componentInParent).GetComponent(); } return componentInParent.viewport; } private static bool IsGridElementVisible(Element element, RectTransform? viewport) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)viewport == (Object)null || (Object)(object)element.m_go == (Object)null) { return true; } RectTransform component = element.m_go.GetComponent(); if (!Object.op_Implicit((Object)(object)component) || !element.m_go.activeInHierarchy) { return false; } Bounds val = RectTransformUtility.CalculateRelativeRectTransformBounds((Transform)(object)viewport, (Transform)(object)component); Rect rect = viewport.rect; if (((Bounds)(ref val)).max.x > ((Rect)(ref rect)).xMin && ((Bounds)(ref val)).min.x < ((Rect)(ref rect)).xMax && ((Bounds)(ref val)).max.y > ((Rect)(ref rect)).yMin) { return ((Bounds)(ref val)).min.y < ((Rect)(ref rect)).yMax; } return false; } private static void EnsureOverlayTemplate(GameObject? elementPrefab) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)elementPrefab == (Object)null) && !((Object)(object)_hotbarPartPrefab == (Object)null) && !InitializedElementPrefabs.Contains(elementPrefab)) { InitializedElementPrefabs.Add(elementPrefab); Transform transform = elementPrefab.transform; GameObject val = Object.Instantiate(_hotbarPartPrefab); val.transform.SetParent(transform, false); ((Object)val).name = "VES_Level"; val.GetComponent().anchoredPosition = Vector2.zero; val.SetActive(false); } } private static void BindScrollVisibilityUpdates(InventoryGrid grid) { InventoryGrid grid2 = grid; if (!Object.op_Implicit((Object)(object)grid2)) { return; } int instanceID = ((Object)grid2).GetInstanceID(); if (!BoundScrollGrids.Add(instanceID)) { return; } ScrollRect componentInParent = ((Component)grid2).GetComponentInParent(); if (Object.op_Implicit((Object)(object)componentInParent)) { ((UnityEvent)(object)componentInParent.onValueChanged).AddListener((UnityAction)delegate { ApplyInventoryGridVisuals(grid2, updateContent: false); }); } } private static void ApplyInventoryGridVisuals(InventoryGrid grid, bool updateContent) { //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)grid) || grid.m_inventory == null || grid.m_elements == null) { return; } RectTransform inventoryViewport = GetInventoryViewport(grid); int width = grid.m_inventory.GetWidth(); foreach (Element element2 in grid.m_elements) { if (!((Object)(object)element2?.m_go == (Object)null)) { Transform val = element2.m_go.transform.Find("VES_Level"); if (!((Object)(object)val == (Object)null) && (!element2.m_used || !IsGridElementVisible(element2, inventoryViewport))) { ((Component)val).gameObject.SetActive(false); } } } foreach (ItemData allItem in grid.m_inventory.GetAllItems()) { Element element = grid.GetElement(allItem.m_gridPos.x, allItem.m_gridPos.y, width); if ((Object)(object)element?.m_go == (Object)null) { continue; } Transform val2 = element.m_go.transform.Find("VES_Level"); if ((Object)(object)val2 == (Object)null) { continue; } Enchantment_Core.Enchanted enchanted = allItem.Data().Get(); bool flag = IsGridElementVisible(element, inventoryViewport); if (!enchanted || enchanted.level <= 0 || !flag) { ((Component)val2).gameObject.SetActive(false); continue; } ((Component)val2).gameObject.SetActive(true); if (updateContent) { int variant; Color color = SyncedData.GetColor(enchanted, out variant, trimApha: true).ToColorAlpha().IncreaseColorLight(); ((Component)((Component)val2).transform.GetChild(0)).GetComponent().text = "+" + enchanted.level; ((Graphic)((Component)((Component)val2).transform.GetChild(0)).GetComponent()).color = color; ((Graphic)((Component)((Component)val2).transform.GetChild(1)).GetComponent()).color = color; } ((Component)((Component)val2).transform.GetChild(1)).gameObject.SetActive(IsInventoryVisualEnabled()); } } public static void UpdateGrid() { if (!ValheimEnchantmentSystem.NoGraphics) { HotkeyBar_UpdateIcons_Patch._needUpdateFrame = Time.frameCount + 1; InventoryGrid_UpdateGui_Patch._needUpdateFrame = Time.frameCount + 1; } } private static void OnInventoryChanged(Inventory inventory) { if (inventory == ((Humanoid)(Player.m_localPlayer?)).m_inventory) { UpdateGrid(); } } private static void OnEquipmentChanged(Player player) { if (!((Object)(object)player != (Object)(object)Player.m_localPlayer)) { UpdateGrid(); } } private static void OnMainMenuAwake(FejdStartup startup) { if (!_menuFontConfigured && !((Object)(object)_hotbarPartPrefab == (Object)null)) { _menuFontConfigured = true; Transform obj = ((Component)startup).transform.Find("StartGame/Panel/JoinPanel/serverCount"); TextMeshProUGUI val = ((obj != null) ? ((Component)obj).GetComponent() : null); if (val != null) { TextMeshProUGUI component = ((Component)_hotbarPartPrefab.transform.GetChild(0)).GetComponent(); ((TMP_Text)component).font = ((TMP_Text)val).font; AccessTools.Field(typeof(TextMeshProUGUI), "m_canvasRenderer").SetValue(component, ((Component)component).GetComponent()); ((TMP_Text)component).outlineWidth = 0.15f; } } } } public static class TerminalCommands { [HarmonyPatch(typeof(Terminal), "InitTerminal")] private static class Terminal_InitTerminal_ConfigReload_Patch { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static ConsoleEvent <>9__0_0; internal void b__0_0(ConsoleEventArgs args) { string target = ((args.Length > 1) ? args[1] : "all"); string message; bool flag = ConfigHotReloadRegistrar.TryReload(target, out message); ConfigReloadPoller.ResetSnapshots(); WriteCommandMessage(flag ? message : ("Reload request completed with issues: " + message)); } } [UsedImplicitly] private static void Postfix(Terminal __instance) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown string usage = ConfigHotReloadRegistrar.Usage; object obj = <>c.<>9__0_0; if (obj == null) { ConsoleEvent val = delegate(ConsoleEventArgs args) { string target = ((args.Length > 1) ? args[1] : "all"); string message; bool flag = ConfigHotReloadRegistrar.TryReload(target, out message); ConfigReloadPoller.ResetSnapshots(); WriteCommandMessage(flag ? message : ("Reload request completed with issues: " + message)); }; <>c.<>9__0_0 = val; obj = (object)val; } new ConsoleCommand("ves_reloadconfig", usage, (ConsoleEvent)obj, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } } [HarmonyPatch(typeof(Terminal), "InitTerminal")] [ClientOnlyPatch] private static class Terminal_InitTerminal_Patch { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static ConsoleEvent <>9__0_0; public static Func <>9__0_2; public static ConsoleEvent <>9__0_1; internal void b__0_0(ConsoleEventArgs args) { if (Utils.IsDebug_Strict) { int level = int.Parse(args[1]); ItemData currentWeapon = ((Humanoid)Player.m_localPlayer).GetCurrentWeapon(); if (currentWeapon != null && Object.op_Implicit((Object)(object)currentWeapon.m_dropPrefab)) { Enchantment_Core.Enchanted orCreate = currentWeapon.Data().GetOrCreate(); orCreate.level = level; orCreate.Save(); EnchantmentSideEffects.ApplyStateChanged(orCreate, refreshEquipment: true); WriteCommandMessage("Enchantment level set to " + level); } } } internal void b__0_1(ConsoleEventArgs args) { if (!Utils.IsDebug_Strict) { return; } int level = int.Parse(args[1]); foreach (ItemData item in ((Humanoid)Player.m_localPlayer).m_inventory.m_inventory.Where(delegate(ItemData x) { GameObject dropPrefab = x.m_dropPrefab; return SyncedData.GetReqs((dropPrefab != null) ? ((Object)dropPrefab).name : null) != null; })) { Enchantment_Core.Enchanted orCreate = item.Data().GetOrCreate(); orCreate.level = level; orCreate.Save(); } Enchantment_VFX.UpdateGrid(); } internal bool b__0_2(ItemData x) { GameObject dropPrefab = x.m_dropPrefab; return SyncedData.GetReqs((dropPrefab != null) ? ((Object)dropPrefab).name : null) != null; } } [UsedImplicitly] private static void Postfix(Terminal __instance) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected O, but got Unknown object obj = <>c.<>9__0_0; if (obj == null) { ConsoleEvent val = delegate(ConsoleEventArgs args) { if (Utils.IsDebug_Strict) { int level2 = int.Parse(args[1]); ItemData currentWeapon = ((Humanoid)Player.m_localPlayer).GetCurrentWeapon(); if (currentWeapon != null && Object.op_Implicit((Object)(object)currentWeapon.m_dropPrefab)) { Enchantment_Core.Enchanted orCreate2 = currentWeapon.Data().GetOrCreate(); orCreate2.level = level2; orCreate2.Save(); EnchantmentSideEffects.ApplyStateChanged(orCreate2, refreshEquipment: true); WriteCommandMessage("Enchantment level set to " + level2); } } }; <>c.<>9__0_0 = val; obj = (object)val; } new ConsoleCommand("setenchant", "", (ConsoleEvent)obj, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj2 = <>c.<>9__0_1; if (obj2 == null) { ConsoleEvent val2 = delegate(ConsoleEventArgs args) { if (Utils.IsDebug_Strict) { int level = int.Parse(args[1]); foreach (ItemData item in ((Humanoid)Player.m_localPlayer).m_inventory.m_inventory.Where(delegate(ItemData x) { GameObject dropPrefab = x.m_dropPrefab; return SyncedData.GetReqs((dropPrefab != null) ? ((Object)dropPrefab).name : null) != null; })) { Enchantment_Core.Enchanted orCreate = item.Data().GetOrCreate(); orCreate.level = level; orCreate.Save(); } Enchantment_VFX.UpdateGrid(); } }; <>c.<>9__0_1 = val2; obj2 = (object)val2; } new ConsoleCommand("setenchantall", "", (ConsoleEvent)obj2, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } } private static void WriteCommandMessage(string message) { Utils.print(message); if (Object.op_Implicit((Object)(object)Chat.instance)) { Chat.instance.m_hideTimer = 0f; ((Terminal)Chat.instance).AddString(message); } } } public static class Utils { [CompilerGenerated] private sealed class d__21 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public int skipFrames; public Action invoke; private int 5__2; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__21(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; 5__2 = 0; break; case 1: <>1__state = -1; 5__2++; break; } if (5__2 < skipFrames) { <>2__current = null; <>1__state = 1; return true; } invoke(); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public static bool IsDebug_VES { get { if (!Player.m_debugMode) { return ZNet.IsSinglePlayer; } return true; } } public static bool IsDebug_Strict => Player.m_debugMode; public static void print(object obj, ConsoleColor color = ConsoleColor.DarkGreen) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 if ((int)Application.platform == 2) { ConsoleManager.SetConsoleColor(color); ConsoleManager.StandardOutStream.WriteLine($"[{DateTime.Now}] [kg.ValheimEnchantmentSystem] {obj}"); ConsoleManager.SetConsoleColor(ConsoleColor.White); { foreach (ILogListener listener in Logger.Listeners) { DiskLogListener val = (DiskLogListener)(object)((listener is DiskLogListener) ? listener : null); if (val != null && val.LogWriter != null) { val.LogWriter.WriteLine($"[{DateTime.Now}] [kg.ValheimEnchantmentSystem] {obj}"); } } return; } } MonoBehaviour.print((object)($"[{DateTime.Now}] [kg.ValheimEnchantmentSystem] " + obj)); } public static void arr_print(IEnumerable arr, ConsoleColor color = ConsoleColor.DarkGreen) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 if ((int)Application.platform == 2) { ConsoleManager.SetConsoleColor(color); ConsoleManager.StandardOutStream.WriteLine($"[ValheimEnchantmentSystem] printing array: {arr}"); int num = 0; foreach (object item in arr) { ConsoleManager.StandardOutStream.WriteLine($"[{num++}] {item}"); foreach (ILogListener listener in Logger.Listeners) { DiskLogListener val = (DiskLogListener)(object)((listener is DiskLogListener) ? listener : null); if (val != null && val.LogWriter != null) { val.LogWriter.WriteLine($"[{num++}] {item}"); } } } ConsoleManager.SetConsoleColor(ConsoleColor.White); return; } MonoBehaviour.print((object)("[ValheimEnchantmentSystem] " + arr)); int num2 = 0; foreach (object item2 in arr) { MonoBehaviour.print((object)$"[{num2++}] {item2}"); } } public static void WriteFile(this string path, string data) { File.WriteAllText(path, data); } public static string ReadFile(this string path) { return File.ReadAllText(path); } public static string Localize(this string text) { if (string.IsNullOrEmpty(text)) { return string.Empty; } try { Localization instance = Localization.instance; return ((instance != null) ? instance.Localize(text) : null) ?? text; } catch { return text; } } public static string Localize(this string text, params string[] args) { if (string.IsNullOrEmpty(text)) { return string.Empty; } try { Localization instance = Localization.instance; return ((instance != null) ? instance.Localize(text, args) : null) ?? text; } catch { return text; } } public static bool StlocIndex(this object obj, int index) { if (obj is LocalBuilder localBuilder) { return localBuilder.LocalIndex == index; } return false; } public static Color ToColorAlpha(this string colorString) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) if (colorString[0] == '#') { colorString = colorString.Substring(1); } if (!uint.TryParse(colorString, NumberStyles.HexNumber, null, out var result)) { return Color.white; } switch (colorString.Length) { case 8: { float num4 = (float)((result >> 24) & 0xFFu) / 255f; float num5 = (float)((result >> 16) & 0xFFu) / 255f; float num6 = (float)((result >> 8) & 0xFFu) / 255f; float num7 = (float)(result & 0xFFu) / 255f; Color result3 = default(Color); ((Color)(ref result3))..ctor(num4, num5, num6, num7); return result3; } case 6: { float num = (float)((result >> 16) & 0xFFu) / 255f; float num2 = (float)((result >> 8) & 0xFFu) / 255f; float num3 = (float)(result & 0xFFu) / 255f; Color result2 = default(Color); ((Color)(ref result2))..ctor(num, num2, num3, 1f); return result2; } default: return Color.white; } } public static int CustomCountItemsNoLevel(string prefab) { int num = 0; foreach (ItemData item in ((Humanoid)Player.m_localPlayer).m_inventory.m_inventory) { if (((Object)item.m_dropPrefab).name == prefab) { num += item.m_stack; } } return num; } public static void CustomRemoveItemsNoLevel(string prefab, int amount) { foreach (ItemData item in ((Humanoid)Player.m_localPlayer).m_inventory.m_inventory) { if (((Object)item.m_dropPrefab).name == prefab) { int num = Mathf.Min(item.m_stack, amount); item.m_stack -= num; amount -= num; if (amount <= 0) { break; } } } ((Humanoid)Player.m_localPlayer).m_inventory.m_inventory.RemoveAll((ItemData x) => x.m_stack <= 0); ((Humanoid)Player.m_localPlayer).m_inventory.Changed(); } public static string IncreaseColorLight(this string color) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) Color val = default(Color); if (!ColorUtility.TryParseHtmlString(color, ref val)) { return color; } float num = default(float); float num2 = default(float); float num3 = default(float); Color.RGBToHSV(val, ref num, ref num2, ref num3); num3 = 1f; val = Color.HSVToRGB(num, num2, num3); return "#" + ColorUtility.ToHtmlStringRGB(val); } public static Color IncreaseColorLight(this Color c) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) float num = default(float); float num2 = default(float); float num3 = default(float); Color.RGBToHSV(c, ref num, ref num2, ref num3); num3 = 1f; c = Color.HSVToRGB(num, num2, num3); return c; } public static string GetPrefabNameByItemName(string itemname) { string itemname2 = itemname; GameObject val = ((IEnumerable)ObjectDB.instance.m_items).FirstOrDefault((Func)((GameObject x) => x.GetComponent().m_itemData.m_shared.m_name == itemname2)); if ((Object)(object)val == (Object)null) { return null; } return ((Object)val).name; } public static bool TryDeserializeYAML(string text, out T obj, out string error) { obj = default(T); error = string.Empty; try { if (string.IsNullOrWhiteSpace(text)) { error = "content is empty"; return false; } T val = new DeserializerBuilder().Build().Deserialize(text); if (val == null) { error = "deserialized to null"; return false; } obj = val; return true; } catch (Exception ex) { error = ex.ToString(); return false; } } public static bool TryFromYAML(this string path, out T obj, out string error) { obj = default(T); try { if (!File.Exists(path)) { error = "file does not exist"; return false; } string text = File.ReadAllText(path); return TryDeserializeYAML(text, out obj, out error); } catch (Exception ex) { error = ex.ToString(); return false; } } public static T FromYAML(this string path) { if (path.TryFromYAML(out T obj, out string error)) { return obj; } throw new InvalidOperationException("Error while deserializing " + path + ": " + error); } public static IEnumerable EquippedEnchantments(this Player p) { return from x in ((Humanoid)p).m_inventory.GetEquippedItems() select x.Data().Get() into x where x != null && x.level > 0 select x; } [IteratorStateMachine(typeof(d__21))] private static IEnumerator DelayedAction(Action invoke, int skipFrames) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__21(0) { invoke = invoke, skipFrames = skipFrames }; } public static void DelayedInvoke(this MonoBehaviour mb, Action invoke, int skipFrames) { mb.StartCoroutine(DelayedAction(invoke, skipFrames)); } public static double RoundOne(this float f) { return Math.Round(f, 1); } public static void IncreaseSkillEXP(SkillType skillType, float expToAdd) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || expToAdd <= 0f) { return; } Skill skill = localPlayer.m_skills.GetSkill(skillType); if (skill == null) { return; } float num = Mathf.Max(0f, skill.m_info?.m_increseStep ?? 1f); expToAdd *= num; while (expToAdd > 0f) { float nextLevelRequirement = skill.GetNextLevelRequirement(); if (skill.m_accumulator + expToAdd >= nextLevelRequirement) { expToAdd -= nextLevelRequirement - skill.m_accumulator; skill.m_accumulator = 0f; skill.m_level += 1f; skill.m_level = Mathf.Clamp(skill.m_level, 0f, 100f); } else { skill.m_accumulator += expToAdd; expToAdd = 0f; } } } public static Transform FindChild(Transform aParent, string aName) { Stack stack = new Stack(); Transform val = aParent; do { for (int num = val.childCount - 1; num >= 0; num--) { stack.Push(val.GetChild(num)); } if (stack.Count <= 0) { return null; } val = stack.Pop(); } while (((Object)val).name != aName); return val; } public static bool IsEnemy(this Character c) { if ((Object)(object)c == (Object)(object)Player.m_localPlayer) { return false; } if (c.IsPlayer()) { if (((Character)Player.m_localPlayer).IsPVPEnabled()) { return c.IsPVPEnabled(); } return false; } if (Object.op_Implicit((Object)(object)c.m_baseAI)) { return c.m_baseAI.IsEnemy((Character)(object)Player.m_localPlayer); } return true; } public static void InstantiateItem(GameObject prefab, int count, int level, Inventory overrideInventory = null) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0115: 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_0124: 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_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer) || !Object.op_Implicit((Object)(object)prefab) || count == 0) { return; } Inventory val = overrideInventory ?? ((Humanoid)localPlayer).m_inventory; ItemDrop component = prefab.GetComponent(); if (component == null) { return; } if (component.m_itemData.m_shared.m_maxStackSize > 1) { GameObject val2 = Object.Instantiate(prefab, ((Component)localPlayer).transform.position + ((Component)localPlayer).transform.forward * 1.5f + Vector3.up * 1.5f, Quaternion.identity); ItemDrop component2 = val2.GetComponent(); component2.m_itemData.m_quality = level; component2.m_itemData.m_stack = count; component2.m_itemData.m_durability = component2.m_itemData.GetMaxDurability(); component2.Save(); val2.SetActive(true); if (val.CanAddItem(val2, -1)) { val.AddItem(component2.m_itemData); ZNetScene.instance.Destroy(val2); } return; } for (int i = 0; i < count; i++) { GameObject val3 = Object.Instantiate(prefab, ((Component)localPlayer).transform.position + ((Component)localPlayer).transform.forward * 1.5f + Vector3.up * 1.5f, Quaternion.identity); ItemDrop component3 = val3.GetComponent(); component3.m_itemData.m_quality = level; component3.m_itemData.m_durability = component3.m_itemData.GetMaxDurability(); component3.Save(); val3.SetActive(true); if (val.CanAddItem(val3, -1)) { val.AddItem(component3.m_itemData); ZNetScene.instance.Destroy(val3); } } } } [BepInPlugin("kg.ValheimEnchantmentSystem", "ValheimEnchantmentSystem", "1.9.9")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class ValheimEnchantmentSystem : BaseUnityPlugin { private enum Toggle { On = 1, Off = 0 } private readonly struct AutoloadFailure { public readonly Type ModuleType; public readonly string Reason; public AutoloadFailure(Type moduleType, string reason) { ModuleType = moduleType; Reason = reason; } } private const string GUID = "kg.ValheimEnchantmentSystem"; private const string PLUGIN_NAME = "ValheimEnchantmentSystem"; private const string PLUGIN_VERSION = "1.9.9"; private const string GeneralConfigSection = "General"; private const string ClientConfigSection = "Client"; private static readonly string ConfigFileName = "kg.ValheimEnchantmentSystem.cfg"; private static readonly string ConfigFileFullPath = Path.Combine(Paths.ConfigPath, ConfigFileName); public static ValheimEnchantmentSystem _thistype; public static AssetBundle _asset; public static readonly Harmony Harmony = new Harmony("kg.ValheimEnchantmentSystem"); public static readonly ConfigSync ConfigSync = new ConfigSync("kg.ValheimEnchantmentSystem") { DisplayName = "ValheimEnchantmentSystem", ModRequired = true, MinimumRequiredVersion = "1.9.9", CurrentVersion = "1.9.9" }; public static string ConfigFolder; private static ConfigEntry _serverConfigLocked = null; public static bool NoGraphics; internal static IEnumerable GetAssemblyTypes() { try { return Assembly.GetExecutingAssembly().GetTypes(); } catch (ReflectionTypeLoadException ex) { foreach (Exception item in ex.LoaderExceptions.Where((Exception e) => e != null)) { Utils.print($"Autoload type scan loader exception: {item}", ConsoleColor.Red); } return ex.Types.Where((Type type) => type != null); } } private static bool TryResolveAutoloadMethod(Type moduleType, VES_Autoload autoload, out MethodInfo method, out string reason) { method = null; string text = (string.IsNullOrWhiteSpace(autoload.InitMethod) ? "OnInit" : autoload.InitMethod); MethodInfo method2 = moduleType.GetMethod(text, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (method2 == null) { reason = "method '" + text + "' not found"; return false; } if (!method2.IsStatic) { reason = "method '" + text + "' must be static"; return false; } if (method2.GetParameters().Length != 0) { reason = "method '" + text + "' must not have parameters"; return false; } if (method2.ReturnType != typeof(void)) { reason = "method '" + text + "' must return void"; return false; } method = method2; reason = string.Empty; return true; } private static HashSet RunAutoload() { List> list = (from t in GetAssemblyTypes() where t.GetCustomAttribute() != null select t into x select new KeyValuePair(x.GetCustomAttribute(), x) into x orderby x.Key.priority select x).ThenBy, string>((KeyValuePair x) => x.Value.FullName, StringComparer.Ordinal).ToList(); HashSet knownAutoloadModules = list.Select((KeyValuePair entry) => GetTopLevelDeclaringType(entry.Value)).ToHashSet(); HashSet hashSet = new HashSet(); List list2 = new List(); int num = 0; foreach (KeyValuePair item in list) { Type value = item.Value; Type topLevelDeclaringType = GetTopLevelDeclaringType(value); Type[] source = (item.Key.DependsOn ?? Array.Empty()).Select(GetTopLevelDeclaringType).Distinct().ToArray(); Type[] array = source.Where((Type dependency) => !knownAutoloadModules.Contains(dependency)).ToArray(); if (array.Length != 0) { string text = "unknown dependency: " + string.Join(", ", array.Select((Type type) => type.FullName ?? type.Name)); hashSet.Add(topLevelDeclaringType); list2.Add(new AutoloadFailure(value, text)); Utils.print("Autoload dependency validation failed for " + value.FullName + ": " + text, ConsoleColor.Red); continue; } Type[] array2 = source.Where(hashSet.Contains).ToArray(); if (array2.Length != 0) { string text2 = "dependency failed: " + string.Join(", ", array2.Select((Type type) => type.FullName ?? type.Name)); hashSet.Add(topLevelDeclaringType); list2.Add(new AutoloadFailure(value, text2)); Utils.print("Autoload skipped " + value.FullName + ": " + text2, ConsoleColor.Yellow); continue; } if (!TryResolveAutoloadMethod(value, item.Key, out MethodInfo method, out string reason)) { hashSet.Add(topLevelDeclaringType); list2.Add(new AutoloadFailure(value, reason)); Utils.print("Autoload validation failed for " + value.FullName + ": " + reason, ConsoleColor.Red); continue; } try { method.Invoke(null, null); num++; } catch (Exception ex) { Exception ex3 = ((ex is TargetInvocationException ex2 && ex.InnerException != null) ? ex2.InnerException : ex); hashSet.Add(topLevelDeclaringType); list2.Add(new AutoloadFailure(value, ex3.Message)); Utils.print($"Autoload exception on method {method}. Class {value}\n:{ex3}", ConsoleColor.Red); } } if (list2.Count > 0) { string arg = string.Join(", ", list2.Select((AutoloadFailure failure) => failure.ModuleType.Name + " (" + failure.Reason + ")")); Utils.print($"Autoload completed with failures. success={num}, failed={list2.Count}. Failed modules: {arg}", ConsoleColor.Yellow); } return hashSet; } internal static Type GetTopLevelDeclaringType(Type type) { Type type2 = type; while (type2.DeclaringType != null) { type2 = type2.DeclaringType; } return type2; } internal static bool IsTypeBlockedByAutoloadFailure(Type type, ISet failedAutoloadTypes) { if (failedAutoloadTypes.Count == 0) { return false; } Type topLevelDeclaringType = GetTopLevelDeclaringType(type); return failedAutoloadTypes.Contains(topLevelDeclaringType); } private void Awake() { bool saveOnSet = BeginBootstrap(); try { InitializeRuntimeState(); InitializeSharedInfrastructure(); InitializeConfigInfrastructure(); InitializeAssets(); HashSet failedAutoloadTypes = RunAutoload(); ApplyRegisteredPatches(failedAutoloadTypes); InitializeConfigReloadInfrastructure(); } finally { EndBootstrap(saveOnSet); } } private void Update() { ConfigReloadPoller.Update(); if (!NoGraphics) { VES_UI.Update(); Info_UI.Update(); Notifications_UI.Update(); } } private void Start() { } private void OnDestroy() { ((BaseUnityPlugin)this).Config.Save(); ConfigReloadPoller.Shutdown(); } private static AssetBundle GetAssetBundle(string filename) { string filename2 = filename; Assembly executingAssembly = Assembly.GetExecutingAssembly(); string name = executingAssembly.GetManifestResourceNames().Single((string str) => str.EndsWith(filename2)); using Stream stream = executingAssembly.GetManifestResourceStream(name); return AssetBundle.LoadFromStream(stream); } private bool BeginBootstrap() { bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet; ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; return saveOnConfigSet; } private void InitializeRuntimeState() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 NoGraphics = (int)SystemInfo.graphicsDeviceType == 4; _thistype = this; } private static void InitializeSharedInfrastructure() { JSON.Parameters = new JSONParameters { UseExtensions = false, SerializeNullValues = false, DateTimeMilliseconds = false, UseUTCDateTime = true, UseOptimizedDatasetSchema = true, UseValuesOfEnums = true }; LocalizationBootstrap.Initialize(); } private void InitializeConfigInfrastructure() { ConfigFolder = Path.Combine(Paths.ConfigPath, "ValheimEnchantmentSystem"); if (!Directory.Exists(ConfigFolder)) { Directory.CreateDirectory(ConfigFolder); } _serverConfigLocked = config("General", "Lock Configuration", Toggle.On, "If on, synced configuration can be changed by server admins only."); ConfigSync.AddLockingConfigEntry(_serverConfigLocked); } private void InitializeAssets() { _asset = GetAssetBundle("kg_enchantment"); } private void ApplyRegisteredPatches(HashSet failedAutoloadTypes) { PatchRegistry.Apply(Harmony, ((BaseUnityPlugin)this).Logger, NoGraphics, failedAutoloadTypes); } private void EndBootstrap(bool saveOnSet) { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnSet; ((BaseUnityPlugin)this).Config.Save(); } private static string WithSyncTag(string description, bool synchronizedSetting) { if (description.Contains("[Synced with Server]") || description.Contains("[Not Synced with Server]")) { return description; } string text = (synchronizedSetting ? "[Synced with Server]" : "[Not Synced with Server]"); if (!string.IsNullOrWhiteSpace(description)) { return description + " " + text; } return text; } private void InitializeConfigReloadInfrastructure() { ConfigHotReloadRegistrar.Initialize(ConfigFileFullPath, TryReloadMainConfig); ConfigReloadPoller.Initialize(); } private bool TryReloadMainConfig() { if (!File.Exists(ConfigFileFullPath)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)(ConfigFileName + " does not exist; skipping config reload.")); return false; } try { ((BaseUnityPlugin)this).Config.Reload(); return true; } catch { ((BaseUnityPlugin)this).Logger.LogError((object)("Could not load " + ConfigFileName + ". Check config format and values.")); return false; } } public static ConfigEntry config(string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown object[] array = description.Tags ?? Array.Empty(); ConfigDescription val = new ConfigDescription(WithSyncTag(description.Description, synchronizedSetting), description.AcceptableValues, array); ConfigEntry val2 = ((BaseUnityPlugin)_thistype).Config.Bind(group, name, value, val); SyncedConfigEntry syncedConfigEntry = ConfigSync.AddConfigEntry(val2); syncedConfigEntry.SynchronizedConfig = synchronizedSetting; return val2; } public static ConfigEntry config(string group, string name, T value, string description, bool synchronizedSetting = true) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown return config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty()), synchronizedSetting); } public static ConfigEntry ClientConfig(string group, string name, T value, ConfigDescription description) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown string text = (string.IsNullOrEmpty(group) ? name : (group + " - " + name)); object[] array = description.Tags ?? Array.Empty(); ConfigDescription val = new ConfigDescription(WithSyncTag(description.Description, synchronizedSetting: false), description.AcceptableValues, array); return ((BaseUnityPlugin)_thistype).Config.Bind("Client", text, value, val); } public static ConfigEntry ClientConfig(string group, string name, T value, string description) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Expected O, but got Unknown return ClientConfig(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty())); } } } namespace kg.ValheimEnchantmentSystem.UI { public static class EnchantmentStatFormatter { private static readonly List CachedValueFields = (from field in AccessTools.GetDeclaredFields(typeof(SyncedData.Stat_Data)) where field.FieldType.IsValueType select field).ToList(); private static readonly (Func Getter, string Label, bool Percent)[] IntTransitions = new(Func, string, bool)[20] { ((SyncedData.Stat_Data stats) => stats.damage_percentage, "$enchantment_bonusespercentdamage", true), ((SyncedData.Stat_Data stats) => stats.attack_speed, "$enchantment_attackspeed", true), ((SyncedData.Stat_Data stats) => stats.movement_speed, "$enchantment_movementspeed", true), ((SyncedData.Stat_Data stats) => stats.durability_percentage, "$item_durability", true), ((SyncedData.Stat_Data stats) => stats.durability, "$item_durability", false), ((SyncedData.Stat_Data stats) => stats.damage_true, "$enchantment_truedamage", false), ((SyncedData.Stat_Data stats) => stats.damage_fire, "$inventory_fire", false), ((SyncedData.Stat_Data stats) => stats.damage_blunt, "$inventory_blunt", false), ((SyncedData.Stat_Data stats) => stats.damage_slash, "$inventory_slash", false), ((SyncedData.Stat_Data stats) => stats.damage_pierce, "$inventory_pierce", false), ((SyncedData.Stat_Data stats) => stats.damage_chop, "$enchantment_chopdamage", false), ((SyncedData.Stat_Data stats) => stats.damage_pickaxe, "$enchantment_pickaxedamage", false), ((SyncedData.Stat_Data stats) => stats.damage_frost, "$inventory_frost", false), ((SyncedData.Stat_Data stats) => stats.damage_lightning, "$inventory_lightning", false), ((SyncedData.Stat_Data stats) => stats.damage_poison, "$inventory_poison", false), ((SyncedData.Stat_Data stats) => stats.damage_spirit, "$inventory_spirit", false), ((SyncedData.Stat_Data stats) => stats.max_hp, "$se_health", false), ((SyncedData.Stat_Data stats) => stats.max_stamina, "$se_stamina", false), ((SyncedData.Stat_Data stats) => stats.API_backpacks_additionalrow_x, "$enchantment_backpacks_additionalrow_x", false), ((SyncedData.Stat_Data stats) => stats.API_backpacks_additionalrow_y, "$enchantment_backpacks_additionalrow_y", false) }; private static readonly (Func Getter, string Label, bool Percent, string Suffix)[] FloatTransitions = new(Func, string, bool, string)[4] { ((SyncedData.Stat_Data stats) => stats.armor_percentage, "$enchantment_bonusespercentarmor", true, string.Empty), ((SyncedData.Stat_Data stats) => stats.armor, "$item_armor", false, string.Empty), ((SyncedData.Stat_Data stats) => stats.hp_regen, "$se_healthregen", false, "/10s"), ((SyncedData.Stat_Data stats) => stats.stamina_regen, "$se_staminaregen", false, "/s") }; private static readonly (Func Getter, string Label)[] ResistanceTransitions = new(Func, string)[10] { ((SyncedData.Stat_Data stats) => stats.resistance_blunt, "$inventory_blunt"), ((SyncedData.Stat_Data stats) => stats.resistance_slash, "$inventory_slash"), ((SyncedData.Stat_Data stats) => stats.resistance_pierce, "$inventory_pierce"), ((SyncedData.Stat_Data stats) => stats.resistance_chop, "$enchantment_chopdamage"), ((SyncedData.Stat_Data stats) => stats.resistance_pickaxe, "$enchantment_pickaxedamage"), ((SyncedData.Stat_Data stats) => stats.resistance_fire, "$inventory_fire"), ((SyncedData.Stat_Data stats) => stats.resistance_frost, "$inventory_frost"), ((SyncedData.Stat_Data stats) => stats.resistance_lightning, "$inventory_lightning"), ((SyncedData.Stat_Data stats) => stats.resistance_poison, "$inventory_poison"), ((SyncedData.Stat_Data stats) => stats.resistance_spirit, "$inventory_spirit") }; public static string BuildAdditionalStats(SyncedData.Stat_Data stats, string color) { if (stats == null || !ShouldShow(stats)) { return "\n"; } StringBuilder stringBuilder = new StringBuilder(); if (stats.attack_speed > 0) { stringBuilder.Append($"\n• $enchantment_attackspeed: +{stats.attack_speed}%"); } if (stats.movement_speed > 0) { stringBuilder.Append($"\n• $enchantment_movementspeed: +{stats.movement_speed}%"); } if (stats.durability_percentage > 0) { stringBuilder.Append($"\n• $item_durability: +{stats.durability_percentage}%"); } if (stats.durability > 0) { stringBuilder.Append($"\n• $item_durability: +{stats.durability}"); } if (stats.damage_true > 0) { stringBuilder.Append($"\n• $enchantment_truedamage: +{stats.damage_true}"); } if (stats.damage_fire > 0) { stringBuilder.Append($"\n• $inventory_fire: +{stats.damage_fire}"); } if (stats.damage_blunt > 0) { stringBuilder.Append($"\n• $inventory_blunt: +{stats.damage_blunt}"); } if (stats.damage_slash > 0) { stringBuilder.Append($"\n• $inventory_slash: +{stats.damage_slash}"); } if (stats.damage_pierce > 0) { stringBuilder.Append($"\n• $inventory_pierce: +{stats.damage_pierce}"); } if (stats.damage_chop > 0) { stringBuilder.Append($"\n• $enchantment_chopdamage: +{stats.damage_chop}"); } if (stats.damage_pickaxe > 0) { stringBuilder.Append($"\n• $enchantment_pickaxedamage: +{stats.damage_pickaxe}"); } if (stats.damage_frost > 0) { stringBuilder.Append($"\n• $inventory_frost: +{stats.damage_frost}"); } if (stats.damage_lightning > 0) { stringBuilder.Append($"\n• $inventory_lightning: +{stats.damage_lightning}"); } if (stats.damage_poison > 0) { stringBuilder.Append($"\n• $inventory_poison: +{stats.damage_poison}"); } if (stats.damage_spirit > 0) { stringBuilder.Append($"\n• $inventory_spirit: +{stats.damage_spirit}"); } if (stats.max_hp > 0) { stringBuilder.Append($"\n• $se_health: +{stats.max_hp}"); } if (stats.hp_regen > 0f) { stringBuilder.Append($"\n• $se_healthregen: +{stats.hp_regen}/10s"); } if (stats.armor > 0f) { stringBuilder.Append($"\n• $item_armor: +{stats.armor}"); } if (stats.max_stamina > 0) { stringBuilder.Append($"\n• $se_stamina: +{stats.max_stamina}"); } if (stats.stamina_regen > 0f) { stringBuilder.Append($"\n• $se_staminaregen: +{stats.stamina_regen}/s"); } if (stats.API_backpacks_additionalrow_x > 0) { stringBuilder.Append($"\n• $enchantment_backpacks_additionalrow_x: {stats.API_backpacks_additionalrow_x}"); } if (stats.API_backpacks_additionalrow_y > 0) { stringBuilder.Append($"\n• $enchantment_backpacks_additionalrow_y: {stats.API_backpacks_additionalrow_y}"); } stringBuilder.Append(SE_Stats.GetDamageModifiersTooltipString(stats.GetResistancePairs()).Replace("\n", "\n• ")); stringBuilder.Append("\n"); return stringBuilder.ToString(); } public static string BuildInfoDescription(SyncedData.Stat_Data stats) { if (stats == null) { return string.Empty; } string text = string.Empty; if (stats.damage_percentage > 0) { text += $"\n• $enchantment_bonusespercentdamage: +{stats.damage_percentage}%"; } if (stats.armor_percentage > 0f) { text += $"\n• $enchantment_bonusespercentarmor: +{stats.armor_percentage}%"; } return text + BuildAdditionalStats(stats, "#FFFFFF"); } public static string BuildTransitionDescription(SyncedData.Stat_Data? current, SyncedData.Stat_Data? next) { //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011c: 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) if (next == null) { return string.Empty; } StringBuilder stringBuilder = new StringBuilder(); (Func, string, bool)[] intTransitions = IntTransitions; for (int i = 0; i < intTransitions.Length; i++) { (Func, string, bool) tuple = intTransitions[i]; Func item = tuple.Item1; string item2 = tuple.Item2; bool item3 = tuple.Item3; int currentValue = ((current != null) ? item(current) : 0); int nextValue = item(next); AppendTransitionLine(stringBuilder, item2, currentValue, nextValue, item3, string.Empty); } (Func, string, bool, string)[] floatTransitions = FloatTransitions; for (int j = 0; j < floatTransitions.Length; j++) { (Func, string, bool, string) tuple2 = floatTransitions[j]; Func item4 = tuple2.Item1; string item5 = tuple2.Item2; bool item6 = tuple2.Item3; string item7 = tuple2.Item4; float currentValue2 = ((current != null) ? item4(current) : 0f); float nextValue2 = item4(next); AppendTransitionLine(stringBuilder, item5, currentValue2, nextValue2, item6, item7); } (Func, string)[] resistanceTransitions = ResistanceTransitions; for (int k = 0; k < resistanceTransitions.Length; k++) { (Func, string) tuple3 = resistanceTransitions[k]; Func item8 = tuple3.Item1; string item9 = tuple3.Item2; DamageModifier currentValue3 = (DamageModifier)((current != null) ? ((int)item8(current)) : 0); DamageModifier nextValue3 = item8(next); AppendResistanceTransitionLine(stringBuilder, item9, currentValue3, nextValue3); } return stringBuilder.ToString().Trim(); } private static bool ShouldShow(SyncedData.Stat_Data stats) { SyncedData.Stat_Data stats2 = stats; return CachedValueFields.Any((FieldInfo field) => !field.GetValue(stats2).Equals(Activator.CreateInstance(field.FieldType))); } private static void AppendTransitionLine(StringBuilder builder, string label, int currentValue, int nextValue, bool percent, string suffix) { if (currentValue != nextValue || nextValue != 0) { string formattedCurrent = FormatValue(currentValue, percent, suffix); string formattedNext = FormatValue(nextValue, percent, suffix); AppendTransitionLine(builder, label, currentValue != 0, formattedCurrent, formattedNext); } } private static void AppendTransitionLine(StringBuilder builder, string label, float currentValue, float nextValue, bool percent, string suffix) { if (!(Math.Abs(currentValue - nextValue) < 0.001f) || !(Math.Abs(nextValue) < 0.001f)) { string formattedCurrent = FormatValue(currentValue, percent, suffix); string formattedNext = FormatValue(nextValue, percent, suffix); AppendTransitionLine(builder, label, Math.Abs(currentValue) >= 0.001f, formattedCurrent, formattedNext); } } private static void AppendTransitionLine(StringBuilder builder, string label, bool hasCurrentValue, string formattedCurrent, string formattedNext) { if (!(string.Equals(formattedCurrent, formattedNext, StringComparison.Ordinal) && hasCurrentValue)) { if (builder.Length > 0) { builder.Append('\n'); } builder.Append("• ").Append(label).Append(": "); if (hasCurrentValue) { builder.Append(formattedCurrent).Append(" > ").Append(formattedNext); } else { builder.Append(formattedNext); } } } private static void AppendResistanceTransitionLine(StringBuilder builder, string label, DamageModifier currentValue, DamageModifier nextValue) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) if ((currentValue != nextValue || (int)nextValue != 0) && currentValue != nextValue) { if (builder.Length > 0) { builder.Append('\n'); } builder.Append("• ").Append(label).Append(": "); if ((int)currentValue != 0) { builder.Append(FormatDamageModifier(currentValue)).Append(" > ").Append(FormatDamageModifier(nextValue)); } else { builder.Append(FormatDamageModifier(nextValue)); } } } private static string FormatValue(int value, bool percent, string suffix) { if (!percent) { return $"+{value}{suffix}"; } return $"+{value}%{suffix}"; } private static string FormatValue(float value, bool percent, string suffix) { string text = value.ToString("0.#", CultureInfo.InvariantCulture); if (!percent) { return "+" + text + suffix; } return "+" + text + "%" + suffix; } private static string FormatDamageModifier(DamageModifier modifier) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected I4, but got Unknown return (modifier - 1) switch { 0 => "$enchantment_modifier_resistant".Localize(), 1 => "$enchantment_modifier_weak".Localize(), 2 => "$enchantment_modifier_immune".Localize(), 3 => "$enchantment_modifier_ignore".Localize(), 4 => "$enchantment_modifier_veryresistant".Localize(), 5 => "$enchantment_modifier_veryweak".Localize(), _ => "$enchantment_modifier_normal".Localize(), }; } } internal sealed class InfoEntryView : MonoBehaviour { private Transform _itemsRoot; private GameObject _iconTemplate; private Text _additionalLabel; private Text _infoText; private Button _toggleButton; private GameObject _openIcon; private GameObject _closeIcon; public bool IsExpanded { get; private set; } public static InfoEntryView Attach(GameObject root) { InfoEntryView orAddComponent = UIBindingHelper.GetOrAddComponent(root); orAddComponent.Bind(); return orAddComponent; } public void Apply(InfoPanelEntryModel model, GameObject? tooltipPrefab) { //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) ClearIcons(); _infoText.text = model.BodyText; bool flag = !string.IsNullOrWhiteSpace(model.AdditionalText); ((Component)_additionalLabel).gameObject.SetActive(flag); if (flag) { _additionalLabel.text = model.AdditionalText; } ((Component)_itemsRoot).gameObject.SetActive(model.Icons.Count > 0); foreach (InfoPanelIconModel icon in model.Icons) { GameObject val = Object.Instantiate(_iconTemplate, _itemsRoot); val.SetActive(true); UIBindingHelper.GetRequired(val.transform, "Icon").sprite = icon.Icon; ((Graphic)UIBindingHelper.GetRequired(val.transform, "border")).color = (icon.Highlight ? Color.green : Color.white); UITooltip component = val.GetComponent(); if (component != null) { component.m_topic = icon.TooltipTopic; component.m_text = icon.TooltipText; if ((Object)(object)tooltipPrefab != (Object)null) { component.m_tooltipPrefab = tooltipPrefab; } } } SetExpanded(model.StartExpanded); } public void BindToggle(Action onToggle) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown Action onToggle2 = onToggle; ((UnityEventBase)_toggleButton.onClick).RemoveAllListeners(); ((UnityEvent)_toggleButton.onClick).AddListener((UnityAction)delegate { onToggle2(); }); } public void SetExpanded(bool expanded) { IsExpanded = expanded; ((Component)_infoText).gameObject.SetActive(expanded); _openIcon.SetActive(!expanded); _closeIcon.SetActive(expanded); } private void Bind() { Transform transform = ((Component)this).transform; _itemsRoot = UIBindingHelper.FindRequired(transform, "Items"); _iconTemplate = ((Component)UIBindingHelper.FindRequired(_itemsRoot, "Icon")).gameObject; _iconTemplate.SetActive(false); _additionalLabel = UIBindingHelper.GetRequired(transform, "ANY"); _infoText = UIBindingHelper.GetRequired(transform, "Info"); _toggleButton = ((Component)UIBindingHelper.FindRequired(transform, "Open")).GetComponent