Decompiled source of CraftedBossDrops v1.0.9

plugins\CraftedBossDrops.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using Common;
using HarmonyLib;
using Jotunn;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("CraftedBossDrops")]
[assembly: AssemblyDescription("https://thunderstore.io/c/valheim/p/probablykory/CraftedBossDrops/")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("probablykory")]
[assembly: AssemblyCopyright("Copyright probablykory © 2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")]
[assembly: AssemblyFileVersion("1.0.9")]
[assembly: AssemblyProduct("CraftedBossDrops")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.9.0")]
[module: <2bbef6a2-ec2f-455d-af37-047412e59296>RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[<d8c74559-f18f-47c0-ad96-ff69778ec96d>Embedded]
	internal sealed class <d8c74559-f18f-47c0-ad96-ff69778ec96d>EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	[<d8c74559-f18f-47c0-ad96-ff69778ec96d>Embedded]
	[CompilerGenerated]
	internal sealed class <2bbef6a2-ec2f-455d-af37-047412e59296>RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public <2bbef6a2-ec2f-455d-af37-047412e59296>RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace CraftedBossDrops
{
	public class Entries
	{
		private Action<object, EventArgs> _action;

		public string Name { get; set; } = string.Empty;


		public ConfigEntry<string> Table { get; set; }

		public ConfigEntry<int> MinTableLevel { get; set; }

		public ConfigEntry<int> Amount { get; set; }

		public ConfigEntry<string> Requirements { get; set; }

		public static Entries GetFromProps(IPlugin instance, string name, string table, int minTableLevel, int amount, string requirements)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Expected O, but got Unknown
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Expected O, but got Unknown
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Expected O, but got Unknown
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Expected O, but got Unknown
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Expected O, but got Unknown
			Entries entries = new Entries();
			entries.Name = name;
			entries.Table = instance.Config(entries.Name, "Table", table, new ConfigDescription("Crafting station needed to craft " + entries.Name + ".", (AcceptableValueBase)(object)CraftingStations.GetAcceptableValueList(), new object[1] { ConfigHelper.GetAdminOnlyFlag() }));
			entries.MinTableLevel = instance.Config(entries.Name, "Table Level", minTableLevel, new ConfigDescription("Level of crafting station required to craft " + entries.Name + ".", (AcceptableValueBase)null, new object[1] { ConfigHelper.GetAdminOnlyFlag() }));
			entries.Amount = instance.Config(entries.Name, "Amount", amount, new ConfigDescription("The amount of " + entries.Name + " created.", (AcceptableValueBase)null, new object[1] { ConfigHelper.GetAdminOnlyFlag() }));
			entries.Requirements = instance.Config(entries.Name, "Requirements", requirements, new ConfigDescription("The required items to craft " + entries.Name + ".", (AcceptableValueBase)(object)new AcceptableValueConfigNote("You must use valid spawn item codes."), new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true,
				CustomDrawer = SharedDrawers.DrawReqConfigTable()
			} }));
			return entries;
		}

		private void OnSettingChanged(object sender, EventArgs e)
		{
			if (_action != null)
			{
				_action(sender, e);
			}
		}

		public void AddSettingsChangedHandler(Action<object, EventArgs> action)
		{
			_action = action;
			Table.SettingChanged += OnSettingChanged;
			MinTableLevel.SettingChanged += OnSettingChanged;
			Amount.SettingChanged += OnSettingChanged;
			Requirements.SettingChanged += OnSettingChanged;
		}

		public void RemoveSettingsChangedHandler()
		{
			Table.SettingChanged -= OnSettingChanged;
			MinTableLevel.SettingChanged -= OnSettingChanged;
			Amount.SettingChanged -= OnSettingChanged;
			Requirements.SettingChanged -= OnSettingChanged;
			_action = null;
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("probablykory.CraftedBossDrops", "CraftedBossDrops", "1.0.9")]
	internal class CraftedBossDrops : BaseUnityPlugin, IPlugin
	{
		public const string PluginAuthor = "probablykory";

		public const string PluginName = "CraftedBossDrops";

		public const string PluginVersion = "1.0.9";

		public const string PluginGUID = "probablykory.CraftedBossDrops";

		private bool settingsUpdated;

		private Harmony harmony;

		internal static CraftedBossDrops Instance;

		private static ConfigEntry<bool> isDebugEnabled;

		private CustomRecipe hardAntlerRecipe;

		private CustomRecipe cryptKeyRecipe;

		private CustomRecipe wishboneRecipe;

		private CustomRecipe dragonTearRecipe;

		private CustomRecipe yagluthDropRecipe;

		private CustomRecipe queenDropRecipe;

		private CustomRecipe faderDropRecipe;

		public ManualLogSource Logger { get; private set; } = Logger.CreateLogSource("CraftedBossDrops");


		public bool Debug
		{
			get
			{
				if (isDebugEnabled == null)
				{
					return true;
				}
				return isDebugEnabled.Value;
			}
		}

		public Entries HardAntlerEntry { get; protected set; }

		public Entries CryptKeyEntry { get; protected set; }

		public Entries WishboneEntry { get; protected set; }

		public Entries DragonTearEntry { get; protected set; }

		public Entries YagluthDropEntry { get; protected set; }

		public Entries QueenDropEntry { get; protected set; }

		public Entries FaderDropEntry { get; protected set; }

		private void Awake()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			harmony = new Harmony("probablykory.CraftedBossDrops");
			harmony.PatchAll();
			isDebugEnabled = this.Config("1 - General", "Debugging Enabled", value: false, "If on, mod will output alot more information in the debug log level.");
			Instance = this;
			InitializeFeatures();
			PrefabManager.OnVanillaPrefabsAvailable += OnVanillaPrefabsAvailable;
			SynchronizationManager.OnConfigurationSynchronized += OnConfigurationSynchronized;
			((BaseUnityPlugin)this).Config.ConfigReloaded += OnConfigReloaded;
			new ConfigWatcher(this);
		}

		private void InitializeFeatures()
		{
			HardAntlerEntry = Entries.GetFromProps(Instance, "HardAntler", "Workbench", 3, 1, "TrophyDeer:10,Resin:20");
			CryptKeyEntry = Entries.GetFromProps(Instance, "CryptKey", "Forge", 3, 1, "AncientSeed:6,Bronze:20");
			WishboneEntry = Entries.GetFromProps(Instance, "Wishbone", "Forge", 7, 1, "WitheredBone:15,Iron:10,TrophyDraugr:3");
			DragonTearEntry = Entries.GetFromProps(Instance, "DragonTear", "Workbench", 5, 2, "DragonEgg:4,Crystal:16");
			YagluthDropEntry = Entries.GetFromProps(Instance, "YagluthDrop", "ArtisanTable", 1, 2, "GoblinTotem:10,TrophyGoblin:3,TrophyGoblinShaman:1,TrophyGoblinBrute:1");
			QueenDropEntry = Entries.GetFromProps(Instance, "QueenDrop", "BlackForge", 2, 1, "DvergrKeyFragment:10,Mandible:5,TrophySeeker:3,TrophySeekerBrute:1");
			FaderDropEntry = Entries.GetFromProps(Instance, "FaderDrop", "ArtisanTable", 2, 1, "BellFragment:10,MorgenHeart:5,TrophyCharredMelee:4,TrophyCharredMage:1");
			HardAntlerEntry.AddSettingsChangedHandler(OnSettingsChanged);
			CryptKeyEntry.AddSettingsChangedHandler(OnSettingsChanged);
			WishboneEntry.AddSettingsChangedHandler(OnSettingsChanged);
			DragonTearEntry.AddSettingsChangedHandler(OnSettingsChanged);
			YagluthDropEntry.AddSettingsChangedHandler(OnSettingsChanged);
			QueenDropEntry.AddSettingsChangedHandler(OnSettingsChanged);
			FaderDropEntry.AddSettingsChangedHandler(OnSettingsChanged);
		}

		private void UpdateFeatures()
		{
			settingsUpdated = false;
			hardAntlerRecipe.Update(getRecipeFromEntry(HardAntlerEntry));
			cryptKeyRecipe.Update(getRecipeFromEntry(CryptKeyEntry));
			wishboneRecipe.Update(getRecipeFromEntry(WishboneEntry));
			dragonTearRecipe.Update(getRecipeFromEntry(DragonTearEntry));
			yagluthDropRecipe.Update(getRecipeFromEntry(YagluthDropEntry));
			queenDropRecipe.Update(getRecipeFromEntry(QueenDropEntry));
			faderDropRecipe.Update(getRecipeFromEntry(FaderDropEntry));
		}

		private void OnVanillaPrefabsAvailable()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Expected O, but got Unknown
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Expected O, but got Unknown
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Expected O, but got Unknown
			this.LogDebugOnly("Vanilla Prefabs Available received.");
			hardAntlerRecipe = new CustomRecipe(getRecipeFromEntry(HardAntlerEntry));
			cryptKeyRecipe = new CustomRecipe(getRecipeFromEntry(CryptKeyEntry));
			wishboneRecipe = new CustomRecipe(getRecipeFromEntry(WishboneEntry));
			dragonTearRecipe = new CustomRecipe(getRecipeFromEntry(DragonTearEntry));
			yagluthDropRecipe = new CustomRecipe(getRecipeFromEntry(YagluthDropEntry));
			queenDropRecipe = new CustomRecipe(getRecipeFromEntry(QueenDropEntry));
			faderDropRecipe = new CustomRecipe(getRecipeFromEntry(FaderDropEntry));
			ItemManager.Instance.AddRecipe(hardAntlerRecipe);
			ItemManager.Instance.AddRecipe(cryptKeyRecipe);
			ItemManager.Instance.AddRecipe(wishboneRecipe);
			ItemManager.Instance.AddRecipe(dragonTearRecipe);
			ItemManager.Instance.AddRecipe(yagluthDropRecipe);
			ItemManager.Instance.AddRecipe(queenDropRecipe);
			ItemManager.Instance.AddRecipe(faderDropRecipe);
			PrefabManager.OnVanillaPrefabsAvailable -= OnVanillaPrefabsAvailable;
		}

		private void OnSettingsChanged(object sender, EventArgs e)
		{
			settingsUpdated = true;
		}

		private void OnConfigReloaded(object sender, EventArgs e)
		{
			if (settingsUpdated)
			{
				UpdateFeatures();
			}
		}

		private void OnConfigurationSynchronized(object sender, ConfigurationSynchronizationEventArgs e)
		{
			UpdateFeatures();
		}

		private RecipeConfig getRecipeFromEntry(Entries entry)
		{
			//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)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: 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_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Expected O, but got Unknown
			return new RecipeConfig
			{
				Item = entry.Name,
				CraftingStation = CraftingStations.GetInternalName(entry.Table.Value),
				RepairStation = CraftingStations.GetInternalName(entry.Table.Value),
				MinStationLevel = entry.MinTableLevel.Value,
				Amount = entry.Amount.Value,
				Requirements = RequirementsEntry.Deserialize(entry.Requirements.Value)
			};
		}

		ConfigFile IPlugin.get_Config()
		{
			return ((BaseUnityPlugin)this).Config;
		}
	}
	public static class Extensions
	{
		private static HashSet<CustomRecipe> hashsetRecipes;

		public static Recipe GetRecipe(this List<Recipe> list, Recipe recipe)
		{
			int num = ObjectDB.instance.m_recipes.IndexOf(recipe);
			if (num > -1)
			{
				return list[num];
			}
			string name = ((object)recipe).ToString();
			return ((IEnumerable<Recipe>)ObjectDB.instance.m_recipes).FirstOrDefault((Func<Recipe, bool>)((Recipe r) => name.Equals(((object)r).ToString())));
		}

		public static bool Update(this CustomRecipe recipe, RecipeConfig newRecipe)
		{
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Expected O, but got Unknown
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Expected O, but got Unknown
			if (hashsetRecipes == null)
			{
				FieldInfo fieldInfo = ((object)ItemManager.Instance).GetType().GetMembers(BindingFlags.Instance | BindingFlags.NonPublic).FirstOrDefault((MemberInfo m) => m.Name == "Recipes") as FieldInfo;
				if (fieldInfo != null && fieldInfo.GetValue(ItemManager.Instance) is HashSet<CustomRecipe> hashSet)
				{
					hashsetRecipes = hashSet;
				}
			}
			Recipe recipe2 = ObjectDB.instance.m_recipes.GetRecipe(recipe.Recipe);
			if ((Object)(object)recipe2 == (Object)null)
			{
				if (hashsetRecipes != null && hashsetRecipes.Contains(recipe))
				{
					IPlugin plugin = Get.Plugin;
					object obj;
					if (recipe == null)
					{
						obj = null;
					}
					else
					{
						Recipe recipe3 = recipe.Recipe;
						obj = ((recipe3 != null) ? ((Object)recipe3).name : null);
					}
					plugin.LogDebugOnly("Removing and re-adding recipe " + (string?)obj + " in ItemManager.");
					ItemManager.Instance.RemoveRecipe(recipe);
					ItemManager.Instance.AddRecipe(new CustomRecipe(newRecipe));
					return true;
				}
				object obj2;
				if (recipe == null)
				{
					obj2 = null;
				}
				else
				{
					Recipe recipe4 = recipe.Recipe;
					obj2 = ((recipe4 != null) ? ((Object)recipe4).name : null);
				}
				Logger.LogError((object)("Error updating recipe " + (string?)obj2 + ", did not find existing recipe in ObjectDB or ItemManager"));
				return false;
			}
			IPlugin plugin2 = Get.Plugin;
			object obj3;
			if (recipe == null)
			{
				obj3 = null;
			}
			else
			{
				Recipe recipe5 = recipe.Recipe;
				obj3 = ((recipe5 != null) ? ((Object)recipe5).name : null);
			}
			plugin2.LogDebugOnly("Updating recipe " + (string?)obj3 + " in place.");
			recipe2.m_amount = newRecipe.Amount;
			recipe2.m_minStationLevel = newRecipe.MinStationLevel;
			GameObject prefab = PrefabManager.Instance.GetPrefab(newRecipe.CraftingStation);
			recipe2.m_craftingStation = ((prefab != null) ? prefab.GetComponent<CraftingStation>() : null);
			recipe2.m_resources = newRecipe.GetRequirements();
			Requirement[] resources = recipe2.m_resources;
			foreach (Requirement val in resources)
			{
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(((Object)val.m_resItem).name.Replace("JVLmock_", ""));
				if ((Object)(object)itemPrefab != (Object)null)
				{
					val.m_resItem = itemPrefab.GetComponent<ItemDrop>();
				}
			}
			if (hashsetRecipes != null)
			{
				hashsetRecipes.Remove(recipe);
				hashsetRecipes.Add(new CustomRecipe(recipe2, false, false));
			}
			return true;
		}
	}
	[HarmonyPatch]
	public static class TraderPatch
	{
		private static Dictionary<string, string> GlobalKeyTokenMap = new Dictionary<string, string>
		{
			{ "defeated_eikthyr", "$item_hardantler" },
			{ "defeated_gdking", "$item_cryptkey" },
			{ "defeated_bonemass", "$item_wishbone" },
			{ "defeated_dragon", "$item_dragontear" },
			{ "defeated_goblinking", "$item_yagluththing" },
			{ "defeated_queen", "$item_queen_drop" },
			{ "defeated_fader", "$item_fader_drop" }
		};

		[HarmonyPatch(typeof(Trader), "GetAvailableItems")]
		[HarmonyPostfix]
		public static List<TradeItem> TraderGetAvailableItems(List<TradeItem> values, Trader __instance)
		{
			if ((Object)(object)__instance == (Object)null)
			{
				return values;
			}
			if (((__instance == null) ? null : ((Object)__instance).name?.Contains("Haldor")).Value || ((__instance == null) ? null : ((Object)__instance).name?.Contains("BogWitch")).Value)
			{
				List<TradeItem> list = new List<TradeItem>();
				{
					foreach (TradeItem item in __instance.m_items)
					{
						if (string.IsNullOrEmpty(item.m_requiredGlobalKey) || ZoneSystem.instance.GetGlobalKey(item.m_requiredGlobalKey) || (GlobalKeyTokenMap.ContainsKey(item.m_requiredGlobalKey) && Player.m_localPlayer.IsKnownMaterial(GlobalKeyTokenMap[item.m_requiredGlobalKey])))
						{
							list.Add(item);
						}
					}
					return list;
				}
			}
			return values;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Player), "AddKnownItem")]
		public static void PlayerAddKnownItem(ItemData item, Player __instance)
		{
			object obj;
			if (item == null)
			{
				obj = null;
			}
			else
			{
				GameObject dropPrefab = item.m_dropPrefab;
				obj = ((dropPrefab != null) ? ((Object)dropPrefab).name : null);
			}
			string text = (string)obj;
			if (!string.IsNullOrEmpty(text) && string.Equals(text, "HardAntler") && !__instance.m_knownMaterial.Contains(item.m_shared.m_name))
			{
				__instance.SetSeenTutorial("blackforest");
			}
		}
	}
}
namespace Microsoft.CodeAnalysis
{
	[Microsoft.CodeAnalysis.Embedded]
	[CompilerGenerated]
	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]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	[Microsoft.CodeAnalysis.Embedded]
	[CompilerGenerated]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Common
{
	internal class AcceptableValueConfigNote : AcceptableValueBase
	{
		public virtual string Note { get; }

		public AcceptableValueConfigNote(string note)
			: base(typeof(string))
		{
			if (string.IsNullOrEmpty(note))
			{
				throw new ArgumentException("A string with atleast 1 character is needed", "Note");
			}
			Note = note;
		}

		public override object Clamp(object value)
		{
			return value;
		}

		public override bool IsValid(object value)
		{
			return !string.IsNullOrEmpty(value as string);
		}

		public override string ToDescriptionString()
		{
			return "# Note: " + Note;
		}
	}
	internal static class ConfigHelper
	{
		public static ConfigurationManagerAttributes GetAdminOnlyFlag()
		{
			//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)
			//IL_000d: Expected O, but got Unknown
			return new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			};
		}

		public static ConfigurationManagerAttributes GetTags(Action<ConfigEntryBase> action)
		{
			//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)
			//IL_000d: Expected O, but got Unknown
			return new ConfigurationManagerAttributes
			{
				CustomDrawer = action
			};
		}

		public static ConfigurationManagerAttributes GetTags()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			return new ConfigurationManagerAttributes();
		}

		public static ConfigEntry<T> Config<T>(this IPlugin instance, string group, string name, T value, ConfigDescription description)
		{
			return instance.Config.Bind<T>(group, name, value, description);
		}

		public static ConfigEntry<T> Config<T>(this IPlugin instance, string group, string name, T value, string description)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			return instance.Config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, new object[1] { GetAdminOnlyFlag() }));
		}
	}
	internal static class RequirementsEntry
	{
		public static RequirementConfig[] Deserialize(string reqs)
		{
			return ((IEnumerable<string>)reqs.Split(new char[1] { ',' })).Select((Func<string, RequirementConfig>)delegate(string r)
			{
				//IL_0012: 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_0020: Unknown result type (might be due to invalid IL or missing references)
				//IL_003c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0058: Unknown result type (might be due to invalid IL or missing references)
				//IL_0060: Expected O, but got Unknown
				string[] array = r.Split(new char[1] { ':' });
				int result;
				int result2;
				return new RequirementConfig
				{
					Item = array[0],
					Amount = ((array.Length <= 1 || !int.TryParse(array[1], out result)) ? 1 : result),
					AmountPerLevel = ((array.Length > 2 && int.TryParse(array[2], out result2)) ? result2 : 0),
					Recover = true
				};
			}).ToArray();
		}

		public static string Serialize(RequirementConfig[] reqs)
		{
			return string.Join(",", reqs.Select((RequirementConfig r) => (r.AmountPerLevel <= 0) ? $"{r.Item}:{r.Amount}" : $"{r.Item}:{r.Amount}:{r.AmountPerLevel}"));
		}
	}
	internal static class SharedDrawers
	{
		private static BaseUnityPlugin configManager;

		private static BaseUnityPlugin GetConfigManager()
		{
			if ((Object)(object)configManager == (Object)null && Chainloader.PluginInfos.TryGetValue("com.bepis.bepinex.configurationmanager", out var value) && Object.op_Implicit((Object)(object)value.Instance))
			{
				configManager = value.Instance;
			}
			return configManager;
		}

		public static int GetRightColumnWidth()
		{
			int result = 130;
			BaseUnityPlugin val = GetConfigManager();
			if ((Object)(object)val != (Object)null)
			{
				PropertyInfo propertyInfo = ((object)val)?.GetType().GetProperty("RightColumnWidth", BindingFlags.Instance | BindingFlags.NonPublic);
				if (propertyInfo != null)
				{
					result = (int)propertyInfo.GetValue(val);
				}
			}
			return result;
		}

		public static void ReloadConfigDisplay()
		{
			BaseUnityPlugin val = GetConfigManager();
			if ((Object)(object)val != (Object)null)
			{
				object obj = ((object)val).GetType()?.GetProperty("DisplayingWindow")?.GetValue(val);
				if (obj is bool && (bool)obj)
				{
					((object)val).GetType().GetMethod("BuildSettingList").Invoke(val, Array.Empty<object>());
				}
			}
		}

		public static Action<ConfigEntryBase> DrawReqConfigTable(bool hasUpgrades = false)
		{
			return delegate(ConfigEntryBase cfg)
			{
				//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_008d: Expected O, but got Unknown
				//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ee: Expected O, but got Unknown
				//IL_0163: Unknown result type (might be due to invalid IL or missing references)
				//IL_0168: Unknown result type (might be due to invalid IL or missing references)
				//IL_017d: Expected O, but got Unknown
				//IL_0125: Unknown result type (might be due to invalid IL or missing references)
				//IL_012a: Unknown result type (might be due to invalid IL or missing references)
				//IL_013f: 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_0191: Unknown result type (might be due to invalid IL or missing references)
				//IL_0199: Unknown result type (might be due to invalid IL or missing references)
				//IL_01a6: Expected O, but got Unknown
				//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
				//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
				//IL_01cf: Expected O, but got Unknown
				//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
				//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
				//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
				//IL_01f0: Expected O, but got Unknown
				List<RequirementConfig> list = new List<RequirementConfig>();
				bool flag = false;
				int rightColumnWidth = GetRightColumnWidth();
				GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
				foreach (RequirementConfig item in RequirementsEntry.Deserialize((string)cfg.BoxedValue).ToList())
				{
					GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
					string text = GUILayout.TextField(item.Item, new GUIStyle(GUI.skin.textField)
					{
						fixedWidth = rightColumnWidth - 33 - (hasUpgrades ? 37 : 0) - 21 - 21 - 12
					}, Array.Empty<GUILayoutOption>());
					string text2 = (string.IsNullOrEmpty(text) ? item.Item : text);
					flag = flag || text2 != item.Item;
					int num = item.Amount;
					if (int.TryParse(GUILayout.TextField(num.ToString(), new GUIStyle(GUI.skin.textField)
					{
						fixedWidth = 33f
					}, Array.Empty<GUILayoutOption>()), out var result) && result != num)
					{
						num = result;
						flag = true;
					}
					int num2 = item.AmountPerLevel;
					if (hasUpgrades && int.TryParse(GUILayout.TextField(num2.ToString(), new GUIStyle(GUI.skin.textField)
					{
						fixedWidth = 33f
					}, Array.Empty<GUILayoutOption>()), out var result2) && result2 != num2)
					{
						num2 = result2;
						flag = true;
					}
					if (GUILayout.Button("x", new GUIStyle(GUI.skin.button)
					{
						fixedWidth = 21f
					}, Array.Empty<GUILayoutOption>()))
					{
						flag = true;
					}
					else
					{
						list.Add(new RequirementConfig
						{
							Item = text2,
							Amount = num,
							AmountPerLevel = num2
						});
					}
					if (GUILayout.Button("+", new GUIStyle(GUI.skin.button)
					{
						fixedWidth = 21f
					}, Array.Empty<GUILayoutOption>()))
					{
						flag = true;
						list.Add(new RequirementConfig
						{
							Item = "<Prefab Name>",
							Amount = 1
						});
					}
					GUILayout.EndHorizontal();
				}
				GUILayout.EndVertical();
				if (flag)
				{
					cfg.BoxedValue = RequirementsEntry.Serialize(list.ToArray());
				}
			};
		}
	}
	internal class ConfigWatcher
	{
		private BaseUnityPlugin configurationManager;

		private IPlugin plugin;

		public ConfigWatcher(IPlugin plugin)
		{
			if (plugin == null)
			{
				throw new ArgumentNullException("plugin");
			}
			this.plugin = plugin;
			CheckForConfigManager();
		}

		private void InitializeWatcher()
		{
			string fileName = Path.GetFileName(plugin.Config.ConfigFilePath);
			new Watcher(Path.GetDirectoryName(plugin.Config.ConfigFilePath), fileName).FileChanged += OnFileChanged;
			Get.Plugin.LogDebugOnly("File system watcher initialized.");
		}

		private void CheckForConfigManager()
		{
			PluginInfo value;
			if (GUIManager.IsHeadless())
			{
				InitializeWatcher();
			}
			else if (Chainloader.PluginInfos.TryGetValue("com.bepis.bepinex.configurationmanager", out value) && Object.op_Implicit((Object)(object)value.Instance))
			{
				configurationManager = value.Instance;
				Get.Plugin.LogDebugOnly("Configuration manager found, hooking DisplayingWindowChanged");
				EventInfo @event = ((object)configurationManager).GetType().GetEvent("DisplayingWindowChanged");
				if (@event != null)
				{
					Action<object, object> action = OnConfigManagerDisplayingWindowChanged;
					Delegate handler = Delegate.CreateDelegate(@event.EventHandlerType, action.Target, action.Method);
					@event.AddEventHandler(configurationManager, handler);
				}
			}
			else
			{
				InitializeWatcher();
			}
		}

		private void OnFileChanged(object sender, FileSystemEventArgs e)
		{
			string configFilePath = plugin.Config.ConfigFilePath;
			if (!File.Exists(configFilePath))
			{
				return;
			}
			try
			{
				plugin.Config.SaveOnConfigSet = false;
				plugin.Config.Reload();
				plugin.Config.SaveOnConfigSet = true;
			}
			catch
			{
				Get.Plugin.LogError("There was an issue with your " + Path.GetFileName(configFilePath) + " file.");
				Get.Plugin.LogError("Please check the format and spelling.");
			}
		}

		private void OnConfigManagerDisplayingWindowChanged(object sender, object e)
		{
			if (!(bool)((object)configurationManager).GetType().GetProperty("DisplayingWindow").GetValue(configurationManager, null))
			{
				plugin.Config.SaveOnConfigSet = false;
				plugin.Config.Reload();
				plugin.Config.SaveOnConfigSet = true;
			}
		}
	}
	internal class CustomSyncedValueBase
	{
		private class Patches
		{
			[HarmonyPatch(typeof(ZNet), "Shutdown")]
			[HarmonyPostfix]
			private static void ZNet_Shutdown()
			{
				if (ZNetExtension.IsClientInstance(ZNet.instance))
				{
					foreach (CustomSyncedValueBase syncedValue in SyncedValues)
					{
						syncedValue.OnResetFromServer();
					}
					return;
				}
				foreach (CustomSyncedValueBase syncedValue2 in SyncedValues)
				{
					syncedValue2.OnServerShutdown();
				}
			}
		}

		public readonly string Name;

		public readonly Type Type;

		private object? boxedValue;

		public object? LocalBaseValue;

		private CustomRPC customRPC;

		private static readonly HashSet<CustomSyncedValueBase> SyncedValues = new HashSet<CustomSyncedValueBase>();

		private static Harmony harmony = null;

		public bool IsSourceOfTruth { get; private set; } = true;


		public object? BoxedValue
		{
			get
			{
				return boxedValue;
			}
			set
			{
				boxedValue = value;
				this.ValueChanged?.Invoke(this, value);
			}
		}

		public event Action<object, object>? ValueChanged;

		protected CustomSyncedValueBase(string name, Type type, object? initialValue)
		{
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Expected O, but got Unknown
			//IL_00af: Expected O, but got Unknown
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			Name = name;
			Type = type;
			SyncedValues.Add(this);
			if (harmony == null)
			{
				harmony = (Harmony)AccessTools.Field(typeof(Main), "Harmony").GetValue(null);
				harmony.PatchAll(typeof(Patches));
				Get.Plugin.LogDebugOnly("Jotunn's harmony instance obtained, CustomSyncedValueBase+Patches applied.");
			}
			boxedValue = initialValue;
			customRPC = NetworkManager.Instance.AddRPC(Name + "_CustomSyncedValue_RPC", new CoroutineHandler(OnServerReceive), new CoroutineHandler(OnClientReceive));
			SynchronizationManager.Instance.AddInitialSynchronization(customRPC, (Func<ZPackage>)GetPackage);
		}

		public void SendPackage()
		{
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				Get.Plugin.LogDebugOnly("SendPackage called but am not connected.");
			}
			if (!SynchronizationManager.Instance.PlayerIsAdmin)
			{
				Get.Plugin.LogDebugOnly("SendPackage called but Player is not admin.");
			}
			if ((Object)(object)ZNet.instance != (Object)null && SynchronizationManager.Instance.PlayerIsAdmin)
			{
				ZPackage package = GetPackage();
				if (ZNetExtension.IsClientInstance(ZNet.instance))
				{
					customRPC.SendPackage(ZRoutedRpc.instance.GetServerPeerID(), package);
				}
				else
				{
					customRPC.SendPackage(ZNet.instance.m_peers, package);
				}
			}
		}

		private ZPackage GetPackage()
		{
			return new PackageEntry
			{
				key = Name,
				type = Type,
				value = boxedValue
			}.ToPackage();
		}

		private IEnumerator OnServerReceive(long sender, ZPackage package)
		{
			Get.Plugin.LogDebugOnly($"Server received RPC: {sender} {package}");
			yield return null;
			ParsedEntries parsedEntries = package.ReadEntries();
			if (parsedEntries.Count > 0 && parsedEntries.TryGetValue(Name, out var value))
			{
				BoxedValue = (LocalBaseValue = value.value);
				Get.Plugin.LogDebugOnly($"Set local and boxed: {value.value}");
				customRPC.SendPackage(ZNet.instance.m_peers.Where((ZNetPeer x) => x.m_uid != sender).ToList(), package);
			}
			else
			{
				OnReceiveError(parsedEntries);
			}
		}

		private IEnumerator OnClientReceive(long sender, ZPackage package)
		{
			Get.Plugin.LogDebugOnly($"Client received RPC: {sender} {package}");
			yield return null;
			ParsedEntries parsedEntries = package.ReadEntries();
			if (parsedEntries.Count > 0 && parsedEntries.TryGetValue(Name, out var value))
			{
				IsSourceOfTruth = false;
				if (LocalBaseValue == null)
				{
					LocalBaseValue = BoxedValue;
				}
				BoxedValue = value.value;
				Get.Plugin.LogDebugOnly($"Set source of truth: {IsSourceOfTruth}, {Environment.NewLine}local: {LocalBaseValue} {Environment.NewLine}boxed: {BoxedValue}");
			}
			else
			{
				OnReceiveError(parsedEntries);
			}
		}

		private void OnReceiveError(ParsedEntries entries)
		{
			Get.Plugin.LogWarning(Name + "_CustomSyncedValue_RPC recieved package without expected key: " + Name);
			string text = "";
			foreach (KeyValuePair<string, PackageEntry> entry in entries)
			{
				text += $"{entry.Key} - {entry.Value.type} - {entry.Value.value?.ToString()} {Environment.NewLine}";
			}
			Get.Plugin.LogWarning("Result: " + Environment.NewLine + text);
		}

		private void OnResetFromServer()
		{
			BoxedValue = LocalBaseValue;
			IsSourceOfTruth = true;
			LocalBaseValue = null;
		}

		private void OnServerShutdown()
		{
		}
	}
	internal sealed class CustomSyncedValue<T> : CustomSyncedValueBase
	{
		public T Value
		{
			get
			{
				return (T)base.BoxedValue;
			}
			set
			{
				base.BoxedValue = value;
				if (base.BoxedValue != null)
				{
					SendPackage();
				}
			}
		}

		public CustomSyncedValue(string name, T value = default(T))
			: base(name, typeof(T), value)
		{
		}

		public void AssignLocalValue(T value)
		{
			if (base.IsSourceOfTruth && SynchronizationManager.Instance.PlayerIsAdmin)
			{
				Value = value;
			}
			else
			{
				LocalBaseValue = value;
			}
		}
	}
	internal class ParsedEntries : Dictionary<string, PackageEntry>
	{
	}
	internal class PackageEntry
	{
		public string key;

		public Type type;

		public object? value;
	}
	internal class InvalidDeserializationTypeException : Exception
	{
		public string expected;

		public string received;

		public string field = "";
	}
	internal static class PackageUtils
	{
		public static string GetPackageTypeString(Type type)
		{
			return type.AssemblyQualifiedName;
		}

		public static void AddValue(this ZPackage package, object? value)
		{
			Type type = value?.GetType();
			if (value is Enum)
			{
				value = ((IConvertible)value).ToType(Enum.GetUnderlyingType(value.GetType()), CultureInfo.InvariantCulture);
			}
			else
			{
				if (value is ICollection collection)
				{
					package.Write(collection.Count);
					{
						foreach (object item in collection)
						{
							package.AddValue(item);
						}
						return;
					}
				}
				if ((object)type != null && type.IsValueType && !type.IsPrimitive)
				{
					FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					package.Write(fields.Length);
					FieldInfo[] array = fields;
					foreach (FieldInfo fieldInfo in array)
					{
						package.Write(GetPackageTypeString(fieldInfo.FieldType));
						package.AddValue(fieldInfo.GetValue(value));
					}
					return;
				}
			}
			ZRpc.Serialize(new object[1] { value }, ref package);
		}

		public static void AddEntry(this ZPackage package, PackageEntry entry)
		{
			package.Write(entry.key);
			package.Write((entry.value == null) ? "" : GetPackageTypeString(entry.type));
			package.AddValue(entry.value);
		}

		public static ZPackage ToPackage(this PackageEntry packageEntry)
		{
			return new List<PackageEntry> { packageEntry }.ToPackage();
		}

		public static ZPackage ToPackage(this IEnumerable<PackageEntry> packageEntries)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			val.Write(packageEntries?.Count() ?? 0);
			foreach (PackageEntry item in packageEntries ?? Array.Empty<PackageEntry>())
			{
				val.AddEntry(item);
			}
			return val;
		}

		public static object ReadValueWithType(this ZPackage package, Type type)
		{
			if ((object)type != null && type.IsValueType && !type.IsPrimitive && !type.IsEnum)
			{
				FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				int num = package.ReadInt();
				if (num != fields.Length)
				{
					throw new InvalidDeserializationTypeException
					{
						received = $"(field count: {num})",
						expected = $"(field count: {fields.Length})"
					};
				}
				object uninitializedObject = FormatterServices.GetUninitializedObject(type);
				FieldInfo[] array = fields;
				foreach (FieldInfo fieldInfo in array)
				{
					string text = package.ReadString();
					if (text != GetPackageTypeString(fieldInfo.FieldType))
					{
						throw new InvalidDeserializationTypeException
						{
							received = text,
							expected = GetPackageTypeString(fieldInfo.FieldType),
							field = fieldInfo.Name
						};
					}
					fieldInfo.SetValue(uninitializedObject, package.ReadValueWithType(fieldInfo.FieldType));
				}
				return uninitializedObject;
			}
			if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<, >))
			{
				int num2 = package.ReadInt();
				IDictionary dictionary = (IDictionary)Activator.CreateInstance(type);
				Type type2 = typeof(KeyValuePair<, >).MakeGenericType(type.GenericTypeArguments);
				FieldInfo field = type2.GetField("key", BindingFlags.Instance | BindingFlags.NonPublic);
				FieldInfo field2 = type2.GetField("value", BindingFlags.Instance | BindingFlags.NonPublic);
				for (int j = 0; j < num2; j++)
				{
					object obj = package.ReadValueWithType(type2);
					dictionary.Add(field.GetValue(obj), field2.GetValue(obj));
				}
				return dictionary;
			}
			if (type != typeof(List<string>) && type.IsGenericType)
			{
				Type type3 = typeof(ICollection<>).MakeGenericType(type.GenericTypeArguments[0]);
				if ((object)type3 != null && type3.IsAssignableFrom(type))
				{
					int num3 = package.ReadInt();
					object obj2 = Activator.CreateInstance(type);
					MethodInfo method = type3.GetMethod("Add");
					for (int k = 0; k < num3; k++)
					{
						method.Invoke(obj2, new object[1] { package.ReadValueWithType(type.GenericTypeArguments[0]) });
					}
					return obj2;
				}
			}
			ParameterInfo parameterInfo = (ParameterInfo)FormatterServices.GetUninitializedObject(typeof(ParameterInfo));
			AccessTools.DeclaredField(typeof(ParameterInfo), "ClassImpl").SetValue(parameterInfo, type);
			List<object> source = new List<object>();
			ZRpc.Deserialize(new ParameterInfo[2] { null, parameterInfo }, package, ref source);
			return source.FirstOrDefault();
		}

		public static ParsedEntries ReadEntries(this ZPackage package)
		{
			ParsedEntries parsedEntries = new ParsedEntries();
			int num = package.ReadInt();
			for (int i = 0; i < num; i++)
			{
				string key = package.ReadString();
				string text = package.ReadString();
				Type type = Type.GetType(text);
				if (text == "" || type != null)
				{
					object obj;
					try
					{
						obj = ((text == "") ? null : package.ReadValueWithType(type));
					}
					catch (InvalidDeserializationTypeException ex)
					{
						Get.Plugin.LogWarning("Got unexpected struct internal type " + ex.received + " for field " + ex.field + " struct " + text);
						continue;
					}
					if (obj != null)
					{
						parsedEntries[key] = new PackageEntry
						{
							key = key,
							type = type,
							value = obj
						};
					}
					continue;
				}
				Get.Plugin.LogWarning("Got invalid type " + text + ", abort reading of received configs");
				return new ParsedEntries();
			}
			return parsedEntries;
		}

		public static void Test()
		{
		}
	}
	internal interface IPlugin
	{
		ConfigFile Config { get; }

		bool Debug { get; }

		ManualLogSource Logger { get; }
	}
	internal static class LoggingExtensions
	{
		private static readonly Dictionary<string, ManualLogSource> logSources = new Dictionary<string, ManualLogSource>();

		internal static ManualLogSource GetLogger(this IPlugin mod)
		{
			if (mod.Debug)
			{
				Type declaringType = new StackFrame(2).GetMethod().DeclaringType;
				if (!logSources.TryGetValue(declaringType.FullName, out var value))
				{
					value = Logger.CreateLogSource(declaringType.FullName);
					logSources.Add(declaringType.FullName, value);
				}
				return value;
			}
			return mod.Logger;
		}

		public static void LogDebugOnly(this IPlugin mod, object data)
		{
			if (mod.Debug)
			{
				mod.GetLogger().LogDebug(data);
			}
		}

		public static void LogDebug(this IPlugin mod, object data)
		{
			if (mod.Debug)
			{
				mod.GetLogger().LogDebug(data);
			}
			else
			{
				mod.Logger.LogDebug(data);
			}
		}

		public static void LogInfo(this IPlugin mod, object data)
		{
			if (mod.Debug)
			{
				mod.GetLogger().LogInfo(data);
			}
			else
			{
				mod.Logger.LogInfo(data);
			}
		}

		public static void LogMessage(this IPlugin mod, object data)
		{
			if (mod.Debug)
			{
				mod.GetLogger().LogMessage(data);
			}
			else
			{
				mod.Logger.LogMessage(data);
			}
		}

		public static void LogWarning(this IPlugin mod, object data)
		{
			if (mod.Debug)
			{
				mod.GetLogger().LogWarning(data);
			}
			else
			{
				mod.Logger.LogWarning(data);
			}
		}

		public static void LogError(this IPlugin mod, object data)
		{
			if (mod.Debug)
			{
				mod.GetLogger().LogError(data);
			}
			else
			{
				mod.Logger.LogError(data);
			}
		}

		public static void LogFatal(this IPlugin mod, object data)
		{
			if (mod.Debug)
			{
				mod.GetLogger().LogFatal(data);
			}
			else
			{
				mod.Logger.LogFatal(data);
			}
		}
	}
	internal static class Get
	{
		private static IPlugin cachedModRef;

		public static IPlugin Plugin
		{
			get
			{
				if (cachedModRef == null)
				{
					cachedModRef = AccessTools.Field((from p in new StackFrame(0).GetMethod().DeclaringType.Assembly.GetTypes()
						where typeof(IPlugin).IsAssignableFrom(p)
						select p).FirstOrDefault(), "Instance").GetValue(null) as IPlugin;
					cachedModRef.LogDebugOnly("Caching static mod reference");
				}
				return cachedModRef;
			}
		}
	}
	internal class Watcher
	{
		private FileSystemWatcher fileSystemWatcher;

		public bool EnableRaisingEvents
		{
			get
			{
				if (fileSystemWatcher != null)
				{
					return fileSystemWatcher.EnableRaisingEvents;
				}
				return false;
			}
			set
			{
				if (fileSystemWatcher != null)
				{
					fileSystemWatcher.EnableRaisingEvents = value;
				}
			}
		}

		public event Action<object, FileSystemEventArgs>? FileChanged;

		public Watcher(string path, string filter)
		{
			if (path == null)
			{
				throw new ArgumentNullException("path");
			}
			if (filter == null)
			{
				throw new ArgumentNullException("filter");
			}
			Get.Plugin.LogDebugOnly("Watcher created for " + path + ", " + filter);
			fileSystemWatcher = new FileSystemWatcher(path, filter);
			fileSystemWatcher.Changed += OnCreatedChangedOrRenamed;
			fileSystemWatcher.Created += OnCreatedChangedOrRenamed;
			fileSystemWatcher.Renamed += OnCreatedChangedOrRenamed;
			fileSystemWatcher.IncludeSubdirectories = true;
			fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject;
			fileSystemWatcher.EnableRaisingEvents = true;
		}

		private void OnCreatedChangedOrRenamed(object sender, FileSystemEventArgs args)
		{
			Get.Plugin.LogDebugOnly($"OnCreatedChangedOrRenamed triggered {args.Name}, {args.ChangeType}");
			this.FileChanged?.Invoke(sender, args);
		}
	}
}