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 DynamicNPCs v0.5.2
DynamicNPCs.dll
Decompiled 7 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using JG224.ModCore.API; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using MagicaCloth2; using Splatform; using UnityEngine; using UnityEngine.UI; using Valheim.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("DynamicNPCs")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.5.2.0")] [assembly: AssemblyInformationalVersion("0.5.2")] [assembly: AssemblyProduct("DynamicNPCs")] [assembly: AssemblyTitle("DynamicNPCs")] [assembly: AssemblyVersion("0.5.2.0")] namespace MercenaryCompanions; internal static class AtomicFile { private static readonly Encoding DefaultEncoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false); internal static void WriteAllText(string path, string contents, Encoding encoding = null) { if (string.IsNullOrWhiteSpace(path)) { throw new ArgumentException("A state-file path is required.", "path"); } string directoryName = Path.GetDirectoryName(path); if (!string.IsNullOrEmpty(directoryName)) { Directory.CreateDirectory(directoryName); } string text = path + "." + Guid.NewGuid().ToString("N") + ".tmp"; try { File.WriteAllText(text, contents ?? "", encoding ?? DefaultEncoding); if (File.Exists(path)) { File.Replace(text, path, path + ".bak", ignoreMetadataErrors: true); } else { File.Move(text, path); } } finally { try { if (File.Exists(text)) { File.Delete(text); } } catch { } } } } internal static class BannerAuthority { private const string ClaimRequestRpc = "DynamicNPCs_BannerClaimRequestV4"; private const string RemoveRequestRpc = "DynamicNPCs_BannerRemoveRequestV4"; private const string MessageReplyRpc = "DynamicNPCs_BannerMessageReplyV4"; private const string SummonRequestRpc = "DynamicNPCs_BannerSummonRequestV1"; private const string UnsummonRequestRpc = "DynamicNPCs_BannerUnsummonRequestV1"; private static readonly FieldInfo ZdoObjectsById = AccessTools.Field(typeof(ZDOMan), "m_objectsByID"); private static readonly List<ZDO> BannerScan = new List<ZDO>(); private static ZRoutedRpc _registeredRpc; private static ZDOMan _scanManager; private static int _scanIndex; private static float _nextScanAt; private static bool _reportedFirstScan; private static readonly Dictionary<ZDOID, List<ZDO>> MercsByBanner = new Dictionary<ZDOID, List<ZDO>>(); private static readonly List<ZDO> OrphanedMercs = new List<ZDO>(); private static float _loadedRosterTimer; private const float HomeSummonTeleportRange = 40f; private static readonly HashSet<long> LoginSpawnGranted = new HashSet<long>(); private static bool _warnedRosterScanBlind; private static string _lastRosterSummary = ""; private const float LoginRejoinWindowSeconds = 180f; private static readonly Dictionary<long, float> OwnerOnlineSince = new Dictionary<long, float>(); internal static void Register() { ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null && instance != _registeredRpc) { instance.Register<ZDOID, int>("DynamicNPCs_BannerClaimRequestV4", (Action<long, ZDOID, int>)OnClaimRequest); instance.Register<ZDOID, int>("DynamicNPCs_BannerRemoveRequestV4", (Action<long, ZDOID, int>)OnRemoveRequest); instance.Register<string>("DynamicNPCs_BannerMessageReplyV4", (Action<long, string>)OnMessageReply); instance.Register<ZDOID>("DynamicNPCs_BannerSummonRequestV1", (Action<long, ZDOID>)OnSummonRequest); instance.Register<ZDOID>("DynamicNPCs_BannerUnsummonRequestV1", (Action<long, ZDOID>)OnUnsummonRequest); _registeredRpc = instance; MercPlugin.Log("Registered global dedicated-server banner authority RPCs."); } } internal static void ResetSceneMemory() { LoginSpawnGranted.Clear(); BannerScan.Clear(); _scanManager = null; _scanIndex = 0; _nextScanAt = 0f; _reportedFirstScan = false; MercsByBanner.Clear(); OrphanedMercs.Clear(); OwnerOnlineSince.Clear(); } private static void EnsureLoadedBannerRosters() { _loadedRosterTimer -= Time.deltaTime; if (_loadedRosterTimer > 0f) { return; } _loadedRosterTimer = 1f; try { foreach (MercBannerSpawn instance in MercBannerSpawn.Instances) { if (!((Object)(object)instance == (Object)null)) { ZNetView component = ((Component)instance).GetComponent<ZNetView>(); ZDO val = (((Object)(object)component != (Object)null && component.IsValid()) ? component.GetZDO() : null); if (IsBannerZdo(val)) { ClaimServerOwnership(val); MigrateLegacyClaim(val); AutoClaimPlacedBanner(val); EnsureRoster(val); } } } } catch (Exception ex) { MercPlugin.LogWarn("Loaded-banner roster pass failed: " + ex.Message); } } internal static void Update() { Register(); if (!IsServer() || ZDOMan.instance == null || (Object)(object)ZNetScene.instance == (Object)null) { return; } try { EnsureLoadedBannerRosters(); if (_scanManager != ZDOMan.instance) { _scanManager = ZDOMan.instance; BannerScan.Clear(); _scanIndex = 0; _nextScanAt = 0f; _reportedFirstScan = false; } if ((_scanIndex == 0 && BannerScan.Count == 0 && Time.unscaledTime < _nextScanAt) || !_scanManager.GetAllZDOsWithPrefabIterative("MercBanner", BannerScan, ref _scanIndex)) { return; } ZDO[] array = BannerScan.ToArray(); BannerScan.Clear(); _scanIndex = 0; _nextScanAt = Time.unscaledTime + 2f; if (!_reportedFirstScan) { _reportedFirstScan = true; MercPlugin.Log($"Global banner authority discovered {array.Length} persistent banner ZDO(s)."); } CollectMercenariesBucketed(); LogRosterSummary(array.Length); ZDO[] array2 = array; foreach (ZDO val in array2) { if (IsBannerZdo(val)) { ClaimServerOwnership(val); MigrateLegacyClaim(val); AutoClaimPlacedBanner(val); EnsureRoster(val); } } TrackOwnerSessions(); GrantLoginSpawns(array); EnforceOneBannerPerPlayer(array); RemoveOrphanedMercenaries(); } catch (Exception ex) { MercPlugin.LogWarn("Global banner authority update failed: " + ex); BannerScan.Clear(); _scanIndex = 0; _nextScanAt = Time.unscaledTime + 2f; } } internal static void RequestClaim(ZDOID bannerId, int progressionSeed) { //IL_0005: 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_0053: Unknown result type (might be due to invalid IL or missing references) LogClientRequest("claim", bannerId); Register(); if (ZRoutedRpc.instance == null) { MercPlugin.LogWarn($"Banner claim request not sent for {bannerId}: ZRoutedRpc.instance is null."); return; } if (((ZDOID)(ref bannerId)).IsNone()) { MercPlugin.LogWarn("Banner claim request not sent: banner ZDOID is None."); return; } ZRoutedRpc.instance.InvokeRoutedRPC("DynamicNPCs_BannerClaimRequestV4", new object[2] { bannerId, progressionSeed }); } internal static void RequestRemoval(ZDOID bannerId, int clientToolHash) { //IL_0005: 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_0053: Unknown result type (might be due to invalid IL or missing references) LogClientRequest("removal", bannerId); Register(); if (ZRoutedRpc.instance == null) { MercPlugin.LogWarn($"Banner removal request not sent for {bannerId}: ZRoutedRpc.instance is null."); return; } if (((ZDOID)(ref bannerId)).IsNone()) { MercPlugin.LogWarn("Banner removal request not sent: banner ZDOID is None."); return; } ZRoutedRpc.instance.InvokeRoutedRPC("DynamicNPCs_BannerRemoveRequestV4", new object[2] { bannerId, clientToolHash }); } private static void AutoClaimPlacedBanner(ZDO banner) { //IL_0122: Unknown result type (might be due to invalid IL or missing references) try { if (!IsServer() || !IsBannerZdo(banner)) { return; } bool flag = MercConfig.ProgressionPerPlayer != null && MercConfig.ProgressionPerPlayer.Value; if ((flag && !WorldDataService.IsWorldStateReady) || banner.GetLong(MercBannerSpawn.ClaimOwnerIdKey, 0L) != 0L) { return; } long num = banner.GetLong(ZDOVars.s_creator, 0L); if (num == 0L) { return; } int num2 = ServerAuthority.EnsureAuthoritativePlayerStage(num, "banner placement server fallback"); if (!flag || num2 >= 0) { string text = null; if (ServerAuthority.TryFindConnectedPeerByPlayerId(num, out var _, out var playerName) && !string.IsNullOrWhiteSpace(playerName)) { text = playerName; } if (string.IsNullOrEmpty(text)) { text = "player " + num; } banner.Set(MercBannerSpawn.ClaimOwnerIdKey, num); banner.Set(MercBannerSpawn.ClaimOwnerNameKey, text); for (int i = 0; i < MercBannerSpawn.Classes.Length; i++) { banner.Set(Mercenary.BannerEmployerIds[i], num); banner.Set(Mercenary.BannerEmployerNames[i], text); banner.Set(Mercenary.BannerFollowNames[i], ""); banner.Set(MercBannerSpawn.RecruitedKeys[i], true); } MercPlugin.Log($"Banner {banner.m_uid} auto-claimed for {text} on placement."); } } catch (Exception ex) { MercPlugin.LogWarn("Banner auto-claim failed: " + ex.Message); } } private static void OnClaimRequest(long sender, ZDOID bannerId, int progressionSeed) { //IL_000b: 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_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0262: 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) MercPlugin.Log($"Banner claim request received: sender={sender}, banner={bannerId}."); if (!RequireServerHandler("claim", sender, bannerId) || !TryValidateNearby("claim", sender, bannerId, 8f, out var requester, out var banner)) { return; } bool flag = MercConfig.ProgressionPerPlayer != null && MercConfig.ProgressionPerPlayer.Value; if (flag && !WorldDataService.IsWorldStateReady) { Reject(sender, "claim", bannerId, "the current world's progression store is not ready", MercLocalization.Phrase("dnpc_banner_loading")); return; } ClaimServerOwnership(banner); MigrateLegacyClaim(banner); long num = banner.GetLong(MercBannerSpawn.ClaimOwnerIdKey, 0L); if (num != 0L && num != requester.PlayerId) { Reject(sender, "claim", bannerId, $"banner belongs to player ID {num}, not requester {requester.PlayerId}", MercLocalization.Phrase("dnpc_message_banner_already_claimed")); return; } int num2 = ServerAuthority.EnsureAuthoritativeRequesterStage(requester, "banner claim server fallback"); if (flag && num2 < 0) { Reject(sender, "claim", bannerId, "the authoritative progression stage could not be persisted", MercLocalization.Phrase("dnpc_banner_loading")); return; } if (num == 0L) { banner.Set(MercBannerSpawn.ClaimOwnerIdKey, requester.PlayerId); banner.Set(MercBannerSpawn.ClaimOwnerNameKey, requester.PlayerName); for (int i = 0; i < MercBannerSpawn.Classes.Length; i++) { if (string.IsNullOrWhiteSpace(banner.GetString(MercBannerSpawn.CustomNameKeys[i], ""))) { banner.Set(MercBannerSpawn.CustomNameKeys[i], MercBannerSpawn.DefaultFirstName(MercBannerSpawn.Classes[i])); } banner.Set(Mercenary.BannerEmployerIds[i], 0L); banner.Set(Mercenary.BannerEmployerNames[i], ""); banner.Set(Mercenary.BannerFollowNames[i], ""); banner.Set(MercBannerSpawn.RecruitedKeys[i], false); } MercPlugin.Log($"{requester.PlayerName} claimed banner ZDO {bannerId} through global authority."); } for (int j = 0; j < MercBannerSpawn.Classes.Length; j++) { banner.Set(Mercenary.BannerEmployerIds[j], requester.PlayerId); banner.Set(Mercenary.BannerEmployerNames[j], requester.PlayerName); banner.Set(Mercenary.BannerFollowNames[j], ""); banner.Set(MercBannerSpawn.RecruitedKeys[j], true); } EnsureRoster(banner); MercPlugin.Log($"Banner claim request accepted: sender={sender}, banner={bannerId}, " + $"owner={requester.PlayerName}, clientStageHint={progressionSeed}, " + $"authoritativeStage={num2}."); SendMessage(sender, MercLocalization.Phrase("dnpc_message_company_arrived")); } private static void OnRemoveRequest(long sender, ZDOID bannerId, int clientToolHash) { //IL_000b: 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_0030: 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_0120: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) MercPlugin.Log($"Banner removal request received: sender={sender}, banner={bannerId}."); if (!RequireServerHandler("removal", sender, bannerId) || !TryValidateNearby("removal", sender, bannerId, 10f, out var requester, out var banner)) { return; } if (banner.GetLong(MercBannerSpawn.ClaimOwnerIdKey, 0L) != requester.PlayerId && !ServerAuthority.IsSenderAdmin(sender)) { Reject(sender, "removal", bannerId, "sender is neither the banner owner nor a server admin", MercLocalization.Phrase("dnpc_message_banner_remove_owner")); return; } int stableHashCode = StringExtensionMethods.GetStableHashCode("Hammer"); int stableHashCode2 = StringExtensionMethods.GetStableHashCode("MercHammer"); int stableHashCode3 = StringExtensionMethods.GetStableHashCode("Mercenary Hammer"); if (clientToolHash != stableHashCode && clientToolHash != stableHashCode2 && clientToolHash != stableHashCode3) { Reject(sender, "removal", bannerId, $"remove-mode tool marker {clientToolHash} did not match a build hammer ({stableHashCode})", MercLocalization.Phrase("dnpc_message_banner_remove_hammer")); return; } string playerName = requester.PlayerName; RemoveBannerAndRoster(banner, "dismantled by " + playerName); SendMessage(sender, MercLocalization.Phrase("dnpc_message_banner_dismantled")); MercPlugin.Log($"Banner removal request accepted: sender={sender}, banner={bannerId}, admin={playerName}."); } internal static void RequestSummon(ZDOID bannerId) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) Register(); if (ZRoutedRpc.instance != null && !((ZDOID)(ref bannerId)).IsNone()) { ZRoutedRpc.instance.InvokeRoutedRPC(ServerAuthority.GetServerPeerUid(), "DynamicNPCs_BannerSummonRequestV1", new object[1] { bannerId }); } } internal static void RequestUnsummon(ZDOID bannerId) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) Register(); if (ZRoutedRpc.instance != null && !((ZDOID)(ref bannerId)).IsNone()) { ZRoutedRpc.instance.InvokeRoutedRPC(ServerAuthority.GetServerPeerUid(), "DynamicNPCs_BannerUnsummonRequestV1", new object[1] { bannerId }); } } private static void OnUnsummonRequest(long sender, ZDOID bannerId) { //IL_0006: 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_0047: 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_008b: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: 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_00b9: Unknown result type (might be due to invalid IL or missing references) if (!RequireServerHandler("unsummon", sender, bannerId) || !TryValidateNearby("unsummon", sender, bannerId, 10f, out var requester, out var banner)) { return; } long num = banner.GetLong(MercBannerSpawn.ClaimOwnerIdKey, 0L); if (num == 0L || num != requester.PlayerId) { Reject(sender, "unsummon", bannerId, "banner is not owned by the requester", MercLocalization.Phrase("dnpc_message_banner_not_yours")); return; } ClaimServerOwnership(banner); banner.Set(MercBannerSpawn.CompanyStabledKey, 1, false); int num2 = 0; for (int i = 0; i < MercBannerSpawn.Classes.Length; i++) { ZDOID zDOID = banner.GetZDOID(MercBannerSpawn.MemberIdKeys[i]); ZDO val = ((!((ZDOID)(ref zDOID)).IsNone() && ZDOMan.instance != null) ? ZDOMan.instance.GetZDO(zDOID) : null); if (IsLivingMercZdo(val)) { ServerAuthority.MarkDeliberateRemoval(val.m_uid); DestroyWorldZdo(val, "company dismissed at banner"); num2++; } banner.RemoveZDOID(MercBannerSpawn.MemberIdKeys[i]); } MercPlugin.Log($"Company dismissed at banner {bannerId} by {requester.PlayerName}: " + $"{num2} member(s) removed."); } private static void OnSummonRequest(long sender, ZDOID bannerId) { //IL_0006: 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_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_033a: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: 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_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: 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_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_0282: 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_028d: 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_02a9: Unknown result type (might be due to invalid IL or missing references) if (!RequireServerHandler("summon", sender, bannerId) || !TryValidateNearby("summon", sender, bannerId, 10f, out var requester, out var banner)) { return; } long num = banner.GetLong(MercBannerSpawn.ClaimOwnerIdKey, 0L); if (num == 0L || num != requester.PlayerId) { Reject(sender, "summon", bannerId, "banner is not claimed by the requester", MercLocalization.Phrase("dnpc_message_banner_claim_before_gather")); return; } ClaimServerOwnership(banner); if (banner.GetInt(MercBannerSpawn.CompanyStabledKey, 0) != 0) { banner.Set(MercBannerSpawn.CompanyStabledKey, 0, false); for (int i = 0; i < MercBannerSpawn.Classes.Length; i++) { ZDOID zDOID = banner.GetZDOID(MercBannerSpawn.MemberIdKeys[i]); ZDO val = ((!((ZDOID)(ref zDOID)).IsNone() && ZDOMan.instance != null) ? ZDOMan.instance.GetZDO(zDOID) : null); if (IsLivingMercZdo(val)) { ServerAuthority.MarkDeliberateRemoval(val.m_uid); DestroyWorldZdo(val, "company re-summoned while stale"); } banner.RemoveZDOID(MercBannerSpawn.MemberIdKeys[i]); banner.Set(MercBannerSpawn.LastSeenKeys[i], 0L); } MercPlugin.Log($"Company summoned back at banner {bannerId} for {requester.PlayerName}."); return; } int num2 = 0; for (int j = 0; j < MercBannerSpawn.Classes.Length; j++) { MercClass mercClass = MercBannerSpawn.Classes[j]; ZDOID zDOID2 = banner.GetZDOID(MercBannerSpawn.MemberIdKeys[j]); ZDO val2 = ((!((ZDOID)(ref zDOID2)).IsNone() && ZDOMan.instance != null) ? ZDOMan.instance.GetZDO(zDOID2) : null); if (!IsMercenaryZdo(val2) || !string.IsNullOrEmpty(Mercenary.FollowNameOf(val2))) { continue; } ClaimServerOwnership(val2); val2.Set(Mercenary.ZdoStayDay, 0, false); Vector3 val3 = (Vector3)(mercClass switch { MercClass.Healer => new Vector3(-2f, 0f, 1f), MercClass.Tank => new Vector3(2f, 0f, 1f), _ => new Vector3(0f, 0f, -2f), }); Vector3 val4 = banner.GetPosition() + val3; if (Vector3.Distance(val2.GetPosition(), val4) <= 40f) { continue; } GameObject val5 = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.FindInstance(zDOID2) : null); Mercenary mercenary = (((Object)(object)val5 != (Object)null) ? val5.GetComponent<Mercenary>() : null); if (((Object)(object)mercenary != (Object)null && (Object)(object)mercenary.Ai != (Object)null && mercenary.Ai.EngagedInCombat) || val2.GetInt(ZDOVars.s_haveTargetHash, 0) != 0) { continue; } try { val2.SetPosition(val4); val2.SetRotation(Quaternion.LookRotation(-val3)); ZDOMan instance = ZDOMan.instance; if (instance != null) { instance.ForceSendZDO(val2.m_uid); } num2++; } catch (Exception ex) { MercPlugin.LogWarn($"Could not summon {mercClass} {zDOID2} home: {ex.Message}"); } } EnsureRoster(banner); SendMessage(sender, (num2 > 0) ? MercLocalization.Phrase("dnpc_message_company_gathering_far", num2) : MercLocalization.Phrase("dnpc_message_company_gathering")); MercPlugin.Log($"Banner summon accepted: sender={sender}, banner={bannerId}, teleported={num2}."); } private static void OnMessageReply(long sender, string message) { if (ServerAuthority.IsAuthoritativeServerSender(sender)) { Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, MercLocalization.Resolve(message), 0, (Sprite)null, false); } } } private static void SendMessage(long target, string message) { if (ZRoutedRpc.instance != null) { ZRoutedRpc.instance.InvokeRoutedRPC(target, "DynamicNPCs_BannerMessageReplyV4", new object[1] { message ?? "" }); } } private static bool IsServer() { if ((Object)(object)ZNet.instance != (Object)null) { return ZNet.instance.IsServer(); } return false; } private static void LogClientRequest(string operation, ZDOID bannerId) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) long num = 0L; try { if ((Object)(object)ZNet.instance != (Object)null) { num = ZNet.GetUID(); } } catch (Exception ex) { MercPlugin.LogWarn("Could not read local routed peer ID for banner " + operation + ": " + ex.Message); } MercPlugin.Log($"Banner client request: operation={operation}, banner={bannerId}, localPeer={num}, routedRpcExists={ZRoutedRpc.instance != null}."); } private static bool RequireServerHandler(string operation, long sender, ZDOID bannerId) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (IsServer()) { return true; } MercPlugin.LogWarn($"Banner {operation} request rejected on a non-server peer: sender={sender}, banner={bannerId}."); return false; } private static bool TryValidateNearby(string operation, long sender, ZDOID bannerId, float range, out ServerAuthority.SenderPlayerState requester, out ZDO banner) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) bool num = ServerAuthority.TryResolveSender(sender, out requester); banner = null; if (!num || requester == null) { return Reject(sender, operation, bannerId, "sender player was not found on the server", MercLocalization.Phrase("dnpc_message_banner_player_missing")); } if (requester.PlayerId == 0L) { return Reject(sender, operation, bannerId, $"character ZDO {requester.CharacterZdoId} has no persistent player ID", MercLocalization.Phrase("dnpc_message_banner_identity_not_ready")); } if (ZDOMan.instance == null || ((ZDOID)(ref bannerId)).IsNone()) { return Reject(sender, operation, bannerId, (ZDOMan.instance == null) ? "ZDOMan is unavailable" : "banner ZDOID is None", MercLocalization.Phrase("dnpc_message_banner_record_missing")); } banner = ZDOMan.instance.GetZDO(bannerId); if (banner == null || !banner.IsValid()) { return Reject(sender, operation, bannerId, "banner ZDO was not found or is invalid", MercLocalization.Phrase("dnpc_message_banner_record_missing")); } int stableHashCode = StringExtensionMethods.GetStableHashCode("MercBanner"); int prefab = banner.GetPrefab(); if (prefab != stableHashCode) { return Reject(sender, operation, bannerId, $"wrong prefab hash {prefab}; expected {stableHashCode}", MercLocalization.Phrase("dnpc_message_banner_wrong_object")); } if (requester.IsDead) { return Reject(sender, operation, bannerId, "requesting player is dead", MercLocalization.Phrase("dnpc_message_banner_while_dead")); } Vector3 position = requester.Position; Vector3 position2 = banner.GetPosition(); float num2 = Vector3.Distance(position, position2); if (num2 > range) { return Reject(sender, operation, bannerId, $"distance {num2:F2}m exceeds {range:F2}m; player={position}, banner={position2}", MercLocalization.Phrase("dnpc_message_banner_move_within", range.ToString("F0"))); } return true; } private static bool Reject(long sender, string operation, ZDOID bannerId, string reason, string playerMessage) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) MercPlugin.LogWarn($"Banner {operation} request rejected: sender={sender}, banner={bannerId}, reason={reason}."); SendMessage(sender, playerMessage); return false; } private static void LogHammerDiagnostics(ServerAuthority.SenderPlayerState requester, long sender, ZDOID bannerId, int mercHammerHash, int displayNameHash) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) GameObject val = null; try { object obj; if (requester == null) { obj = null; } else { Player livePlayer = requester.LivePlayer; obj = ((livePlayer != null) ? ((Humanoid)livePlayer).GetCurrentWeapon() : null); } val = ((ItemData)(obj?)).m_dropPrefab; } catch (Exception ex) { MercPlugin.LogWarn($"Banner removal hammer diagnostics failed for sender={sender}, banner={bannerId}: {ex.Message}"); } MercPlugin.Log($"Banner removal hammer diagnostics: sender={sender}, banner={bannerId}, " + "currentWeaponDropPrefab=" + (((Object)(object)val != (Object)null) ? ((Object)val).name : "<null>") + ", " + $"playerRightItemHash={requester?.RightItemHash ?? 0}, " + $"MercHammerHash={mercHammerHash}, " + $"MercenaryHammerHash={displayNameHash}."); } private static bool IsBannerZdo(ZDO zdo) { if (zdo != null && zdo.IsValid()) { return zdo.GetPrefab() == StringExtensionMethods.GetStableHashCode("MercBanner"); } return false; } private static void ClaimServerOwnership(ZDO zdo) { if (zdo != null && IsServer() && zdo.GetOwner() != ZNet.GetUID()) { zdo.SetOwner(ZNet.GetUID()); } } private static void MigrateLegacyClaim(ZDO banner) { //IL_00b3: Unknown result type (might be due to invalid IL or missing references) if (!IsBannerZdo(banner) || banner.GetLong(MercBannerSpawn.ClaimOwnerIdKey, 0L) != 0L) { return; } for (int i = 0; i < MercBannerSpawn.Classes.Length; i++) { long num = banner.GetLong(Mercenary.BannerEmployerIds[i], 0L); string text = banner.GetString(Mercenary.BannerEmployerNames[i], ""); if (num == 0L || string.IsNullOrWhiteSpace(text)) { continue; } banner.Set(MercBannerSpawn.ClaimOwnerIdKey, num); banner.Set(MercBannerSpawn.ClaimOwnerNameKey, text); for (int j = 0; j < MercBannerSpawn.Classes.Length; j++) { if (string.IsNullOrWhiteSpace(banner.GetString(MercBannerSpawn.CustomNameKeys[j], ""))) { banner.Set(MercBannerSpawn.CustomNameKeys[j], MercBannerSpawn.DefaultFirstName(MercBannerSpawn.Classes[j])); } } MercPlugin.Log($"Global banner authority migrated legacy claim for {text} at {banner.m_uid}."); break; } } private static void GrantLoginSpawns(ZDO[] banners) { //IL_009c: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)ZNet.instance == (Object)null) { return; } foreach (ZDO val in banners) { if (!IsBannerZdo(val)) { continue; } long num = val.GetLong(MercBannerSpawn.ClaimOwnerIdKey, 0L); if (num != 0L && !LoginSpawnGranted.Contains(num) && val.GetInt(MercBannerSpawn.CompanyStabledKey, 0) == 0 && IsOwnerOnline(num)) { LoginSpawnGranted.Add(num); for (int j = 0; j < MercBannerSpawn.Classes.Length; j++) { val.Set(MercBannerSpawn.LastSeenKeys[j], 0L); } MercPlugin.Log($"Login spawn granted for player {num}'s banner {val.m_uid}: missing mercenaries return immediately."); } } } catch (Exception ex) { MercPlugin.LogWarn("Login spawn grant failed: " + ex.Message); } } private static bool IsOwnerOnline(long playerId) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) try { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null && localPlayer.GetPlayerID() == playerId) { return true; } foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { if (peer != null && !((ZDOID)(ref peer.m_characterID)).IsNone()) { ZDO val = ((ZDOMan.instance != null) ? ZDOMan.instance.GetZDO(peer.m_characterID) : null); if (val != null && val.GetLong(ZDOVars.s_playerID, 0L) == playerId) { return true; } } } } catch { } return false; } private static ZDO ChooseSurvivingBanner(ZDO a, ZDO b) { //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_0033: 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_0043: 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_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) try { List<ZDO> list = AllZdosFromTable(); int num = 0; int num2 = 0; foreach (ZDO item in list) { if (item == null || !item.IsValid() || !IsMercenaryZdo(item)) { continue; } ZDOID val = Mercenary.BannerIdOf(item); if (IsLivingMercZdo(item)) { if (val == a.m_uid) { num++; } else if (val == b.m_uid) { num2++; } } } if (num != num2) { return (num > num2) ? a : b; } Vector3 val2 = Vector3.zero; bool flag = false; foreach (Player allPlayer in Player.GetAllPlayers()) { if (!((Object)(object)allPlayer == (Object)null)) { val2 = ((Component)allPlayer).transform.position; flag = true; break; } } if (flag) { return (Vector3.Distance(a.GetPosition(), val2) <= Vector3.Distance(b.GetPosition(), val2)) ? a : b; } } catch (Exception ex) { MercPlugin.LogWarn("Duplicate-banner choice failed: " + ex.Message); } return a; } private static void NotifyOwnerOfDuplicate(long owner, ZDO removed) { try { foreach (Player allPlayer in Player.GetAllPlayers()) { if (!((Object)(object)allPlayer == (Object)null) && allPlayer.GetPlayerID() == owner) { ((Character)allPlayer).Message((MessageType)2, MercLocalization.Text("dnpc_message_duplicate_banner"), 0, (Sprite)null, false); break; } } } catch { } } private static void EnforceOneBannerPerPlayer(ZDO[] banners) { try { Dictionary<long, ZDO> dictionary = new Dictionary<long, ZDO>(); foreach (ZDO val in banners) { if (!IsBannerZdo(val)) { continue; } long num = val.GetLong(ZDOVars.s_creator, 0L); if (num == 0L) { num = val.GetLong(MercBannerSpawn.ClaimOwnerIdKey, 0L); } if (num != 0L) { if (!dictionary.TryGetValue(num, out var value)) { dictionary[num] = val; continue; } ZDO val2 = ChooseSurvivingBanner(value, val); ZDO val3 = ((val2 == value) ? val : value); dictionary[num] = val2; RemoveBannerAndRoster(val3, $"duplicate Mercenary Banner for player {num}"); NotifyOwnerOfDuplicate(num, val3); } } } catch (Exception ex) { MercPlugin.LogWarn("One-banner-per-player enforcement failed: " + ex.Message); } } private static void EnsureRoster(ZDO banner) { //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0375: Unknown result type (might be due to invalid IL or missing references) //IL_0399: Unknown result type (might be due to invalid IL or missing references) //IL_03f9: Unknown result type (might be due to invalid IL or missing references) if (!IsBannerZdo(banner) || (Object)(object)ZNetScene.instance == (Object)null) { return; } bool flag = MercConfig.ProgressionPerPlayer != null && MercConfig.ProgressionPerPlayer.Value; if ((flag && !MercProgressionRules.CanMutatePersonalProgression(flag, WorldDataService.IsWorldStateReady)) || banner.GetLong(MercBannerSpawn.ClaimOwnerIdKey, 0L) == 0L) { return; } AdoptBeforeRosterCreation(banner); int stage; bool flag2 = TryResolveAuthoritativeCompanyStage(banner, out stage); if (flag2) { SynchronizeProgressionStage(banner, stage); } double timeSeconds = ZNet.instance.GetTimeSeconds(); for (int i = 0; i < MercBannerSpawn.Classes.Length; i++) { MercClass mercClass = MercBannerSpawn.Classes[i]; if (!string.IsNullOrWhiteSpace(banner.GetString(Mercenary.BannerEmployerNames[i], ""))) { banner.Set(MercBannerSpawn.RecruitedKeys[i], true); } List<ZDO> list = FindPersistentMercZdos(mercClass, banner.m_uid); ZDOID zDOID = banner.GetZDOID(MercBannerSpawn.MemberIdKeys[i]); ZDO val = ChooseCanonicalMerc(list, zDOID); if (val == null && !((ZDOID)(ref zDOID)).IsNone() && ZDOMan.instance != null) { ZDO zDO = ZDOMan.instance.GetZDO(zDOID); if (IsMercenaryZdo(zDO) && Mercenary.BannerIdOf(zDO) == banner.m_uid) { val = zDO; if (!list.Contains(zDO)) { list.Add(zDO); } } } if (val != null) { banner.Set(MercBannerSpawn.MemberIdKeys[i], val.m_uid); foreach (ZDO item in list) { if (item != null && item.m_uid != val.m_uid) { DestroyWorldZdo(item, $"duplicate {mercClass} for banner {banner.m_uid}"); } } } else { banner.RemoveZDOID(MercBannerSpawn.MemberIdKeys[i]); } if (IsLivingMercZdo(val)) { if (flag2) { SynchronizeProgressionStage(val, stage); } RecoverLostMember(banner, mercClass, val); RejoinFollowedOwner(banner, mercClass, val); long num = Mercenary.EmployerIdOf(val); string text = Mercenary.EmployerNameOf(val); string text2 = Mercenary.FollowNameOf(val); if (val.GetOwner() == ZNet.GetUID()) { Mercenary.RestoreEmploymentFromBanner(val, banner, mercClass); } long num2 = Mercenary.EmployerIdOf(val); string text3 = Mercenary.EmployerNameOf(val); string text4 = Mercenary.FollowNameOf(val); if (num != num2 || text != text3 || text2 != text4) { MercPlugin.Log($"Roster employment repaired: banner={banner.m_uid}, class={mercClass}, " + $"member={val.m_uid}, ownerId={num2}, ownerName={text3}, " + "follow=" + text4 + "."); } banner.Set(MercBannerSpawn.LastSeenKeys[i], (long)timeSeconds); continue; } if (val != null) { AnnounceFallIfUnreported(banner, mercClass, i, val); DestroyWorldZdo(val, $"dead {mercClass} ready for banner respawn"); } banner.RemoveZDOID(MercBannerSpawn.MemberIdKeys[i]); double num3 = banner.GetLong(MercBannerSpawn.LastSeenKeys[i], 0L); if (num3 <= 0.0) { num3 = banner.GetFloat(MercBannerSpawn.LastSeenKeys[i], 0f); } if (banner.GetInt(MercBannerSpawn.CompanyStabledKey, 0) != 0) { continue; } if (val == null && !((ZDOID)(ref zDOID)).IsNone() && num3 > 0.0 && timeSeconds - num3 < 120.0 && ServerAuthority.AnnouncedFallen.Add(zDOID)) { ServerAuthority.AnnounceRosterFall(RosterMemberName(banner, mercClass, i)); MercPlugin.Log($"Roster lost track of {mercClass} {zDOID} without a recorded death; presumed fallen."); } if ((!(num3 > 0.0) || !(timeSeconds - num3 < (double)MercConfig.RespawnDelaySeconds.Value)) && SpawnMerc(banner, mercClass, i, flag2 ? stage : (-1))) { banner.Set(MercBannerSpawn.LastSeenKeys[i], (long)timeSeconds); if (!((ZDOID)(ref zDOID)).IsNone()) { ServerAuthority.AnnouncedFallen.Remove(zDOID); } } } } internal static List<ZDO> AllZdosFromTable() { List<ZDO> list = new List<ZDO>(); if (ZDOMan.instance == null || ZdoObjectsById == null) { return list; } try { if (ZdoObjectsById.GetValue(ZDOMan.instance) is IDictionary<ZDOID, ZDO> dictionary) { list.AddRange(dictionary.Values); } } catch { } return list; } internal static void PublishCompanyStage(long playerId, int stage) { //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) bool personalModeEnabled = MercConfig.ProgressionPerPlayer != null && MercConfig.ProgressionPerPlayer.Value; if (!IsServer() || ZDOMan.instance == null || playerId == 0L || !MercProgressionRules.CanMutatePersonalProgression(personalModeEnabled, WorldDataService.IsWorldStateReady)) { return; } try { int num = MercProgressionRules.ResolveStage(stage, -1); List<ZDO> list = AllZdosFromTable(); HashSet<ZDOID> hashSet = new HashSet<ZDOID>(); int num2 = 0; foreach (ZDO item in list) { if (IsBannerZdo(item) && item.GetLong(MercBannerSpawn.ClaimOwnerIdKey, 0L) == playerId) { hashSet.Add(item.m_uid); if (SynchronizeProgressionStage(item, num)) { num2++; } } } if (hashSet.Count > 0) { foreach (ZDO item2 in list) { if (IsMercenaryZdo(item2) && hashSet.Contains(Mercenary.BannerIdOf(item2)) && SynchronizeProgressionStage(item2, num)) { num2++; } } } if (num2 > 0) { MercPlugin.Log($"Published company progression stage {num} for player " + $"{playerId} to {num2} persistent ZDO(s)."); } } catch (Exception ex) { MercPlugin.LogWarn("Could not publish company progression stage: " + ex.Message); } } private static bool TryResolveAuthoritativeCompanyStage(ZDO banner, out int stage) { stage = -1; if (MercConfig.ProgressionPerPlayer == null || !MercConfig.ProgressionPerPlayer.Value) { return false; } long num = banner.GetLong(MercBannerSpawn.ClaimOwnerIdKey, 0L); if (num == 0L) { return false; } int bannerStage = Mercenary.ProgressionStageOf(banner); if (!WorldDataService.IsWorldStateReady) { return false; } int stage2 = PlayerProgression.GetStage(num); int num2 = MercProgressionRules.SelectDurableStage(stage2, bannerStage, PlayerProgression.WasRecoveredFromBackup); if (num2 >= 0) { if (stage2 < 0 || num2 > stage2) { int num3 = PlayerProgression.EnsureSeeded(num, num2, PlayerProgression.WasRecoveredFromBackup ? "newer banner mirror after atomic-backup recovery" : "recovered banner progression mirror"); if (num3 < num2) { return false; } stage = num3; return true; } stage = num2; return true; } int num4 = ServerAuthority.SeedStageFromLiveGear(num); if (num4 >= 0) { stage = MercProgressionRules.ResolveStage(num4, -1); return true; } stage = PlayerProgression.EnsureSeeded(num, 0, "unobserved legacy company fallback"); return stage >= 0; } private static bool SynchronizeProgressionStage(ZDO zdo, int stage) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) try { if (zdo == null || Mercenary.ProgressionStageOf(zdo) == stage) { return false; } ClaimServerOwnership(zdo); if (!Mercenary.SetProgressionStage(zdo, stage)) { return false; } ZDOMan instance = ZDOMan.instance; if (instance != null) { instance.ForceSendZDO(zdo.m_uid); } return true; } catch (Exception ex) { MercPlugin.LogWarn("Could not synchronize a company progression mirror: " + ex.Message); return false; } } private static void WarnOnceRosterScanBlind(string reason) { if (!_warnedRosterScanBlind) { _warnedRosterScanBlind = true; MercPlugin.LogWarn("Persistent roster scan is blind (" + reason + "); banner adoption and orphan cleanup cannot work this session."); } } private static void LogRosterSummary(int bannerCount) { int num = 0; foreach (KeyValuePair<ZDOID, List<ZDO>> item in MercsByBanner) { num += item.Value.Count; } string text = $"{num} mercenary ZDO(s) under {MercsByBanner.Count} banner id(s), " + $"{OrphanedMercs.Count} orphan(s), {bannerCount} banner(s)"; if (!(text == _lastRosterSummary)) { _lastRosterSummary = text; MercPlugin.Log("Persistent roster census: " + text + "."); } } private static void CollectMercenariesBucketed() { //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) MercsByBanner.Clear(); OrphanedMercs.Clear(); if (ZDOMan.instance == null) { return; } if (ZdoObjectsById == null) { WarnOnceRosterScanBlind("the world ZDO table field was not found"); return; } try { if (!(ZdoObjectsById.GetValue(ZDOMan.instance) is IDictionary<ZDOID, ZDO> dictionary)) { WarnOnceRosterScanBlind("the world ZDO table could not be read"); return; } int stableHashCode = StringExtensionMethods.GetStableHashCode("Merc_Tank"); int stableHashCode2 = StringExtensionMethods.GetStableHashCode("Merc_Healer"); int stableHashCode3 = StringExtensionMethods.GetStableHashCode("Merc_Archer"); foreach (KeyValuePair<ZDOID, ZDO> item in dictionary) { ZDO value = item.Value; if (value == null || !value.IsValid()) { continue; } int prefab = value.GetPrefab(); if (prefab != stableHashCode && prefab != stableHashCode2 && prefab != stableHashCode3) { continue; } ZDOID key = Mercenary.BannerIdOf(value); if (((ZDOID)(ref key)).IsNone()) { if (!value.GetBool(Mercenary.ZdoStandalone, false)) { OrphanedMercs.Add(value); } continue; } if (!MercsByBanner.TryGetValue(key, out var value2)) { value2 = (MercsByBanner[key] = new List<ZDO>()); } value2.Add(value); } } catch (Exception ex) { MercPlugin.LogWarn("Persistent roster scan failed: " + ex.Message); } } private static List<ZDO> FindPersistentMercZdos(MercClass mercClass, ZDOID bannerId) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) List<ZDO> list = new List<ZDO>(); if (MercsByBanner.TryGetValue(bannerId, out var value)) { int stableHashCode = StringExtensionMethods.GetStableHashCode(PrefabName(mercClass)); foreach (ZDO item in value) { if (item != null && item.IsValid() && item.GetPrefab() == stableHashCode) { list.Add(item); } } } return list; } private static ZDO ChooseCanonicalMerc(List<ZDO> candidates, ZDOID trackedId) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) ZDO val = null; int num = int.MinValue; foreach (ZDO candidate in candidates) { if (candidate != null) { int num2 = (IsLivingMercZdo(candidate) ? 10000 : 0); if (!((ZDOID)(ref trackedId)).IsNone() && candidate.m_uid == trackedId) { num2 += 5000; } if (!string.IsNullOrEmpty(Mercenary.EmployerNameOf(candidate))) { num2 += 500; } if (!string.IsNullOrEmpty(Mercenary.FollowNameOf(candidate))) { num2 += 250; } if ((Object)(object)ZNetScene.instance != (Object)null && (Object)(object)ZNetScene.instance.FindInstance(candidate.m_uid) != (Object)null) { num2 += 100; } if (val == null || num2 > num || (num2 == num && ((ZDOID)(ref candidate.m_uid)).CompareTo(val.m_uid) < 0)) { val = candidate; num = num2; } } } return val; } private static void TrackOwnerSessions() { try { bool flag = MercProgressionRules.CanMutatePersonalProgression(MercConfig.ProgressionPerPlayer != null && MercConfig.ProgressionPerPlayer.Value, WorldDataService.IsWorldStateReady); HashSet<long> hashSet = new HashSet<long>(); foreach (Player allPlayer in Player.GetAllPlayers()) { if (!((Object)(object)allPlayer == (Object)null)) { long playerID = allPlayer.GetPlayerID(); if (playerID != 0L) { hashSet.Add(playerID); } } } foreach (long item in hashSet) { if (!OwnerOnlineSince.ContainsKey(item)) { OwnerOnlineSince[item] = Time.time; } if (flag) { ServerAuthority.SeedStageFromLiveGear(item); } } List<long> list = new List<long>(); foreach (KeyValuePair<long, float> item2 in OwnerOnlineSince) { if (!hashSet.Contains(item2.Key)) { list.Add(item2.Key); } } foreach (long item3 in list) { OwnerOnlineSince.Remove(item3); } } catch { } } internal static void HoldFollowingCompanyOnOwnerDeath(Player owner) { //IL_00b5: 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_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)owner == (Object)null || !IsServer() || ZDOMan.instance == null) { return; } long playerID = owner.GetPlayerID(); if (playerID == 0L) { return; } int num = Mathf.Max(1, WorldDataService.CurrentDay); int num2 = 0; foreach (ZDO item in AllZdosFromTable()) { if (!IsBannerZdo(item) || item.GetLong(MercBannerSpawn.ClaimOwnerIdKey, 0L) != playerID) { continue; } ClaimServerOwnership(item); for (int i = 0; i < MercBannerSpawn.Classes.Length; i++) { if (!string.IsNullOrEmpty(item.GetString(Mercenary.BannerFollowNames[i], ""))) { item.Set(Mercenary.BannerFollowNames[i], ""); ZDOID zDOID = item.GetZDOID(MercBannerSpawn.MemberIdKeys[i]); ZDO val = ((!((ZDOID)(ref zDOID)).IsNone()) ? ZDOMan.instance.GetZDO(zDOID) : null); if (IsLivingMercZdo(val)) { ClaimServerOwnership(val); Vector3 position = val.GetPosition(); Mercenary.SetFollowName(val, ""); val.Set(Mercenary.ZdoStayDay, num, false); val.Set(Mercenary.ZdoStayAnchor, position); val.Set(MercAI.ZdoGuideTask, ""); val.Set("merc_guideFind", ""); val.Set("merc_guideRoute", ""); ZDOMan.instance.ForceSendZDO(val.m_uid); GameObject val2 = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.FindInstance(val.m_uid) : null); (((Object)(object)val2 != (Object)null) ? val2.GetComponent<Mercenary>() : null)?.NotifySimulationOwnerOfStateChange(refillFood: false); num2++; } } } } if (num2 > 0) { MercPlugin.Log($"Owner death hold: {num2} following mercenary(s) kept their " + "current positions and stopped guiding for the respawn flow."); } } private static void RejoinFollowedOwner(ZDO banner, MercClass mercClass, ZDO tracked) { //IL_01a6: 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_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) try { int num = Mathf.Clamp((int)mercClass, 0, Mercenary.BannerFollowNames.Length - 1); string text = banner.GetString(Mercenary.BannerFollowNames[num], ""); if (string.IsNullOrEmpty(text)) { return; } long num2 = banner.GetLong(MercBannerSpawn.ClaimOwnerIdKey, 0L); if (num2 != 0L && OwnerOnlineSince.TryGetValue(num2, out var value) && !(Time.time - value > 180f) && TryGetOnlineOwnerPosition(num2, out var position, out var rotation) && (!((Object)(object)ZNetScene.instance != (Object)null) || !((Object)(object)ZNetScene.instance.FindInstance(tracked.m_uid) != (Object)null)) && tracked.GetInt(ZDOVars.s_haveTargetHash, 0) == 0 && !(Vector3.Distance(tracked.GetPosition(), position) <= 60f)) { Vector3 val = (Vector3)(mercClass switch { MercClass.Healer => new Vector3(-2f, 0f, 1f), MercClass.Tank => new Vector3(2f, 0f, 1f), _ => new Vector3(0f, 0f, -2f), }); ClaimServerOwnership(tracked); tracked.SetPosition(position + rotation * val); tracked.SetRotation(rotation); ZDOMan instance = ZDOMan.instance; if (instance != null) { instance.ForceSendZDO(tracked.m_uid); } MercPlugin.Log($"Rejoined owner: {mercClass} {tracked.m_uid}" + (string.IsNullOrEmpty(text) ? "" : (" following '" + text + "'")) + " was stranded far from the online owner; moved to their side."); } } catch (Exception ex) { MercPlugin.LogWarn($"Followed-owner rejoin failed for {tracked.m_uid}: {ex.Message}"); } } private static bool TryGetOnlineOwnerPosition(long playerId, out Vector3 position, out Quaternion rotation) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: 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_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: 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_004b: 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_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) position = Vector3.zero; rotation = Quaternion.identity; try { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null && localPlayer.GetPlayerID() == playerId) { position = ((Component)localPlayer).transform.position; rotation = ((Component)localPlayer).transform.rotation; return true; } if ((Object)(object)ZNet.instance == (Object)null || ZDOMan.instance == null) { return false; } foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { if (peer != null && !((ZDOID)(ref peer.m_characterID)).IsNone()) { ZDO zDO = ZDOMan.instance.GetZDO(peer.m_characterID); if (zDO != null && zDO.IsValid() && zDO.GetLong(ZDOVars.s_playerID, 0L) == playerId) { position = zDO.GetPosition(); rotation = zDO.GetRotation(); return true; } } } } catch { } return false; } private static string RosterMemberName(ZDO banner, MercClass mercClass, int index) { return banner.GetString(MercBannerSpawn.CustomNameKeys[index], MercBannerSpawn.DefaultFirstName(mercClass)) + " " + ServerAuthority.RoleTitle(mercClass); } private static void AnnounceFallIfUnreported(ZDO banner, MercClass mercClass, int index, ZDO tracked) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) try { if (tracked != null && !IsLivingMercZdo(tracked) && ServerAuthority.AnnouncedFallen.Add(tracked.m_uid)) { ServerAuthority.AnnounceRosterFall(RosterMemberName(banner, mercClass, index)); } } catch { } } private static void RecoverLostMember(ZDO banner, MercClass mercClass, ZDO tracked) { //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: 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_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_008e: 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) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) try { if (!string.IsNullOrEmpty(Mercenary.FollowNameOf(tracked))) { return; } int num = tracked.GetInt(Mercenary.ZdoStayDay, 0); int currentDay = WorldDataService.CurrentDay; if ((num > 0 && currentDay > 0 && currentDay - num < 1) || ((Object)(object)ZNetScene.instance != (Object)null && (Object)(object)ZNetScene.instance.FindInstance(tracked.m_uid) != (Object)null)) { return; } Vector3 val = (Vector3)(mercClass switch { MercClass.Healer => new Vector3(-2f, 0f, 1f), MercClass.Tank => new Vector3(2f, 0f, 1f), _ => new Vector3(0f, 0f, -2f), }); Vector3 val2 = banner.GetPosition() + val; if (!(Vector3.Distance(tracked.GetPosition(), val2) <= 40f)) { ClaimServerOwnership(tracked); tracked.SetPosition(val2); tracked.SetRotation(Quaternion.LookRotation(-val)); tracked.Set(Mercenary.ZdoStayDay, 0, false); ZDOMan instance = ZDOMan.instance; if (instance != null) { instance.ForceSendZDO(tracked.m_uid); } MercPlugin.Log($"Recovered lost {mercClass} {tracked.m_uid}: it was not following, " + $"not instantiated, and far from banner {banner.m_uid}; moved home."); } } catch (Exception ex) { MercPlugin.LogWarn($"Lost-member recovery failed for {tracked.m_uid}: {ex.Message}"); } } private static bool IsLivingMercZdo(ZDO zdo) { if (zdo != null && zdo.IsValid() && !zdo.GetBool(ZDOVars.s_dead, false)) { return zdo.GetFloat(ZDOVars.s_health, 1f) > 0f; } return false; } private static bool SpawnMerc(ZDO banner, MercClass mercClass, int classIndex, int progressionStage) { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: 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_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0083: 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_0053: 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_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) GameObject mercPrefab = MercPrefabs.GetMercPrefab(mercClass); if ((Object)(object)mercPrefab == (Object)null) { MercPlugin.LogWarn($"Global banner authority has no prefab for {mercClass}; it will retry."); return false; } Vector3 val = (Vector3)(mercClass switch { MercClass.Healer => new Vector3(-2f, 0f, 1f), MercClass.Tank => new Vector3(2f, 0f, 1f), _ => new Vector3(0f, 0f, -2f), }); Vector3 val2 = banner.GetRotation() * val; Vector3 val3 = banner.GetPosition() + val2; float num = (((Object)(object)ZoneSystem.instance != (Object)null) ? ZoneSystem.instance.GetSolidHeight(val3) : (-10000f)); if (num > -10000f) { val3.y = num + 0.1f; } Quaternion val4 = ((((Vector3)(ref val2)).sqrMagnitude > 0.001f) ? Quaternion.LookRotation(-val2) : Quaternion.identity); GameObject val5 = Object.Instantiate<GameObject>(mercPrefab, val3, val4); ZNetView component = val5.GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid()) { ZDO zDO = component.GetZDO(); ClaimServerOwnership(zDO); zDO.Set(ZDOVars.s_modelIndex, (mercClass == MercClass.Healer) ? 1 : 0, false); Mercenary.SetBannerId(zDO, banner.m_uid); Mercenary.RestoreEmploymentFromBanner(zDO, banner, mercClass); if (progressionStage >= 0) { Mercenary.SetProgressionStage(zDO, progressionStage); } banner.Set(MercBannerSpawn.MemberIdKeys[classIndex], zDO.m_uid); MercPlugin.Log($"Global banner authority spawned {mercClass} {zDO.m_uid} for banner {banner.m_uid}."); MercPlugin.Log($"Employment synchronized: banner={banner.m_uid}, class={mercClass}, " + $"member={zDO.m_uid}, ownerId={Mercenary.EmployerIdOf(zDO)}, " + "ownerName=" + Mercenary.EmployerNameOf(zDO) + ", follow=" + Mercenary.FollowNameOf(zDO) + "."); return true; } Object.Destroy((Object)(object)val5); MercPlugin.LogWarn($"Global banner authority could not create a network ZDO for {mercClass}; it will retry."); return false; } private static void RemoveBannerAndRoster(ZDO banner, string reason) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0043: 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_0057: 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_0085: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) if (!IsBannerZdo(banner) || ZDOMan.instance == null) { return; } ZDOID uid = banner.m_uid; Dictionary<ZDOID, ZDO> dictionary = new Dictionary<ZDOID, ZDO>(); for (int i = 0; i < MercBannerSpawn.Classes.Length; i++) { ZDOID zDOID = banner.GetZDOID(MercBannerSpawn.MemberIdKeys[i]); ZDO val = ((!((ZDOID)(ref zDOID)).IsNone()) ? ZDOMan.instance.GetZDO(zDOID) : null); if (IsMercenaryZdo(val)) { dictionary[val.m_uid] = val; } foreach (ZDO item in FindPersistentMercZdos(MercBannerSpawn.Classes[i], uid)) { dictionary[item.m_uid] = item; } } try { foreach (ZDO item2 in AllZdosFromTable()) { if (item2 != null && item2.IsValid() && IsMercenaryZdo(item2) && Mercenary.BannerIdOf(item2) == uid) { dictionary[item2.m_uid] = item2; } } } catch (Exception ex) { MercPlugin.LogWarn("Banner removal safety sweep failed: " + ex.Message); } foreach (ZDO value in dictionary.Values) { DestroyWorldZdo(value, "its banner was " + reason); } try { MercBannerSpawn.ServerRemovalInProgress = true; DestroyWorldZdo(banner, "banner " + reason); } finally { MercBannerSpawn.ServerRemovalInProgress = false; } MercPlugin.Log($"Global banner authority removed banner {uid} and {dictionary.Count} mercenary ZDO(s): {reason}."); } private static void RemoveOrphanedMercenaries() { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) try { List<ZDO> list = new List<ZDO>(OrphanedMercs); if (ZDOMan.instance != null && ZdoObjectsById != null && ZdoObjectsById.GetValue(ZDOMan.instance) is IDictionary<ZDOID, ZDO>) { foreach (KeyValuePair<ZDOID, List<ZDO>> item in MercsByBanner) { if (!IsBannerZdo(ZDOMan.instance.GetZDO(item.Key))) { list.AddRange(item.Value); } } } int num = 0; int num2 = 0; foreach (ZDO item2 in list) { if (item2 != null && item2.IsValid()) { ZDO val = FindOwnerBannerFor(item2); if (val != null && AdoptIntoBanner(val, item2)) { num++; continue; } DestroyWorldZdo(item2, $"orphaned from missing banner {Mercenary.BannerIdOf(item2)}"); num2++; } } if (num > 0 || num2 > 0) { MercPlugin.Log($"Orphan sweep: adopted {num} living mercenary ZDO(s) into their " + $"employer's current banner; removed {num2} with no home banner."); } } catch (Exception ex) { MercPlugin.LogWarn("Orphaned mercenary cleanup failed: " + ex.Message); } } private static ZDO FindOwnerBannerFor(ZDO orphan) { try { long num = Mercenary.EmployerIdOf(orphan); if (num == 0L) { return null; } foreach (ZDO item in AllZdosFromTable()) { if (IsBannerZdo(item) && item.GetLong(MercBannerSpawn.ClaimOwnerIdKey, 0L) == num) { return item; } } } catch (Exception ex) { MercPlugin.LogWarn("Owner banner lookup failed: " + ex.Message); } return null; } private static bool AdoptIntoBanner(ZDO banner, ZDO orphan) { return TryAdoptLivingOrphan(banner, orphan); } private static void AdoptBeforeRosterCreation(ZDO banner) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) bool flag = false; string[] memberIdKeys = MercBannerSpawn.MemberIdKeys; foreach (string text in memberIdKeys) { if (!IsLivingMercZdo(ZDOMan.instance.GetZDO(banner.GetZDOID(text)))) { flag = true; break; } } if (!flag) { return; } long num = banner.GetLong(MercBannerSpawn.ClaimOwnerIdKey, 0L); foreach (ZDO item in AllZdosFromTable()) { if (IsMercenaryZdo(item) && IsLivingMercZdo(item) && Mercenary.EmployerIdOf(item) == num && !item.GetBool(Mercenary.ZdoStandalone, false)) { ZDOID val = Mercenary.BannerIdOf(item); if (!IsBannerZdo(ZDOMan.instance.GetZDO(val))) { TryAdoptLivingOrphan(banner, item); } } } } internal static bool TryAdoptLivingOrphan(ZDO banner, ZDO orphan) { //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_0164: 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_018f: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) try { if (!IsServer() || !IsBannerZdo(banner) || !IsLivingMercZdo(orphan) || Mercenary.EmployerIdOf(orphan) == 0L || Mercenary.EmployerIdOf(orphan) != banner.GetLong(MercBannerSpawn.ClaimOwnerIdKey, 0L)) { return false; } int prefab = orphan.GetPrefab(); MercClass mercClass = ((prefab != StringExtensionMethods.GetStableHashCode("Merc_Tank")) ? ((prefab == StringExtensionMethods.GetStableHashCode("Merc_Healer")) ? MercClass.Healer : ((prefab == StringExtensionMethods.GetStableHashCode("Merc_Archer")) ? MercClass.Archer : ((MercClass)(-1)))) : MercClass.Tank); if (mercClass < MercClass.Tank) { return false; } int num = Mathf.Clamp((int)mercClass, 0, MercBannerSpawn.MemberIdKeys.Length - 1); ZDOID zDOID = banner.GetZDOID(MercBannerSpawn.MemberIdKeys[num]); ZDO val = ((ZDOMan.instance != null) ? ZDOMan.instance.GetZDO(zDOID) : null); if (val != null && val.IsValid() && val.m_uid != orphan.m_uid && IsLivingMercZdo(val)) { return false; } ZDOID val2 = Mercenary.BannerIdOf(orphan); ClaimServerOwnership(banner); ClaimServerOwnership(orphan); banner.Set(MercBannerSpawn.CustomNameKeys[num], orphan.GetString(Mercenary.ZdoCustomName, MercBannerSpawn.DefaultFirstName(mercClass))); banner.Set(Mercenary.BannerEmployerIds[num], Mercenary.EmployerIdOf(orphan)); banner.Set(Mercenary.BannerEmployerNames[num], Mercenary.EmployerNameOf(orphan)); banner.Set(Mercenary.BannerFollowNames[num], Mercenary.FollowNameOf(orphan)); banner.Set(MercBannerSpawn.RecruitedKeys[num], true); Mercenary.SetBannerId(orphan, banner.m_uid); Mercenary.RestoreEmploymentFromBanner(orphan, banner, mercClass); banner.Set(MercBannerSpawn.MemberIdKeys[num], orphan.m_uid); MercPlugin.Log($"Adopted mercenary {orphan.m_uid} ({mercClass}) into banner {banner.m_uid}; " + $"its previous banner {val2} no longer exists."); return true; } catch (Exception ex) { MercPlugin.LogWarn($"Mercenary adoption failed for {orphan.m_uid}: {ex.Message}"); return false; } } private static bool IsMercenaryZdo(ZDO zdo) { if (zdo == null || !zdo.IsValid()) { return false; } int prefab = zdo.GetPrefab(); if (prefab != StringExtensionMethods.GetStableHashCode("Merc_Tank") && prefab != StringExtensionMethods.GetStableHashCode("Merc_Healer")) { return prefab == StringExtensionMethods.GetStableHashCode("Merc_Archer"); } return true; } internal static void DestroyWorldZdo(ZDO zdo, string reason) { //IL_000c: 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_002d: 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) if (zdo == null || ZDOMan.instance == null) { return; } ZDOID uid = zdo.m_uid; ClaimServerOwnership(zdo); GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.FindInstance(uid) : null); if ((Object)(object)val != (Object)null) { ZNetView component = val.GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid() && !component.IsOwner()) { component.ClaimOwnership(); } ZNetScene.instance.Destroy(val); } else { ClaimServerOwnership(zdo); ZDOMan.instance.DestroyZDO(zdo); } MercPlugin.Log($"Removed ZDO {uid}: {reason}"); } private static string PrefabName(MercClass mercClass) { return mercClass switch { MercClass.Archer => "Merc_Archer", MercClass.Healer => "Merc_Healer", _ => "Merc_Tank", }; } } internal static class ServerAuthority { internal sealed class SenderPlayerState { internal long SenderUid; internal long PeerUid; internal ZDOID CharacterZdoId; internal Player LivePlayer; internal ZDO PlayerZdo; internal long PlayerId; internal string PlayerName; internal Vector3 Position; internal bool IsDead; internal int RightItemHash; } internal sealed class MercenaryState { internal ZDOID MercId; internal ZDO MercZdo; internal ZDOID BannerId; internal ZDO BannerZdo; internal MercClass Class; internal string Name; internal Vector3 Position; internal long EmployerId; internal string EmployerName; internal string FollowName; } private sealed class ResourceJob { internal long Requester; internal long PlayerId; internal long Owner; internal int Token; internal float Expires; internal float NextHit; internal MercResourceWork.Target Target; internal int Stage; } [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static ConsoleEvent <>9__6_0; public static Func<long, bool> <>9__9_0; public static Func<CompanyPreset, string> <>9__9_2; public static Comparison<MercenaryState> <>9__66_0; internal void <RegisterCompanyCommand>b__6_0(ConsoleEventArgs args) { _companyConsole = args.Context; string text = string.Join(" ", args.Args.Skip(1).ToArray()); if (string.IsNullOrWhiteSpace(text)) { text = "status"; } if (text.Length > 160) { args.Context.AddString("Company command is too long."); return; } Register(); if (IsServer()) { OnCompanyCommand(ZNet.GetUID(), text); return; } ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null) { instance.InvokeRoutedRPC("DynamicNPCs_CompanyV1", new object[1] { text }); } } internal bool <OnCompanyCommand>b__9_0(long id) { if (id != ZNet.GetUID()) { return ZNet.instance.GetPeer(id) == null; } return false; } internal string <OnCompanyCommand>b__9_2(CompanyPreset p) { return p.Name + ": " + p.Formation.ToString() + " / " + p.Duty; } internal int <ListOwnedCompany>b__66_0(MercenaryState left, MercenaryState right) { int num = (int)left.Class; return num.CompareTo((int)right.Class); } } private const string CompanyCommandRpc = "DynamicNPCs_CompanyV1"; private const string CompanyReplyRpc = "DynamicNPCs_CompanyReplyV1"; internal const string CompanyFormationKey = "dnpc.company.formation.v1"; private const string CompanyPresetsKey = "dnpc.company.presets.v1"; private static readonly Dictionary<long, float> LastCompanyCommand = new Dictionary<long, float>(); private static Terminal _companyConsole; private const string AgentRequestRpc = "MercAgentRequestV1"; private const string AgentReplyRpc = "MercAgentReplyV1"; private const string CleanupRequestRpc = "DynamicNPCs_AdminClearRadiusRequestV1"; private const string CleanupReplyRpc = "DynamicNPCs_AdminClearRadiusReplyV1"; private const string PurgeRequestRpc = "DynamicNPCs_AdminPurgeMercsRequestV1"; private const string PlayerMessageRpc = "DynamicNPCs_PlayerMessageV1"; private const string MercRehireRequestRpc = "DynamicNPCs_MercRehireRequestV1"; private const string MercCommandRequestRpc = "DynamicNPCs_MercCommandRequestV1"; private const string MercRenameRequestRpc = "DynamicNPCs_MercRenameRequestV1"; private const string MercDismissRequestRpc = "DynamicNPCs_MercDismissRequestV1"; private const string MercConversationRequestRpc = "DynamicNPCs_MercConversationRequestV1"; private const string MercResurrectionRequestRpc = "DynamicNPCs_MercResurrectionRequestV1"; private const string MercSpeechReplyRpc = "DynamicNPCs_MercSpeechReplyV1"; private const string MercGuideApplyRpc = "DynamicNPCs_MercGuideApplyV1"; private const string MercResurrectionApplyRpc = "DynamicNPCs_MercResurrectionApplyV1"; private const string ContextCompanyOrderRequestRpc = "DynamicNPCs_ContextCompanyOrderRequestV1"; private const string ContextTargetApplyRpc = "DynamicNPCs_ContextTargetApplyV1"; private static readonly object RequestLock = new object(); private static readonly Dictionary<long, int> PendingAi = new Dictionary<long, int>(); private static readonly Dictionary<long, int> LastAiRequest = new Dictionary<long, int>(); private static readonly Queue<int> AiRequestTimes = new Queue<int>(); private static readonly object ContextOrderLock = new object(); private static readonly Dictionary<long, int> LastContextOrderAt = new Dictionary<long, int>(); private static readonly Dictionary<long, int> LastContextOrderSequence = new Dictionary<long, int>(); private static readonly object IdentityLock = new object(); private static readonly Dictionary<long, long> PinnedPeerPlayerIds = new Dictionary<long, long>(); private static readonly Dictionary<long, long> PinnedPlayerPeers = new Dictionary<long, long>(); private static readonly FieldInfo PeerSocketField = AccessTools.Field(typeof(ZNetPeer), "m_socket"); private static readonly FieldInfo ZdoObjectsById = AccessTools.Field(typeof(ZDOMan), "m_objectsByID"); private static ZRoutedRpc _registeredRpc; internal static readonly HashSet<ZDOID> AnnouncedFallen = new HashSet<ZDOID>(); private const string ResourceRequestRpc = "DynamicNPCs_ResourceWorkRequestV1"; private const string ResourceApplyRpc = "DynamicNPCs_ResourceWorkApplyV1"; private const string ResourceSwingRpc = "DynamicNPCs_ResourceWorkSwingV1"; private const string ResourceStopRpc = "DynamicNPCs_ResourceWorkStopV1"; private static ZRoutedRpc _resourceRpc; private static int _resourceToken; private static readonly Dictionary<ZDOID, ResourceJob> ResourceJobs = new Dictionary<ZDOID, ResourceJob>(); internal static void RegisterCompanyCommand() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown object obj = <>c.<>9__6_0; if (obj == null) { ConsoleEvent val = delegate(ConsoleEventArgs args) { _companyConsole = args.Context; string text = string.Join(" ", args.Args.Skip(1).ToArray()); if (string.IsNullOrWhiteSpace(text)) { text = "status"; } if (text.Length > 160) { args.Context.AddString("Company command is too long."); } else { Register(); if (IsServer()) { OnCompanyCommand(ZNet.GetUID(), text); } else { ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null) { instance.InvokeRoutedRPC("DynamicNPCs_CompanyV1", new object[1] { text }); } } } }; <>c.<>9__6_0 = val; obj = (object)val; } new ConsoleCommand("dnpc_company", "company status | preset list | preset save <name> <roles|tight|line> <follow|hold> | preset apply/delete <name>", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } private static void OnCompanyReply(long sender, string message) { if (!IsAuthoritativeServerSender(sender) || message == null || message.Length > 1800) { return; } if ((Object)(object)_companyConsole != (Object)null) { _companyConsole.AddString(message); return; } Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)1, message, 0, (Sprite)null, false); } } private static void ReplyCompany(long sender, string message) { message = Bound(message, 1800); if (sender == ZNet.GetUID()) { OnCompanyReply(sender, message); return; } ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null) { instance.InvokeRoutedRPC(sender, "DynamicNPCs_CompanyReplyV1", new object[1] { message }); } } private static void OnCompanyCommand(long sender, string payload) { //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: 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_0250: Unknown result type (might be due to invalid IL or missing references) //IL_0650: Unknown result type (might be due to invalid IL or missing references) //IL_0684: Unknown result type (might be due to invalid IL or missing references) //IL_066d: Unknown result type (might be due to invalid IL or missing references) //IL_0689: Unknown result type (might be due to invalid IL or missing references) //IL_06b1: Unknown result type (might be due to invalid IL or missing references) //IL_06bd: Unknown result type (might be due to invalid IL or missing references) //IL_06c7: Unknown result type (might be due to invalid IL or missing references) //IL_06cc: Unknown result type (might be due to invalid IL or missing references) if (!IsServer() || payload == null || payload.Length > 160 || !TryResolveSender(sender, out var requester)) { return; } float unscaledTime = Time.unscaledTime; if (LastCompanyCommand.TryGetValue(sender, out var value) && unscaledTime - value < 1f) { return; } long[] array = LastCompanyCommand.Keys.Where((long id) => id != ZNet.GetUID() && ZNet.instance.GetPeer(id) == null).ToArray(); foreach (long key in array) { LastCompanyCommand.Remove(key); } LastCompanyCommand[sender] = unscaledTime; try { string[] parts = payload.Trim().ToLowerInvariant().Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries); ZDO val = ((IEnumerable<ZDO>)BannerAuthority.AllZdosFromTable()).FirstOrDefault((Func<ZDO, bool>)((ZDO zdo) => zdo != null && zdo.IsValid() && zdo.GetPrefab() == StringExtensionMethods.GetStableHashCode("MercBanner") && zdo.GetLong(MercBannerSpawn.ClaimOwnerIdKey, 0L) == requester.PlayerId)); if (parts.Length == 1 && parts[0] == "status") { StringBuilder stringBuilder = new StringBuilder("Your company: player=" + requester.PlayerId + ", banner=" + ((val != null) ? ((object)Unsafe.As<ZDOID, ZDOID>(ref val.m_uid)/*cast due to .constrained prefix*/).ToString() : "missing") + "\n"); foreach (ZDO item in BannerAuthority.AllZdosFromTable()) { if (item != null && item.IsValid() && Mercenary.EmployerIdOf(item) == requester.PlayerId && TryResolveMercenary(item.m_uid, out var state, out var _, allowMissingBanner: true)) { stringBuilder.Append(state.Name).Append(": id=").Append(state.MercId) .Append(", owner=") .Append(item.GetOwner()) .Append(", duty=") .Append(string.IsNullOrEmpty(state.FollowName) ? "hold" : "follow") .Append(", distance=") .Append(Vector3.Distance(requester.Position, state.Position).ToString("F0")) .Append("m, ") .Append((state.BannerZdo == null) ? "orphan: awaiting owned banner recovery" : "roster linked") .AppendLine(); } } ReplyCompany(sender, stringBuilder.ToString()); return; } if (val == null) { throw new ArgumentException("Claim a company banner first."); } if (requester.IsDead) { throw new ArgumentException("Company presets cannot change while you are dead."); } if (parts.Length < 2 || parts[0] != "preset") { throw new ArgumentException("Use status or preset list/save/apply/delete."); } List<CompanyPreset> list = CompanyPresetRules.Decode(val.GetString("dnpc.company.presets.v1", "")); if (parts.Length == 2 && parts[1] == "list") { ReplyCompany(sender, (list.Count == 0) ? "No presets. Save one with: dnpc_company preset save travel roles follow" : string.Join("\n", list.Select((CompanyPreset p) => p.Name + ": " + p.Formation.ToString() + " / " + p.Duty))); return; } if (parts.Length < 3 || !CompanyPresetRules.ValidName(parts[2])) { throw new ArgumentException("Use a 1–24 character name containing a-z, 0-9, - or _."); } CompanyPreset companyPreset = list.FirstOrDefault((CompanyPreset p) => p.Name == parts[2]); if (parts[1] == "save" && parts.Length == 5) { if (!Enum.TryParse<CompanyFormation>(parts[3], ignoreCase: true, out var result) || !Enum.IsDefined(typeof(CompanyFormation), result) || !Enum.TryParse<CompanyDuty>(parts[4], ignoreCase: true, out var result2) || !Enum.IsDefined(typeof(CompanyDuty), result2)) { throw new ArgumentException("Choose roles/tight/line and follow/hold."); } if (companyPreset == null) { if (list.Count >= 8) { throw new ArgumentException("Delete a preset before adding a ninth."); } list.Add(companyPreset = new CompanyPreset { Name = parts[2] }); } companyPreset.Formation = result; companyPreset.Duty = result2; EnsureZdoServerOwnership(val); val.Set("dnpc.company.presets.v1", CompanyPresetRules.Encode(list)); ReplyCompany(sender, "Saved preset " + companyPreset.Name + "."); return; } if (parts[1] == "delete" && parts.Length == 3 && companyPreset != null) { list.Remove(companyPreset); EnsureZdoServerOwnership(val); val.Set("dnpc.company.presets.v1", CompanyPresetRules.Encode(list)); ReplyCompany(sender, "Deleted preset " + companyPreset.Name + "."); return; } if (parts[1] == "apply" && parts.Length == 3 && companyPreset != null) { ConfigEntry<bool> contextCompanyOrdersEnabled = MercConfig.ContextCompanyOrdersEnabled; if (contextCompanyOrdersEnabled == null || !contextCompanyOrdersEnabled.Value) { throw new ArgumentException("The server disabled company orders."); } List<MercenaryState> list2 = ListOwnedCompany(requester); if (list2.Count == 0) { throw new ArgumentException("No employed company is ready."); } EnsureZdoServerOwnership(val); val.Set("dnpc.company.formation.v1", (int)companyPreset.Formation); foreach (MercenaryState item2 in list2) { EnsureZdoServerOwnership(item2.MercZdo); item2.MercZdo.Set("dnpc.company.formation.v1", (int)companyPreset.Formation); } if (companyPreset.Duty == CompanyDuty.Follow) { ApplyCompanyRecall(sender, requester, list2); } else { ApplyCompanyHold(sender, requester, list2, requester.Position); Vector3 forward = (((Object)(object)requester.LivePlayer != (Object)null) ? ((Component)requester.LivePlayer).transform.forward : Vector3.forward); foreach (MercenaryState item3 in list2) { item3.MercZdo.Set(Mercenary.ZdoStayAnchor, requester.Position + MercFormation.Offset(item3.Class, forward, MercMovementMode.Travel, companyPreset.Formation)); } } ReplyCompany(sender, "Applied " + companyPreset.Name + ": " + companyPreset.Formation.ToString() + " / " + companyPreset.Duty.ToString() + "."); return; } throw new ArgumentException("Unknown preset or syntax. Use preset list, save <name> <formation> <duty>, apply <name>, or delete <name>."); } catch (Exception ex) { ReplyCompany(sender, "Company: " + ex.Message); } } internal static void Register() { ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null && instance != _registeredRpc) { instance.Register<string>("MercAgentRequestV1", (Action<long, string>)OnAgentRequest); instance.Register<string>("DynamicNPCs_CompanyV1", (Action<long, string>)OnCompanyCommand); instance.Register<string>("DynamicNPCs_CompanyReplyV1", (Action<long, string>)OnCompanyReply); instance.Register<string, string>("MercAgentReplyV1", (Action<long, string, string>)OnAgentReply); instance.Register<float>("DynamicNPCs_AdminClearRadiusRequestV1", (Action<long, float>)OnCleanupRequest); instance.Register<string>("DynamicNPCs_AdminClearRadiusReplyV1", (Action<long, string>)OnCleanupReply); instance.Register("DynamicNPCs_AdminPurgeMercsRequestV1", (Action<long>)OnPurgeRequest); instance.Register<string>("DynamicNPCs_PlayerMessageV1", (Action<long, string>)OnPlayerMessage); instance.Register<ZDOID, int>("DynamicNPCs_MercRehireRequestV1", (Action<long, ZDOID, int>)OnMercRehireRequest); instance.Register<ZDOID, bool>("DynamicNPCs_MercCommandRequestV1", (Action<long, ZDOID, bool>)OnMercCommandRequest); instance.Register<ZDOID, string>("DynamicNPCs_MercRenameRequestV1", (Action<long, ZDOID, string>)OnMercRenameRequest); instance.Register<ZDOID>("DynamicNPCs_MercDismissRequestV1", (Action<long, ZDOID>)OnMercDismissRequest); instance.Register<ZDOID, int, int, string, string>("DynamicNPCs_GuideMenuRequestV1", (Method<ZDOID, int, int, string, string>)OnGuideMenuRequest); instance.Register<ZDOID, string>("DynamicNPCs_MercConversationRequestV1", (Action<long, ZDOID, string>)OnMercConversationRequest); instance.Register<ZDOID, ZDOID>("DynamicNPCs_MercResurrectionRequestV1", (Action<long, ZDOID, ZDOID>)OnMercResurrectionRequest); instance.Register<ZDOID, string, string>("DynamicNPCs_MercSpeechReplyV1", (Action<long, ZDOID, string, string>)OnMercSpeechReply); instance.Register<ZDOID, ZDOID, string>("DynamicNPCs_MercGuideApplyV1", (Action<long, ZDOID, ZDOID, string>)OnMercGuideApply); instance.Register<ZDOID, ZDOID>("DynamicNPCs_MercResurrectionApplyV1", (Action<long, ZDOID, ZDOID>)OnMercResurrectionApply); instance.Register<int, ZDOID, Vector3, int>("DynamicNPCs_ContextCompanyOrderRequestV1", (Method<int, ZDOID, Vector3, int>)OnContextCompanyOrderRequest); instance.Register<ZDOID, ZDOID, int, ZDOID>("DynamicNPCs_ContextTargetApplyV1", (Method<ZDOID, ZDOID, int, ZDOID>)OnContextTargetApply); MercResourceWork.Register(); _registeredRpc = instance; MercPlugin.Log("Registered server-authoritative mercenary RPC protocol."); } } internal static void Reset() { MercResourceWork.Reset(); lock (RequestLock) { PendingAi.Clear(); LastAiRequest.Clear(); AiRequestTimes.Clear(); } lock (ContextOrderLock) { LastContextOrderAt.Clear(); LastContextOrderSequence.Clear(); } lock (IdentityLock) { PinnedPeerPlayerIds.Clear(); PinnedPlayerPeers.Clear(); } AnnouncedFallen.Clear(); } internal static void SendAgentQuestion(string question) { if (ZRoutedRpc.instance != null) { string text = Bound(question, 1000); if (!string.IsNullOrEmpty(text)) { string text2 = "{\"q\":\"" + MiniJson.Escape(text) + "\"}"; ZRoutedRpc.instance.InvokeRoutedRPC("MercAgentRequestV1", new object[1] { text2 }); } } } internal static void RequestNpcCleanup(float radius) { Register(); float num = Mathf.Clamp(radius, 1f, 200f); MercPlugin.Log($"Admin NPC cleanup client request: radius={num:F1}m, " + $"localPeer={(((Object)(object)ZNet.instance != (Object)null) ? ZNet.GetUID() : 0)}, " + $"routedRpcExists={ZRoutedRpc.instance != null}."); if (ZRoutedRpc.instance == null) { Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, MercLocalization.Text("dnpc_message_cleanup_network_failed"), 0, (Sprite)null, false); } } else { ZRoutedRpc.instance.InvokeRoutedRPC("DynamicNPCs_AdminClearRadiusRequestV1", new object[1] { num }); } } internal static void RequestMercPurge() { Register(); if (ZRoutedRpc.instance == null) { Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, MercLocalization.Text("dnpc_message_purge_network_failed"), 0, (Sprite)null, false); } } else { ZRoutedRpc.instance.InvokeRoutedRPC("DynamicNPCs_AdminPurgeMercsRequestV1", Array.Empty<object>()); } } internal static void RequestMercRehire(ZDOID mercId, int progressionSeed) { //IL_000a: 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) Register(); MercPlugin.Log($"Mercenary rehire client request: mercZdo={mercId}, " + $"localPeer={(((Object)(object)ZNet.instance != (Object)null) ? ZNet.GetUID() : 0)}, " + $"routedRpcExists={ZRoutedRpc.instance != null}."); if (ZRoutedRpc.instance == null || ((ZDOID)(ref mercId)).IsNone()) { Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, MercLocalization.Text("dnpc_message_rehire_network_failed"), 0, (Sprite)null, false); } } else { ZRoutedRpc.instance.InvokeRoutedRPC("DynamicNPCs_MercRehireRequestV1", new object[2] { mercId, progressionSeed }); } } internal static void RequestMercCommand(ZDOID mercId, bool message) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) Register(); MercPlugin.Log($"Mercenary command client request: mercZdo={mercId}, localPeer={(((Object)(object)ZNet.instance != (Object)null) ? ZNet.GetUID() : 0)}."); ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null) { instance.InvokeRoutedRPC("DynamicNPCs_MercCommandRequestV1", new object[2] { mercId, message }); } } internal static void RequestMercRename(ZDOID mercId, string name) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) Register(); ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null) { instance.InvokeRoutedRPC("DynamicNPCs_MercRenameRequestV1", new object[2] { mercId, Bound(name, 24) }); } } internal static void RequestMercDismiss(ZDOID mercId) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) Register(); ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null) { instance.InvokeRoutedRPC("DynamicNPCs_MercDismissRequestV1", new object[1] { mercId }); } } internal static void RequestMercConversation(ZDOID mercId, string payload) { //IL_000a: 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) Register(); MercPlugin.Log(string.Format("Merc conversation client request: mercZdo={0}, payloadLength={1}.", mercId, (payload ?? "").Length)); ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null) { instance.InvokeRoutedRPC("DynamicNPCs_MercConversationRequestV1", new object[2] { mercId, Bound(payload, 10000) }); } } internal static void RequestMercResurrection(ZDOID mercId, ZDOID playerId) { //IL_001c: 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) Register(); ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null) { instance.InvokeRoutedRPC("DynamicNPCs_MercResurrectionRequestV1", new object[2] { mercId, playerId }); } } internal static void RequestContextCompanyOrder(MercContextOrderType order, ZDOID targetId, Vector3 point, int sequence) { //IL_0025: 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) Register(); ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null) { instance.InvokeRoutedRPC("DynamicNPCs_ContextCompanyOrderRequestV1", new object[4] { (int)order, targetId, point, sequence }); } } internal static long GetServerPeerUid() { if ((Object)(object)ZNet.instance == (Object)null) { return 0L; } if (ZNet.instance.IsServer()) { return ZNet.GetUID(); } return ZNet.instance.GetServerPeer()?.m_uid ?? 0; } private static void OnAgentRequest(long sender, string payload) { if (string.IsNullOrEmpty(payload) || payload.Length > 10000) { return; } MercPlugin.Log($"Private agent request received: sender={sender}."); if (!IsServer()) { MercPlugin.LogWarn($"Private agent request rejected: sender={sender}, reason=handler is not the authoritative server."); return; } if (!TryResolveSender(sender, out var state)) { MercPlugin.LogWarn($"Private agent request rejected: sender={sender}, reason=sender player/character ZDO could not be resolved."); SendAgentReply(sender, "I cannot identify your character on the server yet. Try again in a moment."); return; } if (!MercConfig.AgentChatEnabled.Value) { MercPlugin.LogWarn($"Private agent request rejected: sender={sender}, reason=AgentChatEnabled is false."); SendAgentReply(sender, "Private ! agent chat is disabled by the server."); return; } if (!TryBeginAi(sender, state, null, agentMode: true)) { MercPlugin.LogWarn($"Private agent request rejected: sender={sender}, reason=AI request is already pending or rate-limited."); return; } string text = Bound(ReadString(MiniJson.Parse(payload) as Dictionary<string, object>, "q"), 1000); if (string.IsNullOrWhiteSpace(