Decompiled source of FehuTerritoryGuards v420.101.1

FehuTerritoryGuards.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FehuTerritoryGuards.AI;
using FehuTerritoryGuards.Areas;
using FehuTerritoryGuards.Core;
using FehuTerritoryGuards.Faction;
using FehuTerritoryGuards.Interaction;
using FehuTerritoryGuards.Networking;
using FehuTerritoryGuards.Persistence;
using FortecaClanWarfare.Core;
using FortecaClanWarfare.Data;
using FortecaClanWarfare.Utils;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("BlackViking")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("420.101.1.0")]
[assembly: AssemblyInformationalVersion("420.101.1")]
[assembly: AssemblyProduct("FehuTerritoryGuards")]
[assembly: AssemblyTitle("FehuTerritoryGuards")]
[assembly: AssemblyVersion("420.101.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[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 FehuTerritoryGuards
{
	[BepInPlugin("com.forteca.blackviking.fehuterritoryguards", "FehuTerritoryGuards", "420.101.1")]
	[BepInDependency("com.forteca.clanwarfare", "420.101.2")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Guid = "com.forteca.blackviking.fehuterritoryguards";

		public const string Version = "420.101.1";

		internal static ManualLogSource Log;

		internal static Settings Local;

		internal static Settings Effective;

		internal static bool SettingsReady;

		internal static ZRoutedRpc Rpc;

		private Harmony harmony;

		private int cursor;

		private float nextHello;

		private void Awake()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Local = Settings.Load(((BaseUnityPlugin)this).Config);
			Effective = Local;
			harmony = new Harmony("com.forteca.blackviking.fehuterritoryguards");
			harmony.PatchAll(typeof(Plugin).Assembly);
			GuardInteraction.RegisterCommands();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"FehuTerritoryGuards 420.101.1 loaded; FCW 420.101.2 baseline; gameplay validation pending.");
		}

		private void Update()
		{
			if (ZRoutedRpc.instance != Rpc)
			{
				Rpc = ZRoutedRpc.instance;
				SettingsReady = false;
				FCWAdapter.Clear();
				Authority.Clear();
				if (Rpc != null)
				{
					Authority.Bind(Rpc);
					nextHello = 0f;
				}
			}
			if (Rpc == null || (Object)(object)ZNet.instance == (Object)null)
			{
				return;
			}
			if (Authority.IsServer)
			{
				Effective = Local;
				SettingsReady = true;
			}
			if (Time.time >= nextHello)
			{
				nextHello = Time.time + 5f;
				Rpc.InvokeRoutedRPC("FTG_V1_Hello", Array.Empty<object>());
			}
			Authority.Cleanup();
			int count = GuardController.Controllers.Count;
			int num = 0;
			int num2 = 0;
			while (num < count && num2 < Effective.DecisionsPerFrame)
			{
				if (cursor >= GuardController.Controllers.Count)
				{
					cursor = 0;
				}
				if (GuardController.Controllers.Count == 0)
				{
					break;
				}
				GuardController guardController = GuardController.Controllers[cursor++];
				num++;
				if (Object.op_Implicit((Object)(object)guardController) && !(Time.time < guardController.NextDecision))
				{
					try
					{
						guardController.Decide();
					}
					catch (Exception ex)
					{
						guardController.State = DutyState.Disabled;
						guardController.ClearTarget();
						guardController.NextDecision = Time.time + 5f;
						Trace("Guard disabled after adapter exception: " + ex);
					}
					if (guardController.Assignment != null)
					{
						num2++;
					}
				}
			}
		}

		internal static void ReceiveSettings(Settings s)
		{
			Effective = s;
			SettingsReady = true;
		}

		internal static void Trace(string message)
		{
			if (Local != null && Local.Debug)
			{
				Log.LogInfo((object)message);
			}
		}

		private void OnDestroy()
		{
			foreach (GuardController controller in GuardController.Controllers)
			{
				if (Object.op_Implicit((Object)(object)controller))
				{
					controller.ClearTarget();
					controller.SetFrozen(value: false);
				}
			}
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			Authority.Clear();
			FCWAdapter.Clear();
			Rpc = null;
			SettingsReady = false;
		}
	}
}
namespace FehuTerritoryGuards.Persistence
{
	internal static class GuardStore
	{
		internal const string Key = "FTG_V1_Record";

		internal const string ProofKey = "FTG_V1_Proof";

		internal static bool Assigned(ZDO z)
		{
			if (z != null)
			{
				return z.GetString("FTG_V1_Record", "").Length > 0;
			}
			return false;
		}

		internal static Assignment Read(ZDO z)
		{
			if (z == null)
			{
				return null;
			}
			string text = z.GetString("FTG_V1_Record", "");
			if (text.Length == 0 || text.Length > 700)
			{
				return null;
			}
			try
			{
				Assignment s;
				return AssignmentCodec.TryDecode(Convert.FromBase64String(text), out s) ? s : null;
			}
			catch (FormatException)
			{
				return null;
			}
		}

		internal static void Write(ZDO z, Assignment s, string proof)
		{
			z.Set("FTG_V1_Record", Convert.ToBase64String(AssignmentCodec.Encode(s)));
			z.Set("FTG_V1_Proof", proof);
			z.Set("FTG_V1_DataVersion", s.Version);
			z.Set("FTG_V1_ClanID", s.ClanId);
		}

		internal static Point Point(Vector3 v)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			return new Point(v.x, v.y, v.z);
		}

		internal static Vector3 Vector(Point p)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3(p.X, p.Y, p.Z);
		}

		internal static ZDOID WardId(Assignment s)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			return new ZDOID(s.WardUser, s.WardId);
		}
	}
}
namespace FehuTerritoryGuards.Networking
{
	internal static class Authority
	{
		private sealed class Active
		{
			internal ZDO Guard;

			internal float Until;

			internal long Owner;
		}

		private sealed class Inspection
		{
			internal ZDOID Guard;

			internal long Requester;

			internal long Owner;

			internal float Until;
		}

		internal const string Command = "FTG_V1_Command";

		internal const string Commit = "FTG_V1_Commit";

		internal const string Combat = "FTG_V1_Combat";

		internal const string Permit = "FTG_V1_Permit";

		internal const string Damage = "FTG_V1_Damage";

		internal const string Hello = "FTG_V1_Hello";

		internal const string SettingsRpc = "FTG_V1_Settings";

		internal const string Reply = "FTG_V1_Reply";

		internal const string DebugRead = "FTG_V1_DebugRead";

		internal const string DebugResult = "FTG_V1_DebugResult";

		private static readonly Dictionary<int, Inspection> Inspections = new Dictionary<int, Inspection>();

		private static int nextInspection;

		private static readonly Dictionary<ZDOID, Assignment> Accepted = new Dictionary<ZDOID, Assignment>();

		private static readonly Dictionary<ZDOID, Active> ActiveGuards = new Dictionary<ZDOID, Active>();

		private static readonly Dictionary<(ZDOID guard, ZDOID target), float> Threats = new Dictionary<(ZDOID, ZDOID), float>();

		private static readonly Dictionary<(long sender, int kind), float> Rates = new Dictionary<(long, int), float>();

		private static readonly HashSet<long> CompatiblePeers = new HashSet<long>();

		private static readonly List<ZDOID> Expired = new List<ZDOID>();

		private static float nextCleanup;

		internal static bool IsServer
		{
			get
			{
				if ((Object)(object)ZNet.instance != (Object)null)
				{
					return ZNet.instance.IsServer();
				}
				return false;
			}
		}

		internal static bool SupportsOwner(long peer)
		{
			if (peer != ZNet.GetUID())
			{
				if (CompatiblePeers.Contains(peer))
				{
					return ZNet.instance.GetPeer(peer) != null;
				}
				return false;
			}
			return true;
		}

		internal static bool FromServer(long sender)
		{
			if ((Object)(object)ZNet.instance != (Object)null)
			{
				if (!IsServer)
				{
					return sender == ZNet.instance.GetServerPeer()?.m_uid;
				}
				return sender == ZNet.GetUID();
			}
			return false;
		}

		internal static void Bind(ZRoutedRpc rpc)
		{
			Clear();
			rpc.Register<ZPackage>("FTG_V1_Command", (Action<long, ZPackage>)delegate(long sender, ZPackage p)
			{
				Safe(delegate
				{
					OnCommand(sender, p);
				});
			});
			rpc.Register<ZPackage>("FTG_V1_Commit", (Action<long, ZPackage>)delegate(long sender, ZPackage p)
			{
				Safe(delegate
				{
					OnCommit(sender, p);
				});
			});
			rpc.Register<ZPackage>("FTG_V1_Combat", (Action<long, ZPackage>)delegate(long sender, ZPackage p)
			{
				Safe(delegate
				{
					OnCombat(sender, p);
				});
			});
			rpc.Register<ZPackage>("FTG_V1_Permit", (Action<long, ZPackage>)delegate(long sender, ZPackage p)
			{
				Safe(delegate
				{
					OnPermit(sender, p);
				});
			});
			rpc.Register<ZPackage>("FTG_V1_Damage", (Action<long, ZPackage>)delegate(long sender, ZPackage p)
			{
				Safe(delegate
				{
					OnDamage(sender, p);
				});
			});
			rpc.Register<ZPackage>("FTG_V1_DebugRead", (Action<long, ZPackage>)delegate(long sender, ZPackage p)
			{
				Safe(delegate
				{
					OnDebugRead(sender, p);
				});
			});
			rpc.Register<ZPackage>("FTG_V1_DebugResult", (Action<long, ZPackage>)delegate(long sender, ZPackage p)
			{
				Safe(delegate
				{
					OnDebugResult(sender, p);
				});
			});
			rpc.Register("FTG_V1_Hello", (Action<long>)delegate(long sender)
			{
				Safe(delegate
				{
					OnHello(sender);
				});
			});
			rpc.Register<ZPackage>("FTG_V1_Settings", (Action<long, ZPackage>)delegate(long sender, ZPackage p)
			{
				Safe(delegate
				{
					if (FromServer(sender))
					{
						Plugin.ReceiveSettings(Settings.Read(p));
					}
				});
			});
			rpc.Register<string>("FTG_V1_Reply", (Action<long, string>)delegate(long sender, string text)
			{
				if (FromServer(sender) && text.Length <= 4096)
				{
					GuardInteraction.Notify(text);
				}
			});
		}

		private static void Safe(Action a)
		{
			try
			{
				a();
			}
			catch (Exception ex)
			{
				Plugin.Trace("RPC rejected: " + ex.GetType().Name + " " + ex.Message);
			}
		}

		private static bool Rate(long sender, int kind, float seconds)
		{
			if (sender != ZNet.GetUID() && ZNet.instance.GetPeer(sender) == null)
			{
				return false;
			}
			(long, int) key = (sender, kind);
			if (Rates.TryGetValue(key, out var value) && Time.time < value)
			{
				return false;
			}
			Rates[key] = Time.time + seconds;
			return true;
		}

