Decompiled source of EtchedRunes v1.0.0

plugins/EtchedRunes.dll

Decompiled 2 days ago
using 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;
		}
	}
}