Decompiled source of ZenWorldSettings v1.7.3

plugins/ZenWorldSettings.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using JetBrains.Annotations;
using Jotunn.Configs;
using Jotunn.Extensions;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.SceneManagement;
using Zen;
using Zen.Compatibility;
using Zen.Interop;
using Zen.Lib;
using Zen.Lib.Config;
using ZenWorldSettings.Sections;
using ZenWorldSettings.Sections.Fireplaces;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ZenWorldSettings")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ZenWorldSettings")]
[assembly: AssemblyCopyright("Copyright \ufffd  2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")]
[assembly: AssemblyFileVersion("0.0.1.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.1.0")]
[module: RefSafetyRules(11)]
[CompilerGenerated]
internal delegate void <>f__AnonymousDelegate0<T1, T2, T3>(T1 arg1, T2 arg2, params T3[] arg3);
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;
		}
	}
}
namespace ZenWorldSettings
{
	[Disable(new Type[] { typeof(TombStone) })]
	[BepInIncompatibility("org.bepinex.plugins.hildirsquest")]
	[BepInPlugin("ZenDragon.ZenWorldSettings", "ZenWorldSettings", "1.7.3")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	internal class Plugin : ZenMod<Plugin>
	{
		public const string PluginName = "ZenWorldSettings";

		public const string PluginVersion = "1.7.3";

		public const string PluginGUID = "ZenDragon.ZenWorldSettings";

		protected override void Setup()
		{
			((ZenMod)this).RunOnServer = true;
			base.ConfigSync += DoorKeys.InitKeys;
			base.ConfigSync += CraftTeleportRules.Init;
			base.ConfigSync += BurnAnything.SetupKiln;
			base.ConfigSync += CampfireRules.InitPrefab;
			SpawnerRules.InitTerminal();
		}

		protected override void TitleScene(bool isFirstBoot)
		{
		}

		protected override void HotRestore()
		{
			DoorKeys.InitKeys();
		}

		protected override void WorldStart()
		{
			EnvironmentRules.Start();
			TurretRules.Start();
			ShieldGen.Start();
			DoorKeys.UpdateRecipes();
			Quests.RegisterRPC();
		}

		protected override void Shutdown()
		{
			TurretRules.Shutdown();
			ShieldGen.Shutdown();
			DoorKeys.Shutdown();
			Quests.Shutdown();
		}
	}
}
namespace ZenWorldSettings.Sections
{
	[HarmonyPatch]
	internal static class LootContainers
	{
		private static class Configs
		{
			private const string SECTION_LOOT_CONTAINER = "Loot - Containers";

			public static readonly ConfigEntry<StringList> LimitedUseContainers;

			public static readonly ConfigEntry<int> LimitedUseMax;

			static Configs()
			{
				//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_001b: Expected O, but got Unknown
				//IL_001b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0026: Expected O, but got Unknown
				//IL_0030: Expected O, but got Unknown
				StringList val = new StringList();
				((List<string>)val).Add("Player_tombstone");
				((List<string>)val).Add("CargoCrate");
				LimitedUseContainers = Config.Define<StringList>(true, "Loot - Containers", "Limited Use Containers", val, "Some containers are free indestructable storage that can be exploited.\r\nAdd any prefab names of containers that should have a limited number of uses before thy self destruct.\r\nContents are dropped on the ground when they break.");
				LimitedUseMax = Config.Define<int>(true, "Loot - Containers", "Limited Use Max", 5, Config.AcceptRange<int>(1, 9), "The max number of times a limited use container can be opened before it breaks appart.");
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(InventoryGui), "Hide")]
		[HarmonyPriority(800)]
		private static void InventoryGui_Hide(InventoryGui __instance)
		{
			if (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || ((Character)Player.m_localPlayer).InGodMode())
			{
				return;
			}
			Container currentContainer = __instance.m_currentContainer;
			if (currentContainer.IsLimitedUse())
			{
				if (!currentContainer.m_nview.IsOwner())
				{
					currentContainer.m_nview.ClaimOwnership();
				}
				ZDO zDO = currentContainer.m_nview.GetZDO();
				int @int = zDO.GetInt(ZDOVars.s_pickedUp, 0);
				@int++;
				zDO.Set(ZDOVars.s_pickedUp, @int, false);
				if (currentContainer.GetInventory().NrOfItems() > 0)
				{
					((Character)Player.m_localPlayer).Message((MessageType)2, "$container_decay", 0, (Sprite)null);
				}
				if (@int >= Configs.LimitedUseMax.Value)
				{
					DestroyAfterDelay(currentContainer);
				}
			}
		}

		private static void DestroyAfterDelay(Container container)
		{
			Container container2 = container;
			Timing.Delay((MonoBehaviour)(object)container2, 2f, (Action)delegate
			{
				if (Object.op_Implicit((Object)(object)container2) && Object.op_Implicit((Object)(object)container2.m_nview) && container2.m_nview.IsValid())
				{
					InventoryGui instance = InventoryGui.instance;
					if (Object.op_Implicit((Object)(object)instance) && !((Object)(object)instance.m_currentContainer == (Object)(object)container2))
					{
						container2.DropAllItems();
						TombStone val = default(TombStone);
						Destructible val2 = default(Destructible);
						if (((Component)container2).TryGetComponent<TombStone>(ref val))
						{
							val.UpdateDespawn();
						}
						else if (((Component)container2).TryGetComponent<Destructible>(ref val2))
						{
							val2.Destroy((HitData)null);
						}
						else
						{
							container2.m_nview.Destroy();
						}
					}
				}
			});
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Container), "GetHoverText")]
		[HarmonyPriority(100)]
		private static void Container_GetHoverText(Container __instance, ref string __result)
		{
			__result += GetHoverTextContainerDecay(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(TombStone), "GetHoverText")]
		[HarmonyPriority(100)]
		private static void TombStone_GetHoverText(TombStone __instance, ref string __result)
		{
			__result += GetHoverTextContainerDecay(__instance.m_container);
		}

		private static string GetHoverTextContainerDecay(Container c)
		{
			if (!c.IsLimitedUse())
			{
				return string.Empty;
			}
			ZDO zDO = c.m_nview.GetZDO();
			int value = Configs.LimitedUseMax.Value;
			int num = Mathf.Clamp(zDO.GetInt(ZDOVars.s_pickedUp, 0), 0, value);
			if (num <= 0)
			{
				return string.Empty;
			}
			string arg = UI.CreateMeter("◉", "◉", UIColor.MajorInfo, UIColor.DarkOrange, (float)(value - num), (float)value, value);
			return StringExt.Localize($"\n\n<color={UIColor.MajorInfo}>$container_decay\n{arg}</color>");
		}