		private static ZDO Actor(long sender, out long playerId, out bool admin)
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			playerId = 0L;
			admin = false;
			if (sender == ZNet.GetUID())
			{
				if ((Object)(object)Player.m_localPlayer == (Object)null)
				{
					return null;
				}
				playerId = Player.m_localPlayer.GetPlayerID();
				admin = true;
				ZNetView component = ((Component)Player.m_localPlayer).GetComponent<ZNetView>();
				if (component == null)
				{
					return null;
				}
				return component.GetZDO();
			}
			ZNetPeer peer = ZNet.instance.GetPeer(sender);
			if (peer == null)
			{
				return null;
			}
			ZDO zDO = ZDOMan.instance.GetZDO(peer.m_characterID);
			if (zDO == null || zDO.GetOwner() != sender)
			{
				return null;
			}
			playerId = zDO.GetLong(ZDOVars.s_playerID, 0L);
			if (playerId == 0L || playerId != peer.m_playerID)
			{
				playerId = 0L;
				return null;
			}
			admin = ZNet.instance.IsAdmin(peer.m_socket.GetHostName());
			return zDO;
		}

		internal static ZDO OnlinePlayer(long playerId)
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			if (playerId == 0L || (Object)(object)ZNet.instance == (Object)null)
			{
				return null;
			}
			if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && Player.m_localPlayer.GetPlayerID() == playerId)
			{
				ZNetView component = ((Component)Player.m_localPlayer).GetComponent<ZNetView>();
				if (component == null)
				{
					return null;
				}
				return component.GetZDO();
			}
			foreach (ZNetPeer peer in ZNet.instance.GetPeers())
			{
				if (peer.m_playerID == playerId)
				{
					return ZDOMan.instance.GetZDO(peer.m_characterID);
				}
			}
			return null;
		}

		internal static bool Compatible(ZDO z)
		{
			if (z == null || !z.GetBool(ZDOVars.s_tamed, false) || (Object)(object)ZNetScene.instance == (Object)null)
			{
				return false;
			}
			GameObject prefab = ZNetScene.instance.GetPrefab(z.GetPrefab());
			if (Object.op_Implicit((Object)(object)prefab) && Object.op_Implicit((Object)(object)prefab.GetComponent<Tameable>()) && Object.op_Implicit((Object)(object)prefab.GetComponent<Humanoid>()) && Object.op_Implicit((Object)(object)prefab.GetComponent<MonsterAI>()))
			{
				return !Plugin.Local.Excluded(((Object)prefab).name);
			}
			return false;
		}

		private static Assignment State(ZDO z)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			if (Accepted.TryGetValue(z.m_uid, out var value))
			{
				return value;
			}
			Assignment assignment = GuardStore.Read(z);
			if (!RecordProof.Verify(assignment, ((ZDOID)(ref z.m_uid)).UserID, ((ZDOID)(ref z.m_uid)).ID, Plugin.Local.SigningKey, z.GetString("FTG_V1_Proof", "")))
			{
				return null;
			}
			Accepted[z.m_uid] = assignment.Copy();
			return assignment;
		}

		private static void CommitState(ZDO z, Assignment s)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			//IL_004d: 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)
			string text = RecordProof.Sign(s, ((ZDOID)(ref z.m_uid)).UserID, ((ZDOID)(ref z.m_uid)).ID, Plugin.Local.SigningKey);
			Accepted[z.m_uid] = s.Copy();
			GuardStore.Write(z, s, text);
			ZPackage val = new ZPackage();
			val.Write(z.m_uid);
			val.Write(AssignmentCodec.Encode(s));
			val.Write(text);
			ZRoutedRpc.instance.InvokeRoutedRPC(0L, "FTG_V1_Commit", new object[1] { val });
			ZDOMan.instance.ForceSendZDO(z.m_uid);
		}

		private static void OnCommit(long sender, ZPackage p)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			if (!FromServer(sender) || p.Size() > 640)
			{
				return;
			}
			ZDOID val = p.ReadZDOID();
			if (!AssignmentCodec.TryDecode(p.ReadByteArray(), out var s))
			{
				return;
			}
			string text = p.ReadString();
			if (text.Length != 44)
			{
				return;
			}
			ZDO zDO = ZDOMan.instance.GetZDO(val);
			if (zDO == null)
			{
				return;
			}
			Assignment assignment = GuardStore.Read(zDO);
			if (assignment == null || assignment.Revision <= s.Revision)
			{
				GuardStore.Write(zDO, s, text);
				if (zDO.IsOwner())
				{
					ZDOMan.instance.ForceSendZDO(val);
				}
				GuardController.Find(val)?.Refresh(s);
			}
		}

		private static void OnHello(long sender)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			if (IsServer && Rate(sender, 0, 2f))
			{
				CompatiblePeers.Add(sender);
				ZPackage val = new ZPackage();
				Plugin.Local.Write(val);
				ZRoutedRpc.instance.InvokeRoutedRPC(sender, "FTG_V1_Settings", new object[1] { val });
			}
		}

		private static void Respond(long sender, string text)
		{
			ZRoutedRpc.instance.InvokeRoutedRPC(sender, "FTG_V1_Reply", new object[1] { text });
		}

		internal static void SendCommand(ZDOID id, int operation, Order order, Behavior behavior, float radius, ZDOID ward, bool locked)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			ZPackage val = new ZPackage();
			val.Write(id);
			val.Write(operation);
			val.Write((int)order);
			val.Write((int)behavior);
			val.Write(radius);
			val.Write(ward);
			val.Write(locked);
			ZRoutedRpc.instance.InvokeRoutedRPC("FTG_V1_Command", new object[1] { val });
		}

		private static void OnCommand(long sender, ZPackage p)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_029d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: Expected O, but got Unknown
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			//IL_0378: Unknown result type (might be due to invalid IL or missing references)
			//IL_03da: Unknown result type (might be due to invalid IL or missing references)
			//IL_047d: Unknown result type (might be due to invalid IL or missing references)
			//IL_050c: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0564: Unknown result type (might be due to invalid IL or missing references)
			//IL_056b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0589: Unknown result type (might be due to invalid IL or missing references)
			//IL_0590: Unknown result type (might be due to invalid IL or missing references)
			if (!IsServer || p.Size() > 160 || !Rate(sender, 1, 0.2f))
			{
				return;
			}
			ZDO zDO = ZDOMan.instance.GetZDO(p.ReadZDOID());
			int num = p.ReadInt();
			Order order = (Order)p.ReadInt();
			Behavior behavior = (Behavior)p.ReadInt();
			float num2 = p.ReadSingle();
			ZDOID val = p.ReadZDOID();
			bool locked = p.ReadBool();
			long playerId;
			bool admin;
			ZDO val2 = Actor(sender, out playerId, out admin);
			if (val2 == null || zDO == null)
			{
				Respond(sender, "Guard/player is unavailable on server.");
				return;
			}
			if (num == 4)
			{
				if (!admin)
				{
					Respond(sender, "Inspect requires server admin.");
					return;
				}
				Assignment assignment = State(zDO);
				GameObject prefab = ZNetScene.instance.GetPrefab(zDO.GetPrefab());
				Respond(sender, $"FTG server: prefab={((prefab != null) ? ((Object)prefab).name : null)} tamed={zDO.GetBool(ZDOVars.s_tamed, false)} AI={((prefab == null) ? null : ((object)prefab.GetComponent<BaseAI>())?.GetType().Name)} ZNetOwner={zDO.GetOwner()}\n" + ((assignment == null) ? "No valid assignment" : $"ClanID={assignment.ClanId} Order={assignment.Order} Behavior={assignment.Behavior} Area={assignment.Area} Ward={GuardStore.WardId(assignment)} Territory={assignment.TerritoryId} Anchor={GuardStore.Vector(assignment.Anchor)} Locked={assignment.Locked} Revision={assignment.Revision}"));
				if (zDO.GetOwner() != 0L && SupportsOwner(zDO.GetOwner()))
				{
					int num3 = ++nextInspection;
					Inspections[num3] = new Inspection
					{
						Guard = zDO.m_uid,
						Requester = sender,
						Owner = zDO.GetOwner(),
						Until = Time.time + 5f
					};
					ZPackage val3 = new ZPackage();
					val3.Write(num3);
					val3.Write(zDO.m_uid);
					ZRoutedRpc.instance.InvokeRoutedRPC(zDO.GetOwner(), "FTG_V1_DebugRead", new object[1] { val3 });
				}
				else
				{
					Respond(sender, "AI owner diagnostics unavailable; no connected compatible owner.");
				}
				return;
			}
			if (!Plugin.Local.Enabled || !FCWAdapter.Ready)
			{
				Respond(sender, "FCW/server guard system is not ready.");
				return;
			}
			if (Vector3.Distance(val2.GetPosition(), zDO.GetPosition()) > 10f || !Compatible(zDO))
			{
				Respond(sender, "Select a compatible already-tamed creature within 10m.");
				return;
			}
			if (!SupportsOwner(zDO.GetOwner()))
			{
				Respond(sender, "Current tame owner must have FehuTerritoryGuards installed and connected.");
				return;
			}
			int num4 = FCWAdapter.Clan(playerId);
			if (num4 <= 0)
			{
				Respond(sender, "An FCW clan is required.");
				return;
			}
			Assignment assignment2 = State(zDO);
			if (assignment2 == null && GuardStore.Assigned(zDO))
			{
				Respond(sender, "Unsupported or corrupt FTG record; preserved for recovery.");
				return;
			}
			if (assignment2 != null && !Policy.WorldValid(assignment2.WorldId, ZNet.instance.GetWorldUID()))
			{
				Respond(sender, "FTG record belongs to another world; preserved for recovery.");
				return;
			}
			if (assignment2 != null && !Policy.CanEdit(assignment2.ClanId, num4, assignment2.Locked, FCWAdapter.Leader(playerId), admin))
			{
				Respond(sender, "Duty is locked or belongs to another clan.");
				return;
			}
			if (assignment2 == null)
			{
				ClanTerritory val4 = FCWAdapter.Territory(FCWAdapter.TerritoryAt(zDO.GetPosition()));
				if (!admin && (val4 == null || val4.OwnerClanId != num4 || val4.IsAbandoned))
				{
					Respond(sender, "Initial clan assignment requires your clan's FCW territory (admin override available).");
					return;
				}
			}
			Assignment assignment3 = assignment2?.Copy() ?? new Assignment
			{
				ClanId = num4,
				OriginalOwner = playerId,
				Anchor = GuardStore.Point(zDO.GetPosition()),
				WorldId = ZNet.instance.GetWorldUID()
			};
			if (assignment2 != null)
			{
				assignment3.Revision = checked(assignment2.Revision + 1);
			}
			switch (num)
			{
			case 3:
				if (!admin && !FCWAdapter.Leader(playerId) && playerId != assignment3.OriginalOwner)
				{
					Respond(sender, "Lock requires original assigner, FCW officer/Jarl or admin.");
					return;
				}
				assignment3.Locked = locked;
				break;
			case 2:
				assignment3.Behavior = behavior;
				break;
			case 1:
				assignment3.Order = order;
				assignment3.Behavior = behavior;
				assignment3.Area = Policy.RequiredArea(order);
				assignment3.Anchor = GuardStore.Point(zDO.GetPosition());
				assignment3.FollowPlayer = (Policy.Follows(order) ? playerId : 0);
				assignment3.WardUser = 0L;
				assignment3.WardId = 0u;
				assignment3.TerritoryId = "";
				if (Policy.Follows(order) && num4 != assignment3.ClanId)
				{
					Respond(sender, "Follow/escort requires a player in the guard's assigned clan.");
					return;
				}
				assignment3.Radius = Mathf.Clamp(num2, 1f, Plugin.Local.MaxRadius);
				if (assignment3.Area == AreaKind.Ward)
				{
					ZDO zDO2 = ZDOMan.instance.GetZDO(val);
					object obj;
					if (zDO2 != null)
					{
						GameObject prefab2 = ZNetScene.instance.GetPrefab(zDO2.GetPrefab());
						obj = ((prefab2 != null) ? prefab2.GetComponent<PrivateArea>() : null);
					}
					else
					{
						obj = null;
					}
					PrivateArea val5 = (PrivateArea)obj;
					if (zDO2 == null || !Object.op_Implicit((Object)(object)val5) || !zDO2.GetBool(ZDOVars.s_enabled, false) || !WardArea.WardAccess(zDO2, playerId) || Vector3.Distance(val2.GetPosition(), zDO2.GetPosition()) > 10f)
					{
						Respond(sender, "Select an enabled Ward you created or are permitted at, within 10m.");
						return;
					}
					if (Vector3.Distance(zDO.GetPosition(), zDO2.GetPosition()) > val5.m_radius)
					{
						Respond(sender, "Guard must be inside selected Ward.");
						return;
					}
					assignment3.WardUser = ((ZDOID)(ref val)).UserID;
					assignment3.WardId = ((ZDOID)(ref val)).ID;
					assignment3.Radius = val5.m_radius;
				}
				if (assignment3.Area == AreaKind.Territory)
				{
					assignment3.TerritoryId = FCWAdapter.TerritoryAt(zDO.GetPosition());
					ClanTerritory val6 = FCWAdapter.Territory(assignment3.TerritoryId);
					if (val6 == null || !Policy.TerritoryValid(ready: true, assignment3.ClanId, val6.OwnerClanId, val6.IsAbandoned))
					{
						Respond(sender, "Guard must be in a territory owned by its assigned clan.");
						return;
					}
				}
				break;
			default:
				Respond(sender, "Unknown operation.");
				return;
			}
			if (!Policy.Valid(assignment3))
			{
				Respond(sender, "Invalid FTG assignment.");
				return;
			}
			CommitState(zDO, assignment3);
			Respond(sender, $"FTG: {assignment3.Order} / {assignment3.Behavior}, clan #{assignment3.ClanId}, lock={assignment3.Locked}");
		}

		internal static void RequestCombat(GuardController g, Character target, bool sensed, bool bodyguardThreat)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_0008: 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_002c: Unknown result type (might be due to invalid IL or missing references)
			ZPackage val = new ZPackage();
			val.Write(g.Id);
			val.Write(g.Assignment.Revision);
			val.Write(Object.op_Implicit((Object)(object)target) ? target.GetZDOID() : ZDOID.None);
			val.Write(sensed);
			val.Write(bodyguardThreat);
			ZRoutedRpc.instance.InvokeRoutedRPC("FTG_V1_Combat", new object[1] { val });
		}

		private static bool Enemy(Assignment s, ZDO target)
		{
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Invalid comparison between Unknown and I4
			if (!FCWAdapter.Ready || target == null)
			{
				return false;
			}
			long num = target.GetLong(ZDOVars.s_playerID, 0L);
			if (num != 0L)
			{
				PlayerClanInfo val = FCWAdapter.Player(num);
				if (val == null)
				{
					return false;
				}
				return Policy.Enemy(FCWAdapter.Relation(s.ClanId, val.ClanId), Plugin.Local.NeutralHostile);
			}
			Assignment assignment = State(target);
			if (assignment != null)
			{
				return Policy.Enemy(FCWAdapter.Relation(s.ClanId, assignment.ClanId), Plugin.Local.NeutralHostile);
			}
			if (target.GetBool(ZDOVars.s_tamed, false))
			{
				return false;
			}
			GameObject prefab = ZNetScene.instance.GetPrefab(target.GetPrefab());
			Character val2 = ((prefab != null) ? prefab.GetComponent<Character>() : null);
			if (Object.op_Implicit((Object)(object)val2) && (int)val2.GetFaction() != 0)
			{
				return (int)val2.GetFaction() != 10;
			}
			return false;
		}

		private static bool Threat(Assignment s, ZDO guard, ZDO target)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			if (Threats.TryGetValue((guard.m_uid, target.m_uid), out var value))
			{
				return Time.time < value;
			}
			return false;
		}

		private static bool Leashed(Assignment s, IGuardArea area, ZDO guard, ZDO target)
		{
			//IL_007e: 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_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			if (Policy.Follows(s.Order))
			{
				ZDO val = OnlinePlayer(s.FollowPlayer);
				if (val != null && FCWAdapter.Clan(s.FollowPlayer) == s.ClanId && Vector3.Distance(guard.GetPosition(), val.GetPosition()) <= Plugin.Local.FollowLeash)
				{
					if (target != null)
					{
						return Vector3.Distance(target.GetPosition(), val.GetPosition()) <= Plugin.Local.FollowLeash;
					}
					return true;
				}
				return false;
			}
			if (area.IsValid && area.DistanceOutside(guard.GetPosition()) <= Plugin.Local.Leash)
			{
				if (target != null)
				{
					return area.DistanceOutside(target.GetPosition()) <= Plugin.Local.Leash;
				}
				return true;
			}
			return false;
		}

		private unsafe static void OnCombat(long sender, ZPackage p)
		{
			//IL_0018: 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_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_029c: Unknown result type (might be due to invalid IL or missing references)
			//IL_028f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02de: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0324: Unknown result type (might be due to invalid IL or missing references)
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_025f: Unknown result type (might be due to invalid IL or missing references)
			//IL_033c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0334: Unknown result type (might be due to invalid IL or missing references)
			if (!IsServer || p.Size() > 100)
			{
				return;
			}
			ZDO zDO = ZDOMan.instance.GetZDO(p.ReadZDOID());
			int revision = p.ReadInt();
			ZDO zDO2 = ZDOMan.instance.GetZDO(p.ReadZDOID());
			bool sensed = p.ReadBool();
			bool flag = p.ReadBool();
			if (zDO == null || zDO.GetOwner() != sender || !Compatible(zDO))
			{
				return;
			}
			Assignment assignment = State(zDO);
			if (assignment == null)
			{
				return;
			}
			if (!Policy.OwnerRequest(zDO.GetOwner(), sender, revision, assignment.Revision))
			{
				CommitState(zDO, assignment);
			}
			else
			{
				if (ActiveGuards.TryGetValue(zDO.m_uid, out var value) && Time.time < value.Until - 5.7f)
				{
					return;
				}
				ActiveGuards[zDO.m_uid] = new Active
				{
					Guard = zDO,
					Until = Time.time + 6f,
					Owner = sender
				};
				IGuardArea guardArea = GuardArea.Create(assignment);
				bool flag2 = Plugin.Local.Enabled && FCWAdapter.Ready && FortecaClanWarfareApi.GetClan(assignment.ClanId) != null && Policy.WorldValid(assignment.WorldId, ZNet.instance.GetWorldUID());
				if (flag2 && ((assignment.Area == AreaKind.Territory && FCWAdapter.GeometryReady && !guardArea.IsValid) || (assignment.Area == AreaKind.Ward && !guardArea.IsValid) || (Policy.Follows(assignment.Order) && (OnlinePlayer(assignment.FollowPlayer) == null || FCWAdapter.Clan(assignment.FollowPlayer) != assignment.ClanId))))
				{
					assignment = Policy.Fallback(assignment, Policy.Follows(assignment.Order) ? GuardStore.Point(zDO.GetPosition()) : assignment.Anchor);
					CommitState(zDO, assignment);
					guardArea = GuardArea.Create(assignment);
					ManualLogSource log = Plugin.Log;
					ZDOID uid = zDO.m_uid;
					log.LogInfo((object)("FTG duty invalidated once: " + ((object)(*(ZDOID*)(&uid))/*cast due to .constrained prefix*/).ToString() + "; original clan retained."));
				}
				bool leashed = flag2 && Leashed(assignment, guardArea, zDO, zDO2);
				bool flag3 = zDO2 != null && Threat(assignment, zDO, zDO2);
				if (flag && assignment.Order == Order.Bodyguard && zDO2 != null)
				{
					ZDO val = OnlinePlayer(assignment.FollowPlayer);
					flag3 |= val != null && zDO2.GetBool(ZDOVars.s_haveTargetHash, false) && Vector3.Distance(zDO2.GetPosition(), val.GetPosition()) < Plugin.Local.Detection;
				}
				int num;
				if (zDO2 != null)
				{
					if (!Policy.Follows(assignment.Order))
					{
						num = (guardArea.Contains(zDO2.GetPosition()) ? 1 : 0);
					}
					else
					{
						Vector3 position = zDO2.GetPosition();
						ZDO obj = OnlinePlayer(assignment.FollowPlayer);
						num = ((Vector3.Distance(position, (obj != null) ? obj.GetPosition() : GuardStore.Vector(assignment.Anchor)) < Plugin.Local.Detection) ? 1 : 0);
					}
				}
				else
				{
					num = 0;
				}
				bool inside = (byte)num != 0;
				bool flag4 = zDO2 != null && Vector3.Distance(zDO2.GetPosition(), zDO.GetPosition()) <= Plugin.Local.Detection && Policy.MayEngage(assignment.Order, assignment.Behavior, Enemy(assignment, zDO2), sensed, flag3, inside, leashed, returning: false);
				SendPermit(sender, zDO.m_uid, assignment.Revision, flag4 ? zDO2.m_uid : ZDOID.None, flag2 && guardArea.IsValid, leashed);
			}
		}

		private static void SendPermit(long peer, ZDOID guard, int revision, ZDOID target, bool ready, bool leashed)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: 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)
			ZPackage val = new ZPackage();
			val.Write(guard);
			val.Write(revision);
			val.Write(target);
			val.Write(ready);
			val.Write(leashed);
			val.Write(peer);
			ZRoutedRpc.instance.InvokeRoutedRPC(peer, "FTG_V1_Permit", new object[1] { val });
			ZDO zDO = ZDOMan.instance.GetZDO(target);
			if (zDO != null && zDO.GetOwner() != peer && zDO.GetOwner() != 0L)
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(zDO.GetOwner(), "FTG_V1_Permit", new object[1] { val });
			}
		}

		private static void OnPermit(long sender, ZPackage p)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			if (FromServer(sender) && p.Size() <= 100)
			{
				ZDOID id = p.ReadZDOID();
				int revision = p.ReadInt();
				ZDOID target = p.ReadZDOID();
				bool ready = p.ReadBool();
				bool leashed = p.ReadBool();
				long owner = p.ReadLong();
				GuardController.Find(id)?.AcceptPermit(revision, target, ready, leashed, owner);
			}
		}

		internal static void ReportDamage(Character victim, Character attacker)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)victim) && Object.op_Implicit((Object)(object)attacker) && ZRoutedRpc.instance != null && ZRoutedRpc.instance == Plugin.Rpc)
			{
				ZPackage val = new ZPackage();
				val.Write(victim.GetZDOID());
				val.Write(attacker.GetZDOID());
				ZRoutedRpc.instance.InvokeRoutedRPC("FTG_V1_Damage", new object[1] { val });
			}
		}

		private static void OnDebugRead(long sender, ZPackage p)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			if (FromServer(sender) && p.Size() <= 64)
			{
				int num = p.ReadInt();
				ZDOID val = p.ReadZDOID();
				GuardController guardController = GuardController.Find(val);
				ZPackage val2 = new ZPackage();
				val2.Write(num);
				val2.Write(val);
				val2.Write((Object.op_Implicit((Object)(object)guardController) && guardController.View.IsOwner()) ? ("FTG current AI owner: " + guardController.Inspect()) : "AI instance not loaded/owned here; retry after ownership settles.");
				ZRoutedRpc.instance.InvokeRoutedRPC("FTG_V1_DebugResult", new object[1] { val2 });
			}
		}

		private static void OnDebugResult(long sender, ZPackage p)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			if (!IsServer || p.Size() > 8192)
			{
				return;
			}
			int key = p.ReadInt();
			ZDOID val = p.ReadZDOID();
			string text = p.ReadString();
			if (text.Length <= 4096 && Inspections.TryGetValue(key, out var value) && value.Owner == sender && !(value.Guard != val) && !(Time.time > value.Until))
			{
				Inspections.Remove(key);
				ZDO zDO = ZDOMan.instance.GetZDO(val);
				if (zDO == null || zDO.GetOwner() != sender)
				{
					Respond(value.Requester, "AI ownership changed during inspect; retry.");
				}
				else
				{
					Respond(value.Requester, text);
				}
			}
		}

		private static void OnDamage(long sender, ZPackage p)
		{
			//IL_002d: 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_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0247: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			if (!IsServer || p.Size() > 80 || !Rate(sender, 2, 0.1f) || !FCWAdapter.Ready)
			{
				return;
			}
			ZDO zDO = ZDOMan.instance.GetZDO(p.ReadZDOID());
			ZDO zDO2 = ZDOMan.instance.GetZDO(p.ReadZDOID());
			if (zDO == null || zDO2 == null || zDO.GetOwner() != sender || Vector3.Distance(zDO.GetPosition(), zDO2.GetPosition()) > Plugin.Local.Detection)
			{
				return;
			}
			Assignment assignment = State(zDO);
			long num = zDO.GetLong(ZDOVars.s_playerID, 0L);
			int num2 = 0;
			if (assignment != null && Enemy(assignment, zDO2))
			{
				Threats[(zDO.m_uid, zDO2.m_uid)] = Time.time + Plugin.Local.AlarmDuration;
			}
			foreach (Active value in ActiveGuards.Values)
			{
				if (num2 >= Plugin.Local.MaxResponders)
				{
					break;
				}
				if (Time.time > value.Until || value.Guard == null || value.Guard == zDO)
				{
					continue;
				}
				Assignment assignment2 = State(value.Guard);
				if (assignment2 == null)
				{
					continue;
				}
				bool num3 = num != 0L && assignment2.Order == Order.Bodyguard && assignment2.FollowPlayer == num;
				bool flag = assignment != null && assignment2.ClanId == assignment.ClanId && Vector3.Distance(zDO.GetPosition(), value.Guard.GetPosition()) <= Plugin.Local.SwarmRadius;
				if ((num3 || flag) && Enemy(assignment2, zDO2) && Leashed(assignment2, GuardArea.Create(assignment2), value.Guard, zDO2) && assignment2.Behavior != Behavior.Passive && assignment2.Order != Order.Static && !(Vector3.Distance(value.Guard.GetPosition(), zDO2.GetPosition()) > Plugin.Local.Detection))
				{
					Threats[(value.Guard.m_uid, zDO2.m_uid)] = Time.time + Plugin.Local.AlarmDuration;
					if (assignment2.Behavior != Behavior.Territorial)
					{
						SendPermit(value.Guard.GetOwner(), value.Guard.m_uid, assignment2.Revision, zDO2.m_uid, ready: true, leashed: true);
						num2++;
					}
				}
			}
		}

		internal static void Cleanup()
		{
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: 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)
			//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
			if (!IsServer || Time.time < nextCleanup)
			{
				return;
			}
			nextCleanup = Time.time + 10f;
			Expired.Clear();
			foreach (KeyValuePair<ZDOID, Active> activeGuard in ActiveGuards)
			{
				if (Time.time > activeGuard.Value.Until || ZDOMan.instance.GetZDO(activeGuard.Key) == null)
				{
					Expired.Add(activeGuard.Key);
				}
			}
			foreach (ZDOID item in Expired)
			{
				ActiveGuards.Remove(item);
			}
			List<(ZDOID, ZDOID)> list = new List<(ZDOID, ZDOID)>();
			foreach (KeyValuePair<(ZDOID, ZDOID), float> threat in Threats)
			{
				if (Time.time > threat.Value)
				{
					list.Add(threat.Key);
				}
			}
			foreach (var item2 in list)
			{
				Threats.Remove(item2);
			}
			List<(long, int)> list2 = new List<(long, int)>();
			foreach (KeyValuePair<(long, int), float> rate in Rates)
			{
				if (Time.time > rate.Value + 10f)
				{
					list2.Add(rate.Key);
				}
			}
			foreach (var item3 in list2)
			{
				Rates.Remove(item3);
			}
			List<int> list3 = new List<int>();
			foreach (KeyValuePair<int, Inspection> inspection in Inspections)
			{
				if (Time.time > inspection.Value.Until)
				{
					list3.Add(inspection.Key);
				}
			}
			foreach (int item4 in list3)
			{
				Respond(Inspections[item4].Requester, "AI owner inspect timed out; retry after ownership settles.");
				Inspections.Remove(item4);
			}
			List<ZDOID> list4 = new List<ZDOID>();
			foreach (ZDOID key in Accepted.Keys)
			{
				if (ZDOMan.instance.GetZDO(key) == null)
				{
					list4.Add(key);
				}
			}
			foreach (ZDOID item5 in list4)
			{
				Accepted.Remove(item5);
			}
			FlushAccepted();
		}

		internal static void FlushAccepted()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			if (!IsServer)
			{
				return;
			}
			foreach (KeyValuePair<ZDOID, Assignment> item in Accepted)
			{
				ZDO zDO = ZDOMan.instance.GetZDO(item.Key);
				if (zDO != null)
				{
					Assignment value = item.Value;
					ZDOID key = item.Key;
					long userID = ((ZDOID)(ref key)).UserID;
					key = item.Key;
					string text = RecordProof.Sign(value, userID, ((ZDOID)(ref key)).ID, Plugin.Local.SigningKey);
					string text2 = Convert.ToBase64String(AssignmentCodec.Encode(item.Value));
					if (zDO.GetString("FTG_V1_Record", "") != text2 || zDO.GetString("FTG_V1_Proof", "") != text)
					{
						GuardStore.Write(zDO, item.Value, text);
					}
				}
			}
		}

		internal static void Clear()
		{
			Accepted.Clear();
			ActiveGuards.Clear();
			Threats.Clear();
			Rates.Clear();
			CompatiblePeers.Clear();
			Inspections.Clear();
			nextCleanup = 0f;
		}
	}
	[HarmonyPatch(typeof(ZDOMan), "PrepareSave")]
	internal static class AuthoritativeSavePatch
	{
		private static void Prefix()
		{
			Authority.FlushAccepted();
		}
	}
	[HarmonyPatch(typeof(ZRoutedRpc), "RPC_RoutedRPC")]
	internal static class TransportPatch
	{
		private static readonly HashSet<int> Requests = new HashSet<int>
		{
			StringExtensionMethods.GetStableHashCode("FTG_V1_Command"),
			StringExtensionMethods.GetStableHashCode("FTG_V1_Combat"),
			StringExtensionMethods.GetStableHashCode("FTG_V1_Damage"),
			StringExtensionMethods.GetStableHashCode("FTG_V1_Hello"),
			StringExtensionMethods.GetStableHashCode("FTG_V1_DebugResult")
		};

		private static readonly HashSet<int> Responses = new HashSet<int>
		{
			StringExtensionMethods.GetStableHashCode("FTG_V1_Commit"),
			StringExtensionMethods.GetStableHashCode("FTG_V1_Permit"),
			StringExtensionMethods.GetStableHashCode("FTG_V1_Settings"),
			StringExtensionMethods.GetStableHashCode("FTG_V1_Reply"),
			StringExtensionMethods.GetStableHashCode("FTG_V1_DebugRead")
		};

		private static bool Prefix(ZRpc rpc, ZPackage pkg)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			int pos = pkg.GetPos();
			long claimedSender;
			long num;
			ZDOID val;
			int item;
			try
			{
				if (pkg.Size() - pos < 40)
				{
					return true;
				}
				pkg.ReadLong();
				claimedSender = pkg.ReadLong();
				num = pkg.ReadLong();
				val = pkg.ReadZDOID();
				item = pkg.ReadInt();
			}
			finally
			{
				pkg.SetPos(pos);
			}
			bool flag = Requests.Contains(item);
			bool flag2 = Responses.Contains(item);
			if (!flag && !flag2)
			{
				return true;
			}
			if (pkg.Size() > 8192 || !((ZDOID)(ref val)).IsNone() || (Object)(object)ZNet.instance == (Object)null)
			{
				return false;
			}
			long transportPeer = 0L;
			foreach (ZNetPeer peer in ZNet.instance.GetPeers())
			{
				if (peer.m_rpc == rpc)
				{
					transportPeer = peer.m_uid;
					break;
				}
			}
			long num2 = (Authority.IsServer ? ZNet.GetUID() : (ZNet.instance.GetServerPeer()?.m_uid ?? 0));
			return Policy.RpcTransport(Authority.IsServer, claimedSender, transportPeer, num2, flag, flag2, num == num2);
		}
	}
}
namespace FehuTerritoryGuards.Interaction
{
	internal static class GuardInteraction
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static ConsoleEvent <0>__Run;
		}

		private static ZDOID selected = ZDOID.None;

		private static ZDOID selectedWard = ZDOID.None;

		internal static bool ControlHeld
		{
			get
			{
				if (!Input.GetKey((KeyCode)306))
				{
					return Input.GetKey((KeyCode)305);
				}
				return true;
			}
		}

		internal static void Notify(string text)
		{
			if (Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				((Character)Player.m_localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false);
			}
			if (Object.op_Implicit((Object)(object)Console.instance))
			{
				Console.instance.Print(text);
			}
		}

		private static Tameable HoverTame()
		{
			GameObject val = (Object.op_Implicit((Object)(object)Player.m_localPlayer) ? ((Humanoid)Player.m_localPlayer).GetHoverObject() : null);
			if (!Object.op_Implicit((Object)(object)val))
			{
				return null;
			}
			return val.GetComponentInParent<Tameable>();
		}

		private static ZDOID Current()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			Tameable val = HoverTame();
			object obj;
			if (!Object.op_Implicit((Object)(object)val))
			{
				obj = null;
			}
			else
			{
				ZNetView component = ((Component)val).GetComponent<ZNetView>();
				obj = ((component != null) ? component.GetZDO() : null);
			}
			ZDO val2 = (ZDO)obj;
			if (val2 != null)
			{
				selected = val2.m_uid;
			}
			return selected;
		}

		internal static void RegisterCommands()
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			object obj = <>O.<0>__Run;
			if (obj == null)
			{
				ConsoleEvent val = Run;
				<>O.<0>__Run = val;
				obj = (object)val;
			}
			new ConsoleCommand("ftg", "select | ward | order <Stay|Follow|Bodyguard|FollowAttack|GuardPosition|GuardRadius|GuardWard|GuardTerritory|Static> [radius] | behavior <Passive|Defensive|Territorial|Aggressive> | lock <on|off> | inspect", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
		}

		private unsafe static void Run(ConsoleEventArgs args)
		{
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0249: Unknown result type (might be due to invalid IL or missing references)
			//IL_02af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_0269: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ce: Unknown result type (might be due to invalid IL or missing references)
			if (args.Length < 2)
			{
				Notify("ftg select; ftg ward; ftg order <name> [radius]; ftg behavior <name>; ftg lock on/off; ftg inspect");
				return;
			}
			if (Plugin.Rpc == null)
			{
				Notify("Not connected to a world.");
				return;
			}
			if (args[1].Equals("ward", StringComparison.OrdinalIgnoreCase))
			{
				GameObject val = (Object.op_Implicit((Object)(object)Player.m_localPlayer) ? ((Humanoid)Player.m_localPlayer).GetHoverObject() : null);
				PrivateArea val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponentInParent<PrivateArea>() : null);
				if (Object.op_Implicit((Object)(object)val2))
				{
					selectedWard = ((Component)val2).GetComponent<ZNetView>().GetZDO().m_uid;
					ZDOID val3 = selectedWard;
					Notify("Ward selected: " + ((object)(*(ZDOID*)(&val3))/*cast due to .constrained prefix*/).ToString());
				}
				else
				{
					Notify("Look at a Ward, close the console, then Ctrl+E to select it.");
				}
				return;
			}
			ZDOID val4 = Current();
			if (((ZDOID)(ref val4)).IsNone())
			{
				Notify("Look at a tame and use Ctrl+E to select it first.");
				return;
			}
			Assignment assignment = GuardStore.Read(ZDOMan.instance.GetZDO(val4));
			switch (args[1].ToLowerInvariant())
			{
			case "select":
			{
				ZDOID val3 = val4;
				Notify("Guard selected: " + ((object)(*(ZDOID*)(&val3))/*cast due to .constrained prefix*/).ToString());
				break;
			}
			case "order":
			{
				if (args.Length < 3 || !Enum.TryParse<Order>(args[2], ignoreCase: true, out var result2) || !Enum.IsDefined(typeof(Order), result2))
				{
					Notify("Unknown V1 order.");
					break;
				}
				float result3 = 20f;
				if (args.Length > 3 && (!float.TryParse(args[3], NumberStyles.Float, CultureInfo.InvariantCulture, out result3) || !Policy.Finite(result3)))
				{
					Notify("Invalid radius.");
					break;
				}
				Behavior behavior = (Behavior)(((int?)assignment?.Behavior) ?? ((result2 != Order.FollowAttack) ? 1 : 3));
				if (result2 == Order.FollowAttack)
				{
					behavior = Behavior.Aggressive;
				}
				Authority.SendCommand(val4, 1, result2, behavior, result3, selectedWard, locked: false);
				break;
			}
			case "behavior":
			{
				if (args.Length < 3 || !Enum.TryParse<Behavior>(args[2], ignoreCase: true, out var result) || !Enum.IsDefined(typeof(Behavior), result))
				{
					Notify("Unknown behavior.");
				}
				else
				{
					Authority.SendCommand(val4, 2, assignment?.Order ?? Order.Stay, result, assignment?.Radius ?? 20f, selectedWard, locked: false);
				}
				break;
			}
			case "lock":
				if (args.Length != 3 || (args[2] != "on" && args[2] != "off"))
				{
					Notify("Use ftg lock on/off.");
				}
				else
				{
					Authority.SendCommand(val4, 3, assignment?.Order ?? Order.Stay, assignment?.Behavior ?? Behavior.Defensive, 20f, selectedWard, args[2] == "on");
				}
				break;
			case "inspect":
				Authority.SendCommand(val4, 4, Order.Stay, Behavior.Passive, 20f, selectedWard, locked: false);
				break;
			default:
				Notify("Unknown ftg action.");
				break;
			}
		}

		internal static void SelectWard(PrivateArea pa)
		{
			//IL_0020: 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 (Object.op_Implicit((Object)(object)pa))
			{
				ZNetView component = ((Component)pa).GetComponent<ZNetView>();
				ZDO val = ((component != null) ? component.GetZDO() : null);
				if (val != null)
				{
					selectedWard = val.m_uid;
					Notify("Ward selected for GuardWard.");
				}
			}
		}

		internal static bool Interact(Tameable tame, bool hold)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: 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_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			if (hold)
			{
				return false;
			}
			ZNetView component = ((Component)tame).GetComponent<ZNetView>();
			ZDO val = ((component != null) ? component.GetZDO() : null);
			if (val == null || !tame.IsTamed())
			{
				return false;
			}
			selected = val.m_uid;
			Assignment assignment = GuardStore.Read(val);
			if (Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303))
			{
				Authority.SendCommand(selected, 2, assignment?.Order ?? Order.Stay, (Behavior)((int)((assignment?.Behavior ?? Behavior.Passive) + 1) % 4), assignment?.Radius ?? 20f, selectedWard, locked: false);
			}
			else
			{
				Order order = ((assignment != null) ? ((Order)((int)(assignment.Order + 1) % 9)) : Order.Stay);
				Authority.SendCommand(selected, 1, order, (order == Order.FollowAttack) ? Behavior.Aggressive : (assignment?.Behavior ?? Behavior.Defensive), assignment?.Radius ?? 20f, selectedWard, locked: false);
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Tameable), "GetHoverText")]
	internal static class HoverPatch
	{
		private static void Postfix(Tameable __instance, ref string __result)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
			Assignment assignment = GuardStore.Read((component != null) ? component.GetZDO() : null);
			if (assignment == null)
			{
				if (__instance.IsTamed())
				{
					__result += "\n[Ctrl+Use] Assign/select clan guard";
				}
				return;
			}
			object obj;
			if (assignment.Area != AreaKind.Territory)
			{
				obj = ((assignment.Area == AreaKind.Ward) ? ("Ward " + ((object)GuardStore.WardId(assignment)/*cast due to .constrained prefix*/).ToString()) : assignment.Area.ToString());
			}
			else
			{
				ClanTerritory obj2 = FCWAdapter.Territory(assignment.TerritoryId);
				obj = ((obj2 != null) ? obj2.DisplayName : null) ?? assignment.TerritoryId;
			}
			string text = (string)obj;
			__result = __result + $"\nClan: {FCWAdapter.ClanName(assignment.ClanId)}\nDuty: {assignment.Order}\nArea: {text}\nBehavior: {assignment.Behavior}" + (assignment.Locked ? "\nDuty locked" : "") + "\n[Ctrl+Use] Next duty  [Ctrl+Shift+Use] Behavior\nConsole: ftg";
		}
	}
	[HarmonyPatch(typeof(Tameable), "Interact")]
	internal static class InteractionPatch
	{
		private static bool Prefix(Tameable __instance, bool hold, bool alt, ref bool __result)
		{
			if (alt || !GuardInteraction.ControlHeld || Plugin.Rpc == null)
			{
				return true;
			}
			__result = GuardInteraction.Interact(__instance, hold);
			return !__result;
		}
	}
	[HarmonyPatch(typeof(PrivateArea), "Interact")]
	internal static class WardSelectPatch
	{
		private static bool Prefix(PrivateArea __instance, bool hold, bool alt, ref bool __result)
		{
			if (alt || hold || !GuardInteraction.ControlHeld)
			{
				return true;
			}
			GuardInteraction.SelectWard(__instance);
			__result = true;
			return false;
		}
	}
}
namespace FehuTerritoryGuards.Faction
{
	internal static class FCWAdapter
	{
		private static readonly Dictionary<long, (Relation relation, float until)> Relations = new Dictionary<long, (Relation, float)>();

