Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of EtchedRunes v1.0.0
plugins/EtchedRunes.dll
Decompiled 2 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using EpicLoot; using HarmonyLib; using Jotunn.Entities; using Jotunn.Managers; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")] [assembly: AssemblyCompany("HaldorExtraItems")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("HaldorExtraItems")] [assembly: AssemblyTitle("HaldorExtraItems")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace HaldorExtraItems { [BepInPlugin("com.haldorextraitems.mod", "Haldor Extra Items", "1.9.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { public sealed class MagicRecipe { public string EffectType; public float EffectValue; public ItemRarity Rarity; } public sealed class TradeOffer { public string PrefabName; public int Stack; public int Price; public string RequiredGlobalKey; } private sealed class ItemConfig { public ConfigEntry<bool> Enabled; public ConfigEntry<string> Prefab; public ConfigEntry<string> Enchantment; public ConfigEntry<float> EnchantmentValue; public ConfigEntry<string> Rarity; public ConfigEntry<int> CoinsCost; public ConfigEntry<int> Stack; } public const string PluginGuid = "com.haldorextraitems.mod"; public const string PluginName = "Haldor Extra Items"; public const string PluginVersion = "1.9.0"; internal static ManualLogSource Log; internal static readonly List<TradeOffer> Offers = new List<TradeOffer>(); internal static readonly Dictionary<string, MagicRecipe> MagicByPrefab = new Dictionary<string, MagicRecipe>(StringComparer.Ordinal); private bool _registered; private readonly ItemConfig[] _items = new ItemConfig[8]; private void Awake() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; BindAllItemConfigs(); PrefabManager.OnPrefabsRegistered += TryRegister; ItemManager.OnItemsRegistered += TryRegister; new Harmony("com.haldorextraitems.mod").PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Haldor Extra Items 1.9.0 loaded (normal Haldor shop only)."); } private void BindAllItemConfigs() { string[] array = new string[8] { "EtchedRunestoneMagic", "EtchedRunestoneMagic", "EtchedRunestoneRare", "EtchedRunestoneRare", "EtchedRunestoneEpic", "EtchedRunestoneEpic", "EtchedRunestoneLegendary", "EtchedRunestoneMythic" }; string[] array2 = new string[8] { "Magic", "Magic", "Rare", "Rare", "Epic", "Epic", "Legendary", "Mythic" }; float[] array3 = new float[8] { 10f, 15f, 20f, 25f, 30f, 35f, 40f, 50f }; int[] array4 = new int[8] { 350, 500, 800, 1100, 1800, 2400, 4000, 7500 }; for (int i = 0; i < 8; i++) { string text = $"Item {i + 1}"; ItemConfig itemConfig = new ItemConfig(); itemConfig.Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>(text, "Enabled", true, "Enable this entry."); itemConfig.Prefab = ((BaseUnityPlugin)this).Config.Bind<string>(text, "Prefab", array[i], "Prefab to clone."); itemConfig.Enchantment = ((BaseUnityPlugin)this).Config.Bind<string>(text, "Enchantment", "Riches", "Magic effect type."); itemConfig.EnchantmentValue = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Enchantment Value", array3[i], "Effect strength."); itemConfig.Rarity = ((BaseUnityPlugin)this).Config.Bind<string>(text, "Rarity", array2[i], "Magic, Rare, Epic, Legendary, Mythic."); itemConfig.CoinsCost = ((BaseUnityPlugin)this).Config.Bind<int>(text, "Coins Cost", array4[i], "Coin price."); itemConfig.Stack = ((BaseUnityPlugin)this).Config.Bind<int>(text, "Stack", 1, "Stack per purchase."); _items[i] = itemConfig; } } private void TryRegister() { if (_registered) { return; } if ((Object)(object)FindPrefab("RunestoneMagic") == (Object)null && (Object)(object)FindPrefab("EtchedRunestoneMagic") == (Object)null) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Waiting for Epic Loot runestones..."); return; } _registered = true; PrefabManager.OnPrefabsRegistered -= TryRegister; ItemManager.OnItemsRegistered -= TryRegister; try { Offers.Clear(); MagicByPrefab.Clear(); for (int i = 0; i < 8; i++) { AddConfiguredItem(i); } ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Done. Trade offers: {Offers.Count}"); } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Registration failed: {arg}"); _registered = false; } } private void AddConfiguredItem(int index) { //IL_0105: 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_0122: 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_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Expected O, but got Unknown string text = $"Item {index + 1}"; ItemConfig itemConfig = _items[index]; if (!itemConfig.Enabled.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("[" + text + "] disabled.")); return; } string text2 = ResolveSourceName(itemConfig.Prefab.Value); if (text2 == null) { ((BaseUnityPlugin)this).Logger.LogError((object)("[" + text + "] No source prefab found.")); return; } string value = itemConfig.Enchantment.Value; string value2 = itemConfig.Rarity.Value; float value3 = itemConfig.EnchantmentValue.Value; int value4 = itemConfig.CoinsCost.Value; int stack = Math.Max(1, itemConfig.Stack.Value); string text3 = $"HEI_{index + 1}_{Sanitize(value)}_{Sanitize(value2)}_{Mathf.RoundToInt(value3)}"; string text4 = ResolveEffectType(value); ItemRarity rarity = ParseRarity(value2); MagicRecipe magicRecipe = new MagicRecipe { EffectType = text4, EffectValue = value3, Rarity = rarity }; MagicByPrefab[text3] = magicRecipe; GameObject prefab = PrefabManager.Instance.GetPrefab(text3); if ((Object)(object)prefab == (Object)null) { prefab = PrefabManager.Instance.CreateClonedPrefab(text3, text2); if ((Object)(object)prefab == (Object)null) { ((BaseUnityPlugin)this).Logger.LogError((object)("[" + text + "] CreateClonedPrefab failed.")); return; } ItemDrop component = prefab.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null) { ((BaseUnityPlugin)this).Logger.LogError((object)("[" + text + "] No ItemDrop on clone.")); return; } ApplyMagicToItemData(component.m_itemData, magicRecipe); component.m_itemData.m_dropPrefab = prefab; ItemManager.Instance.AddItem(new CustomItem(prefab, false)); ((BaseUnityPlugin)this).Logger.LogInfo((object)("[" + text + "] Cloned '" + text3 + "' from '" + text2 + "'.")); } else { ((BaseUnityPlugin)this).Logger.LogInfo((object)("[" + text + "] '" + text3 + "' already present.")); ItemDrop component2 = prefab.GetComponent<ItemDrop>(); if ((Object)(object)component2 != (Object)null) { ApplyMagicToItemData(component2.m_itemData, magicRecipe); component2.m_itemData.m_dropPrefab = prefab; } } if ((Object)(object)ObjectDB.instance != (Object)null) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(text3); if ((Object)(object)itemPrefab != (Object)null) { ItemDrop component3 = itemPrefab.GetComponent<ItemDrop>(); if ((Object)(object)component3 != (Object)null) { ApplyMagicToItemData(component3.m_itemData, magicRecipe); component3.m_itemData.m_dropPrefab = itemPrefab; } } } ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[{text}] Magic applied: {text4}={value3}, rarity={value2}"); Offers.Add(new TradeOffer { PrefabName = text3, Stack = stack, Price = Math.Max(1, value4), RequiredGlobalKey = "" }); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[{text}] -> Haldor shop @ {value4} coins"); } internal static void ApplyMagicToItemData(ItemData itemData, MagicRecipe recipe) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown if (itemData == null || recipe == null) { return; } MagicItem val = new MagicItem { Rarity = recipe.Rarity }; MagicItemEffect val2 = new MagicItemEffect(recipe.EffectType, 1f); SetNumericEffectValue(val2, recipe.EffectValue); val.Effects.Add(val2); ItemDataExtensions.SaveMagicItem(itemData, val); try { Type type = typeof(MagicItem).Assembly.GetType("EpicLoot.MagicItemComponent"); if (type == null) { return; } object obj = ((object)itemData).GetType().GetMethod("Data", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.Invoke(itemData, null); if (obj != null) { MethodInfo method = obj.GetType().GetMethod("GetOrCreate"); if (!(method == null)) { object obj2 = method.MakeGenericMethod(type).Invoke(obj, null); type.GetMethod("SetMagicItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.Invoke(obj2, new object[1] { val }); type.GetMethod("Save", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.Invoke(obj2, null); } } } catch { } } private string ResolveSourceName(string requested) { string[] obj = new string[12] { requested, "EtchedRunestoneMagic", "EtchedRunestoneRare", "EtchedRunestoneEpic", "EtchedRunestoneLegendary", "EtchedRunestoneMythic", "RunestoneMagic", "RunestoneRare", "RunestoneEpic", "RunestoneLegendary", "RunestoneMythic", "Runestone" }; HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); string[] array = obj; foreach (string text in array) { if (!string.IsNullOrEmpty(text) && hashSet.Add(text) && (Object)(object)FindPrefab(text) != (Object)null) { if (!text.Equals(requested, StringComparison.OrdinalIgnoreCase)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("'" + requested + "' missing – using '" + text + "'.")); } return text; } } return null; } private static GameObject FindPrefab(string name) { if (string.IsNullOrEmpty(name)) { return null; } GameObject val = ((PrefabManager.Instance != null) ? PrefabManager.Instance.GetPrefab(name) : null); if ((Object)(object)val == (Object)null && (Object)(object)ObjectDB.instance != (Object)null) { val = ObjectDB.instance.GetItemPrefab(name); } return val; } private static string ResolveEffectType(string value) { FieldInfo field = typeof(MagicEffectType).GetField(value, BindingFlags.IgnoreCase | BindingFlags.Static | BindingFlags.Public); if (field != null && field.FieldType == typeof(string)) { string text = field.GetValue(null) as string; if (!string.IsNullOrEmpty(text)) { return text; } } return value; } private static ItemRarity ParseRarity(string value) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) if (!Enum.TryParse<ItemRarity>(value, ignoreCase: true, out ItemRarity result)) { throw new ArgumentException("Unknown rarity '" + value + "'."); } return result; } private static void SetNumericEffectValue(MagicItemEffect effect, float value) { Type type = ((object)effect).GetType(); string[] array = new string[4] { "EffectValue", "Value", "Power", "EffectPower" }; foreach (string name in array) { FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null && IsNumeric(field.FieldType)) { field.SetValue(effect, ConvertNumber(value, field.FieldType)); return; } PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.CanWrite && IsNumeric(property.PropertyType)) { property.SetValue(effect, ConvertNumber(value, property.PropertyType), null); return; } } throw new MissingMemberException("No numeric member on MagicItemEffect."); } private static bool IsNumeric(Type t) { if (!(t == typeof(float)) && !(t == typeof(double)) && !(t == typeof(int))) { return t == typeof(long); } return true; } private static object ConvertNumber(float value, Type type) { if (type == typeof(float)) { return value; } if (type == typeof(double)) { return (double)value; } if (type == typeof(int)) { return (int)Math.Round(value); } if (type == typeof(long)) { return (long)Math.Round(value); } throw new NotSupportedException(type.FullName); } private static string Sanitize(string value) { char[] invalidFileNameChars = Path.GetInvalidFileNameChars(); foreach (char oldChar in invalidFileNameChars) { value = value.Replace(oldChar, '_'); } return value.Replace(' ', '_'); } } [HarmonyPatch(typeof(ItemData), "Clone")] internal static class ItemData_Clone_Patch { private static void Postfix(ItemData __instance, ItemData __result) { if (__result == null) { return; } string text = null; if ((Object)(object)__result.m_dropPrefab != (Object)null) { text = ((Object)__result.m_dropPrefab).name; } else if ((Object)(object)__instance?.m_dropPrefab != (Object)null) { text = ((Object)__instance.m_dropPrefab).name; __result.m_dropPrefab = __instance.m_dropPrefab; } if (!string.IsNullOrEmpty(text) && text.StartsWith("HEI_", StringComparison.Ordinal) && Plugin.MagicByPrefab.TryGetValue(text, out var value)) { Plugin.ApplyMagicToItemData(__result, value); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[Clone] Re-applied magic on '" + text + "'.")); } } } } [HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData) })] internal static class Inventory_AddItem_Patch { private static void Prefix(ItemData item) { if ((Object)(object)item?.m_dropPrefab == (Object)null) { return; } string name = ((Object)item.m_dropPrefab).name; if (!name.StartsWith("HEI_", StringComparison.Ordinal) || !Plugin.MagicByPrefab.TryGetValue(name, out var value)) { return; } try { MagicItem magicItem = ItemDataExtensions.GetMagicItem(item); if (magicItem != null && magicItem.Effects != null && magicItem.Effects.Count > 0) { return; } } catch { } Plugin.ApplyMagicToItemData(item, value); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[Inventory] Re-applied magic on '" + name + "'.")); } } } [HarmonyPatch(typeof(Trader), "GetAvailableItems")] internal static class Trader_GetAvailableItems_Patch { private static void Postfix(Trader __instance, ref List<TradeItem> __result) { //IL_0158: 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_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Expected O, but got Unknown if (Plugin.Offers.Count == 0 || __result == null || (Object)(object)ObjectDB.instance == (Object)null || !IsHaldor(__instance)) { return; } int num = 0; foreach (Plugin.TradeOffer offer in Plugin.Offers) { GameObject val = ObjectDB.instance.GetItemPrefab(offer.PrefabName); if ((Object)(object)val == (Object)null && PrefabManager.Instance != null) { val = PrefabManager.Instance.GetPrefab(offer.PrefabName); } if ((Object)(object)val == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Shop] '" + offer.PrefabName + "' not in ObjectDB.")); } continue; } ItemDrop component = val.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null) { continue; } if (Plugin.MagicByPrefab.TryGetValue(offer.PrefabName, out var value)) { Plugin.ApplyMagicToItemData(component.m_itemData, value); component.m_itemData.m_dropPrefab = val; } bool flag = false; foreach (TradeItem item in __result) { if ((Object)(object)item?.m_prefab != (Object)null && ((Object)item.m_prefab).name == ((Object)component).name) { flag = true; break; } } if (!flag) { __result.Add(new TradeItem { m_prefab = component, m_stack = offer.Stack, m_price = offer.Price, m_requiredGlobalKey = (offer.RequiredGlobalKey ?? "") }); num++; } } if (num > 0) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[Shop] Added {num} item(s) to {((Object)((Component)__instance).gameObject).name}."); } } } private static bool IsHaldor(Trader trader) { string name = ((Object)((Component)trader).gameObject).name; if (name.IndexOf("Haldor", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } if (name.IndexOf("Vendor_BlackForest", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } if (trader.m_items != null) { foreach (TradeItem item in trader.m_items) { if (!((Object)(object)item?.m_prefab == (Object)null)) { switch (((Object)item.m_prefab).name) { case "YmirRemains": case "FishingRod": case "Thunderstone": return true; } } } } return false; } } }