Decompiled source of ProtectiveWards v2.1.0

ProtectiveWards.dll

Decompiled 3 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using HarmonyLib;
using JetBrains.Annotations;
using Jotunn.GUI;
using Jotunn.Managers;
using Jotunn.Utils;
using LocalizationManager;
using Microsoft.CodeAnalysis;
using ProtectiveWards;
using ProtectiveWards.Compatibility;
using SoftReferenceableAssets;
using Splatform;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using YamlDotNet.Serialization;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("Protective Wards")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Protective Wards")]
[assembly: AssemblyCopyright("Copyright ©  2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("f71912b8-9b1c-4181-911a-1550f4ec2889")]
[assembly: AssemblyFileVersion("2.1.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.1.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.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]
	[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]
	[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 const string defaultLanguage = "English";

		private static readonly Dictionary<string, Dictionary<string, Func<string>>> PlaceholderProcessors = new Dictionary<string, Dictionary<string, Func<string>>>();

		private static readonly Dictionary<string, Dictionary<string, string>> loadedTexts = new Dictionary<string, Dictionary<string, string>>();

		private static readonly ConditionalWeakTable<Localization, string> localizationLanguage = new ConditionalWeakTable<Localization, string>();

		private static readonly List<WeakReference<Localization>> localizationObjects = new List<WeakReference<Localization>>();

		private static BaseUnityPlugin? _plugin;

		private static readonly List<string> fileExtensions = new List<string> { ".json", ".yml" };

		private static bool initialized;

		private static bool localizationEnabled;

		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;
			}
		}

		private static void UpdatePlaceholderText(Localization localization, string key)
		{
			localizationLanguage.TryGetValue(localization, out string value);
			string text = loadedTexts[value][key];
			if (PlaceholderProcessors.TryGetValue(key, out Dictionary<string, Func<string>> 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
		{
			if (convertConfigValue == null)
			{
				convertConfigValue = (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] = () => convertConfigValue(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 Initialize()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Invalid comparison between Unknown and I4
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			if (!initialized)
			{
				initialized = true;
				if ((int)SystemInfo.graphicsDeviceType != 4)
				{
					EnsureYamlDotNetAvailable();
					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);
					localizationEnabled = true;
				}
			}
		}

		public static void ApplyCurrentLocalization()
		{
			if (!localizationEnabled || Localization.m_instance == null)
			{
				return;
			}
			string language = "English";
			if (PlatformManager.DistributionPlatform != null && PlatformInitializer.PreferencesInitialized)
			{
				string selectedLanguage = Localization.m_instance.GetSelectedLanguage();
				if (string.IsNullOrEmpty(selectedLanguage))
				{
					PlatformPrefs.SetString("language", "English");
				}
				else
				{
					language = selectedLanguage;
				}
			}
			LoadLocalization(Localization.m_instance, language);
		}

		private static void EnsureYamlDotNetAvailable()
		{
			try
			{
				if (Type.GetType("YamlDotNet.Serialization.DeserializerBuilder, YamlDotNet", throwOnError: false) != null)
				{
					return;
				}
			}
			catch (Exception innerException)
			{
				throw new FileNotFoundException("YamlDotNet is required for localization but could not be loaded. Install ValheimModding-YamlDotNet.", innerException);
			}
			throw new FileNotFoundException("YamlDotNet is required for localization but could not be loaded. Install ValheimModding-YamlDotNet.");
		}

		private static void LoadLocalization(Localization __instance, string language)
		{
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Expected O, but got Unknown
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Expected O, but got Unknown
			if (!localizationLanguage.Remove(__instance))
			{
				localizationObjects.Add(new WeakReference<Localization>(__instance));
			}
			localizationLanguage.Add(__instance, language);
			Dictionary<string, string> localizationFiles = new Dictionary<string, string>();
			string[] prefixes = new string[2]
			{
				Plugin.Info.Metadata.Name + ".",
				Plugin.Info.Metadata.Name.Replace(" ", "") + "."
			};
			Scan(Paths.ConfigPath, warn: true);
			byte[] array = LoadTranslationFromAssembly("English");
			if (array == 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.");
			}
			Dictionary<string, string> dictionary = ((BuilderSkeleton<DeserializerBuilder>)new DeserializerBuilder()).IgnoreFields().Build().Deserialize<Dictionary<string, string>>(Encoding.UTF8.GetString(array));
			if (dictionary == null)
			{
				throw new Exception("Localization for mod " + Plugin.Info.Metadata.Name + " failed: Localization file was empty.");
			}
			string text = null;
			if (language != "English")
			{
				if (localizationFiles.ContainsKey(language))
				{
					text = File.ReadAllText(localizationFiles[language]);
				}
				else
				{
					byte[] array2 = LoadTranslationFromAssembly(language);
					if (array2 != null)
					{
						text = Encoding.UTF8.GetString(array2);
					}
				}
			}
			if (text == null && localizationFiles.ContainsKey("English"))
			{
				text = File.ReadAllText(localizationFiles["English"]);
			}
			if (text != null)
			{
				Dictionary<string, string> dictionary2;
				try
				{
					dictionary2 = ((BuilderSkeleton<DeserializerBuilder>)new DeserializerBuilder()).IgnoreFields().Build().Deserialize<Dictionary<string, string>>(text) ?? new Dictionary<string, string>();
				}
				catch (Exception arg)
				{
					global::ProtectiveWards.ProtectiveWards.LogInfo($"Failed to deserialize localization for language '{language}'. Using base localization only.\n{arg}");
					dictionary2 = new Dictionary<string, string>();
				}
				foreach (KeyValuePair<string, string> item in dictionary2)
				{
					dictionary[item.Key] = item.Value;
				}
			}
			loadedTexts[language] = dictionary;
			foreach (KeyValuePair<string, string> item2 in dictionary)
			{
				UpdatePlaceholderText(__instance, item2.Key);
			}
			void Scan(string root, bool warn)
			{
				foreach (string item3 in from f in Directory.GetFiles(root, "*.*", SearchOption.AllDirectories)
					where fileExtensions.Contains(Path.GetExtension(f))
					select f)
				{
					string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(item3);
					string[] array3 = prefixes;
					foreach (string text2 in array3)
					{
						if (fileNameWithoutExtension.StartsWith(text2))
						{
							string text3 = fileNameWithoutExtension.Substring(text2.Length);
							if (!string.IsNullOrWhiteSpace(text3))
							{
								if (localizationFiles.ContainsKey(text3))
								{
									if (warn)
									{
										global::ProtectiveWards.ProtectiveWards.LogInfo("Duplicate localization '" + text3 + "' for " + Plugin.Info.Metadata.Name + ". Skipping " + item3);
									}
								}
								else
								{
									localizationFiles[text3] = item3;
								}
							}
							break;
						}
					}
				}
			}
		}

		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();
		}
	}
}
namespace ProtectiveWards
{
	internal static class AdminServerFeatures
	{
		[HarmonyPatch(typeof(Terminal), "InitTerminal")]
		private static class Terminal_InitTerminal_RegisterCommands
		{
			private static void Postfix()
			{
				RegisterCommands();
			}
		}

		[HarmonyPatch(typeof(ZoneSystem), "Start")]
		private static class ZoneSystem_Start_RegisterAdminRPCs
		{
			private static void Postfix()
			{
				RegisterRPCs();
			}
		}

		[HarmonyPatch(typeof(ZoneSystem), "OnDestroy")]
		private static class ZoneSystem_OnDestroy_ResetAdminRPCs
		{
			private static void Postfix()
			{
				ResetRPCRegistration();
			}
		}

		[HarmonyPatch(typeof(Piece), "SetCreator")]
		private static class Piece_SetCreator_CheckWardBuildLimit
		{
			private static void Postfix(Piece __instance, long uid)
			{
				//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_0096: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
				if (ProtectiveWards.wardBuildLimitPerPlayer.Value <= 0 || (Object)(object)__instance == (Object)null || uid == 0L || (Object)(object)((Component)__instance).GetComponent<PrivateArea>() == (Object)null || !WardZdoUtils.IsWardPrefab(((Component)__instance).gameObject))
				{
					return;
				}
				ZNetView componentZNetView = ((Component)(object)__instance).GetComponentZNetView();
				if ((Object)(object)componentZNetView == (Object)null || !componentZNetView.IsValid())
				{
					return;
				}
				ZDO zDO = componentZNetView.GetZDO();
				if (zDO != null)
				{
					ZDOID uid2 = zDO.m_uid;
					if (!s_requestedWardLimitChecks.Contains(uid2))
					{
						s_requestedWardLimitChecks.Add(uid2);
						RequestWardBuildLimitCheck(uid, uid2);
					}
				}
			}
		}

		private const string RPC_CheckWardBuildLimit = "PW_CheckWardBuildLimit";

		private const string RPC_DestroyWardForBuildLimit = "PW_DestroyWardForBuildLimit";

		private static readonly HashSet<ZDOID> s_requestedWardLimitChecks = new HashSet<ZDOID>();

		private static bool s_rpcRegistered;

		private static bool s_commandRegistered;

		internal static void RegisterRPCs()
		{
			if (!s_rpcRegistered && ZRoutedRpc.instance != null)
			{
				WardRpc.Register("PW_DestroyWardForBuildLimit", RPC_DestroyWardForBuildLimitClient);
				ZNet instance = ZNet.instance;
				if (instance != null && instance.IsServer())
				{
					WardRpc.Register("PW_CheckWardBuildLimit", RPC_CheckWardBuildLimitServer);
				}
				s_rpcRegistered = true;
			}
		}

		internal static void ResetRPCRegistration()
		{
			s_rpcRegistered = false;
			s_requestedWardLimitChecks.Clear();
		}

		private static void RegisterCommands()
		{
			if (!s_commandRegistered)
			{
				RegisterPlayerListCommand("pw_permit", "<player name> - add an online player to the nearest ward within configured range", RequestPermit);
				RegisterPlayerListCommand("ward_permit", "<player name> - add an online player to the nearest ward within configured range", RequestPermit);
				RegisterPlayerListCommand("pw_unpermit", "<player name> - remove a player from the nearest ward permitted list", RequestUnpermit);
				RegisterPlayerListCommand("ward_unpermit", "<player name> - remove a player from the nearest ward permitted list", RequestUnpermit);
				RegisterWardStateCommand("pw_enable", "enable the nearest ward within configured range", enabled: true);
				RegisterWardStateCommand("ward_enable", "enable the nearest ward within configured range", enabled: true);
				RegisterWardStateCommand("pw_disable", "disable the nearest ward within configured range", enabled: false);
				RegisterWardStateCommand("ward_disable", "disable the nearest ward within configured range", enabled: false);
				RegisterWardExpirationStateCommand("pw_set_expired", "mark the nearest ward as expired", expired: true);
				RegisterWardExpirationStateCommand("ward_set_expired", "mark the nearest ward as expired", expired: true);
				RegisterWardExpirationStateCommand("pw_set_unexpired", "clear expired state from the nearest ward", expired: false);
				RegisterWardExpirationStateCommand("ward_set_unexpired", "clear expired state from the nearest ward", expired: false);
				s_commandRegistered = true;
			}
		}

		private static void RegisterPlayerListCommand(string command, string description, Action<string, Terminal> action)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			new ConsoleCommand(command, description, (ConsoleEvent)delegate(ConsoleEventArgs args)
			{
				if (ValidateWardControlCommand(args.Context))
				{
					if (args.Length < 2)
					{
						args.Context.AddString("Usage: <player name>");
					}
					else
					{
						action(GetCommandQuery(args), args.Context);
					}
				}
			}, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
		}

		private static void RegisterWardStateCommand(string command, string description, bool enabled)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			new ConsoleCommand(command, description, (ConsoleEvent)delegate(ConsoleEventArgs args)
			{
				if (ValidateWardControlCommand(args.Context))
				{
					RequestSetWardEnabled(enabled, args.Context);
				}
			}, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
		}

		private static void RegisterWardExpirationStateCommand(string command, string description, bool expired)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			new ConsoleCommand(command, description, (ConsoleEvent)delegate(ConsoleEventArgs args)
			{
				if (ValidateWardControlCommand(args.Context))
				{
					RequestSetWardExpired(expired, args.Context);
				}
			}, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
		}

		private static string GetCommandQuery(ConsoleEventArgs args)
		{
			return string.Join(" ", args.Args.Skip(1).ToArray()).Trim();
		}

		private static bool ValidateWardControlCommand(Terminal context)
		{
			if (AreWardControlCommandsEnabled())
			{
				return true;
			}
			context.AddString("Ward control commands are disabled.");
			return false;
		}

		private static bool AreWardControlCommandsEnabled()
		{
			return ProtectiveWards.wardExternalControlCommandsEnabled.Value;
		}

		private static float GetWardControlCommandRange()
		{
			return Math.Max(ProtectiveWards.wardExternalControlCommandRange.Value, 0f);
		}

		private static void RequestPermit(string query, Terminal context)
		{
			RequestControl(WardControl.Operation.Permit, query, context);
		}

		private static void RequestUnpermit(string query, Terminal context)
		{
			RequestControl(WardControl.Operation.Unpermit, query, context);
		}

		private static void RequestSetWardEnabled(bool enabled, Terminal context)
		{
			RequestControl(enabled ? WardControl.Operation.Enable : WardControl.Operation.Disable, "", context);
		}

		private static void RequestSetWardExpired(bool expired, Terminal context)
		{
			RequestControl(expired ? WardControl.Operation.Expire : WardControl.Operation.Unexpire, "", context);
		}

		internal static void RequestPermittedWardToggle(PrivateArea ward, long playerID)
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			if (ward == null)
			{
				return;
			}
			ZNetView nview = ward.m_nview;
			if (((nview != null) ? new bool?(nview.IsValid()) : ((bool?)null)) == true)
			{
				Player localPlayer = Player.m_localPlayer;
				if (localPlayer != null && localPlayer.GetPlayerID() == playerID)
				{
					WardControl.Request(ward.m_nview.GetZDO().m_uid, WardControl.Operation.Toggle);
				}
			}
		}

		private static void RequestControl(WardControl.Operation action, string query, Terminal context)
		{
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				context.AddString("Player is not available.");
				return;
			}
			PrivateArea val = null;
			float num = GetWardControlCommandRange();
			foreach (PrivateArea allArea in PrivateArea.m_allAreas)
			{
				if (!ProtectiveWards.IsPlayerWardPrefab(allArea))
				{
					continue;
				}
				ZNetView nview = allArea.m_nview;
				if (nview != null && nview.IsValid())
				{
					float num2 = Utils.DistanceXZ(((Component)allArea).transform.position, ((Component)localPlayer).transform.position);
					if (num2 <= num)
					{
						num = num2;
						val = allArea;
					}
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				context.AddString("$pw_permit_no_ward".Localize());
			}
			else
			{
				WardControl.Request(val.m_nview.GetZDO().m_uid, action, query, context);
			}
		}

		private static void RequestWardBuildLimitCheck(long creatorID, ZDOID newWardID)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			val.Write(creatorID);
			val.Write(newWardID);
			ZNet instance = ZNet.instance;
			if (instance != null && instance.IsServer())
			{
				RPC_CheckWardBuildLimitServer(0L, new ZPackage(val.GetArray()));
			}
			else
			{
				WardRpc.SendToServer("PW_CheckWardBuildLimit", val);
			}
		}

		private static void RPC_CheckWardBuildLimitServer(long sender, ZPackage package)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: 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)
			long num = package.ReadLong();
			ZDOID val = package.ReadZDOID();
			try
			{
				if (ProtectiveWards.wardBuildLimitPerPlayer.Value <= 0 || num == 0L || ((ZDOID)(ref val)).Equals(ZDOID.None) || !ProtectiveWards.TryGetRoutedPlayer(sender, num, out var player))
				{
					return;
				}
				ZDOMan instance = ZDOMan.instance;
				ZDO val2 = ((instance != null) ? instance.GetZDO(val) : null);
				if (val2.IsWard() && val2.IsCreator(player.PlayerID) && (sender == 0L || val2.GetOwner() == sender))
				{
					int value = ProtectiveWards.wardBuildLimitPerPlayer.Value;
					int num2 = WardZdoUtils.CountWardsByCreator(player.PlayerID);
					if (num2 > value)
					{
						int current = Math.Max(num2 - 1, 0);
						SendDestroyWardForBuildLimit(val2, current, value);
					}
				}
			}
			finally
			{
				s_requestedWardLimitChecks.Remove(val);
			}
		}

		private static void SendDestroyWardForBuildLimit(ZDO zdo, int current, int limit)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//IL_002a: 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_0095: Expected O, but got Unknown
			if (zdo != null)
			{
				ZDOID uid = zdo.m_uid;
				long owner = zdo.GetOwner();
				DestroyWardForBuildLimitServer(zdo);
				ZPackage val = new ZPackage();
				val.Write(uid);
				val.Write(current);
				val.Write(limit);
				if (owner != 0L && ZRoutedRpc.instance != null)
				{
					ZRoutedRpc.instance.InvokeRoutedRPC(owner, "PW_DestroyWardForBuildLimit", new object[1] { val });
				}
				else if ((Object)(object)Player.m_localPlayer != (Object)null)
				{
					RPC_DestroyWardForBuildLimitClient(0L, new ZPackage(val.GetArray()));
				}
			}
		}

		private static void DestroyWardForBuildLimitServer(ZDO zdo)
		{
			if (zdo != null && ZDOMan.instance != null)
			{
				zdo.SetOwner(ZDOMan.instance.m_sessionID);
				ZDOMan.instance.DestroyZDO(zdo);
			}
		}

		private static void RPC_DestroyWardForBuildLimitClient(long sender, ZPackage package)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			if (ProtectiveWards.IsServerRpcSender(sender))
			{
				ZDOID wardID = package.ReadZDOID();
				int num = package.ReadInt();
				int num2 = package.ReadInt();
				DestroyLocalWard(wardID);
				Player localPlayer = Player.m_localPlayer;
				if (localPlayer != null)
				{
					((Character)localPlayer).Message((MessageType)2, "$pw_ward_limit_reached".Localize(num.ToString(), num2.ToString()), 0, (Sprite)null, false);
				}
			}
		}

		private static void DestroyLocalWard(ZDOID wardID)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)ZNetScene.instance == (Object)null))
			{
				GameObject val = ZNetScene.instance.FindInstance(wardID);
				if ((Object)(object)val != (Object)null)
				{
					ZNetScene.instance.Destroy(val);
				}
			}
		}
	}
	internal static class WardRequestFlow
	{
		private sealed class Pending
		{
			internal string Request;

			internal string Result;

			internal ZDOID Ward;

			internal ZNetPeer Server;

			internal float Deadline;
		}

		private sealed class DispatchContext
		{
			internal long ID;

			internal long Sender;

			internal string Result;

			internal bool Replied;
		}

		[HarmonyPatch(typeof(Player), "Update")]
		private static class Player_Update_RequestTimeouts
		{
			private static void Postfix(Player __instance)
			{
				//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || s_pending.Count == 0)
				{
					return;
				}
				long[] array = (from pair in s_pending.Where(delegate(KeyValuePair<long, Pending> pair)
					{
						ZNetPeer server = pair.Value.Server;
						ZNet instance = ZNet.instance;
						return server != ((instance != null) ? instance.GetServerPeer() : null) || Time.realtimeSinceStartup >= pair.Value.Deadline;
					})
					select pair.Key).ToArray();
				foreach (long key in array)
				{
					if (s_pending.TryGetValue(key, out var value))
					{
						s_pending.Remove(key);
						Recover(value.Ward);
					}
				}
			}
		}

		[HarmonyPatch(typeof(ZoneSystem), "OnDestroy")]
		private static class ZoneSystem_OnDestroy_ClearRequests
		{
			private static void Postfix()
			{
				s_pending.Clear();
				s_dispatch.Clear();
			}
		}

		private static readonly Dictionary<string, string> s_results = new Dictionary<string, string>(StringComparer.Ordinal)
		{
			["PW_ApplyWardSettings"] = "PW_ApplyWardSettingsResult",
			["PW_UpdateWardPassword"] = "PW_UpdateWardPasswordResult",
			["PW_SubmitWardPassword"] = "PW_SubmitWardPasswordResult",
			["PW_UpdateGuildBinding"] = "PW_UpdateGuildBindingResult",
			["PW_UpdatePermittedPlayers"] = "PW_UpdatePermittedPlayersResult",
			["PW_ReactivateExpiredWard"] = "PW_ReactivateExpiredWardResult"
		};

		private static readonly Dictionary<long, Pending> s_pending = new Dictionary<long, Pending>();

		private static readonly Stack<DispatchContext> s_dispatch = new Stack<DispatchContext>();

		internal static bool TrySend(string method, ZPackage payload)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Expected O, but got Unknown
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			if (!s_results.TryGetValue(method, out var value))
			{
				return false;
			}
			int pos = payload.GetPos();
			payload.SetPos(0);
			ZDOID ward = payload.ReadZDOID();
			payload.SetPos(pos);
			Cancel(method, ward);
			if (s_pending.Count < 32)
			{
				ZNet instance = ZNet.instance;
				if (((instance != null) ? instance.GetServerPeer() : null) != null)
				{
					long num = Utils.GenerateUID();
					s_pending[num] = new Pending
					{
						Request = method,
						Result = value,
						Ward = ward,
						Server = ZNet.instance.GetServerPeer(),
						Deadline = Time.realtimeSinceStartup + 20f
					};
					ZPackage val = new ZPackage();
					val.Write(num);
					val.Write(payload);
					ZRoutedRpc.instance.InvokeRoutedRPC(method, new object[1] { val });
					return true;
				}
			}
			Recover(ward);
			return true;
		}

		internal static void Dispatch(string method, long sender, ZPackage envelope, Action<long, ZPackage> handler)
		{
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Expected O, but got Unknown
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			if (s_results.TryGetValue(method, out var value))
			{
				ZNet instance = ZNet.instance;
				if (instance == null || !instance.IsServer())
				{
					return;
				}
				long num = envelope.ReadLong();
				ZPackage val = envelope.ReadPackage();
				if (num == 0L || envelope.GetPos() != envelope.Size() || val.Size() > 65536)
				{
					return;
				}
				DispatchContext dispatchContext = new DispatchContext
				{
					ID = num,
					Sender = sender,
					Result = value
				};
				s_dispatch.Push(dispatchContext);
				try
				{
					handler(sender, val);
					return;
				}
				finally
				{
					s_dispatch.Pop();
					if (!dispatchContext.Replied)
					{
						Reply(dispatchContext, completed: false, new ZPackage());
					}
				}
			}
			if (s_results.ContainsValue(method))
			{
				if (!ProtectiveWards.IsServerRpcSender(sender))
				{
					return;
				}
				long key = envelope.ReadLong();
				bool flag = envelope.ReadBool();
				ZPackage val2 = envelope.ReadPackage();
				if (!s_pending.TryGetValue(key, out var value2) || value2.Result != method)
				{
					return;
				}
				ZNetPeer server = value2.Server;
				ZNet instance2 = ZNet.instance;
				if (server != ((instance2 != null) ? instance2.GetServerPeer() : null))
				{
					return;
				}
				s_pending.Remove(key);
				if (flag && envelope.GetPos() == envelope.Size() && val2.Size() <= 65536)
				{
					try
					{
						handler(sender, val2);
						return;
					}
					catch
					{
						Recover(value2.Ward);
						throw;
					}
				}
				Recover(value2.Ward);
			}
			else
			{
				handler(sender, envelope);
			}
		}

		internal static bool TryReply(long peerID, string method, ZPackage payload)
		{
			if (s_dispatch.Count == 0)
			{
				return false;
			}
			DispatchContext dispatchContext = s_dispatch.Peek();
			if (dispatchContext.Sender != peerID || dispatchContext.Result != method)
			{
				return false;
			}
			if (!dispatchContext.Replied)
			{
				Reply(dispatchContext, completed: true, payload);
			}
			return true;
		}

		private static void Reply(DispatchContext context, bool completed, ZPackage payload)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Expected O, but got Unknown
			context.Replied = true;
			ZPackage val = new ZPackage();
			val.Write(context.ID);
			val.Write(completed);
			val.Write(payload);
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance != null)
			{
				instance.InvokeRoutedRPC(context.Sender, context.Result, new object[1] { val });
			}
		}

		internal static void Cancel(string method, ZDOID ward)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			long[] array = (from pair in s_pending
				where pair.Value.Request == method && pair.Value.Ward == ward
				select pair.Key).ToArray();
			foreach (long key in array)
			{
				s_pending.Remove(key);
			}
		}

		private static void Recover(ZDOID ward)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			WardSettingsUI.CancelPendingNetworkOperation(ward);
			WardPermittedPlayersUI.CancelPendingNetworkOperation(ward);
			WardPasswordProtection.CancelPendingNetworkOperation(ward);
			if (!((ZDOID)(ref ward)).IsNone())
			{
				ZDOMan instance = ZDOMan.instance;
				if (instance != null)
				{
					instance.RequestZDO(ward);
				}
			}
			Player localPlayer = Player.m_localPlayer;
			if (localPlayer != null)
			{
				((Character)localPlayer).Message((MessageType)2, "Ward request outcome is unknown. Its state is being refreshed; reopen the ward before retrying.", 0, (Sprite)null, false);
			}
		}
	}
	internal static class WardControl
	{
		internal enum Operation
		{
			Permit,
			Unpermit,
			Enable,
			Disable,
			Expire,
			Unexpire,
			Toggle,
			ToggleSelfPermit
		}

		private sealed class PendingRequest
		{
			internal Terminal Console;

			internal Operation Action;

			internal float Deadline;
		}

		[HarmonyPatch(typeof(ZoneSystem), "Start")]
		private static class ZoneSystem_Start_RegisterControl
		{
			private static void Postfix()
			{
				WardRpc.Register("PW_WardControlResultV2", HandleResult);
				ZNet instance = ZNet.instance;
				if (instance != null && instance.IsServer())
				{
					WardRpc.Register("PW_WardControlV2", HandleRequest);
				}
			}
		}

		[HarmonyPatch(typeof(Player), "Update")]
		private static class Player_Update_ExpirePendingControl
		{
			private static void Postfix(Player __instance)
			{
				if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && s_pending.Count != 0)
				{
					long[] array = (from entry in s_pending
						where Time.realtimeSinceStartup >= entry.Value.Deadline
						select entry.Key).ToArray();
					foreach (long key in array)
					{
						PendingRequest pendingRequest = s_pending[key];
						s_pending.Remove(key);
						Report(pendingRequest.Console, "No ward response was received. The outcome is unknown; check the ward before retrying.");
					}
				}
			}
		}

		[HarmonyPatch(typeof(ZoneSystem), "OnDestroy")]
		private static class ZoneSystem_OnDestroy_ClearControl
		{
			private static void Postfix()
			{
				s_pending.Clear();
				s_network = null;
			}
		}

		[HarmonyPatch(typeof(PrivateArea), "RPC_ToggleEnabled")]
		private static class PrivateArea_RPC_ToggleEnabled_RejectLegacyMutation
		{
			private static bool Prefix(PrivateArea __instance)
			{
				return !ProtectiveWards.IsPlayerWardPrefab(__instance);
			}
		}

		[HarmonyPatch(typeof(PrivateArea), "RPC_TogglePermitted")]
		private static class PrivateArea_RPC_TogglePermitted_RejectLegacyMutation
		{
			private static bool Prefix(PrivateArea __instance)
			{
				return !ProtectiveWards.IsPlayerWardPrefab(__instance);
			}
		}

		private const string RpcRequest = "PW_WardControlV2";

		private const string RpcResult = "PW_WardControlResultV2";

		private const int Protocol = 1;

		private static readonly Dictionary<long, PendingRequest> s_pending = new Dictionary<long, PendingRequest>();

		private static ZNet s_network;

		internal static void Request(ZDOID wardID, Operation action, string query = "", Terminal console = null)
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Expected O, but got Unknown
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && !((ZDOID)(ref wardID)).IsNone() && !((Object)(object)ZNet.instance == (Object)null) && s_pending.Count < 32)
			{
				if ((Object)(object)s_network != (Object)(object)ZNet.instance)
				{
					s_pending.Clear();
					s_network = ZNet.instance;
				}
				long num = Utils.GenerateUID();
				ZPackage val = new ZPackage();
				val.Write(1);
				val.Write(num);
				val.Write((int)action);
				val.Write(wardID);
				val.Write(localPlayer.GetPlayerID());
				val.Write(query ?? "");
				s_pending[num] = new PendingRequest
				{
					Console = console,
					Action = action,
					Deadline = Time.realtimeSinceStartup + 15f
				};
				if (ZNet.instance.IsServer())
				{
					HandleRequest(0L, new ZPackage(val.GetArray()));
				}
				else
				{
					WardRpc.SendToServer("PW_WardControlV2", val);
				}
			}
		}

		private static void HandleRequest(long sender, ZPackage package)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ba: Unknown result type (might be due to invalid IL or missing references)
			long num = 0L;
			Operation operation = Operation.Toggle;
			string message = "Ward request was rejected.";
			try
			{
				ZNet instance = ZNet.instance;
				if (instance == null || !instance.IsServer() || package.ReadInt() != 1)
				{
					return;
				}
				num = package.ReadLong();
				operation = (Operation)package.ReadInt();
				ZDOID zdoID = package.ReadZDOID();
				long claimedPlayerID = package.ReadLong();
				string text = package.ReadString().Trim();
				if (!Enum.IsDefined(typeof(Operation), operation) || text.Length > 64 || package.GetPos() != package.Size())
				{
					message = "Invalid ward control request.";
					return;
				}
				if (!ProtectiveWards.TryGetRoutedPlayer(sender, claimedPlayerID, out var player))
				{
					message = "The requesting player is not available.";
					return;
				}
				ZDO ward = WardZdoUtils.GetWard(zdoID);
				if (ward == null)
				{
					message = "The ward is no longer available.";
					return;
				}
				bool flag = operation <= Operation.Unexpire;
				if (flag && !ProtectiveWards.wardExternalControlCommandsEnabled.Value)
				{
					message = "Ward control commands are disabled.";
					return;
				}
				float distance = (flag ? ProtectiveWards.wardExternalControlCommandRange.Value : 10f);
				if (!WardRpc.IsWithinReach(player, ward, distance, flag))
				{
					message = "The ward is outside the allowed interaction range.";
					return;
				}
				bool flag2 = ward.IsCreator(player.PlayerID) || ProtectiveWards.HasWardManagementAccess(ward, player.PlayerID);
				if (!ProtectiveWards.HasWardManagementAccess(ward, player.PlayerID) && ProtectiveWards.ShouldBlockInactiveWardAccess(ward, player.PlayerID))
				{
					message = "Another ward blocks access to this inactive ward.";
					return;
				}
				int num2;
				bool flag3;
				bool flag4;
				switch (operation)
				{
				case Operation.Permit:
				case Operation.Unpermit:
					if (!CanManageMembersByCommand(ward, player.PlayerID))
					{
						message = "You do not have access to this ward.";
						return;
					}
					message = ChangeMember(ward, operation, text);
					break;
				case Operation.Toggle:
					num2 = (ProtectiveWards.CanPermittedPlayersToggleWard(ward, player.PlayerID) ? 1 : 0);
					goto IL_0226;
				case Operation.Enable:
				case Operation.Disable:
					num2 = 0;
					goto IL_0226;
				case Operation.Expire:
				case Operation.Unexpire:
					if (!ProtectiveWards.HasWardAdminAccess(player.PlayerID))
					{
						message = "You are not allowed to change ward expiration.";
						return;
					}
					WardExpiration.SetExpired(ward, operation == Operation.Expire, player.PlayerID, player.PlayerName);
					message = ((operation == Operation.Expire) ? "Ward marked expired." : "Ward expiration cleared.");
					break;
				case Operation.ToggleSelfPermit:
					{
						if (ward.GetBool(ZDOVars.s_enabled, false) || (WardPasswordProtection.IsPasswordProtectionActive(ward) && !WardZdoUtils.HasDirectAccessToWardZdo(ward, player.PlayerID)))
						{
							message = "You cannot change your permission on this ward.";
							return;
						}
						if (WardZdoUtils.IsExplicitlyPermitted(ward, player.PlayerID))
						{
							WardZdoUtils.RemovePermitted(ward, player.PlayerID, out var _);
							message = "You were removed from the ward's permitted list.";
						}
						else
						{
							WardZdoUtils.AddPermitted(ward, player.PlayerID, player.PlayerName);
							message = "You were added to the ward's permitted list.";
						}
						break;
					}
					IL_0226:
					flag3 = (byte)num2 != 0;
					if (!flag2 && !flag3)
					{
						message = "You are not allowed to toggle this ward.";
						return;
					}
					flag4 = ((operation == Operation.Toggle) ? (!ward.GetBool(ZDOVars.s_enabled, false)) : (operation == Operation.Enable));
					if (ward.GetBool(ZDOVars.s_enabled, false) == flag4)
					{
						message = (flag4 ? "Ward is already enabled." : "Ward is already disabled.");
						return;
					}
					SetEnabled(ward, flag4);
					if (flag4 && flag2)
					{
						ProtectiveWards.ActivateConnectedWardZdos(ward, player.PlayerID, player.PlayerName);
					}
					message = (flag4 ? "Ward enabled." : "Ward disabled.");
					break;
				}
				WardZdoUtils.UpdateWardRuntimeFields(ward);
				PrivateArea val = WardZdoUtils.FindLoadedWard(zdoID);
				if ((Object)(object)val != (Object)null)
				{
					ProtectiveWards.RefreshWardVisuals(val);
				}
			}
			catch (Exception ex)
			{
				message = "The ward request could not be completed. Refresh its state before retrying.";
				Debug.LogWarning((object)("[ProtectiveWards] Ward control failed: " + ex.GetType().Name + "."));
			}
			finally
			{
				if (num != 0)
				{
					SendResult(sender, num, operation, message);
				}
			}
		}

		private static bool CanManageMembersByCommand(ZDO ward, long playerID)
		{
			return WardZdoUtils.HasDirectAccessToWardZdo(ward, playerID) || (WardExpiration.IsWardActive(ward) && ward.HasConnectedWardAccess(playerID, ProtectiveWards.wardAccessConnectedAccessMode.Value, WardExpiration.IsWardActive));
		}

		private static string ChangeMember(ZDO ward, Operation action, string query)
		{
			if (query.Length == 0)
			{
				return "Specify a player name.";
			}
			List<KeyValuePair<long, string>> list;
			if (action == Operation.Permit)
			{
				list = WardPlayers.FindByName(query);
			}
			else
			{
				List<KeyValuePair<long, string>> permittedPlayers = WardZdoUtils.GetPermittedPlayers(ward);
				list = permittedPlayers.Where((KeyValuePair<long, string> p) => string.Equals(p.Value, query, StringComparison.OrdinalIgnoreCase)).ToList();
				if (list.Count == 0)
				{
					list = permittedPlayers.Where((KeyValuePair<long, string> p) => p.Value.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0).ToList();
				}
			}
			if (list.Count == 0)
			{
				return "No matching player was found.";
			}
			if (list.Count != 1)
			{
				return "More than one player matches. Use the exact name.";
			}
			KeyValuePair<long, string> keyValuePair = list[0];
			if (action == Operation.Permit)
			{
				if (WardZdoUtils.IsExplicitlyPermitted(ward, keyValuePair.Key))
				{
					return "The player is already permitted.";
				}
				WardZdoUtils.AddPermitted(ward, keyValuePair.Key, keyValuePair.Value);
				return "Added " + keyValuePair.Value + " to the ward's permitted list.";
			}
			WardZdoUtils.RemovePermitted(ward, keyValuePair.Key, out var _);
			return "Removed " + keyValuePair.Value + " from the ward's permitted list.";
		}

		private static void SetEnabled(ZDO ward, bool enabled)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			PrivateArea val = WardZdoUtils.FindLoadedWard(ward.m_uid);
			if ((Object)(object)val != (Object)null)
			{
				val.SetEnabled(enabled);
			}
			else
			{
				ward.Set(ZDOVars.s_enabled, enabled);
			}
		}

		private static void SendResult(long peerID, long requestID, Operation action, string message)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			val.Write(requestID);
			val.Write((int)action);
			val.Write(message);
			if (peerID == 0)
			{
				HandleResult(0L, new ZPackage(val.GetArray()));
				return;
			}
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance != null)
			{
				instance.InvokeRoutedRPC(peerID, "PW_WardControlResultV2", new object[1] { val });
			}
		}

		private static void HandleResult(long sender, ZPackage package)
		{
			if (ProtectiveWards.IsServerRpcSender(sender) && !((Object)(object)s_network != (Object)(object)ZNet.instance))
			{
				long key = package.ReadLong();
				Operation operation = (Operation)package.ReadInt();
				string text = package.ReadString();
				if (text.Length <= 1024 && package.GetPos() == package.Size() && s_pending.TryGetValue(key, out var value) && value.Action == operation)
				{
					s_pending.Remove(key);
					Report(value.Console, text);
				}
			}
		}

		private static void Report(Terminal console, string message)
		{
			if ((Object)(object)console != (Object)null)
			{
				console.AddString(message);
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if (localPlayer != null)
			{
				((Character)localPlayer).Message((MessageType)2, message, 0, (Sprite)null, false);
			}
		}
	}
	internal static class WardPlayers
	{
		internal readonly struct OnlinePlayer
		{
			internal readonly long PlayerID;

			internal readonly ZDOID CharacterID;

			internal readonly string Name;

			internal readonly bool AdminAccess;

			internal OnlinePlayer(long playerID, ZDOID characterID, string name, bool adminAccess = false)
			{
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				PlayerID = playerID;
				CharacterID = characterID;
				Name = name ?? "";
				AdminAccess = adminAccess;
			}
		}

		[HarmonyPatch(typeof(ZoneSystem), "Start")]
		private static class ZoneSystem_Start_RegisterRoster
		{
			private static void Postfix()
			{
				if (ZRoutedRpc.instance != null)
				{
					WardRpc.Register("PW_OnlinePlayerRoster", Receive);
					s_registered = true;
					Publish();
				}
			}
		}

		[HarmonyPatch(typeof(ZNet), "SendPlayerList")]
		private static class ZNet_SendPlayerList_PublishRoster
		{
			private static void Postfix()
			{
				Publish();
			}
		}

		[HarmonyPatch(typeof(ZoneSystem), "OnDestroy")]
		private static class ZoneSystem_OnDestroy_ClearRoster
		{
			private static void Postfix()
			{
				s_registered = false;
				s_remotePlayers.Clear();
			}
		}

		private const string RpcRoster = "PW_OnlinePlayerRoster";

		private const int MaximumPlayers = 512;

		private static readonly List<OnlinePlayer> s_remotePlayers = new List<OnlinePlayer>();

		private static bool s_registered;

		internal static IEnumerable<OnlinePlayer> GetOnlinePlayers()
		{
			ZNet network = ZNet.instance;
			if ((Object)(object)network == (Object)null)
			{
				yield break;
			}
			Player local = Player.m_localPlayer;
			long localID = ((local != null) ? local.GetPlayerID() : 0);
			if (localID != 0)
			{
				yield return new OnlinePlayer(localID, ((Character)local).GetZDOID(), local.GetPlayerName());
			}
			if (!network.IsServer())
			{
				foreach (OnlinePlayer player in s_remotePlayers)
				{
					if (player.PlayerID != localID)
					{
						yield return player;
					}
				}
				yield break;
			}
			foreach (ZNetPeer peer in network.GetPeers())
			{
				if (peer == null || !peer.IsReady() || peer.m_server || ((ZDOID)(ref peer.m_characterID)).IsNone())
				{
					continue;
				}
				long playerID = peer.m_playerID;
				if (playerID == 0)
				{
					ZDOMan instance = ZDOMan.instance;
					long? obj;
					if (instance == null)
					{
						obj = null;
					}
					else
					{
						ZDO zDO = instance.GetZDO(peer.m_characterID);
						obj = ((zDO != null) ? new long?(zDO.GetLong(ZDOVars.s_playerID, 0L)) : ((long?)null));
					}
					long? num = obj;
					playerID = num.GetValueOrDefault();
				}
				if (playerID != 0L && playerID != localID)
				{
					yield return new OnlinePlayer(playerID, peer.m_characterID, peer.m_playerName);
				}
			}
		}

		internal static List<KeyValuePair<long, string>> FindByName(string query)
		{
			string normalized = (query ?? "").Trim();
			if (normalized.Length == 0 || normalized.Length > 64)
			{
				return new List<KeyValuePair<long, string>>();
			}
			List<KeyValuePair<long, string>> source = (from player in GetOnlinePlayers()
				group player by player.PlayerID into @group
				select new KeyValuePair<long, string>(@group.Key, @group.First().Name)).ToList();
			List<KeyValuePair<long, string>> list = source.Where((KeyValuePair<long, string> player) => string.Equals(player.Value, normalized, StringComparison.OrdinalIgnoreCase)).ToList();
			return (list.Count > 0) ? list : source.Where((KeyValuePair<long, string> player) => player.Value.IndexOf(normalized, StringComparison.OrdinalIgnoreCase) >= 0).ToList();
		}

		internal static bool TryGet(long playerID, out OnlinePlayer result)
		{
			foreach (OnlinePlayer onlinePlayer in GetOnlinePlayers())
			{
				if (onlinePlayer.PlayerID != playerID)
				{
					continue;
				}
				result = onlinePlayer;
				return true;
			}
			result = default(OnlinePlayer);
			return false;
		}

		internal static bool HasRemoteAdminAccess(long playerID)
		{
			if ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer())
			{
				return false;
			}
			foreach (OnlinePlayer s_remotePlayer in s_remotePlayers)
			{
				if (s_remotePlayer.PlayerID == playerID)
				{
					return s_remotePlayer.AdminAccess;
				}
			}
			return false;
		}

		private static void Publish()
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Expected O, but got Unknown
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			if (!s_registered)
			{
				return;
			}
			ZNet instance = ZNet.instance;
			if (instance == null || !instance.IsServer())
			{
				return;
			}
			List<OnlinePlayer> list = (from player in GetOnlinePlayers()
				group player by player.PlayerID into @group
				select @group.First()).Take(512).ToList();
			ZPackage val = new ZPackage();
			val.Write(list.Count);
			foreach (OnlinePlayer item in list)
			{
				val.Write(item.PlayerID);
				val.Write(item.CharacterID);
				val.Write((item.Name.Length > 64) ? item.Name.Substring(0, 64) : item.Name);
				val.Write(ProtectiveWards.HasWardAdminAccess(item.PlayerID));
			}
			foreach (ZNetPeer peer in ZNet.instance.GetPeers())
			{
				if (peer != null && peer.IsReady() && !peer.m_server)
				{
					ZRoutedRpc.instance.InvokeRoutedRPC(peer.m_uid, "PW_OnlinePlayerRoster", new object[1] { val });
				}
			}
		}

		private static void Receive(long sender, ZPackage package)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			if (!ProtectiveWards.IsServerRpcSender(sender))
			{
				return;
			}
			ZNet instance = ZNet.instance;
			if (instance == null || instance.IsServer())
			{
				return;
			}
			int num = package.ReadInt();
			if (num < 0 || num > 512)
			{
				return;
			}
			List<OnlinePlayer> list = new List<OnlinePlayer>(num);
			HashSet<long> hashSet = new HashSet<long>();
			for (int i = 0; i < num; i++)
			{
				long num2 = package.ReadLong();
				ZDOID characterID = package.ReadZDOID();
				string text = package.ReadString();
				bool adminAccess = package.ReadBool();
				if (num2 == 0L || ((ZDOID)(ref characterID)).IsNone() || text.Length > 64 || !hashSet.Add(num2))
				{
					return;
				}
				list.Add(new OnlinePlayer(num2, characterID, text, adminAccess));
			}
			if (package.GetPos() == package.Size())
			{
				s_remotePlayers.Clear();
				s_remotePlayers.AddRange(list);
			}
		}
	}
	internal static class WardRpc
	{
		[HarmonyPatch(typeof(ZNet), "SendServerSyncPlayerData")]
		private static class ZNet_SendServerSyncPlayerData_AdminMode
		{
			private static void Prefix(ZNet __instance)
			{
				if (!__instance.IsServer())
				{
					Dictionary<string, string> serverSyncedPlayerData = __instance.m_serverSyncedPlayerData;
					Player localPlayer = Player.m_localPlayer;
					serverSyncedPlayerData["pw_admin_god_mode"] = ((localPlayer != null && ((Character)localPlayer).InGodMode()) ? "1" : "0");
				}
			}
		}

		[HarmonyPatch(typeof(Player), "SetGodMode")]
		private static class Player_SetGodMode_SynchronizeAdminMode
		{
			private static void Postfix(Player __instance)
			{
				if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer)
				{
					SyncLocalAdminMode();
				}
			}
		}

		[HarmonyPatch(typeof(ZRoutedRpc), "RPC_RoutedRPC")]
		private static class ZRoutedRpc_RPC_RoutedRPC_ValidateWardSender
		{
			[HarmonyPriority(800)]
			private static bool Prefix(ZRpc rpc, ZPackage pkg)
			{
				//IL_003b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0040: Unknown result type (might be due to invalid IL or missing references)
				//IL_0068: Unknown result type (might be due to invalid IL or missing references)
				if (pkg == null || (Object)(object)ZNet.instance == (Object)null)
				{
					return true;
				}
				int pos = pkg.GetPos();
				try
				{
					pkg.ReadLong();
					long num = pkg.ReadLong();
					pkg.ReadLong();
					ZDOID val = pkg.ReadZDOID();
					int num2 = pkg.ReadInt();
					int num3;
					if (num2 == s_toggleEnabled || num2 == s_togglePermitted)
					{
						ZDOMan instance = ZDOMan.instance;
						num3 = (WardZdoUtils.IsWard((instance != null) ? instance.GetZDO(val) : null) ? 1 : 0);
					}
					else
					{
						num3 = 0;
					}
					bool flag = (byte)num3 != 0;
					if (!s_methods.Contains(num2) && !flag)
					{
						return true;
					}
					ZNet instance2 = ZNet.instance;
					ZNetPeer peer = instance2.GetPeer(rpc);
					bool flag2 = ((!instance2.IsServer()) ? (instance2.GetServerPeer()?.m_rpc == rpc) : (peer != null && peer.IsReady() && num == peer.m_uid));
					if (!flag2)
					{
						WarnRejected("sender identity");
					}
					return flag2;
				}
				catch (EndOfStreamException)
				{
					WarnRejected("truncated header");
					return false;
				}
				finally
				{
					pkg.SetPos(pos);
				}
			}
		}

		private const string AdminGodModeKey = "pw_admin_god_mode";

		private const int MaximumPackageBytes = 262144;

		private static readonly HashSet<int> s_methods = new HashSet<int>
		{
			StringExtensionMethods.GetStableHashCode("PW_GrowPlant"),
			StringExtensionMethods.GetStableHashCode("PW_AugmentStructure")
		};

		private static readonly HashSet<int> s_registered = new HashSet<int>();

		private static readonly int s_toggleEnabled = StringExtensionMethods.GetStableHashCode("ToggleEnabled");

		private static readonly int s_togglePermitted = StringExtensionMethods.GetStableHashCode("TogglePermitted");

		private static ZRoutedRpc s_router;

		private static ZNetPeer s_adminPeer;

		private static float s_nextWarning;

		internal static void Register(string name, Action<long, ZPackage> handler)
		{
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance == null || handler == null)
			{
				return;
			}
			if (s_router != instance)
			{
				s_router = instance;
				s_registered.Clear();
				s_adminPeer = null;
			}
			int stableHashCode = StringExtensionMethods.GetStableHashCode(name);
			s_methods.Add(stableHashCode);
			if (!s_registered.Add(stableHashCode))
			{
				return;
			}
			instance.Register<ZPackage>(name, (Action<long, ZPackage>)delegate(long sender, ZPackage package)
			{
				if (package == null || package.Size() > 262144)
				{
					WarnRejected(name);
					return;
				}
				try
				{
					WardRequestFlow.Dispatch(name, sender, package, handler);
				}
				catch (Exception ex)
				{
					Debug.LogWarning((object)("[ProtectiveWards] Request " + name + " failed: " + ex.GetType().Name + "."));
				}
			});
		}

		internal static void SendToServer(string name, ZPackage package)
		{
			SyncLocalAdminMode();
			if (!WardRequestFlow.TrySend(name, package))
			{
				ZRoutedRpc instance = ZRoutedRpc.instance;
				if (instance != null)
				{
					instance.InvokeRoutedRPC(name, new object[1] { package });
				}
			}
		}

		internal static void SendResponse(long peerID, string name, ZPackage package)
		{
			if (!WardRequestFlow.TryReply(peerID, name, package))
			{
				ZRoutedRpc instance = ZRoutedRpc.instance;
				if (instance != null)
				{
					instance.InvokeRoutedRPC(peerID, name, new object[1] { package });
				}
			}
		}

		internal static bool HasRemoteGodMode(long playerID)
		{
			ZNet instance = ZNet.instance;
			if ((Object)(object)instance == (Object)null || !instance.IsServer() || playerID == 0)
			{
				return false;
			}
			foreach (ZNetPeer peer in instance.GetPeers())
			{
				if (peer == null || !peer.IsReady() || peer.m_playerID != playerID)
				{
					continue;
				}
				string value;
				return peer.m_serverSyncedPlayerData.TryGetValue("pw_admin_god_mode", out value) && value == "1";
			}
			return false;
		}

		internal static void SyncLocalAdminMode()
		{
			ZNet instance = ZNet.instance;
			if ((Object)(object)instance == (Object)null || instance.IsServer())
			{
				return;
			}
			ZNetPeer serverPeer = instance.GetServerPeer();
			if (serverPeer != null && serverPeer.IsReady())
			{
				Player localPlayer = Player.m_localPlayer;
				string text = ((localPlayer != null && ((Character)localPlayer).InGodMode()) ? "1" : "0");
				if (s_adminPeer != serverPeer || !instance.m_serverSyncedPlayerData.TryGetValue("pw_admin_god_mode", out var value) || !(value == text))
				{
					s_adminPeer = serverPeer;
					instance.m_serverSyncedPlayerData["pw_admin_god_mode"] = text;
					instance.SendServerSyncPlayerData(serverPeer);
				}
			}
		}

		internal static bool IsWithinReach(ProtectiveWards.RoutedPlayerContext player, ZDO target, float distance = 10f, bool horizontal = false)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			if (target == null || !player.HasPosition || distance < 0f || float.IsNaN(distance) || float.IsInfinity(distance))
			{
				return false;
			}
			Vector3 val = player.Position - target.GetPosition();
			if (horizontal)
			{
				val.y = 0f;
			}
			return ((Vector3)(ref val)).sqrMagnitude <= distance * distance;
		}

		private static void WarnRejected(string method)
		{
			if (!(Time.realtimeSinceStartup < s_nextWarning))
			{
				s_nextWarning = Time.realtimeSinceStartup + 5f;
				Debug.LogWarning((object)("[ProtectiveWards] Rejected invalid ward RPC (" + method + ")."));
			}
		}
	}
	internal static class ItemNameTokens
	{
		[HarmonyPatch(typeof(ObjectDB), "Awake")]
		private static class ObjectDB_Awake_UpdateItemNameTokens
		{
			private static void Postfix()
			{
				UpdateRegisters();
			}
		}

		[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
		private static class ObjectDB_CopyOtherDB_UpdateItemNameTokens
		{
			private static void Postfix()
			{
				UpdateRegisters();
			}
		}

		[HarmonyPatch(typeof(Player), "Load")]
		private static class Player_Load_UpdateItemNameTokens
		{
			private static void Prefix()
			{
				UpdateRegisters();
			}
		}

		private static readonly Dictionary<string, string> s_itemNames = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

		internal static void UpdateRegisters()
		{
			if (!Object.op_Implicit((Object)(object)ObjectDB.instance))
			{
				return;
			}
			s_itemNames.Clear();
			foreach (GameObject item in ObjectDB.instance.m_items)
			{
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				ItemDrop component = item.GetComponent<ItemDrop>();
				if (component != null)
				{
					SharedData val = component.m_itemData?.m_shared;
					if (val != null && !string.IsNullOrWhiteSpace(val.m_name) && val.m_name.StartsWith("$"))
					{
						Register(((Object)item).name, val.m_name);
						Register(val.m_name, val.m_name);
						Localization instance = Localization.instance;
						Register((instance != null) ? instance.Localize(val.m_name) : null, val.m_name);
					}
				}
			}
		}

		internal static string GetItemName(this string input)
		{
			if (string.IsNullOrWhiteSpace(input))
			{
				return "";
			}
			string text = input.Trim();
			string value;
			return s_itemNames.TryGetValue(text, out value) ? value : text;
		}

		private static void Register(string key, string token)
		{
			if (!string.IsNullOrWhiteSpace(key))
			{
				s_itemNames[key.Trim()] = token;
			}
		}
	}
	public static class StringExtensions
	{
		public static string Localize(this string text)
		{
			return (Localization.instance != null) ? Localization.instance.Localize(text) : text;
		}

		public static string Localize(this string text, params string[] words)
		{
			return (Localization.instance != null) ? Localization.instance.Localize(text, words) : text;
		}
	}
	internal static class ComponentExtensions
	{
		internal static bool IsVehicle(this Component component)
		{
			return (Object)(object)component != (Object)null && ((Object)(object)component.GetComponentInParent<Ship>() != (Object)null || (Object)(object)component.GetComponentInParent<Vagon>() != (Object)null);
		}

		internal static ZNetView GetComponentZNetView(this Component component)
		{
			if ((Object)(object)component == (Object)null)
			{
				return null;
			}
			PrivateArea val = (PrivateArea)(object)((component is PrivateArea) ? component : null);
			if (val != null)
			{
				return val.m_nview;
			}
			Ship val2 = (Ship)(object)((component is Ship) ? component : null);
			if (val2 != null)
			{
				return val2.m_nview;
			}
			ShipControlls val3 = (ShipControlls)(object)((component is ShipControlls) ? component : null);
			if (val3 != null)
			{
				return val3.m_nview;
			}
			Vagon val4 = (Vagon)(object)((component is Vagon) ? component : null);
			if (val4 != null)
			{
				return val4.m_nview;
			}
			Catapult val5 = (Catapult)(object)((component is Catapult) ? component : null);
			if (val5 != null)
			{
				return val5.m_nview;
			}
			MapTable val6 = (MapTable)(object)((component is MapTable) ? component : null);
			if (val6 != null)
			{
				return val6.m_nview;
			}
			Turret val7 = (Turret)(object)((component is Turret) ? component : null);
			if (val7 != null)
			{
				return val7.m_nview;
			}
			Fireplace val8 = (Fireplace)(object)((component is Fireplace) ? component : null);
			if (val8 != null)
			{
				return val8.m_nview;
			}
			Tameable val9 = (Tameable)(object)((component is Tameable) ? component : null);
			if (val9 != null)
			{
				return val9.m_nview;
			}
			Sadle val10 = (Sadle)(object)((component is Sadle) ? component : null);
			if (val10 != null)
			{
				return val10.m_nview;
			}
			TeleportWorld val11 = (TeleportWorld)(object)((component is TeleportWorld) ? component : null);
			if (val11 != null)
			{
				return val11.m_nview;
			}
			return component.GetComponent<ZNetView>() ?? component.GetComponentInParent<ZNetView>();
		}

		internal static ZDO GetWardZDO(this Component component)
		{
			ZNetView componentZNetView = component.GetComponentZNetView();
			return ((Object)(object)componentZNetView != (Object)null && componentZNetView.IsValid()) ? componentZNetView.GetZDO() : null;
		}
	}
	internal static class UIExtensions
	{
		internal static void KeepClickSfxOnly(this GameObject button)
		{
			ButtonSfx val = default(ButtonSfx);
			if ((Object)(object)button != (Object)null && button.TryGetComponent<ButtonSfx>(ref val))
			{
				val.m_selectSfxPrefab = null;
				val.m_selectSfxPrefabVibrationOnly = null;
			}
		}
	}
	internal static class PrivateAreaExtensions
	{
		internal static ZDO GetWardZDO(this PrivateArea ward)
		{
			ZNetView componentZNetView = ((Component)(object)ward).GetComponentZNetView();
			return ((Object)(object)componentZNetView != (Object)null && componentZNetView.IsValid()) ? componentZNetView.GetZDO() : null;
		}

		internal static bool HasDirectWardAccess(this PrivateArea ward, long playerID)
		{
			return ProtectiveWards.HasDirectAccessToWard(ward, playerID);
		}

		internal static bool HasConnectedWardAccess(this PrivateArea ward, long playerID, ProtectiveWards.WardConnectedAccessMode mode)
		{
			return ProtectiveWards.HasAccessToWardOrConnectedWard(ward, playerID, mode);
		}
	}
	internal static class WardZdoExtensions
	{
		internal static bool IsWard(this ZDO zdo)
		{
			return WardZdoUtils.IsWard(zdo);
		}

		internal static long GetCreatorId(this ZDO zdo)
		{
			return (zdo != null) ? zdo.GetLong(ZDOVars.s_creator, 0L) : 0;
		}

		internal static bool IsCreator(this ZDO zdo, long creatorID)
		{
			return zdo.GetCreatorId() == creatorID;
		}

		internal static bool HasDirectWardAccess(this ZDO zdo, long playerID)
		{
			return WardZdoUtils.HasDirectAccessToWardZdo(zdo, playerID);
		}

		internal static bool HasConnectedWardAccess(this ZDO zdo, long playerID, ProtectiveWards.WardConnectedAccessMode mode, Func<ZDO, bool> isActiveCandidate)
		{
			return WardZdoUtils.HasAccessToWardOrConnectedWardZdo(zdo, playerID, mode, isActiveCandidate);
		}

		internal static float GetWardRadius(this ZDO zdo)
		{
			return WardZdoUtils.GetWardRadius(zdo);
		}

		internal static bool IsWardPermitted(this ZDO zdo, long playerID)
		{
			return WardZdoUtils.IsPermitted(zdo, playerID);
		}
	}
	internal static class WardZdoUtils
	{
		private sealed class WardTraversal
		{
			internal readonly HashSet<ZDOID> Visited = new HashSet<ZDOID>();

			internal readonly List<ZDO> Queue = new List<ZDO>();

			internal readonly List<ZDO> Candidates = new List<ZDO>();
		}

		[HarmonyPatch]
		private static class ZDOMan_Load_WardListInit
		{
			private static IEnumerable<MethodBase> TargetMethods()
			{
				yield return AccessTools.Method(typeof(ZDOMan), "Load", (Type[])null, (Type[])null);
				yield return AccessTools.Method(typeof(ZDOMan), "LoadChunks", (Type[])null, (Type[])null);
			}

			private static void Postfix(ZDOMan __instance)
			{
				RebuildWardObjects(__instance);
			}
		}

		[HarmonyPatch(typeof(ZoneSystem), "Start")]
		private static class ZoneSystem_Start_WardListInit
		{
			private static void Postfix()
			{
				EnsureWardObjectsInitialized();
				UpdateAllWardRuntimeFields();
			}
		}

		[HarmonyPatch(typeof(ZDOMan), "CreateNewZDO", new Type[]
		{
			typeof(ZDOID),
			typeof(Vector3),
			typeof(int)
		})]
		private static class ZDOMan_CreateNewZDO_WardListAddNew
		{
			private static void Postfix(int prefabHashIn, ZDO __result)
			{
				if (ShouldTrackServerWards() && (prefabHashIn == 0 || prefabHashIn == s_wardPrefabHash))
				{
					AddIfWard(__result);
				}
			}
		}

		[HarmonyPatch(typeof(ZDOMan), "HandleDestroyedZDO")]
		private static class ZDOMan_HandleDestroyedZDO_WardListRemove
		{
			private static void Prefix(ZDOMan __instance, ZDOID uid)
			{
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				if (__instance != null)
				{
					RemoveIfWard(__instance.GetZDO(uid));
				}
			}
		}

		[HarmonyPatch(typeof(ZDO), "SetPrefab")]
		private static class ZDO_SetPrefab_WardListUpdate
		{
			private static void Postfix(ZDO __instance)
			{
				if (ShouldTrackServerWards())
				{
					if (IsWard(__instance))
					{
						s_wardObjects.Add(__instance);
						EnsureWardSettingsInitialized(__instance);
					}
					else
					{
						s_wardObjects.Remove(__instance);
					}
				}
			}
		}

		[HarmonyPatch(typeof(ZDO), "Deserialize")]
		private static class ZDO_Deserialize_WardListAdd
		{
			private static void Postfix(ZDO __instance)
			{
				AddIfWard(__instance);
				ProtectiveWards.NotifyWardZdoSynchronized(__instance);
			}
		}

		[HarmonyPatch(typeof(ZoneSystem), "OnDestroy")]
		private static class ZoneSystem_OnDestroy_WardListClear
		{
			private static void Postfix()
			{
				s_wardObjects.Clear();
				s_wardObjectsInitialized = false;
				s_wardDefaultRadius = 32f;
				s_wardDefaultRadiusCached = false;
			}
		}

		[CompilerGenerated]
		private sealed class <ConnectedAccessWardZdos>d__46 : IEnumerable<ZDO>, IEnumerable, IEnumerator<ZDO>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private ZDO <>2__current;

			private int <>l__initialThreadId;

			private ZDO rootWard;

			public ZDO <>3__rootWard;

			private ProtectiveWards.WardConnectedAccessMode mode;

			public ProtectiveWards.WardConnectedAccessMode <>3__mode;

			private Func<ZDO, bool> isActiveCandidate;

			public Func<ZDO, bool> <>3__isActiveCandidate;

			private WardTraversal <traversal>5__1;

			private int <queueIndex>5__2;

			private IEnumerator<ZDO> <>s__3;

			private ZDO <candidate>5__4;

			private ZDO <current>5__5;

			private List<ZDO>.Enumerator <>s__6;

			private ZDO <candidate>5__7;

			private bool <retain>5__8;

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

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

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

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 2)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<traversal>5__1 = null;
				<>s__3 = null;
				<candidate>5__4 = null;
				<current>5__5 = null;
				<>s__6 = default(List<ZDO>.Enumerator);
				<candidate>5__7 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
				//IL_0202: Unknown result type (might be due to invalid IL or missing references)
				//IL_0290: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						if (!IsWard(rootWard))
						{
							return false;
						}
						<>2__current = rootWard;
						<>1__state = 1;
						return true;
					case 1:
						<>1__state = -1;
						if (mode == ProtectiveWards.WardConnectedAccessMode.Off)
						{
							return false;
						}
						<traversal>5__1 = ((s_traversalPool.Count > 0) ? s_traversalPool.Pop() : new WardTraversal());
						<>1__state = -3;
						<traversal>5__1.Visited.Add(rootWard.m_uid);
						<traversal>5__1.Queue.Add(rootWard);
						<>s__3 = GetAllWards().GetEnumerator();
						try
						{
							while (<>s__3.MoveNext())
							{
								<candidate>5__4 = <>s__3.Current;
								<traversal>5__1.Candidates.Add(<candidate>5__4);
								<candidate>5__4 = null;
							}
						}
						finally
						{
							if (<>s__3 != null)
							{
								<>s__3.Dispose();
							}
						}
						<>s__3 = null;
						<queueIndex>5__2 = 0;
						goto IL_02f3;
					case 2:
						{
							<>1__state = -3;
							goto IL_01b6;
						}
						IL_02f3:
						if (<queueIndex>5__2 < <traversal>5__1.Queue.Count)
						{
							<current>5__5 = <traversal>5__1.Queue[<queueIndex>5__2++];
							if (<queueIndex>5__2 > 1)
							{
								<>2__current = <current>5__5;
								<>1__state = 2;
								return true;
							}
							goto IL_01b6;
						}
						<>m__Finally1();
						return false;
						IL_01b6:
						<>s__6 = <traversal>5__1.Candidates.GetEnumerator();
						try
						{
							while (<>s__6.MoveNext())
							{
								<candidate>5__7 = <>s__6.Current;
								if (IsWard(<candidate>5__7) && !<traversal>5__1.Visited.Contains(<candidate>5__7.m_uid) && (isActiveCandidate == null || isActiveCandidate(<candidate>5__7)) && AreWardZdosOverlapping(<current>5__5, <candidate>5__7) && CanShareConnectedWardAccess(rootWard, <candidate>5__7, mode))
								{
									<traversal>5__1.Visited.Add(<candidate>5__7.m_uid);
									<traversal>5__1.Queue.Add(<candidate>5__7);
									<candidate>5__7 = null;
								}
							}
						}
						finally
						{
							((IDisposable)<>s__6/*cast due to .constrained prefix*/).Dispose();
						}
						<>s__6 = default(List<ZDO>.Enumerator);
						<current>5__5 = null;
						goto IL_02f3;
					}
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

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

			private void <>m__Finally1()
			{
				<>1__state = -1;
				<retain>5__8 = <traversal>5__1.Candidates.Count <= 4096 && <traversal>5__1.Queue.Count <= 4096;
				<traversal>5__1.Visited.Clear();
				<traversal>5__1.Queue.Clear();
				<traversal>5__1.Candidates.Clear();
				if (<retain>5__8 && s_traversalPool.Count < 4)
				{
					s_traversalPool.Push(<traversal>5__1);
				}
			}

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

			[DebuggerHidden]
			IEnumerator<ZDO> IEnumerable<ZDO>.GetEnumerator()
			{
				<ConnectedAccessWardZdos>d__46 <ConnectedAccessWardZdos>d__;
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					<ConnectedAccessWardZdos>d__ = this;
				}
				else
				{
					<ConnectedAccessWardZdos>d__ = new <ConnectedAccessWardZdos>d__46(0);
				}
				<ConnectedAccessWardZdos>d__.rootWard = <>3__rootWard;
				<ConnectedAccessWardZdos>d__.mode = <>3__mode;
				<ConnectedAccessWardZdos>d__.isActiveCandidate = <>3__isActiveCandidate;
				return <ConnectedAccessWardZdos>d__;
			}

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

		internal const string WardPrefabName = "guard_stone";

		internal static readonly int s_wardPrefabHash = StringExtensionMethods.GetStableHashCode("guard_stone");

		private static readonly HashSet<ZDO> s_wardObjects = new HashSet<ZDO>();

		private static bool s_wardObjectsInitialized;

		private static bool s_wardDefaultRadiusCached;

		private static float s_wardDefaultRadius = 32f;

		private const int MaximumPooledBuffers = 4;

		private const int MaximumRetainedEntries = 4096;

		private static readonly Stack<HashSet<ZDOID>> s_visitedPool = new Stack<HashSet<ZDOID>>();

		private static readonly Stack<WardTraversal> s_traversalPool = new Stack<WardTraversal>();

		private static readonly int[] s_permittedPlayerIdHashes = CreatePermittedPlayerIdHashes();

		private const string HasFieldsKey = "HasFields";

		private const string HasPrivateAreaFieldsKey = "HasFieldsPrivateArea";

		internal const string PrivateAreaRadiusField = "PrivateArea.m_radius";

		private const string PrivateAreaFlashAvailableField = "PrivateArea.m_flashAvailable";

		private static int[] CreatePermittedPlayerIdHashes()
		{
			int[] array = new int[64];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = StringExtensionMethods.GetStableHashCode("pu_id" + i);
			}
			return array;
		}

		internal static bool IsWardPrefab(GameObject gameObject)
		{
			return (Object)(object)gameObject != (Object)null && Utils.GetPrefabName(gameObject) == "guard_stone";
		}

		internal static bool IsWard(ZDO zdo)
		{
			return zdo != null && zdo.GetPrefab() == s_wardPrefabHash;
		}

		internal static bool HasStoredWardSettings(ZDO zdo)
		{
			return IsWard(zdo) && zdo.GetInt(ProtectiveWards.s_wardSettingsVersion, 0) >= 1;
		}

		private static bool CanWriteWardZdo(ZDO zdo)
		{
			int result;
			if (IsWard(zdo))
			{
				ZNet instance = ZNet.instance;
				result = ((instance != null && instance.IsServer()) ? 1 : 0);
			}
			else
			{
				result = 0;
			}
			return (byte)result != 0;
		}

		internal static void EnsureWardSettingsInitialized(ZDO zdo)
		{
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			if (!CanWriteWardZdo(zdo))
			{
				return;
			}
			if (!HasStoredWardSettings(zdo))
			{
				bool flag = ProtectiveWards.HasZdoVec3(zdo, ProtectiveWards.s_color);
				if (!ProtectiveWards.HasZdoBool(zdo, ProtectiveWards.s_customRange))
				{
					zdo.Set(ProtectiveWards.s_customRange, ProtectiveWards.HasZdoFloat(zdo, ProtectiveWards.s_range) || ProtectiveWards.setWardRange.Value);
				}
				if (!ProtectiveWards.HasZdoFloat(zdo, ProtectiveWards.s_range))
				{
					zdo.Set(ProtectiveWards.s_range, ProtectiveWards.ClampWardRange(ProtectiveWards.wardRange.Value));
				}
				if (!ProtectiveWards.HasZdoBool(zdo, ProtectiveWards.s_customColor))
				{
					zdo.Set(ProtectiveWards.s_customColor, flag || ProtectiveWards.wardEmissionColorEnabled.Value);
				}
				if (!ProtectiveWards.HasZdoVec3(zdo, ProtectiveWards.s_color))
				{
					zdo.Set(ProtectiveWards.s_color, new Vector3(ProtectiveWards.wardEmissionColor.Value.r, ProtectiveWards.wardEmissionColor.Value.g, ProtectiveWards.wardEmissionColor.Value.b));
				}
				if (!ProtectiveWards.HasZdoFloat(zdo, ProtectiveWards.s_colorMultiplier))
				{
					zdo.Set(ProtectiveWards.s_colorMultiplier, flag ? 1f : ProtectiveWards.wardEmissionColorMultiplier.Value);
				}
				if (!ProtectiveWards.HasZdoBool(zdo, ProtectiveWards.s_bubbleEnabled))
				{
					zdo.Set(ProtectiveWards.s_bubbleEnabled, ProtectiveWards.wardBubbleShow.Value);
				}
				if (!ProtectiveWards.HasZdoVec3(zdo, ProtectiveWards.s_bubbleColor))
				{
					zdo.Set(ProtectiveWards.s_bubbleColor, new Vector3(ProtectiveWards.wardBubbleColor.Value.r, ProtectiveWards.wardBubbleColor.Value.g, ProtectiveWards.wardBubbleColor.Value.b));
				}
				if (!ProtectiveWards.HasZdoFloat(zdo, ProtectiveWards.s_bubbleColorAlpha))
				{
					zdo.Set(ProtectiveWards.s_bubbleColorAlpha, ProtectiveWards.wardBubbleColor.Value.a);
				}
				SetFloatIfMissing(zdo, ProtectiveWards.s_bubbleRefractionIntensity, ProtectiveWards.wardBubbleRefractionIntensity.Value);
				SetFloatIfMissing(zdo, ProtectiveWards.s_bubbleWaveVel, ProtectiveWards.wardBubbleWaveIntensity.Value);
				SetFloatIfMissing(zdo, ProtectiveWards.s_bubbleGlossiness, ProtectiveWards.wardBubbleGlossiness.Value);
				SetFloatIfMissing(zdo, ProtectiveWards.s_bubbleMetallic, ProtectiveWards.wardBubbleMetallic.Value);
				SetFloatIfMissing(zdo, ProtectiveWards.s_bubbleNormalScale, ProtectiveWards.wardBubbleNormalScale.Value);
				SetFloatIfMissing(zdo, ProtectiveWards.s_bubbleDepthFade, ProtectiveWards.wardBubbleDepthFade.Value);
				if (!ProtectiveWards.HasZdoBool(zdo, ProtectiveWards.s_circleEnabled))
				{
					zdo.Set(ProtectiveWards.s_circleEnabled, ProtectiveWards.wardAreaMarkerPatch.Value);
				}
				SetStringIfMissing(zdo, ProtectiveWards.s_circleStartColor, ColorUtility.ToHtmlStringRGBA(ProtectiveWards.wardAreaMarkerStartColor.Value));
				SetStringIfMissing(zdo, ProtectiveWards.s_circleEndColor, ColorUtility.ToHtmlStringRGBA(ProtectiveWards.wardAreaMarkerEndColor.Value));
				SetFloatIfMissing(zdo, ProtectiveWards.s_circleSpeed, ProtectiveWards.wardAreaMarkerSpeed.Value);
				SetFloatIfMissing(zdo, ProtectiveWards.s_circleLength, ProtectiveWards.wardAreaMarkerLength.Value);
				SetFloatIfMissing(zdo, ProtectiveWards.s_circleWidth, ProtectiveWards.wardAreaMarkerWidth.Value);
				SetFloatIfMissing(zdo, ProtectiveWards.s_circleAmount, ProtectiveWards.wardAreaMarkerAmount.Value);
				if (!ProtectiveWards.HasZdoBool(zdo, ProtectiveWards.s_permitEveryone))
				{
					zdo.Set(ProtectiveWards.s_permitEveryone, ProtectiveWards.permitEveryone.Value);
				}
				if (!ProtectiveWards.HasZdoBool(zdo, ProtectiveWards.s_permittedPlayersCanToggle))
				{
					zdo.Set(ProtectiveWards.s_permittedPlayersCanToggle, ProtectiveWards.wardPermittedPlayersCanToggle.Value);
				}
				zdo.Set(ProtectiveWards.s_wardSettingsVersion, 1, false);
			}
			UpdateWardRuntimeFields(zdo);
		}

		private static void SetFloatIfMissing(ZDO zdo, int key, float value)
		{
			if (!ProtectiveWards.HasZdoFloat(zdo, key))
			{
				zdo.Set(key, value);
			}
		}

		private static void SetStringIfMissing(ZDO zdo, int key, string value)
		{
			if (!ProtectiveWards.HasZdoString(zdo, key))
			{
				zdo.Set(key, value ?? string.Empty);
			}
		}

		internal static void UpdateWardRuntimeFields(ZDO zdo)
		{
			if (CanWriteWardZdo(zdo))
			{
				zdo.Set("HasFields", true);
				zdo.Set("HasFieldsPrivateArea", true);
				zdo.Set("PrivateArea.m_radius", GetWardRadius(zdo));
				zdo.Set("PrivateArea.m_flashAvailable", true);
			}
		}

		internal static void UpdateAllWardRuntimeFields()
		{
			ZDO[] array = GetAllWards().ToArray();
			foreach (ZDO zdo in array)
			{
				EnsureWardSettingsInitialized(zdo);
			}
		}

		internal static IEnumerable<ZDO> GetAllWards()
		{
			if (ShouldTrackServerWards())
			{
				EnsureWardObjectsInitialized();
				PruneWardObjects();
				foreach (ZDO s_wardObject in s_wardObjects)
				{
					yield return s_wardObject;
				}
				yield break;
			}
			HashSet<ZDOID> visited = ((s_visitedPool.Count > 0) ? s_visitedPool.Pop() : new HashSet<ZDOID>());
			try
			{
				foreach (PrivateArea area in PrivateArea.m_allAreas)
				{
					int num;
					if (area == null)
					{
						num = 0;
					}
					else
					{
						ZNetView nview = area.m_nview;
						num = ((((nview != null) ? new bool?(nview.IsValid()) : ((bool?)null)) == true) ? 1 : 0);
					}
					ZDO zdo = ((num != 0) ? area.m_nview.GetZDO() : null);
					if (IsWard(zdo) && visited.Add(zdo.m_uid))
					{
						yield return zdo;
					}
				}
			}
			finally
			{
				bool retain = visited.Count <= 4096;
				visited.Clear();
				if (retain && s_visitedPool.Count < 4)
				{
					s_visitedPool.Push(visited);
				}
			}
		}

		internal static bool TryFindActiveWardContainingPoint(Vector3 point, Func<ZDO, bool> isActive, out ZDO ward)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			ward = null;
			if (ShouldTrackServerWards())
			{
				EnsureWardObjectsInitialized();
				PruneWardObjects();
				foreach (ZDO s_wardObject in s_wardObjects)
				{
					if (!isActive(s_wardObject) || !ProtectiveWards.IsInsideWardXZ(s_wardObject, point))
					{
						continue;
					}
					ward = s_wardObject;
					return true;
				}
				return false;
			}
			foreach (PrivateArea allArea in PrivateArea.m_allAreas)
			{
				object obj;
				if (allArea != null)
				{
					ZNetView nview = allArea.m_nview;
					if (((nview != null) ? new bool?(nview.IsValid()) : ((bool?)null)) == true)
					{
						obj = allArea.m_nview.GetZDO();
						goto IL_00da;
					}
				}
				obj = null;
				goto IL_00da;
				IL_00da:
				ZDO val = (ZDO)obj;
				if (!IsWard(val) || !isActive(val) || !ProtectiveWards.IsInsideWardXZ(val, point))
				{
					continue;
				}
				ward = val;
				return true;
			}
			return false;
		}

		internal static int CountWardsByCreator(long creatorID)
		{
			if (creatorID == 0)
			{
				return 0;
			}
			int num = 0;
			foreach (ZDO allWard in GetAllWards())
			{
				if (allWard.IsCreator(creatorID))
				{
					num++;
				}
			}
			return num;
		}

		internal static PrivateArea FindLoadedWard(ZDOID zdoID)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			foreach (PrivateArea allArea in PrivateArea.m_allAreas)
			{
				if (!((Object)(object)allArea == (Object)null) && !((Object)(object)allArea.m_nview == (Object)null) && allArea.m_nview.IsValid())
				{
					ZDO zDO = allArea.m_nview.GetZDO();
					if (zDO != null && ((ZDOID)(ref zDO.m_uid)).Equals(zdoID))
					{
						return allArea;
					}
				}
			}
			return null;
		}

		internal static ZDO GetWard(ZDOID zdoID)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			ZDOMan instance = ZDOMan.instance;
			ZDO val = ((instance != null) ? instance.GetZDO(zdoID) : null);
			return IsWard(val) ? val : null;
		}

		internal static bool TryGetWard(ZDOID zdoID, out ZDO zdo)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			zdo = GetWard(zdoID);
			return zdo != null;
		}

		internal static List<KeyValuePair<long, string>> GetPermittedPlayers(ZDO zdo)
		{
			List<KeyValuePair<long, string>> list = new List<KeyValuePair<long, string>>();
			if (!IsWard(zdo))
			{
				return list;
			}
			int num = Math.Max(zdo.GetInt(ZDOVars.s_permitted, 0), 0);
			for (int i = 0; i < num; i++)
			{
				long num2 = zdo.GetLong("pu_id" + i, 0L);
				if (num2 != 0)
				{
					list.Add(new KeyValuePair<long, string>(num2, zdo.GetString("pu_name" + i, "")));
				}
			}
			return list;
		}

		internal static bool IsExplicitlyPermitted(ZDO zdo, long playerID)
		{
			if (playerID == 0L || !IsWard(zdo))
			{
				return false;
			}
			int num = Math.Max(zdo.GetInt(ZDOVars.s_permitted, 0), 0);
			for (int i = 0; i < num; i++)
			{
				int num2 = ((i < s_permittedPlayerIdHashes.Length) ? s_permittedPlayerIdHashes[i] : StringExtensionMethods.GetStableHashCode("pu_id" + i));
				if (zdo.GetLong(num2, 0L) == playerID)
				{
					return true;
				}
			}
			return false;
		}

		internal static bool AddPermitted(ZDO zdo, long playerID, string playerName)
		{
			if (!IsWard(zdo) || playerID == 0)
			{
				return false;
			}
			List<KeyValuePair<long, string>> permittedPlayers = GetPermittedPlayers(zdo);
			if (permittedPlayers.Any((KeyValuePair<long, string> player) => player.Key == playerID))
			{
				return false;
			}
			permittedPlayers.Add(new KeyValuePair<long, string>(playerID, playerName ?? ""));
			SetPermittedPlayers(zdo, permittedPlayers);
			return true;
		}

		internal static bool RemovePermitted(ZDO zdo, long playerID, out string playerName)
		{
			playerName = "";
			if (!IsWard(zdo) || playerID == 0)
			{
				return false;
			}
			List<KeyValuePair<long, string>> permittedPlayers = GetPermittedPlayers(zdo);
			KeyValuePair<long, string> keyValuePair = permittedPlayers.FirstOrDefault((KeyValuePair<long, string> player) => player.Key == playerID);
			if (keyValuePair.Key == 0)
			{
				return false;
			}
			playerName = keyValuePair.Value ?? "";
			permittedPlayers.RemoveAll((KeyValuePair<long, string> player) => player.Key == playerID);
			SetPermittedPlayers(zdo, permittedPlayers);
			return true;
		}

		internal static void SetPermittedPlayers(ZDO zdo, List<KeyValuePair<long, string>> permitted)
		{
			if (IsWard(zdo))
			{
				if (permitted == null)
				{
					permitted = new List<KeyValuePair<long, string>>();
				}
				zdo.Set(ZDOVars.s_permitted, permitted.Count, false);
				for (int i = 0; i < permitted.Count; i++)
				{
					zdo.Set("pu_id" + i, permitted[i].Key);
					zdo.Set("pu_name" + i, permitted[i].Value ?? "");
				}
			}
		}

		internal static bool IsPermitted(ZDO zdo, long playerID)
		{
			if (zdo == null || playerID == 0)
			{
				return false;
			}
			if (ProtectiveWards.HasWardManagementAccess(zdo, playerID))
			{
				return true;
			}
			if (IsExplicitlyPermitted(zdo, playerID))
			{
				return true;
			}
			return GuildsCompat.HasWardGuildAccess(zdo, playerID);
		}

		internal static bool HasDirectAccessToWardZdo(ZDO zdo, long playerID)
		{
			if (zdo == null)
			{
				return true;
			}
			if (playerID == 0)
			{
				return false;
			}
			if (!IsWard(zdo))
			{
				return false;
			}
			if (zdo.IsCreator(playerID))
			{
				return true;
			}
			return IsPermitted(zdo, playerID);
		}

		internal static bool UseCustomWardRange(ZDO zdo)
		{
			if (!ProtectiveWards.ArePerWardSettingsEnabled())
			{
				return ProtectiveWards.setWardRange.Value;
			}
			if (zdo == null)
			{
				return false;
			}
			if (HasStoredWardSettings(zdo))
			{
				return zdo.GetBool(ProtectiveWards.s_customRange, false);
			}
			return ProtectiveWards.HasZdoFloat(zdo, ProtectiveWards.s_range) || zdo.GetBool(ProtectiveWards.s_customRange, false);
		}

		internal static float GetConfiguredWardRange(ZDO zdo)
		{
			if (!ProtectiveWards.ArePerWardSettingsEnabled())
			{
				return ProtectiveWards.ClampWardRange(ProtectiveWards.wardRange.Value);
			}
			if (zdo == null)
			{
				return GetWardDefaultRadius();
			}
			return ProtectiveWards.ClampWardRange(zdo.GetFloat(ProtectiveWards.s_range, GetWardDefaultRadius()));
		}

		internal static float GetWardDefaultRadius()
		{
			if (s_wardDefaultRadiusCached)
			{
				return ProtectiveWards.ClampWardRange(s_wardDefaultRadius);
			}
			if ((Object)(object)ZNetScene.instance != (Object)null)
			{
				GameObject prefab = ZNetScene.instance.GetPrefab("guard_stone");
				PrivateArea val = ((prefab != null) ? prefab.GetComponent<PrivateArea>() : null);
				if ((Object)(object)val != (Object)null)
				{
					s_wardDefaultRadius = val.m_radius;
					s_wardDefaultRadiusCached = true;
				}
			}
			return ProtectiveWards.ClampWardRange(s_wardDefaultRadius);
		}

		internal static float GetWardRadius(ZDO zdo)
		{
			if (zdo == null)
			{
				return GetWardDefaultRadius();
			}
			float radius = default(float);
			if (ProtectiveWards.ArePerWardSettingsEnabled() && !HasStoredWardSettings(zdo) && zdo.GetFloat("PrivateArea.m_radius", ref radius))
			{
				return ProtectiveWards.ClampWardRange(radius);
			}
			return UseCustomWardRange(zdo) ? GetConfiguredWardRange(zdo) : GetWardDefaultRadius();
		}

		internal static bool AreWardZdosOverlapping(ZDO protectedWard, ZDO candidateWard)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			if (!IsWard(protectedWard) || !IsWard(candidateWard))
			{
				return false;
			}
			float wardRadius = GetWardRadius(protectedWard);
			float wardRadius2 = GetWardRadius(candidateWard);
			return ProtectiveWards.GetConfiguredWardDistance(protectedWard.GetPosition(), candidateWard.GetPosition()) <= wardRadius + wardRadius2;
		}

		internal static bool HasWardTrustAccess(ZDO ward, long playerID)
		{
			return IsWard(ward) && playerID != 0L && (ward.IsCreator(playerID) || ProtectiveWards.IsPermitEveryone(ward) || IsExplicitlyPermitted(ward, playerID) || GuildsCompat.HasWardGuildAccess(ward, playerID));
		}

		internal static bool CanShareConnectedWardAccess(ZDO protectedWard, ZDO candidateWard, ProtectiveWards.WardConnectedAccessMode mode)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			if (mode == ProtectiveWards.WardConnectedAccessMode.Off)
			{
				return false;
			}
			if (!IsWard(protectedWard) || !IsWard(candidateWard))
			{
				return false;
			}
			if (protectedWard == candidateWard || ((ZDOID)(ref protectedWard.m_uid)).Equals(candidateWard.m_uid))
			{
				return true;
			}
			switch (mode)
			{
			case ProtectiveWards.WardConnectedAccessMode.SameCreatorOnly:
			{
				long creatorId = protectedWard.GetCreatorId();
				long creatorId2 = candidateWard.GetCreatorId();
				return creatorId != 0L && creatorId == creatorId2;
			}
			case ProtectiveWards.WardConnectedAccessMode.MutualTrust:
			{
				long creatorId = protectedWard.GetCreatorId();
				long creatorId2 = candidateWard.GetCreatorId();
				return creatorId != 0L && creatorId2 != 0L && HasWardTrustAccess(protectedWard, creatorId2) && HasWardTrustAccess(candidateWard, creatorId);
			}
			case ProtectiveWards.WardConnectedAccessMode.AnyConnected:
				return true;
			default:
				return false;
			}
		}

		internal static IEnumerable<ZDO> ConnectedAccessWardZdos(ZDO rootWard, ProtectiveWards.WardConnectedAccessMode mode, Func<ZDO, bool> isActiveCandidate)
		{
			if (!IsWard(rootWard))
			{
				yield break;
			}
			yield return rootWard;
			if (mode == ProtectiveWards.WardConnectedAccessMode.Off)
			{
				yield break;
			}
			WardTraversal traversal = ((s_traversalPool.Count > 0) ? s_traversalPool.Pop() : new WardTraversal());
			try
			{
				traversal.Visited.Add(rootWard.m_uid);
				traversal.Queue.Add(rootWard);
				foreach (ZDO candidate in GetAllWards())
				{
					traversal.Candidates.Add(candidate);
				}
				int queueIndex = 0;
				while (queueIndex < traversal.Queue.Count)
				{
					ZDO current = traversal.Queue[queueIndex++];
					if (queueIndex > 1)
					{
						yield return current;
					}
					foreach (ZDO candidate2 in traversal.Candidates)
					{
						if (IsWard(candidate2) && !traversal.Visited.Contains(candidate2.m_uid) && (isActiveCandidate == null || isActiveCandidate(candidate2)) && AreWardZdosOverlapping(current, candidate2) && CanShareConnectedWardAccess(rootWard, candidate2, mode))
						{
							traversal.Visited.Add(candidate2.m_uid);
							traversal.Queue.Add(candidate2);
						}
					}
				}
			}
			finally
			{
				((<ConnectedAccessWardZdos>d__46)/*Error near IL_0008: stateMachine*/).<retain>5__8 = traversal.Candidates.Count <= 4096 && traversal.Queue.Count <= 4096;
				traversal.Visited.Clear();
				traversal.Queue.Clear();
				traversal.Candidates.Clear();
				bool retain = default(bool);
				if (retain && s_traversalPool.Count < 4)
				{
					s_traversalPool.Push(traversal);
				}
			}
		}

		internal static bool HasAccessToWardOrConnectedWardZdo(ZDO rootWard, long playerID, ProtectiveWards.WardConnectedAccessMode mode, Func<ZDO, bool> isActiveCandidate)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			if (HasDirectAccessToWardZdo(rootWard, playerID))
			{
				return true;
			}
			if (mode == ProtectiveWards.WardConnectedAccessMode.Off)
			{
				return false;
			}
			foreach (ZDO item in ConnectedAccessWardZdos(rootWard, mode, isActiveCandidate))
			{
				if (item == null || ((ZDOID)(ref item.m_uid)).Equals(rootWard.m_uid) || !HasDirectAccessToWardZdo(item, playerID))
				{
					continue;
				}
				return true;
			}
			return false;
		}

		private static bool ShouldTrackServerWards()
		{
			return (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer();
		}

		private static void AddIfWard(ZDO zdo)
		{
			if (ShouldTrackServerWards() && IsWard(zdo))
			{
				s_wardObjects.Add(zdo);
				EnsureWardSettingsInitialized(zdo);
			}
		}

		private static void RemoveIfWard(ZDO zdo)
		{
			if (zdo != null && IsWard(zdo))
			{
				s_wardObjects.Remove(zdo);
			}
		}

		private static void PruneWardObjects()
		{
			s_wardObjects.RemoveWhere((ZDO zdo) => zdo == null || !IsWard(zdo));
		}

		private static void EnsureWardObjectsInitialized()
		{
			if (ShouldTrackServerWards())
			{
				ZDOMan instance = ZDOMan.instance;
				if (instance != null && !s_wardObjectsInitialized)
				{
					RebuildWardObjects(instance);
				}
			}
		}

		private static void RebuildWardObjects(ZDOMan zdoMan)
		{
			s_wardObjects.Clear();
			if (!ShouldTrackServerWards() || zdoMan == null)
			{
				s_wardObjectsInitialized = false;
				return;
			}
			s_wardObjectsInitialized = true;
			foreach (KeyValuePair<ZDOID, ZDO> item in zdoMan.m_objectsByID)
			{
				AddIfWard(item.Value);
			}
		}
	}
	internal static class BackgroundProtection
	{
		private struct CachedBool
		{
			public float Time;

			public bool Value;
		}

		[HarmonyPatch(typeof(ZoneSystem), "Start")]
		private static class ZoneSystem_Start_ResetBackgroundProtectionCache
		{
			private static void Postfix()
			{
				ResetCache();
			}
		}

		[HarmonyPatch(typeof(ZoneSystem), "OnDestroy")]
		private static class ZoneSystem_OnDestroy_ResetBackgroundProtectionCache
		{
			private static void Postfix()
			{
				ResetCache();
			}
		}

		[HarmonyPatch(typeof(Player), "TryPlacePiece")]
		private static class Player_TryPlacePiece_PreventBuildingWithoutPermittedPlayersNearby
		{
			[HarmonyPriority(800)]
			private static bool Prefix(Player __instance, Piece piece, ref bool __result)
			{
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)__instance == (Object)null || (Object)(object)piece == (Object)null || (Object)(object)__instance.m_placementGhost == (Object)null)
				{
					return true;
				}
				if (!IsBuildingRestricted(__instance, __instance.m_placementGhost.transform.position))
				{
					return true;
				}
				((Character)__instance).Message((MessageType)2, "$msg_privatezone", 0, (Sprite)null, false);
				__result = false;
				return false;
			}
		}

		[HarmonyPatch(typeof(Player), "CheckCanRemovePiece")]
		private static class Player_CheckCanRemovePiece_PreventDemolishingWithoutPermittedPlayersNearby
		{
			[HarmonyPriority(800)]
			private static bool Prefix(Player __instance, Piece piece, ref bool __result)
			{
				//IL_0031: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)__instance == (Object)null || (Object)(object)piece == (Object)null)
				{
					return true;
				}
				if (piece.IsCreator())
				{
					return true;
				}
				if (!IsBuildingRestricted(__instance, ((Component)piece).transform.position))
				{
					return true;
				}
				((Character)__instance).Message((MessageType)2, "$msg_privatezone", 0, (Sprite)null, false);
				__result = false;
				return false;
			}
		}

		[HarmonyPatch(typeof(WearNTear), "Damage")]
		private static class WearNTear_Damage_BackgroundProtection
		{
			private static void Prefix(WearNTear __instance, HitData hit)
			{
				if (!((Object)(object)__instance == (Object)null) && hit != null)
				{
					bool flag = (Object)(object)((Component)__instance).GetComponentInParent<Ship>() != (Object)null;
					bool flag2 = (Object)(object)((Component)__instance).GetComponentInParent<Vagon>() != (Object)null;
					if ((!ProtectiveWards.vehiclesNeverProtected.Value || !(flag || flag2)) && (ShouldSuppressWearNTearDamage(__instance, hit, flag, flag2) || ShouldSuppressTameDamageToStructure(__instance, hit)))
					{
						((DamageTypes)(ref hit.m_damage)).Modify(0f);
					}
				}
			}
		}

		[HarmonyPatch(typeof(Character), "Damage")]
		private static class Character_Damage_BackgroundTameProtection
		{
			private static void Prefix(Character __instance, HitData hit)
			{
				if (ShouldSuppressTameCharacterDamage(__instance))
				{
					((Da