		internal static bool Ready
		{
			get
			{
				if ((Object)(object)WarfareManager.Instance != (Object)null && WarfareManager.Instance.IsServerDataReady)
				{
					return WarfareManager.Instance.Data != null;
				}
				return false;
			}
		}

		internal static bool GeometryReady
		{
			get
			{
				if (Ready && VoronoiGrid.Instance != null)
				{
					return VoronoiGrid.Instance.IsInitialized;
				}
				return false;
			}
		}

		internal static PlayerClanInfo Player(long id)
		{
			if (!Ready)
			{
				return null;
			}
			return WarfareManager.Instance.Data.GetPlayer(id);
		}

		internal static int Clan(long id)
		{
			return Player(id)?.ClanId ?? 0;
		}

		internal static bool Leader(long id)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Invalid comparison between Unknown and I4
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Invalid comparison between Unknown and I4
			PlayerClanInfo val = Player(id);
			if (val != null)
			{
				if ((int)val.Rank != 2)
				{
					return (int)val.Rank == 1;
				}
				return true;
			}
			return false;
		}

		internal static Relation Relation(int a, int b)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected I4, but got Unknown
			if (!Ready)
			{
				return FehuTerritoryGuards.Core.Relation.Unknown;
			}
			long key = ((long)a << 32) | (uint)b;
			if (Relations.TryGetValue(key, out (Relation, float) value) && Time.time < value.Item2)
			{
				return value.Item1;
			}
			Relation relation = Policy.Map(ready: true, a, b, (int)FortecaClanWarfareApi.GetClanRelation(a, b));
			if (Relations.Count > 2048)
			{
				Relations.Clear();
			}
			Relations[key] = (relation, Time.time + 1f);
			return relation;
		}

		internal static ClanTerritory Territory(string id)
		{
			if (!GeometryReady || string.IsNullOrEmpty(id))
			{
				return null;
			}
			if (!WarfareManager.Instance.Data.Territories.TryGetValue(id, out var value))
			{
				return null;
			}
			return value;
		}

		internal static string TerritoryAt(Vector3 p)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			if (!GeometryReady)
			{
				return "";
			}
			Vector2i region = VoronoiGrid.Instance.GetRegion(p);
			return region.x + "," + region.y;
		}

		internal static string ClanName(int id)
		{
			return FortecaClanWarfareApi.GetClan(id)?.Name ?? ("#" + id);
		}

		internal static void Clear()
		{
			Relations.Clear();
		}
	}
}
namespace FehuTerritoryGuards.Core
{
	public enum Order
	{
		Stay,
		Follow,
		Bodyguard,
		FollowAttack,
		GuardPosition,
		GuardRadius,
		GuardWard,
		GuardTerritory,
		Static
	}
	public enum Behavior
	{
		Passive,
		Defensive,
		Territorial,
		Aggressive
	}
	public enum AreaKind
	{
		Point,
		Radius,
		Ward,
		Territory
	}
	public enum Relation
	{
		Unknown,
		Friend,
		Neutral,
		Hostile
	}
	public enum DutyState
	{
		Idle,
		SelectingPoint,
		Moving,
		Waiting,
		Combat,
		Returning,
		Follow,
		Disabled
	}
	public struct Point
	{
		public float X;

