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 TooManyLags FGN Addon v1.0.12
TooManyLags.dll
Decompiled 4 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.Generic; using System.Globalization; using System.IO; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; using System.Security.Cryptography; using System.Text; using System.Threading; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using HarmonyLib; using TooManyLags.PlayerSimulation; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("1.0.12.0")] namespace TooManyLags { internal sealed class AuthorityController { private struct Receipt { internal int Epoch; internal bool Ready; } private struct OwnerCell : IEquatable<OwnerCell> { internal long Owner; internal Cell Cell; internal Vector2s Center; public bool Equals(OwnerCell other) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) if (Owner == other.Owner && Cell.Equals(other.Cell)) { return ((Vector2s)(ref Center)).Equals(other.Center); } return false; } public override bool Equals(object other) { if (other is OwnerCell) { return Equals((OwnerCell)other); } return false; } public override int GetHashCode() { return Owner.GetHashCode() ^ Cell.GetHashCode() ^ ((object)Unsafe.As<Vector2s, Vector2s>(ref Center)/*cast due to .constrained prefix*/).GetHashCode(); } } internal sealed class NativeNode : AuthorityNode { private readonly AuthorityController owner; internal readonly ZDO Data; internal readonly ZDOID Id; internal readonly ZNetView View; internal readonly Kinds Kind; private readonly WearNTear wear; private readonly Character actor; private readonly Tameable tameable; private readonly bool ship; private readonly bool serverStation; private readonly bool multipleInventories; private readonly Vagon cart; private readonly Container container; internal long ObservedOwner; internal uint Revision; internal int Requests; private float refillAt; private float refillUntil; private float inventoryAt; private float inventoryUntil; private long refillOwner; private long inventoryOwner; private uint refillRevision; private bool coveredBefore; internal bool ServerStation => serverStation; internal bool Summoned { get { if (Kind == Kinds.TamedAnimals) { if (!ObjectCatalog.IsSummoned(tameable)) { return FriendlyCreatures.IsFriendly(actor); } return true; } return false; } } internal override long CurrentOwner => Data.GetOwner(); internal NativeNode(AuthorityController owner, ZDO data, ZNetView view, Kinds kind, Cell cell, Tameable animal, Character character) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) this.owner = owner; Data = data; Id = data.m_uid; View = view; Kind = kind; Cell = cell; coveredBefore = owner.indexed.Grid.Candidate(cell) != 0; wear = ((Component)view).GetComponent<WearNTear>(); ship = kind == Kinds.Vehicles && Object.op_Implicit((Object)(object)((Component)view).GetComponent<Ship>()); if (kind == Kinds.Vehicles) { cart = ((Component)view).GetComponent<Vagon>(); } if (kind == Kinds.TamedAnimals) { actor = character; tameable = animal; } Container[] componentsInChildren = ((Component)view).GetComponentsInChildren<Container>(true); foreach (Container val in componentsInChildren) { ZNetView val2 = (Object.op_Implicit((Object)(object)val.m_rootObjectOverride) ? val.m_rootObjectOverride : ((Component)val).GetComponentInParent<ZNetView>()); if (!((Object)(object)val2 != (Object)(object)view)) { if (Object.op_Implicit((Object)(object)container)) { multipleInventories = true; } else { container = val; } } } serverStation = Object.op_Implicit((Object)(object)((Component)view).GetComponentInChildren<Smelter>(true)) || Object.op_Implicit((Object)(object)((Component)view).GetComponentInChildren<CookingStation>(true)) || Object.op_Implicit((Object)(object)((Component)view).GetComponentInChildren<Fireplace>(true)) || Object.op_Implicit((Object)(object)((Component)view).GetComponentInChildren<Fermenter>(true)) || Object.op_Implicit((Object)(object)((Component)view).GetComponentInChildren<ShieldGenerator>(true)) || Object.op_Implicit((Object)(object)((Component)view).GetComponentInChildren<Turret>(true)) || kind == Kinds.Incinerators; ObservedOwner = data.GetOwner(); Revision = data.OwnerRevision; } internal override bool CanRemember(long fieldOwner) { long num = ((owner.refillStations && serverStation) ? owner.server : fieldOwner); if (Managed && ManagedOwner == num) { return Data.GetOwner() == num; } return false; } internal void Refilled(int method) { if (ObjectCatalog.RefillRequest(Kind, method)) { refillOwner = Data.GetOwner(); refillRevision = Data.OwnerRevision; refillAt = Time.unscaledTime; refillUntil = refillAt + 10f; } if (method == StringExtensionMethods.GetStableHashCode("RPC_RequestOpen") || method == StringExtensionMethods.GetStableHashCode("RPC_RequestStack") || method == StringExtensionMethods.GetStableHashCode("RPC_RequestTakeAll")) { inventoryOwner = Data.GetOwner(); inventoryAt = Time.unscaledTime; inventoryUntil = inventoryAt + 5f; } } internal bool UseProtected() { float unscaledTime = Time.unscaledTime; if (refillOwner == 0 || !(unscaledTime >= refillAt) || !(unscaledTime < refillUntil) || Data.GetOwner() != refillOwner || Data.OwnerRevision != refillRevision) { if (Object.op_Implicit((Object)(object)container)) { if (!(unscaledTime >= inventoryAt) || !(unscaledTime < inventoryUntil) || inventoryOwner == 0) { return Data.GetInt(ZDOVars.s_inUse, 0) != 0; } return true; } return false; } return true; } internal void ObserveUse() { if (Object.op_Implicit((Object)(object)container) && Data.GetInt(ZDOVars.s_inUse, 0) != 0) { inventoryOwner = 0L; inventoryUntil = 0f; } } internal bool Identity() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) if (!Removed && Data.IsValid() && Data.m_uid == Id && object.ReferenceEquals(owner.world.GetZDO(Id), Data) && Object.op_Implicit((Object)(object)View) && View.IsValid() && object.ReferenceEquals(View.GetZDO(), Data) && ((Component)View).gameObject.activeInHierarchy && !View.m_distant && (Object)(object)((Component)View).transform.parent == (Object)null) { return !BakedObjects.IsBaked(Data); } return false; } internal bool Controllable() { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Invalid comparison between Unknown and I4 if (Kind == Kinds.Incinerators) { return false; } if (multipleInventories || (Object.op_Implicit((Object)(object)container) && (int)container.m_privacy != 2)) { return false; } if (Kind != Kinds.TamedAnimals) { if (View.m_persistent && (!Object.op_Implicit((Object)(object)wear) || ((Behaviour)wear).isActiveAndEnabled) && (!ship || !owner.compatibility.ShipsOwnedExternally) && Data.GetLong(ZDOVars.s_user, 0L) == 0) { if (Object.op_Implicit((Object)(object)cart)) { return !cart.InUse(); } return true; } return false; } if (!Summoned && Object.op_Implicit((Object)(object)actor) && !(actor is Player) && ((Behaviour)actor).isActiveAndEnabled && Data.GetBool(ZDOVars.s_tamed, false) && Data.GetLong(ZDOVars.s_user, 0L) == 0 && !actor.IsDead() && !actor.IsAttached() && !actor.IsRiding() && (!Object.op_Implicit((Object)(object)tameable) || !tameable.HaveRider())) { if (Object.op_Implicit((Object)(object)tameable) && tameable.m_commandable) { return string.IsNullOrEmpty(Data.GetString(ZDOVars.s_follow, "")); } return true; } return false; } private long DesiredOwner(long fieldOwner) { if (owner.refillStations && serverStation) { return owner.server; } if (!owner.NeedsGrid(Cell)) { return 0L; } if (owner.indexed.Grid.Candidate(Cell) == 0) { if (owner.keepOnExit && coveredBefore) { return 0L; } if (owner.directional && !coveredBefore) { fieldOwner = 0L; } } if (fieldOwner == 0 && owner.defaultInteractives) { return owner.server; } return fieldOwner; } internal override ApplyResult Apply(long target) { //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: 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_0187: Invalid comparison between Unknown and I4 //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_0335: Unknown result type (might be due to invalid IL or missing references) //IL_0325: Unknown result type (might be due to invalid IL or missing references) //IL_0389: Unknown result type (might be due to invalid IL or missing references) //IL_038e: Unknown result type (might be due to invalid IL or missing references) //IL_038f: Unknown result type (might be due to invalid IL or missing references) //IL_0394: Unknown result type (might be due to invalid IL or missing references) //IL_03d8: Unknown result type (might be due to invalid IL or missing references) //IL_03dd: Unknown result type (might be due to invalid IL or missing references) //IL_03ec: Unknown result type (might be due to invalid IL or missing references) //IL_0420: Unknown result type (might be due to invalid IL or missing references) //IL_04b7: Unknown result type (might be due to invalid IL or missing references) //IL_05c0: Unknown result type (might be due to invalid IL or missing references) //IL_0557: Unknown result type (might be due to invalid IL or missing references) //IL_06c8: Unknown result type (might be due to invalid IL or missing references) //IL_0617: Unknown result type (might be due to invalid IL or missing references) if (!Identity() || Summoned) { owner.Remove(this); return ApplyResult.Dropped; } if ((!owner.refillStations || !serverStation) && !owner.NeedsGrid(Cell)) { if (owner.Inventory.Transitioning(Data) || owner.Cooperative.Transitioning(Data) || owner.TransferPending(Data)) { return ApplyResult.Pending; } owner.Inventory.Forget(Data); owner.Cooperative.Forget(Data); Managed = false; return ApplyResult.Done; } if (!coveredBefore && owner.indexed.Grid.Candidate(Cell) != 0) { coveredBefore = true; } if (!Controllable()) { Managed = false; if (Kind == Kinds.TamedAnimals && Object.op_Implicit((Object)(object)actor) && !actor.IsDead() && Data.GetBool(ZDOVars.s_tamed, false)) { return ApplyResult.Pending; } if (Kind == Kinds.Vehicles && !multipleInventories && (!ship || !owner.compatibility.ShipsOwnedExternally) && (!Object.op_Implicit((Object)(object)container) || (int)container.m_privacy == 2)) { return ApplyResult.Pending; } return ApplyResult.Dropped; } if ((!owner.refillStations || !serverStation) && target == 0 && owner.defaultInteractives && owner.indexed.Grid.Candidate(Cell) != 0) { return ApplyResult.Pending; } target = DesiredOwner(target); if (target == 0) { return ApplyResult.Done; } Vector3 position = Data.GetPosition(); if (!Finite(position) || !Cell.At(position.x, position.z, owner.cellSize, out var cell)) { return ApplyResult.Dropped; } if (!cell.Equals(Cell)) { owner.indexed.Move(this, cell, Time.unscaledTime); return ApplyResult.Pending; } if (!owner.AvailableOwner(target, position)) { return ApplyResult.Pending; } long num = Data.GetOwner(); uint ownerRevision = Data.OwnerRevision; bool flag = owner.TransferPending(Data); if (num == target && !flag && (!Object.op_Implicit((Object)(object)container) || !owner.Inventory.Received(Data) || owner.Inventory.Acquire(Data, View, container) == 2)) { Managed = true; ManagedOwner = target; owner.Inventory.Forget(Data); owner.Cooperative.Forget(Data); return ApplyResult.Done; } if (UseProtected() && owner.AvailableOwner(num, position)) { return ApplyResult.Pending; } if (!owner.AreaReady(position)) { return ApplyResult.Pending; } if (Kind != Kinds.TamedAnimals) { if (ObjectCatalog.Classify(((Component)View).gameObject) != Kind) { goto IL_03a4; } if (Object.op_Implicit((Object)(object)wear) && wear.m_staticPosition) { Vector3 val = ((Component)View).transform.position - position; if (((Vector3)(ref val)).sqrMagnitude > 0.0025f) { goto IL_03a4; } } } if (!Identity() || !Controllable() || Data.GetOwner() != num || Data.OwnerRevision != ownerRevision || Data.GetPosition() != position || !owner.AvailableOwner(target, position)) { return ApplyResult.Pending; } if (ownerRevision == 65535) { Managed = false; return ApplyResult.Dropped; } if (Object.op_Implicit((Object)(object)container)) { if (num != 0 && owner.AvailableOwner(num, position)) { if (owner.Inventory.Acquire(Data, View, container) != 2) { return ApplyResult.Pending; } num = Data.GetOwner(); ownerRevision = Data.OwnerRevision; } else { owner.Inventory.Forget(Data); } } else if (Kind != Kinds.TamedAnimals && num != owner.server && num != 0 && owner.AvailableOwner(num, position)) { switch (owner.Cooperative.Request(Data, target)) { case 1: return ApplyResult.Pending; case 2: Managed = true; ManagedOwner = Data.GetOwner(); ObservedOwner = ManagedOwner; Revision = Data.OwnerRevision; owner.Cooperative.Forget(Data); if (ManagedOwner != owner.server) { owner.world.ForceSendZDO(ManagedOwner, Id); } return ApplyResult.Done; } } if (!Identity() || !Controllable() || Data.GetOwner() != num || Data.OwnerRevision != ownerRevision || DesiredOwner(owner.indexed.Grid.Owner(Cell)) != target || !owner.AvailableOwner(target, Data.GetPosition())) { return ApplyResult.Pending; } if (Data.GetOwner() != target) { if (Data.OwnerRevision == ushort.MaxValue) { return ApplyResult.Dropped; } owner.writing = true; try { if (target != owner.server) { owner.world.ForceSendZDO(target, Id); } Data.SetOwner(target); } finally { owner.writing = false; } } ObservedOwner = Data.GetOwner(); Revision = Data.OwnerRevision; Managed = ObservedOwner == target; ManagedOwner = ObservedOwner; if (Managed) { owner.Inventory.Forget(Data); owner.Cooperative.Forget(Data); if (target != owner.server) { owner.world.ForceSendZDO(target, Id); } } if (!Managed) { return ApplyResult.Pending; } return ApplyResult.Done; IL_03a4: return ApplyResult.Dropped; } } private readonly Kinds kinds; private float delay; private readonly OwnershipCadence cadence; private readonly CompatibilityBridge compatibility; private readonly Action<Exception> fault; private readonly Action<Exception> requestFault; private readonly bool staticEnabled; private readonly bool defaultInteractives; private readonly bool refillStations; private readonly bool keepOnExit; private readonly int cellSize; private readonly GridCoveragePattern pattern; private readonly bool directional; private float innerDelay; private float outerDelay; private float forwardDelay; private StaticBuildings statics; private readonly Dictionary<ZDOID, NativeNode> nodes = new Dictionary<ZDOID, NativeNode>(); private ConditionalWeakTable<ZNetView, NativeNode> views = new ConditionalWeakTable<ZNetView, NativeNode>(); private readonly Dictionary<Vector2s, Receipt> readiness = new Dictionary<Vector2s, Receipt>(); private readonly Dictionary<OwnerCell, bool> available = new Dictionary<OwnerCell, bool>(); private readonly List<GridPeer> peers = new List<GridPeer>(); private readonly HashSet<long> peerIds = new HashSet<long>(); private readonly CameraWake cameras = new CameraWake(); private readonly RegionContentionGate regions = new RegionContentionGate(); private readonly List<RegionPeer> regionPeers = new List<RegionPeer>(); private readonly List<ZDO> characters = new List<ZDO>(); private static readonly Comparison<GridPeer> peerOrder = (GridPeer a, GridPeer b) => a.Uid.CompareTo(b.Uid); private readonly Func<ZNetScene, Dictionary<ZDO, ZNetView>> instances; private ObjectCatalog catalog; private AuthorityWorld indexed; private ZNet network; private ZDOMan world; private ZNetScene scene; private long server; private int epoch; private bool primed; private bool active; private bool failed; private bool writing; private bool coarseEnabled; internal readonly RequestRouter Router; internal NativeInventoryHandoff Inventory { get; private set; } internal FgnOwnerHandoff Cooperative { get; private set; } internal bool SendingInventory { get { if (Inventory != null) { return Inventory.Sending; } return false; } } internal bool IsActive { get { if (active) { return !failed; } return false; } } internal RegionContentionGate RegionGate => regions; internal int ScheduledAttempts { get { if (indexed != null) { return indexed.Attempts; } return 0; } } internal int FieldUpdates { get { if (indexed != null) { return indexed.Grid.PlayerUpdates; } return 0; } } internal bool DiagnosticsEnabled => false; internal long Server => server; internal AuthorityController(Kinds kinds, float delay, CompatibilityBridge compatibility, Action<Exception> fault, bool staticEnabled, Action<Exception> requestFault, float checkIntervalSeconds, bool defaultInteractives, bool refillStations, int cellSize, GridCoveragePattern pattern, bool keepOnExit, bool directional = false, float innerDelay = 0f, float outerDelay = 3f, float forwardDelay = 0.2f) { this.kinds = kinds; this.delay = delay; cadence = new OwnershipCadence(checkIntervalSeconds); this.compatibility = compatibility; this.fault = fault; this.requestFault = requestFault; this.staticEnabled = staticEnabled; this.defaultInteractives = defaultInteractives; this.refillStations = refillStations; this.keepOnExit = keepOnExit; this.cellSize = ((cellSize == 4 || cellSize == 16) ? cellSize : 8); this.directional = directional; this.innerDelay = innerDelay; this.outerDelay = outerDelay; this.forwardDelay = forwardDelay; this.pattern = ((pattern == GridCoveragePattern.Rounded5x5 || pattern == GridCoveragePattern.Rounded7x7) ? pattern : GridCoveragePattern.Square3x3); if (this.cellSize == 4 && this.pattern == GridCoveragePattern.Square3x3) { throw new ArgumentException("4-metre cells require Rounded5x5 or Rounded7x7."); } FieldInfo field = typeof(ZNetScene).GetField("m_instances", BindingFlags.Instance | BindingFlags.NonPublic); if (field == null || field.FieldType != typeof(Dictionary<ZDO, ZNetView>)) { throw new NotSupportedException("Native instance registry changed."); } DynamicMethod dynamicMethod = new DynamicMethod("BotanicInstances", field.FieldType, new Type[1] { typeof(ZNetScene) }, typeof(AuthorityController).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ldfld, field); iLGenerator.Emit(OpCodes.Ret); instances = (Func<ZNetScene, Dictionary<ZDO, ZNetView>>)dynamicMethod.CreateDelegate(typeof(Func<ZNetScene, Dictionary<ZDO, ZNetView>>)); Router = new RequestRouter(this); } private bool Context() { if (failed || !Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsDedicated() || ZNet.IsSinglePlayer || ZDOMan.instance == null || !Object.op_Implicit((Object)(object)ZNetScene.instance) || !Object.op_Implicit((Object)(object)ZoneSystem.instance)) { return false; } if (!object.ReferenceEquals(world, ZDOMan.instance) || !object.ReferenceEquals(network, ZNet.instance) || !object.ReferenceEquals(scene, ZNetScene.instance)) { Reset(); world = ZDOMan.instance; network = ZNet.instance; scene = ZNetScene.instance; server = ZDOMan.GetSessionID(); if (server == 0) { return false; } coarseEnabled = !defaultInteractives && ZoneSystem.instance.m_zoneSize == 64f; catalog = new ObjectCatalog(kinds); indexed = new AuthorityWorld(server, delay, pattern, keepOnExit, directional, innerDelay, outerDelay, cellSize == 4, forwardDelay); statics = (staticEnabled ? new StaticBuildings(() => active) : null); Inventory = new NativeInventoryHandoff(server); Cooperative = new FgnOwnerHandoff(compatibility.Assembly, server); } return indexed != null; } internal void Poll(float now) { if (cadence.Due(now)) { Tick(); } } internal void ConfigureInterval(float interval) { cadence.Configure(interval); } internal void ConfigureDelays(float full, float inner, float forward, float outer) { delay = full; innerDelay = inner; forwardDelay = forward; outerDelay = outer; if (indexed != null) { indexed.Grid.ConfigureDelays(full, inner, forward, outer); } } internal void Tick() { //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_029a: Unknown result type (might be due to invalid IL or missing references) //IL_02a8: Unknown result type (might be due to invalid IL or missing references) //IL_02a3: Unknown result type (might be due to invalid IL or missing references) //IL_032d: Unknown result type (might be due to invalid IL or missing references) //IL_0332: Unknown result type (might be due to invalid IL or missing references) //IL_0361: Unknown result type (might be due to invalid IL or missing references) //IL_0363: Unknown result type (might be due to invalid IL or missing references) //IL_0357: Unknown result type (might be due to invalid IL or missing references) //IL_035d: Unknown result type (might be due to invalid IL or missing references) //IL_0368: Unknown result type (might be due to invalid IL or missing references) //IL_037a: Unknown result type (might be due to invalid IL or missing references) //IL_037c: Unknown result type (might be due to invalid IL or missing references) //IL_0370: Unknown result type (might be due to invalid IL or missing references) //IL_0376: Unknown result type (might be due to invalid IL or missing references) //IL_0381: Unknown result type (might be due to invalid IL or missing references) try { cameras.Clear(); active = Context() && compatibility.Enabled(); if (!active) { Router.Flush(); return; } bool flag = !defaultInteractives && ZoneSystem.instance.m_zoneSize == 64f; if (coarseEnabled != flag) { coarseEnabled = flag; regions.Clear(); } readiness.Clear(); available.Clear(); if (statics != null) { statics.Begin(network, scene, server, 0, takeovers: true); } if (!primed) { foreach (KeyValuePair<ZDO, ZNetView> item in instances(scene)) { Register(item.Key, item.Value); } primed = true; } peers.Clear(); peerIds.Clear(); regionPeers.Clear(); characters.Clear(); List<ZNetPeer> list = network.GetPeers(); if (coarseEnabled && list.Count <= 1) { if (list.Count == 1) { ZNetPeer val = list[0]; if (val != null && val.IsReady() && val.m_uid != 0 && val.m_uid != server) { regionPeers.Add(new RegionPeer(val.m_uid, default(Cell), referenceValid: true, default(Cell), characterValid: false)); } } regions.Update(regionPeers); indexed.Tick(peers, Time.unscaledTime); Router.Flush(); return; } foreach (ZNetPeer item2 in list) { if (item2 == null || !item2.IsReady() || item2.m_uid == 0 || item2.m_uid == server || !peerIds.Add(item2.m_uid)) { continue; } ZDO val2 = (((ZDOID)(ref item2.m_characterID)).IsNone() ? null : world.GetZDO(item2.m_characterID)); Vector3 val3 = (Vector3)((val2 != null && val2.IsValid()) ? val2.GetPosition() : new Vector3(float.NaN, 0f, float.NaN)); Cell cell; bool flag2 = Cell.At(val3.x, val3.z, cellSize, out cell); if (flag2) { peers.Add(GridPeer.Covered(item2.m_uid, cell, (!coarseEnabled && directional) ? CameraHeading.Read(val2, item2.m_uid, cameras) : 0)); if (coarseEnabled) { characters.Add(val2); } } if (coarseEnabled) { Vector3 refPos = item2.GetRefPos(); Cell cell2; bool flag3 = Cell.At(refPos.x, refPos.z, cellSize, out cell2); Vector2s val4 = (Vector2s)(flag3 ? ZoneSystem.GetZone(refPos) : default(Vector2s)); Vector2s val5 = (Vector2s)(flag2 ? ZoneSystem.GetZone(val3) : default(Vector2s)); regionPeers.Add(new RegionPeer(item2.m_uid, new Cell(val4.x, val4.y), flag3, new Cell(val5.x, val5.y), flag2)); } } if (coarseEnabled) { regions.Update(regionPeers); int num = 0; for (int i = 0; i < peers.Count; i++) { GridPeer value = peers[i]; if (regions.Shared(value.Uid)) { if (directional) { value.Coverage = CameraHeading.Read(characters[i], value.Uid, cameras); } peers[num++] = value; } } if (num != peers.Count) { peers.RemoveRange(num, peers.Count - num); } characters.Clear(); } peers.Sort(peerOrder); indexed.Tick(peers, Time.unscaledTime); Router.Flush(); } catch (Exception error) { Fail(error); } } internal void Register(ZDO data, ZNetView view) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011e: 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_015f: Unknown result type (might be due to invalid IL or missing references) try { if (!Context()) { return; } epoch++; if (statics != null) { statics.InvalidateReadiness(); } if (data == null || !Object.op_Implicit((Object)(object)view) || !view.IsValid() || !object.ReferenceEquals(view.GetZDO(), data) || ((ZDOID)(ref data.m_uid)).IsNone() || BakedObjects.IsBaked(data)) { return; } if (nodes.TryGetValue(data.m_uid, out var value)) { if (object.ReferenceEquals(value.Data, data) && object.ReferenceEquals(value.View, view)) { return; } Remove(value); } Kinds kinds = catalog.Instance(data.GetPrefab(), view); switch (kinds) { case Kinds.TamedAnimals: if (!data.GetBool(ZDOVars.s_tamed, false)) { return; } break; case Kinds.None: return; } Tameable animal = ((kinds == Kinds.TamedAnimals) ? ((Component)view).GetComponent<Tameable>() : null); Character val = ((kinds == Kinds.TamedAnimals) ? ((Component)view).GetComponent<Character>() : null); if (kinds != Kinds.TamedAnimals || (!ObjectCatalog.IsSummoned(animal) && !FriendlyCreatures.IsFriendly(val))) { Vector3 position = data.GetPosition(); if (Finite(position) && Cell.At(position.x, position.z, cellSize, out var cell)) { NativeNode nativeNode = new NativeNode(this, data, view, kinds, cell, animal, val); nodes.Add(nativeNode.Id, nativeNode); views.Remove(view); views.Add(view, nativeNode); indexed.Add(nativeNode, Time.unscaledTime, NeedsPolicy(nativeNode)); } } } catch (Exception error) { Fail(error); } } internal void Unregister(ZNetView view) { if (object.ReferenceEquals(view, null)) { return; } try { epoch++; if (statics != null) { statics.InvalidateReadiness(); statics.Remove(view); } if (views.TryGetValue(view, out var value)) { Remove(value); } } catch (Exception error) { Fail(error); } } private void Remove(NativeNode node) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) Inventory.Forget(node.Data); Cooperative.Forget(node.Data); indexed.Remove(node); nodes.Remove(node.Id); views.Remove(node.View); Router.Remove(node); } internal void Position(ZDO data) { //IL_0018: 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_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) if (failed || indexed == null) { return; } try { if (!nodes.TryGetValue(data.m_uid, out var value) || !object.ReferenceEquals(value.Data, data)) { return; } Vector3 position = data.GetPosition(); if (!Finite(position)) { Remove(value); return; } float num = (float)(value.Cell.X * cellSize) - 32f; float num2 = (float)(value.Cell.Z * cellSize) - 32f; if (!(position.x >= num) || !(position.x < num + (float)cellSize) || !(position.z >= num2) || !(position.z < num2 + (float)cellSize)) { if (!Cell.At(position.x, position.z, cellSize, out var cell)) { Remove(value); return; } bool schedule = NeedsGrid(cell) || (refillStations && value.ServerStation) || ProtectedTransfer(data); indexed.Move(value, cell, Time.unscaledTime, schedule); } } catch (Exception error) { Fail(error); } } internal void DataChanged(ZDO data) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) if (failed || indexed == null) { return; } try { if (active && object.ReferenceEquals(world, ZDOMan.instance) && cameras.Changed(data)) { cadence.Request(); } if (nodes.TryGetValue(data.m_uid, out var value) && object.ReferenceEquals(value.Data, data)) { value.ObserveUse(); if (value.Kind == Kinds.TamedAnimals && (!data.GetBool(ZDOVars.s_tamed, false) || value.Summoned)) { Remove(value); } } else if ((kinds & Kinds.TamedAnimals) != Kinds.None && data.GetBool(ZDOVars.s_tamed, false)) { ZNetView val = scene.FindInstance(data); if (Object.op_Implicit((Object)(object)val)) { Register(data, val); } } } catch (Exception error) { Fail(error); } } internal void OwnerChanged(ZDO data, bool ownershipField = true) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: 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) if (failed || writing || indexed == null) { return; } try { if (!nodes.TryGetValue(data.m_uid, out var value) || !object.ReferenceEquals(value.Data, data)) { long owner = data.GetOwner(); if (active && ownershipField && catalog.IsLooseDrop(data.GetPrefab()) && owner != 0 && owner != server && data.IsValid() && object.ReferenceEquals(world.GetZDO(data.m_uid), data)) { ZNetPeer peer = network.GetPeer(owner); ZNetView val = scene.FindInstance(data); if (peer != null && peer.IsReady() && Object.op_Implicit((Object)(object)val) && val.IsValid() && object.ReferenceEquals(val.GetZDO(), data) && Object.op_Implicit((Object)(object)((Component)val).GetComponent<ItemDrop>())) { world.ForceSendZDO(owner, data.m_uid); } } } else { if (Inventory.Transitioning(data) || Cooperative.Transitioning(data)) { return; } long owner2 = data.GetOwner(); uint ownerRevision = data.OwnerRevision; if (value.ObservedOwner == owner2 && value.Revision == ownerRevision) { return; } value.ObservedOwner = owner2; value.Revision = ownerRevision; if (active && (Inventory.Received(data) || Cooperative.Received(data)) && value.Identity() && value.Controllable() && AvailableOwner(owner2, data.GetPosition())) { value.Managed = true; value.ManagedOwner = owner2; if (owner2 != server) { world.ForceSendZDO(owner2, data.m_uid); } indexed.Received(value, Time.unscaledTime); } else { indexed.Changed(value, Time.unscaledTime, NeedsPolicy(value)); } } } catch (Exception error) { Fail(error); } } internal bool Persistent(ZDO data) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) bool persistent = data.Persistent; try { if (!active || failed || !persistent || !object.ReferenceEquals(world, ZDOMan.instance) || BakedObjects.IsBaked(data)) { return persistent; } if (nodes.TryGetValue(data.m_uid, out var value) && object.ReferenceEquals(value.Data, data) && (value.UseProtected() || ProtectedTransfer(data) || (value.Managed && value.ManagedOwner == data.GetOwner() && (NeedsGrid(value.Cell) || (refillStations && value.ServerStation)))) && value.Identity() && value.Controllable() && AvailableOwner(data.GetOwner(), data.GetPosition())) { return false; } return (statics == null || !statics.Manage(data)) && persistent; } catch (Exception error) { Fail(error); return persistent; } } internal bool TransferPending(ZDO data) { if (Inventory == null || !Inventory.Pending(data)) { if (Cooperative != null) { return Cooperative.Pending(data); } return false; } return true; } internal void InventoryResponse(Container container, long sender, bool granted) { if (!active || Inventory == null) { return; } try { Inventory.Response(container, sender, granted); } catch (Exception error) { Fail(error); } } internal bool AvailableOwner(long owner, Vector3 position) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: 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_00bf: 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_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) if (owner == server) { return true; } ZNetPeer peer = network.GetPeer(owner); if (peer == null || !peer.IsReady() || !Cell.At(position.x, position.z, cellSize, out var cell)) { return false; } OwnerCell key = new OwnerCell { Owner = owner, Cell = cell, Center = ZoneSystem.GetZone(peer.GetRefPos()) }; if (available.TryGetValue(key, out var value)) { return value; } float num = (float)(cell.X * cellSize) - 32f; float num2 = (float)(cell.Z * cellSize) - 32f; value = ZNetScene.InActiveArea(new Vector3(num, 0f, num2), key.Center) && ZNetScene.InActiveArea(new Vector3(num + (float)cellSize, 0f, num2), key.Center) && ZNetScene.InActiveArea(new Vector3(num, 0f, num2 + (float)cellSize), key.Center) && ZNetScene.InActiveArea(new Vector3(num + (float)cellSize, 0f, num2 + (float)cellSize), key.Center); available[key] = value; return value; } private bool AreaReady(Vector3 position) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //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_000d: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) Vector2s zone = ZoneSystem.GetZone(position); if (readiness.TryGetValue(zone, out var value) && value.Epoch == epoch) { return value.Ready; } int num = epoch; bool flag = scene.IsAreaReady(position); if (num != epoch) { return false; } readiness[zone] = new Receipt { Epoch = epoch, Ready = flag }; return flag; } internal NativeNode RequestNode(ZDOID id, int method) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) if (!active || failed || !nodes.TryGetValue(id, out var value) || !ObjectCatalog.OwnerRequest(value.Kind, method) || !value.Identity()) { return null; } return value; } private bool NeedsGrid(Cell cell) { if (coarseEnabled) { return regions.Contains(cell, cellSize); } return true; } private bool ProtectedTransfer(ZDO data) { if (!Inventory.Transitioning(data) && !Cooperative.Transitioning(data) && !TransferPending(data)) { return Cooperative.Reserved(data); } return true; } private bool NeedsPolicy(NativeNode node) { if (!NeedsGrid(node.Cell) && (!refillStations || !node.ServerStation)) { return ProtectedTransfer(node.Data); } return true; } internal void RequestFinished(NativeNode node) { if (indexed != null && !node.Removed) { indexed.Received(node, Time.unscaledTime); } } internal void SceneDestroyed(ZNetScene destroyed) { if (object.ReferenceEquals(scene, destroyed)) { Reset(); } } internal void RouterFault(Exception error) { Fail(error); } internal void RequestFault(Exception error) { try { if (requestFault != null) { requestFault(error); } } catch { } } internal void Reset() { active = false; primed = false; coarseEnabled = false; if (Inventory != null) { Inventory.Clear(); } if (Cooperative != null) { Cooperative.Clear(); } Inventory = null; Cooperative = null; nodes.Clear(); views = new ConditionalWeakTable<ZNetView, NativeNode>(); readiness.Clear(); available.Clear(); peers.Clear(); peerIds.Clear(); cameras.Clear(); regionPeers.Clear(); characters.Clear(); regions.Clear(); Router.Clear(); indexed = null; catalog = null; statics = null; scene = null; network = null; world = null; epoch = 0; } private void Fail(Exception error) { failed = true; Reset(); try { fault(error); } catch { } } private static bool Finite(Vector3 v) { if (!float.IsNaN(v.x) && !float.IsNaN(v.y) && !float.IsNaN(v.z) && !float.IsInfinity(v.x) && !float.IsInfinity(v.y)) { return !float.IsInfinity(v.z); } return false; } } internal abstract class AuthorityNode { internal Cell Cell; internal bool Managed; internal bool Removed; internal long ManagedOwner; internal long ConfirmedFieldOwner; internal float NotBefore; internal abstract long CurrentOwner { get; } internal abstract ApplyResult Apply(long target); internal virtual bool CanRemember(long fieldOwner) { if (Managed && ManagedOwner == fieldOwner) { return CurrentOwner == fieldOwner; } return false; } } internal enum GridCoveragePattern { Square3x3, Rounded5x5, Rounded7x7 } internal enum FieldTier : byte { Outer, Inner, Forward } internal struct Cell : IEquatable<Cell> { internal int X; internal int Z; internal Cell(int x, int z) { X = x; Z = z; } internal static bool At(float x, float z, out Cell cell) { return At(x, z, 8, out cell); } internal static bool At(float x, float z, int size, out Cell cell) { cell = default(Cell); if (size != 4 && size != 8 && size != 16) { return false; } if (float.IsNaN(x) || float.IsNaN(z) || float.IsInfinity(x) || float.IsInfinity(z)) { return false; } double num = Math.Floor(((double)x + 32.0) / (double)size); double num2 = Math.Floor(((double)z + 32.0) / (double)size); int num3 = 16384 / size; if (num < (double)(-num3) || num >= (double)num3 || num2 < (double)(-num3) || num2 >= (double)num3) { return false; } cell = new Cell((int)num, (int)num2); return true; } public bool Equals(Cell other) { if (X == other.X) { return Z == other.Z; } return false; } public override bool Equals(object other) { if (other is Cell) { return Equals((Cell)other); } return false; } public override int GetHashCode() { return (X * 397) ^ Z; } } internal struct GridPeer { internal long Uid; internal Cell Cell; internal float Yaw; internal int Coverage; internal GridPeer(long uid, Cell cell, float yaw = 0f, int coverage = -1) { Uid = uid; Cell = cell; Yaw = yaw; Coverage = coverage; } internal static GridPeer Covered(long uid, Cell cell, int coverage) { return new GridPeer(uid, cell, float.NaN, coverage); } } internal sealed class AuthorityGrid { private sealed class Policy { internal long Candidate; internal long Owner; internal long Uids; internal int Count; internal int FastCount; internal int ForwardCount; internal float Since; internal float Wait; internal float Deadline; internal bool Deferred; internal Request First; internal List<Request> Others; } private struct Request { internal long Uid; internal float Since; internal FieldTier Tier; internal Request(long uid, float since, FieldTier tier) { Uid = uid; Since = since; Tier = tier; } } private sealed class PeerState { internal Cell Cell; internal float Yaw; internal int Heading; internal bool Refreshed; } private struct Offset { internal Cell Cell; internal FieldTier Tier; internal Offset(int x, int z, FieldTier tier) { Cell = new Cell(x, z); Tier = tier; } } private readonly Dictionary<Cell, Policy> policies = new Dictionary<Cell, Policy>(); private readonly Stack<Policy> reusable = new Stack<Policy>(); private readonly Dictionary<long, PeerState> previous = new Dictionary<long, PeerState>(); private readonly Dictionary<Cell, long> remembered = new Dictionary<Cell, long>(); private readonly HashSet<long> seen = new HashSet<long>(); private readonly List<long> departed = new List<long>(); private readonly HashSet<Cell> dirty = new HashSet<Cell>(); private readonly HashSet<Cell> pending = new HashSet<Cell>(); private readonly List<Cell> due = new List<Cell>(); internal readonly List<Cell> Changes = new List<Cell>(); private readonly long server; private readonly Offset[][] footprints = new Offset[16][]; private readonly Dictionary<Cell, FieldTier>[] maskTypes = new Dictionary<Cell, FieldTier>[16]; internal readonly HashSet<Cell> Accelerations = new HashSet<Cell>(); private readonly bool directional; private readonly bool discardVacant; private float innerDelay; private float outerDelay; private float forwardDelay; internal float Delay; private float lastTime; private float nextDue = float.PositiveInfinity; private int deferredCells; internal int Rebuilds; internal int NeighborReads; internal int PlayerUpdates; internal int TimerVisits; internal int PolicyAllocations; internal int RememberedCells => remembered.Count; internal bool Directional => directional; internal bool HasPeers => previous.Count != 0; internal int CachedCells => policies.Count; internal int ReusablePolicies => reusable.Count; internal int DeferredCells => deferredCells; internal AuthorityGrid(long server, float delay, GridCoveragePattern pattern = GridCoveragePattern.Square3x3, bool directional = false, float innerDelay = 0f, float outerDelay = 3f, bool discardVacant = false, bool forward = false, float forwardDelay = 0.2f) { this.server = server; Delay = delay; this.directional = directional; this.discardVacant = discardVacant; this.innerDelay = SafeDelay(innerDelay, 0f); this.outerDelay = SafeDelay(outerDelay, 3f); this.forwardDelay = SafeDelay(forwardDelay, 0.2f); int num = pattern switch { GridCoveragePattern.Rounded5x5 => 2, GridCoveragePattern.Rounded7x7 => 3, _ => 1, }; forward = directional && forward && num > 1; int[] array = new int[8] { 0, 1, 1, 1, 0, -1, -1, -1 }; int[] array2 = new int[8] { 1, 1, 0, -1, -1, -1, 0, 1 }; for (int i = 0; i < 8; i++) { List<Offset> list = new List<Offset>(37); for (int j = -num; j <= num; j++) { for (int k = -num; k <= num; k++) { int num2 = j * array[i] + k * array2[i]; int value = -j * array2[i] + k * array[i]; bool flag = array[i] != 0 && array2[i] != 0; bool flag2 = forward && ((!flag) ? (num2 == 2 && Math.Abs(value) <= 1) : ((j == 2 * array[i] && (k == array2[i] || k == 2 * array2[i])) || (j == array[i] && k == 2 * array2[i]))); if ((num == 1 || j * j + k * k <= num * (num + 1) || flag2) && (!directional || num2 >= 0 || (num2 >= -1 && Math.Abs(value) > 1))) { bool flag3 = false; if (directional) { flag3 = ((array[i] != 0 && array2[i] != 0) ? ((j == 0 && k == 0) || (num2 == 0 && Math.Abs(j) == 1 && Math.Abs(k) == 1) || (j == array[i] && k == array2[i]) || (j == array[i] && k == 0) || (j == 0 && k == array2[i])) : (num2 >= 0 && num2 <= 1 && Math.Abs(value) <= 1)); } list.Add(new Offset(j, k, flag3 ? FieldTier.Inner : (flag2 ? FieldTier.Forward : FieldTier.Outer))); } } } footprints[i] = list.ToArray(); Dictionary<Cell, FieldTier> dictionary = new Dictionary<Cell, FieldTier>(list.Count); foreach (Offset item in list) { dictionary.Add(item.Cell, item.Tier); } maskTypes[i] = dictionary; } for (int l = 0; l < 8; l++) { if (!directional) { footprints[8 + l] = footprints[l]; maskTypes[8 + l] = maskTypes[l]; continue; } Dictionary<Cell, FieldTier> dictionary2 = new Dictionary<Cell, FieldTier>(maskTypes[l]); Offset[] array3 = footprints[(l + 1) & 7]; for (int m = 0; m < array3.Length; m++) { Offset offset = array3[m]; if (!dictionary2.TryGetValue(offset.Cell, out var value2) || offset.Tier == FieldTier.Inner || (value2 == FieldTier.Outer && offset.Tier == FieldTier.Forward)) { dictionary2[offset.Cell] = offset.Tier; } } List<Offset> list2 = new List<Offset>(dictionary2.Count); foreach (KeyValuePair<Cell, FieldTier> item2 in dictionary2) { list2.Add(new Offset(item2.Key.X, item2.Key.Z, item2.Value)); } footprints[8 + l] = list2.ToArray(); maskTypes[8 + l] = dictionary2; } } internal static int HeadingCoverage(float yaw) { if (float.IsNaN(yaw) || float.IsInfinity(yaw)) { return -1; } yaw %= 360f; if (yaw < 0f) { yaw += 360f; } int num = (int)(yaw / 45f); float num2 = yaw - (float)num * 45f; if (!(num2 < 7.5f)) { if (!(num2 <= 37.5f)) { return (num + 1) & 7; } return 8 + num; } return num; } private static float SafeDelay(float value, float fallback) { if (!float.IsNaN(value) && !float.IsInfinity(value)) { return Math.Max(0f, Math.Min(30f, value)); } return fallback; } internal void ConfigureDelays(float full, float inner, float forward, float outer) { Delay = SafeDelay(full, 2f); innerDelay = SafeDelay(inner, 0f); forwardDelay = SafeDelay(forward, 0.2f); outerDelay = SafeDelay(outer, 3f); } private static float Yaw(float value, float fallback) { if (float.IsNaN(value) || float.IsInfinity(value)) { return fallback; } value %= 360f; if (!(value < 0f)) { return value; } return value + 360f; } internal long Owner(Cell cell) { if (!policies.TryGetValue(cell, out var value)) { return 0L; } return value.Owner; } internal long Candidate(Cell cell) { if (!policies.TryGetValue(cell, out var value)) { return 0L; } return value.Candidate; } private float FieldWait(Policy policy) { if (!directional) { return Delay; } if (policy.ForwardCount != 0) { float num = forwardDelay; if (policy.FastCount != 0) { num = Math.Min(num, innerDelay); } if (policy.Count > policy.FastCount + policy.ForwardCount) { num = Math.Min(num, outerDelay); } return num; } if (policy.FastCount == 0) { return outerDelay; } if (policy.FastCount != policy.Count) { return Math.Min(innerDelay, outerDelay); } return innerDelay; } internal float Wait(Cell cell) { if (!policies.TryGetValue(cell, out var value)) { if (!directional) { return Delay; } return outerDelay; } return FieldWait(value); } internal float Remaining(Cell cell, float now) { if (!policies.TryGetValue(cell, out var value) || value.Owner == value.Candidate) { return 0f; } return Math.Max(0f, value.Deadline - now); } internal bool IsRemembered(Cell cell, long uid) { if (uid != 0 && uid != server && remembered.TryGetValue(cell, out var value)) { return value == uid; } return false; } internal void Remember(Cell cell, long uid) { if (uid != 0 && uid != server && Owner(cell) == uid && Candidate(cell) == uid) { remembered[cell] = uid; } } internal void Forget(Cell cell) { remembered.Remove(cell); } private void Contribute(long uid, PeerState peer, bool add, float now) { Offset[] array = footprints[peer.Heading]; for (int i = 0; i < array.Length; i++) { Offset offset = array[i]; Contribution(uid, new Cell(peer.Cell.X + offset.Cell.X, peer.Cell.Z + offset.Cell.Z), offset.Tier, add, now); } } private void Contribution(long uid, Cell cell, FieldTier tier, bool add, float now) { NeighborReads++; if (!policies.TryGetValue(cell, out var value)) { if (reusable.Count != 0) { value = reusable.Pop(); } else { value = new Policy(); PolicyAllocations++; } policies.Add(cell, value); } value.Count += (add ? 1 : (-1)); value.Uids ^= uid; switch (tier) { case FieldTier.Inner: value.FastCount += (add ? 1 : (-1)); break; case FieldTier.Forward: value.ForwardCount += (add ? 1 : (-1)); break; } if (add) { Request request = new Request(uid, now, tier); if (value.Count == 1) { value.First = request; } else { if (value.Others == null) { value.Others = new List<Request>(1); } value.Others.Add(request); } if (remembered.Count != 0 && remembered.TryGetValue(cell, out var value2) && value2 != uid) { remembered.Remove(cell); } } else if (value.First.Uid == uid) { if (value.Others != null && value.Others.Count != 0) { int index = value.Others.Count - 1; value.First = value.Others[index]; value.Others.RemoveAt(index); } else { value.First = default(Request); } } else if (value.Others != null) { for (int i = 0; i < value.Others.Count; i++) { if (value.Others[i].Uid == uid) { value.Others.RemoveAt(i); break; } } } dirty.Add(cell); } private void Reclassify(long uid, Cell cell, FieldTier before, FieldTier after) { Policy policy = policies[cell]; NeighborReads += 2; switch (before) { case FieldTier.Inner: policy.FastCount--; break; case FieldTier.Forward: policy.ForwardCount--; break; } switch (after) { case FieldTier.Inner: policy.FastCount++; break; case FieldTier.Forward: policy.ForwardCount++; break; } if (policy.First.Uid == uid) { policy.First.Tier = after; } else if (policy.Others != null) { for (int i = 0; i < policy.Others.Count; i++) { if (policy.Others[i].Uid == uid) { Request value = policy.Others[i]; value.Tier = after; policy.Others[i] = value; break; } } } dirty.Add(cell); } private void MoveContribution(long uid, PeerState old, Cell next, int heading, float now) { Offset[] array = footprints[old.Heading]; for (int i = 0; i < array.Length; i++) { Offset offset = array[i]; Cell cell = new Cell(old.Cell.X + offset.Cell.X, old.Cell.Z + offset.Cell.Z); if (maskTypes[heading].TryGetValue(new Cell(cell.X - next.X, cell.Z - next.Z), out var value)) { if (value != offset.Tier) { Reclassify(uid, cell, offset.Tier, value); } else if (deferredCells != 0 && policies[cell].Deferred) { dirty.Add(cell); } } else { Contribution(uid, cell, offset.Tier, add: false, now); } } Offset[] array2 = footprints[heading]; for (int j = 0; j < array2.Length; j++) { Offset offset2 = array2[j]; Cell cell2 = new Cell(next.X + offset2.Cell.X, next.Z + offset2.Cell.Z); if (!maskTypes[old.Heading].ContainsKey(new Cell(cell2.X - old.Cell.X, cell2.Z - old.Cell.Z))) { Contribution(uid, cell2, offset2.Tier, add: true, now); } } } private void Commit(Cell cell, Policy policy) { pending.Remove(cell); if (policy.Owner != policy.Candidate) { policy.Owner = policy.Candidate; Changes.Add(cell); } if (policy.Count == 0 && policy.Owner == 0 && policies.Remove(cell) && discardVacant && reusable.Count < 1024) { policy.Candidate = (policy.Owner = (policy.Uids = 0L)); policy.Count = (policy.FastCount = (policy.ForwardCount = 0)); policy.Since = (policy.Wait = (policy.Deadline = 0f)); policy.First = default(Request); if (policy.Others != null) { policy.Others.Clear(); } reusable.Push(policy); } } private void Evaluate(Cell cell, float now) { Policy policy = policies[cell]; if (discardVacant && policy.Count == 0) { SetDeferred(policy, value: false); policy.Candidate = 0L; Commit(cell, policy); return; } if (directional && discardVacant && policy.Count == 1 && policy.First.Tier != FieldTier.Inner && (policy.Deferred || policy.Candidate == server) && previous.TryGetValue(policy.Uids, out var value) && !value.Refreshed) { SetDeferred(policy, value: true); policy.Candidate = policy.Owner; policy.Wait = FieldWait(policy); pending.Remove(cell); return; } SetDeferred(policy, value: false); long num = ((policy.Count > 1) ? server : ((policy.Count == 1) ? policy.Uids : 0)); if (policy.Candidate != num) { if (policy.Owner == policy.Candidate || policy.Candidate == 0 || num != server) { policy.Since = now; } policy.Candidate = num; } float num2 = FieldWait(policy); if (num2 < policy.Wait && policy.Candidate != 0) { Accelerations.Add(cell); } policy.Wait = num2; if (num == server && remembered.Count != 0) { Forget(cell); } if (policy.Owner == num || (remembered.Count != 0 && IsRemembered(cell, num))) { Commit(cell, policy); return; } policy.Deadline = policy.Since + num2; if (policy.Count != 0) { policy.Deadline = RequestDeadline(policy.First, policy.Since, now); if (policy.Others != null) { foreach (Request other in policy.Others) { policy.Deadline = Math.Min(policy.Deadline, RequestDeadline(other, policy.Since, now)); } } } if (now >= policy.Deadline) { Commit(cell, policy); return; } pending.Add(cell); nextDue = Math.Min(nextDue, policy.Deadline); } private float RequestDeadline(Request request, float since, float now) { return Math.Max(Math.Min(request.Since, now), since) + ((!directional) ? Delay : ((request.Tier == FieldTier.Inner) ? innerDelay : ((request.Tier == FieldTier.Forward) ? forwardDelay : outerDelay))); } private void SetDeferred(Policy policy, bool value) { if (policy.Deferred != value) { policy.Deferred = value; deferredCells += (value ? 1 : (-1)); } } internal void Update(List<GridPeer> peers, float now) { Changes.Clear(); Accelerations.Clear(); dirty.Clear(); seen.Clear(); departed.Clear(); bool flag = now < lastTime; lastTime = now; if (flag) { nextDue = float.PositiveInfinity; foreach (Cell item in pending) { Policy policy = policies[item]; policy.Since = now; policy.Deadline = now + policy.Wait; policy.First.Since = now; if (policy.Others != null) { for (int i = 0; i < policy.Others.Count; i++) { Request value = policy.Others[i]; value.Since = now; policy.Others[i] = value; } } nextDue = Math.Min(nextDue, policy.Deadline); } } bool flag2 = false; foreach (GridPeer peer in peers) { if (peer.Uid == 0 || peer.Uid == server || !seen.Add(peer.Uid)) { continue; } PeerState value2; bool flag3 = previous.TryGetValue(peer.Uid, out value2); if (flag3) { value2.Refreshed = false; } float num = Yaw(peer.Yaw, flag3 ? value2.Yaw : 0f); int num2 = (directional ? ((peer.Coverage >= 0 && peer.Coverage < 16) ? peer.Coverage : ((flag3 && (float.IsNaN(peer.Yaw) || float.IsInfinity(peer.Yaw))) ? value2.Heading : ((int)((num + 22.5f) / 45f) & 7))) : 0); if (!flag3 || !value2.Cell.Equals(peer.Cell) || value2.Heading != num2) { if (flag3) { MoveContribution(peer.Uid, value2, peer.Cell, num2, now); } else { value2 = new PeerState(); previous.Add(peer.Uid, value2); } value2.Cell = peer.Cell; value2.Yaw = num; value2.Heading = num2; value2.Refreshed = true; if (!flag3) { Contribute(peer.Uid, value2, add: true, now); } flag2 = true; PlayerUpdates++; } } foreach (KeyValuePair<long, PeerState> previou in previous) { if (!seen.Contains(previou.Key)) { departed.Add(previou.Key); } } foreach (long item2 in departed) { Contribute(item2, previous[item2], add: false, now); previous.Remove(item2); flag2 = true; } if (flag2) { Rebuilds++; foreach (Cell item3 in dirty) { Evaluate(item3, now); } } if (pending.Count == 0) { nextDue = float.PositiveInfinity; } else { if (now < nextDue) { return; } due.Clear(); foreach (Cell item4 in pending) { due.Add(item4); } nextDue = float.PositiveInfinity; foreach (Cell item5 in due) { TimerVisits++; if (policies.TryGetValue(item5, out var value3)) { if (now >= value3.Deadline) { Commit(item5, value3); } else { nextDue = Math.Min(nextDue, value3.Deadline); } } } due.Clear(); } } } internal enum ApplyResult { Done, Pending, Dropped } internal sealed class AuthorityWorld { private sealed class ObjectBucket { internal readonly HashSet<AuthorityNode> Nodes = new HashSet<AuthorityNode>(); internal long Target; internal int Unconfirmed; } internal readonly AuthorityGrid Grid; private readonly Dictionary<Cell, ObjectBucket> buckets = new Dictionary<Cell, ObjectBucket>(); private readonly HashSet<AuthorityNode> pending = new HashSet<AuthorityNode>(); private readonly List<AuthorityNode> scratch = new List<AuthorityNode>(); private readonly bool keepOnExit; private readonly long server; private float lastTime; internal int Attempts; internal int SkippedCells; internal int BucketCount => buckets.Count; internal int PendingCount => pending.Count; internal AuthorityWorld(long server, float delay, GridCoveragePattern pattern = GridCoveragePattern.Square3x3, bool keepOnExit = true, bool directional = false, float innerDelay = 0f, float outerDelay = 3f, bool forward = false, float forwardDelay = 0.2f) { Grid = new AuthorityGrid(server, delay, pattern, directional, innerDelay, outerDelay, keepOnExit, forward, forwardDelay); this.keepOnExit = keepOnExit; this.server = server; } internal void Add(AuthorityNode node, float now, bool schedule = true) { node.Removed = false; ObjectBucket objectBucket = Bucket(node.Cell); if (objectBucket.Nodes.Add(node)) { node.ConfirmedFieldOwner = 0L; if (objectBucket.Target != 0) { objectBucket.Unconfirmed++; } if (keepOnExit) { Grid.Forget(node.Cell); } if (schedule) { Queue(node, now); } else { node.Managed = false; } } } internal void Remove(AuthorityNode node) { Detach(node); node.Removed = true; node.Managed = false; pending.Remove(node); } internal void Move(AuthorityNode node, Cell next, float now, bool schedule = true) { if (!node.Removed && !node.Cell.Equals(next)) { Detach(node); node.Cell = next; ObjectBucket objectBucket = Bucket(next); objectBucket.Nodes.Add(node); node.ConfirmedFieldOwner = 0L; if (objectBucket.Target != 0) { objectBucket.Unconfirmed++; } if (keepOnExit) { Grid.Forget(next); } if (schedule) { Queue(node, now + Grid.Wait(next)); return; } pending.Remove(node); node.Managed = false; } } internal void Changed(AuthorityNode node, float now, bool schedule = true) { if (!node.Removed) { Invalidate(node); if (schedule) { Queue(node, now + Grid.Wait(node.Cell)); return; } pending.Remove(node); node.Managed = false; } } internal void Received(AuthorityNode node, float now) { if (!node.Removed) { Invalidate(node); Queue(node, Math.Max(now, node.NotBefore)); } } internal void Tick(List<GridPeer> peers, float now) { if (peers.Count == 0 && !Grid.HasPeers && Grid.CachedCells == 0 && pending.Count == 0) { Grid.Changes.Clear(); Grid.Accelerations.Clear(); return; } if (now < lastTime) { foreach (AuthorityNode item in pending) { item.NotBefore = now + Grid.Wait(item.Cell); } } lastTime = now; Grid.Update(peers, now); foreach (Cell change in Grid.Changes) { if ((keepOnExit && Grid.Owner(change) == 0) || !buckets.TryGetValue(change, out var value)) { continue; } long num = Grid.Owner(change); if (keepOnExit && Grid.IsRemembered(change, num) && value.Target == num && value.Unconfirmed == 0) { SkippedCells++; continue; } value.Target = ((keepOnExit && num != server) ? num : 0); value.Unconfirmed = ((value.Target != 0) ? value.Nodes.Count : 0); foreach (AuthorityNode node in value.Nodes) { node.ConfirmedFieldOwner = 0L; if (!pending.Contains(node)) { Queue(node, now); } else if (Grid.Directional) { node.NotBefore = Math.Min(node.NotBefore, now + Grid.Wait(change)); } } } scratch.Clear(); foreach (AuthorityNode item2 in pending) { scratch.Add(item2); } foreach (AuthorityNode item3 in scratch) { if (item3.Removed || !pending.Contains(item3)) { continue; } if (Grid.Accelerations.Count != 0 && Grid.Accelerations.Contains(item3.Cell)) { item3.NotBefore = Math.Min(item3.NotBefore, now + Grid.Wait(item3.Cell)); } if (now < item3.NotBefore) { continue; } Attempts++; ApplyResult applyResult = item3.Apply(Grid.Owner(item3.Cell)); if (applyResult != ApplyResult.Pending) { pending.Remove(item3); } switch (applyResult) { case ApplyResult.Dropped: item3.Managed = false; break; case ApplyResult.Done: if (keepOnExit && !item3.Removed) { Confirm(item3); } break; } } scratch.Clear(); } private void Queue(AuthorityNode node, float at) { node.NotBefore = at; pending.Add(node); } private void Invalidate(AuthorityNode node) { if (keepOnExit) { Grid.Forget(node.Cell); if (buckets.TryGetValue(node.Cell, out var value) && value.Target != 0 && node.ConfirmedFieldOwner == value.Target) { node.ConfirmedFieldOwner = 0L; value.Unconfirmed++; } } } private void Confirm(AuthorityNode node) { if (buckets.TryGetValue(node.Cell, out var value) && value.Target != 0 && node.ConfirmedFieldOwner != value.Target && node.CanRemember(value.Target)) { node.ConfirmedFieldOwner = value.Target; value.Unconfirmed--; Certify(node.Cell, value); } } private void Certify(Cell cell, ObjectBucket bucket) { if (keepOnExit && bucket.Target != 0 && bucket.Unconfirmed == 0) { Grid.Remember(cell, bucket.Target); } } private void Detach(AuthorityNode node) { if (buckets.TryGetValue(node.Cell, out var value) && value.Nodes.Remove(node)) { bool flag = value.Target != 0 && node.ConfirmedFieldOwner != value.Target; if (flag) { value.Unconfirmed--; } node.ConfirmedFieldOwner = 0L; if (value.Nodes.Count == 0) { buckets.Remove(node.Cell); Grid.Forget(node.Cell); } else if (flag) { Certify(node.Cell, value); } } } private ObjectBucket Bucket(Cell cell) { if (!buckets.TryGetValue(cell, out var value)) { long num = Grid.Owner(cell); ObjectBucket objectBucket = new ObjectBucket(); objectBucket.Target = ((keepOnExit && num != server) ? num : 0); value = objectBucket; buckets.Add(cell, value); } return value; } } internal static class BakedObjects { private static readonly int multiplayer = StringExtensionMethods.GetStableHashCode("PUP_SAFE_Baked_multiplayer"); private static readonly int solo = StringExtensionMethods.GetStableHashCode("PUP_SAFE_Baked_solo"); internal static bool IsBaked(ZDO data) { if (!data.GetBool(multiplayer, false)) { return data.GetBool(solo, false); } return true; } } internal static class CameraHeading { internal static readonly int Key = StringExtensionMethods.GetStableHashCode("botanic.toomanylags.fgnaddon.cameraCoverage75"); internal static int Coverage(float yaw) { return AuthorityGrid.HeadingCoverage(yaw); } internal static int Coverage(float x, float z) { if (float.IsNaN(x) || float.IsNaN(z) || float.IsInfinity(x) || float.IsInfinity(z) || (double)x * (double)x + (double)z * (double)z < 1E-06) { return -1; } return Coverage((float)(Math.Atan2(x, z) * (180.0 / Math.PI))); } internal static int Read(ZDO player, long peer, CameraWake wake = null) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0043: 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) bool flag = player.GetOwner() == peer; int num = (flag ? player.GetInt(Key, -1) : (-1)); if (wake != null && flag) { wake.Track(player.m_uid, peer, num); } if (num < 0 || num >= 16) { Quaternion rotation = player.GetRotation(); return Coverage(((Quaternion)(ref rotation)).eulerAngles.y); } return num; } } internal sealed class CameraWake { private struct Stamp { internal long Peer; internal int Coverage; } private readonly Dictionary<ZDOID, Stamp> players = new Dictionary<ZDOID, Stamp>(); internal int Count => players.Count; private static int Valid(int value) { if (value < 0 || value >= 16) { return -1; } return value; } internal void Clear() { players.Clear(); } internal void Track(ZDOID id, long peer, int coverage) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) players[id] = new Stamp { Peer = peer, Coverage = Valid(coverage) }; } internal bool Changed(ZDO data) { //IL_000a: 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_007d: Unknown result type (might be due to invalid IL or missing references) if (data == null || !players.TryGetValue(data.m_uid, out var value) || data.GetOwner() != value.Peer || !data.IsValid() || ZDOMan.instance == null || !object.ReferenceEquals(ZDOMan.instance.GetZDO(data.m_uid), data)) { return false; } int num = Valid(data.GetInt(CameraHeading.Key, -1)); if (num == value.Coverage) { return false; } value.Coverage = num; players[data.m_uid] = value; return true; } } internal sealed class CameraPublisher { private readonly OwnershipCadence cadence; private ZDO previous; private ZNet network; private ZDOMan world; internal CameraPublisher(float interval) { cadence = new OwnershipCadence(interval); } internal void Configure(float interval) { cadence.Configure(interval); } internal void Sample(float now) { //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) if (!cadence.Due(now)) { return; } ZNet instance = ZNet.instance; if (!Object.op_Implicit((Object)(object)instance) || instance.IsDedicated() || ZNet.IsSinglePlayer || ZDOMan.instance == null) { Reset(); return; } Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer) || instance.GetServerPeer() == null) { Reset(); return; } ZNetView component = ((Component)localPlayer).GetComponent<ZNetView>(); if (!Object.op_Implicit((Object)(object)component) || !component.IsValid() || !component.IsOwner()) { Reset(); return; } ZDO zDO = component.GetZDO(); if (zDO == null || !zDO.IsValid() || ((ZDOID)(ref zDO.m_uid)).IsNone() || !object.ReferenceEquals(ZDOMan.instance.GetZDO(zDO.m_uid), zDO)) { Reset(); return; } bool flag = !object.ReferenceEquals(previous, zDO) || !object.ReferenceEquals(network, instance) || !object.ReferenceEquals(world, ZDOMan.instance); GameCamera instance2 = GameCamera.instance; int num = -1; if (Object.op_Implicit((Object)(object)instance2) && !GameCamera.InFreeFly()) { Vector3 forward = ((Component)instance2).transform.forward; num = CameraHeading.Coverage(forward.x, forward.z); } if (flag) { ZDOExtraData.AddSessionHash(CameraHeading.Key); } if (flag || zDO.GetInt(CameraHeading.Key, -1) != num) { zDO.Set(CameraHeading.Key, num, false); ZDOMan.instance.ForceSendZDO(zDO.m_uid); } previous = zDO; network = instance; world = ZDOMan.instance; } internal void Reset(bool invalidate = false) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) if (invalidate && previous != null && object.ReferenceEquals(network, ZNet.instance) && object.ReferenceEquals(world, ZDOMan.instance) && previous.IsValid() && previous.GetOwner() == ZDOMan.GetSessionID() && object.ReferenceEquals(world.GetZDO(previous.m_uid), previous) && previous.GetInt(CameraHeading.Key, -1) != -1) { previous.Set(CameraHeading.Key, -1, false); world.ForceSendZDO(previous.m_uid); } previous = null; network = null; world = null; } } [HarmonyPatch(typeof(GameCamera), "LateUpdate")] internal static class CameraSamplePatch { [HarmonyPriority(0)] [HarmonyPostfix] private static void Postfix() { Plugin.SampleCamera(); } } [HarmonyPatch(typeof(GameCamera), "OnDestroy")] internal static class CameraLossPatch { [HarmonyPrefix] private static void Prefix(GameCamera __instance) { if ((Object)(object)GameCamera.instance == (Object)(object)__instance) { Plugin.InvalidateCamera(); } } } internal abstract class CellReadiness { internal abstract bool Ready(Vector3 point, float radius); internal static CellReadiness Create(MonoBehaviour pup) { Type type = ((object)pup).GetType(); Type type2 = type.GetField("multiplayerRemoteCells", BindingFlags.Instance | BindingFlags.NonPublic).FieldType.GetGenericArguments()[1]; Type type3 = type.GetField("fastColliderCells", BindingFlags.Instance | BindingFlags.NonPublic).FieldType.GetGenericArguments()[1]; Type type4 = type.GetField("records", BindingFlags.Instance | BindingFlags.NonPublic).FieldType.GetGenericArguments()[1].GetGenericArguments()[0]; return (CellReadiness)Activator.CreateInstance(typeof(TypedCellReadiness<, , >).MakeGenericType(type2, type3, type4), pup); } } internal sealed class TypedCellReadiness<R, F, B> : CellReadiness where R : class where F : class { private readonly MonoBehaviour pup; private readonly Func<object, Dictionary<Vector2Int, List<B>>> records; private readonly Func<object, Dictionary<Vector2Int, R>> remotes; private readonly Func<object, Dictionary<Vector2Int, F>> fasts; private readonly Func<object, Dictionary<Vector2Int, GameObject>> roots; private readonly Func<object, Dictionary<Vector2Int, string>> ids; private readonly Func<object, Dictionary<GameObject, string>> validated; private readonly Func<object, Dictionary<Vector2Int, bool>> active; private readonly Func<object, Dictionary<Vector2Int, HashSet<string>>> loaded; private readonly Func<object, HashSet<Vector2Int>> physics; private readonly Func<object, HashSet<Vector2Int>> verified; private readonly Func<object, HashSet<Vector2Int>> worldRestores; private readonly Func<object, HashSet<Vector2Int>> vanillaRestores; private readonly Func<object, HashSet<Vector2Int>> loading; private readonly Func<object, int> queued; private readonly Func<R, string> remoteId; private readonly Func<F, string> fastId; private readonly Func<F, GameObject> fastRoot; private readonly Func<F, HashSet<string>> required; private readonly Func<Vector2Int, bool> pending; public TypedCellReadiness(MonoBehaviour value) { pup = value; Type type = ((object)pup).GetType(); records = Read<Dictionary<Vector2Int, List<B>>>(type, "records"); remotes = Read<Dictionary<Vector2Int, R>>(type, "multiplayerRemoteCells"); fasts = Read<Dictionary<Vector2Int, F>>(type, "fastColliderCells"); roots = Read<Dictionary<Vector2Int, GameObject>>(type, "clusters"); ids = Read<Dictionary<Vector2Int, string>>(type, "cacheIds"); validated = Read<Dictionary<GameObject, string>>(type, "validatedReplacementCacheIds"); active = Read<Dictionary<Vector2Int, bool>>(type, "colliderCellActive"); loaded = Read<Dictionary<Vector2Int, HashSet<string>>>(type, "fastLoadedSubclusters"); physics = Read<HashSet<Vector2Int>>(type, "multiplayerRemotePhysicsReady"); verified = Read<HashSet<Vector2Int>>(type, "verifiedRemoteReplacements"); worldRestores = Read<HashSet<Vector2Int>>(type, "pendingWorldSaveRestores"); vanillaRestores = Read<HashSet<Vector2Int>>(type, "multiplayerPendingVanillaRestore"); loading = Read<HashSet<Vector2Int>>(type, "loadingCells"); queued = Read<int>(type, "queuedColliderCount"); remoteId = FieldReader.Create<R, string>(Field(typeof(R), "cacheId")); fastId = FieldReader.Create<F, string>(Field(typeof(F), "cacheId")); fastRoot = FieldReader.Create<F, GameObject>(Field(typeof(F), "root")); required = FieldReader.Create<F, HashSet<string>>(Field(typeof(F), "required")); pending = (Func<Vector2Int, bool>)Delegate.CreateDelegate(typeof(Func<Vector2Int, bool>), pup, type.GetMethod("HasPendingCollidersForCell", BindingFlags.Instance | BindingFlags.NonPublic)); } private static FieldInfo Field(Type type, string name) { return type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } private static Func<object, T> Read<T>(Type type, string name) { return FieldReader.Create<object, T>(Field(type, name)); } internal override bool Ready(Vector3 point, float radius) { //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_029e: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_02c6: 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) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_0392: Unknown result type (might be due to invalid IL or missing references) //IL_0306: Unknown result type (might be due to invalid IL or missing references) //IL_03c0: Unknown result type (might be due to invalid IL or missing references) //IL_0338: Unknown result type (might be due to invalid IL or missing references) //IL_03f0: Unknown result type (might be due to invalid IL or missing references) //IL_03e3: Unknown result type (might be due to invalid IL or missing references) int num = Mathf.FloorToInt((point.x - radius) / 64f); int num2 = Mathf.FloorToInt((point.x + radius) / 64f); int num3 = Mathf.FloorToInt((point.z - radius) / 64f); int num4 = Mathf.FloorToInt((point.z + radius) / 64f); Dictionary<Vector2Int, R> dictionary = remotes(pup); Dictionary<Vector2Int, GameObject> dictionary2 = roots(pup); Dictionary<Vector2Int, bool> dictionary3 = active(pup); Vector2Int val = default(Vector2Int); for (int i = num; i <= num2; i++) { for (int j = num3; j <= num4; j++) { float num5 = Mathf.Max(0f, Mathf.Max((float)i * 64f - point.x, point.x - (float)(i + 1) * 64f)); float num6 = Mathf.Max(0f, Mathf.Max((float)j * 64f - point.z, point.z - (float)(j + 1) * 64f)); if (num5 * num5 + num6 * num6 > radius * radius) { continue; } ((Vector2Int)(ref val))..ctor(i, j); R value; bool flag = dictionary.TryGetValue(val, out value); List<B> value2; bool flag2 = records(pup).TryGetValue(val, out value2); if (!flag && !flag2) { continue; } if (worldRestores(pup).Contains(val) || vanillaRestores(pup).Contains(val) || !flag2 || value2 == null || value2.Count == 0 || !ids(pup).TryGetValue(val, out var value3) || string.IsNullOrEmpty(value3) || value3 == "RESTORE_PENDING" || (flag && value3 != remoteId(value))) { return false; } GameObject value4; if (flag) { if (!physics(pup).Contains(val) || !verified(pup).Contains(val) || !dictionary2.TryGetValue(val, out value4) || !Object.op_Implicit((Object)(object)value4) || !value4.activeInHierarchy || !validated(pup).TryGetValue(value4, out var value5) || value5 != remoteId(value)) { return false; } } else { if (ZNet.instance.IsDedicated() || (!ids(pup).ContainsKey(val) && !dictionary2.ContainsKey(val))) { continue; } if (fasts(pup).TryGetValue(val, out var value6)) { value4 = fastRoot(value6); if (!Object.op_Implicit((Object)(object)value4) || !value4.activeInHierarchy || !ids(pup).TryGetValue(val, out var value7) || value7 != fastId(value6) || !loaded(pup).TryGetValue(val, out var value8)) { return false; } foreach (string item in required(value6)) { if (!value8.Contains(item)) { return false; } } } else if (!dictionary2.TryGetValue(val, out value4) || !Object.op_Implicit((Object)(object)value4) || !value4.activeInHierarchy || loading(pup).Contains(val) || (queued(pup) > 0 && pending(val))) { return false; } } if (dictionary3.TryGetValue(val, out var value9) && !value9) { return false; } } } return true; } } internal sealed class CompatibilityBridge { private const BindingFlags Flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; private readonly BaseUnityPlugin fgn; private readonly ConfigEntry<bool> sss; private readonly ConfigEntry<bool> broad; private readonly ConfigEntry<bool> selective; private readonly ConfigEntry<bool> inserts; private readonly Func<bool> simulation; private readonly Func<bool> serverShips; private readonly Func<ConfigEntry<bool>> helm; internal readonly Assembly Assembly; internal bool ShipsOwnedExternally { get; private set; } internal CompatibilityBridge(BaseUnityPlugin fgn) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown this.fgn = fgn; Assembly = ((object)fgn).GetType().Assembly; BepInPlugin val = (BepInPlugin)Attribute.GetCustomAttribute(((object)fgn).GetType(), typeof(BepInPlugin)); if (val == null || val.GUID != "com.Fire.FiresGhettoNetworkMod") { throw new NotSupportedException("FGN plugin identity changed."); } sss = Config(((object)fgn).GetType(), "ConfigEnableServerAuthority"); broad = Config(((object)fgn).GetType(), "ConfigEnableServerOwnership"); selective = Config(((object)fgn).GetType(), "ConfigEnableServerOwnershipSelective"); simulation = Read<bool>(Assembly.GetType("FiresGhettoNetworkMod.ServerAuthorityPatches", throwOnError: true), "SimulationActive"); inserts = Config(Assembly.GetType("FiresGhettoNetworkMod.StationRouter", throwOnError: true), "ConfigEnabled"); Type type = Assembly.GetType("FiresGhettoNetworkMod.HelmOwnership", throwOnError: false); if (type != null) { serverShips = Read<bool>(type, "ServerOwnsShips"); helm = Read<ConfigEntry<bool>>(type, "ConfigEnabled"); } } internal bool Enabled() { ConfigEntry<bool> val = ((helm == null) ? null : helm()); ShipsOwnedExternally = serverShips != null && serverShips() && val != null && val.Value; if (Object.op_Implicit((Object)(object)fgn) && ((Behaviour)fgn).isActiveAndEnabled && sss.Value && simulation() && !broad.Value && !selective.Value) { return inserts.Value; } return false; } internal bool Configured() { if (sss.Value && !broad.Value && !selective.Value) { return inserts.Value; } return false; } internal string State() { return "SSS=" + sss.Value + "; simulation=" + simulation() + "; broad=" + broad.Value + "; selective=" + selective.Value + "; stationRouter=" + inserts.Value; } private static ConfigEntry<bool> Config(Type type, string name) { FieldInfo field = type.GetField(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field == null || field.FieldType != typeof(ConfigEntry<bool>)) { throw new NotSupportedException("FGN configuration contract changed: " + name); } ConfigEntry<bool> val = (ConfigEntry<bool>)field.GetValue(null); if (val == null) { throw new NotSupportedException("FGN configuration is not initialized: " + name); } return val; } private static Func<T> Read<T>(Type type, string name) { FieldInfo field = type.GetField(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field == null || field.FieldType != typeof(T)) { throw new NotSupportedException("FGN state contract changed: " + name); } DynamicMethod dynamicMethod = new DynamicMethod("BotanicFgn_" + name, typeof(T), Type.EmptyTypes, typeof(CompatibilityBridge).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldsfld, field); iLGenerator.Emit(OpCodes.Ret); return (Func<T>)dynamicMethod.CreateDelegate(typeof(Func<T>)); } } internal sealed class ConfigCommands { private readonly ConfigFile config; private readonly Action<string> apply; private readonly Dictionary<string, object> active = new Dictionary<string, object>(StringComparer.Ordinal); internal ConfigCommands(ConfigFile config, Action<string> apply) { this.config = config; this.apply = apply; foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item in config) { if (!Live(item.Key.Key)) { active.Add(item.Key.Key, item.Value.BoxedValue); } } } internal static bool Local(string key) { return string.Equals(key, "EnableLogs", StringComparison.OrdinalIgnoreCase); } internal static bool Live(string key) { switch (key) { case "EnableLogs": case "CameraHeadingCheckIntervalSeconds": case "MovementRotationCheckIntervalSeconds": case "InnerTransitionDelaySeconds": case "ForwardTransitionDelaySeconds": case "OuterTransitionDelaySeconds": case "TransitionDelaySeconds": case "ServerFallbackPingMs": case "ServerFallbackRadius": return true; default: return false; } } internal string Execute(string command, bool server) { if (command == null || command.Length > 256) { return "Invalid config command."; } string[] array = command.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (array.Length == 1 && string.Equals(array[0], "list", StringComparison.OrdinalIgnoreCase)) { StringBuilder stringBuilder = new StringBuilder(server ? "SERVER settings (live/restart):" : "LOCAL settings (live):"); foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item in config) { if (server != Local(item.Key.Key)) { stringBuilder.Append('\n').Append(Display(item.Value)); } } return stringBuilder.ToString(); } if (array.Length < 1 || array.Length > 2) { return "Usage: tml_config list | <Key> [value]."; } ConfigEntryBase val = null; foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item2 in config) { if (string.Equals(item2.Key.Key, array[0], StringComparison.OrdinalIgnoreCase)) { val = item2.Value; break; } } if (val == null) { return "Unknown setting. Use tml_config list."; } string key = val.Definition.Key; if (server == Local(key)) { return "Wrong setting scope. Logging is local; camera timing and ownership settings belong on the server."; } if (array.Length == 1) { return Display(val) + "\n" + val.Description.Description; } if (!Parse(val.SettingType, array[1], out var value) || (val.Description.AcceptableValues != null && !val.Description.AcceptableValues.IsValid(value))) { return "Invalid value for " + key + ".\n" + val.Description.Description + "\n" + ((val.Description.AcceptableValues == null) ? "" : val.Description.AcceptableValues.ToDescriptionString()); } if (InvalidGrid(key, value)) { return "Invalid grid combination: 4-metre cells require Rounded5x5 or Rounded7x7. Change the other setting first."; } bool flag = Live(key); if (object.Equals(val.BoxedValue, value)) { return key + " is already " + Value(value) + "." + (Pending(val) ? RestartNotice(key) : ""); } object boxedValue = val.BoxedValue; bool saveOnConfigSet = config.SaveOnConfigSet; config.SaveOnConfigSet = false; try { val.BoxedValue = value; config.Save(); if (flag) { apply(key); } string text = (server ? "SERVER: " : "LOCAL: ") + key + " = " + Value(value); if (flag) { return text + " (saved and applied; existing handoffs remain protected)."; } return text + (Pending(val) ? (" (saved)." + RestartNotice(key)) : " (saved; matches the current session, no restart pending)."); } catch (Exception ex) { val.BoxedValue = boxedValue; try { if (flag) { apply(key); } config.Save(); } catch (Exception) { } return "Change failed: " + ex.GetBaseException().Message; } finally { config.SaveOnConfigSet = saveOnConfigSet; } } private bool Pending(ConfigEntryBase entry) { if (active.TryGetValue(entry.Definition.Key, out var value)) { return !object.Equals(value, entry.BoxedValue); } return false; } private string Display(ConfigEntryBase entry) { string key = entry.Definition.Key; string text = key + " = " + Value(entry.BoxedValue); if (Pending(entry)) { return text + " [restart pending; active: " + Value(active[key]) + "]"; } return text + (Live(key) ? " [live]" : " [restart]"); } private static string RestartNotice(string key) { return " Takes effect after server restart; the current session is unchanged." + ((key == "Enabled" || key == "EnableAIOwnership") ? " Set the same value on every client and restart those clients too." : ""); } private bool InvalidGrid(string key, object value) { if (key != "GridCellSizeMeters" && key != "GridCoveragePattern") { return false; } int num = 0; string text = null; foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item in config) { if (item.Key.Key == "GridCellSizeMeters") { num = (int)((key == item.Key.Key) ? value : item.Value.BoxedValue); } else if (item.Key.Key == "GridCoveragePattern") { text = (string)((key == item.Key.Key) ? value : item.Value.BoxedValue); } } if (num == 4) { return text == "Square3x3"; } return false; } private static string Value(object value) { return Convert.ToString(value, CultureInfo.InvariantCulture); } private static bool Parse(Type type, string text, out object value) { value = null; int result2; float result3; if (type == typeof(bool) && bool.TryParse(text, out var result)) { value = result; } else if (type == typeof(string)) { value = text; } else if (type == typeof(int) && int.TryParse(text, NumberStyles.Integer, CultureInfo.InvariantCulture, out result2)) { value = result2; } else if (type == typeof(float) && float.TryParse(text.Replace(',', '.'), NumberStyles.Float, CultureInfo.InvariantCulture, out result3) && !float.IsNaN(result3) && !float.IsInfinity(result3)) { value = result3; } return value != null; } } internal static class ConfigConsole { private const string RequestRpc = "TooManyLags_Config_1"; private const string ReplyRpc = "TooManyLags_ConfigReply_1"; private const string CameraRpc = "TooManyLags_CameraInterval_1"; private static bool registered; private static WeakReference terminal; private static ZNet network; private static int ticket; private static double until; private static ZNet cameraNetwork; internal static bool CameraConfigured { get { if (Object.op_Implicit((Object)(object)ZNet.instance)) { return object.ReferenceEquals(cameraNetwork, ZNet.instance); } return false; } } internal static void Register() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown //IL_0028: Unknown result type (might be due to invalid IL or missing references) if (!registered) { new ConsoleCommand("tml_config", "tml_config list | <Key> [value]. Server settings require admin; logging is local. Restart settings are saved for the next restart.", new ConsoleEvent(Run), false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); registered = true; } } private static void Run(ConsoleEventArgs args) { if (args == null || !Object.op_Implicit((Object)(object)args.Context)) { return; } if (args.Args.Length < 2) { args.Context.AddString("tml_config list | <Key> [value]. EnableLogs applies locally. Camera timing and ownership settings require server admin rights."); return; } string text = string.Join(" ", args.Args, 1, args.Args.Length - 1); if (ConfigCommands.Local(args.Args[1])) { Print(args.Context, Plugin.ConfigCommand(text, server: false)); return; } if (Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsDedicated()) { Print(args.Context, Plugin.ConfigCommand(text, server: true)); return; } ZNetPeer val = (Object.op_Implicit((Object)(object)ZNet.instance) ? ZNet.instance.GetServerPeer() : null); if (val == null || !val.IsReady() || val.m_rpc == null) { args.Context.AddString("Connect to a dedicated server running this TooManyLags version first."); return; } if (text.Length > 256) { args.Context.AddString("Config command too long."); return; } ticket = ((ticket == int.MaxValue) ? 1 : (ticket + 1)); terminal = new WeakReference(args.Context); network = ZNet.instance; until = Time.realtimeSinceStartupAsDouble + 10.0; try { val.m_rpc.Invoke("TooManyLags_Config_1", new object[2] { text, ticket }); } catch (Exception ex) { args.Context.AddString("Config request failed: " + ex.GetBaseException().Message); } } internal static void Connect(ZNetPeer peer) { if (peer == null || peer.m_rpc == null) { return; } if (peer.m_server && Object.op_Implicit((Object)(object)ZNet.instance) && !ZNet.instance.IsDedicated()) { cameraNetwork = null; } double window = -100.0; int requests = 0; peer.m_rpc.Register<string, int>("TooManyLags_Config_1", (Action<ZRpc, string, int>)delegate(ZRpc rpc, string command, int id) { ZNet instance = ZNet.instance; if (Object.op_Implicit((Object)(object)instance) && instance.IsDedicated() && peer.IsReady() && object.ReferenceEquals(instance.GetPeer(peer.m_uid), peer) && object.ReferenceEquals(rpc, peer.m_rpc)) { double realtimeSinceStartupAsDouble = Time.realtimeSinceStartupAsDouble; if (realtimeSinceStartupAsDouble - window >= 1.0) { window = realtimeSinceStartupAsDouble; requests = 0; } if (++requests <= 4 && id > 0 && command != null && command.Length <= 256) { string text = ((peer.m_socket != null && instance.IsAdmin(peer.m_socket.GetHostName())) ? Plugin.ConfigCommand(command, server: true) : "Server configuration requires admin rights (adminlist.txt)."); try { rpc.Invoke("TooManyLags_ConfigReply_1", new object[2] { text, id }); } catch (Exception) { } } } }); peer.m_rpc.Register<string, int>("TooManyLags_ConfigReply_1", (Action<ZRpc, string, int>)delegate(ZRpc rpc, string reply, int id) { if (Object.op_Implicit((Object)(object)ZNet.instance) && !ZNet.instance.IsDedicated() && peer.m_server && object.ReferenceEquals(network, ZNet.instance) && object.ReferenceEquals(ZNet.instance.GetServerPeer(), peer) && object.ReferenceEquals(rpc, peer.m_rpc) && id == ticket && terminal != null && !(Time.realtimeSinceStartupAsDouble > until) && reply != null && reply.Length <= 6000) { object? target = terminal.Target; Terminal val = (Terminal)((target is Terminal) ? target : null); terminal = null; network = null; if (Object.op_Implicit((Object)(object)val)) { Print(val, reply); } } }); peer.m_rpc.Register<float>("TooManyLags_CameraInterval_1", (Action<ZRpc, float>)delegate(ZRpc rpc, float interval) { if (Object.op_Implicit((Object)(object)ZNet.instance) && !ZNet.instance.IsDedicated() && peer.m_server && peer.IsReady() && object.ReferenceEquals(ZNet.instance.GetServerPeer(), peer) && object.ReferenceEquals(rpc, peer.m_rpc) && !float.IsNaN(interval) && !float.IsInfinity(interval) && !(interval < 0.05f) && !(interval > 5f)) { Plugin.ApplyCameraInterval(interval); cameraNetwork = ZNet.instance; } }); } internal static void Ready(ZRpc rpc) { if (!Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsDedicated()) { return; } foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { if (peer != null && peer.IsReady() && object.ReferenceEquals(peer.m_rpc, rpc)) { SendCamera(peer, Plugin.CameraInterval()); break; } } } internal static void BroadcastCamera(float interval) { if (!Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsDedicated()) { return; } foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { if (peer != null && peer.IsReady()) { SendCamera(peer, interval); } } } private static void SendCamera(ZNetPeer peer, float interval) { try { if (peer.m_rpc != null) { peer.m_rpc.Invoke("TooManyLags_CameraInterval_1", new object[1] { interval }); } } catch (Exception) { } } private static void Print(Terminal context, string lines) { string[] array = lines.Split('\n'); foreach (string text in array) { context.AddString(text.TrimEnd('\r')); } } internal static void Reset() { terminal = null; network = null; cameraNetwork = null; until = 0.0; } } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] internal static class ConfigConnectionPatch { [HarmonyPostfix] private static void Postfix(ZNetPeer peer) { ConfigConsole.Connect(peer); } } [HarmonyPatch(typeof(ZNet), "Shutdown")] internal static class ConfigShutdownPatch { [HarmonyPrefix] private static void Prefix() { ConfigConsole.Reset(); } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] internal static class ConfigReadyPatch { [HarmonyPostfix] private static void Postfix(ZRpc rpc) { ConfigConsole.Ready(rpc); } } internal static class FgnAttackRetry { private sealed class Ticket { internal Humanoid Mob; internal ZDO Data; internal ZDOMan World; internal ZNet Network; internal long Owner; internal long Epoch; internal uint Revision; } private static ConditionalWeakTable<Attack, Ticket> waiting = new ConditionalWeakTable<Attack, Ticket>(); private static Func<Humanoid, Attack> currentAttack; private static SynchronizationContext context; private static Action<Humanoid, ZDO> retry; private static Action<Exception> fail; private static readonly SendOrPostCallback dispatch = Dispatch; private static long epoch; private static int armedCount; internal static void Install(Harmony harmony, Action<Humanoid, ZDO> onEnd, Action<Exception> onFailure) { //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Expected O, but got Unknown SynchronizationContext current = SynchronizationContext.Current; FieldInfo fieldInfo = AccessTools.Field(typeof(Humanoid), "m_currentAttack"); MethodInfo methodInfo = AccessTools.Method(typeof(Attack), "Stop", Type.EmptyTypes, (Type[])null); if (current == null || current.GetType().FullName != "UnityEngine.UnitySynchronizationContext" || fieldInfo == null || fieldInfo.IsStatic || fieldInfo.FieldType != typeof(Attack) || methodInfo == null || methodInfo.IsStatic || methodInfo.ReturnType != typeof(void)) { throw new NotSupportedException("Native attack-end re