		private static bool IsLimitedUse(this Container? c)
		{
			if (!Object.op_Implicit((Object)(object)c) || !Object.op_Implicit((Object)(object)c.m_nview) || !c.m_nview.IsValid())
			{
				return false;
			}
			string prefabName = c.m_nview.GetPrefabName();
			return Configs.LimitedUseContainers.Value.Contains(prefabName, true);
		}
	}
	[HarmonyPatch]
	internal static class DoorKeys
	{
		private static class Configs
		{
			private const string SECTION_DOOR_KEYS = "Door Keys";

			public static readonly ConfigEntry<int> UsageLimit = Config.Define<int>(true, "Door Keys", "Usage Limit", 1, Config.AcceptRange<int>(0, 10), "Door keys break after this many uses.  Set to 0 for infinite use. (Vanilla: 0)\r\nThis is the initial number of uses for level 1 keys. Upgrades add more uses.\r\nNote: The default config settings allow keys to be repaired at the forge.\r\n[logout required for changes to take effect]");

			public static readonly ConfigEntry<StringList> UpgradeCost;

			public static readonly ConfigEntry<int> MaxQuality;

			public static readonly ConfigEntry<int> StationLevel;

			public static readonly ConfigEntry<string> Station;

			public static readonly ConfigEntry<bool> Repairable;

			public static readonly ConfigEntry<StringList> IndestructibleDoorKeys;

			public static readonly ConfigEntry<StringList> RemoveBrokenKeys;

			static Configs()
			{
				//IL_002e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0033: Unknown result type (might be due to invalid IL or missing references)
				//IL_003e: Expected O, but got Unknown
				//IL_003e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0049: Expected O, but got Unknown
				//IL_0053: Expected O, but got Unknown
				StringList val = new StringList();
				((List<string>)val).Add("Iron:1:1");
				((List<string>)val).Add("Guck:1:1");
				UpgradeCost = Config.Define<StringList>(true, "Door Keys", "Upgrade Cost", val, "Comma separated list of resource requirements for upgrading keys.\r\nPrefabName:Cost:IncreasedCostPerLevel\r\n[logout required for changes to take effect]");
				MaxQuality = Config.Define<int>(true, "Door Keys", "Max Quality", 4, Config.AcceptRange<int>(1, 9), "Max quality that door keys can be leveled up.  (Vanilla: 1)\r\nEach level increases the number of uses by 1.\r\nSet to 1 to disable upgrading keys.\r\n[logout required for changes to take effect]");
				StationLevel = Config.Define<int>(true, "Door Keys", "Station Level", 3, Config.AcceptRange<int>(1, 7), "Minimum station level needed to repair keys.\r\nNOTE: Upgrade requires +1 to this level\r\n[logout required for changes to take effect]");
				Station = Config.Define<string>(true, "Door Keys", "Station", "Forge", CraftingStations.GetAcceptableValueList(), "The station that can be used to repair and upgrade any keys that are NOT crafted, such as keys dropped from monsters, or found in chests, or purchased.\r\nIf the key is crafted then it repairs and upgrades at the station that was used to craft it.\r\n[logout required for changes to take effect]");
				Repairable = Config.Define<bool>(true, "Door Keys", "Repairable", true, "If true then keys can be repaired when broken. This requires a " + ((ConfigEntryBase)Station).Definition.Key + "\r\nA broken key can not be used to open a door.\r\n[logout required for changes to take effect]");
				IndestructibleDoorKeys = Config.Define<StringList>(true, "Door Keys", "Indestructible Keys", StringList.Empty, "Comma separted list of item prefab names for Door Keys that should never break.\r\nThese keys will be ignored by the system.\r\n[logout required for changes to take effect]");
				RemoveBrokenKeys = Config.Define<StringList>(true, "Door Keys", "Remove Broken Keys", StringList.Empty, "Comma separated list of key prefab names.\r\nKeys will be removed from the inventory when they break.\r\nAny existing broken keys in your inventory will not be affected.\r\nThis will override the repair configs since the key will be erased when it breaks.\r\nExample: CryptKey");
			}
		}

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

		private static readonly List<Recipe> KeyRecipes = new List<Recipe>();

		private static bool IsKeysUnlimited => Configs.UsageLimit.Value == 0;

		internal static void Shutdown()
		{
			RemoveUpgradeRecipes();
		}

		private static void RemoveUpgradeRecipes()
		{
			foreach (Recipe keyRecipe in KeyRecipes)
			{
				ObjectDB.instance.m_recipes.Remove(keyRecipe);
				Object.Destroy((Object)(object)keyRecipe);
			}
			KeyRecipes.Clear();
		}

		public static void InitKeys()
		{
			Logging<Plugin>.Info((object)"Setup door keys", 0);
			RemoveUpgradeRecipes();
			KeyNames.Clear();
			if (IsKeysUnlimited)
			{
				Logging<Plugin>.Info((object)"Usage limit set to infinite in configs", 0);
				return;
			}
			foreach (GameObject prefab in ZNetScene.instance.m_prefabs)
			{
				Door componentInChildren = prefab.GetComponentInChildren<Door>();
				if (Object.op_Implicit((Object)(object)componentInChildren) && Object.op_Implicit((Object)(object)componentInChildren.m_keyItem))
				{
					ItemDrop keyItem = componentInChildren.m_keyItem;
					string prefabName = ItemDataExt.GetPrefabName(keyItem);
					Logging<Plugin>.Info((object)("Door " + ((Object)prefab).name + " has key: " + prefabName), 0);
					if (!KeyNames.Add(prefabName))
					{
						Logging<Plugin>.Info((object)("Key " + prefabName + " already added, skipping"), 0);
					}
					else if (IsLimitedUseKey(prefabName))
					{
						InitKeyItem(keyItem.m_itemData);
						InitKeyRecipe(keyItem);
					}
				}
			}
		}

		private static void InitKeyItem(ItemData doorKey)
		{
			Logging<Plugin>.Info((object)("Setup the the door key: " + ItemDataExt.GetName(doorKey)), 0);
			doorKey.m_shared.m_useDurability = true;
			doorKey.m_shared.m_maxDurability = Configs.UsageLimit.Value;
			doorKey.m_shared.m_canBeReparied = Configs.Repairable.Value && Configs.Station.Value != CraftingStations.None;
			doorKey.m_shared.m_durabilityPerLevel = 1f;
			doorKey.m_shared.m_maxQuality = Configs.MaxQuality.Value;
			doorKey.m_durability = Mathf.Min(doorKey.m_durability, doorKey.GetMaxDurability());
		}

		private static void InitKeyRecipe(ItemDrop doorKey)
		{
			string prefabName = ItemDataExt.GetPrefabName(doorKey);
			Logging<Plugin>.Info((object)("Init limited use key recipe: " + prefabName), 0);
			if (!doorKey.m_itemData.m_shared.m_canBeReparied)
			{
				Logging<Plugin>.Info((object)(prefabName + " can not be repaired, not configured or no repair station defined."), 0);
				return;
			}
			Recipe recipe = ObjectDB.instance.GetRecipe(doorKey.m_itemData);
			if (Object.op_Implicit((Object)(object)recipe))
			{
				Logging<Plugin>.Info((object)("Recipe already exists: " + prefabName), 0);
				return;
			}
			Logging<Plugin>.Info((object)("Adding repair/upgrade recipe: " + prefabName), 0);
			bool flag = doorKey.m_itemData.m_shared.m_maxQuality > 1;
			recipe = ScriptableObject.CreateInstance<Recipe>();
			recipe.m_item = doorKey;
			recipe.m_enabled = flag;
			recipe.m_resources = Configs.UpgradeCost.Value.ToRequirements(':');
			CraftingStation craftingStation = PrefabManagerExt.GetCraftingStation(PrefabManager.Instance, Configs.Station.Value);
			recipe.m_craftingStation = (flag ? craftingStation : null);
			recipe.m_repairStation = craftingStation;
			recipe.m_minStationLevel = Configs.StationLevel.Value;
			KeyRecipes.Add(recipe);
		}

		private static bool IsLimitedUseKey(string prefabName)
		{
			if (Utility.IsNullOrWhiteSpace(prefabName))
			{
				return false;
			}
			if (KeyNames.Contains(prefabName))
			{
				return !Configs.IndestructibleDoorKeys.Value.Contains(prefabName, true);
			}
			return false;
		}

		private static ItemData? FindLimitedKey(this Inventory inventory, string keyPrefabName)
		{
			string keyPrefabName2 = keyPrefabName;
			if (!IsLimitedUseKey(keyPrefabName2))
			{
				return null;
			}
			return ((IEnumerable<ItemData>)(from item in inventory.GetAllItems()
				orderby item.m_durability
				select item)).FirstOrDefault((Func<ItemData, bool>)((ItemData item) => ItemDataExt.GetPrefabName(item) == keyPrefabName2 && item.m_durability > 0f));
		}

		private static void DegradeItem(this Player player, ItemData key)
		{
			Inventory inventory = ((Humanoid)player).GetInventory();
			key.m_durability = Mathf.Clamp(key.m_durability - 1f, 0f, key.GetMaxDurability());
			inventory.Changed();
			if (!(key.m_durability > 0f))
			{
				Logging<Plugin>.Info((object)("Item broke " + ItemDataExt.GetName(key)), 0);
				((Character)player).Message((MessageType)2, StringExt.Localize("$msg_broke", new string[1] { ItemDataExt.GetName(key) }), 0, (Sprite)null);
				if (Configs.RemoveBrokenKeys.Value.Contains(ItemDataExt.GetPrefabName(key), true))
				{
					Logging<Plugin>.Info((object)("Removing key " + ItemDataExt.GetPrefabName(key) + " from inventory"), 0);
					inventory.RemoveItem(key);
				}
			}
		}

		private static void UseLimitedKey(this Player player, string keyPrefabName)
		{
			ItemData val = ((Humanoid)player).GetInventory().FindLimitedKey(keyPrefabName);
			if (val != null)
			{
				player.DegradeItem(val);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Door), "Interact")]
		private static void Door_Interact(Door __instance, Humanoid character, bool hold, bool alt, bool __result)
		{
			if (!IsKeysUnlimited && !(hold || alt) && __result && Object.op_Implicit((Object)(object)__instance.m_keyItem))
			{
				Player val = (Player)(object)((character is Player) ? character : null);
				if (val != null)
				{
					val.UseLimitedKey(ItemDataExt.GetPrefabName(__instance.m_keyItem));
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Door), "HaveKey")]
		private static void Door_HaveKey(Door __instance, Humanoid player, ref bool __result)
		{
			if (!IsKeysUnlimited && Object.op_Implicit((Object)(object)__instance.m_keyItem) && __result)
			{
				__result = player.GetInventory().FindLimitedKey(ItemDataExt.GetPrefabName(__instance.m_keyItem)) != null;
			}
		}

		internal static void UpdateRecipes()
		{
			List<Recipe> recipes = ObjectDB.instance.m_recipes;
			Logging<Plugin>.Info((object)$"UpgradeKeyRecipes Count: {KeyRecipes.Count}", 0);
			foreach (Recipe keyRecipe in KeyRecipes)
			{
				Logging<Plugin>.Info((object)("Add recipe: " + ItemDataExt.GetPrefabName(keyRecipe.m_item)), 0);
				if (!recipes.Contains(keyRecipe))
				{
					recipes.Add(keyRecipe);
				}
			}
		}

		[HarmonyTranspiler]
		[HarmonyPatch(typeof(Player), "GetAvailableRecipes")]
		private static IEnumerable<CodeInstruction> Player_GetAvailableRecipes(IEnumerable<CodeInstruction> codes)
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(List<Recipe>), "Add", (Type[])null, (Type[])null);
			Action<List<Recipe>, Recipe> action = RecipeAdd_Intercept;
			return Transpilers.MethodReplacer(codes, (MethodBase)methodInfo, (MethodBase)action.Method);
		}

		private static void RecipeAdd_Intercept(List<Recipe> recipes, Recipe recipe)
		{
			if (KeyRecipes.Contains(recipe) && InventoryGui.instance.InCraftTab())
			{
				Logging<Plugin>.Info((object)("Skip recipe on crafting tab: " + ItemDataExt.GetPrefabName(recipe.m_item)), 0);
			}
			else
			{
				recipes.Add(recipe);
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Inventory), "AddItem", new Type[]
		{
			typeof(ItemData),
			typeof(int),
			typeof(int),
			typeof(int)
		})]
		private static void Inventory_AddItem(Inventory __instance, ItemData item)
		{
			if (!IsKeysUnlimited && IsLimitedUseKey(ItemDataExt.GetPrefabName(item)))
			{
				InitKeyItem(item);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(InventoryGui), "Update")]
		private static void InventoryGui_Update(InventoryGui __instance)
		{
			HandleAdminForcedKeyDegrade();
		}

		private static void HandleAdminForcedKeyDegrade()
		{
			if (InventoryGui.IsVisible() && Object.op_Implicit((Object)(object)Player.m_localPlayer) && ((Character)Player.m_localPlayer).InGodMode())
			{
				ItemData dragItem = InventoryGui.instance.m_dragItem;
				if (dragItem != null && ZInput.GetKey((KeyCode)303, true) && ZInput.GetKeyDown((KeyCode)305, true) && IsLimitedUseKey(ItemDataExt.GetPrefabName(dragItem)))
				{
					Logging<Plugin>.Warning((object)("DEBUG: " + ItemDataExt.GetPrefabName(dragItem) + " Removed Durability"), 0);
					Player.m_localPlayer.DegradeItem(dragItem);
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class CraftTeleportRules
	{
		private static class Configs
		{
			private const string CRAFT_TELEPORT = "Craft / Teleport";

			public static readonly ConfigEntry<StringList> CraftItemsDeny = Config.Define<StringList>(true, "Craft / Teleport", "Craft Items - Deny", StringList.Empty, "List of items to remove from crafting.\r\nRecipies are removed and new instances of the item can't be crafted.\r\nHowever, any existing items will still remain.  Additionlly any loot drops of the item will still be possible.\r\n[reboot required for changes to take effect]");

			public static readonly ConfigEntry<StringList> CraftPiecesDeny = Config.Define<StringList>(true, "Craft / Teleport", "Craft Pieces - Deny", StringList.Empty, "List of pieces which can not be crafted.\r\nHowever, nocost flag will still allow them to be built. Existing instances of pieces will still remain.\r\n[reboot required for changes to take effect]");

			public static readonly ConfigEntry<StringList> TeleportItemsDeny;

			public static readonly ConfigEntry<StringList> TeleportItemsAllow;

			static Configs()
			{
				//IL_0049: 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_0059: Expected O, but got Unknown
				//IL_0063: Expected O, but got Unknown
				//IL_0073: 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_0083: Expected O, but got Unknown
				//IL_008d: Expected O, but got Unknown
				StringList val = new StringList();
				((List<string>)val).Add("Thunderstone");
				TeleportItemsDeny = Config.Define<StringList>(true, "Craft / Teleport", "Teleport Items - Deny", val, "List of items which CAN NOT be teleported.\r\nWhy is Thunderstone default? \r\nBecause with ZenRecycle it becomes possible to reclaim materials via the Obliterator.\r\nRestriction of teleporting the Thunderstone makes it more challenging to setup a recycler at far away bases.\r\n[reboot required for changes to take effect]");
				StringList val2 = new StringList();
				((List<string>)val2).Add("Ironpit");
				TeleportItemsAllow = Config.Define<StringList>(true, "Craft / Teleport", "Teleport Items - Allow", val2, "List of items which CAN be teleported. \r\nMake items teleportable which would otherwise not be teleportable.\r\nCan be useful for example if you wanted to teleport refined metals but not ore:\r\nCopper, Tin, Bronze, Iron, Silver, BlackMetal, Flametal, FlametalNew\r\n[reboot required for changes to take effect]");
			}
		}

		internal static void Init()
		{
			DisableItems();
			DisablePieces();
			SetTeleportRules();
		}

		private static void SetTeleportRules()
		{
			foreach (string item in (List<string>)(object)Configs.TeleportItemsDeny.Value)
			{
				SetTeleport(item, state: false);
			}
			foreach (string item2 in (List<string>)(object)Configs.TeleportItemsAllow.Value)
			{
				SetTeleport(item2, state: true);
			}
			static void SetTeleport(string prefabName, bool state)
			{
				GameObject val = default(GameObject);
				if (ObjectDB.instance.TryGetItemPrefab(prefabName, ref val))
				{
					val.GetComponent<ItemDrop>().m_itemData.m_shared.m_teleportable = state;
					Logging<Plugin>.Info((object)$"AllowTeleport Item: {((Object)val).name} - {state}", 0);
				}
			}
		}

		private static void DisableItems()
		{
			if (((List<string>)(object)Configs.CraftItemsDeny.Value).Count == 0)
			{
				return;
			}
			foreach (Recipe recipe in ObjectDB.instance.m_recipes)
			{
				ItemDrop item = recipe.m_item;
				string text = ((item != null) ? ItemDataExt.GetPrefabName(item) : null) ?? string.Empty;
				if (Configs.CraftItemsDeny.Value.Contains(text, true))
				{
					recipe.m_enabled = false;
					Logging<Plugin>.Info((object)("NoCraft Item: " + text), 0);
				}
			}
		}

		private static void DisablePieces()
		{
			Piece val = default(Piece);
			foreach (string item in (List<string>)(object)Configs.CraftPiecesDeny.Value)
			{
				GameObject prefab = ZNetScene.instance.GetPrefab(item);
				if (Object.op_Implicit((Object)(object)prefab) && prefab.TryGetComponent<Piece>(ref val))
				{
					val.m_enabled = false;
					Logging<Plugin>.Info((object)("NoCraft Piece: " + ((Object)val).name), 0);
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class Loot
	{
		private static class Configs
		{
			private const string SECTION_LOOT = "Loot";

			public static readonly ConfigEntry<bool> DropPerPlayer = Config.Define<bool>(true, "Loot", "Drop Per Player", false, "Drop one Loot Item per player in range so that everyone can have a copy.");

			public static readonly ConfigEntry<StringList> LootItems = Config.Define<StringList>(true, "Loot", "Loot Items", StringList.Empty, "Comma separated list of items to drop per player.\r\nHildir's Quest items: chest_hildir1, chest_hildir2, chest_hildir3\r\nNOTE: Hildir's Quest items are not enabled by default because \r\nQuest Keys are flagged by proximity to the trader when turning in a chest.\r\nHowever, the item names are provided here for reference if desired.");

			public static readonly ConfigEntry<float> LootDropPlayerRange = Config.Define<float>(true, "Loot", "Player Range", 25f, Config.AcceptRange<float>(10f, 100f), "Range to check for players around the area when dropping loot per player.");

			public static readonly ConfigEntry<int> LootDespawnDays = Config.Define<int>(true, "Loot", "Item Despawn Days", 2, Config.AcceptRange<int>(0, 10), "Items despawn if they are in the wild after this many days. (Vanilla: 3600s aka 2days)\r\nThis opton changes the item despawn timer to use the environment's day duration instead of a fixed constant 3600s.\r\nIf set to 0 will disable this option and revert to vanilla's default static value of 3600s.\r\n(NOTE: If ZenRaids is installed then items are protected by firelight)");
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(CharacterDrop), "GenerateDropList")]
		private static void CharacterDrop_GenerateDropList(CharacterDrop __instance, List<KeyValuePair<GameObject, int>> __result)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			if (!Configs.DropPerPlayer.Value)
			{
				return;
			}
			int playersInRangeXZ = Player.GetPlayersInRangeXZ(((Component)__instance).transform.position, Configs.LootDropPlayerRange.Value);
			for (int i = 0; i < __result.Count; i++)
			{
				GameObject key = __result[i].Key;
				if (Configs.LootItems.Value.Contains(((Object)key).name, true))
				{
					__result[i] = new KeyValuePair<GameObject, int>(key, playersInRangeXZ);
					Logging<Plugin>.Info((object)$"Drop {((Object)key).name} per player x{playersInRangeXZ}", 0);
				}
			}
		}

		[HarmonyTranspiler]
		[HarmonyPatch(typeof(ItemDrop), "TimedDestruction")]
		[HarmonyPriority(100)]
		private static IEnumerable<CodeInstruction> ItemDrop_TimedDestruction(IEnumerable<CodeInstruction> codes)
		{
			Func<float> getDespawnTime = GetDespawnTime;
			return Transpilers.Manipulator(codes, (Func<CodeInstruction, bool>)IsVanillaDuration, (Action<CodeInstruction>)delegate(CodeInstruction c)
			{
				c.opcode = OpCodes.Call;
				c.operand = getDespawnTime.Method;
			});
			static float GetDespawnTime()
			{
				int value = Configs.LootDespawnDays.Value;
				float num = ((value > 0) ? ((float)(value * EnvMan.instance.m_dayLengthSec)) : 3600f);
				Logging<Plugin>.Debug((object)$"Item despawn time: {num}s", 0);
				return num;
			}
			static bool IsVanillaDuration(CodeInstruction c)
			{
				if (!CodeInstructionExtensions.Is(c, OpCodes.Ldc_R8, (object)3600f))
				{
					return CodeInstructionExtensions.Is(c, OpCodes.Ldc_R4, (object)3600f);
				}
				return true;
			}
		}
	}
	[HarmonyPatch]
	internal class PvPRules
	{
		private static class Configs
		{
			private const string SECTION_PVP = "PvP";

			public static readonly ConfigEntry<Mode> PvPMode = Config.Define<Mode>(true, "PvP", "PvP Mode", Mode.Toggleable, "Set the PvP mode for the world");

			public static readonly ConfigEntry<bool> CanKillTames = Config.Define<bool>(true, "PvP", "Can Kill Tames", false, "When true you can kill tames with any weapon in PvP mode, not just the Butcher Knife. (vanilla: true)");
		}

		private enum Mode : byte
		{
			Toggleable,
			War,
			Peace
		}

		private static bool _currentPvP;

		private static bool IsRequired()
		{
			return Configs.PvPMode.Value == Mode.War;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "Update")]
		private static void Player_Update(Player __instance)
		{
			if (Configs.PvPMode.Value == Mode.Toggleable)
			{
				return;
			}
			_currentPvP = IsRequired();
			if (__instance.m_pvp != _currentPvP)
			{
				__instance.SetPVP(_currentPvP);
				if (Object.op_Implicit((Object)(object)InventoryGui.instance))
				{
					InventoryGui.instance.m_pvp.isOn = _currentPvP;
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "CanSwitchPVP")]
		private static void Player_CanSwitchPVP(ref bool __result)
		{
			if (Configs.PvPMode.Value != 0)
			{
				__result = false;
			}
		}

		[HarmonyTranspiler]
		[HarmonyPatch(typeof(Attack), "DoMeleeAttack")]
		private static IEnumerable<CodeInstruction> Attack_DoMeleeAttack(IEnumerable<CodeInstruction> codes)
		{
			return Intercept_FindHitObject(codes);
		}

		[HarmonyTranspiler]
		[HarmonyPatch(typeof(Projectile), "OnHit")]
		private static IEnumerable<CodeInstruction> Projectile_OnHit(IEnumerable<CodeInstruction> codes)
		{
			return Intercept_FindHitObject(codes);
		}

		private static IEnumerable<CodeInstruction> Intercept_FindHitObject(IEnumerable<CodeInstruction> codes)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Expected O, but got Unknown
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(Projectile), "FindHitObject", (Type[])null, (Type[])null);
			Func<Collider, object, GameObject> func = HandlePvpAttackTame;
			CodeMatch[] array = (CodeMatch[])(object)new CodeMatch[1]
			{
				new CodeMatch((OpCode?)OpCodes.Call, (object)methodInfo, (string)null)
			};
			return new CodeMatcher(codes, (ILGenerator)null).MatchStartForward(array).ThrowIfInvalid("Unable to match IL sequence").Set(OpCodes.Call, (object)func.Method)
				.Insert((CodeInstruction[])(object)new CodeInstruction[1]
				{
					new CodeInstruction(OpCodes.Ldarg_0, (object)null)
				})
				.InstructionEnumeration();
		}

		private static GameObject? HandlePvpAttackTame(Collider collider, object caller)
		{
			GameObject val = Projectile.FindHitObject(collider);
			if (!Object.op_Implicit((Object)(object)val))
			{
				return null;
			}
			if (Configs.CanKillTames.Value)
			{
				return val;
			}
			Attack val2 = (Attack)((caller is Attack) ? caller : null);
			(Character, ItemData) tuple;
			if (val2 == null)
			{
				Projectile val3 = (Projectile)((caller is Projectile) ? caller : null);
				tuple = ((val3 == null) ? (null, null) : (val3.m_owner, val3.m_weapon));
			}
			else
			{
				tuple = ((Character)(object)val2.m_character, val2.m_weapon);
			}
			var (val4, val5) = tuple;
			if (!Object.op_Implicit((Object)(object)val4) || !val4.IsPlayer())
			{
				return val;
			}
			Character component = val.GetComponent<Character>();
			if (!Object.op_Implicit((Object)(object)component) || !component.IsTamed())
			{
				return val;
			}
			if (val5 != null)
			{
				SharedData shared = val5.m_shared;
				if (shared != null && shared.m_tamedOnly)
				{
					return val;
				}
			}
			return ((Component)val4).gameObject;
		}
	}
	[HarmonyPatch]
	internal static class Quests
	{
		private static class Configs
		{
			private const string SECTION_QUESTS = "Quests";

			public static readonly ConfigEntry<bool> PerPlayerQuests = Config.Define<bool>(true, "Quests", "Active Per Player", true, "Make quests such as Hidler's Quest per player instead of worldwide. (Vanilla: false)");

			public static readonly ConfigEntry<StringList> QuestKeys;

			public static readonly ConfigEntry<float> QuestKeyRange;

			public static readonly ConfigEntry<StringList> QuestTraders;

			static Configs()
			{
				//IL_0026: 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: Expected O, but got Unknown
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				//IL_0041: Expected O, but got Unknown
				//IL_0041: Unknown result type (might be due to invalid IL or missing references)
				//IL_004c: Expected O, but got Unknown
				//IL_0056: Expected O, but got Unknown
				//IL_0094: Unknown result type (might be due to invalid IL or missing references)
				//IL_0099: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a4: Expected O, but got Unknown
				//IL_00f0: Expected O, but got Unknown
				StringList val = new StringList();
				((List<string>)val).Add("Hildir1");
				((List<string>)val).Add("Hildir2");
				((List<string>)val).Add("Hildir3");
				QuestKeys = Config.Define<StringList>(true, "Quests", "Quest Keys", val, "Comma separated list conditional keys used to flag quest status.\r\nNormally these are global keys, define them here to treat them as per player keys instead.\r\nNOTE: when debugging you can manually add/remove these keys to your player keys.\r\nHowever, you will need to leave the area for the scene to reload before you can see the changes.\r\nYou can view the active keys via the vanilla console command: listkeys\r\nGoogle for more info on vanilla key commands.");
				QuestKeyRange = Config.Define<float>(true, "Quests", "Quest Key Range", 20f, Config.AcceptRange<float>(0f, 100f), "When performing an action that applies a Quest Key, such as turning in a quest item, \r\nall players in the area will also be flagged with the key.\r\nThis way you have the option to share rewards without duplicating quest loot.\r\nInstead, replicate the reward flag to all players nearby when turning in a quest item.\r\nSet to 0 to disable this feature.");
				StringList val2 = new StringList();
				((List<string>)val2).Add("Hildir");
				QuestTraders = Config.Define<StringList>(true, "Quests", "Quest Traders", val2, "Comma separated list of traders which give quests which use " + ((ConfigEntryBase)QuestKeys).Definition.Key + "\r\nThey have inventories determined by " + ((ConfigEntryBase)QuestKeys).Definition.Key + "\r\nNormally the global keys are checked.  This will force them to use per player keys instead.");
			}
		}

		[HarmonyPatch]
		private static class ActiveTrader
		{
			private static Trader? _trader;

			public static bool IsAllowed()
			{
				Trader trader;
				return IsAllowed(out trader);
			}

			public static bool IsAllowed(out Trader trader)
			{
				trader = null;
				if (!Object.op_Implicit((Object)(object)_trader))
				{
					return true;
				}
				trader = _trader;
				string prefabName = GameObjectExt.GetPrefabName(((Component)_trader).gameObject);
				return Configs.QuestTraders.Value.Contains(prefabName, true);
			}

			[UsedImplicitly]
			private static IEnumerable<MethodInfo> TargetMethods()
			{
				return new <>z__ReadOnlyArray<MethodInfo>(new MethodInfo[2]
				{
					AccessTools.DeclaredMethod(typeof(Trader), "UseItem", (Type[])null, (Type[])null),
					AccessTools.DeclaredMethod(typeof(Trader), "Interact", (Type[])null, (Type[])null)
				});
			}

			[UsedImplicitly]
			private static void Prefix(Trader __instance)
			{
				_trader = __instance;
			}

			[UsedImplicitly]
			private static void Postfix(Trader __instance)
			{
				_trader = null;
			}
		}

		[HarmonyPatch]
		private static class TraderTranspiler
		{
			[UsedImplicitly]
			private static IEnumerable<MethodInfo> TargetMethods()
			{
				return new <>z__ReadOnlyArray<MethodInfo>(new MethodInfo[2]
				{
					AccessTools.DeclaredMethod(typeof(Trader), "UseItem", (Type[])null, (Type[])null),
					AccessTools.DeclaredMethod(typeof(Trader), "GetAvailableItems", (Type[])null, (Type[])null)
				});
			}

			[UsedImplicitly]
			private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> codes)
			{
				return GlobalToPlayerKeys(codes);
			}
		}

		internal static void RegisterRPC()
		{
			ZRoutedRpc.instance.Register<Vector3, string>("RPC_SetKeyProximity", (Action<long, Vector3, string>)RPC_SetKeyProximity);
		}

		internal static void Shutdown()
		{
			if (ZRoutedRpc.instance != null)
			{
				ZRoutedRpcExt.Unregister(ZRoutedRpc.instance, "RPC_SetKeyProximity");
			}
		}

		private static bool IsPerPlayerQuestKey(string key)
		{
			return Configs.QuestKeys.Value.Contains(key, true);
		}

		private static void SetKey(string key)
		{
			//IL_005d: 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_0062: 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 (!Configs.PerPlayerQuests.Value || !IsPerPlayerQuestKey(key))
			{
				ZoneSystem.instance.SetGlobalKey(key);
				return;
			}
			((Humanoid)Player.m_localPlayer).AddUniqueKey(key);
			if (!(Configs.QuestKeyRange.Value <= 0f))
			{
				Trader trader;
				Vector3 val = (ActiveTrader.IsAllowed(out trader) ? ((Component)trader).transform.position : ((Component)Player.m_localPlayer).transform.position);
				ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "RPC_SetKeyProximity", new object[2] { val, key });
			}
		}

		private static void RPC_SetKeyProximity(long sender, Vector3 position, string key)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			if (!ZNet.instance.IsDedicated() && ZDOMan.GetSessionID() != sender && MathExt.DistanceTo((MonoBehaviour)(object)Player.m_localPlayer, position) < Configs.QuestKeyRange.Value)
			{
				((Humanoid)Player.m_localPlayer).AddUniqueKey(key);
			}
		}

		private static bool GetKey(string key)
		{
			if (!Configs.PerPlayerQuests.Value || !ActiveTrader.IsAllowed() || !IsPerPlayerQuestKey(key))
			{
				return ZoneSystem.instance.GetGlobalKey(key);
			}
			if (Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				return ((Humanoid)Player.m_localPlayer).HaveUniqueKey(key);
			}
			return false;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(ConditionalObject), "ShouldBeVisible")]
		private static void ConditionalObject_ShouldBeVisible(ConditionalObject __instance, ref bool __result)
		{
			string globalKeyCondition = __instance.m_globalKeyCondition;
			if (!Utility.IsNullOrWhiteSpace(globalKeyCondition) && IsPerPlayerQuestKey(globalKeyCondition))
			{
				__result = GetKey(__instance.m_globalKeyCondition);
			}
		}

		private static IEnumerable<CodeInstruction> GlobalToPlayerKeys(IEnumerable<CodeInstruction> codes)
		{
			return Transpilers.Manipulator(Transpilers.Manipulator(Transpilers.Manipulator(codes, (Func<CodeInstruction, bool>)ZoneSystemInstance, (Action<CodeInstruction>)Nop), (Func<CodeInstruction, bool>)GetGlobalKey, (Action<CodeInstruction>)GetPlayerKey), (Func<CodeInstruction, bool>)SetGlobalKey, (Action<CodeInstruction>)SetPlayerKey);
			static bool GetGlobalKey(CodeInstruction c)
			{
				MethodInfo methodInfo2 = AccessTools.DeclaredMethod(typeof(ZoneSystem), "GetGlobalKey", new Type[1] { typeof(string) }, (Type[])null);
				if (c.opcode == OpCodes.Callvirt)
				{
					return (MethodInfo)c.operand == methodInfo2;
				}
				return false;
			}
			static void GetPlayerKey(CodeInstruction c)
			{
				Func<string, bool> func = GetKey;
				c.opcode = OpCodes.Call;
				c.operand = func.Method;
			}
			static void Nop(CodeInstruction c)
			{
				c.opcode = OpCodes.Nop;
				c.operand = null;
			}
			static bool SetGlobalKey(CodeInstruction c)
			{
				MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(ZoneSystem), "SetGlobalKey", new Type[1] { typeof(string) }, (Type[])null);
				if (c.opcode == OpCodes.Callvirt)
				{
					return (MethodInfo)c.operand == methodInfo;
				}
				return false;
			}
			static void SetPlayerKey(CodeInstruction c)
			{
				Action<string> action = SetKey;
				c.opcode = OpCodes.Call;
				c.operand = action.Method;
			}
			static bool ZoneSystemInstance(CodeInstruction c)
			{
				MethodInfo methodInfo3 = AccessTools.PropertyGetter(typeof(ZoneSystem), "instance");
				if (c.opcode == OpCodes.Call)
				{
					return (MethodInfo)c.operand == methodInfo3;
				}
				return false;
			}
		}
	}
	[HarmonyPatch]
	internal static class ShieldGen
	{
		private static class Configs
		{
			private const string SECTION_SHIELDGEN = "Shield Generator";

			public static readonly ConfigEntry<bool> EnableEjectFuel = Config.Define<bool>(true, "Shield Generator", "Enable Eject Fuel", true, "Add an option to eject the fuel on shield generators and cause them to shutdown.");

			public static readonly ConfigEntry<bool> ShieldProtectsFireFromRain = Config.Define<bool>(true, "Shield Generator", "Shield Protects Fire From Rain", true, "Shield Generator protects fireplaces from the rain so they stay lit without a roof. (Vanilla: False)");
		}

		public static void Start()
		{
			ZRoutedRpc.instance.Register<ZDOID>("RPC_EjectShieldFuel", (Action<long, ZDOID>)RPC_EjectShieldFuel);
		}

		public static void Shutdown()
		{
			ZRoutedRpcExt.Unregister(ZRoutedRpc.instance, "RPC_EjectShieldFuel");
		}

		private static void RPC_EjectShieldFuel(long sender, ZDOID shieldGenID)
		{
			//IL_0005: 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)
			GameObject val = ZNetScene.instance.FindInstance(shieldGenID);
			if (!Object.op_Implicit((Object)(object)val))
			{
				Logging<Plugin>.Error((object)$"Shield Generator not found for ZDOID: {shieldGenID}", (ushort)0);
			}
			else
			{
				EjectFuel(val.GetComponent<ShieldGenerator>());
			}
		}

		private static GameObject GetFuelPrefab(ShieldGenerator shieldGenerator)
		{
			return ZNetScene.instance.GetPrefab("BoneFragments");
		}

		private static void EjectFuel(ShieldGenerator shieldGenerator)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: 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_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: 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_0073: 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_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			if (shieldGenerator.m_nview.IsOwner())
			{
				int num = Mathf.CeilToInt(shieldGenerator.GetFuel());
				GameObject fuelPrefab = GetFuelPrefab(shieldGenerator);
				Transform transform = ((Component)shieldGenerator).transform;
				for (int i = 0; i < num; i++)
				{
					Vector3 val = transform.position + transform.forward + Vector3.up + Random.insideUnitSphere * 0.3f;
					Quaternion val2 = Quaternion.Euler(0f, (float)Random.Range(0, 360), 0f);
					Object.Instantiate<GameObject>(fuelPrefab, val, val2).GetComponent<ItemDrop>().m_autoPickup = false;
				}
				shieldGenerator.m_nview.GetZDO().Set(ZDOVars.s_fuel, 0f);
				shieldGenerator.m_fuelAddedEffects.Create(transform.position, transform.rotation, transform, 1f, -1);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Switch), "GetHoverText")]
		private static void Switch_ShieldGenerator_GetHoverText(Switch __instance, ref string __result)
		{
			if (Configs.EnableEjectFuel.Value && WardAccessExt.CanAccessWard((MonoBehaviour)(object)__instance, false))
			{
				ShieldGenerator componentInParent = ((Component)__instance).GetComponentInParent<ShieldGenerator>();
				if (Object.op_Implicit((Object)(object)componentInParent) && componentInParent.GetFuel() > 0f)
				{
					__result += Localization.instance.Localize("\n" + UI.PromptInteractAlt + " $hud_remove $piece_shieldgenerator_fuelname");
				}
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Switch), "Interact")]
		private static void Switch_ShieldGenerator_Interact(Switch __instance, bool alt, ref bool __result, ref bool __runOriginal)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			if (!Configs.EnableEjectFuel.Value || !alt)
			{
				return;
			}
			if (!WardAccessExt.CanAccessWard((MonoBehaviour)(object)__instance, false))
			{
				__result = false;
				__runOriginal = false;
				return;
			}
			ShieldGenerator componentInParent = ((Component)__instance).GetComponentInParent<ShieldGenerator>();
			if (Object.op_Implicit((Object)(object)componentInParent))
			{
				ZDO zDO = componentInParent.m_nview.GetZDO();
				ZRoutedRpc.instance.InvokeRoutedRPC(zDO.GetOwner(), "RPC_EjectShieldFuel", new object[1] { zDO.m_uid });
				__runOriginal = false;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Fireplace), "CheckWet")]
		private static void Fireplace_CheckWet(Fireplace __instance)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			if (__instance.m_wet && Configs.ShieldProtectsFireFromRain.Value)
			{
				__instance.m_wet = !ShieldGenerator.IsInsideShield(((Component)__instance).transform.position);
			}
		}
	}
	[HarmonyPatch]
	internal static class ShipRules
	{
		private static class Configs
		{
			public static readonly ConfigEntry<float> RefundPercent;

			public static readonly ConfigEntry<bool> SafeHarbor;

			static Configs()
			{
				RefundPercent = Config.Define<float>(true, "Ships", "Refund Percent", 0.5f, Config.AcceptRange<float>(0f, 1f), "The percentage of the ship's construction materials to refund when destroyed. (Vanilla: 100%)\r\nDefault is 50% to discourage boat-in-a-box.");
				SafeHarbor = Config.Define<bool>(true, "Ships", "Safe Harbor", true, "Ships are ignored by monsters when no crew is onboard. (Vanilla: false)\r\nHowever, if you were on the ship and then jump off while a monster was nearby they may still attack the ship.\r\nThis helps to protect ships in the harbor from being attacked by monsters when nobody is around.\r\nBut if you are onboard they will see you and attack and may keep attacking the ship even once you disembark.");
			}
		}

		[HarmonyPatch]
		private static class NoCrew
		{
			[UsedImplicitly]
			private static IEnumerable<MethodInfo> TargetMethods()
			{
				return new <>z__ReadOnlyArray<MethodInfo>(new MethodInfo[2]
				{
					AccessTools.DeclaredMethod(typeof(Piece), "IsPriorityTarget", (Type[])null, (Type[])null),
					AccessTools.DeclaredMethod(typeof(Piece), "IsRandomTarget", (Type[])null, (Type[])null)
				});
			}

			[UsedImplicitly]
			private static void Prefix(Piece __instance, ref bool __runOriginal, ref bool __result)
			{
				if (Configs.SafeHarbor.Value && __instance.IsPlayerCreatedShip(out Ship ship) && !ship.HasPlayerOnboard())
				{
					Logging<Plugin>.Info((object)("Safe Harbor: No crew on " + ((Object)__instance).name + ", not a valid target."), 0);
					__runOriginal = (__result = false);
				}
			}
		}

		private static bool IsPlayerCreatedShip(this Piece? piece)
		{
			Ship ship;
			return piece.IsPlayerCreatedShip(out ship);
		}

		private static bool IsPlayerCreatedShip(this Piece? piece, out Ship ship)
		{
			if (Object.op_Implicit((Object)(object)piece) && piece.IsPlacedByPlayer())
			{
				ship = ((Component)piece).GetComponent<Ship>();
				return Object.op_Implicit((Object)(object)ship);
			}
			ship = null;
			return false;
		}

		[HarmonyTranspiler]
		[HarmonyPatch(typeof(Piece), "DropResources")]
		private static IEnumerable<CodeInstruction> Piece_DropResources(IEnumerable<CodeInstruction> codes, ILGenerator gen)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected O, but got Unknown
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Expected O, but got Unknown
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			CodeMatch[] array = (CodeMatch[])(object)new CodeMatch[3]
			{
				new CodeMatch((OpCode?)OpCodes.Ldloc_S, (object)null, (string)null),
				new CodeMatch((OpCode?)OpCodes.Ldfld, (object)AccessTools.Field(typeof(Requirement), "m_amount"), (string)null),
				new CodeMatch((OpCode?)OpCodes.Stloc_S, (object)null, (string)null)
			};
			Func<int, Piece, Requirement, int> func = AdjustAmount;
			CodeInstruction[] array2 = (CodeInstruction[])(object)new CodeInstruction[3]
			{
				new CodeInstruction(OpCodes.Ldarg_0, (object)null),
				new CodeInstruction(OpCodes.Ldloc_S, (object)(byte)4),
				new CodeInstruction(OpCodes.Call, (object)func.Method)
			};
			return new CodeMatcher(codes, gen).MatchEndForward(array).ThrowIfInvalid("Unable to match IL sequence").Insert(array2)
				.InstructionEnumeration();
			static int AdjustAmount(int amount, Piece piece, Requirement resource)
			{
				if (!piece.IsPlayerCreatedShip())
				{
					return amount;
				}
				float value = Configs.RefundPercent.Value;
				int num = Mathf.RoundToInt((float)amount * value);
				ItemDrop resItem = resource.m_resItem;
				string text = ((resItem != null) ? ItemDataExt.GetPrefabName(resItem) : null) ?? "Unknown";
				Logging<Plugin>.Info((object)$"Ship refund {((Object)piece).name} {text}: {value * 100f:n0}% = {num}", 0);
				return num;
			}
		}
	}
	[HarmonyPatch]
	internal static class SpawnerRules
	{
		private struct SpawnRule
		{
			public ConfigEntry<StringList> BlockedGlobalKeys;

			public ConfigEntry<StringList> BlockedPrefabs;

			public ConfigEntry<StringList> AllowedPrefabs;

			public ConfigEntry<bool> DisableHuntPlayer;
		}

		private static class Configs
		{
			private const string SECTION_SPAWNERS = "Spawners";

			public static readonly ConfigEntry<bool> EnableSpawnRules;

			public static readonly Dictionary<Biome, SpawnRule> BiomeRules;

			private const string KilledEikthyr = "defeated_eikthyr";

			private const string KilledTheElder = "defeated_gdking";

			private const string KilledBonemass = "defeated_bonemass";

			private const string KilledDragon = "defeated_dragon";

			private const string KilledGoblinKing = "defeated_goblinking";

			private const string KilledQueen = "defeated_queen";

			private const string KilledFader = "defeated_fader";

			private static readonly List<Biome> BiomeOrder;

			private static readonly Dictionary<Biome, StringList> DefaultBlockedKeys;

			static Configs()
			{
				//IL_0067: Unknown result type (might be due to invalid IL or missing references)
				//IL_006c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0077: Expected O, but got Unknown
				//IL_0077: Unknown result type (might be due to invalid IL or missing references)
				//IL_0082: Expected O, but got Unknown
				//IL_0082: Unknown result type (might be due to invalid IL or missing references)
				//IL_008d: Expected O, but got Unknown
				//IL_008d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0098: Expected O, but got Unknown
				//IL_0098: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a3: Expected O, but got Unknown
				//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ae: Expected O, but got Unknown
				//IL_00b3: Expected O, but got Unknown
				//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c5: Expected O, but got Unknown
				//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d0: Expected O, but got Unknown
				//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
				//IL_00db: Expected O, but got Unknown
				//IL_00db: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e6: Expected O, but got Unknown
				//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f1: Expected O, but got Unknown
				//IL_00f6: Expected O, but got Unknown
				//IL_00f8: 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_0108: Expected O, but got Unknown
				//IL_0108: Unknown result type (might be due to invalid IL or missing references)
				//IL_0113: Expected O, but got Unknown
				//IL_0113: Unknown result type (might be due to invalid IL or missing references)
				//IL_011e: Expected O, but got Unknown
				//IL_011e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0129: Expected O, but got Unknown
				//IL_012e: Expected O, but got Unknown
				//IL_0130: Unknown result type (might be due to invalid IL or missing references)
				//IL_0135: Unknown result type (might be due to invalid IL or missing references)
				//IL_0140: Expected O, but got Unknown
				//IL_0140: Unknown result type (might be due to invalid IL or missing references)
				//IL_014b: Expected O, but got Unknown
				//IL_014b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0156: Expected O, but got Unknown
				//IL_015b: Expected O, but got Unknown
				//IL_015e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0163: Unknown result type (might be due to invalid IL or missing references)
				//IL_016e: Expected O, but got Unknown
				//IL_016e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0179: Expected O, but got Unknown
				//IL_017e: Expected O, but got Unknown
				//IL_0184: Unknown result type (might be due to invalid IL or missing references)
				//IL_0189: Unknown result type (might be due to invalid IL or missing references)
				//IL_0194: Expected O, but got Unknown
				//IL_0199: Expected O, but got Unknown
				//IL_019c: Unknown result type (might be due to invalid IL or missing references)
				//IL_01a6: Expected O, but got Unknown
				//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
				//IL_01b3: Expected O, but got Unknown
				//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
				//IL_01c3: Expected O, but got Unknown
				BiomeRules = new Dictionary<Biome, SpawnRule>();
				BiomeOrder = new List<Biome>(9)
				{
					(Biome)1,
					(Biome)8,
					(Biome)2,
					(Biome)4,
					(Biome)16,
					(Biome)512,
					(Biome)32,
					(Biome)64,
					(Biome)256
				};
				Dictionary<Biome, StringList> dictionary = new Dictionary<Biome, StringList>();
				StringList val = new StringList();
				((List<string>)val).Add("defeated_gdking");
				((List<string>)val).Add("defeated_bonemass");
				((List<string>)val).Add("defeated_dragon");
				((List<string>)val).Add("defeated_goblinking");
				((List<string>)val).Add("defeated_queen");
				((List<string>)val).Add("defeated_fader");
				dictionary.Add((Biome)1, val);
				StringList val2 = new StringList();
				((List<string>)val2).Add("defeated_bonemass");
				((List<string>)val2).Add("defeated_dragon");
				((List<string>)val2).Add("defeated_goblinking");
				((List<string>)val2).Add("defeated_queen");
				((List<string>)val2).Add("defeated_fader");
				dictionary.Add((Biome)8, val2);
				StringList val3 = new StringList();
				((List<string>)val3).Add("defeated_dragon");
				((List<string>)val3).Add("defeated_goblinking");
				((List<string>)val3).Add("defeated_queen");
				((List<string>)val3).Add("defeated_fader");
				dictionary.Add((Biome)2, val3);
				StringList val4 = new StringList();
				((List<string>)val4).Add("defeated_goblinking");
				((List<string>)val4).Add("defeated_queen");
				((List<string>)val4).Add("defeated_fader");
				dictionary.Add((Biome)4, val4);
				StringList val5 = new StringList();
				((List<string>)val5).Add("defeated_queen");
				((List<string>)val5).Add("defeated_fader");
				dictionary.Add((Biome)16, val5);
				StringList val6 = new StringList();
				((List<string>)val6).Add("defeated_fader");
				dictionary.Add((Biome)512, val6);
				dictionary.Add((Biome)32, new StringList());
				dictionary.Add((Biome)64, new StringList());
				dictionary.Add((Biome)256, new StringList());
				DefaultBlockedKeys = dictionary;
				EnableSpawnRules = Config.Define<bool>(true, "Spawners", "_Enable Spawner Rules", false, "Enable or disable this entire section. If disabled then vanilla spawn rules are applied.\r\nThe default configuration is setup to prevent high level monsters from spawning in low level zones.\r\nThis is to help keep some zones safe from global world progression and make the game a bit\r\neasier for low level players just starting out, or to just have some areas safe from the harder spawns.\r\nThese rules are not applied to raid events or trigger spawns.\r\nNOTE: These rules do not affect existing monsters. Only spawning new ones.\r\nFor more info: \r\nSee: https://valheim.fandom.com/wiki/Spawn_zones\r\nTo view the spawners in the world run this command.\r\nIt is useful for figuring out what rules you would like to apply apply:\r\nConsole command: Zen_Spawners");
				InitBiomeConfigs();
			}

			private static void InitBiomeConfigs()
			{
				//IL_001d: 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_0023: 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: Invalid comparison between Unknown and I4
				//IL_003c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0055: Unknown result type (might be due to invalid IL or missing references)
				//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_0090: Unknown result type (might be due to invalid IL or missing references)
				//IL_0094: Unknown result type (might be due to invalid IL or missing references)
				//IL_009b: Invalid comparison between Unknown and I4
				//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c7: 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_0103: Unknown result type (might be due to invalid IL or missing references)
				//IL_0119: Unknown result type (might be due to invalid IL or missing references)
				//IL_013c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0148: Unknown result type (might be due to invalid IL or missing references)
				//IL_014d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0158: Expected O, but got Unknown
				//IL_0158: Unknown result type (might be due to invalid IL or missing references)
				//IL_0163: Expected O, but got Unknown
				//IL_0168: Unknown result type (might be due to invalid IL or missing references)
				//IL_0179: Expected O, but got Unknown
				//IL_018b: Unknown result type (might be due to invalid IL or missing references)
				//IL_019d: Unknown result type (might be due to invalid IL or missing references)
				//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
				foreach (Biome value3 in Enum.GetValues(typeof(Biome)))
				{
					bool flag = (((int)value3 == 0 || (int)value3 == 895) ? true : false);
					if (!flag && !BiomeOrder.Contains(value3))
					{
						BiomeOrder.Insert(BiomeOrder.Count - 1, value3);
					}
				}
				SpawnRule value = default(SpawnRule);
				foreach (Biome item in BiomeOrder)
				{
					if (((int)item != 0 && (int)item != 895) || 1 == 0)
					{
						value.BlockedGlobalKeys = Config.Define<StringList>(true, "Spawners", $"{item} - Blocked Keys", DefaultBlockedKeys.TryGetValue(item, out StringList value2) ? value2 : StringList.Empty, $"Comma separated list of global keys.\r\nAny prefabs that require these keys to be present are prevented from spawning in {item}.\r\nUseful for preventing high level monsters from spawning in newbie zones based on world progression.");
						value.BlockedPrefabs = Config.Define<StringList>(true, "Spawners", $"{item} - Blocked Creatures", StringList.Empty, $"Comma separated list of prefab names that are never allowed to spawn in {item}.");
						string text = $"{item} - Allowed Creatures";
						StringList val2 = new StringList();
						((List<string>)val2).Add("odin");
						((List<string>)val2).Add("Skeleton");
						value.AllowedPrefabs = Config.Define<StringList>(true, "Spawners", text, val2, $"Comma separated list of prefab names that are always allowed to spawn in the {item} even if restrictions are applied.");
						value.DisableHuntPlayer = Config.Define<bool>(true, "Spawners", $"{item} - Disable Hunt Player", false, $"If true the spawned monster will not hunt the player in {item}.\r\nNote, this does not prevent hunting from events or spawn triggers.  Just regular spawns.");
						BiomeRules.Add(item, value);
					}
				}
			}
		}

		private const string ConsoleCommand = "Spawners";

		public static void InitTerminal()
		{
			ZenMod<Plugin>.Terminal.CreateCommand("Spawners", "List the spawn data", true, (Action<string[]>)ExecCommand);
			static void ExecCommand(string[] args)
			{
				//IL_00ca: 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_00ed: Unknown result type (might be due to invalid IL or missing references)
				//IL_0188: Unknown result type (might be due to invalid IL or missing references)
				if (args.Length < 2 || !Enum.TryParse<Biome>(args[1], out Biome result))
				{
					Console.instance.Print("Usage: " + args[0] + " <biome|All> [prefabName|keyName]");
					return;
				}
				HashSet<string> hashSet = new HashSet<string>();
				foreach (SpawnSystemList item2 in SpawnSystem.m_instances.SelectMany((SpawnSystem sys) => sys.m_spawnLists))
				{
					foreach (SpawnData spawner in item2.m_spawners)
					{
						if (args.Length == 3)
						{
							string text = args[2].ToLower();
							if (GameObjectExt.GetPrefabName(spawner.m_prefab).ToLower() != text && !spawner.m_requiredGlobalKey.ToLower().Contains(text))
							{
								continue;
							}
						}
						if (((Enum)result).HasFlag((Enum)(object)(Biome)895) || ((Enum)spawner.m_biome).HasFlag((Enum)(object)result))
						{
							string text2 = (spawner.m_spawnAtNight ? "Night " : string.Empty);
							string text3 = (spawner.m_spawnAtDay ? "Day " : string.Empty);
							string text4 = (spawner.m_huntPlayer ? "Hunt " : string.Empty);
							string text5 = (Utility.IsNullOrWhiteSpace(spawner.m_requiredGlobalKey) ? string.Empty : ("RequiredKey: " + spawner.m_requiredGlobalKey));
							string item = $"{((Object)spawner.m_prefab).name} ({spawner.m_biome}) {text2}{text3}{text4} {text5}";
							hashSet.Add(item);
						}
					}
				}
				foreach (string item3 in hashSet.OrderBy((string s) => s))
				{
					Print(item3);
				}
			}
			static void Print(string s)
			{
				Console.instance.Print(s);
				Logging<Plugin>.Info((object)s, 0);
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(SpawnSystem), "Spawn")]
		private static void SpawnSystem_Spawn(SpawnSystem __instance, SpawnData critter, Vector3 spawnPoint, bool eventSpawner, ref bool __runOriginal)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0052: 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_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			if (!Configs.EnableSpawnRules.Value || eventSpawner)
			{
				return;
			}
			Biome biome = WorldGenerator.instance.GetBiome(spawnPoint);
			if (Configs.BiomeRules.TryGetValue(biome, out var value))
			{
				string prefabName = GameObjectExt.GetPrefabName(critter.m_prefab);
				BaseAI val = default(BaseAI);
				if (value.AllowedPrefabs.Value.Contains(prefabName, true))
				{
					Logging<Plugin>.Info((object)$"{biome} - Always allowed to spawn: {prefabName}", 0);
				}
				else if (value.BlockedPrefabs.Value.Contains(prefabName, true))
				{
					Logging<Plugin>.Info((object)$"{biome} - Blocking spawn of {prefabName}", 0);
					__runOriginal = false;
				}
				else if (!critter.m_prefab.TryGetComponent<BaseAI>(ref val))
				{
					Logging<Plugin>.Info((object)string.Format("{0} - No {1} for {2}, spawning. (Ignoring other rules)", biome, "BaseAI", prefabName), 0);
				}
				else if (value.BlockedGlobalKeys.Value.Contains(critter.m_requiredGlobalKey, true))
				{
					Logging<Plugin>.Info((object)$"{biome} - Blocking spawn of {prefabName} due to blocked key: {critter.m_requiredGlobalKey}", 0);
					__runOriginal = false;
				}
			}
		}

		[HarmonyTranspiler]
		[HarmonyPatch(typeof(SpawnSystem), "Spawn")]
		private static IEnumerable<CodeInstruction> SpawnSystem_Spawn_Transpile(IEnumerable<CodeInstruction> codes)
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(BaseAI), "SetHuntPlayer", (Type[])null, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(SpawnerRules), "SetHuntPlayerIntercept", (Type[])null, (Type[])null);
			return Transpilers.MethodReplacer(codes, (MethodBase)methodInfo, (MethodBase)methodInfo2);
		}

		private static void SetHuntPlayerIntercept(BaseAI baseAI, bool hunt)
		{
			//IL_001a: 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_0024: 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)
			BaseAI baseAI2 = baseAI;
			Biome biome = WorldGenerator.instance.GetBiome(((Component)baseAI2).transform.position);
			if (CanHunt())
			{
				baseAI2.SetHuntPlayer(hunt);
			}
			else
			{
				Logging<Plugin>.Info((object)$"Disabling HuntPlayer for {((Object)baseAI2).name} in {biome}", 0);
			}
			bool CanHunt()
			{
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				if (!Configs.EnableSpawnRules.Value)
				{
					return true;
				}
				BaseAI obj = baseAI2;
				MonsterAI val = (MonsterAI)(object)((obj is MonsterAI) ? obj : null);
				if (val != null && val.IsEventCreature())
				{
					return true;
				}
				if (!Configs.BiomeRules.TryGetValue(biome, out var value))
				{
					return true;
				}
				return !value.DisableHuntPlayer.Value;
			}
		}
	}
	[HarmonyPatch]
	internal static class TurretRules
	{
		private static class Configs
		{
			private const string SECTION_TURRET = "Turret";

			public static readonly ConfigEntry<bool> TargetPlayers;

			public static readonly ConfigEntry<bool> TargetTamed;

			public static readonly ConfigEntry<int> MaxAmmo;

			public static readonly ConfigEntry<int> MaxTargets;

			public static readonly ConfigEntry<bool> StackAmmoOnDestroy;

			static Configs()
			{
				TargetPlayers = Config.Define<bool>(true, "Turret", "Target Players", true, "Can turrets target players? (Vanilla: true)\nVanilla behavior is to target players unless a trophy is set.\nIf this is disabled then turrets can be used to be easily cheese boss fights and push into in\nunexplored areas because all the undefeated monsters will be targeted and the player will not.\nPlacing a trophy to limit which creature type the turret attacks is a sensible balance as it\nmakes it a bit more difficult to use the turrets to cheese into unexplored areas since you\nneed to kill the creature once before it can be targeted and the turret can only kill a single type\nof monster, therefor multiple turrets would need to be built in order to defend against multiple types.\nIf this option is false then the turret will always ignore the Player and kill anything else...\nThat will result in an easier run since less turrets would need to be built.");
				TargetTamed = Config.Define<bool>(true, "Turret", "Target Tamed", true, "Can turrets target tamed creatures? (Vanilla: true)\nPopulation control...");
				MaxAmmo = Config.Define<int>(true, "Turret", "Max Ammo", 40, Config.AcceptRange<int>(1, 100), "Max ammo capacity (Vanilla: 40)");
				MaxTargets = Config.Define<int>(true, "Turret", "Max Targets", 2, Config.AcceptRange<int>(1, 10), "Max number of target trophies that can be set at once. (Vanilla: 1)");
				StackAmmoOnDestroy = Config.Define<bool>(true, "Turret", "Stack Ammo On Destroy", false, "When the turret dies should the ammo be returned as a stack or as a bunch of individual bolts on the ground?\nCaution: if Max Ammo is high this can kill the framerate as it tries to dump a ton of ammo objects on the ground unstacked.  (Vanilla: false)");
			}
		}

		internal static void Start()
		{
			ZRoutedRpc.instance.Register<ZDOID>("RPC_ResetTurret", (Action<long, ZDOID>)RPC_ResetTurret);
		}

		internal static void Shutdown()
		{
			ZRoutedRpcExt.Unregister(ZRoutedRpc.instance, "RPC_ResetTurret");
		}

		private static bool ClearTrophies(this Turret turret)
		{
			if (turret.m_targetItems.Count == 0)
			{
				return false;
			}
			turret.m_targetItems.Clear();
			turret.SetTargets();
			return true;
		}

		private static bool EjectAmmo(this Turret turret)
		{
			//IL_0044: 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_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: 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)
			//IL_0079: 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)
			//IL_008a: 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_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			if (!turret.HasAmmo())
			{
				Logging<Plugin>.Info((object)"Turret is empty", 0);
				return false;
			}
			Logging<Plugin>.Info((object)"Eject Ammo", 0);
			int ammo = turret.GetAmmo();
			string ammoType = turret.GetAmmoType();
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(ammoType);
			Quaternion rotation = turret.m_turretBody.transform.rotation;
			Vector3 val = turret.m_eye.transform.position + turret.m_eye.transform.forward * 2f;
			Quaternion val2 = rotation * Quaternion.Euler(0f, 180f, 0f);
			ItemDrop component = Object.Instantiate<GameObject>(itemPrefab, val, val2).GetComponent<ItemDrop>();
			component.SetStack(ammo);
			ItemDrop.OnCreateNew(component);
			turret.m_addAmmoEffect.Create(turret.m_turretBody.transform.position, rotation, (Transform)null, 1f, -1);
			ZDO zDO = turret.m_nview.GetZDO();
			if (zDO.IsOwner())
			{
				zDO.Set(ZDOVars.s_ammo, 0, false);
				zDO.Set(ZDOVars.s_ammoType, string.Empty);
			}
			((Character)Player.m_localPlayer).Message((MessageType)1, "$hud_remove " + ItemDataExt.GetName(component), ammo, ItemDataExt.GetIcon(component));
			return true;
		}

		private static void RPC_ResetTurret(long sender, ZDOID turretID)
		{
			//IL_0005: 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)
			GameObject val = ZNetScene.instance.FindInstance(turretID);
			if (!Object.op_Implicit((Object)(object)val))
			{
				Logging<Plugin>.Error((object)$"Turret not found for ZDOID: {turretID}", (ushort)0);
				return;
			}
			Turret component = val.GetComponent<Turret>();
			if (component.EjectAmmo() || component.ClearTrophies())
			{
				((Character)Player.m_localPlayer).Message((MessageType)2, "$menu_modifier_default", 0, (Sprite)null);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Turret), "Awake")]
		private static void Turret_Awake(Turret __instance)
		{
			__instance.m_targetPlayers = Configs.TargetPlayers.Value;
			__instance.m_targetTamed = Configs.TargetTamed.Value;
			__instance.m_maxAmmo = Configs.MaxAmmo.Value;
			__instance.m_maxConfigTargets = Configs.MaxTargets.Value;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Turret), "OnDestroyed")]
		private static void Turret_OnDestroyed(Turret __instance, ref bool __runOriginal)
		{
			if (Configs.StackAmmoOnDestroy.Value)
			{
				__runOriginal = false;
				if (__instance.m_nview.IsOwner() && __instance.m_returnAmmoOnDestroy)
				{
					__instance.EjectAmmo();
				}
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Turret), "Interact")]
		private static void Turret_Interact(Turret __instance, bool alt, bool hold, ref bool __result, ref bool __runOriginal)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			if (!WardAccessExt.CanAccessWard((MonoBehaviour)(object)__instance, true))
			{
				__result = true;
				__runOriginal = false;
			}
			else if (!(!alt || hold))
			{
				ZDO zDO = __instance.m_nview.GetZDO();
				ZRoutedRpc.instance.InvokeRoutedRPC(zDO.GetOwner(), "RPC_ResetTurret", new object[1] { zDO.m_uid });
				__runOriginal = false;
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Turret), "UseItem")]
		private static void Turret_UseItem(Turret __instance, ItemData? item, ref bool __result, ref bool __runOriginal)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Invalid comparison between Unknown and I4
			if (item != null && (int)item.m_shared.m_itemType == 13 && !WardAccessExt.CanAccessWard((MonoBehaviour)(object)__instance, true))
			{
				__runOriginal = false;
				__result = true;
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Turret), "GetHoverText")]
		private static void Turret_GetHoverText(Turret __instance, ref string __result, ref bool __runOriginal)
		{
			__runOriginal = false;
			if (!__instance.m_nview.IsValid())
			{
				__result = "";
				return;
			}
			if (!__instance.m_targetEnemies)
			{
				__result = Localization.instance.Localize(__instance.m_name);
				return;
			}
			HoverItem.UpdateIcons(__instance.m_targetItems.Select((ItemDrop item) => ItemDataExt.GetIcon(item)));
			__instance.sb.Clear();
			__instance.sb.Append((!__instance.HasAmmo()) ? (__instance.m_name + " ($piece_turret_noammo)") : $"{__instance.m_name} ({__instance.GetAmmo()}/{__instance.m_maxAmmo})");
			if (!WardAccessExt.CanAccessWard((MonoBehaviour)(object)__instance, false))
			{
				__instance.sb.Append("\n$piece_noaccess");
			}
			else
			{
				__instance.sb.Append("\n" + UI.PromptInteract + " $piece_turret_addammo");
				if (__instance.HasAmmo() || __instance.m_targetItems.Count > 0)
				{
					__instance.sb.Append("\n" + UI.PromptInteractAlt + " $settings_resetcontrols");
				}
				__instance.sb.Append("\n" + UI.PromptUseItem + " $piece_turret_target_set");
				if (Configs.MaxTargets.Value > 1)
				{
					__instance.sb.Append($" ({__instance.m_targetItems.Count}/{Configs.MaxTargets.Value})");
				}
			}
			__instance.sb.Append("\n");
			__instance.sb.Append($"<color={UIColor.Gray}>$piece_turret_target ");
			if (__instance.m_targetCharacters.Count == 0)
			{
				UIColor arg = ((Configs.TargetPlayers.Value || Configs.TargetTamed.Value) ? UIColor.MajorInfo : UIColor.Teal);
				__instance.sb.Append($"<color={arg}>");
				__instance.sb.Append(StringExtensions.CapitalizeFirstLetter(StringExt.Localize("$piece_turret_target_everything")));
				__instance.sb.Append("</color>");
			}
			else
			{
				__instance.sb.Append(__instance.m_targetsText);
			}
			__instance.sb.Append("</color>");
			__result = Localization.instance.Localize(__instance.sb.ToString());
		}
	}
	[HarmonyPatch]
	internal static class EnvironmentRules
	{
		private static class Configs
		{
			private const string SECTION_ENVIRONMENT = "Environment";

			public static readonly ConfigEntry<bool> ShowSkyTree;

			public static readonly ConfigEntry<bool> ShowWindPixels;

			public static readonly ConfigEntry<int> DayLengthSeconds;

			public static readonly ConfigEntry<bool> ShowDayNumber;

			public static readonly ConfigEntry<int> SnowStormParticlesMax;

			static Configs()
			{
				ShowSkyTree = Config.Define<bool>(true, "Environment", "Show Sky Tree", false, "Navigate with only the sun and stars.");
				ShowWindPixels = Config.Define<bool>(true, "Environment", "Show Wind Pixels", false, "Enable the chunky wind pixels");
				DayLengthSeconds = Config.Define<int>(true, "Environment", "Day Length Seconds", 0, Config.AcceptRange<int>(0, 10800), "Length of an in game day in seconds. (Vanilla: 1800)\r\nSet to 0 to disable this setting.\r\nNOTE: When multiplayer, this mod must be installed on the server and all clients for this setting to work.");
				ShowDayNumber = Config.Define<bool>(true, "Environment", "Show Day Number", false, "Display the day number each morning. (Vanilla: true)");
				SnowStormParticlesMax = (SnowStormParticlesMax = Config.Define<int>(true, "Environment", "SnowStorm Particles Max", -1, Config.AcceptRange<int>(-1, 5000), "Set the snow max particles (Vanilla: 2000-5000)\r\nSet to -1 to disable this setting and use vanilla values\r\n[logout required to revert to vanilla]"));
				ShowSkyTree.SettingChanged += delegate
				{
					SetSkyTree();
				};
				ShowWindPixels.SettingChanged += delegate
				{
					SetWindPixels();
				};
				DayLengthSeconds.SettingChanged += delegate
				{
					SetDayLength();
				};
				SnowStormParticlesMax.SettingChanged += delegate
				{
					SetSnowStormParticles();
				};
			}
		}

		private static bool IsMainScene
		{
			get
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				Scene activeScene = SceneManager.GetActiveScene();
				return ((Scene)(ref activeScene)).name == "main";
			}
		}

		internal static void Start()
		{
			SetDayLength();
			SetSkyTree();
			SetWindPixels();
			SetSnowStormParticles();
		}

		private static void SetSkyTree()
		{
			if (IsMainScene && Object.op_Implicit((Object)(object)EnvMan.instance))
			{
				GameObject val = GameObject.Find("_GameMain/_Environment/YggdrasilBranch");
				if (Object.op_Implicit((Object)(object)val))
				{
					val.SetActive(Configs.ShowSkyTree.Value);
				}
				else
				{
					Logging<Plugin>.Warning((object)"Unable to set sky tree visibility, node not found", 0);
				}
			}
		}

		private static void SetWindPixels()
		{
			if (IsMainScene && Object.op_Implicit((Object)(object)EnvMan.instance))
			{
				GameObject val = GameObject.Find("_GameMain/_Environment/FollowPlayer/GlobalWindParticles/particles_pixel");
				if (Object.op_Implicit((Object)(object)val))
				{
					val.SetActive(Configs.ShowWindPixels.Value);
				}
				else
				{
					Logging<Plugin>.Warning((object)"Unable to set wind pixels visibility, node not found", 0);
				}
			}
		}

		private static void SetDayLength()
		{
			if (!IsMainScene || !Object.op_Implicit((Object)(object)EnvMan.instance))
			{
				return;
			}
			if (Configs.DayLengthSeconds.Value > 0)
			{
				if (ZenMod<Plugin>.IsOnServerAndAllClients)
				{
					EnvMan.instance.m_dayLengthSec = Configs.DayLengthSeconds.Value;
				}
				else
				{
					Logging<Plugin>.Warning((object)"Changing day length requires this mod to be installed on the server and all clients.", 0);
				}
			}
			Logging<Plugin>.Message((object)$"Day Length: {EnvMan.instance.m_dayLengthSec} seconds", 0);
		}

		private static void SetSnowStormParticles()
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			int configMax = Configs.SnowStormParticlesMax.Value;
			if (configMax < 0)
			{
				return;
			}
			foreach (Transform item in GameObject.Find("_GameMain/_Environment/FollowPlayer").transform)
			{
				Transform val = item;
				if (((Object)val).name.Contains("SnowStorm"))
				{
					SetMaxParticles(((Component)val).gameObject);
				}
			}
			void SetMaxParticles(GameObject obj)
			{
				//IL_002f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0034: Unknown result type (might be due to invalid IL or missing references)
				Logging<Plugin>.Message((object)$"Set max particles for env: {((Object)obj).name} {configMax}", 0);
				ParticleSystem[] componentsInChildren = obj.GetComponentsInChildren<ParticleSystem>();
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					MainModule main = componentsInChildren[i].main;
					((MainModule)(ref main)).maxParticles = configMax;
				}
			}
		}

		[HarmonyTranspiler]
		[HarmonyPatch(typeof(EnvMan), "OnMorning")]
		private static IEnumerable<CodeInstruction> EnvMan_OnMorning_Transpile(IEnumerable<CodeInstruction> codes)
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(Character), "Message", (Type[])null, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(EnvironmentRules), "MorningMessageIntercept", (Type[])null, (Type[])null);
			return Transpilers.MethodReplacer(codes, (MethodBase)methodInfo, (MethodBase)methodInfo2);
		}

		private static void MorningMessageIntercept(Character p, MessageType type, string msg, int amount, Sprite sprite)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			if (Configs.ShowDayNumber.Value)
			{
				p.Message(type, msg, amount, sprite);
			}
			else
			{
				Logging<Plugin>.Message((object)("Morning message suppressed: " + msg), 0);
			}
		}
	}
}
namespace ZenWorldSettings.Sections.Fireplaces
{
	[HarmonyPatch]
	internal static class ToggleInfiniteFuel
	{
		private const string ZDOVarInfiniteFuel = "Zen_InfiniteFuel";

