Decompiled source of BiomeLock v1.0.9

plugins/BiomeLock.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using JetBrains.Annotations;
using LocalizationManager;
using Microsoft.CodeAnalysis;
using ServerSync;
using TMPro;
using UnityEngine;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Core.ObjectPool;
using YamlDotNet.Core.Tokens;
using YamlDotNet.Helpers;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.BufferedDeserialization;
using YamlDotNet.Serialization.BufferedDeserialization.TypeDiscriminators;
using YamlDotNet.Serialization.Callbacks;
using YamlDotNet.Serialization.Converters;
using YamlDotNet.Serialization.EventEmitters;
using YamlDotNet.Serialization.NamingConventions;
using YamlDotNet.Serialization.NodeDeserializers;
using YamlDotNet.Serialization.NodeTypeResolvers;
using YamlDotNet.Serialization.ObjectFactories;
using YamlDotNet.Serialization.ObjectGraphTraversalStrategies;
using YamlDotNet.Serialization.ObjectGraphVisitors;
using YamlDotNet.Serialization.Schemas;
using YamlDotNet.Serialization.TypeInspectors;
using YamlDotNet.Serialization.TypeResolvers;
using YamlDotNet.Serialization.Utilities;
using YamlDotNet.Serialization.ValueDeserializers;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("BiomeLock")]
[assembly: AssemblyDescription("Biome gating via private keys, WAP-like flow")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("BiomeLock")]
[assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("b8f1a3c4-5dcf-4df6-899e-73f354a55c84")]
[assembly: AssemblyFileVersion("1.2.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.2.0.0")]
[module: UnverifiableCode]
[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 LocalizationManager
{
	[PublicAPI]
	public class Localizer
	{
		private static readonly Dictionary<string, Dictionary<string, Func<string>>> PlaceholderProcessors;

		private static readonly Dictionary<string, Dictionary<string, string>> loadedTexts;

		private static readonly ConditionalWeakTable<Localization, string> localizationLanguage;

		private static readonly List<WeakReference<Localization>> localizationObjects;

		private static BaseUnityPlugin? _plugin;

		private static readonly List<string> fileExtensions;

		private static BaseUnityPlugin plugin
		{
			get
			{
				//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b2: Expected O, but got Unknown
				if (_plugin == null)
				{
					IEnumerable<TypeInfo> source;
					try
					{
						source = Assembly.GetExecutingAssembly().DefinedTypes.ToList();
					}
					catch (ReflectionTypeLoadException ex)
					{
						source = from t in ex.Types
							where t != null
							select t.GetTypeInfo();
					}
					_plugin = (BaseUnityPlugin)Chainloader.ManagerObject.GetComponent((Type)source.First((TypeInfo t) => t.IsClass && typeof(BaseUnityPlugin).IsAssignableFrom(t)));
				}
				return _plugin;
			}
		}

		public static event Action? OnLocalizationComplete;

		private static void UpdatePlaceholderText(Localization localization, string key)
		{
			localizationLanguage.TryGetValue(localization, out var value);
			string text = loadedTexts[value][key];
			if (PlaceholderProcessors.TryGetValue(key, out var value2))
			{
				text = value2.Aggregate(text, (string current, KeyValuePair<string, Func<string>> kv) => current.Replace("{" + kv.Key + "}", kv.Value()));
			}
			localization.AddWord(key, text);
		}

		public static void AddPlaceholder<T>(string key, string placeholder, ConfigEntry<T> config, Func<T, string>? convertConfigValue = null) where T : notnull
		{
			Func<T, string> convertConfigValue2 = convertConfigValue;
			if (convertConfigValue2 == null)
			{
				convertConfigValue2 = (T val) => val.ToString();
			}
			if (!PlaceholderProcessors.ContainsKey(key))
			{
				PlaceholderProcessors[key] = new Dictionary<string, Func<string>>();
			}
			config.SettingChanged += delegate
			{
				UpdatePlaceholder();
			};
			if (loadedTexts.ContainsKey(Localization.instance.GetSelectedLanguage()))
			{
				UpdatePlaceholder();
			}
			void UpdatePlaceholder()
			{
				PlaceholderProcessors[key][placeholder] = () => convertConfigValue2(config.Value);
				UpdatePlaceholderText(Localization.instance, key);
			}
		}

		public static void AddText(string key, string text)
		{
			List<WeakReference<Localization>> list = new List<WeakReference<Localization>>();
			foreach (WeakReference<Localization> localizationObject in localizationObjects)
			{
				if (localizationObject.TryGetTarget(out var target))
				{
					Dictionary<string, string> dictionary = loadedTexts[localizationLanguage.GetOrCreateValue(target)];
					if (!target.m_translations.ContainsKey(key))
					{
						dictionary[key] = text;
						target.AddWord(key, text);
					}
				}
				else
				{
					list.Add(localizationObject);
				}
			}
			foreach (WeakReference<Localization> item in list)
			{
				localizationObjects.Remove(item);
			}
		}

		public static void Load()
		{
			_ = plugin;
		}

		public static void LoadLocalizationLater(Localization __instance)
		{
			LoadLocalization(Localization.instance, __instance.GetSelectedLanguage());
		}

		public static void SafeCallLocalizeComplete()
		{
			Localizer.OnLocalizationComplete?.Invoke();
		}

		private static void LoadLocalization(Localization __instance, string language)
		{
			if (!localizationLanguage.Remove(__instance))
			{
				localizationObjects.Add(new WeakReference<Localization>(__instance));
			}
			localizationLanguage.Add(__instance, language);
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			foreach (string item in from f in Directory.GetFiles(Path.GetDirectoryName(Paths.PluginPath), plugin.Info.Metadata.Name + ".*", SearchOption.AllDirectories)
				where fileExtensions.IndexOf(Path.GetExtension(f)) >= 0
				select f)
			{
				string[] array = Path.GetFileNameWithoutExtension(item).Split(new char[1] { '.' });
				if (array.Length >= 2)
				{
					string text = array[1];
					if (dictionary.ContainsKey(text))
					{
						Debug.LogWarning((object)("Duplicate key " + text + " found for " + plugin.Info.Metadata.Name + ". The duplicate file found at " + item + " will be skipped."));
					}
					else
					{
						dictionary[text] = item;
					}
				}
			}
			byte[] array2 = LoadTranslationFromAssembly("English");
			if (array2 == null)
			{
				throw new Exception("Found no English localizations in mod " + plugin.Info.Metadata.Name + ". Expected an embedded resource translations/English.json or translations/English.yml.");
			}
			string input = Encoding.UTF8.GetString(array2).TrimStart(new char[1] { '\ufeff' });
			Dictionary<string, string> dictionary2 = new DeserializerBuilder().IgnoreFields().Build().Deserialize<Dictionary<string, string>>(input);
			if (dictionary2 == null)
			{
				throw new Exception("Localization for mod " + plugin.Info.Metadata.Name + " failed: Localization file was empty.");
			}
			string text2 = null;
			if (language != "English")
			{
				if (dictionary.TryGetValue(language, out var value))
				{
					text2 = File.ReadAllText(value);
				}
				else
				{
					byte[] array3 = LoadTranslationFromAssembly(language);
					if (array3 != null)
					{
						text2 = Encoding.UTF8.GetString(array3);
					}
				}
			}
			if (text2 == null && dictionary.TryGetValue("English", out var value2))
			{
				text2 = File.ReadAllText(value2);
			}
			if (text2 != null)
			{
				text2 = text2.TrimStart(new char[1] { '\ufeff' });
				foreach (KeyValuePair<string, string> item2 in new DeserializerBuilder().IgnoreFields().Build().Deserialize<Dictionary<string, string>>(text2) ?? new Dictionary<string, string>())
				{
					dictionary2[item2.Key] = item2.Value;
				}
			}
			loadedTexts[language] = dictionary2;
			foreach (KeyValuePair<string, string> item3 in dictionary2)
			{
				UpdatePlaceholderText(__instance, item3.Key);
			}
		}

		static Localizer()
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Expected O, but got Unknown
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Expected O, but got Unknown
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Expected O, but got Unknown
			PlaceholderProcessors = new Dictionary<string, Dictionary<string, Func<string>>>();
			loadedTexts = new Dictionary<string, Dictionary<string, string>>();
			localizationLanguage = new ConditionalWeakTable<Localization, string>();
			localizationObjects = new List<WeakReference<Localization>>();
			fileExtensions = new List<string>(2) { ".json", ".yml" };
			Harmony val = new Harmony("org.bepinex.helpers.LocalizationManager");
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Localization), "SetupLanguage", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "LoadLocalization", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(FejdStartup), "SetupGui", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "LoadLocalizationLater", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(FejdStartup), "Start", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "SafeCallLocalizeComplete", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		private static byte[]? LoadTranslationFromAssembly(string language)
		{
			foreach (string fileExtension in fileExtensions)
			{
				byte[] array = ReadEmbeddedFileBytes("translations." + language + fileExtension);
				if (array != null)
				{
					return array;
				}
			}
			return null;
		}

		public static byte[]? ReadEmbeddedFileBytes(string resourceFileName, Assembly? containingAssembly = null)
		{
			using MemoryStream memoryStream = new MemoryStream();
			if ((object)containingAssembly == null)
			{
				containingAssembly = Assembly.GetCallingAssembly();
			}
			string text = containingAssembly.GetManifestResourceNames().FirstOrDefault((string str) => str.EndsWith(resourceFileName, StringComparison.Ordinal));
			if (text != null)
			{
				containingAssembly.GetManifestResourceStream(text)?.CopyTo(memoryStream);
			}
			return (memoryStream.Length == 0L) ? null : memoryStream.ToArray();
		}
	}
	public static class LocalizationManagerVersion
	{
		public const string Version = "1.4.1";
	}
}
namespace BiomeLock
{
	public static class BiomeLockAPI
	{
		public const string PrivatePrefix = "bl_";

		private static bool _resolved;

		private static Type? _tKeys;

		private static FieldInfo? _fiPrivateKeys;

		private static MethodInfo? _miNormalizeKey;

		private static void ResolveOnce()
		{
			if (_resolved)
			{
				return;
			}
			_resolved = true;
			_tKeys = Type.GetType("BiomeLock.BiomeLockPrivateKeys, " + typeof(BiomeLockPlugin).Assembly.GetName().Name, throwOnError: false);
			if (_tKeys == null)
			{
				_tKeys = typeof(BiomeLockPlugin).Assembly.GetType("BiomeLock.BiomeLockPrivateKeys", throwOnError: false);
			}
			if (!(_tKeys == null))
			{
				_fiPrivateKeys = _tKeys.GetField("PrivateKeys", BindingFlags.Static | BindingFlags.NonPublic);
				if (_fiPrivateKeys == null)
				{
					_fiPrivateKeys = _tKeys.GetField("PrivateKeys", BindingFlags.Static | BindingFlags.Public);
				}
				_miNormalizeKey = _tKeys.GetMethod("NormalizeKey", BindingFlags.Static | BindingFlags.NonPublic, null, new Type[1] { typeof(string) }, null) ?? _tKeys.GetMethod("NormalizeKey", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(string) }, null);
			}
		}

		private static bool IsAvailable()
		{
			try
			{
				return (Object)(object)ZNetScene.instance != (Object)null && (Object)(object)Player.m_localPlayer != (Object)null;
			}
			catch
			{
				return false;
			}
		}

		private static string NormalizeKey(string key)
		{
			if (key == null)
			{
				return string.Empty;
			}
			ResolveOnce();
			try
			{
				if (_miNormalizeKey != null)
				{
					return (string)_miNormalizeKey.Invoke(null, new object[1] { key });
				}
			}
			catch
			{
			}
			return key.Trim().ToLowerInvariant();
		}

		private static string ToPrivateKey(string globalOrPrivateKey)
		{
			string text = NormalizeKey(globalOrPrivateKey);
			if (text.Length == 0)
			{
				return string.Empty;
			}
			if (text.StartsWith("bl_", StringComparison.Ordinal))
			{
				return text;
			}
			return "bl_" + text;
		}

		public static bool HasPrivateKey(string globalOrPrivateKey)
		{
			if (!IsAvailable())
			{
				return false;
			}
			string text = ToPrivateKey(globalOrPrivateKey);
			if (text.Length == 0)
			{
				return false;
			}
			HashSet<string> hashSet = TryGetPrivateKeysRef();
			if (hashSet == null)
			{
				return false;
			}
			lock (hashSet)
			{
				return hashSet.Contains(text);
			}
		}

