Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of FehuTerritoryGuards v420.101.1
FehuTerritoryGuards.dll
Decompiled a week ago
The result has been truncated due to the large size, download it to view full contents!
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