		public float Y;

		public float Z;

		public bool Finite
		{
			get
			{
				if (Policy.Finite(X) && Policy.Finite(Y))
				{
					return Policy.Finite(Z);
				}
				return false;
			}
		}

		public Point(float x, float y, float z)
		{
			X = x;
			Y = y;
			Z = z;
		}

		public float DistanceXZ(Point p)
		{
			float num = X - p.X;
			float num2 = Z - p.Z;
			return (float)Math.Sqrt(num * num + num2 * num2);
		}
	}
	public sealed class Assignment
	{
		public const int CurrentVersion = 1;

		public int Version = 1;

		public int Revision = 1;

		public int ClanId;

		public Order Order;

		public Behavior Behavior;

		public AreaKind Area;

		public Point Anchor;

		public float Radius = 20f;

		public long OriginalOwner;

		public long FollowPlayer;

		public long WorldId;

		public long WardUser;

		public uint WardId;

		public string TerritoryId = "";

		public bool Locked;

		public Assignment Copy()
		{
			return (Assignment)MemberwiseClone();
		}
	}
	public static class Policy
	{
		public static bool Finite(float f)
		{
			if (!float.IsNaN(f))
			{
				return !float.IsInfinity(f);
			}
			return false;
		}

		public static Relation Map(bool ready, int a, int b, int diplomacy)
		{
			if (!ready || a <= 0)
			{
				return Relation.Unknown;
			}
			if (b == a)
			{
				return Relation.Friend;
			}
			if (b <= 0)
			{
				return Relation.Neutral;
			}
			switch (diplomacy)
			{
			case 1:
			case 2:
				return Relation.Friend;
			case 3:
			case 4:
				return Relation.Hostile;
			case 0:
				return Relation.Neutral;
			default:
				return Relation.Unknown;
			}
		}

