Decompiled source of ZenWorldSettings v0.5.4

plugins\ZenWorldSettings.dll

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

[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)]
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) })]
	[BepInPlugin("ZenDragon.ZenWorldSettings", "ZenWorldSettings", "0.5.4")]
	[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 = "0.5.4";

		public const string PluginGUID = "ZenDragon.ZenWorldSettings";

		protected override void Setup()
		{
			((ZenMod)this).RunOnServer = true;
			((ZenMod)this).ConfigSync += DoorKeys.InitKeys;
			((ZenMod)this).ConfigSync += CraftTeleportRules.Init;
			Spawners.InitTerminal();
		}

		protected override void TitleScene(bool isFirstBoot)
		{
		}

		protected override void WorldStart()
		{
			EnvironmentRules.Init();
			TurretRules.Start();
			ShieldGen.Start();
		}

		protected override void Shutdown()
		{
			TurretRules.Shutdown();
			ShieldGen.Shutdown();
		}
	}
}
namespace ZenWorldSettings.Sections
{
	[HarmonyPatch]
	internal static class Candle
	{
		private static class Configs
		{
			private const string SECTION_CANDLE = "Candle";

			public static readonly ConfigEntry<bool> EnableRefill = Config.Define<bool>(true, "Candle", "Enable Refill", true, "When enabled the candle can be refilled after it is empty. (Vanilla: false)");
		}

		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.EnableRefill.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> Transpile(IEnumerable<CodeInstruction> codes)
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(ZNetView), "InvokeRPC", new Type[2]
			{
				typeof(string),
				typeof(object[])
			}, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(Candle), "Interact_InvokeRPC_Intercept", (Type[])null, (Type[])null);
			return Transpilers.MethodReplacer(codes, (MethodBase)methodInfo, (MethodBase)methodInfo2);
		}

		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 CartRules
	{
		private static class Configs
		{
			private const string SECTION_CART = "Cart";

			internal static readonly ConfigEntry<bool> SnapToPlayer = Config.Define<bool>(true, "Cart", "Snap To Player", true, "When true the cart attaches to the player much more easily.");

			internal static readonly ConfigEntry<float> AttachDistance = Config.Define<float>(true, "Cart", "Attach Distance", 7f, Config.AcceptRange<float>(1f, 10f), "Minimum distance the player must be from the cart in order to attach it.");

			internal static readonly ConfigEntry<bool> IgnoreUpsideDown = Config.Define<bool>(true, "Cart", "Ignore Upside Down", true, "If true the cart will not prevent attach when upside down.");
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Vagon), "CanAttach")]
		private static void Vagon_CanAttach(Vagon __instance, GameObject go, ref bool __result, ref bool __runOriginal)
		{
			//IL_005d: 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_00c8: Unknown result type (might be due to invalid IL or missing references)
			if (Configs.SnapToPlayer.Value)
			{
				Catapult val = default(Catapult);
				if (((Component)__instance).TryGetComponent<Catapult>(ref val) && val.m_lockedLegs)
				{
					__result = false;
					__runOriginal = false;
				}
				else if (Configs.IgnoreUpsideDown.Value || !(((Component)__instance).transform.up.y < 0.1f))
				{
					Humanoid component = go.GetComponent<Humanoid>();
					bool flag = MathExt.AlignmentRatioTo(((Component)__instance).transform, ((Component)component).transform.position) > 0f;
					__result = !Object.op_Implicit((Object)(object)component) || ((flag & !((Character)component).IsTeleporting()) && !((Character)component).InDodge() && !((Character)component).IsBlocking() && !((Character)component).InAttack() && !((Character)component).IsCrouching() && !((Character)component).InEmote() && !((Character)component).IsDrawingBow() && !ZInput.GetButtonDown("JoyButtonB") && MathExt.DistanceTo((MonoBehaviour)(object)component, ((Component)__instance).transform.position) < Configs.AttachDistance.Value);
					__runOriginal = false;
				}
			}
		}
	}
	[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> DefaultStationLevel;

			public static readonly ConfigEntry<string> DefaultStation;

			public static readonly ConfigEntry<bool> Repairable;

			public static readonly ConfigEntry<StringList> IndestructibleDoorKeys;

			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_0048: Expected O, but got Unknown
				StringList val = new StringList();
				((List<string>)val).Add("Iron: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", 5, 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]");
				DefaultStationLevel = Config.Define<int>(true, "Door Keys", "Default Station Level", 1, Config.AcceptRange<int>(1, 4), "Minimum station level needed to upgrade or repair keys.\r\n[logout required for changes to take effect]");
				DefaultStation = Config.Define<string>(true, "Door Keys", "Default 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)DefaultStation).Definition.Key + "\r\nA broken key can not be used to open a door.  However, it can be recycled for scrap using ZenRecycle.\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]");
			}
		}

		private static readonly HashSet<ItemDrop> Keys = new HashSet<ItemDrop>();

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

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

		public static void InitKeys()
		{
			RemoveUpgradeRecipes();
			Keys.Clear();
			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))
				{
					Keys.Add(componentInChildren.m_keyItem);
				}
			}
			foreach (ItemDrop key in Keys)
			{
				InitKeyPrefab(key);
			}
		}

		private static bool TryInitKey(ItemData key)
		{
			if (!key.IsLimitedUseKey())
			{
				return false;
			}
			if (Configs.UsageLimit.Value == 0)
			{
				Log.Info((object)("Usage limit set to infinite in configs: " + ItemDataExt.GetPrefabName(key)), (ushort)0);
				key.m_shared.m_useDurability = false;
				return false;
			}
			Log.Info((object)("Init limited use key: " + ItemDataExt.GetPrefabName(key)), (ushort)0);
			key.m_shared.m_useDurability = true;
			key.m_shared.m_maxDurability = Configs.UsageLimit.Value;
			key.m_shared.m_canBeReparied = Configs.Repairable.Value && Configs.DefaultStation.Value != CraftingStations.None;
			key.m_shared.m_durabilityPerLevel = 1f;
			key.m_shared.m_maxQuality = Configs.MaxQuality.Value;
			key.m_durability = Mathf.Min(key.m_durability, key.GetMaxDurability());
			return true;
		}

		private static void InitKeyPrefab(ItemDrop keyItemDrop)
		{
			ItemData itemData = keyItemDrop.m_itemData;
			if (!TryInitKey(itemData))
			{
				return;
			}
			if (!itemData.m_shared.m_canBeReparied)
			{
				Log.Info((object)"Can not be repaired, not configured or no repair station defined.", (ushort)0);
				return;
			}
			Recipe recipe = ObjectDB.instance.GetRecipe(itemData);
			if (Object.op_Implicit((Object)(object)recipe))
			{
				Log.Info((object)"Recipe already exists", (ushort)0);
				return;
			}
			Log.Info((object)"No recipe defined, adding repair/upgrade recipe", (ushort)0);
			bool flag = itemData.m_shared.m_maxQuality > 1;
			recipe = ScriptableObject.CreateInstance<Recipe>();
			recipe.m_item = keyItemDrop;
			recipe.m_enabled = flag;
			recipe.m_resources = Configs.UpgradeCost.Value.ToRequirements(':');
			CraftingStation craftingStation = PrefabManagerExt.GetCraftingStation(PrefabManager.Instance, Configs.DefaultStation.Value);
			recipe.m_craftingStation = (flag ? craftingStation : null);
			recipe.m_repairStation = craftingStation;
			recipe.m_minStationLevel = Configs.DefaultStationLevel.Value;
			UpgradeKeyRecipes.Add(recipe);
		}

		private static bool IsLimitedUseKey(this ItemData item)
		{
			string prefabName = ItemDataExt.GetPrefabName(item);
			if (Configs.IndestructibleDoorKeys.Value.Contains(prefabName, true))
			{
				return false;
			}
			ItemDrop component = ObjectDB.instance.GetItemPrefab(prefabName).GetComponent<ItemDrop>();
			return Keys.Contains(component);
		}

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

		private static void UseLimitedKey(this Player player, ItemDrop item)
		{
			ItemData val = ((Humanoid)player).GetInventory().FindLimitedKey(item);
			if (val != null)
			{
				val.m_durability = Mathf.Clamp(val.m_durability - 1f, 0f, val.GetMaxDurability());
				if (!(val.m_durability > 0f))
				{
					Log.Info((object)("Key broke " + ItemDataExt.GetName(val)), (ushort)0);
					((Character)player).Message((MessageType)2, StringExt.Localize("$msg_broke", new string[1] { ItemDataExt.GetName(val) }), 0, (Sprite)null);
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Door), "Interact")]
		private static void Door_Interact(Door __instance, Humanoid character, bool __result)
		{
			if (Configs.UsageLimit.Value != 0 && __result && Object.op_Implicit((Object)(object)__instance.m_keyItem))
			{
				Player val = (Player)(object)((character is Player) ? character : null);
				if (val != null)
				{
					val.UseLimitedKey(__instance.m_keyItem);
				}
			}
		}

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

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Game), "Start")]
		private static void Game_Start()
		{
			foreach (Recipe upgradeKeyRecipe in UpgradeKeyRecipes)
			{
				ObjectDB.instance.m_recipes.Add(upgradeKeyRecipe);
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(InventoryGui), "UpdateRecipeList")]
		private static void InventoryGui_UpdateRecipeList(InventoryGui __instance, List<Recipe> recipes)
		{
			if (!__instance.InCraftTab())
			{
				return;
			}
			foreach (Recipe upgradeKeyRecipe in UpgradeKeyRecipes)
			{
				recipes.Remove(upgradeKeyRecipe);
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(InventoryGui), "Show")]
		private static void InventoryGui_Show(Container? container)
		{
			ValidateKeys(((Humanoid)Player.m_localPlayer).GetInventory().GetAllItems());
			if (Object.op_Implicit((Object)(object)container))
			{
				ValidateKeys(container.GetInventory().GetAllItems());
			}
			static void ValidateKeys(IEnumerable<ItemData> items)
			{
				foreach (ItemData item in items)
				{
					TryInitKey(item);
				}
			}
		}
	}
	[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 = Config.Define<StringList>(true, "Craft / Teleport", "Teleport Items - Deny", StringList.Empty, "List of items which CAN NOT be teleported.\r\n[reboot required for changes to take effect]");

			public static readonly ConfigEntry<StringList> TeleportItemsAllow = Config.Define<StringList>(true, "Craft / Teleport", "Teleport Items - Allow", StringList.Empty, "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;
					Log.Info((object)$"AllowTeleport Item: {((Object)val).name} - {state}", (ushort)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;
					Log.Info((object)("NoCraft Item: " + text), (ushort)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;
					Log.Info((object)("NoCraft Piece: " + ((Object)val).name), (ushort)0);
				}
			}
		}
	}
	[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))
			{
				Log.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 Spawners
	{
		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: " + ZenMod<Plugin>.Terminal.Prefix + "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_0152: Unknown result type (might be due to invalid IL or missing references)
				//IL_0175: Unknown result type (might be due to invalid IL or missing references)
				//IL_0187: Unknown result type (might be due to invalid IL or missing references)
				//IL_01a2: 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}.");
						value.AllowedPrefabs = Config.Define<StringList>(true, "Spawners", $"{item} - Allowed Creatures", StringList.Empty, $"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 mhunting 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);
				Log.Info((object)s, (ushort)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))
				{
					Log.Info((object)$"{biome} - Always allowed to spawn: {prefabName}", (ushort)0);
				}
				else if (value.BlockedPrefabs.Value.Contains(prefabName, true))
				{
					Log.Info((object)$"{biome} - Blocking spawn of {prefabName}", (ushort)0);
					__runOriginal = false;
				}
				else if (!critter.m_prefab.TryGetComponent<BaseAI>(ref val))
				{
					Log.Info((object)string.Format("{0} - No {1} for {2}, spawning. (Ignoring other rules)", biome, "BaseAI", prefabName), (ushort)0);
				}
				else if (value.BlockedGlobalKeys.Value.Contains(critter.m_requiredGlobalKey, true))
				{
					Log.Info((object)$"{biome} - Blocking spawn of {prefabName} due to blocked key: {critter.m_requiredGlobalKey}", (ushort)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(Spawners), "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
			{
				Log.Info((object)$"Disabling HuntPlayer for {((Object)baseAI2).name} in {biome}", (ushort)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]
	public static class TombStoneRules
	{
		private static class Configs
		{
			private const string SECTION_TOMBSTONE = "Tombstone";

			public static readonly ConfigEntry<bool> DecayAfterOpen = Config.Define<bool>(true, "Tombstone", "Decay After Open", true, "Tombstones are a free 32 slot indestructible containers that can be easily abused.\r\nThis option prevents them from being used as reusable containers.\r\nOnce opened, a tombstone will begin to decay. When it finishes decaying, it will \r\nself-destruct and drop all its contents on the ground.\r\nThe countdown will not start until it has been opened once. (vanilla: false)");

			public static readonly ConfigEntry<int> DecayMessageCooldown = Config.Define<int>(true, "Tombstone", "Decay Message Interval", 30, Config.AcceptRange<int>(0, 600), "How frequently should warning messages be displayed when the tombstone is decaying? (seconds)\r\nSet to 0 to disable repeating warning messages.");

			public static readonly ConfigEntry<int> DecayTimer = Config.Define<int>(true, "Tombstone", "Decay Timer", 1800, Config.AcceptRange<int>(0, 3600), "After opening the tombstone once, how long before it self-destructs? (seconds)\r\nWhen it self destructs it will drop all items on the ground.\r\nDefault is 1 game day (30 minutes) \r\n0 = self-destruct instantly after closing the container.");
		}

		[CompilerGenerated]
		private sealed class <ShakeAnimation>d__11 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public TombStone tombStone;

			private float <startTime>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <ShakeAnimation>d__11(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_008c: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
				//IL_00de: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e8: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					goto IL_00f8;
				case 1:
					<>1__state = -1;
					goto IL_00ad;
				case 2:
					{
						<>1__state = -1;
						goto IL_00f8;
					}
					IL_00f8:
					if (!IsDecayExpired(tombStone))
					{
						<startTime>5__2 = Time.time;
						goto IL_00ad;
					}
					return false;
					IL_00ad:
					if (Time.time < <startTime>5__2 + 1f)
					{
						float time = Time.time;
						float num = 1f - Mathf.Clamp01(time - <startTime>5__2);
						float num2 = num * num * num * 1.5f;
						((Component)tombStone).transform.localRotation = Quaternion.Euler(Mathf.Sin(time * 40f) * num2, 0f, Mathf.Cos(time * 0.9f * 40f) * num2);
						<>2__current = null;
						<>1__state = 1;
						return true;
					}
					((Component)tombStone).transform.localRotation = Quaternion.identity;
					<>2__current = (object)new WaitForSeconds(2f);
					<>1__state = 2;
					return true;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private const float ShakeIntervalDelay = 2f;

		private static float _lastDecayMessageTime;

		[HarmonyPrefix]
		[HarmonyPatch(typeof(InventoryGui), "Hide")]
		private static void InventoryGui_Hide(InventoryGui __instance)
		{
			TombStone val = default(TombStone);
			if (Configs.DecayAfterOpen.Value && Object.op_Implicit((Object)(object)__instance.m_currentContainer) && ((Component)__instance.m_currentContainer).TryGetComponent<TombStone>(ref val) && !IsDecayStarted(val))
			{
				Log.Info((object)"Start tombstone decay", (ushort)0);
				val.m_nview.GetZDO().Set(ZDOVars.s_pickedTime, ZNet.instance.GetTime().Ticks);
				WarnPlayer(val);
				((MonoBehaviour)val).StartCoroutine(ShakeAnimation(val));
			}
		}

		private static void WarnPlayer(TombStone tombStone)
		{
			Timing.Delay((MonoBehaviour)(object)tombStone, 0.5f, (Action)delegate
			{
				((Character)Player.m_localPlayer).Message((MessageType)2, "$tombstone_decay_warning", 0, (Sprite)null);
				_lastDecayMessageTime = Time.time;
			});
		}

		private static float DecayElapsedSeconds(TombStone tombStone)
		{
			long @long = tombStone.m_nview.GetZDO().GetLong(ZDOVars.s_pickedTime, 0L);
			if (@long == 0L)
			{
				return 0f;
			}
			DateTime dateTime = new DateTime(@long);
			return (float)(ZNet.instance.GetTime() - dateTime).TotalSeconds;
		}

		private static bool IsDecayExpired(TombStone tombStone)
		{
			if (IsDecayStarted(tombStone))
			{
				return DecayElapsedSeconds(tombStone) >= (float)Configs.DecayTimer.Value;
			}
			return false;
		}

		private static bool IsDecayStarted(TombStone tombStone)
		{
			return DecayElapsedSeconds(tombStone) > 0f;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(TombStone), "UpdateDespawn")]
		private static void TombStone_UpdateDespawn(TombStone __instance)
		{
			if (Configs.DecayAfterOpen.Value)
			{
				if (IsDecayStarted(__instance) && Time.time > _lastDecayMessageTime + (float)Configs.DecayMessageCooldown.Value && Configs.DecayMessageCooldown.Value > 0)
				{
					WarnPlayer(__instance);
				}
				if (__instance.m_nview.IsOwner() && IsDecayExpired(__instance) && !__instance.m_container.IsInUse())
				{
					Log.Info((object)"Tombstone self destruct, dump all contents", (ushort)0);
					__instance.m_container.DropAllItems();
				}
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(TombStone), "GiveBoost")]
		private static void TombStone_GiveBoost(TombStone __instance, ref bool __runOriginal)
		{
			if (Configs.DecayAfterOpen.Value && IsDecayExpired(__instance))
			{
				__runOriginal = false;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(TombStone), "GetHoverText")]
		[HarmonyPriority(300)]
		private static void TombStone_GetHoverText(TombStone __instance, ref string __result)
		{
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			if (Configs.DecayAfterOpen.Value && IsDecayStarted(__instance) && Configs.DecayTimer.Value > 0)
			{
				float num = DecayElapsedSeconds(__instance);
				float num2 = Mathf.Max(0f, (float)Configs.DecayTimer.Value - num);
				int num3 = 100 - Mathf.FloorToInt(Mathf.Clamp01(num2 / (float)Configs.DecayTimer.Value) * 100f);
				string arg = StringExt.Localize("$tombstone_decay", new string[1] { num3.ToString() });
				__result += $"\n<color={UIColor.MajorInfo}>{arg}</color>";
			}
		}

		[IteratorStateMachine(typeof(<ShakeAnimation>d__11))]
		private static IEnumerator ShakeAnimation(TombStone tombStone)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <ShakeAnimation>d__11(0)
			{
				tombStone = tombStone
			};
		}
	}
	[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())
			{
				Log.Info((object)"Turret is empty", (ushort)0);
				return false;
			}
			Log.Info((object)"Eject Ammo", (ushort)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))
			{
				Log.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)
		{
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			__runOriginal = false;
			if (!__instance.m_nview.IsValid())
			{
				__result = "";
				return;
			}
			if (!__instance.m_targetEnemies)
			{
				__result = Localization.instance.Localize(__instance.m_name);
				return;
			}
			HudExt.UpdateHoverIcons(Hud.instance, __instance.m_targetItems.Select((ItemDrop item) => ItemDataExt.GetIcon(item)).ToArray());
			__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)
			{
				ZColor val = ((Configs.TargetPlayers.Value || Configs.TargetTamed.Value) ? UIColor.MajorInfo : UIColor.Teal);
				__instance.sb.Append($"<color={val}>");
				__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;

			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.");
				ShowDayNumber = Config.Define<bool>(true, "Environment", "Show Day Number", false, "Display the day number each morning. (Vanilla: true)");
				ShowSkyTree.SettingChanged += delegate
				{
					SetSkyTree();
				};
				ShowWindPixels.SettingChanged += delegate
				{
					SetWindPixels();
				};
				DayLengthSeconds.SettingChanged += delegate
				{
					SetDayLength();
				};
			}
		}

		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 Init()
		{
			SetDayLength();
			SetSkyTree();
			SetWindPixels();
		}

		private static void SetSkyTree()
		{
			if (IsMainScene)
			{
				GameObject.Find("_GameMain/_Environment/YggdrasilBranch").SetActive(Configs.ShowSkyTree.Value);
			}
		}

		private static void SetWindPixels()
		{
			if (IsMainScene)
			{
				GameObject.Find("_GameMain/_Environment/FollowPlayer/GlobalWindParticles/particles_pixel").SetActive(Configs.ShowWindPixels.Value);
			}
		}

		private static void SetDayLength()
		{
			if (IsMainScene)
			{
				EnvMan instance = EnvMan.instance;
				if (Configs.DayLengthSeconds.Value > 0)
				{
					instance.m_dayLengthSec = Configs.DayLengthSeconds.Value;
				}
				Log.Message((object)$"Day Length: {instance.m_dayLengthSec} seconds", (ushort)0);
			}
		}

		[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
			{
				Log.Message((object)("Morning message suppressed: " + msg), (ushort)0);
			}
		}
	}
}