		private static bool IsPlayerCreated(this Fireplace fireplace)
		{
			if (fireplace.m_nview.IsValid())
			{
				return ZdoExt.IsPlayerCreated(fireplace.m_nview.GetZDO());
			}
			return false;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Fireplace), "Awake")]
		private static void Fireplace_Awake(Fireplace __instance)
		{
			if (!__instance.m_infiniteFuel && __instance.IsPlayerCreated())
			{
				__instance.m_infiniteFuel = __instance.m_nview.GetZDO().GetBool("Zen_InfiniteFuel", false);
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Fireplace), "Interact")]
		private static void Fireplace_Interact(Fireplace __instance, bool hold)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			if (!hold && (!Configs.InfiniteFuelIsAdminOnly.Value || ((Character)Player.m_localPlayer).InGodMode()) && ZInput.GetKey(Configs.InfiniteFuelToggleKey.Value, true) && __instance.IsPlayerCreated())
			{
				__instance.m_infiniteFuel = !__instance.m_infiniteFuel;
				__instance.m_nview.ClaimOwnership();
				__instance.m_nview.GetZDO().Set("Zen_InfiniteFuel", __instance.m_infiniteFuel);
				Logging<Plugin>.Message((object)$"Toggle Infinite Fuel: {__instance.m_infiniteFuel}", 0);
			}
		}
	}
	[HarmonyPatch]
	internal static class CampfireRules
	{
		private const string Campfire = "fire_pit";

		private const string Wood = "Wood";

		private const string Stone = "Stone";

		private static readonly Collider[] Buffer = (Collider[])(object)new Collider[8];

		internal static void InitPrefab()
		{
			if (!Configs.CampfireStartEmpty.Value)
			{
				return;
			}
			GameObject prefab = ZNetScene.instance.GetPrefab("fire_pit");
			Fireplace val = default(Fireplace);
			if (Object.op_Implicit((Object)(object)prefab) && prefab.TryGetComponent<Fireplace>(ref val))
			{
				val.m_startFuel = 0f;
				Piece component = prefab.GetComponent<Piece>();
				List<Requirement> list = component.m_resources.ToList();
				Requirement val2 = list.Find((Requirement req) => ItemDataExt.GetPrefabName(req.m_resItem) == "Stone");
				if (val2 != null)
				{
					val2.m_amount = 8;
				}
				list.RemoveAll((Requirement req) => ItemDataExt.GetPrefabName(req.m_resItem) == "Wood");
				component.m_resources = list.ToArray();
			}
			else
			{
				Logging<Plugin>.Error((object)"fire_pit prefab or Fireplace component not found", (ushort)0);
			}
		}

		private static bool IsOverlapCharacter(Fireplace fireplace)
		{
			//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_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: 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_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: 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_007f: 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_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: 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_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_007c: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = ((Component)fireplace).transform;
			Vector3 position = transform.position;
			Quaternion orientation = transform.rotation;
			Vector3 halfExtents = Vector3.one;
			WearNTear val = default(WearNTear);
			if (((Component)fireplace).TryGetComponent<WearNTear>(ref val))
			{
				List<BoundData> bounds = val.m_bounds;
				if (bounds != null && bounds.Count > 0)
				{
					BoundData val2 = val.m_bounds.OrderByDescending((BoundData b) => b.m_size.x * b.m_size.z).First();
					position = val2.m_pos;
					orientation = val2.m_rot;
					halfExtents = val2.m_size;
				}
			}
			return IsOverlapCharacter(position, orientation, halfExtents);
		}

		private static bool IsOverlapCharacter(Vector3 position, Quaternion orientation, Vector3 halfExtents)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: 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)
			Logging<Plugin>.Info((object)$"Check character overlap area: {halfExtents}", 0);
			int num = Physics.OverlapBoxNonAlloc(position, halfExtents, Buffer, orientation, Character.s_characterLayerMask);
			Player localPlayer = Player.m_localPlayer;
			for (int i = 0; i < num; i++)
			{
				if (Object.op_Implicit((Object)(object)localPlayer) && (Object)(object)((Character)localPlayer).m_collider != (Object)(object)Buffer[i])
				{
					((Character)localPlayer).Message((MessageType)2, "$msg_blocked", 0, (Sprite)null);
					return true;
				}
			}
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Fireplace), "UseItem")]
		[HarmonyPriority(600)]
		private static void Fireplace_UseItem(Fireplace __instance, ref bool __runOriginal)
		{
			if (Configs.PreventCharacterOverlap.Value)
			{
				__runOriginal = !IsOverlapCharacter(__instance);
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Fireplace), "Interact")]
		[HarmonyPriority(600)]
		private static void Fireplace_Interact(Fireplace __instance, ref bool __runOriginal)
		{
			if (Configs.PreventCharacterOverlap.Value)
			{
				__runOriginal = !IsOverlapCharacter(__instance);
			}
		}
	}
	[HarmonyPatch]
	internal static class CandleRules
	{
		private static Fireplace? _refuelCandle;

		private static bool IsCandle(this Fireplace fireplace)
		{
			return fireplace.m_nview.GetPrefabName() == "Candle_resin";
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Fireplace), "GetHoverText")]
		private static void Fireplace_GetHoverText(Fireplace __instance)
		{
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Fireplace), "UpdateState")]
		private static void Fireplace_UpdateState(Fireplace __instance)
		{
			if (__instance.IsCandle() && Configs.CandleRefill.Value)
			{
				__instance.m_canTurnOff = !(__instance.m_canRefill = FireplaceExt.IsFuelEmpty(__instance));
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Fireplace), "Interact")]
		private static void Fireplace_Interact_Prefix(Fireplace __instance, bool alt, bool hold)
		{
			if (__instance.IsCandle() && !(alt || hold))
			{
				_refuelCandle = (__instance.m_canRefill ? __instance : null);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Fireplace), "Interact")]
		private static void Fireplace_Interact_Postfix()
		{
			_refuelCandle = null;
		}

		[HarmonyTranspiler]
		[HarmonyPatch(typeof(Fireplace), "Interact")]
		private static IEnumerable<CodeInstruction> Fireplace_Interact_Transpiler(IEnumerable<CodeInstruction> codes)
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(ZNetView), "InvokeRPC", new Type[2]
			{
				typeof(string),
				typeof(object[])
			}, (Type[])null);
			<>f__AnonymousDelegate0<ZNetView, string, object> <>f__AnonymousDelegate = Interact_InvokeRPC_Intercept;
			return Transpilers.MethodReplacer(codes, (MethodBase)methodInfo, (MethodBase)<>f__AnonymousDelegate.Method);
		}

		private static void Interact_InvokeRPC_Intercept(ZNetView nview, string method, params object[] parameters)
		{
			if (Object.op_Implicit((Object)(object)_refuelCandle) && method == "RPC_AddFuel")
			{
				nview.InvokeRPC("RPC_SetFuelAmount", new object[1] { _refuelCandle.m_startFuel });
			}
			else
			{
				nview.InvokeRPC(method, parameters);
			}
		}
	}
	[HarmonyPatch]
	internal static class BurnAnything
	{
		[HarmonyPatch(typeof(Fireplace), "UseItem")]
		private static class FireplaceUseItem
		{
			[UsedImplicitly]
			private static void Prefix(Fireplace __instance, ItemData item, out Action? __state)
			{
				SwapFuel(__instance, item, out __state);
			}

			[UsedImplicitly]
			private static void Postfix(Action? __state)
			{
				RestoreFuel(__state);
			}
		}

		[HarmonyPatch(typeof(Switch), "UseItem")]
		private static class SwitchUseItem
		{
			[UsedImplicitly]
			private static void Prefix(Switch __instance, ItemData item, out Action? __state)
			{
				SwapFuel(((Delegate)(object)__instance.m_onUse).Target, item, out __state);
			}

			[UsedImplicitly]
			private static void Postfix(Action? __state)
			{
				RestoreFuel(__state);
			}
		}

		private const string WoodPrefab = "Wood";

		private const string KilnPrefab = "charcoal_kiln";

		private static bool IsWood(this ItemDrop? itemDrop)
		{
			if ((Object)(object)itemDrop != (Object)null)
			{
				return ItemDataExt.GetPrefabName(itemDrop) == "Wood";
			}
			return false;
		}

		private static bool IsBurnable(this ItemData item)
		{
			return Configs.BurnableItems.Value.Contains(ItemDataExt.GetPrefabName(item), true);
		}

		internal static void SetupKiln()
		{
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Expected O, but got Unknown
			GameObject prefab = ZNetScene.instance.GetPrefab("charcoal_kiln");
			Smelter component = prefab.GetComponent<Smelter>();
			ItemConversion val = component.m_conversion.Find((ItemConversion c) => ItemDataExt.GetPrefabName(c.m_from) == "Wood");
			foreach (string burnable in (List<string>)(object)Configs.BurnableItems.Value)
			{
				if (!component.m_conversion.Any((ItemConversion c) => ItemDataExt.GetPrefabName(c.m_from) == burnable))
				{
					GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(burnable);
					ItemConversion item = new ItemConversion
					{
						m_from = itemPrefab.GetComponent<ItemDrop>(),
						m_to = val.m_to
					};
					Logging<Plugin>.Info((object)("Adding " + burnable + " to " + ((Object)prefab).name + " conversions"), 0);
					component.m_conversion.Add(item);
				}
			}
		}

		private static bool IsValidTarget(object target)
		{
			if (target is Fireplace || target is Smelter || target is CookingStation)
			{
				return true;
			}
			return false;
		}

		private static ref ItemDrop? GetFuelField(object target, out Action? restore)
		{
			restore = null;
			Fireplace val = (Fireplace)((target is Fireplace) ? target : null);
			ItemDrop orig;
			if (val == null)
			{
				CookingStation val2 = (CookingStation)((target is CookingStation) ? target : null);
				if (val2 == null)
				{
					Smelter val3 = (Smelter)((target is Smelter) ? target : null);
					if (val3 != null)
					{
						orig = val3.m_fuelItem;
						restore = delegate
						{
							val3.m_fuelItem = orig;
						};
						return ref val3.m_fuelItem;
					}
					throw new ArgumentOutOfRangeException("target", target, "Not a valid type");
				}
				orig = val2.m_fuelItem;
				restore = delegate
				{
					val2.m_fuelItem = orig;
				};
				return ref val2.m_fuelItem;
			}
			orig = val.m_fuelItem;
			restore = delegate
			{
				val.m_fuelItem = orig;
			};
			return ref val.m_fuelItem;
		}

		private static void SwapFuel(object target, ItemData item, out Action? restore)
		{
			restore = null;
			if (IsValidTarget(target) && item.IsBurnable())
			{
				ref ItemDrop fuelField = ref GetFuelField(target, out restore);
				if (fuelField.IsWood())
				{
					fuelField = item.m_dropPrefab.GetComponent<ItemDrop>();
				}
			}
		}

		private static void RestoreFuel(Action? restore)
		{
			restore?.Invoke();
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Smelter), "FindCookableItem")]
		private static void Smelter_FindCookableItem(Smelter __instance, Inventory inventory, ref ItemData? __result, ref bool __runOriginal)
		{
			if (Configs.KilnInteractWoodOnly.Value && !(GameObjectExt.GetPrefabName(((Component)__instance).gameObject) != "charcoal_kiln"))
			{
				__runOriginal = false;
				__result = inventory.GetItem("Wood", -1, true);
			}
		}
	}
	internal static class Configs
	{
		private const string SECTION_FIREPLACE = "Fireplaces";

		public static readonly ConfigEntry<bool> CandleRefill = Config.Define<bool>(true, "Fireplaces", "Refillable Candles", true, "When enabled the candle can be refilled after it is empty. (Vanilla: false)");

		public static readonly ConfigEntry<bool> CampfireStartEmpty = Config.Define<bool>(true, "Fireplaces", "Campfires Start Empty", true, "When enabled the campfire starts empty, like the bonfire, and must be fueled before it will light. (Vanilla: false)\r\nThis helps prevent spawning campfires under monsters and using them as a weapon to cheese them.\r\nThis also changes the resource cost: No wood instead of 2 wood to account for the ignite cost.\r\nThe stone cost is increased from 5 to 8 to offset the loss of wood cost. \r\nThis also makes the Iron Fire Pit more desirable since it weighs less and starts lit.\r\n(This mod, by default, makes the Iron Fire Pit teleportable)\r\n[game restart required for changes to take effect]");

		public static readonly ConfigEntry<bool> PreventCharacterOverlap = Config.Define<bool>(true, "Fireplaces", "Prevent Character Overlap", true, "Prevent fueling a fire when a character is standing on the fire. (Vanilla: false)\r\nThis prevents the player from being able to light a fire when a monster is standing on it.\r\nAnti-cheese, lighting a campfire under a monster is cheese.\r\nIgnores yourself, you can always burn yourself, be careful.");

		public static readonly ConfigEntry<StringList> BurnableItems;

		public static readonly ConfigEntry<bool> KilnInteractWoodOnly;

		public static readonly ConfigEntry<bool> SparkEnabled;

		public static readonly ConfigEntry<string> SparkItem;

		public static readonly ConfigEntry<bool> SparkItemConsume;

		public static readonly ConfigEntry<bool> SparkWithTorch;

		public static readonly ConfigEntry<bool> SparkWithTorchAutoEquip;

		public static readonly ConfigEntry<StringList> SparkableFuel;

		public static readonly ConfigEntry<bool> InfiniteFuelIsAdminOnly;

		public static readonly ConfigEntry<KeyCode> InfiniteFuelToggleKey;

		static Configs()
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected O, but got Unknown
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Expected O, but got Unknown
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Expected O, but got Unknown
			//IL_00a2: Expected O, but got Unknown
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Expected O, but got Unknown
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Expected O, but got Unknown
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Expected O, but got Unknown
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Expected O, but got Unknown
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Expected O, but got Unknown
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Exp