		public static bool Enemy(Relation relation, bool neutralHostile)
		{
			if (relation != Relation.Hostile)
			{
				return relation == Relation.Neutral && neutralHostile;
			}
			return true;
		}

		public static bool Follows(Order o)
		{
			if (o != Order.Follow && o != Order.Bodyguard)
			{
				return o == Order.FollowAttack;
			}
			return true;
		}

		public static bool Patrols(Order o)
		{
			if (o != Order.GuardRadius && o != Order.GuardWard)
			{
				return o == Order.GuardTerritory;
			}
			return true;
		}

		public static AreaKind RequiredArea(Order o)
		{
			return o switch
			{
				Order.GuardTerritory => AreaKind.Territory, 
				Order.GuardWard => AreaKind.Ward, 
				Order.GuardRadius => AreaKind.Radius, 
				_ => AreaKind.Point, 
			};
		}

		public static bool Valid(Assignment s)
		{
			if (s != null && s.Version == 1 && s.Revision > 0 && s.ClanId > 0 && Enum.IsDefined(typeof(Order), s.Order) && Enum.IsDefined(typeof(Behavior), s.Behavior) && Enum.IsDefined(typeof(AreaKind), s.Area) && s.Area == RequiredArea(s.Order) && s.Anchor.Finite && Math.Abs(s.Anchor.X) <= 20000f && Math.Abs(s.Anchor.Z) <= 20000f && Math.Abs(s.Anchor.Y) <= 10000f && Finite(s.Radius) && s.Radius >= 1f && s.Radius <= 500f && s.OriginalOwner != 0L && (!Follows(s.Order) || s.FollowPlayer != 0L) && (s.Area != AreaKind.Ward || (s.WardUser != 0L && s.WardId != 0)))
			{
				if (s.Area == AreaKind.Territory)
				{
					if (!string.IsNullOrWhiteSpace(s.TerritoryId))
					{
						return s.TerritoryId.Length <= 64;
					}
					return false;
				}
				return true;
			}
			return false;
		}

