Decompiled source of HaldorExpansion v0.4.0

HaldorExpansion.dll

Decompiled 3 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using MushroomMods;
using MushroomSync;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_utils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("HaldorExpansion")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.4.0.0")]
[assembly: AssemblyInformationalVersion("0.4.0+3c15a0cc54c8b70d1d4aad090ba6cdc3ca225dc9")]
[assembly: AssemblyProduct("HaldorExpansion")]
[assembly: AssemblyTitle("HaldorExpansion")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.4.0.0")]
[module: UnverifiableCode]
[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 HaldorExpansion
{
	internal sealed class ItemConfig
	{
		public readonly ConfigEntry<bool> Enabled;

		public readonly ConfigEntry<int> Cost;

		public readonly ConfigEntry<UnlockBoss> UnlockBoss;

		public ItemConfig(ConfigEntry<bool> enabled, ConfigEntry<int> cost, ConfigEntry<UnlockBoss> unlockBoss)
		{
			Enabled = enabled;
			Cost = cost;
			UnlockBoss = unlockBoss;
		}
	}
	internal sealed class ModConfig
	{
		private readonly ConfigFile _configFile;

		private readonly ConfigEntry<bool> _lockConfiguration;

		private readonly Dictionary<string, ItemConfig> _items = new Dictionary<string, ItemConfig>();

		internal bool LockConfiguration => _lockConfiguration.Value;

		private ConfigEntry<T> Bind<T>(string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true)
		{
			ConfigEntry<T> val = _configFile.Bind<T>(group, name, value, description);
			if (synchronizedSetting)
			{
				Plugin.Sync.Register((ConfigEntryBase)(object)val);
			}
			return val;
		}

		internal ModConfig(ConfigFile configFile)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Expected O, but got Unknown
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Expected O, but got Unknown
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Expected O, but got Unknown
			_configFile = configFile;
			configFile.SaveOnConfigSet = false;
			_lockConfiguration = Bind("Server", "LockConfiguration", value: true, new ConfigDescription("If on, connected clients use this machine's item settings instead of their local values.", (AcceptableValueBase)null, Array.Empty<object>()), synchronizedSetting: false);
			TradeEntry[] haldor = TradeTable.Haldor;
			foreach (TradeEntry tradeEntry in haldor)
			{
				string text = "Items." + tradeEntry.PrefabName;
				ConfigEntry<bool> enabled = Bind(text, "Enabled", value: true, new ConfigDescription("If off, " + tradeEntry.PrefabName + " is not added to Haldor's stock.", (AcceptableValueBase)null, Array.Empty<object>()));
				int pricePerUnit = tradeEntry.PricePerUnit;
				string[] obj = new string[7] { "Coins charged per unit of ", tradeEntry.PrefabName, ". One purchase delivers ", null, null, null, null };
				int stack = tradeEntry.Stack;
				obj[3] = stack.ToString();
				obj[4] = " for Cost x ";
				stack = tradeEntry.Stack;
				obj[5] = stack.ToString();
				obj[6] = " coins.";
				ConfigEntry<int> cost = Bind(text, "Cost", pricePerUnit, new ConfigDescription(string.Concat(obj), (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100000), Array.Empty<object>()));
				ConfigEntry<UnlockBoss> unlockBoss = Bind(text, "UnlockBoss", tradeEntry.DefaultUnlockBoss, new ConfigDescription("Boss that must be defeated before " + tradeEntry.PrefabName + " appears in Haldor's stock. None means always available.", (AcceptableValueBase)null, Array.Empty<object>()));
				_items[tradeEntry.PrefabName] = new ItemConfig(enabled, cost, unlockBoss);
			}
			configFile.Save();
			configFile.SaveOnConfigSet = true;
		}

		internal bool IsEnabled(TradeEntry entry)
		{
			if (!_items.TryGetValue(entry.PrefabName, out var value))
			{
				return true;
			}
			return value.Enabled.Value;
		}

		internal int GetCostPerUnit(TradeEntry entry)
		{
			if (!_items.TryGetValue(entry.PrefabName, out var value))
			{
				return entry.PricePerUnit;
			}
			int value2 = value.Cost.Value;
			if (value2 >= 0)
			{
				return value2;
			}
			return 0;
		}

		internal int GetPurchasePrice(TradeEntry entry)
		{
			return GetCostPerUnit(entry) * entry.Stack;
		}

		internal UnlockBoss GetUnlockBoss(TradeEntry entry)
		{
			if (!_items.TryGetValue(entry.PrefabName, out var value))
			{
				return entry.DefaultUnlockBoss;
			}
			return value.UnlockBoss.Value;
		}

		internal string GetRequiredGlobalKey(TradeEntry entry)
		{
			return UnlockBossKeys.Get(GetUnlockBoss(entry));
		}
	}
	internal static class Diagnostics
	{
		private static bool _done;

		private static readonly string[] SearchTerms = new string[10] { "stone", "wood", "surtling", "core", "graus", "ash", "mist", "torch", "wisp", "demister" };

		public static void DumpOnce(Trader trader, List<TradeItem> available)
		{
			if (!_done)
			{
				_done = true;
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("===== HALDOR EXPANSION :: VERIFICATION DUMP =====");
				stringBuilder.AppendLine("Table hash: " + TradeTable.Hash);
				DumpGlobalKeys(stringBuilder);
				DumpVanillaStock(stringBuilder, trader, available);
				DumpTargets(stringBuilder);
				DumpCandidates(stringBuilder);
				stringBuilder.AppendLine("===== END VERIFICATION DUMP =====");
				Plugin.Log.LogInfo((object)stringBuilder.ToString());
			}
		}

		private static void DumpGlobalKeys(StringBuilder sb)
		{
			sb.AppendLine();
			sb.AppendLine("--- GLOBAL KEYS CURRENTLY SET ---");
			ZoneSystem instance = ZoneSystem.instance;
			if ((Object)(object)instance == (Object)null)
			{
				sb.AppendLine("  ZoneSystem not available.");
				return;
			}
			bool flag = false;
			foreach (string globalKey2 in instance.GetGlobalKeys())
			{
				sb.AppendLine("  " + globalKey2);
				flag = true;
			}
			if (!flag)
			{
				sb.AppendLine("  (none set on this world)");
			}
			sb.AppendLine();
			sb.AppendLine("  --- boss keys we gate on ---");
			foreach (UnlockBoss value in Enum.GetValues(typeof(UnlockBoss)))
			{
				if (value != UnlockBoss.None)
				{
					string text = UnlockBossKeys.Get(value);
					bool globalKey = instance.GetGlobalKey(text);
					sb.AppendLine("  " + value.ToString().PadRight(10) + " '" + text + "' set: " + globalKey);
				}
			}
		}

		private static void DumpVanillaStock(StringBuilder sb, Trader trader, List<TradeItem> available)
		{
			sb.AppendLine();
			sb.AppendLine("--- VANILLA TRADER STOCK (price anchors) ---");
			sb.AppendLine("  Trader GameObject: " + (((Object)(object)trader != (Object)null) ? ((Object)((Component)trader).gameObject).name : "null"));
			if ((Object)(object)trader == (Object)null || trader.m_items == null)
			{
				sb.AppendLine("  No configured item list.");
				return;
			}
			foreach (TradeItem item in trader.m_items)
			{
				if (item != null && !((Object)(object)item.m_prefab == (Object)null))
				{
					string text = (string.IsNullOrEmpty(item.m_requiredGlobalKey) ? "-" : item.m_requiredGlobalKey);
					sb.AppendLine("  " + ((Object)item.m_prefab).name.PadRight(24) + " stack=" + item.m_stack.ToString().PadRight(5) + " price=" + item.m_price.ToString().PadRight(7) + " key=" + text);
				}
			}
			sb.AppendLine("  (currently offered to this player: " + (available?.Count ?? 0) + " rows)");
		}

		private static void DumpTargets(StringBuilder sb)
		{
			sb.AppendLine();
			sb.AppendLine("--- OUR TRADE TARGETS ---");
			TradeEntry[] haldor = TradeTable.Haldor;
			foreach (TradeEntry tradeEntry in haldor)
			{
				ItemDrop val = PrefabCache.Resolve(tradeEntry.PrefabName);
				if ((Object)(object)val == (Object)null)
				{
					sb.AppendLine("  " + tradeEntry.PrefabName.PadRight(20) + " UNRESOLVED -- wrong spelling?");
					continue;
				}
				int maxStackSize = val.m_itemData.m_shared.m_maxStackSize;
				object obj;
				int stack;
				if (tradeEntry.Stack <= maxStackSize)
				{
					obj = "";
				}
				else
				{
					stack = tradeEntry.Stack;
					obj = "  <-- CONFIGURED STACK " + stack + " EXCEEDS MAX STACK " + maxStackSize;
				}
				string text = (string)obj;
				ModConfig settings = Plugin.Settings;
				bool flag = settings?.IsEnabled(tradeEntry) ?? true;
				int num = settings?.GetCostPerUnit(tradeEntry) ?? tradeEntry.PricePerUnit;
				int num2 = settings?.GetPurchasePrice(tradeEntry) ?? tradeEntry.Price;
				UnlockBoss boss = settings?.GetUnlockBoss(tradeEntry) ?? tradeEntry.DefaultUnlockBoss;
				string text2 = UnlockBossKeys.Get(boss) ?? "-";
				string[] obj2 = new string[16]
				{
					"  ",
					tradeEntry.PrefabName.PadRight(20),
					flag ? " on " : " OFF",
					" boss=",
					boss.ToString().PadRight(10),
					" key=",
					text2.PadRight(20),
					" maxStack=",
					maxStackSize.ToString().PadRight(5),
					" ourStack=",
					null,
					null,
					null,
					null,
					null,
					null
				};
				stack = tradeEntry.Stack;
				obj2[10] = stack.ToString().PadRight(5);
				obj2[11] = " price=";
				obj2[12] = num2.ToString().PadRight(6);
				obj2[13] = " perUnit=";
				obj2[14] = num.ToString();
				obj2[15] = text;
				sb.AppendLine(string.Concat(obj2));
			}
			sb.AppendLine("  NOTE: buy one of each in-game and confirm the delivered amount matches ourStack. If m_stack clamps to maxStack, a purchase silently shortchanges the buyer.");
		}

		private static void DumpCandidates(StringBuilder sb)
		{
			sb.AppendLine();
			sb.AppendLine("--- ITEM CANDIDATES (ObjectDB names matching our search terms) ---");
			ObjectDB instance = ObjectDB.instance;
			if ((Object)(object)instance == (Object)null || instance.m_items == null)
			{
				sb.AppendLine("  ObjectDB not available.");
				return;
			}
			foreach (GameObject item in instance.m_items)
			{
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				string text = ((Object)item).name.ToLowerInvariant();
				string[] searchTerms = SearchTerms;
				foreach (string value in searchTerms)
				{
					if (text.Contains(value))
					{
						ItemDrop component = item.GetComponent<ItemDrop>();
						string text2 = (((Object)(object)component != (Object)null && component.m_itemData != null && component.m_itemData.m_shared != null) ? component.m_itemData.m_shared.m_maxStackSize.ToString() : "?");
						sb.AppendLine("  " + ((Object)item).name.PadRight(28) + " maxStack=" + text2);
						break;
					}
				}
			}
		}
	}
	[HarmonyPatch(typeof(ObjectDB))]
	internal static class ObjectDbPatches
	{
		[HarmonyPostfix]
		[HarmonyPriority(800)]
		[HarmonyPatch("Awake")]
		private static void AwakePostfix(ObjectDB __instance)
		{
			try
			{
				PrefabCache.Reset();
				SuperMistTorch.EnsureRegistered(__instance);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("ObjectDB.Awake SuperMistTorch registration failed: " + ex));
			}
		}

		[HarmonyPostfix]
		[HarmonyPriority(800)]
		[HarmonyPatch("CopyOtherDB")]
		private static void CopyOtherDbPostfix(ObjectDB __instance)
		{
			try
			{
				PrefabCache.Reset();
				SuperMistTorch.EnsureRegistered(__instance);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("ObjectDB.CopyOtherDB SuperMistTorch registration failed: " + ex));
			}
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "Awake")]
	internal static class ZNetSceneAwakePatch
	{
		[HarmonyPostfix]
		[HarmonyPriority(800)]
		private static void Postfix(ZNetScene __instance)
		{
			try
			{
				SuperMistTorch.EnsureNetworkRegistered(__instance);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("ZNetScene.Awake SuperMistTorch registration failed: " + ex));
			}
		}
	}
	[HarmonyPatch(typeof(Game), "Start")]
	internal static class GameStartPatch
	{
		[HarmonyPostfix]
		[HarmonyPriority(800)]
		private static void Postfix()
		{
			try
			{
				SuperMistTorch.EnsureNetworkRegistered(ZNetScene.instance);
				SuperMistTorch.EnsureRegistered(ObjectDB.instance);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Game.Start SuperMistTorch registration failed: " + ex));
			}
		}
	}
	[HarmonyPatch(typeof(Player), "OnSpawned")]
	internal static class PlayerOnSpawnedPatch
	{
		[HarmonyPostfix]
		private static void Postfix(Player __instance)
		{
			try
			{
				SuperMistTorch.EnsureKnown(__instance);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Failed to unlock SuperMistTorch for player: " + ex));
			}
		}
	}
	[HarmonyPatch(typeof(Player), "PlacePiece")]
	internal static class PlayerPlacePiecePatch
	{
		[HarmonyPostfix]
		private static void Postfix(Player __instance)
		{
			try
			{
				SuperMistTorch.UnequipIfDepleted(__instance);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("SuperMistTorch post-placement check failed: " + ex));
			}
		}
	}
	[BepInPlugin("nicks.haldorexpansion", "Haldor Expansion", "0.4.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginId = "nicks.haldorexpansion";

		public const string PluginName = "Haldor Expansion";

		public const string PluginVersion = "0.4.0";

		internal static ManualLogSource Log;

		internal static ModConfig Settings;

		internal static ConfigSync Sync;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Sync = ConfigSync.Create("nicks.haldorexpansion", "0.4.0", ((BaseUnityPlugin)this).Logger).Protecting(((BaseUnityPlugin)this).Config).OnApplied((Action)delegate
			{
				SuperMistTorch.RefreshFromConfig();
				Log.LogInfo((object)("Trade table hash: " + TradeTable.Hash));
			});
			Settings = new ModConfig(((BaseUnityPlugin)this).Config);
			Sync.GatedBy((Func<bool>)(() => Settings == null || Settings.LockConfiguration)).WatchForChanges(((BaseUnityPlugin)this).Config).Start();
			_harmony = new Harmony("nicks.haldorexpansion");
			int num = PatchIsolation.PatchAllIsolated(_harmony, typeof(Plugin).Assembly, Log);
			Log.LogInfo((object)("Haldor Expansion 0.4.0 loaded." + ((num > 0) ? (" " + num + " patch class(es) skipped - see the errors above.") : "")));
			Log.LogInfo((object)("Trade table hash: " + TradeTable.Hash + " -- on a server, clients should match this after config sync."));
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	internal static class PrefabCache
	{
		private static readonly Dictionary<string, ItemDrop> Cache = new Dictionary<string, ItemDrop>();

		private static readonly HashSet<string> Reported = new HashSet<string>();

		public static ItemDrop Resolve(string prefabName)
		{
			if (Cache.TryGetValue(prefabName, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			ObjectDB instance = ObjectDB.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return null;
			}
			GameObject itemPrefab = instance.GetItemPrefab(prefabName);
			if ((Object)(object)itemPrefab == (Object)null)
			{
				Warn(prefabName, "not found in ObjectDB");
				return null;
			}
			ItemDrop component = itemPrefab.GetComponent<ItemDrop>();
			if ((Object)(object)component == (Object)null)
			{
				Warn(prefabName, "found in ObjectDB but has no ItemDrop component");
				return null;
			}
			Cache[prefabName] = component;
			return component;
		}

		public static void Reset()
		{
			Cache.Clear();
			Reported.Clear();
		}

		private static void Warn(string prefabName, string reason)
		{
			if (Reported.Add(prefabName))
			{
				Plugin.Log.LogError((object)("Prefab '" + prefabName + "' " + reason + ". This row will not appear in the shop. Check the ITEM CANDIDATES section of the diagnostics dump for the correct spelling."));
			}
		}
	}
	internal static class SuperMistTorch
	{
		internal const string PrefabName = "SuperMistTorch";

		internal const string PiecePrefabName = "SuperMistTorchPiece";

		private const string DisplayName = "Super Mist Torch";

		private const string Description = "A towering wisp torch. Clears mist in a vast circle around it.";

		private const string CloneSourcePiece = "piece_groundtorch_mist";

		private const string ItemCloneSource = "Wood";

		private const int MaxStackSize = 1;

		private const float ItemWeight = 10f;

		private const float VisualScale = 2f;

		private const float WorldDemistRadius = 100f;

		private static GameObject _itemPrefab;

		private static GameObject _piecePrefab;

		private static GameObject _prefabContainer;

		private static PieceTable _pieceTable;

		internal static GameObject Prefab => _itemPrefab;

		internal static GameObject PiecePrefab => _piecePrefab;

		internal static ItemDrop ItemDrop
		{
			get
			{
				if (!((Object)(object)_itemPrefab != (Object)null))
				{
					return null;
				}
				return _itemPrefab.GetComponent<ItemDrop>();
			}
		}

		private static TradeEntry TradeEntry
		{
			get
			{
				TradeEntry[] haldor = TradeTable.Haldor;
				foreach (TradeEntry tradeEntry in haldor)
				{
					if (tradeEntry.PrefabName == "SuperMistTorch")
					{
						return tradeEntry;
					}
				}
				return null;
			}
		}

		internal static void RefreshFromConfig()
		{
			ApplyEnabledToPieceTable();
		}

		internal static void EnsureRegistered(ObjectDB odb)
		{
			if (!((Object)(object)odb == (Object)null) && odb.m_items != null && EnsureBuilt())
			{
				if (!odb.m_items.Contains(_itemPrefab))
				{
					odb.m_items.Add(_itemPrefab);
					odb.UpdateRegisters();
					Plugin.Log.LogInfo((object)"Registered SuperMistTorch with ObjectDB.");
				}
				ApplyEnabledToPieceTable();
			}
		}

		internal static void EnsureNetworkRegistered(ZNetScene scene)
		{
			if (!((Object)(object)scene == (Object)null) && EnsureBuilt())
			{
				RegisterWithScene(scene, _piecePrefab);
				RegisterWithScene(scene, _itemPrefab);
				EnsureRegistered(ObjectDB.instance);
			}
		}

		private static void RegisterWithScene(ZNetScene scene, GameObject prefab)
		{
			if (!((Object)(object)prefab == (Object)null))
			{
				if (!scene.m_prefabs.Contains(prefab))
				{
					scene.m_prefabs.Add(prefab);
				}
				int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)prefab).name);
				if (!scene.m_namedPrefabs.ContainsKey(stableHashCode))
				{
					scene.m_namedPrefabs[stableHashCode] = prefab;
					Plugin.Log.LogInfo((object)("Registered " + ((Object)prefab).name + " with ZNetScene."));
				}
			}
		}

		internal static void EnsureKnown(Player player)
		{
			if (!((Object)(object)player == (Object)null) && !((Object)(object)_piecePrefab == (Object)null) && (Plugin.Settings == null || Plugin.Settings.IsEnabled(TradeEntry)))
			{
				Piece component = _piecePrefab.GetComponent<Piece>();
				if (!((Object)(object)component == (Object)null) && !player.IsRecipeKnown(component.m_name))
				{
					player.AddKnownPiece(component);
				}
			}
		}

		private static bool EnsureBuilt()
		{
			if ((Object)(object)_itemPrefab != (Object)null && (Object)(object)_piecePrefab != (Object)null)
			{
				return true;
			}
			EnsureContainer();
			if ((Object)(object)_piecePrefab == (Object)null)
			{
				_piecePrefab = BuildPiecePrefab();
				if ((Object)(object)_piecePrefab == (Object)null)
				{
					return false;
				}
			}
			if ((Object)(object)_itemPrefab == (Object)null)
			{
				_itemPrefab = BuildItemPrefab();
				if ((Object)(object)_itemPrefab == (Object)null)
				{
					return false;
				}
			}
			WirePieceToItem();
			return true;
		}

		private static void EnsureContainer()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			if (!((Object)(object)_prefabContainer != (Object)null))
			{
				_prefabContainer = new GameObject("HaldorExpansionPrefabs");
				_prefabContainer.SetActive(false);
				Object.DontDestroyOnLoad((Object)(object)_prefabContainer);
			}
		}

		private static GameObject BuildPiecePrefab()
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			ZNetScene instance = ZNetScene.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return null;
			}
			GameObject prefab = instance.GetPrefab("piece_groundtorch_mist");
			if ((Object)(object)prefab == (Object)null)
			{
				Plugin.Log.LogError((object)"Cannot build SuperMistTorchPiece: ZNetScene has no 'piece_groundtorch_mist'.");
				return null;
			}
			GameObject val = Object.Instantiate<GameObject>(prefab, _prefabContainer.transform);
			((Object)val).name = "SuperMistTorchPiece";
			val.transform.localScale = prefab.transform.localScale * 2f;
			Piece component = val.GetComponent<Piece>();
			if ((Object)(object)component == (Object)null)
			{
				Plugin.Log.LogError((object)"Cannot build SuperMistTorchPiece: 'piece_groundtorch_mist' has no Piece.");
				Object.Destroy((Object)(object)val);
				return null;
			}
			component.m_name = "Super Mist Torch";
			component.m_description = "A towering wisp torch. Clears mist in a vast circle around it.";
			component.m_craftingStation = null;
			ConfigureDemisterRadius(val);
			Plugin.Log.LogInfo((object)("Built SuperMistTorchPiece from piece_groundtorch_mist (scale x" + 2f + ", demist " + 100f + " m)."));
			return val;
		}

		private static GameObject BuildItemPrefab()
		{
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			ObjectDB instance = ObjectDB.instance;
			GameObject val = (((Object)(object)instance != (Object)null) ? instance.GetItemPrefab("Wood") : null);
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogDebug((object)"Deferring SuperMistTorch build: ObjectDB has no 'Wood' to clone the item from yet.");
				return null;
			}
			if ((Object)(object)val.GetComponent<ItemDrop>() == (Object)null)
			{
				Plugin.Log.LogError((object)"Cannot build SuperMistTorch: the 'Wood' prefab has no ItemDrop to clone.");
				return null;
			}
			GameObject val2 = Object.Instantiate<GameObject>(val, _prefabContainer.transform);
			((Object)val2).name = "SuperMistTorch";
			ItemDrop component = val2.GetComponent<ItemDrop>();
			SharedData shared = component.m_itemData.m_shared;
			shared.m_name = "Super Mist Torch";
			shared.m_description = "A towering wisp torch. Clears mist in a vast circle around it.";
			shared.m_itemType = (ItemType)19;
			shared.m_buildPieces = EnsurePieceTable();
			shared.m_useDurability = false;
			shared.m_maxQuality = 1;
			shared.m_maxStackSize = 1;
			shared.m_weight = 10f;
			Piece val3 = (((Object)(object)_piecePrefab != (Object)null) ? _piecePrefab.GetComponent<Piece>() : null);
			if ((Object)(object)val3 != (Object)null && (Object)(object)val3.m_icon != (Object)null)
			{
				shared.m_icons = (Sprite[])(object)new Sprite[1] { val3.m_icon };
			}
			component.m_itemData.m_dropPrefab = val2;
			component.m_itemData.m_stack = 1;
			Plugin.Log.LogInfo((object)"Built SuperMistTorch from Wood.");
			return val2;
		}

		private static void WirePieceToItem()
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Expected O, but got Unknown
			Piece val = (((Object)(object)_piecePrefab != (Object)null) ? _piecePrefab.GetComponent<Piece>() : null);
			ItemDrop itemDrop = ItemDrop;
			if (!((Object)(object)val == (Object)null) && !((Object)(object)itemDrop == (Object)null))
			{
				val.m_resources = (Requirement[])(object)new Requirement[1]
				{
					new Requirement
					{
						m_resItem = itemDrop,
						m_amount = 1,
						m_amountPerLevel = 0,
						m_recover = true
					}
				};
			}
		}

		private static PieceTable EnsurePieceTable()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_pieceTable != (Object)null)
			{
				return _pieceTable;
			}
			GameObject val = new GameObject("SuperMistTorchPieceTable");
			val.transform.SetParent(_prefabContainer.transform);
			Piece val2 = (((Object)(object)_piecePrefab != (Object)null) ? _piecePrefab.GetComponent<Piece>() : null);
			_pieceTable = val.AddComponent<PieceTable>();
			_pieceTable.m_pieces = new List<GameObject>();
			_pieceTable.m_categories = new List<PieceCategory> { (PieceCategory)(((Object)(object)val2 != (Object)null) ? ((int)val2.m_category) : 0) };
			_pieceTable.m_canRemovePieces = false;
			_pieceTable.m_canRemoveFeasts = false;
			_pieceTable.m_hideAdvancedMenu = true;
			_pieceTable.m_skill = (SkillType)0;
			return _pieceTable;
		}

		private static void ApplyEnabledToPieceTable()
		{
			if (!((Object)(object)_piecePrefab == (Object)null) && !((Object)(object)_pieceTable == (Object)null))
			{
				TradeEntry tradeEntry = TradeEntry;
				bool flag = tradeEntry == null || Plugin.Settings == null || Plugin.Settings.IsEnabled(tradeEntry);
				bool flag2 = _pieceTable.m_pieces.Contains(_piecePrefab);
				if (flag && !flag2)
				{
					_pieceTable.m_pieces.Add(_piecePrefab);
				}
				else if (!flag && flag2)
				{
					_pieceTable.m_pieces.Remove(_piecePrefab);
				}
			}
		}

		internal static void UnequipIfDepleted(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return;
			}
			ItemData rightItem = ((Humanoid)player).GetRightItem();
			if (rightItem?.m_shared != null && !(rightItem.m_shared.m_name != "Super Mist Torch"))
			{
				Inventory inventory = ((Humanoid)player).GetInventory();
				if (inventory != null && !inventory.ContainsItem(rightItem))
				{
					((Humanoid)player).UnequipItem(rightItem, false);
				}
			}
		}

		private static void ConfigureDemisterRadius(GameObject clone)
		{
			float num = 50f;
			int num2 = 0;
			ParticleSystemForceField[] componentsInChildren = clone.GetComponentsInChildren<ParticleSystemForceField>(true);
			foreach (ParticleSystemForceField val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null))
				{
					if (val.endRange > 0f)
					{
						float num3 = val.startRange / val.endRange;
						val.endRange = num;
						val.startRange = num * num3;
					}
					else
					{
						val.endRange = num;
					}
					num2++;
				}
			}
			if (num2 == 0)
			{
				Plugin.Log.LogWarning((object)"SuperMistTorchPiece has no ParticleSystemForceField; demist radius was not changed.");
			}
		}
	}
	[HarmonyPatch(typeof(Trader), "GetAvailableItems")]
	internal static class TraderGetAvailableItemsPatch
	{
		private static readonly EffectList NoBuyEffects = new EffectList();

		private static void Postfix(Trader __instance, List<TradeItem> __result)
		{
			//IL_00a2: 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_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: 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_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: 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_010e: Expected O, but got Unknown
			if ((Object)(object)__instance == (Object)null || __result == null)
			{
				return;
			}
			Diagnostics.DumpOnce(__instance, __result);
			SuperMistTorch.RefreshFromConfig();
			if (PrefabName(((Component)__instance).gameObject) != "Haldor")
			{
				return;
			}
			EffectList buyPlayerEffects = BuyEffectsFrom(__instance);
			TradeEntry[] haldor = TradeTable.Haldor;
			foreach (TradeEntry tradeEntry in haldor)
			{
				if ((Plugin.Settings == null || Plugin.Settings.IsEnabled(tradeEntry)) && IsUnlocked(tradeEntry))
				{
					ItemDrop val = PrefabCache.Resolve(tradeEntry.PrefabName);
					if (!((Object)(object)val == (Object)null))
					{
						int price = ((Plugin.Settings != null) ? Plugin.Settings.GetPurchasePrice(tradeEntry) : tradeEntry.Price);
						__result.Add(new TradeItem
						{
							m_prefab = val,
							m_stack = tradeEntry.Stack,
							m_price = price,
							m_requiredGlobalKey = "",
							m_buyPlayerEffects = buyPlayerEffects,
							m_levelUpEffect = false,
							m_name = tradeEntry.PrefabName,
							m_tooltip = "",
							m_buyKey = "",
							m_incrementKey = ""
						});
					}
				}
			}
		}

		private static EffectList BuyEffectsFrom(Trader trader)
		{
			List<TradeItem> items = trader.m_items;
			if (items == null)
			{
				return NoBuyEffects;
			}
			foreach (TradeItem item in items)
			{
				if (item != null && !((Object)(object)item.m_prefab == (Object)null) && string.IsNullOrEmpty(item.m_buyKey) && item.m_buyPlayerEffects != null && item.m_buyPlayerEffects.HasEffects())
				{
					return item.m_buyPlayerEffects;
				}
			}
			return NoBuyEffects;
		}

		private static bool IsUnlocked(TradeEntry entry)
		{
			string text = ((Plugin.Settings != null) ? Plugin.Settings.GetRequiredGlobalKey(entry) : UnlockBossKeys.Get(entry.DefaultUnlockBoss));
			if (string.IsNullOrEmpty(text))
			{
				return true;
			}
			ZoneSystem instance = ZoneSystem.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return false;
			}
			return instance.GetGlobalKey(text);
		}

		private static string PrefabName(GameObject go)
		{
			if ((Object)(object)go == (Object)null)
			{
				return string.Empty;
			}
			string name = ((Object)go).name;
			int num = name.IndexOf("(Clone)");
			if (num < 0)
			{
				return name;
			}
			return name.Substring(0, num);
		}
	}
	internal enum UnlockBoss
	{
		None,
		Eikthyr,
		Elder,
		Bonemass,
		Moder,
		Yagluth,
		Queen,
		Fader
	}
	internal static class UnlockBossKeys
	{
		public static string Get(UnlockBoss boss)
		{
			return boss switch
			{
				UnlockBoss.Eikthyr => "defeated_eikthyr", 
				UnlockBoss.Elder => "defeated_gdking", 
				UnlockBoss.Bonemass => "defeated_bonemass", 
				UnlockBoss.Moder => "defeated_dragon", 
				UnlockBoss.Yagluth => "defeated_goblinking", 
				UnlockBoss.Queen => "defeated_queen", 
				UnlockBoss.Fader => "defeated_fader", 
				_ => null, 
			};
		}
	}
	internal sealed class TradeEntry
	{
		public readonly string PrefabName;

		public readonly int Stack;

		public readonly int Price;

		public readonly UnlockBoss DefaultUnlockBoss;

		public int PricePerUnit
		{
			get
			{
				if (Stack <= 0)
				{
					return Price;
				}
				return Price / Stack;
			}
		}

		public TradeEntry(string prefabName, int stack, int price, UnlockBoss defaultUnlockBoss = UnlockBoss.None)
		{
			PrefabName = prefabName;
			Stack = stack;
			Price = price;
			DefaultUnlockBoss = defaultUnlockBoss;
		}
	}
	internal static class TradeTable
	{
		public const string HaldorPrefab = "Haldor";

		public static readonly TradeEntry[] Haldor = new TradeEntry[6]
		{
			new TradeEntry("Wood", 50, 50, UnlockBoss.Elder),
			new TradeEntry("Stone", 50, 50, UnlockBoss.Elder),
			new TradeEntry("Grausten", 50, 100, UnlockBoss.Queen),
			new TradeEntry("Blackwood", 50, 100, UnlockBoss.Queen),
			new TradeEntry("SurtlingCore", 5, 500, UnlockBoss.Bonemass),
			new TradeEntry("SuperMistTorch", 1, 100, UnlockBoss.Queen)
		};

		public static string Hash
		{
			get
			{
				StringBuilder stringBuilder = new StringBuilder();
				ModConfig settings = Plugin.Settings;
				TradeEntry[] haldor = Haldor;
				foreach (TradeEntry tradeEntry in haldor)
				{
					bool flag = settings?.IsEnabled(tradeEntry) ?? true;
					int value = settings?.GetPurchasePrice(tradeEntry) ?? tradeEntry.Price;
					UnlockBoss unlockBoss = settings?.GetUnlockBoss(tradeEntry) ?? tradeEntry.DefaultUnlockBoss;
					stringBuilder.Append(tradeEntry.PrefabName).Append('|').Append(flag ? "1" : "0")
						.Append('|')
						.Append(tradeEntry.Stack)
						.Append('|')
						.Append(value)
						.Append('|')
						.Append(unlockBoss)
						.Append(';');
				}
				ulong num = 14695981039346656037uL;
				string text = stringBuilder.ToString();
				foreach (char c in text)
				{
					num ^= c;
					num *= 1099511628211L;
				}
				return num.ToString("x16");
			}
		}
	}
}
namespace MushroomMods
{
	internal static class PatchIsolation
	{
		internal static int PatchAllIsolated(Harmony harmony, Assembly assembly, ManualLogSource log)
		{
			int num = 0;
			Type[] typesFromAssembly = AccessTools.GetTypesFromAssembly(assembly);
			foreach (Type type in typesFromAssembly)
			{
				try
				{
					harmony.CreateClassProcessor(type).Patch();
				}
				catch (Exception ex)
				{
					num++;
					log.LogError((object)("Harmony patch class " + type.FullName + " was skipped and the rest of " + harmony.Id + " is still active. " + ex));
				}
			}
			return num;
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}