		private static HashSet<string>? TryGetPrivateKeysRef()
		{
			ResolveOnce();
			if (_fiPrivateKeys == null)
			{
				return null;
			}
			try
			{
				return _fiPrivateKeys.GetValue(null) as HashSet<string>;
			}
			catch
			{
				return null;
			}
		}
	}
	internal static class AssetLoader
	{
		private static AssetBundle _bundle;

		private const string ResourceName = "BiomeLock.assets.rd_biome";

		internal static void LoadBundle()
		{
			if ((Object)(object)_bundle != (Object)null)
			{
				return;
			}
			try
			{
				Assembly executingAssembly = Assembly.GetExecutingAssembly();
				using Stream stream = executingAssembly.GetManifestResourceStream("BiomeLock.assets.rd_biome");
				if (stream != null)
				{
					byte[] array = new byte[stream.Length];
					stream.Read(array, 0, array.Length);
					_bundle = AssetBundle.LoadFromMemory(array);
				}
			}
			catch
			{
			}
		}

		internal static Sprite GetSprite(string name)
		{
			LoadBundle();
			if ((Object)(object)_bundle == (Object)null)
			{
				return null;
			}
			try
			{
				return _bundle.LoadAsset<Sprite>(name);
			}
			catch
			{
				return null;
			}
		}
	}
	internal static class BiomeLock_SE
	{
		[HarmonyPatch(typeof(Vegvisir), "Interact")]
		private static class Vegvisir_Interact_Block_HildirMapTable
		{
			private static bool Prefix(Vegvisir __instance)
			{
				try
				{
					if (!BiomeLockPlugin.CE_SE_Block_HildirMapTable.Value)
					{
						return true;
					}
					if ((Object)(object)__instance == (Object)null)
					{
						return true;
					}
					if (IsHildirMapTable(__instance))
					{
						return false;
					}
					return true;
				}
				catch
				{
					return true;
				}
			}
		}

		[HarmonyPatch(typeof(Vegvisir), "GetHoverText")]
		private static class Vegvisir_GetHoverText_Block_HildirMapTable
		{
			private static bool Prefix(Vegvisir __instance, ref string __result)
			{
				try
				{
					if (!BiomeLockPlugin.CE_SE_Block_HildirMapTable.Value)
					{
						return true;
					}
					if ((Object)(object)__instance == (Object)null)
					{
						return true;
					}
					if (IsHildirMapTable(__instance))
					{
						__result = string.Empty;
						return false;
					}
					return true;
				}
				catch
				{
					return true;
				}
			}
		}

		[HarmonyPatch(typeof(Vegvisir), "GetHoverName")]
		private static class Vegvisir_GetHoverName_Block_HildirMapTable
		{
			private static bool Prefix(Vegvisir __instance, ref string __result)
			{
				try
				{
					if (!BiomeLockPlugin.CE_SE_Block_HildirMapTable.Value)
					{
						return true;
					}
					if ((Object)(object)__instance == (Object)null)
					{
						return true;
					}
					if (IsHildirMapTable(__instance))
					{
						__result = string.Empty;
						return false;
					}
					return true;
				}
				catch
				{
					return true;
				}
			}
		}

		[HarmonyPatch(typeof(Humanoid), "StartAttack")]
		private static class Humanoid_StartAttack_Block_All
		{
			private static bool Prefix(Humanoid __instance, ref bool __result)
			{
				try
				{
					if (!BiomeLockPlugin.CE_SE_Block_AttackBlock.Value)
					{
						return true;
					}
					Player val = (Player)(object)((__instance is Player) ? __instance : null);
					if ((Object)(object)val == (Object)null)
					{
						return true;
					}
					if (!ShouldBlock(val))
					{
						return true;
					}
					__result = false;
					return false;
				}
				catch
				{
					return true;
				}
			}
		}

		[HarmonyPatch(typeof(Humanoid), "IsBlocking")]
		private static class Humanoid_IsBlocking_Block_Parry
		{
			private static bool Prefix(Humanoid __instance, ref bool __result)
			{
				try
				{
					if (!BiomeLockPlugin.CE_SE_Block_AttackBlock.Value)
					{
						return true;
					}
					Player val = (Player)(object)((__instance is Player) ? __instance : null);
					if ((Object)(object)val == (Object)null)
					{
						return true;
					}
					if (!ShouldBlock(val))
					{
						return true;
					}
					__result = false;
					return false;
				}
				catch
				{
					return true;
				}
			}
		}

		[HarmonyPatch(typeof(Attack), "OnAttackTrigger")]
		private static class Attack_OnAttackTrigger_Block_All
		{
			private static bool Prefix(Attack __instance)
			{
				try
				{
					if (!BiomeLockPlugin.CE_SE_Block_AttackBlock.Value)
					{
						return true;
					}
					Player localPlayer = Player.m_localPlayer;
					if ((Object)(object)localPlayer == (Object)null)
					{
						return true;
					}
					if ((Object)(object)__instance.m_character != (Object)(object)localPlayer)
					{
						return true;
					}
					if (!ShouldBlock(localPlayer))
					{
						return true;
					}
					return false;
				}
				catch
				{
					return true;
				}
			}
		}

		[HarmonyPatch(typeof(Player), "UpdateAttackBowDraw")]
		private static class Player_UpdateAttackBowDraw_Block_Draw
		{
			private static bool Prefix(Player __instance, ItemData weapon, float dt)
			{
				try
				{
					if (!BiomeLockPlugin.CE_SE_Block_AttackBlock.Value)
					{
						return true;
					}
					if ((Object)(object)__instance == (Object)null)
					{
						return true;
					}
					if (!ShouldBlock(__instance))
					{
						return true;
					}
					((Humanoid)__instance).m_attackDrawTime = -1f;
					if (weapon != null && weapon.m_shared != null && weapon.m_shared.m_attack != null && !string.IsNullOrEmpty(weapon.m_shared.m_attack.m_drawAnimationState))
					{
						((Character)__instance).m_zanim.SetBool(weapon.m_shared.m_attack.m_drawAnimationState, false);
					}
					return false;
				}
				catch
				{
					return true;
				}
			}
		}

		[HarmonyPatch(typeof(Player), "UpdateBiome")]
		private static class Player_UpdateBiome_ApplySE
		{
			private static void Postfix(Player __instance)
			{
				try
				{
					if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
					{
						ApplyOrRemove(__instance);
					}
				}
				catch
				{
				}
			}
		}

		[HarmonyPatch(typeof(Hud), "Update")]
		private static class Hud_Update_Broadcast
		{
			private static void Postfix(Hud __instance)
			{
				if (!BiomeLockPlugin.CE_SE_Broadcast_Enabled.Value)
				{
					return;
				}
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer == (Object)null || !((Character)localPlayer).GetSEMan().HaveStatusEffect(SE_Hash))
				{
					return;
				}
				float time = Time.time;
				float num = Mathf.Max(2f, BiomeLockPlugin.CE_SE_Broadcast_Interval.Value);
				if (time < _nextBroadcastTime)
				{
					return;
				}
				_nextBroadcastTime = time + num;
				if (BroadcastTokens.Length != 0)
				{
					string text = BroadcastTokens[Random.Range(0, BroadcastTokens.Length)];
					string text2 = ((Localization.instance != null) ? Localization.instance.Localize(text) : text);
					MessageHud instance = MessageHud.instance;
					if (instance != null)
					{
						instance.ShowMessage((MessageType)2, text2, 0, (Sprite)null, false);
					}
				}
			}
		}

		[HarmonyPatch(typeof(ObjectDB), "Awake")]
		private static class ObjectDB_Awake_RegisterSE
		{
			private static void Postfix()
			{
				try
				{
					EnsureSERegistered();
				}
				catch
				{
				}
			}
		}

		[HarmonyPatch(typeof(Teleport), "Interact")]
		private static class Teleport_Interact_BlockDungeon
		{
			private static bool Prefix(Teleport __instance, Humanoid character, bool hold, bool alt)
			{
				//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_007b: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					if (!BiomeLockPlugin.CE_SE_Block_DungeonTeleport.Value)
					{
						return true;
					}
					if (hold)
					{
						return true;
					}
					Player val = (Player)(object)((character is Player) ? character : null);
					if ((Object)(object)val == (Object)null)
					{
						return true;
					}
					SEMan sEMan = ((Character)val).GetSEMan();
					if (sEMan == null || !sEMan.HaveStatusEffect(SE_HASH))
					{
						return true;
					}
					Biome biome = Heightmap.FindBiome(((Component)__instance).transform.position);
					if (!NeedsRestriction(val, biome))
					{
						return true;
					}
					((Character)val).Message((MessageType)2, "$biomelock_dungeon_blocked", 0, (Sprite)null);
					return false;
				}
				catch
				{
					return true;
				}
			}
		}

		[HarmonyPatch(typeof(Player), "UpdatePlacement")]
		private static class Player_UpdatePlacement_Block
		{
			private static bool Prefix(Player __instance)
			{
				if (!BiomeLockPlugin.CE_SE_Block_Hammer.Value)
				{
					return true;
				}
				return !ShouldBlock(__instance);
			}
		}

		[HarmonyPatch(typeof(Player), "PlacePiece")]
		private static class Player_PlacePiece_Block
		{
			private static bool Prefix(Player __instance)
			{
				if (!BiomeLockPlugin.CE_SE_Block_Hammer.Value)
				{
					return true;
				}
				return !ShouldBlock(__instance);
			}
		}

		[HarmonyPatch(typeof(Player), "Repair")]
		private static class Player_Repair_Block
		{
			private static bool Prefix(Player __instance)
			{
				if (!BiomeLockPlugin.CE_SE_Block_Hammer.Value)
				{
					return true;
				}
				return !ShouldBlock(__instance);
			}
		}

		[HarmonyPatch(typeof(Player), "RemovePiece")]
		private static class Player_RemovePiece_Block
		{
			private static bool Prefix(Player __instance)
			{
				if (!BiomeLockPlugin.CE_SE_Block_Hammer.Value)
				{
					return true;
				}
				return !ShouldBlock(__instance);
			}
		}

		[HarmonyPatch(typeof(Hud), "TogglePieceSelection")]
		private static class Hud_TogglePieceSelection_Block
		{
			private static bool Prefix(Hud __instance)
			{
				if (!BiomeLockPlugin.CE_SE_Block_Hammer.Value)
				{
					return true;
				}
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer == (Object)null)
				{
					return true;
				}
				if (!ShouldBlock(localPlayer))
				{
					return true;
				}
				if ((Object)(object)__instance != (Object)null && (Object)(object)__instance.m_pieceSelectionWindow != (Object)null && __instance.m_pieceSelectionWindow.activeSelf)
				{
					return true;
				}
				return false;
			}
		}

		[HarmonyPatch(typeof(Player), "AutoPickup")]
		private static class Player_AutoPickup_Block
		{
			private static bool Prefix(Player __instance)
			{
				if (!BiomeLockPlugin.CE_SE_Block_AutoPickup.Value)
				{
					return true;
				}
				return !ShouldBlock(__instance);
			}
		}

		[HarmonyPatch(typeof(Humanoid), "Pickup")]
		private static class Humanoid_Pickup_Block
		{
			private static bool Prefix(Humanoid __instance)
			{
				if (!BiomeLockPlugin.CE_SE_Block_Pickup.Value)
				{
					return true;
				}
				Player val = (Player)(object)((__instance is Player) ? __instance : null);
				return (Object)(object)val == (Object)null || !ShouldBlock(val);
			}
		}

		[HarmonyPatch]
		private static class Interact_Implementations_Block_UserHoldAlt
		{
			[CompilerGenerated]
			private sealed class <TargetMethods>d__0 : IEnumerable<MethodBase>, IEnumerable, IEnumerator<MethodBase>, IDisposable, IEnumerator
			{
				private int <>1__state;

				private MethodBase <>2__current;

				private int <>l__initialThreadId;

				private Assembly <asm>5__1;

				private Type <interactable>5__2;

				private Type[] <types>5__3;

				private ReflectionTypeLoadException <e>5__4;

				private int <i>5__5;

				private Type <t>5__6;

				private MethodInfo <m>5__7;

				private ParameterInfo[] <ps>5__8;

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

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

				[DebuggerHidden]
				public <TargetMethods>d__0(int <>1__state)
				{
					this.<>1__state = <>1__state;
					<>l__initialThreadId = Environment.CurrentManagedThreadId;
				}

				[DebuggerHidden]
				void IDisposable.Dispose()
				{
					<asm>5__1 = null;
					<interactable>5__2 = null;
					<types>5__3 = null;
					<e>5__4 = null;
					<t>5__6 = null;
					<m>5__7 = null;
					<ps>5__8 = null;
					<>1__state = -2;
				}

				private bool MoveNext()
				{
					int num = <>1__state;
					if (num != 0)
					{
						if (num != 1)
						{
							return false;
						}
						<>1__state = -1;
						<t>5__6 = null;
						<m>5__7 = null;
						<ps>5__8 = null;
						goto IL_0211;
					}
					<>1__state = -1;
					<asm>5__1 = typeof(Interactable).Assembly;
					<interactable>5__2 = typeof(Interactable);
					try
					{
						<types>5__3 = <asm>5__1.GetTypes();
					}
					catch (ReflectionTypeLoadException ex)
					{
						<e>5__4 = ex;
						<types>5__3 = <e>5__4.Types ?? Array.Empty<Type>();
					}
					<i>5__5 = 0;
					goto IL_0223;
					IL_0223:
					if (<i>5__5 < <types>5__3.Length)
					{
						<t>5__6 = <types>5__3[<i>5__5];
						if (!(<t>5__6 == null) && !<t>5__6.IsInterface && !<t>5__6.IsAbstract && <interactable>5__2.IsAssignableFrom(<t>5__6))
						{
							<m>5__7 = <t>5__6.GetMethod("Interact", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[3]
							{
								typeof(Humanoid),
								typeof(bool),
								typeof(bool)
							}, null);
							if (!(<m>5__7 == null) && <m>5__7.GetMethodBody() != null)
							{
								<ps>5__8 = <m>5__7.GetParameters();
								if (<ps>5__8.Length == 3 && string.Equals(<ps>5__8[0].Name, "user", StringComparison.Ordinal) && string.Equals(<ps>5__8[1].Name, "hold", StringComparison.Ordinal))
								{
									<>2__current = <m>5__7;
									<>1__state = 1;
									return true;
								}
							}
						}
						goto IL_0211;
					}
					return false;
					IL_0211:
					int num2 = <i>5__5 + 1;
					<i>5__5 = num2;
					goto IL_0223;
				}

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

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

				[DebuggerHidden]
				IEnumerator<MethodBase> IEnumerable<MethodBase>.GetEnumerator()
				{
					if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
					{
						<>1__state = 0;
						return this;
					}
					return new <TargetMethods>d__0(0);
				}

				[DebuggerHidden]
				IEnumerator IEnumerable.GetEnumerator()
				{
					return ((IEnumerable<MethodBase>)this).GetEnumerator();
				}
			}

			[IteratorStateMachine(typeof(<TargetMethods>d__0))]
			private static IEnumerable<MethodBase> TargetMethods()
			{
				//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
				return new <TargetMethods>d__0(-2);
			}

			private static bool Prefix(object __instance, Humanoid user, bool hold, bool alt, ref bool __result)
			{
				try
				{
					if (!BiomeLockPlugin.CE_SE_Block_GenericInteract.Value)
					{
						return true;
					}
					Player val = (Player)(object)((user is Player) ? user : null);
					if ((Object)(object)val == (Object)null)
					{
						return true;
					}
					if (!ShouldBlock(val))
					{
						return true;
					}
					Component val2 = (Component)((__instance is Component) ? __instance : null);
					if ((Object)(object)val2 != (Object)null && IsAllowedInteractableGO(val2.gameObject))
					{
						return true;
					}
					__result = false;
					return false;
				}
				catch
				{
					return true;
				}
			}
		}

		[HarmonyPatch]
		private static class Interact_Implementations_Block_CharacterRepeatAlt
		{
			[CompilerGenerated]
			private sealed class <TargetMethods>d__0 : IEnumerable<MethodBase>, IEnumerable, IEnumerator<MethodBase>, IDisposable, IEnumerator
			{
				private int <>1__state;

				private MethodBase <>2__current;

				private int <>l__initialThreadId;

				private Assembly <asm>5__1;

				private Type <interactable>5__2;

				private Type[] <types>5__3;

				private ReflectionTypeLoadException <e>5__4;

				private int <i>5__5;

				private Type <t>5__6;

				private MethodInfo <m>5__7;

				private ParameterInfo[] <ps>5__8;

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

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

				[DebuggerHidden]
				public <TargetMethods>d__0(int <>1__state)
				{
					this.<>1__state = <>1__state;
					<>l__initialThreadId = Environment.CurrentManagedThreadId;
				}

				[DebuggerHidden]
				void IDisposable.Dispose()
				{
					<asm>5__1 = null;
					<interactable>5__2 = null;
					<types>5__3 = null;
					<e>5__4 = null;
					<t>5__6 = null;
					<m>5__7 = null;
					<ps>5__8 = null;
					<>1__state = -2;
				}

				private bool MoveNext()
				{
					int num = <>1__state;
					if (num != 0)
					{
						if (num != 1)
						{
							return false;
						}
						<>1__state = -1;
						<t>5__6 = null;
						<m>5__7 = null;
						<ps>5__8 = null;
						goto IL_0211;
					}
					<>1__state = -1;
					<asm>5__1 = typeof(Interactable).Assembly;
					<interactable>5__2 = typeof(Interactable);
					try
					{
						<types>5__3 = <asm>5__1.GetTypes();
					}
					catch (ReflectionTypeLoadException ex)
					{
						<e>5__4 = ex;
						<types>5__3 = <e>5__4.Types ?? Array.Empty<Type>();
					}
					<i>5__5 = 0;
					goto IL_0223;
					IL_0223:
					if (<i>5__5 < <types>5__3.Length)
					{
						<t>5__6 = <types>5__3[<i>5__5];
						if (!(<t>5__6 == null) && !<t>5__6.IsInterface && !<t>5__6.IsAbstract && <interactable>5__2.IsAssignableFrom(<t>5__6))
						{
							<m>5__7 = <t>5__6.GetMethod("Interact", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[3]
							{
								typeof(Humanoid),
								typeof(bool),
								typeof(bool)
							}, null);
							if (!(<m>5__7 == null) && <m>5__7.GetMethodBody() != null)
							{
								<ps>5__8 = <m>5__7.GetParameters();
								if (<ps>5__8.Length == 3 && string.Equals(<ps>5__8[0].Name, "character", StringComparison.Ordinal) && string.Equals(<ps>5__8[1].Name, "repeat", StringComparison.Ordinal))
								{
									<>2__current = <m>5__7;
									<>1__state = 1;
									return true;
								}
							}
						}
						goto IL_0211;
					}
					return false;
					IL_0211:
					int num2 = <i>5__5 + 1;
					<i>5__5 = num2;
					goto IL_0223;
				}

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

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

				[DebuggerHidden]
				IEnumerator<MethodBase> IEnumerable<MethodBase>.GetEnumerator()
				{
					if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
					{
						<>1__state = 0;
						return this;
					}
					return new <TargetMethods>d__0(0);
				}

				[DebuggerHidden]
				IEnumerator IEnumerable.GetEnumerator()
				{
					return ((IEnumerable<MethodBase>)this).GetEnumerator();
				}
			}

			[IteratorStateMachine(typeof(<TargetMethods>d__0))]
			private static IEnumerable<MethodBase> TargetMethods()
			{
				//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
				return new <TargetMethods>d__0(-2);
			}

			private static bool Prefix(object __instance, Humanoid character, bool repeat, bool alt, ref bool __result)
			{
				try
				{
					if (!BiomeLockPlugin.CE_SE_Block_GenericInteract.Value)
					{
						return true;
					}
					Player val = (Player)(object)((character is Player) ? character : null);
					if ((Object)(object)val == (Object)null)
					{
						return true;
					}
					if (!ShouldBlock(val))
					{
						return true;
					}
					Component val2 = (Component)((__instance is Component) ? __instance : null);
					if ((Object)(object)val2 != (Object)null && IsAllowedInteractableGO(val2.gameObject))
					{
						return true;
					}
					__result = false;
					return false;
				}
				catch
				{
					return true;
				}
			}
		}

		[HarmonyPatch(typeof(ItemDrop), "Interact")]
		private static class ItemDrop_Interact_Block
		{
			private static bool Prefix(Humanoid character, ref bool __result)
			{
				try
				{
					if (!BiomeLockPlugin.CE_SE_Block_ItemDropInteract.Value)
					{
						return true;
					}
					Player val = (Player)(object)((character is Player) ? character : null);
					if ((Object)(object)val == (Object)null)
					{
						return true;
					}
					if (ShouldBlock(val))
					{
						__result = false;
						return false;
					}
					return true;
				}
				catch
				{
					return true;
				}
			}
		}

		[HarmonyPatch(typeof(Pickable), "Interact")]
		private static class Pickable_Interact_Block
		{
			private static bool Prefix(Humanoid character, ref bool __result)
			{
				try
				{
					if (!BiomeLockPlugin.CE_SE_Block_PickableInteract.Value)
					{
						return true;
					}
					Player val = (Player)(object)((character is Player) ? character : null);
					if ((Object)(object)val == (Object)null)
					{
						return true;
					}
					if (ShouldBlock(val))
					{
						__result = false;
						return false;
					}
					return true;
				}
				catch
				{
					return true;
				}
			}
		}

		[HarmonyPatch(typeof(Container), "Interact")]
		private static class Container_Interact_Block
		{
			private static bool Prefix(Container __instance, Humanoid character, ref bool __result)
			{
				try
				{
					if (!BiomeLockPlugin.CE_SE_Block_ContainerInteract.Value)
					{
						return true;
					}
					Player val = (Player)(object)((character is Player) ? character : null);
					if ((Object)(object)val == (Object)null)
					{
						return true;
					}
					if (!ShouldBlock(val))
					{
						return true;
					}
					if (IsAllowedInteractableGO(((Component)__instance).gameObject))
					{
						return true;
					}
					__result = false;
					return false;
				}
				catch
				{
					return true;
				}
			}
		}

		[HarmonyPatch(typeof(Minimap), "ShowPinNameInput")]
		private static class Minimap_ShowPinNameInput_Block_When_SE_Active
		{
			private static bool Prefix(Vector3 pos)
			{
				try
				{
					Player localPlayer = Player.m_localPlayer;
					if ((Object)(object)localPlayer == (Object)null)
					{
						return true;
					}
					SEMan sEMan = ((Character)localPlayer).GetSEMan();
					if (sEMan == null || !sEMan.HaveStatusEffect(SE_HASH))
					{
						return true;
					}
					((Character)localPlayer).Message((MessageType)2, "$biomelock_map_pin_blocked", 0, (Sprite)null);
					return false;
				}
				catch
				{
					return true;
				}
			}
		}

		[HarmonyPatch(typeof(Minimap), "UpdateExplore")]
		private static class Minimap_UpdateExplore_Block
		{
			private static bool Prefix(Minimap __instance, Player player)
			{
				try
				{
					if (!BiomeLockPlugin.CE_SE_Block_MapExplore.Value)
					{
						return true;
					}
					if ((Object)(object)player == (Object)null)
					{
						return true;
					}
					if (!ShouldBlock(player))
					{
						return true;
					}
					__instance.m_exploreTimer = 0f;
					return false;
				}
				catch
				{
					return true;
				}
			}
		}

		[HarmonyPatch(typeof(StoreGui), "Show", new Type[] { typeof(Trader) })]
		private static class StoreGui_Show_Block
		{
			private static bool Prefix(StoreGui __instance, Trader trader)
			{
				try
				{
					if (BiomeLockPlugin.CE_SE_AdminBypass.Value && BiomeLockPlugin.IsLocalPlayerAdmin())
					{
						return true;
					}
					Player localPlayer = Player.m_localPlayer;
					if ((Object)(object)localPlayer == (Object)null)
					{
						return true;
					}
					if (!HasBiomeLockSE(localPlayer))
					{
						return true;
					}
					if (TraderAllowedByApiRule(trader))
					{
						return true;
					}
					MessageHud instance = MessageHud.instance;
					if (instance != null)
					{
						instance.ShowMessage((MessageType)2, "$bl_se_trader_blocked", 0, (Sprite)null, false);
					}
					return false;
				}
				catch
				{
					return true;
				}
			}
		}

		[HarmonyPatch(typeof(Heightmap), "ApplyModifier")]
		private static class Heightmap_ApplyModifier_Block_PlayerTerrain
		{
			private static bool Prefix(Heightmap __instance, TerrainModifier modifier, float[] baseHeights, float[] levelOnly)
			{
				try
				{
					if (!BiomeLockPlugin.CE_SE_Block_TerrainHoe.Value)
					{
						return true;
					}
					Player localPlayer = Player.m_localPlayer;
					if ((Object)(object)localPlayer == (Object)null)
					{
						return true;
					}
					if (!ShouldBlock(localPlayer))
					{
						return true;
					}
					if ((Object)(object)modifier == (Object)null)
					{
						return true;
					}
					if (!modifier.m_playerModifiction)
					{
						return true;
					}
					return false;
				}
				catch
				{
					return true;
				}
			}
		}

		[HarmonyPatch(typeof(SpawnSystem), "GetPlayersInZone")]
		private static class SpawnSystem_GetPlayersInZone_FilterRestrictedPlayers
		{
			private static void Postfix(List<Player> players)
			{
				try
				{
					if (players == null || players.Count == 0)
					{
						return;
					}
					for (int num = players.Count - 1; num >= 0; num--)
					{
						Player val = players[num];
						if (!((Object)(object)val == (Object)null) && HasBiomeLockSE(val))
						{
							players.RemoveAt(num);
						}
					}
				}
				catch
				{
				}
			}
		}

		[HarmonyPatch(typeof(Player), "IsPlayerInRange", new Type[]
		{
			typeof(Vector3),
			typeof(float)
		})]
		private static class Player_IsPlayerInRange_IgnoreRestrictedPlayers
		{
			private static bool Prefix(Vector3 point, float range, ref bool __result)
			{
				//IL_0060: 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_0066: Unknown result type (might be due to invalid IL or missing references)
				//IL_006b: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					List<Player> allPlayers = Player.GetAllPlayers();
					if (allPlayers == null || allPlayers.Count == 0)
					{
						__result = false;
						return false;
					}
					float num = range * range;
					for (int i = 0; i < allPlayers.Count; i++)
					{
						Player val = allPlayers[i];
						if (!((Object)(object)val == (Object)null) && !HasBiomeLockSE(val))
						{
							Vector3 val2 = ((Component)val).transform.position - point;
							if (((Vector3)(ref val2)).sqrMagnitude <= num)
							{
								__result = true;
								return false;
							}
						}
					}
					__result = false;
					return false;
				}
				catch
				{
					return true;
				}
			}
		}

		private static Biome _blockedBiomesCache = (Biome)0;

		private static string _blockedBiomesRaw = "";

		private const string SE_Name = "SE_BiomeLock";

		private static readonly int SE_Hash = StringExtensionMethods.GetStableHashCode("SE_BiomeLock");

		private static float _nextBroadcastTime;

		private static readonly string[] BroadcastTokens = new string[5] { "$bl_se_msg_1", "$bl_se_msg_2", "$bl_se_msg_3", "$bl_se_msg_4", "$bl_se_msg_5" };

		internal const string SE_NAME = "SE_BiomeLock";

		internal static readonly int SE_HASH = StringExtensionMethods.GetStableHashCode("SE_BiomeLock");

		private static readonly HashSet<string> AllowedInteractables = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "TombStone", "ShipControlls", "Ladder", "Saddle", "Sadle", "Chair" };

		private const string MapPinBlockedToken = "$biomelock_map_pin_blocked";

		internal static readonly Dictionary<Biome, string> BiomeRequirement = new Dictionary<Biome, string>
		{
			{
				(Biome)8,
				"defeated_eikthyr"
			},
			{
				(Biome)256,
				"defeated_eikthyr"
			},
			{
				(Biome)2,
				"defeated_gdking"
			},
			{
				(Biome)4,
				"defeated_bonemass"
			},
			{
				(Biome)16,
				"defeated_dragon"
			},
			{
				(Biome)512,
				"defeated_goblinking"
			},
			{
				(Biome)32,
				"defeated_queen"
			},
			{
				(Biome)64,
				"defeated_fader"
			}
		};

		private static bool IsHildirMapTable(Vegvisir v)
		{
			return v.m_locations != null && v.m_locations.Count > 1;
		}

		private static Biome GetBlockedBiomes()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: 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_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			string text = BiomeLockPlugin.CE_SE_BlockedBiomes.Value ?? "";
			if (string.Equals(text, _blockedBiomesRaw, StringComparison.Ordinal))
			{
				return _blockedBiomesCache;
			}
			_blockedBiomesRaw = text;
			_blockedBiomesCache = (Biome)0;
			string[] array = text.Split(new char[6] { ',', ';', ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				if (Enum.TryParse<Biome>(array[i], ignoreCase: true, out Biome result))
				{
					_blockedBiomesCache |= result;
				}
			}
			return _blockedBiomesCache;
		}

		private static bool IsBiomeBlockedByConfig(Biome biome)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Invalid comparison between Unknown and I4
			return (GetBlockedBiomes() & biome) > 0;
		}

		internal static void ApplyOrRemove(Player p)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: 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)
			if ((Object)(object)p == (Object)null || ((Character)p).InIntro() || ((Character)p).IsDead() || ((Character)p).InCutscene() || ((Character)p).IsTeleporting() || p.m_isLoading || (Object.op_Implicit((Object)(object)((Character)p).m_nview) && !((Character)p).m_nview.IsOwner()))
			{
				return;
			}
			Biome currentBiome = p.GetCurrentBiome();
			bool flag = IsBiomeBlockedByConfig(currentBiome) && NeedsRestriction(p, currentBiome);
			SEMan sEMan = ((Character)p).GetSEMan();
			if (sEMan == null)
			{
				return;
			}
			bool flag2 = sEMan.HaveStatusEffect(SE_HASH);
			if (flag)
			{
				if (!flag2)
				{
					EnsureSERegistered();
					sEMan.AddStatusEffect(SE_HASH, true, 0, 0f);
				}
			}
			else if (flag2)
			{
				sEMan.RemoveStatusEffect(SE_HASH, true);
			}
		}

		internal static void EnsureSERegistered()
		{
			if (Object.op_Implicit((Object)(object)ObjectDB.instance))
			{
				StatusEffect statusEffect = ObjectDB.instance.GetStatusEffect(SE_HASH);
				if (!((Object)(object)statusEffect != (Object)null))
				{
					StatusEffect val = ScriptableObject.CreateInstance<StatusEffect>();
					((Object)val).name = "SE_BiomeLock";
					val.m_name = "$se_biome_lock";
					val.m_category = "BiomeLock";
					val.m_tooltip = "$biomelock_se_tooltip";
					val.m_ttl = 0f;
					val.m_startMessage = "";
					val.m_stopMessage = "";
					val.m_repeatMessage = "";
					val.m_repeatInterval = 0f;
					val.m_icon = AssetLoader.GetSprite("biomelock_icon");
					ObjectDB.instance.m_StatusEffects.Add(val);
				}
			}
		}

		private static bool IsAllowedInteractableGO(GameObject go)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			try
			{
				if ((Object)(object)go == (Object)null)
				{
					return false;
				}
				if ((Object)(object)go.GetComponent<TombStone>() != (Object)null)
				{
					return true;
				}
				if ((Object)(object)go.GetComponentInParent<TombStone>() != (Object)null)
				{
					return true;
				}
				Interactable val = go.GetComponent<Interactable>() ?? go.GetComponentInParent<Interactable>();
				if ((Object)val == (Object)null)
				{
					return false;
				}
				return AllowedInteractables.Contains(((object)val).GetType().Name);
			}
			catch
			{
				return false;
			}
		}

		private static bool ShouldBlock(Player p)
		{
			int result;
			if ((Object)(object)p == (Object)(object)Player.m_localPlayer)
			{
				SEMan sEMan = ((Character)p).GetSEMan();
				result = ((sEMan != null && sEMan.HaveStatusEffect(SE_HASH)) ? 1 : 0);
			}
			else
			{
				result = 0;
			}
			return (byte)result != 0;
		}

		internal static bool NeedsRestriction(Player p, Biome biome)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			if (BiomeLockPlugin.CE_SE_AdminBypass.Value && BiomeLockPlugin.IsLocalPlayerAdmin())
			{
				return false;
			}
			if (!BiomeRequirement.TryGetValue(biome, out string value))
			{
				return false;
			}
			if (string.IsNullOrEmpty(value))
			{
				return false;
			}
			return !BiomeLockAPI.HasPrivateKey(value);
		}

		private static string GetPrefabName(GameObject go)
		{
			try
			{
				if ((Object)(object)go == (Object)null)
				{
					return string.Empty;
				}
				ZNetView component = go.GetComponent<ZNetView>();
				if ((Object)(object)component == (Object)null)
				{
					return string.Empty;
				}
				ZDO zDO = component.GetZDO();
				if (zDO == null)
				{
					return string.Empty;
				}
				int prefab = zDO.GetPrefab();
				if (prefab == 0 || (Object)(object)ZNetScene.instance == (Object)null)
				{
					return string.Empty;
				}
				GameObject prefab2 = ZNetScene.instance.GetPrefab(prefab);
				return ((Object)(object)prefab2 != (Object)null) ? ((Object)prefab2).name : string.Empty;
			}
			catch
			{
				return string.Empty;
			}
		}

		private static bool TraderAllowedByApiRule(Trader t)
		{
			try
			{
				if ((Object)(object)t == (Object)null)
				{
					return true;
				}
				string text = GetPrefabName(((Component)t).gameObject);
				if (string.IsNullOrEmpty(text))
				{
					text = ((Object)t).name ?? ((Object)((Component)t).gameObject).name;
				}
				if (!string.IsNullOrEmpty(text) && text.EndsWith("(Clone)", StringComparison.Ordinal))
				{
					text = text.Replace("(Clone)", string.Empty);
				}
				if (text == "Haldor")
				{
					return BiomeLockAPI.HasPrivateKey("defeated_eikthyr");
				}
				if (text == "BogWitch")
				{
					return BiomeLockAPI.HasPrivateKey("defeated_gdking");
				}
				return true;
			}
			catch
			{
				return true;
			}
		}

		private static bool HasBiomeLockSE(Player p)
		{
			try
			{
				if (!BiomeLockPlugin.CE_SE_Block_SpawnBlock.Value)
				{
					return false;
				}
				if ((Object)(object)p == (Object)null)
				{
					return false;
				}
				SEMan sEMan = ((Character)p).GetSEMan();
				return sEMan != null && sEMan.HaveStatusEffect(SE_HASH);
			}
			catch
			{
				return false;
			}
		}
	}
	[HarmonyPatch]
	internal static class BiomeLock_ZoneSystem_GetGlobalKey_RedirectPrivateKeys
	{
		private static readonly HashSet<string> RedirectedKeys = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
		{
			"defeated_eikthyr", "defeated_gdking", "defeated_bonemass", "defeated_dragon", "defeated_goblinking", "defeated_queen", "defeated_fader", "defeated_serpent", "KilledTroll", "killed_surtling",
			"KilledBat", "Hildir1", "Hildir2", "Hildir3"
		};

		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(typeof(ZoneSystem), "GetGlobalKey", new Type[2]
			{
				typeof(string),
				typeof(string).MakeByRefType()
			}, (Type[])null);
		}

		private static bool Prefix(string name, ref string value, ref bool __result)
		{
			try
			{
				if (string.IsNullOrWhiteSpace(name))
				{
					return true;
				}
				if ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsDedicated())
				{
					return true;
				}
				if (!BiomeLockPlugin.CE_GlobalKeys_PrivateKeys.Value)
				{
					return true;
				}
				if (BiomeLockPlugin.CE_SE_AdminBypass.Value && BiomeLockPlugin.IsLocalPlayerAdmin())
				{
					return true;
				}
				if (!RedirectedKeys.Contains(name))
				{
					return true;
				}
				__result = BiomeLockAPI.HasPrivateKey(name);
				value = string.Empty;
				return false;
			}
			catch
			{
				return true;
			}
		}
	}
	internal static class BiomeLock_KeyRefresh
	{
		private static bool _pending;

		private static float _nextRunAt;

		private static MethodInfo? _miStoreGui_FillList;

		private static MethodInfo? _miInventoryGui_UpdateCraftingPanel;

		private static MethodInfo? _miInventoryGui_UpdateRecipeList;

		private static MethodInfo? _miPlayer_UpdateKnownRecipesList;

		private static MethodInfo? _miPlayer_UpdateAvailablePiecesList;

		internal static void NotifyKeysChanged()
		{
			try
			{
				_pending = true;
				float time = Time.time;
				if (_nextRunAt < time)
				{
					_nextRunAt = time + 0.05f;
				}
			}
			catch
			{
			}
		}

		private static void EnsureMethods()
		{
			if (_miStoreGui_FillList == null)
			{
				_miStoreGui_FillList = AccessTools.Method(typeof(StoreGui), "FillList", (Type[])null, (Type[])null);
			}
			if (_miInventoryGui_UpdateCraftingPanel == null)
			{
				_miInventoryGui_UpdateCraftingPanel = AccessTools.Method(typeof(InventoryGui), "UpdateCraftingPanel", (Type[])null, (Type[])null);
			}
			if (_miInventoryGui_UpdateRecipeList == null)
			{
				_miInventoryGui_UpdateRecipeList = AccessTools.Method(typeof(InventoryGui), "UpdateRecipeList", (Type[])null, (Type[])null);
			}
			if (_miPlayer_UpdateKnownRecipesList == null)
			{
				_miPlayer_UpdateKnownRecipesList = AccessTools.Method(typeof(Player), "UpdateKnownRecipesList", (Type[])null, (Type[])null);
			}
			if (_miPlayer_UpdateAvailablePiecesList == null)
			{
				_miPlayer_UpdateAvailablePiecesList = AccessTools.Method(typeof(Player), "UpdateAvailablePiecesList", (Type[])null, (Type[])null);
			}
		}

		internal static void TryRunPending()
		{
			try
			{
				if (!_pending || Time.time < _nextRunAt)
				{
					return;
				}
				_pending = false;
				if ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsDedicated() || (Object)(object)Player.m_localPlayer == (Object)null)
				{
					return;
				}
				EnsureMethods();
				Player localPlayer = Player.m_localPlayer;
				try
				{
					if (_miPlayer_UpdateKnownRecipesList != null)
					{
						_miPlayer_UpdateKnownRecipesList.Invoke(localPlayer, Array.Empty<object>());
					}
					if (_miPlayer_UpdateAvailablePiecesList != null)
					{
						_miPlayer_UpdateAvailablePiecesList.Invoke(localPlayer, Array.Empty<object>());
					}
				}
				catch
				{
				}
				try
				{
					localPlayer.UpdateEvents();
				}
				catch
				{
				}
				try
				{
					if ((Object)(object)InventoryGui.instance != (Object)null)
					{
						if (_miInventoryGui_UpdateCraftingPanel != null)
						{
							_miInventoryGui_UpdateCraftingPanel.Invoke(InventoryGui.instance, Array.Empty<object>());
						}
						if (_miInventoryGui_UpdateRecipeList != null)
						{
							_miInventoryGui_UpdateRecipeList.Invoke(InventoryGui.instance, Array.Empty<object>());
						}
					}
				}
				catch
				{
				}
				try
				{
					if ((Object)(object)StoreGui.instance != (Object)null && StoreGui.IsVisible() && _miStoreGui_FillList != null)
					{
						_miStoreGui_FillList.Invoke(StoreGui.instance, Array.Empty<object>());
					}
				}
				catch
				{
				}
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(Hud), "Update")]
	internal static class BL_KeyRefresh_HudUpdate
	{
		private static void Postfix()
		{
			BiomeLock_KeyRefresh.TryRunPending();
		}
	}
	[HarmonyPatch]
	internal static class BL_KeyRefresh_RPC_SetPrivateKey
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(typeof(BiomeLockPrivateKeys), "RPC_BL_SetPrivateKey", (Type[])null, (Type[])null);
		}

		private static void Postfix()
		{
			BiomeLock_KeyRefresh.NotifyKeysChanged();
		}
	}
	[HarmonyPatch]
	internal static class BL_KeyRefresh_RPC_RemovePrivateKey
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(typeof(BiomeLockPrivateKeys), "RPC_BL_RemovePrivateKey", (Type[])null, (Type[])null);
		}

		private static void Postfix()
		{
			BiomeLock_KeyRefresh.NotifyKeysChanged();
		}
	}
	[HarmonyPatch]
	internal static class BL_KeyRefresh_RPC_ResetPrivateKeys
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(typeof(BiomeLockPrivateKeys), "RPC_BL_ResetPrivateKeys", (Type[])null, (Type[])null);
		}

		private static void Postfix()
		{
			BiomeLock_KeyRefresh.NotifyKeysChanged();
		}
	}
	[HarmonyPatch]
	internal static class BL_KeyRefresh_LoadKeysFromPlayer
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(typeof(BiomeLockPrivateKeys), "LoadKeysFromPlayer", (Type[])null, (Type[])null);
		}

		private static void Postfix()
		{
			BiomeLock_KeyRefresh.NotifyKeysChanged();
		}
	}
	internal static class BiomeLock_SkillCapBoss
	{
		internal static void Init()
		{
		}

		internal static int GetEffectiveSkillCap()
		{
			int cap = 0;
			ApplyCapIfMissing("defeated_eikthyr", BiomeLockPlugin.CE_SkillCap_Eikthyr.Value);
			ApplyCapIfMissing("defeated_gdking", BiomeLockPlugin.CE_SkillCap_Elder.Value);
			ApplyCapIfMissing("defeated_bonemass", BiomeLockPlugin.CE_SkillCap_Bonemass.Value);
			ApplyCapIfMissing("defeated_dragon", BiomeLockPlugin.CE_SkillCap_Moder.Value);
			ApplyCapIfMissing("defeated_goblinking", BiomeLockPlugin.CE_SkillCap_Yagluth.Value);
			ApplyCapIfMissing("defeated_queen", BiomeLockPlugin.CE_SkillCap_Queen.Value);
			ApplyCapIfMissing("defeated_fader", BiomeLockPlugin.CE_SkillCap_Fader.Value);
			return cap;
			void ApplyCapIfMissing(string bossKey, int bossCap)
			{
				if (bossCap > 0 && !BiomeLockAPI.HasPrivateKey(bossKey))
				{
					if (cap <= 0)
					{
						cap = bossCap;
					}
					else
					{
						cap = Mathf.Min(cap, bossCap);
					}
				}
			}
		}
	}
	[HarmonyPatch(typeof(Skills), "RaiseSkill")]
	internal static class BiomeLock_SkillCapBoss_RaiseSkill_Patch
	{
		private static void Prefix(Skills __instance, SkillType skillType, ref float factor)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Invalid comparison between Unknown and I4
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			if (!BiomeLockPlugin.CE_SkillCap_Enabled.Value || (int)skillType == 0 || (int)skillType == 999 || factor <= 0f)
			{
				return;
			}
			int effectiveSkillCap = BiomeLock_SkillCapBoss.GetEffectiveSkillCap();
			if (effectiveSkillCap > 0)
			{
				Skill skill = __instance.GetSkill(skillType);
				if (skill != null && skill.m_level >= (float)effectiveSkillCap)
				{
					factor = 0f;
				}
			}
		}
	}
	internal static class BiomeLock_GuardianPowerKey
	{
		[HarmonyPatch(typeof(ItemStand), "DelayedPowerActivation")]
		private static class Patch_ItemStand_DelayedPowerActivation
		{
			[HarmonyPriority(100)]
			private static bool Prefix(ItemStand __instance)
			{
				try
				{
					if (ShouldBlock(__instance))
					{
						NotifyBlocked();
						return false;
					}
					return true;
				}
				catch
				{
					return true;
				}
			}
		}

		private static string GetNameSafe(Object? obj)
		{
			try
			{
				if (obj == (Object)null)
				{
					return string.Empty;
				}
				string text = obj.name ?? string.Empty;
				int num = text.IndexOf("(Clone)", StringComparison.Ordinal);
				if (num >= 0)
				{
					text = text.Substring(0, num);
				}
				return text.Trim();
			}
			catch
			{
				return string.Empty;
			}
		}

		private static string GetRequiredGuardianPowerGlobalKeyLower(string guardianPowerName)
		{
			if (guardianPowerName.Length == 0)
			{
				return string.Empty;
			}
			if (guardianPowerName.Equals("GP_Eikthyr", StringComparison.OrdinalIgnoreCase))
			{
				return "defeated_eikthyr";
			}
			if (guardianPowerName.Equals("GP_TheElder", StringComparison.OrdinalIgnoreCase))
			{
				return "defeated_gdking";
			}
			if (guardianPowerName.Equals("GP_Bonemass", StringComparison.OrdinalIgnoreCase))
			{
				return "defeated_bonemass";
			}
			if (guardianPowerName.Equals("GP_Moder", StringComparison.OrdinalIgnoreCase))
			{
				return "defeated_dragon";
			}
			if (guardianPowerName.Equals("GP_Yagluth", StringComparison.OrdinalIgnoreCase))
			{
				return "defeated_goblinking";
			}
			if (guardianPowerName.Equals("GP_Queen", StringComparison.OrdinalIgnoreCase))
			{
				return "defeated_queen";
			}
			if (guardianPowerName.Equals("GP_Fader", StringComparison.OrdinalIgnoreCase))
			{
				return "defeated_fader";
			}
			return string.Empty;
		}

		public static bool ShouldBlock(ItemStand stand)
		{
			try
			{
				if ((Object)(object)Player.m_localPlayer == (Object)null)
				{
					return false;
				}
				if (BiomeLockPlugin.CE_SE_AdminBypass.Value && BiomeLockPlugin.IsLocalPlayerAdmin())
				{
					return false;
				}
				if ((Object)(object)stand == (Object)null)
				{
					return false;
				}
				string nameSafe = GetNameSafe((Object?)(object)stand.m_guardianPower);
				string requiredGuardianPowerGlobalKeyLower = GetRequiredGuardianPowerGlobalKeyLower(nameSafe);
				if (requiredGuardianPowerGlobalKeyLower.Length == 0)
				{
					return false;
				}
				return !BiomeLockAPI.HasPrivateKey(requiredGuardianPowerGlobalKeyLower);
			}
			catch
			{
				return false;
			}
		}

		private static void NotifyBlocked()
		{
			try
			{
				Player localPlayer = Player.m_localPlayer;
				if (!((Object)(object)localPlayer == (Object)null))
				{
					((Character)localPlayer).Message((MessageType)2, Localization.instance.Localize("$biomelock_guardian_power_locked"), 0, (Sprite)null);
				}
			}
			catch
			{
			}
		}
	}
	internal static class BiomeLock_BossSummonDay
	{
		[HarmonyPatch(typeof(OfferingBowl), "InitiateSpawnBoss")]
		private static class Patch_OfferingBowl_InitiateSpawnBoss
		{
			[HarmonyPriority(200)]
			private static bool Prefix(OfferingBowl __instance)
			{
				try
				{
					if (ShouldBlock(__instance, out var requiredDay, out var currentDay))
					{
						NotifyBlocked(requiredDay, currentDay);
						return false;
					}
					return true;
				}
				catch
				{
					return true;
				}
			}
		}

		private static string GetPrefabNameSafe(GameObject? go)
		{
			try
			{
				if ((Object)(object)go == (Object)null)
				{
					return string.Empty;
				}
				string text = ((Object)go).name ?? string.Empty;
				int num = text.IndexOf("(Clone)", StringComparison.Ordinal);
				if (num >= 0)
				{
					text = text.Substring(0, num);
				}
				return text.Trim();
			}
			catch
			{
				return string.Empty;
			}
		}

		private static int GetCurrentDaySafe()
		{
			try
			{
				if ((Object)(object)EnvMan.instance == (Object)null)
				{
					return 0;
				}
				return EnvMan.instance.GetDay();
			}
			catch
			{
				return 0;
			}
		}

		private static int GetRequiredDayForBoss(string bossPrefabName)
		{
			if (bossPrefabName.Length == 0)
			{
				return 0;
			}
			if (bossPrefabName.Equals("Eikthyr", StringComparison.OrdinalIgnoreCase))
			{
				return BiomeLockPlugin.CE_BossDay_Eikthyr.Value;
			}
			if (bossPrefabName.Equals("gd_king", StringComparison.OrdinalIgnoreCase))
			{
				return BiomeLockPlugin.CE_BossDay_Elder.Value;
			}
			if (bossPrefabName.Equals("Bonemass", StringComparison.OrdinalIgnoreCase))
			{
				return BiomeLockPlugin.CE_BossDay_Bonemass.Value;
			}
			if (bossPrefabName.Equals("Dragon", StringComparison.OrdinalIgnoreCase))
			{
				return BiomeLockPlugin.CE_BossDay_Moder.Value;
			}
			if (bossPrefabName.Equals("GoblinKing", StringComparison.OrdinalIgnoreCase))
			{
				return BiomeLockPlugin.CE_BossDay_Yagluth.Value;
			}
			if (bossPrefabName.Equals("SeekerQueen", StringComparison.OrdinalIgnoreCase))
			{
				return BiomeLockPlugin.CE_BossDay_Queen.Value;
			}
			if (bossPrefabName.Equals("Fader", StringComparison.OrdinalIgnoreCase))
			{
				return BiomeLockPlugin.CE_BossDay_Fader.Value;
			}
			return 0;
		}

		public static bool ShouldBlock(OfferingBowl bowl, out int requiredDay, out int currentDay)
		{
			requiredDay = 0;
			currentDay = 0;
			try
			{
				if ((Object)(object)Player.m_localPlayer == (Object)null)
				{
					return false;
				}
				if (!BiomeLockPlugin.CE_BossDay_Enabled.Value)
				{
					return false;
				}
				if (BiomeLockPlugin.CE_SE_AdminBypass.Value && BiomeLockPlugin.IsLocalPlayerAdmin())
				{
					return false;
				}
				if ((Object)(object)bowl == (Object)null)
				{
					return false;
				}
				if ((Object)(object)bowl.m_bossPrefab == (Object)null)
				{
					return false;
				}
				string prefabNameSafe = GetPrefabNameSafe(bowl.m_bossPrefab);
				requiredDay = GetRequiredDayForBoss(prefabNameSafe);
				if (requiredDay <= 0)
				{
					return false;
				}
				currentDay = GetCurrentDaySafe();
				return currentDay < requiredDay;
			}
			catch
			{
				return false;
			}
		}

		private static void NotifyBlocked(int requiredDay, int currentDay)
		{
			try
			{
				Player localPlayer = Player.m_localPlayer;
				if (!((Object)(object)localPlayer == (Object)null))
				{
					((Character)localPlayer).Message((MessageType)2, string.Format(Localization.instance.Localize("$biomelock_boss_day_locked"), requiredDay, currentDay), 0, (Sprite)null);
				}
			}
			catch
			{
			}
		}
	}
	internal static class BiomeLock_BossSummonKey
	{
		[HarmonyPatch(typeof(OfferingBowl), "InitiateSpawnBoss")]
		private static class Patch_OfferingBowl_InitiateSpawnBoss
		{
			[HarmonyPriority(100)]
			private static bool Prefix(OfferingBowl __instance)
			{
				try
				{
					if (ShouldBlock(__instance))
					{
						NotifyBlocked();
						return false;
					}
					return true;
				}
				catch
				{
					return true;
				}
			}
		}

		private static string GetPrefabNameSafe(GameObject? go)
		{
			try
			{
				if ((Object)(object)go == (Object)null)
				{
					return string.Empty;
				}
				string text = ((Object)go).name ?? string.Empty;
				int num = text.IndexOf("(Clone)", StringComparison.Ordinal);
				if (num >= 0)
				{
					text = text.Substring(0, num);
				}
				return text.Trim();
			}
			catch
			{
				return string.Empty;
			}
		}

		private static string GetRequiredPreviousBossGlobalKeyLower(string bossPrefabName)
		{
			if (bossPrefabName.Length == 0)
			{
				return string.Empty;
			}
			if (bossPrefabName.Equals("Eikthyr", StringComparison.OrdinalIgnoreCase))
			{
				return string.Empty;
			}
			if (bossPrefabName.Equals("gd_king", StringComparison.OrdinalIgnoreCase))
			{
				return "defeated_eikthyr";
			}
			if (bossPrefabName.Equals("Bonemass", StringComparison.OrdinalIgnoreCase))
			{
				return "defeated_gdking";
			}
			if (bossPrefabName.Equals("Dragon", StringComparison.OrdinalIgnoreCase))
			{
				return "defeated_bonemass";
			}
			if (bossPrefabName.Equals("GoblinKing", StringComparison.OrdinalIgnoreCase))
			{
				return "defeated_dragon";
			}
			if (bossPrefabName.Equals("SeekerQueen", StringComparison.OrdinalIgnoreCase))
			{
				return "defeated_goblinking";
			}
			if (bossPrefabName.Equals("Fader", StringComparison.OrdinalIgnoreCase))
			{
				return "defeated_queen";
			}
			return string.Empty;
		}

		public static bool ShouldBlock(OfferingBowl bowl)
		{
			try
			{
				if ((Object)(object)Player.m_localPlayer == (Object)null)
				{
					return false;
				}
				if (!BiomeLockPlugin.CE_BossPrevKey_Enabled.Value)
				{
					return false;
				}
				if (BiomeLockPlugin.CE_SE_AdminBypass.Value && BiomeLockPlugin.IsLocalPlayerAdmin())
				{
					return false;
				}
				if ((Object)(object)bowl == (Object)null)
				{
					return false;
				}
				if ((Object)(object)bowl.m_bossPrefab == (Object)null)
				{
					return false;
				}
				if (BiomeLock_BossSummonDay.ShouldBlock(bowl, out var _, out var _))
				{
					return false;
				}
				string prefabNameSafe = GetPrefabNameSafe(bowl.m_bossPrefab);
				string requiredPreviousBossGlobalKeyLower = GetRequiredPreviousBossGlobalKeyLower(prefabNameSafe);
				if (requiredPreviousBossGlobalKeyLower.Length == 0)
				{
					return false;
				}
				return !BiomeLockAPI.HasPrivateKey(requiredPreviousBossGlobalKeyLower);
			}
			catch
			{
				return false;
			}
		}

		private static void NotifyBlocked()
		{
			try
			{
				Player localPlayer = Player.m_localPlayer;
				if (!((Object)(object)localPlayer == (Object)null))
				{
					((Character)localPlayer).Message((MessageType)2, Localization.instance.Localize("$biomelock_boss_prev_key_locked"), 0, (Sprite)null);
				}
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(Terminal), "InitTerminal")]
	internal static class BL_Commands
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static ConsoleEvent <>9__1_0;

			public static ConsoleEvent <>9__1_1;

			public static ConsoleEvent <>9__1_2;

			public static ConsoleEvent <>9__1_3;

			internal void <Postfix>b__1_0(ConsoleEventArgs args)
			{
				if (!RequireAdmin(args))
				{
					return;
				}
				if (args.Length < 2)
				{
					args.Context.AddString("Syntax: bl_setkey bl_<key> [optional: player name]");
					return;
				}
				if (!TryGetPrivateKeyArg(args[1], out string privateKey, out string error))
				{
					args.Context.AddString(error);
					return;
				}
				long uid = 0L;
				string text = "";
				bool flag = true;
				if (args.Length >= 3)
				{
					string text2 = JoinName(args, 2).Trim();
					text = text2;
					flag = IsLocalPlayerName(text2);
					if (!flag && !BiomeLockPrivateKeys.TryResolveUidByPlayerName(text2, out uid))
					{
						args.Context.AddString("Player not found: " + text2);
						return;
					}
				}
				if (ZRoutedRpc.instance == null)
				{
					args.Context.AddString("ZRoutedRpc not ready.");
					return;
				}
				if (uid == 0)
				{
					uid = ZNet.GetUID();
				}
				ZRoutedRpc.instance.InvokeRoutedRPC(uid, "BL_SetPrivateKey", new object[1] { privateKey });
				args.Context.AddString(flag ? ("Key added to you: " + privateKey) : ("Key added to player: " + text + " -> " + privateKey));
			}

			internal void <Postfix>b__1_1(ConsoleEventArgs args)
			{
				if (!RequireAdmin(args))
				{
					return;
				}
				if (args.Length < 2)
				{
					args.Context.AddString("Syntax: bl_removekey bl_<key> [optional: player name]");
					return;
				}
				if (!TryGetPrivateKeyArg(args[1], out string privateKey, out string error))
				{
					args.Context.AddString(error);
					return;
				}
				long uid = 0L;
				string text = "";
				bool flag = true;
				if (args.Length >= 3)
				{
					string text2 = JoinName(args, 2).Trim();
					text = text2;
					flag = IsLocalPlayerName(text2);
					if (!flag && !BiomeLockPrivateKeys.TryResolveUidByPlayerName(text2, out uid))
					{
						args.Context.AddString("Player not found: " + text2);
						return;
					}
				}
				if (ZRoutedRpc.instance == null)
				{
					args.Context.AddString("ZRoutedRpc not ready.");
					return;
				}
				if (uid == 0)
				{
					uid = ZNet.GetUID();
				}
				ZRoutedRpc.instance.InvokeRoutedRPC(uid, "BL_RemovePrivateKey", new object[1] { privateKey });
				args.Context.AddString(flag ? ("Key removed from you: " + privateKey) : ("Key removed from player: " + text + " -> " + privateKey));
			}

			internal void <Postfix>b__1_2(ConsoleEventArgs args)
			{
				if (!RequireAdmin(args))
				{
					return;
				}
				long uid = 0L;
				string text = "";
				bool flag = true;
				if (args.Length >= 2)
				{
					string text2 = JoinName(args, 1).Trim();
					text = text2;
					flag = IsLocalPlayerName(text2);
					if (!flag && !BiomeLockPrivateKeys.TryResolveUidByPlayerName(text2, out uid))
					{
						args.Context.AddString("Player not found: " + text2);
						return;
					}
				}
				if (ZRoutedRpc.instance == null)
				{
					args.Context.AddString("ZRoutedRpc not ready.");
					return;
				}
				if (uid == 0)
				{
					uid = ZNet.GetUID();
				}
				ZRoutedRpc.instance.InvokeRoutedRPC(uid, "BL_ResetPrivateKeys", Array.Empty<object>());
				args.Context.AddString(flag ? "Keys reset for you." : ("Keys reset for player: " + text + "."));
			}

			internal void <Postfix>b__1_3(ConsoleEventArgs args)
			{
				if (!RequireAdmin(args))
				{
					return;
				}
				if (args.Length == 1)
				{
					args.Context.AddString("Listing local keys:");
					args.Context.AddString("Total Keys: " + BiomeLockPrivateKeys.PrivateKeys.Count);
					{
						foreach (string privateKey in BiomeLockPrivateKeys.PrivateKeys)
						{
							args.Context.AddString(privateKey);
						}
						return;
					}
				}
				string text = JoinName(args, 1).Trim();
				if (IsLocalPlayerName(text))
				{
					args.Context.AddString("Listing local keys:");
					args.Context.AddString("Total Keys: " + BiomeLockPrivateKeys.PrivateKeys.Count);
					{
						foreach (string privateKey2 in BiomeLockPrivateKeys.PrivateKeys)
						{
							args.Context.AddString(privateKey2);
						}
						return;
					}
				}
				if (!BiomeLockPrivateKeys.TryResolveUidByPlayerName(text, out var uid))
				{
					args.Context.AddString("Player not found: " + text);
					return;
				}
				if (ZRoutedRpc.instance == null)
				{
					args.Context.AddString("ZRoutedRpc not ready.");
					return;
				}
				ZRoutedRpc.instance.InvokeRoutedRPC("BL_ServerListKeys", new object[1] { uid });
			}
		}

		[HarmonyPriority(800)]
		private static void Prefix(out bool __state)
		{
			__state = Terminal.m_terminalInitialized;
		}

		private static void Postfix(bool __state)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			//IL_0075: 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_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Expected O, but got Unknown
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Expected O, but got Unknown
			if (__state)
			{
				return;
			}
			object obj = <>c.<>9__1_0;
			if (obj == null)
			{
				ConsoleEvent val = delegate(ConsoleEventArgs args)
				{
					if (RequireAdmin(args))
					{
						string privateKey2;
						string error2;
						if (args.Length < 2)
						{
							args.Context.AddString("Syntax: bl_setkey bl_<key> [optional: player name]");
						}
						else if (!TryGetPrivateKeyArg(args[1], out privateKey2, out error2))
						{
							args.Context.AddString(error2);
						}
						else
						{
							long uid4 = 0L;
							string text6 = "";
							bool flag3 = true;
							if (args.Length >= 3)
							{
								string text7 = JoinName(args, 2).Trim();
								text6 = text7;
								flag3 = IsLocalPlayerName(text7);
								if (!flag3 && !BiomeLockPrivateKeys.TryResolveUidByPlayerName(text7, out uid4))
								{
									args.Context.AddString("Player not found: " + text7);
									return;
								}
							}
							if (ZRoutedRpc.instance == null)
							{
								args.Context.AddString("ZRoutedRpc not ready.");
							}
							else
							{
								if (uid4 == 0)
								{
									uid4 = ZNet.GetUID();
								}
								ZRoutedRpc.instance.InvokeRoutedRPC(uid4, "BL_SetPrivateKey", new object[1] { privateKey2 });
								args.Context.AddString(flag3 ? ("Key added to you: " + privateKey2) : ("Key added to player: " + text6 + " -> " + privateKey2));
							}
						}
					}
				};
				<>c.<>9__1_0 = val;
				obj = (object)val;
			}
			new ConsoleCommand("bl_setkey", "[bl_key] [optional: player name]", (ConsoleEvent)obj, true, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			object obj2 = <>c.<>9__1_1;
			if (obj2 == null)
			{
				ConsoleEvent val2 = delegate(ConsoleEventArgs args)
				{
					if (RequireAdmin(args))
					{
						string privateKey;
						string error;
						if (args.Length < 2)
						{
							args.Context.AddString("Syntax: bl_removekey bl_<key> [optional: player name]");
						}
						else if (!TryGetPrivateKeyArg(args[1], out privateKey, out error))
						{
							args.Context.AddString(error);
						}
						else
						{
							long uid3 = 0L;
							string text4 = "";
							bool flag2 = true;
							if (args.Length >= 3)
							{
								string text5 = JoinName(args, 2).Trim();
								text4 = text5;
								flag2 = IsLocalPlayerName(text5);
								if (!flag2 && !BiomeLockPrivateKeys.TryResolveUidByPlayerName(text5, out uid3))
								{
									args.Context.AddString("Player not found: " + text5);
									return;
								}
							}
							if (ZRoutedRpc.instance == null)
							{
								args.Context.AddString("ZRoutedRpc not ready.");
							}
							else
							{
								if (uid3 == 0)
								{
									uid3 = ZNet.GetUID();
								}
								ZRoutedRpc.instance.InvokeRoutedRPC(uid3, "BL_RemovePrivateKey", new object[1] { privateKey });
								args.Context.AddString(flag2 ? ("Key removed from you: " + privateKey) : ("Key removed from player: " + text4 + " -> " + privateKey));
							}
						}
					}
				};
				<>c.<>9__1_1 = val2;
				obj2 = (object)val2;
			}
			new ConsoleCommand("bl_removekey", "[bl_key] [optional: player name]", (ConsoleEvent)obj2, true, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			object obj3 = <>c.<>9__1_2;
			if (obj3 == null)
			{
				ConsoleEvent val3 = delegate(ConsoleEventArgs args)
				{
					if (RequireAdmin(args))
					{
						long uid2 = 0L;
						string text2 = "";
						bool flag = true;
						if (args.Length >= 2)
						{
							string text3 = JoinName(args, 1).Trim();
							text2 = text3;
							flag = IsLocalPlayerName(text3);
							if (!flag && !BiomeLockPrivateKeys.TryResolveUidByPlayerName(text3, out uid2))
							{
								args.Context.AddString("Player not found: " + text3);
								return;
							}
						}
						if (ZRoutedRpc.instance == null)
						{
							args.Context.AddString("ZRoutedRpc not ready.");
						}
						else
						{
							if (uid2 == 0)
							{
								uid2 = ZNet.GetUID();
							}
							ZRoutedRpc.instance.InvokeRoutedRPC(uid2, "BL_ResetPrivateKeys", Array.Empty<object>());
							args.Context.AddString(flag ? "Keys reset for you." : ("Keys reset for player: " + text2 + "."));
						}
					}
				};
				<>c.<>9__1_2 = val3;
				obj3 = (object)val3;
			}
			new ConsoleCommand("bl_resetkeys", "[optional: player name]", (ConsoleEvent)obj3, true, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			object obj4 = <>c.<>9__1_3;
			if (obj4 == null)
			{
				ConsoleEvent val4 = delegate(ConsoleEventArgs args)
				{
					if (RequireAdmin(args))
					{
						if (args.Length == 1)
						{
							args.Context.AddString("Listing local keys:");
							args.Context.AddString("Total Keys: " + BiomeLockPrivateKeys.PrivateKeys.Count);
							{
								foreach (string privateKey3 in BiomeLockPrivateKeys.PrivateKeys)
								{
									args.Context.AddString(privateKey3);
								}
								return;
							}
						}
						string text = JoinName(args, 1).Trim();
						if (IsLocalPlayerName(text))
						{
							args.Context.AddString("Listing local keys:");
							args.Context.AddString("Total Keys: " + BiomeLockPrivateKeys.PrivateKeys.Count);
							{
								foreach (string privateKey4 in BiomeLockPrivateKeys.PrivateKeys)
								{
									args.Context.AddString(privateKey4);
								}
								return;
							}
						}
						if (!BiomeLockPrivateKeys.TryResolveUidByPlayerName(text, out var uid))
						{
							args.Context.AddString("Player not found: " + text);
						}
						else if (ZRoutedRpc.instance == null)
						{
							args.Context.AddString("ZRoutedRpc not ready.");
						}
						else
						{
							ZRoutedRpc.instance.InvokeRoutedRPC("BL_ServerListKeys", new object[1] { uid });
						}
					}
				};
				<>c.<>9__1_3 = val4;
				obj4 = (object)val4;
			}
			new ConsoleCommand("bl_listkeys", "[optional: player name]", (ConsoleEvent)obj4, true, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
		}

		private static bool IsLocalPlayerName(string name)
		{
			try
			{
				if ((Object)(object)Player.m_localPlayer == (Object)null)
				{
					return false;
				}
				string playerName = Player.m_localPlayer.GetPlayerName();
				if (string.IsNullOrEmpty(playerName))
				{
					return false;
				}
				return string.Equals(playerName, name, StringComparison.OrdinalIgnoreCase);
			}
			catch
			{
				return false;
			}
		}

		private static bool RequireAdmin(ConsoleEventArgs args)
		{
			bool flag = false;
			try
			{
				flag = BiomeLockPlugin.IsLocalPlayerAdmin();
			}
			catch
			{
			}
			if (!flag)
			{
				flag = IsVanillaAdmin();
			}
			if (!flag)
			{
				args.Context.AddString("Admin only.");
			}
			return flag;
		}

		private static bool IsVanillaAdmin()
		{
			try
			{
				if ((Object)(object)ZNet.instance == (Object)null)
				{
					return false;
				}
				if ((Object)(object)Player.m_localPlayer != (Object)null)
				{
					return ZNet.instance.IsAdmin(Player.m_localPlayer.GetPlayerName());
				}
				return false;
			}
			catch
			{
				return false;
			}
		}

		private static string JoinName(ConsoleEventArgs args, int startIndex)
		{
			string text = args[startIndex];
			for (int i = startIndex + 1; i < args.Length; i++)
			{
				text = text + " " + args[i];
			}
			return text;
		}

		private static bool TryGetPrivateKeyArg(string arg, out string privateKey, out string error)
		{
			privateKey = "";
			error = "";
			string text = BiomeLockPrivateKeys.NormalizeKey(arg);
			if (!text.StartsWith("bl_", StringComparison.Ordinal))
			{
				error = "Key must include prefix. Example: bl_defeated_eikthyr";
				return false;
			}
			string text2 = text.Substring("bl_".Length);
			if (string.IsNullOrEmpty(text2))
			{
				error = "Invalid key.";
				return false;
			}
			if (!BiomeLockPrivateKeys.IsBossGlobalKey(text2))
			{
				error = "Invalid key: " + text;
				return false;
			}
			privateKey = text;
			return true;
		}
	}
	[BepInPlugin("radamanto.BiomeLock", "BiomeLock", "1.0.9")]
	public class BiomeLockPlugin : BaseUnityPlugin
	{
		private class ConfigurationManagerAttributes
		{
			public bool? Browsable = false;
		}

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

			private object <>2__current;

			public float quietSeconds;

			public BiomeLockPlugin <>4__this;

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

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

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

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

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					break;
				case 1:
					<>1__state = -1;
					break;
				}
				if ((DateTime.UtcNow - <>4__this._lastCfgWriteUtc).TotalSeconds < (double)quietSeconds)
				{
					<>2__current = null;
					<>1__state = 1;
					return true;
				}
				try
				{
					if (<>4__this._configWatcher == null || !<>4__this._watcherReady)
					{
						return false;
					}
					<>4__this._configWatcher.EnableRaisingEvents = false;
					if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
					{
						((BaseUnityPlugin)<>4__this).Config.Reload();
						<>4__this._ignoreEventsUntilUtc = DateTime.UtcNow.AddSeconds(1.0);
						((BaseUnityPlugin)<>4__this).Config.Save();
					}
				}
				catch
				{
				}
				finally
				{
					if (<>4__this._configWatcher != null)
					{
						<>4__this._configWatcher.EnableRaisingEvents = true;
					}
					<>4__this._reloadScheduled = false;
				}
				return false;
			}

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

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

		internal const string ModGUID = "radamanto.BiomeLock";

		internal const string ModName = "BiomeLock";

		internal const string ModVersion = "1.0.9";

		internal static ManualLogSource? Log;

		private Harmony _harmony = null;

		internal static ConfigEntry<bool> CE_SE_AdminBypass;

		internal static ConfigEntry<string> CE_SE_BlockedBiomes;

		internal static ConfigEntry<bool> CE_SE_Block_DungeonTeleport;

		internal static ConfigEntry<bool> CE_SE_Block_MapExplore;

		internal static ConfigEntry<bool> CE_SE_Block_AutoPickup;

		internal static ConfigEntry<bool> CE_SE_Block_Pickup;

		internal static ConfigEntry<bool> CE_SE_Block_GenericInteract;

		internal static ConfigEntry<bool> CE_SE_Block_ItemDropInteract;

		internal static ConfigEntry<bool> CE_SE_Block_PickableInteract;

		internal static ConfigEntry<bool> CE_SE_Block_ContainerInteract;

		internal static ConfigEntry<bool> CE_SE_Block_AttackBlock;

		internal static ConfigEntry<bool> CE_SE_Block_Hammer;

		internal static ConfigEntry<bool> CE_SE_Block_TerrainHoe;

		internal static ConfigEntry<bool> CE_SE_Broadcast_Enabled;

		internal static ConfigEntry<float> CE_SE_Broadcast_Interval;

		internal static ConfigEntry<bool> CE_GuardianPower_Enabled;

		internal static ConfigEntry<bool> CE_BossPrevKey_Enabled;

		internal static ConfigEntry<bool> CE_BossDay_Enabled;

		internal static ConfigEntry<int> CE_BossDay_Eikthyr;

		internal static ConfigEntry<int> CE_BossDay_Elder;

		internal static ConfigEntry<int> CE_BossDay_Bonemass;

		internal static ConfigEntry<int> CE_BossDay_Moder;

		internal static ConfigEntry<int> CE_BossDay_Yagluth;

		internal static ConfigEntry<int> CE_BossDay_Queen;

		internal static ConfigEntry<int> CE_BossDay_Fader;

		internal static ConfigEntry<bool> CE_SE_Block_SpawnBlock;

		internal static ConfigEntry<bool> CE_SE_Block_MapPins;

		internal static ConfigEntry<bool> CE_GlobalKeys_PrivateKeys;

		internal static ConfigEntry<bool> CE_SE_Block_TraderInteract;

		internal static ConfigEntry<bool> CE_SE_Block_HildirMapTable;

		internal static ConfigEntry<bool> CE_SkillCap_Enabled;

		internal static ConfigEntry<int> CE_SkillCap_Eikthyr;

		internal static ConfigEntry<int> CE_SkillCap_Elder;

		internal static ConfigEntry<int> CE_SkillCap_Bonemass;

		internal static ConfigEntry<int> CE_SkillCap_Moder;

		internal static ConfigEntry<int> CE_SkillCap_Yagluth;

		internal static ConfigEntry<int> CE_SkillCap_Queen;

		internal static ConfigEntry<int> CE_SkillCap_Fader;

		internal static ConfigSync? ConfigSync;

		private static ConfigEntry<bool>? _serverConfigLocked;

		private FileSystemWatcher? _configWatcher;

		private DateTime _lastCfgWriteUtc = DateTime.MinValue;

		private bool _reloadScheduled;

		private bool _watcherReady;

		private DateTime _ignoreEventsUntilUtc = DateTime.MinValue;

		private void Awake()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			Localizer.Load();
			Log = ((BaseUnityPlugin)this).Logger;
			_harmony = new Harmony("radamanto.BiomeLock");
			SetupServerSyncAndWatcher();
			SetupSEBinds();
			_harmony.PatchAll();
		}

		public static bool IsLocalPlayerAdmin()
		{
			return ConfigSync != null && ConfigSync.IsAdmin;
		}

		private void SetupSEBinds()
		{
			CE_SE_AdminBypass = Cfg("01 - General", "AdminBypass", defaultValue: true, "If true, administrators bypass restrictions.");
			CE_GlobalKeys_PrivateKeys = Cfg("01 - General", "PrivateKeys", defaultValue: true, "If true, redirects content unlocks based on Global Keys to per-player Private Keys.");
			CE_SE_BlockedBiomes = Cfg("02 - BiomeLock", "02.1 - BlockedBiomes", "BlackForest,Swamp,Mountain,Plains,Mistlands,AshLands,DeepNorth", "The biomes listed here will be blocked for players who have not defeated the previous biome’s boss.\nAllowed values: BlackForest, Swamp, Mountain, Plains, Mistlands, AshLands, DeepNorth, Ocean");
			CE_SE_Block_TraderInteract = Cfg("03 - Traders", "03.01 - TraderInteract", defaultValue: true, "If true, blocks interaction with the traders Haldor and the Bog Witch.");
			CE_SE_Block_HildirMapTable = Cfg("03 - Traders", "03.02 - HildirMapTable", defaultValue: true, "If true, blocks interaction on Hildir's map table.");
			CE_SE_Block_DungeonTeleport = Cfg("04 - SE Blocks", "04.01 - Dungeon", defaultValue: true, "If true, blocks dungeon teleport entrances/exits.");
			CE_SE_Block_MapExplore = Cfg("04 - SE Blocks", "04.02 - MapExplore", defaultValue: true, "If true, blocks map exploration.");
			CE_SE_Block_AutoPickup = Cfg("04 - SE Blocks", "04.03 - AutoPickup", defaultValue: true, "If true, blocks automatic pickup.");
			CE_SE_Block_Pickup = Cfg("04 - SE Blocks", "04.04 - Pickup", defaultValue: true, "If true, blocks manual pickup.");
			CE_SE_Block_GenericInteract = Cfg("04 - SE Blocks", "04.05 - Interact", defaultValue: true, "If true, blocks interactions.");
			CE_SE_Block_ItemDropInteract = Cfg("04 - SE Blocks", "04.06 - ItemDropInteract", defaultValue: true, "If true, blocks item drop interactions.");
			CE_SE_Block_PickableInteract = Cfg("04 - SE Blocks", "04.07 - PickableInteract", defaultValue: true, "If true, blocks pickable interactions.");
			CE_SE_Block_ContainerInteract = Cfg("04 - SE Blocks", "04.08 - ContainerInteract", defaultValue: true, "If true, blocks container interactions.");
			CE_SE_Block_AttackBlock = Cfg("04 - SE Blocks", "04.09 - AttackBlock", defaultValue: true, "If true, blocks all player attacks.");
			CE_SE_Block_Hammer = Cfg("04 - SE Blocks", "04.10 - Hammer", defaultValue: true, "If true, blocks hammer actions.");
			CE_SE_Block_TerrainHoe = Cfg("04 - SE Blocks", "04.11 - Hoe/Cultivator", defaultValue: true, "If true, blocks terrain modification by hoe/cultivator.");
			CE_SE_Block_MapPins = Cfg("04 - SE Blocks", "04.12 - MapPins", defaultValue: true, "If true, blocks placing pins on the map.");
			CE_SE_Block_SpawnBlock = Cfg("04 - SE Blocks", "04.13 - MobSpawn", defaultValue: true, "If true, blocks mob spawning.");
			CE_SE_Broadcast_Enabled = Cfg("05 - SE Broadcast", "05.01 - Enable", defaultValue: true, "Displays messages in the center of the screen while the SE_BiomeLock is active.");
			CE_SE_Broadcast_Interval = Cfg("05 - SE Broadcast", "05.02 - IntervalSeconds", 8f, "Interval (in seconds) between BiomeLock broadcast messages.");
			CE_GuardianPower_Enabled = Cfg("06 - Guardian Power", "06.01 - Enable", defaultValue: true, "If true, blocks claiming guardian powers at the altar until the player has the required private key.");
			CE_BossPrevKey_Enabled = Cfg("07 - Boss Summon Key", "07.01 - Enable", defaultValue: true, "If true, blocks boss altar interaction until the player has defeated the previous boss.");
			CE_BossDay_Enabled = Cfg("08 - Boss Summon Day", "08.01 - Enable", defaultValue: true, "If true, blocks boss altar interaction until the configured day.");
			CE_BossDay_Eikthyr = Cfg("08 - Boss Summon Day", "08.02 - Eikthyr", 100, "Minimum day required to summon Eikthyr. (0 = disabled)");
			CE_BossDay_Elder = Cfg("08 - Boss Summon Day", "08.03 - Elder", 200, "Minimum day required to summon Elder. (0 = disabled)");
			CE_BossDay_Bonemass = Cfg("08 - Boss Summon Day", "08.04 - Bonemass", 300, "Minimum day required to summon Bonemass. (0 = disabled)");
			CE_BossDay_Moder = Cfg("08 - Boss Summon Day", "08.05 - Moder", 400, "Minimum day required to summon Moder. (0 = disabled)");
			CE_BossDay_Yagluth = Cfg("08 - Boss Summon Day", "08.06 - Yagluth", 500, "Minimum day required to summon Yagluth. (0 = disabled)");
			CE_BossDay_Queen = Cfg("08 - Boss Summon Day", "08.07 - Queen", 600, "Minimum day required to summon The Queen. (0 = disabled)");
			CE_BossDay_Fader = Cfg("08 - Boss Summon Day", "08.08 - Fader", 700, "Minimum day required to summon Fader. (0 = disabled)");
			CE_SkillCap_Enabled = Cfg("09 - Skill Cap", "09.01 - Enable", defaultValue: true, "If true, caps skill (all skills) levels by boss private keys.");
			CE_SkillCap_Eikthyr = Cfg("09 - Skill Cap", "09.02 - Eikthyr", 0, "Maximum skill level (all skills) allowed while the player does NOT have Eikthyr private key. (0 = disabled)");
			CE_SkillCap_Elder = Cfg("09 - Skill Cap", "09.03 - Elder", 0, "Maximum skill level (all skills) allowed while the player does NOT have Elder private key. (0 = disabled)");
			CE_SkillCap_Bonemass = Cfg("09 - Skill Cap", "09.04 - Bonemass", 0, "Maximum skill level (all skills) allowed while the player does NOT have Bonemass private key. (0 = disabled)");
			CE_SkillCap_Moder = Cfg("09 - Skill Cap", "09.05 - Moder", 0, "Maximum skill level (all skills) allowed while the player does NOT have Moder private key. (0 = disabled)");
			CE_SkillCap_Yagluth = Cfg("09 - Skill Cap", "09.06 - Yagluth", 0, "Maximum skill level (all skills) allowed while the player does NOT have Yagluth private key. (0 = disabled)");
			CE_SkillCap_Queen = Cfg("09 - Skill Cap", "09.07 - Queen", 0, "Maximum skill level (all skills) allowed while the player does NOT have The Queen private key. (0 = disabled)");
			CE_SkillCap_Fader = Cfg("09 - Skill Cap", "09.08 - Fader", 0, "Maximum skill level (all skills) allowed while the player does NOT have Fader private key. Example: (0 = disabled)");
		}

		public void SetupServerSyncAndWatcher()
		{
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Expected O, but got Unknown
			bool flag = false;
			try
			{
				((BaseUnityPlugin)this).Config.SaveOnConfigSet = false;
				ConfigSync = new ConfigSync(((BaseUnityPlugin)this).Info.Metadata.GUID)
				{
					DisplayName = ((BaseUnityPlugin)this).Info.Metadata.Name,
					CurrentVersion = ((BaseUnityPlugin)this).Info.Metadata.Version.ToString(),
					MinimumRequiredVersion = ((BaseUnityPlugin)this).Info.Metadata.Version.ToString()
				};
				_serverConfigLocked = ((BaseUnityPlugin)this).Config.Bind<bool>("01 - General", "LockConfiguration", true, new ConfigDescription("If true, the server locks synchronized configs.", (AcceptableValueBase)null, new object[1]
				{
					new ConfigurationManagerAttributes
					{
						Browsable = false
					}
				}));
				ConfigSync.AddLockingConfigEntry<bool>(_serverConfigLocked);
				SetupConfigWatcher();
				flag = true;
			}
			catch
			{
			}
			finally
			{
				((BaseUnityPlugin)this).Config.SaveOnConfigSet = true;
				if (flag)
				{
					((BaseUnityPlugin)this).Config.Save();
				}
			}
		}

		protected ConfigEntry<T> Cfg<T>(string section, string key, T defaultValue, string description, bool synced = true)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			return config(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()), synced);
		}

		private ConfigEntry<T> config<T>(string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			ConfigDescription val = new ConfigDescription(description.Description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]"), description.AcceptableValues, description.Tags);
			ConfigEntry<T> val2 = ((BaseUnityPlugin)this).Config.Bind<T>(group, name, value, val);
			try
			{
				SyncedConfigEntry<T> syncedConfigEntry = ((ConfigSync != null) ? ConfigSync.AddConfigEntry<T>(val2) : null);
				if (syncedConfigEntry != null)
				{
					syncedConfigEntry.SynchronizedConfig = synchronizedSetting;
				}
			}
			catch
			{
			}
			return val2;
		}

		private void SetupConfigWatcher()
		{
			try
			{
				if (_configWatcher != null)
				{
					_configWatcher.Dispose();
				}
				string configPath = Paths.ConfigPath;
				string fileName = Path.GetFileName(((BaseUnityPlugin)this).Config.ConfigFilePath);
				_configWatcher = new FileSystemWatcher(configPath, fileName)
				{
					IncludeSubdirectories = false,
					NotifyFilter = (NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite | NotifyFilters.CreationTime)
				};
				FileSystemEventHandler onChanged = delegate
				{
					if (!(DateTime.UtcNow < _ignoreEventsUntilUtc))
					{
						_lastCfgWriteUtc = DateTime.UtcNow;
						if (!_reloadScheduled)
						{
							_reloadScheduled = true;
							((MonoBehaviour)this).StartCoroutine(ReloadConfigAfterQuietPeriod(0.75f));
						}
					}
				};
				_configWatcher.Changed += onChanged;
				_configWatcher.Created += onChanged;
				_configWatcher.Renamed += delegate(object _, RenamedEventArgs __)
				{
					onChanged(_, __);
				};
				_configWatcher.EnableRaisingEvents = true;
				_watcherReady = true;
			}
			catch
			{
			}
		}

		[IteratorStateMachine(typeof(<ReloadConfigAfterQuietPeriod>d__58))]
		private IEnumerator ReloadConfigAfterQuietPeriod(float quietSeconds)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <ReloadConfigAfterQuietPeriod>d__58(0)
			{
				<>4__this = this,
				quietSeconds = quietSeconds
			};
		}
	}
	internal static class BiomeLockPrivateKeys
	{
		internal const string PrivatePrefix = "bl_";

		internal const string PlayerSaveKey = "BL_PrivateKeys";

		internal const string RPC_SetPrivateKey = "BL_SetPrivateKey";

		internal const string RPC_RemovePrivateKey = "BL_RemovePrivateKey";

		internal const string RPC_ResetPrivateKeys = "BL_ResetPrivateKeys";

		internal const string RPC_ClientListKeysBegin = "BL_ClientListKeysBegin";

		internal const string RPC_ClientListKeysLine = "BL_ClientListKeysLine";

		internal const string RPC_ClientListKeysEnd = "BL_ClientListKeysEnd";

		internal const string RPC_ServerListKeys = "BL_ServerListKeys";

		internal const string RPC_ServerSetPrivateKeys = "BL_ServerSetPrivateKeys";

		internal const string RPC_ServerSetPrivateKey = "BL_ServerSetPrivateKey";

		internal const string RPC_ServerRemovePrivateKey = "BL_ServerRemovePrivateKey";

		internal const float ShareRadiusMeters = 120f;

		internal static HashSet<string> PrivateKeys = new HashSet<string>(StringComparer.Ordinal);

		internal static readonly Dictionary<long, HashSet<string>> ServerPrivateKeysByUid = new Dictionary<long, HashSet<string>>();

		private static readonly HashSet<string> BossGlobalKeys = new HashSet<string>(StringComparer.Ordinal)
		{
			"defeated_eikthyr", "defeated_gdking", "defeated_bonemass", "defeated_dragon", "defeated_goblinking", "defeated_queen", "defeated_fader", "defeated_serpent", "KilledTroll", "killed_surtling",
			"KilledBat", "Hildir1", "Hildir2", "Hildir3"
		};

		internal static bool IsInMainScene()
		{
			try
			{
				return (Object)(object)ZNetScene.instance != (Object)null && (Object)(object)Player.m_localPlayer != (Object)null;
			}
			catch
			{
				return false;
			}
		}

		internal static string NormalizeKey(string key)
		{
			return (key ?? string.Empty).Trim().ToLowerInvariant();
		}

		internal static bool IsBossGlobalKey(string globalKeyLower)
		{
			return BossGlobalKeys.Contains(globalKeyLower);
		}

		internal static string ToPrivateKey(string globalKeyLower)
		{
			return "bl_" + globalKeyLower;
		}

		internal static void EnsurePlayerRpcRegistered()
		{
			if (ZRoutedRpc.instance == null)
			{
				return;
			}
			try
			{
				ZRoutedRpc.instance.Register<string>("BL_SetPrivateKey", (Action<long, string>)RPC_BL_SetPrivateKey);
				ZRoutedRpc.instance.Register<string>("BL_RemovePrivateKey", (Action<long, string>)RPC_BL_RemovePrivateKey);
				ZRoutedRpc.instance.Register("BL_ResetPrivateKeys", (Action<long>)RPC_BL_ResetPrivateKeys);
				ZRoutedRpc.instance.Register<long, int>("BL_ClientListKeysBegin", (Action<long, long, int>)RPC_BL_ClientListKeysBegin);
				ZRoutedRpc.instance.Register<long, string>("BL_ClientListKeysLine", (Action<long, long, string>)RPC_BL_ClientListKeysLine);
				ZRoutedRpc.instance.Register<long>("BL_ClientListKeysEnd", (Action<long, long>)RPC_BL_ClientListKeysEnd);
			}
			catch
			{
			}
		}

		internal static void EnsureServerRpcRegistered()
		{
			if (ZRoutedRpc.instance == null || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
			{
				return;
			}
			try
			{
				ZRoutedRpc.instance.Register<long>("BL_ServerListKeys", (Action<long, long>)RPC_BL_ServerListKeys);
				ZRoutedRpc.instance.Register<string, long>("BL_ServerSetPrivateKeys", (Action<long, string, long>)RPC_BL_ServerSetPrivateKeys);
				ZRoutedRpc.instance.Register<string, long>("BL_ServerSetPrivateKey", (Action<long, string, long>)RPC_BL_ServerSetPrivateKey);
				ZRoutedRpc.instance.Register<string, long>("BL_ServerRemovePrivateKey", (Action<long, string, long>)RPC_BL_ServerRemovePrivateKey);
			}
			catch