		public static bool CanEdit(int guardClan, int actorClan, bool locked, bool leader, bool admin)
		{
			if (!admin)
			{
				if (guardClan > 0 && guardClan == actorClan)
				{
					return !locked || leader;
				}
				return false;
			}
			return true;
		}

		public static bool OwnerRequest(long owner, long sender, int revision, int acceptedRevision)
		{
			if (owner != 0L && owner == sender && revision > 0)
			{
				return revision == acceptedRevision;
			}
			return false;
		}

		public static bool CurrentPermit(long owner, long permitOwner, float now, float until)
		{
			if (owner != 0L && owner == permitOwner && Finite(now) && Finite(until))
			{
				return now < until;
			}
			return false;
		}

		public static bool WorldValid(long assignedWorld, long currentWorld)
		{
			if (currentWorld != 0L)
			{
				return assignedWorld == currentWorld;
			}
			return false;
		}

		public static bool RpcTransport(bool server, long claimedSender, long transportPeer, long serverPeer, bool request, bool response, bool addressedToServer)
		{
			if (transportPeer == 0L || claimedSender != transportPeer)
			{
				return false;
			}
			if (!server)
			{
				if (response && !request)
				{
					return transportPeer == serverPeer;
				}
				return false;
			}
			return request && !response && addressedToServer;
		}

		public static bool TerritoryValid(bool ready, int guardClan, int ownerClan, bool abandoned)
		{
			if (ready && guardClan > 0 && guardClan == ownerClan)
			{
				return !abandoned;
			}
			return false;
		}

		public static bool CircularContains(Point anchor, float radius, Point p)
		{
			if (anchor.Finite && p.Finite && Finite(radius) && radius > 0f)
			{
				return anchor.DistanceXZ(p) <= radius;
			}
			return false;
		}

		public static float CircularOutside(Point anchor, float radius, Point p)
		{
			return Math.Max(0f, anchor.DistanceXZ(p) - radius);
		}

		public static float BoundaryUpperBound(Point position, Point knownInterior, Func<Point, bool> contains, out Point interior)
		{
			interior = knownInterior;
			if (!position.Finite || !knownInterior.Finite || !contains(knownInterior))
			{
				return float.PositiveInfinity;
			}
			if (contains(position))
			{
				interior = position;
				return 0f;
			}
			Point point = position;
			for (int i = 0; i < 10; i++)
			{
				Point point2 = new Point((interior.X + point.X) / 2f, (interior.Y + point.Y) / 2f, (interior.Z + point.Z) / 2f);
				if (contains(point2))
				{
					interior = point2;
				}
				else
				{
					point = point2;
				}
			}
			return position.DistanceXZ(interior);
		}

		public static bool MayEngage(Order order, Behavior behavior, bool enemy, bool sensed, bool directThreat, bool inside, bool leashed, bool returning)
		{
			if (!(!enemy || !leashed || returning) && order != Order.Static)
			{
				switch (behavior)
				{
				case Behavior.Passive:
					break;
				case Behavior.Defensive:
					return directThreat;
				case Behavior.Territorial:
					return sensed && inside;
				case Behavior.Aggressive:
					return sensed || directThreat;
				default:
					return false;
				}
			}
			return false;
		}

		public static DutyState CombatTransition(bool returning, bool guardLeashed, bool targetLeashed, bool target, bool reachedHome)
		{
			if (returning)
			{
				if (!reachedHome)
				{
					return DutyState.Returning;
				}
				return DutyState.Idle;
			}
			if (!guardLeashed || (target && !targetLeashed))
			{
				return DutyState.Returning;
			}
			if (!target)
			{
				return DutyState.Idle;
			}
			return DutyState.Combat;
		}

		public static Assignment Fallback(Assignment s, Point safeAnchor)
		{
			Assignment assignment = s.Copy();
			assignment.Order = Order.Stay;
			assignment.Area = AreaKind.Point;
			assignment.Anchor = safeAnchor;
			assignment.FollowPlayer = 0L;
			assignment.WardUser = 0L;
			assignment.WardId = 0u;
			assignment.TerritoryId = "";
			assignment.Revision = checked(s.Revision + 1);
			return assignment;
		}
	}
	public static class AssignmentCodec
	{
		public const int MaxBytes = 512;

		public static byte[] Encode(Assignment s)
		{
			if (!Policy.Valid(s))
			{
				throw new InvalidDataException("Invalid FTG assignment");
			}
			using MemoryStream memoryStream = new MemoryStream();
			using BinaryWriter binaryWriter = new BinaryWriter(memoryStream, Encoding.UTF8);
			binaryWriter.Write(s.Version);
			binaryWriter.Write(s.Revision);
			binaryWriter.Write(s.ClanId);
			binaryWriter.Write((int)s.Order);
			binaryWriter.Write((int)s.Behavior);
			binaryWriter.Write((int)s.Area);
			binaryWriter.Write(s.Anchor.X);
			binaryWriter.Write(s.Anchor.Y);
			binaryWriter.Write(s.Anchor.Z);
			binaryWriter.Write(s.Radius);
			binaryWriter.Write(s.OriginalOwner);
			binaryWriter.Write(s.FollowPlayer);
			binaryWriter.Write(s.WorldId);
			binaryWriter.Write(s.WardUser);
			binaryWriter.Write(s.WardId);
			binaryWriter.Write(s.TerritoryId ?? "");
			binaryWriter.Write(s.Locked);
			return memoryStream.ToArray();
		}

		public static bool TryDecode(byte[] bytes, out Assignment s)
		{
			s = null;
			if (bytes == null || bytes.Length > 512 || bytes.Length < 78)
			{
				return false;
			}
			try
			{
				using MemoryStream memoryStream = new MemoryStream(bytes);
				using BinaryReader binaryReader = new BinaryReader(memoryStream, Encoding.UTF8);
				Assignment assignment = new Assignment
				{
					Version = binaryReader.ReadInt32(),
					Revision = binaryReader.ReadInt32(),
					ClanId = binaryReader.ReadInt32(),
					Order = (Order)binaryReader.ReadInt32(),
					Behavior = (Behavior)binaryReader.ReadInt32(),
					Area = (AreaKind)binaryReader.ReadInt32(),
					Anchor = new Point(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle()),
					Radius = binaryReader.ReadSingle(),
					OriginalOwner = binaryReader.ReadInt64(),
					FollowPlayer = binaryReader.ReadInt64(),
					WorldId = binaryReader.ReadInt64(),
					WardUser = binaryReader.ReadInt64(),
					WardId = binaryReader.ReadUInt32(),
					TerritoryId = binaryReader.ReadString(),
					Locked = binaryReader.ReadBoolean()
				};
				if (memoryStream.Position != memoryStream.Length || !Policy.Valid(assignment))
				{
					return false;
				}
				s = assignment;
				return true;
			}
			catch (IOException)
			{
				return false;
			}
			catch (ArgumentException)
			{
				return false;
			}
			catch (FormatException)
			{
				return false;
			}
		}
	}
	public static class RecordProof
	{
		public static string Sign(Assignment s, long zdoUser, uint zdoId, byte[] key)
		{
			if (key == null || key.Length != 32)
			{
				throw new ArgumentException("FTG signing key must contain 32 bytes");
			}
			using MemoryStream memoryStream = new MemoryStream();
			using BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
			binaryWriter.Write(zdoUser);
			binaryWriter.Write(zdoId);
			binaryWriter.Write(AssignmentCodec.Encode(s));
			using HMACSHA256 hMACSHA = new HMACSHA256(key);
			return Convert.ToBase64String(hMACSHA.ComputeHash(memoryStream.ToArray()));
		}

		public static bool Verify(Assignment s, long zdoUser, uint zdoId, byte[] key, string proof)
		{
			if (s == null || proof == null || proof.Length != 44 || key == null || key.Length != 32)
			{
				return false;
			}
			try
			{
				byte[] array = Convert.FromBase64String(Sign(s, zdoUser, zdoId, key));
				byte[] array2 = Convert.FromBase64String(proof);
				if (array2.Length != array.Length)
				{
					return false;
				}
				int num = 0;
				for (int i = 0; i < array.Length; i++)
				{
					num |= array[i] ^ array2[i];
				}
				return num == 0;
			}
			catch (FormatException)
			{
				return false;
			}
			catch (InvalidDataException)
			{
				return false;
			}
		}
	}
	internal sealed class Settings
	{
		internal bool Enabled = true;

		internal bool NeutralHostile;

		internal bool Debug;

		internal float Decision = 0.75f;

		internal float Detection = 30f;

		internal float Leash = 15f;

		internal float FollowLeash = 35f;

		internal float PointRadius = 3f;

		internal float MaxRadius = 200f;

		internal float SwarmRadius = 30f;

		internal float AlarmDuration = 10f;

		internal float PatrolWait = 5f;

		internal float MaxHeight = 10f;

		internal float MaxSlope = 45f;

		internal int MaxResponders = 8;

		internal int Attempts = 6;

		internal int DecisionsPerFrame = 4;

		internal int CandidateBudget = 12;

		internal string Blacklist = "";

		internal byte[] SigningKey;

		internal static Settings Load(ConfigFile c)
		{
			byte[] array = new byte[32];
			using (RandomNumberGenerator randomNumberGenerator = RandomNumberGenerator.Create())
			{
				randomNumberGenerator.GetBytes(array);
			}
			string s = B<string>("Authority", "RecordSigningKey", Convert.ToBase64String(array), "Server-private ZDO record signing key. Never synchronized. Preserve with test-world backups; changing it invalidates assignments.");
			byte[] array2;
			try
			{
				array2 = Convert.FromBase64String(s);
			}
			catch (FormatException)
			{
				throw new InvalidOperationException("FTG RecordSigningKey is corrupt; restore the server configuration backup.");
			}
			if (array2.Length != 32)
			{
				throw new InvalidOperationException("FTG RecordSigningKey must contain 32 bytes; restore the server configuration backup.");
			}
			return new Settings
			{
				SigningKey = array2,
				Enabled = B<bool>("General", "Enabled", value: true, "Server authority. Enable assigned guards."),
				NeutralHostile = B<bool>("Faction", "NeutralIsHostile", value: false, "Neutral clans and clanless players are hostile when enabled; unknown FCW identities remain protected."),
				Detection = B<float>("Combat", "DetectionRange", 30f, "Maximum sensed target distance, metres (5..100)."),
				Leash = B<float>("Combat", "OutsideAreaLeash", 15f, "Maximum excursion outside duty area, metres (1..100)."),
				FollowLeash = B<float>("Combat", "FollowLeash", 35f, "Maximum distance from protected player (5..100)."),
				PointRadius = B<float>("Guard", "PointRadius", 3f, "Return tolerance around anchor (1..10)."),
				MaxRadius = B<float>("Guard", "MaximumRadius", 200f, "Maximum user radius (5..500)."),
				PatrolWait = B<float>("Guard", "PatrolWait", 5f, "Seconds at patrol destination (1..30)."),
				MaxHeight = B<float>("Guard", "MaximumHeightDifference", 10f, "Reject patrol points with larger height differences (1..30)."),
				MaxSlope = B<float>("Guard", "MaximumGroundSlope", 45f, "Reject steeper ground (5..60 degrees)."),
				SwarmRadius = B<float>("Swarm", "Radius", 30f, "Local same-clan alarm radius (1..100)."),
				AlarmDuration = B<float>("Swarm", "Duration", 10f, "Seconds for a direct-threat alarm (1..30)."),
				MaxResponders = B<int>("Swarm", "MaxResponders", 8, "Maximum additional guards per local alarm (0..25)."),
				Decision = B<float>("Performance", "DecisionInterval", 0.75f, "Staggered per-guard seconds (0.3..3)."),
				Attempts = B<int>("Performance", "PatrolAttempts", 6, "Bounded point retries per decision (1..12)."),
				DecisionsPerFrame = B<int>("Performance", "DecisionsPerFrame", 4, "Maximum expensive guard decisions per frame (1..10)."),
				CandidateBudget = B<int>("Performance", "CandidateBudget", 12, "Maximum nearby target candidates inspected per decision (1..32)."),
				Blacklist = B<string>("Compatibility", "PrefabBlacklist", "", "Comma-separated exact prefab names excluded from commands."),
				Debug = B<bool>("Debug", "Logging", value: false, "Optional diagnostics; disabled normally.")
			}.Normalize();
			T B<T>(string section, string key, T value, string description)
			{
				return c.Bind<T>(section, key, value, description).Value;
			}
		}

		internal Settings Normalize()
		{
			Decision = C(Decision, 0.3f, 3f, 0.75f);
			Detection = C(Detection, 5f, 100f, 30f);
			Leash = C(Leash, 1f, 100f, 15f);
			FollowLeash = C(FollowLeash, 5f, 100f, 35f);
			PointRadius = C(PointRadius, 1f, 10f, 3f);
			MaxRadius = C(MaxRadius, 5f, 500f, 200f);
			SwarmRadius = C(SwarmRadius, 1f, 100f, 30f);
			AlarmDuration = C(AlarmDuration, 1f, 30f, 10f);
			PatrolWait = C(PatrolWait, 1f, 30f, 5f);
			MaxHeight = C(MaxHeight, 1f, 30f, 10f);
			MaxSlope = C(MaxSlope, 5f, 60f, 45f);
			MaxResponders = I(MaxResponders, 0, 25);
			Attempts = I(Attempts, 1, 12);
			DecisionsPerFrame = I(DecisionsPerFrame, 1, 10);
			CandidateBudget = I(CandidateBudget, 1, 32);
			Blacklist = (((Blacklist ?? "").Length <= 1024) ? (Blacklist ?? "") : "");
			return this;
			static float C(float x, float lo, float hi, float fallback)
			{
				if (!Policy.Finite(x))
				{
					return fallback;
				}
				return Math.Max(lo, Math.Min(hi, x));
			}
			static int I(int x, int lo, int hi)
			{
				return Math.Max(lo, Math.Min(hi, x));
			}
		}

		internal bool Excluded(string prefab)
		{
			string[] array = Blacklist.Split(new char[1] { ',' });
			for (int i = 0; i < array.Length; i++)
			{
				if (string.Equals(array[i].Trim(), prefab, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return false;
		}

		internal void Write(ZPackage p)
		{
			p.Write(1);
			p.Write(Enabled);
			p.Write(NeutralHostile);
			p.Write(Decision);
			p.Write(Detection);
			p.Write(Leash);
			p.Write(FollowLeash);
			p.Write(PointRadius);
			p.Write(MaxRadius);
			p.Write(SwarmRadius);
			p.Write(AlarmDuration);
			p.Write(PatrolWait);
			p.Write(MaxHeight);
			p.Write(MaxSlope);
			p.Write(MaxResponders);
			p.Write(Attempts);
			p.Write(DecisionsPerFrame);
			p.Write(CandidateBudget);
			p.Write(Blacklist);
		}

		internal static Settings Read(ZPackage p)
		{
			if (p.Size() > 2048 || p.ReadInt() != 1)
			{
				throw new InvalidDataException("FTG settings version");
			}
			return new Settings
			{
				Enabled = p.ReadBool(),
				NeutralHostile = p.ReadBool(),
				Decision = p.ReadSingle(),
				Detection = p.ReadSingle(),
				Leash = p.ReadSingle(),
				FollowLeash = p.ReadSingle(),
				PointRadius = p.ReadSingle(),
				MaxRadius = p.ReadSingle(),
				SwarmRadius = p.ReadSingle(),
				AlarmDuration = p.ReadSingle(),
				PatrolWait = p.ReadSingle(),
				MaxHeight = p.ReadSingle(),
				MaxSlope = p.ReadSingle(),
				MaxResponders = p.ReadInt(),
				Attempts = p.ReadInt(),
				DecisionsPerFrame = p.ReadInt(),
				CandidateBudget = p.ReadInt(),
				Blacklist = p.ReadString()
			}.Normalize();
		}
	}
}
namespace FehuTerritoryGuards.Areas
{
	internal interface IGuardArea
	{
		bool IsValid { get; }

		Vector3 Anchor { get; }

		float SamplingRadius { get; }

		string Identity { get; }

		bool Contains(Vector3 p);

		float DistanceOutside(Vector3 p);

		bool TryGetPatrolPoint(GuardController guard, out Vector3 p);
	}
	internal abstract class GuardArea : IGuardArea
	{
		internal readonly Assignment Assignment;

		public abstract bool IsValid { get; }

		public virtual Vector3 Anchor => GuardStore.Vector(Assignment.Anchor);

		public abstract float SamplingRadius { get; }

		public abstract string Identity { get; }

		protected GuardArea(Assignment s)
		{
			Assignment = s;
		}

		public abstract bool Contains(Vector3 p);

		public abstract float DistanceOutside(Vector3 p);

		public bool TryGetPatrolPoint(GuardController guard, out Vector3 p)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			p = Anchor;
			if (!IsValid)
			{
				return false;
			}
			float num = Mathf.Min(SamplingRadius, 40f);
			Vector3 val = (Contains(((Component)guard).transform.position) ? ((Component)guard).transform.position : Anchor);
			for (int i = 0; i < Plugin.Effective.Attempts; i++)
			{
				Vector2 val2 = Random.insideUnitCircle * num;
				Vector3 candidate = val + new Vector3(val2.x, 0f, val2.y);
				if (Navigation.TryPoint(guard, this, candidate, out p))
				{
					return true;
				}
			}
			return false;
		}

		internal static IGuardArea Create(Assignment s)
		{
			return s.Area switch
			{
				AreaKind.Ward => new WardArea(s), 
				AreaKind.Territory => new TerritoryArea(s), 
				_ => new CircleArea(s), 
			};
		}
	}
	internal sealed class CircleArea : GuardArea
	{
		public override bool IsValid => Policy.Valid(Assignment);

		public override float SamplingRadius
		{
			get
			{
				if (Assignment.Area != AreaKind.Point)
				{
					return Assignment.Radius;
				}
				return Plugin.Effective.PointRadius;
			}
		}

		public override string Identity
		{
			get
			{
				if (Assignment.Area != AreaKind.Point)
				{
					return "Radius " + Assignment.Radius.ToString("0.0") + "m";
				}
				return "Anchor";
			}
		}

		internal CircleArea(Assignment s)
			: base(s)
		{
		}

		public override bool Contains(Vector3 p)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			return Policy.CircularContains(Assignment.Anchor, SamplingRadius, GuardStore.Point(p));
		}

		public override float DistanceOutside(Vector3 p)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			return Policy.CircularOutside(Assignment.Anchor, SamplingRadius, GuardStore.Point(p));
		}
	}
	internal sealed class WardArea : GuardArea
	{
		internal ZDO Ward
		{
			get
			{
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				ZDOMan instance = ZDOMan.instance;
				if (instance == null)
				{
					return null;
				}
				return instance.GetZDO(GuardStore.WardId(Assignment));
			}
		}

		internal PrivateArea Prefab
		{
			get
			{
				if (Ward != null)
				{
					ZNetScene instance = ZNetScene.instance;
					if (instance == null)
					{
						return null;
					}
					GameObject prefab = instance.GetPrefab(Ward.GetPrefab());
					if (prefab == null)
					{
						return null;
					}
					return prefab.GetComponent<PrivateArea>();
				}
				return null;
			}
		}

		public override bool IsValid
		{
			get
			{
				//IL_0064: Unknown result type (might be due to invalid IL or missing references)
				if (Ward != null && (Object)(object)Prefab != (Object)null && Assignment.WorldId == ZNet.instance.GetWorldUID() && Ward.GetBool(ZDOVars.s_enabled, false) && WardAccess(Ward, Assignment.OriginalOwner))
				{
					return Contains(GuardStore.Vector(Assignment.Anchor));
				}
				return false;
			}
		}

		public override Vector3 Anchor
		{
			get
			{
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				ZDO ward = Ward;
				if (ward == null)
				{
					return base.Anchor;
				}
				return ward.GetPosition();
			}
		}

		public override float SamplingRadius
		{
			get
			{
				if (!((Object)(object)Prefab != (Object)null))
				{
					return Assignment.Radius;
				}
				return Prefab.m_radius;
			}
		}

		public override string Identity => "Ward " + ((object)GuardStore.WardId(Assignment)/*cast due to .constrained prefix*/).ToString();

		internal WardArea(Assignment s)
			: base(s)
		{
		}

		public override bool Contains(Vector3 p)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			return Policy.CircularContains(GuardStore.Point(Anchor), SamplingRadius, GuardStore.Point(p));
		}

		public override float DistanceOutside(Vector3 p)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			return Policy.CircularOutside(GuardStore.Point(Anchor), SamplingRadius, GuardStore.Point(p));
		}

		internal static bool WardAccess(ZDO z, long player)
		{
			if (z.GetLong(ZDOVars.s_creator, 0L) == player)
			{
				return true;
			}
			int num = Math.Min(128, Math.Max(0, z.GetInt(ZDOVars.s_permitted, 0)));
			for (int i = 0; i < num; i++)
			{
				if (z.GetLong("pu_id" + i, 0L) == player)
				{
					return true;
				}
			}
			return false;
		}
	}
	internal sealed class TerritoryArea : GuardArea
	{
		private readonly Dictionary<(int, int), (Point inside, float until)> borders = new Dictionary<(int, int), (Point, float)>();

		private ClanTerritory Territory => FCWAdapter.Territory(Assignment.TerritoryId);

		public override bool IsValid
		{
			get
			{
				//IL_0058: Unknown result type (might be due to invalid IL or missing references)
				if (Territory != null && Policy.TerritoryValid(FCWAdapter.GeometryReady, Assignment.ClanId, Territory.OwnerClanId, Territory.IsAbandoned) && Assignment.WorldId == ZNet.instance.GetWorldUID())
				{
					return Contains(GuardStore.Vector(Assignment.Anchor));
				}
				return false;
			}
		}

		public override float SamplingRadius
		{
			get
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				if (Territory != null)
				{
					return VoronoiGrid.Instance.GetApproximateRegionRadius(Territory.GridPosition);
				}
				return 0f;
			}
		}

		public override string Identity
		{
			get
			{
				ClanTerritory territory = Territory;
				return ((territory != null) ? territory.DisplayName : null) ?? Assignment.TerritoryId;
			}
		}

		internal TerritoryArea(Assignment s)
			: base(s)
		{
		}

		public override bool Contains(Vector3 p)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			if (FCWAdapter.GeometryReady)
			{
				return FCWAdapter.TerritoryAt(p) == Assignment.TerritoryId;
			}
			return false;
		}

		public override float DistanceOutside(Vector3 p)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			if (Contains(p))
			{
				return 0f;
			}
			(int, int) key = (Mathf.FloorToInt(p.x / 8f), Mathf.FloorToInt(p.z / 8f));
			Point position = GuardStore.Point(p);
			if (borders.TryGetValue(key, out (Point, float) value) && Time.time < value.Item2 && Contains(GuardStore.Vector(value.Item1)))
			{
				return position.DistanceXZ(value.Item1);
			}
			Point interior;
			float result = Policy.BoundaryUpperBound(position, Assignment.Anchor, (Point q) => Contains(GuardStore.Vector(q)), out interior);
			if (borders.Count > 64)
			{
				borders.Clear();
			}
			borders[key] = (interior, Time.time + 1f);
			return result;
		}
	}
	internal static class Navigation
	{
		internal static readonly int GroundMask = LayerMask.GetMask(new string[5] { "Default", "static_solid", "Default_small", "terrain", "piece" });

		private static readonly Collider[] Obstacles = (Collider[])(object)new Collider[32];

		internal static bool TryPoint(GuardController g, IGuardArea area, Vector3 candidate, out Vector3 point)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_0269: Unknown result type (might be due to invalid IL or missing references)
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: 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)
			//IL_0292: Unknown result type (might be due to invalid IL or missing references)
			//IL_0294: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02da: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
			point = candidate;
			if (!Policy.Finite(candidate.x) || !Policy.Finite(candidate.z) || (Object)(object)Pathfinding.instance == (Object)null || (Object)(object)ZoneSystem.instance == (Object)null)
			{
				return false;
			}
			RaycastHit val = default(RaycastHit);
			if (!Physics.Raycast(candidate + Vector3.up * Plugin.Effective.MaxHeight, Vector3.down, ref val, Plugin.Effective.MaxHeight * 2f + 3f, GroundMask, (QueryTriggerInteraction)1))
			{
				return false;
			}
			if (Vector3.Angle(((RaycastHit)(ref val)).normal, Vector3.up) > Plugin.Effective.MaxSlope || Math.Abs(((RaycastHit)(ref val)).point.y - ((Component)g).transform.position.y) > Plugin.Effective.MaxHeight)
			{
				return false;
			}
			if (((BaseAI)g.AI).m_avoidWater && ((RaycastHit)(ref val)).point.y < ZoneSystem.instance.m_waterLevel + 0.2f)
			{
				return false;
			}
			if (!Pathfinding.instance.FindValidPoint(ref point, ((RaycastHit)(ref val)).point, 1f, ((BaseAI)g.AI).m_pathAgentType) || !area.Contains(point))
			{
				return false;
			}
			if (Math.Abs(point.y - ((RaycastHit)(ref val)).point.y) > 2f)
			{
				return false;
			}
			float num = Mathf.Max(0.25f, g.Character.GetRadius());
			int num2 = Physics.OverlapCapsuleNonAlloc(point + Vector3.up * (num + 0.15f), point + Vector3.up * (num * 2f + 1f), num, Obstacles, GroundMask, (QueryTriggerInteraction)1);
			if (num2 == Obstacles.Length)
			{
				return false;
			}
			for (int i = 0; i < num2; i++)
			{
				if (Object.op_Implicit((Object)(object)Obstacles[i]) && !((Component)Obstacles[i]).transform.IsChildOf(((Component)g).transform))
				{
					Bounds bounds = Obstacles[i].bounds;
					if (((Bounds)(ref bounds)).max.y > point.y + 0.3f)
					{
						return false;
					}
				}
			}
			List<Vector3> path = g.Path;
			path.Clear();
			if (!Pathfinding.instance.GetPath(((Component)g).transform.position, point, path, ((BaseAI)g.AI).m_pathAgentType, true, true, false))
			{
				return false;
			}
			Vector3 val2 = ((Component)g).transform.position;
			if (!area.Contains(val2))
			{
				return false;
			}
			int num3 = 0;
			foreach (Vector3 item in path)
			{
				int num4 = Mathf.CeilToInt(Vector3.Distance(val2, item) / 2f);
				if (num4 > 256 || num3 + num4 > 256)
				{
					return false;
				}
				num3 += num4;
				for (int j = 1; j <= num4; j++)
				{
					if (!area.Contains(Vector3.Lerp(val2, item, (float)j / (float)num4)))
					{
						return false;
					}
				}
				val2 = item;
			}
			return true;
		}
	}
}
namespace FehuTerritoryGuards.AI
{
	internal sealed class GuardController : MonoBehaviour
	{
		private delegate bool MoveDelegate(BaseAI ai, float dt, Vector3 point, float distance, bool run);

		private delegate void AlertDelegate(BaseAI ai, bool alert);

		private static readonly MoveDelegate NativeMove = AccessTools.MethodDelegate<MoveDelegate>(AccessTools.Method(typeof(BaseAI), "MoveTo", (Type[])null, (Type[])null), (object)null, true);

		private static readonly AlertDelegate NativeAlert = AccessTools.MethodDelegate<AlertDelegate>(AccessTools.Method(typeof(BaseAI), "SetAlerted", (Type[])null, (Type[])null), (object)null, true);

		private static readonly FieldRef<MonsterAI, Character> Target = AccessTools.FieldRefAccess<MonsterAI, Character>("m_targetCreature");

		private static readonly FieldRef<MonsterAI, StaticTarget> StaticTarget = AccessTools.FieldRefAccess<MonsterAI, StaticTarget>("m_targetStatic");

		private static readonly FieldRef<MonsterAI, Vector3> LastTarget = AccessTools.FieldRefAccess<MonsterAI, Vector3>("m_lastKnownTargetPos");

		internal static readonly List<GuardController> Controllers = new List<GuardController>();

		private static readonly Dictionary<ZDOID, GuardController> ById = new Dictionary<ZDOID, GuardController>();

		private static readonly Collider[] Nearby = (Collider[])(object)new Collider[96];

		private readonly HashSet<Character> seen = new HashSet<Character>();

		internal readonly List<Vector3> Path = new List<Vector3>();

		internal Character Character;

		internal MonsterAI AI;

		internal ZNetView View;

		internal Assignment Assignment;

		internal IGuardArea Area;

		internal DutyState State = DutyState.Disabled;

		internal Vector3 Destination;

		internal string ReturnReason = "";

		internal float NextDecision;

		private float waitUntil;

		private float permitUntil;

		private float combatUntil;

		private float lastProgress;

		private float progressDistance;

		private float localThreatUntil;

		private Character permittedTarget;

		private Character localThreat;

		private bool serverReady;

		private bool serverLeashed;

		private bool wasOwner;

		private bool hadCombat;

		private bool frozen;

		private long permitOwner;

		private int candidateCursor;

		private ZDOID registeredId = ZDOID.None;

		private Rigidbody body;

		private RigidbodyConstraints originalConstraints;

		internal ZDOID Id
		{
			get
			{
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				//IL_002b: Unknown result type (might be due to invalid IL or missing references)
				if (!Object.op_Implicit((Object)(object)View) || !View.IsValid())
				{
					return ZDOID.None;
				}
				return View.GetZDO().m_uid;
			}
		}

		internal bool Active
		{
			get
			{
				if (Assignment != null && Object.op_Implicit((Object)(object)Character) && Character.IsTamed() && Object.op_Implicit((Object)(object)View))
				{
					return View.IsValid();
				}
				return false;
			}
		}

		internal bool OwnerActive
		{
			get
			{
				if (Active && View.IsOwner() && Plugin.SettingsReady)
				{
					return Plugin.Effective.Enabled;
				}
				return false;
			}
		}

		internal bool Returning => State == DutyState.Returning;

		internal bool Immobile
		{
			get
			{
				Assignment assignment = Assignment;
				if (assignment == null)
				{
					return false;
				}
				return assignment.Order == Order.Static;
			}
		}

		internal Vector3 Home
		{
			get
			{
				//IL_005e: Unknown result type (might be due to invalid IL or missing references)
				//IL_004d: 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)
				if (Assignment != null && Policy.Follows(Assignment.Order))
				{
					Player player = Player.GetPlayer(Assignment.FollowPlayer);
					if (Object.op_Implicit((Object)(object)player))
					{
						return ((Component)player).transform.position;
					}
				}
				if (Assignment == null)
				{
					return ((Component)this).transform.position;
				}
				return GuardStore.Vector(Assignment.Anchor);
			}
		}

		internal static GuardController Find(ZDOID id)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			if (!ById.TryGetValue(id, out var value) || !Object.op_Implicit((Object)(object)value))
			{
				return null;
			}
			return value;
		}

		internal static GuardController For(BaseAI ai)
		{
			if (!Object.op_Implicit((Object)(object)ai))
			{
				return null;
			}
			return ((Component)ai).GetComponent<GuardController>();
		}

		private void Awake()
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: 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_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			Character = ((Component)this).GetComponent<Character>();
			AI = ((Component)this).GetComponent<MonsterAI>();
			View = ((Component)this).GetComponent<ZNetView>();
			body = ((Component)this).GetComponent<Rigidbod