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 WorldCleaner v0.31.0
BepInEx/plugins/WorldCleaner/WorldCleaner.dll
Decompiled 5 days 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.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("WorldCleaner")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("WorldCleaner")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("c4fa187a-d091-4b48-aa9b-d09eb8b13e7c")] [assembly: AssemblyFileVersion("0.31.0.1")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("0.31.0.1")] namespace WorldCleaner; public class Class1 { } internal sealed class ActiveCleanerAreas { internal static ActiveCleanerAreas Active; private static readonly FieldInfo Sectors = AccessTools.Field(typeof(ZDOMan), "m_objectsBySector"); private static readonly FieldInfo Portals = AccessTools.Field(typeof(ZDOMan), "m_portalObjects"); private static readonly MethodInfo Generated = AccessTools.Method(typeof(ZoneSystem), "IsZoneGenerated", new Type[1] { typeof(Vector2s) }, (Type[])null); private static readonly MethodInfo Poke = AccessTools.Method(typeof(ZoneSystem), "PokeLocalZone", new Type[1] { typeof(Vector2s) }, (Type[])null); private static readonly MethodInfo Create = AccessTools.Method(typeof(ZNetScene), "CreateObject", new Type[1] { typeof(ZDO) }, (Type[])null); private List<ZDO>[] sectors; private Dictionary<SectorIndex, List<ZDO>> portals; private CleanerAreaPlan plan = new CleanerAreaPlan(); private List<ZDO> records = new List<ZDO>(); private IEnumerator<object> rebuilding; private int pokeCursor; private int createCursor; private float nextPlan; private float nextPoke; private float nextCreate; private float nextWarning; private float nextReadyReport; private readonly Dictionary<int, bool> retainedPrefabs = new Dictionary<int, bool>(); private readonly HashSet<int> wardPrefabs = new HashSet<int>(); private HashSet<ZDOID> missingObjects = new HashSet<ZDOID>(); private CleanerRegionReadiness<ZDOID> readiness = new CleanerRegionReadiness<ZDOID>(new GridPoint[0]); private readonly HashSet<ZDOID> failedCreations = new HashSet<ZDOID>(); private bool allowed; private bool warmingPaused; private int objectCap = 4096; private Action<string> warning; internal ActiveCleanerAreas() { Active = this; } internal void Reset() { rebuilding?.Dispose(); rebuilding = null; allowed = false; warmingPaused = false; plan = new CleanerAreaPlan(); records.Clear(); retainedPrefabs.Clear(); wardPrefabs.Clear(); missingObjects.Clear(); failedCreations.Clear(); sectors = null; portals = null; readiness = new CleanerRegionReadiness<ZDOID>(plan.Zones); nextPlan = (nextPoke = (nextCreate = 0f)); pokeCursor = (createCursor = 0); nextReadyReport = Time.realtimeSinceStartup + 30f; } internal void Dispose() { Reset(); if (Active == this) { Active = null; } } private void Warn(string message) { if (!(Time.realtimeSinceStartup < nextWarning)) { nextWarning = Time.realtimeSinceStartup + 15f; warning?.Invoke(message); } } internal void Tick(bool enabled, Vector3[] anchors, float radius, int zoneLimit, int objectLimit, double milliseconds, Action<string> warn) { //IL_05ea: Unknown result type (might be due to invalid IL or missing references) //IL_0665: Unknown result type (might be due to invalid IL or missing references) //IL_06a1: 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_04dd: Unknown result type (might be due to invalid IL or missing references) //IL_04c5: Unknown result type (might be due to invalid IL or missing references) //IL_04f9: Unknown result type (might be due to invalid IL or missing references) //IL_034d: Unknown result type (might be due to invalid IL or missing references) //IL_0565: Unknown result type (might be due to invalid IL or missing references) //IL_056c: Unknown result type (might be due to invalid IL or missing references) //IL_0517: Unknown result type (might be due to invalid IL or missing references) //IL_0371: Unknown result type (might be due to invalid IL or missing references) warning = warn; if (!enabled || !CollectionAuthority.IsServer || ZDOMan.instance == null || (Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ZoneSystem.instance == (Object)null || anchors == null || anchors.Length == 0) { if (allowed) { Reset(); } return; } if (Sectors == null || Portals == null || Poke == null || Create == null || Generated == null) { Warn("Cleaner background area API unavailable; automatic area activity disabled."); return; } allowed = true; objectCap = objectLimit; Stopwatch stopwatch = Stopwatch.StartNew(); try { if (rebuilding == null && Time.realtimeSinceStartup >= nextPlan) { sectors = Sectors.GetValue(ZDOMan.instance) as List<ZDO>[]; portals = Portals.GetValue(ZDOMan.instance) as Dictionary<SectorIndex, List<ZDO>>; if (sectors == null || portals == null) { return; } rebuilding = Rebuild(anchors, radius, zoneLimit, objectLimit).GetEnumerator(); nextPlan = Time.realtimeSinceStartup + 1f; } if (rebuilding != null) { if (!rebuilding.MoveNext()) { rebuilding.Dispose(); rebuilding = null; } if (stopwatch.Elapsed.TotalMilliseconds >= milliseconds) { return; } } if (plan.Zones.Count == 0) { return; } if (missingObjects.Count > 0 && Time.realtimeSinceStartup >= nextReadyReport) { nextReadyReport = Time.realtimeSinceStartup + 30f; Warn("Background storage waiting for " + missingObjects.Count + " objects across " + plan.Zones.Count + " retained zones; cursor " + createCursor + "/" + records.Count + ", failed initializations " + failedCreations.Count + ", warmup paused=" + warmingPaused + "."); } if (Time.realtimeSinceStartup >= nextPoke) { GridPoint gridPoint = plan.Zones[pokeCursor % plan.Zones.Count]; Vector2s val = default(Vector2s); ((Vector2s)(ref val))..ctor(gridPoint.X, gridPoint.Z); if (!warmingPaused || ZoneSystem.instance.IsZoneLoaded(val)) { try { Poke.Invoke(ZoneSystem.instance, new object[1] { val }); } catch (Exception ex) { Warn("Cleaner zone initialization deferred; other zones continue: " + ex.Message); } } pokeCursor++; if (pokeCursor >= plan.Zones.Count) { pokeCursor = 0; nextPoke = Time.realtimeSinceStartup + 1f; } if (stopwatch.Elapsed.TotalMilliseconds >= milliseconds) { return; } } if (warmingPaused || Time.realtimeSinceStartup < nextCreate) { return; } int num = Math.Min(128, records.Count); for (int i = 0; i < num; i++) { if (!(stopwatch.Elapsed.TotalMilliseconds < milliseconds)) { break; } if (records.Count == 0) { break; } createCursor %= records.Count; ZDO val2 = records[createCursor++]; if (val2 == null) { continue; } if (!val2.IsValid()) { RemoveMissing(val2.m_uid); } else { if (failedCreations.Contains(val2.m_uid)) { continue; } GameObject val3 = ZNetScene.instance.FindInstance(val2.m_uid); if ((Object)(object)val3 != (Object)null) { RemoveMissing(val2.m_uid); Container component = val3.GetComponent<Container>(); if (!CollectionAuthority.PeerOwns(val2.GetOwner()) && (Object)(object)component != (Object)null) { OwnershipCoordinator.Acquire(val3.GetComponent<ZNetView>(), component); } } else { if (!ZoneSystem.instance.IsZoneReadyForType(val2.GetSector(), val2.Type) || (Object)(object)ZNetScene.instance.GetPrefab(val2.GetPrefab()) == (Object)null) { continue; } if (!CollectionAuthority.PeerOwns(val2.GetOwner())) { val2.SetOwner(ZDOMan.GetSessionID()); } try { Create.Invoke(ZNetScene.instance, new object[1] { val2 }); } catch (Exception ex2) { failedCreations.Add(val2.m_uid); Warn("Cleaner object initialization failed; other objects continue: " + ex2.Message); } finally { AccessTools.Field(typeof(ZNetView), "m_useInitZDO")?.SetValue(null, false); AccessTools.Field(typeof(ZNetView), "m_initZDO")?.SetValue(null, null); } if ((Object)(object)ZNetScene.instance.FindInstance(val2.m_uid) == (Object)null) { failedCreations.Add(val2.m_uid); Warn("A cleaner-region object failed to initialize; physical deliveries remain deferred until the region is ready."); } else { RemoveMissing(val2.m_uid); } break; } } } } catch (Exception ex3) { warmingPaused = true; Warn("Cleaner area warmup paused: " + ex3); } finally { double totalMilliseconds = stopwatch.Elapsed.TotalMilliseconds; if (totalMilliseconds > 100.0) { nextCreate = (nextPoke = Time.realtimeSinceStartup + 2f); Warn("Cleaner area warmup cooling down for two seconds after " + totalMilliseconds.ToString("F1") + " ms, then resuming other objects."); } else if (totalMilliseconds > 20.0) { nextCreate = (nextPoke = Time.realtimeSinceStartup + 1f); Warn("Cleaner area warmup backing off after " + totalMilliseconds.ToString("F1") + " ms."); } } } private int Index(GridPoint p) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: 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_0086: Unknown result type (might be due to invalid IL or missing references) if (p.X < -32768 || p.X > 32767 || p.Z < -32768 || p.Z > 32767) { return -1; } uint sector = ZoneSystem.SectorToIndex(p.X, p.Z).Sector; if (sector >= sectors.Length) { return -1; } Vector2s val = ZoneSystem.IndexToSector(sector); return (val.x == p.X && val.y == p.Z) ? ((int)sector) : (-1); } private List<ZDO> Portal(int index) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) List<ZDO> value; return portals.TryGetValue(new SectorIndex((uint)index), out value) ? value : null; } private int Count(GridPoint p) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) int num = Index(p); if (num < 0 || !(bool)Generated.Invoke(ZoneSystem.instance, new object[1] { (object)new Vector2s(p.X, p.Z) })) { return -1; } return (sectors[num]?.Count ?? 0) + (Portal(num)?.Count ?? 0); } private IEnumerable<object> Rebuild(Vector3[] anchors, float radius, int zoneLimit, int objectLimit) { CleanerAreaPlan next = new CleanerAreaPlan(); foreach (Vector3 anchor in anchors) { yield return null; Vector2s center = ZoneSystem.GetZone(anchor); Vector2s lo = ZoneSystem.GetZone(anchor - new Vector3(radius, 0f, radius)); Vector2s hi = ZoneSystem.GetZone(anchor + new Vector3(radius, 0f, radius)); int reach = Math.Max(1, Math.Max(Math.Max(center.x - lo.x, hi.x - center.x), Math.Max(center.y - lo.y, hi.y - center.y))); int val = reach; SimulationDistance syncedSimulationDistance = ZNet.instance.GetSyncedSimulationDistance(); if (!next.TryAdd(reach: Math.Max(val, ((SimulationDistance)(ref syncedSimulationDistance)).NearSimulationDistance), center: new GridPoint(center.x, center.y), maximumZones: zoneLimit, maximumObjects: objectLimit, count: Count)) { Warn("Cleaner background region deferred: ungenerated terrain or configured zone/object cap. Its archive stays intact."); } } List<ZDO> snapshot = new List<ZDO>(Math.Min(next.Objects, objectLimit)); CleanerRegionReadiness<ZDOID> nextReadiness = new CleanerRegionReadiness<ZDOID>(next.Zones); HashSet<ZDOID> missing = new HashSet<ZDOID>(); int batch = 0; foreach (GridPoint cell in next.Zones) { int index = Index(cell); if (index < 0) { continue; } for (int layer = 0; layer < 2; layer++) { List<ZDO> list = ((layer == 0) ? sectors[index] : Portal(index)); if (list == null) { continue; } for (int j = 0; j < list.Count; j++) { if (snapshot.Count >= objectLimit) { Warn("Cleaner background region changed beyond object cap; keeping the previous complete plan."); yield break; } if (list[j] != null && RetainRecord(list[j])) { snapshot.Add(list[j]); if ((Object)(object)ZNetScene.instance.FindInstance(list[j].m_uid) == (Object)null) { missing.Add(list[j].m_uid); nextReadiness.Add(list[j].m_uid, cell); } } int num = batch + 1; batch = num; if (num >= 128) { batch = 0; yield return null; } } } } yield return null; snapshot.Sort((ZDO a, ZDO b) => Priority(b).CompareTo(Priority(a))); plan = next; records = snapshot; missingObjects = missing; readiness = nextReadiness; pokeCursor = ((plan.Zones.Count != 0) ? (pokeCursor % plan.Zones.Count) : 0); createCursor = ((records.Count != 0) ? (createCursor % records.Count) : 0); } private bool RetainRecord(ZDO zdo) { if (zdo == null || !zdo.IsValid() || !zdo.Persistent) { return false; } int prefab = zdo.GetPrefab(); if (retainedPrefabs.TryGetValue(prefab, out var value)) { return value; } GameObject prefab2 = ZNetScene.instance.GetPrefab(prefab); if ((Object)(object)prefab2 == (Object)null) { return false; } value = (Object)(object)prefab2.GetComponent<Character>() == (Object)null && (Object)(object)prefab2.GetComponent<CreatureSpawner>() == (Object)null && (Object)(object)prefab2.GetComponent<SpawnArea>() == (Object)null; if (value && (Object)(object)prefab2.GetComponent<PrivateArea>() != (Object)null) { wardPrefabs.Add(prefab); } retainedPrefabs[prefab] = value; return value; } private int Priority(ZDO zdo) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected I4, but got Unknown return zdo.Type * 2 + (wardPrefabs.Contains(zdo.GetPrefab()) ? 1 : 0); } private void RemoveMissing(ZDOID id) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) missingObjects.Remove(id); readiness.Remove(id); } internal static bool StorageReady(Vector3 position) { //IL_000d: 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_0022: 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_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) if (Active == null || !Active.Contains(position)) { return true; } Vector2s zone = ZoneSystem.GetZone(position); return Active.readiness.Ready(new GridPoint(zone.x, zone.y)); } private bool Contains(Vector3 point) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0034: 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) if (!allowed || plan.Zones.Count == 0) { return false; } Vector2s zone = ZoneSystem.GetZone(point); return plan.Contains(new GridPoint(zone.x, zone.y)); } internal static bool Inside(Vector3 point) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) return Active != null && Active.Contains(point); } internal static void Retain(List<ZDO> near) { ActiveCleanerAreas active = Active; if (active == null || !active.allowed || near == null || active.sectors == null) { return; } long num = 0L; foreach (GridPoint zone in active.plan.Zones) { int num2 = active.Index(zone); if (num2 >= 0) { num += (active.sectors[num2]?.Count ?? 0) + (active.Portal(num2)?.Count ?? 0); } } if (num > active.objectCap) { active.Warn("Cleaner regions exceeded the object cap; releasing complete regions through native unloading. Archive delivery will wait."); active.Reset(); return; } foreach (GridPoint zone2 in active.plan.Zones) { int num3 = active.Index(zone2); if (num3 < 0) { continue; } for (int i = 0; i < 2; i++) { List<ZDO> list = ((i == 0) ? active.sectors[num3] : active.Portal(num3)); if (list == null) { continue; } for (int j = 0; j < list.Count; j++) { if (active.RetainRecord(list[j])) { near.Add(list[j]); } } } } } } [HarmonyPatch(typeof(ZNetScene), "RemoveObjects")] internal static class RetainCleanerObjectsPatch { [HarmonyPrefix] private static void Prefix(List<ZDO> __0) { ActiveCleanerAreas.Retain(__0); } } [HarmonyPatch(typeof(ZNetScene), "PointInsideActiveArea")] internal static class CleanerActiveAreaPatch { [HarmonyPostfix] private static void Postfix(Vector2s __0, Vector3 __1, ref bool __result) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) if (!__result && ActiveCleanerAreas.Inside(__1) && (Object)(object)ZNet.instance != (Object)null && __0 == ZoneSystem.GetZone(ZNet.instance.GetReferencePosition())) { __result = true; } } } internal sealed class ArchiveCatalog : IDisposable { private readonly ItemArchive archive; private readonly ArchiveCheckout checkout; private readonly Dictionary<string, VirtualStacks.Row> byKey = new Dictionary<string, VirtualStacks.Row>(StringComparer.Ordinal); private readonly Dictionary<string, VirtualStacks.Row> byToken = new Dictionary<string, VirtualStacks.Row>(StringComparer.Ordinal); private readonly Dictionary<string, int> quantities = new Dictionary<string, int>(StringComparer.Ordinal); private readonly HashSet<string> counted = new HashSet<string>(StringComparer.Ordinal); private readonly Dictionary<string, LinkedListNode<ItemArchive.Entry>> nodes = new Dictionary<string, LinkedListNode<ItemArchive.Entry>>(StringComparer.Ordinal); private readonly Queue<ItemArchive.Entry> pending = new Queue<ItemArchive.Entry>(); private int cursor; internal readonly List<VirtualStacks.Row> Rows = new List<VirtualStacks.Row>(); internal readonly List<VirtualStacks.Row> ActiveRows = new List<VirtualStacks.Row>(); internal int AvailableCount { get; private set; } internal int Revision { get; private set; } internal bool Ready => cursor >= archive.RecordCount && pending.Count == 0; internal int IndexedCount => cursor; internal VirtualStacks.Row RowFor(string token) { VirtualStacks.Row value; return byToken.TryGetValue(token, out value) ? value : null; } internal ArchiveCatalog(ItemArchive archive, ArchiveCheckout checkout) { this.archive = archive; this.checkout = checkout; archive.RecordAvailable += Enqueue; checkout.TokenChanged += Changed; } public void Dispose() { archive.RecordAvailable -= Enqueue; checkout.TokenChanged -= Changed; } private void Enqueue(ItemArchive.Entry record) { pending.Enqueue(record); } private void Changed(string token) { Revision++; if (!byToken.TryGetValue(token, out var value)) { return; } bool flag = checkout.IsBlocked(token); if (flag && counted.Remove(token)) { value.Total -= quantities[token]; AvailableCount--; value.ActiveCount--; value.Available.Remove(nodes[token]); nodes.Remove(token); if (value.ActiveCount == 0) { ActiveRows.Remove(value); } } else if (!flag && counted.Add(token)) { if (value.ActiveCount == 0) { ActiveRows.Add(value); } value.Total += quantities[token]; AvailableCount++; value.ActiveCount++; nodes[token] = value.Available.AddLast(archive.FindRecord(token)); } } private void Index(ItemArchive.Entry record) { if (record == null || record.State != "REMOVED" || byToken.ContainsKey(record.Token)) { return; } Revision++; if (!checkout.IsBlocked(record.Token)) { ItemData val = VirtualStacks.Inspect(record); ItemIdentity.Snapshot cachedIdentity = record.CachedIdentity; string key = ((val == null) ? ("invalid:" + record.Token) : (cachedIdentity.MayMerge ? cachedIdentity.Sha256 : ("token:" + record.Token))); if (!byKey.TryGetValue(key, out var value)) { value = new VirtualStacks.Row { Example = val, Key = key, DisplayName = ((val == null) ? "Unavailable item" : ((Object)val.m_dropPrefab).name), MaxStack = ((val == null) ? 1 : Math.Max(1, val.m_shared.m_maxStackSize)) }; byKey.Add(key, value); Rows.Add(value); } value.Records.Add(record); byToken.Add(record.Token, value); quantities.Add(record.Token, val?.m_stack ?? 0); counted.Add(record.Token); nodes.Add(record.Token, value.Available.AddLast(record)); if (value.ActiveCount == 0) { ActiveRows.Add(value); } value.Total += quantities[record.Token]; AvailableCount++; value.ActiveCount++; } } internal int Tick(int maximumRecords, double milliseconds) { Stopwatch stopwatch = Stopwatch.StartNew(); int i; for (i = 0; i < maximumRecords; i++) { if (!(stopwatch.Elapsed.TotalMilliseconds < milliseconds)) { break; } if (pending.Count > 0) { Index(pending.Dequeue()); continue; } if (cursor < archive.RecordCount) { Index(archive.RecordAt(cursor++)); continue; } break; } return i; } } internal sealed class ArchiveCheckout { internal sealed class Operation { internal string Id; internal string Token; internal string State; internal string Receipt; internal string IntentContext; internal long Ticks; } private const int Magic = 1464025905; private const int MaxFrame = 1048576; private readonly string file; private readonly object gate = new object(); private readonly Dictionary<string, Operation> byId = new Dictionary<string, Operation>(); private readonly Dictionary<string, string> byToken = new Dictionary<string, string>(); private readonly List<string> orderedIds = new List<string>(); private bool healthy; private int ambiguousCount; internal bool Healthy { get { lock (gate) { return healthy; } } } internal int OperationCount { get { lock (gate) { return orderedIds.Count; } } } internal int AmbiguousCount { get { lock (gate) { return ambiguousCount; } } } internal event Action<string> TokenChanged; internal ArchiveCheckout(string directory) { file = Path.Combine(directory, "checkouts.wcc"); } internal void Load() { lock (gate) { healthy = false; byId.Clear(); byToken.Clear(); orderedIds.Clear(); ambiguousCount = 0; if (!File.Exists(file)) { healthy = true; return; } using (FileStream fileStream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read)) { using BinaryReader binaryReader = new BinaryReader(fileStream, Encoding.UTF8); while (fileStream.Position < fileStream.Length) { long position = fileStream.Position; if (fileStream.Length - position < 12) { throw new InvalidDataException("Truncated checkout frame at " + position); } if (binaryReader.ReadInt32() != 1464025905) { throw new InvalidDataException("Checkout frame magic mismatch at " + position); } int num = binaryReader.ReadInt32(); byte[] bytes = BitConverter.GetBytes(binaryReader.ReadUInt32()); if (num <= 0 || num > 1048576 || fileStream.Length - fileStream.Position < num) { throw new InvalidDataException("Truncated or oversized checkout frame at " + position); } byte[] buffer = binaryReader.ReadBytes(num); using (SHA256 sHA = SHA256.Create()) { byte[] source = sHA.ComputeHash(buffer); if (!source.Take(4).SequenceEqual(bytes)) { throw new InvalidDataException("Checkout checksum mismatch at " + position); } } using MemoryStream memoryStream = new MemoryStream(buffer); using BinaryReader binaryReader2 = new BinaryReader(memoryStream, Encoding.UTF8); Operation operation = new Operation { Id = binaryReader2.ReadString(), Token = binaryReader2.ReadString(), State = binaryReader2.ReadString(), Receipt = binaryReader2.ReadString(), Ticks = binaryReader2.ReadInt64() }; if (memoryStream.Position != memoryStream.Length || !Valid(operation.State) || string.IsNullOrWhiteSpace(operation.Id) || string.IsNullOrWhiteSpace(operation.Token)) { throw new InvalidDataException("Invalid checkout record at " + position); } if (!byId.ContainsKey(operation.Id) && operation.State != "INTENT") { throw new InvalidDataException("Checkout has no initial intent at " + position); } if (byId.TryGetValue(operation.Id, out var value) && (value.Token != operation.Token || value.Ticks != operation.Ticks || !CanAdvance(value.State, operation.State))) { throw new InvalidDataException("Invalid checkout transition at " + position); } if (byToken.TryGetValue(operation.Token, out var value2) && value2 != operation.Id) { throw new InvalidDataException("Archive token has multiple checkouts: " + operation.Token); } if (byId.TryGetValue(operation.Id, out value)) { operation.IntentContext = value.IntentContext; } else { operation.IntentContext = operation.Receipt; orderedIds.Add(operation.Id); } byId[operation.Id] = operation; if (operation.State == "CANCELLED") { byToken.Remove(operation.Token); } else { byToken[operation.Token] = operation.Id; } } } healthy = true; ambiguousCount = byId.Values.Count((Operation v) => v.State == "INTENT"); } } internal string Begin(string token) { if (string.IsNullOrWhiteSpace(token)) { throw new ArgumentException("Missing archive token"); } lock (gate) { if (!healthy) { throw new InvalidOperationException("Checkout journal unavailable; reload and review required"); } if (byToken.ContainsKey(token)) { throw new InvalidOperationException("Token is already reserved or spent"); } Operation operation = new Operation { Id = Guid.NewGuid().ToString("N"), Token = token, State = "INTENT", Receipt = "", Ticks = DateTime.UtcNow.Ticks }; Write(operation); byId.Add(operation.Id, operation); byToken.Add(token, operation.Id); orderedIds.Add(operation.Id); ambiguousCount++; this.TokenChanged?.Invoke(token); return operation.Id; } } internal string[] BeginBatch(string[] tokens, string intentContext = "") { if (intentContext == null || intentContext.Length > 4096) { throw new ArgumentException("Invalid intent context"); } lock (gate) { if (!healthy || tokens.Length == 0 || tokens.Distinct<string>(StringComparer.Ordinal).Count() != tokens.Length || tokens.Any((string t) => string.IsNullOrWhiteSpace(t) || byToken.ContainsKey(t))) { throw new InvalidOperationException("Batch has unavailable or repeated tokens"); } Operation[] array = tokens.Select((string t) => new Operation { Id = Guid.NewGuid().ToString("N"), Token = t, State = "INTENT", Receipt = intentContext, IntentContext = intentContext, Ticks = DateTime.UtcNow.Ticks }).ToArray(); WriteBatch(array); Operation[] array2 = array; foreach (Operation operation in array2) { byId.Add(operation.Id, operation); byToken.Add(operation.Token, operation.Id); ambiguousCount++; orderedIds.Add(operation.Id); this.TokenChanged?.Invoke(operation.Token); } return array.Select((Operation o) => o.Id).ToArray(); } } internal Operation[] Snapshot() { lock (gate) { return byId.Values.Select((Operation op) => Copy(op, op.State, op.Receipt)).ToArray(); } } internal Operation OperationAt(int index) { lock (gate) { if (index < 0 || index >= orderedIds.Count) { return null; } Operation operation = byId[orderedIds[index]]; return Copy(operation, operation.State, operation.Receipt); } } internal Operation ForToken(string token) { lock (gate) { if (!byToken.TryGetValue(token, out var value)) { return null; } Operation operation = byId[value]; return Copy(operation, operation.State, operation.Receipt); } } internal void CommitBatch(string[] ids, string receipt) { lock (gate) { if (ids.Length == 0 || ids.Distinct<string>(StringComparer.Ordinal).Count() != ids.Length) { throw new ArgumentException("Batch receipt must contain unique operations"); } if (string.IsNullOrWhiteSpace(receipt)) { throw new ArgumentException("Receipt required"); } Operation[] array = ids.Select(delegate(string id) { if (!byId.TryGetValue(id, out var value) || value.State != "INTENT") { throw new InvalidOperationException("Cannot commit batch"); } return Copy(value, "COMMITTED", receipt); }).ToArray(); WriteBatch(array); Operation[] array2 = array; foreach (Operation operation in array2) { byId[operation.Id] = operation; ambiguousCount--; } } } internal void CommitReceipt(string id, string destinationReceipt) { if (string.IsNullOrWhiteSpace(destinationReceipt)) { throw new ArgumentException("Destination receipt required"); } lock (gate) { if (!byId.TryGetValue(id, out var value) || value.State != "INTENT") { throw new InvalidOperationException("Cannot commit checkout"); } Operation operation = Copy(value, "COMMITTED", destinationReceipt); Write(operation); byId[id] = operation; ambiguousCount--; } } internal void CancelBeforeDelivery(string id) { lock (gate) { if (!byId.TryGetValue(id, out var value) || value.State != "INTENT") { throw new InvalidOperationException("Cannot cancel checkout"); } Operation operation = Copy(value, "CANCELLED", ""); Write(operation); byId[id] = operation; byToken.Remove(value.Token); ambiguousCount--; this.TokenChanged?.Invoke(value.Token); } } internal bool IsBlocked(string token) { lock (gate) { return !healthy || byToken.ContainsKey(token); } } private static Operation Copy(Operation o, string state, string receipt) { return new Operation { Id = o.Id, Token = o.Token, State = state, Receipt = receipt, IntentContext = o.IntentContext, Ticks = o.Ticks }; } private static bool Valid(string s) { return s == "INTENT" || s == "COMMITTED" || s == "CANCELLED"; } private static bool CanAdvance(string a, string b) { return a == "INTENT" && (b == "COMMITTED" || b == "CANCELLED"); } private void Write(Operation op) { WriteBatch(new Operation[1] { op }); } private void WriteBatch(Operation[] operations) { if (!healthy) { throw new InvalidOperationException("Checkout journal is write-locked"); } try { WriteCore(operations); } catch { healthy = false; throw; } } private void WriteCore(Operation[] operations) { byte[] array2; using (MemoryStream memoryStream = new MemoryStream()) { using BinaryWriter binaryWriter = new BinaryWriter(memoryStream, Encoding.UTF8, leaveOpen: true); foreach (Operation operation in operations) { byte[] array; using (MemoryStream memoryStream2 = new MemoryStream()) { using (BinaryWriter binaryWriter2 = new BinaryWriter(memoryStream2, Encoding.UTF8, leaveOpen: true)) { binaryWriter2.Write(operation.Id); binaryWriter2.Write(operation.Token); binaryWriter2.Write(operation.State); binaryWriter2.Write(operation.Receipt); binaryWriter2.Write(operation.Ticks); } array = memoryStream2.ToArray(); } if (array.Length > 1048576) { throw new IOException("Checkout frame too large"); } byte[] value; using (SHA256 sHA = SHA256.Create()) { value = sHA.ComputeHash(array); } binaryWriter.Write(1464025905); binaryWriter.Write(array.Length); binaryWriter.Write(BitConverter.ToUInt32(value, 0)); binaryWriter.Write(array); } binaryWriter.Flush(); array2 = memoryStream.ToArray(); } Directory.CreateDirectory(Path.GetDirectoryName(file)); using FileStream fileStream = new FileStream(file, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); long length = fileStream.Length; try { fileStream.Position = length; fileStream.Write(array2, 0, array2.Length); fileStream.Flush(flushToDisk: true); } catch { try { fileStream.SetLength(length); fileStream.Flush(flushToDisk: true); } catch { } throw; } } } internal sealed class ArchiveChestDistributor { private ArchiveCatalog catalog; private ItemArchive indexedArchive; private ArchiveCheckout indexedCheckout; private int cursor; private readonly Dictionary<VirtualStacks.Row, LinkedListNode<ItemArchive.Entry>> rowCursors = new Dictionary<VirtualStacks.Row, LinkedListNode<ItemArchive.Entry>>(); internal void Reset() { catalog?.Dispose(); catalog = null; indexedArchive = null; indexedCheckout = null; cursor = 0; rowCursors.Clear(); } internal unsafe IEnumerable<object> Drain(ItemArchive archive, ArchiveCheckout checkout, Container[] chests, Vector3[] anchors, int budget, float radius, Action<string> trace, Action<string> warn, Func<Vector3[]> currentAnchors = null, bool useNearby = true, int archiveMB = 4096) { if (archive == null || checkout == null || !archive.JournalHealthy || !checkout.Healthy || anchors == null || anchors.Length == 0 || !CollectionAuthority.IsServer) { yield break; } if (indexedArchive != archive || indexedCheckout != checkout) { Reset(); indexedArchive = archive; indexedCheckout = checkout; catalog = new ArchiveCatalog(archive, checkout); } int watermark = archive.RecordCount; do { yield return "archive refill index"; if (!CollectionAuthority.IsServer || !archive.JournalHealthy || !checkout.Healthy) { yield break; } catalog.Tick(32, 0.75); } while (catalog.IndexedCount < watermark); int activeCount = catalog.ActiveRows.Count; int count = Math.Min(Mathf.Clamp(budget, 1, 1000), activeCount); VirtualStacks.Row[] rows = new VirtualStacks.Row[count]; for (int i = 0; i < count; i++) { rows[i] = catalog.ActiveRows[(cursor + i) % activeCount]; } if (activeCount > 0) { cursor = (cursor + count) % activeCount; } int sent = 0; for (int visit = 0; visit < count; visit++) { yield return "archive refill"; if (!CollectionAuthority.IsServer || !archive.JournalHealthy || !checkout.Healthy) { yield break; } if (currentAnchors != null) { anchors = currentAnchors(); } if (anchors == null || anchors.Length == 0) { yield break; } VirtualStacks.Row row = rows[visit]; List<ItemArchive.Entry> candidates = NextWindow(row); ItemArchive.Entry record = candidates.FirstOrDefault(); if (record == null || checkout.IsBlocked(record.Token)) { continue; } ItemData original = VirtualStacks.Inspect(record); if (original == null) { continue; } Vector3 anchor = AnchorFor(record, anchors); ItemData item = original.Clone(); item.m_stack = (int)Math.Min(val2: Math.Max(1, item.m_shared.m_maxStackSize), val1: row.Total); int stillNeeded = item.m_stack; List<Tuple<StorageTarget, int>> plan = new List<Tuple<StorageTarget, int>>(); foreach (StorageTarget chest in ChestTransfer.StorageRefillDestinations(chests, anchor, radius, useNearby)) { if (stillNeeded == 0 || plan.Count >= 32) { break; } int fitting = chest.AmountThatFits(item, stillNeeded); if (fitting > 0) { plan.Add(Tuple.Create(chest, fitting)); stillNeeded -= fitting; } } int capacity = item.m_stack - stillNeeded; if (capacity == 0) { continue; } string[] intents = null; bool deliveryAttempted = false; try { int selected = 0; List<string> tokens = new List<string>(); foreach (ItemArchive.Entry candidate in candidates) { int num; if (!checkout.IsBlocked(candidate.Token)) { Vector3 val = AnchorFor(candidate, anchors) - anchor; num = ((((Vector3)(ref val)).sqrMagnitude > 0.01f) ? 1 : 0); } else { num = 1; } if (num != 0) { continue; } ItemData restored = VirtualStacks.Inspect(candidate); if (restored != null && candidate.CachedIdentity.CanonicalPayload.SequenceEqual(record.CachedIdentity.CanonicalPayload)) { item.m_cheated |= restored.m_cheated; int taking = Math.Min(restored.m_stack, capacity - selected); string token = candidate.Token; if (taking < restored.m_stack) { token = ArchiveSplit.TakePortion(archive, checkout, token, restored, taking, archiveMB); } tokens.Add(token); selected += taking; if (selected == capacity) { break; } } } if (selected == 0) { continue; } item.m_stack = selected; intents = checkout.BeginBatch(intentContext: "archive_refill:" + string.Join(",", plan.Select(delegate(Tuple<StorageTarget, int> p) { //IL_0010: 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) ZDOID uid = p.Item1.View.GetZDO().m_uid; return ((object)(*(ZDOID*)(&uid))/*cast due to .constrained prefix*/).ToString() + "=" + p.Item2; })), tokens: tokens.ToArray()); int remaining = selected; foreach (Tuple<StorageTarget, int> allocation in plan) { int amount = Math.Min(remaining, allocation.Item2); if (amount == 0) { break; } deliveryAttempted = true; if (!allocation.Item1.TryInsert(item, amount, CollectionAuthority.ActorFor(anchor), out var failure)) { throw new InvalidOperationException(failure ?? "Destination rejected planned insertion"); } remaining -= amount; failure = null; } checkout.CommitBatch(intents, "chests:" + plan.Count + ":" + record.Token); sent += selected; trace("Virtual archive -> physical storage: " + selected + " " + item.m_shared.m_name + " from " + tokens.Count + " records"); } catch (Exception ex) { Exception ex2 = ex; if (intents != null && !deliveryAttempted) { string[] array = intents; foreach (string intent in array) { try { checkout.CancelBeforeDelivery(intent); } catch { } } } warn("Virtual archive chest delivery UNCERTAIN; affected records retained for review: " + ex2); } } if (sent > 0) { trace("Archive refill completed: " + sent + " items"); } } private List<ItemArchive.Entry> NextWindow(VirtualStacks.Row row) { if (!rowCursors.TryGetValue(row, out var value) || value == null || value.List != row.Available) { value = row.Available.First; } List<ItemArchive.Entry> list = new List<ItemArchive.Entry>(); LinkedListNode<ItemArchive.Entry> linkedListNode = value; while (value != null && list.Count < 128) { list.Add(value.Value); value = value.Next ?? row.Available.First; if (value == linkedListNode) { break; } } rowCursors[row] = value; return list; } private static Vector3 AnchorFor(ItemArchive.Entry record, Vector3[] anchors) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: 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) //IL_0026: 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_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) if (!TrySourcePosition(record.Source, out var position)) { position = anchors[0]; } Vector3 val = anchors[0]; Vector3 val2 = val - position; float num = ((Vector3)(ref val2)).sqrMagnitude; for (int i = 1; i < anchors.Length; i++) { val2 = anchors[i] - position; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; if (sqrMagnitude < num) { num = sqrMagnitude; val = anchors[i]; } } return val; } private static bool TrySourcePosition(string source, out Vector3 position) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_012b: 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) position = Vector3.zero; if (string.IsNullOrEmpty(source)) { return false; } int num = source.LastIndexOf('@'); if (num < 0) { return false; } int num2 = source.IndexOf(':', num + 1); if (num2 <= num + 1) { return false; } string[] array = source.Substring(num + 1, num2 - num - 1).Split(new char[1] { ',' }); if (array.Length != 3) { return false; } if (!float.TryParse(array[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) || !float.TryParse(array[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) || !float.TryParse(array[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3)) { return false; } if (float.IsNaN(result) || float.IsNaN(result2) || float.IsNaN(result3) || float.IsInfinity(result) || float.IsInfinity(result2) || float.IsInfinity(result3)) { return false; } position = new Vector3(result, result2, result3); return true; } } internal static class ArchiveDeposit { internal static bool Transfer(ItemArchive archive, string source, ItemData item, int capMB, Action removeAndSave, out string error) { error = null; if (archive == null || !archive.JournalHealthy || item == null || item.m_stack <= 0) { return false; } if (!archive.TryPrepare(source, item.Clone(), capMB, out var token)) { return false; } try { removeAndSave(); archive.MarkOriginalRemoved(token); return true; } catch (Exception ex) { error = "Deposit held for recovery review: " + ex.Message; return false; } } } internal static class ArchiveNetworkWithdrawal { internal static int Deliver(ItemArchive archive, ArchiveCheckout checkout, ArchiveCatalog catalog, string key, int capacity, int archiveMB, Func<ItemData, string, string> deliver, long recipient = 0L) { if (archive == null || checkout == null || catalog == null || !catalog.Ready || !archive.JournalHealthy || !checkout.Healthy || capacity <= 0 || deliver == null) { return 0; } VirtualStacks.Row row = catalog.ActiveRows.FirstOrDefault((VirtualStacks.Row r) => r.Key == key); ItemArchive.Entry entry = row?.Available.First?.Value; if (entry == null || row.Example == null) { return 0; } ItemData obj = VirtualStacks.Inspect(entry); ItemData val = ((obj != null) ? obj.Clone() : null); if (val == null) { return 0; } int num = (int)Math.Min(row.Total, Math.Min(capacity, Math.Max(1, val.m_shared.m_maxStackSize))); List<string> list = new List<string>(); int num2 = 0; ItemArchive.Entry[] array = row.Available.Take(128).ToArray(); foreach (ItemArchive.Entry entry2 in array) { if (!checkout.IsBlocked(entry2.Token)) { ItemData val2 = VirtualStacks.Inspect(entry2); if (val2 == null || !entry2.CachedIdentity.CanonicalPayload.SequenceEqual(entry.CachedIdentity.CanonicalPayload)) { throw new InvalidOperationException("Archive delivery metadata mismatch"); } int num4 = Math.Min(val2.m_stack, num - num2); string text = entry2.Token; if (num4 < val2.m_stack) { text = ArchiveSplit.TakePortion(archive, checkout, text, val2, num4, archiveMB); } val.m_cheated |= val2.m_cheated; list.Add(text); num2 += num4; if (num2 == num) { break; } } } if (num2 == 0) { return 0; } string text2 = Guid.NewGuid().ToString("N"); string[] ids = checkout.BeginBatch(list.ToArray(), "network_delivery_intent:" + text2 + ":recipient=" + recipient.ToString(CultureInfo.InvariantCulture)); val.m_stack = num2; string text3 = deliver(val, text2); if (string.IsNullOrEmpty(text3)) { throw new InvalidOperationException("Missing network delivery receipt"); } checkout.CommitBatch(ids, "network_delivery:" + text2 + ":" + text3); return num2; } } internal static class ArchiveSplit { internal static string TakePortion(ItemArchive archive, ArchiveCheckout checkout, string token, ItemData item, int amount, int capMB) { if (amount <= 0 || amount >= item.m_stack) { throw new ArgumentOutOfRangeException("amount"); } string id = checkout.Begin(token); string token2 = null; try { ItemData val = item.Clone(); val.m_stack = amount; ItemData val2 = item.Clone(); val2.m_stack -= amount; string text = "split:" + token + ":"; string text2 = archive.FindRecord(token)?.Source; int num = text2?.LastIndexOf('@') ?? (-1); int num2 = ((num < 0) ? (-1) : text2.IndexOf(':', num + 1)); string text3 = ((num2 > num && num >= 0) ? (text2.Substring(num, num2 - num + 1) + "split") : ""); if (!archive.TryPrepare(text + "take" + text3, val, capMB, out token2) || !archive.TryPrepare(text + "rest" + text3, val2, capMB, out var token3)) { throw new InvalidOperationException("Cannot prepare both split records; parent reserved for recovery"); } archive.MarkOriginalRemoved(token2); archive.MarkOriginalRemoved(token3); checkout.CommitReceipt(id, "split:" + token2 + ":" + token3); return token2; } catch { throw; } } } internal sealed class BufferedDebugLog { private readonly Queue<string> buffer = new Queue<string>(); private readonly string directory; private const int MaxLines = 500; private const long MaxBytes = 16777216L; private bool failed; internal BufferedDebugLog(string directoryPath) { directory = directoryPath; } internal void Enqueue(string message) { if (!failed) { if (buffer.Count >= 500) { buffer.Dequeue(); } buffer.Enqueue(DateTime.UtcNow.ToString("O") + " " + message); } } internal void Flush(Action<string> warn) { if (failed || buffer.Count == 0) { return; } try { Directory.CreateDirectory(directory); string text = Path.Combine(directory, "WorldCleaner-debug.log"); if (File.Exists(text) && new FileInfo(text).Length > 16777216) { string text2 = Path.Combine(directory, "WorldCleaner-debug.previous.log"); if (File.Exists(text2)) { File.Delete(text2); } File.Move(text, text2); } string[] value = buffer.ToArray(); File.AppendAllText(text, string.Join(Environment.NewLine, value) + Environment.NewLine, Encoding.UTF8); buffer.Clear(); } catch (Exception ex) { failed = true; buffer.Clear(); warn?.Invoke("Debug file disabled after I/O error: " + ex.Message); } } } internal static class ChestTransfer { private sealed class DestinationCache { internal Vector3 Position; internal float Radius; internal float Expires; internal int Revision; internal Container[] Chests; } private static readonly List<DestinationCache> destinations = new List<DestinationCache>(); private static Container[] cachedChests = (Container[])(object)new Container[0]; private static float chestExpires; private static int chestRevision = -1; private static readonly HashSet<ZDOID> failedDestinations = new HashSet<ZDOID>(); private static readonly MethodInfo SaveMethod = typeof(Container).GetMethod("Save", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); private static readonly MethodInfo AccessMethod = typeof(Container).GetMethod("CheckAccess", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(long) }, null); internal static Func<Container, bool> ArchiveViewOwnsChest = (Container chest) => false; internal static void ResetFailures() { failedDestinations.Clear(); } internal static void ResetCache() { destinations.Clear(); cachedChests = (Container[])(object)new Container[0]; chestExpires = 0f; chestRevision = -1; } internal static Container[] CachedChests() { if (Time.realtimeSinceStartup >= chestExpires || chestRevision != LoadedObjects.ChestRevision) { cachedChests = LoadedObjects.Chests(); chestRevision = LoadedObjects.ChestRevision; chestExpires = Time.realtimeSinceStartup + 2f; } return cachedChests; } internal static bool CanUse(Container chest, bool requireReady = true, long? actor = null) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)chest == (Object)null || (chest.IsInUse() && !ArchiveViewOwnsChest(chest)) || (Object)(object)((Component)chest).GetComponent<Piece>() == (Object)null || AccessMethod == null) { return false; } if (requireReady && !ActiveCleanerAreas.StorageReady(((Component)chest).transform.position)) { return false; } ZNetView component = ((Component)chest).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return false; } if (failedDestinations.Contains(component.GetZDO().m_uid)) { return false; } try { if (actor.HasValue) { return ServerAccess.ChestAccess(chest, actor.Value) && OwnershipCoordinator.Acquire(component, chest); } if (!component.IsOwner()) { return false; } if ((Object)(object)Player.m_localPlayer == (Object)null) { return false; } return PrivateArea.CheckAccess(((Component)chest).transform.position, 0f, false, false) && (bool)AccessMethod.Invoke(chest, new object[1] { Player.m_localPlayer.GetPlayerID() }); } catch { return false; } } internal static IEnumerable<Container> Destinations(Container[] all, Vector3 anchor, float radius) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: 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) float r2 = radius * radius; DestinationCache destinationCache = destinations.Find(delegate(DestinationCache c) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_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) Vector3 val = c.Position - anchor; return ((Vector3)(ref val)).sqrMagnitude < 0.01f && c.Radius == radius; }); if (destinationCache == null || destinationCache.Revision != LoadedObjects.ChestRevision || Time.realtimeSinceStartup >= destinationCache.Expires) { if (destinationCache == null) { if (destinations.Count >= 128) { destinations.RemoveAll((DestinationCache c) => c.Expires <= Time.realtimeSinceStartup); } if (destinations.Count >= 128) { destinations.RemoveAt(0); } destinationCache = new DestinationCache(); destinations.Add(destinationCache); } destinationCache.Position = anchor; destinationCache.Radius = radius; destinationCache.Revision = LoadedObjects.ChestRevision; destinationCache.Expires = Time.realtimeSinceStartup + 2f; destinationCache.Chests = (all ?? CachedChests()).Where(delegate(Container c) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) int result; if ((Object)(object)c != (Object)null && !VacuumAnchors.IsVacuum(c)) { Vector3 val = ((Component)c).transform.position - anchor; result = ((((Vector3)(ref val)).sqrMagnitude <= r2) ? 1 : 0); } else { result = 0; } return (byte)result != 0; }).OrderBy(delegate(Container c) { //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_0016: Unknown result type (might be due to invalid IL or missing references) Vector3 val = ((Component)c).transform.position - anchor; return ((Vector3)(ref val)).sqrMagnitude; }).ToArray(); } long actor = CollectionAuthority.ActorFor(anchor); return destinationCache.Chests.Where(delegate(Container c) { //IL_002b: 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_0036: 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) int result; if ((Object)(object)c != (Object)null && !VacuumAnchors.IsVacuum(c) && CanUse(c, requireReady: true, actor)) { Vector3 val = ((Component)c).transform.position - anchor; result = ((((Vector3)(ref val)).sqrMagnitude <= r2) ? 1 : 0); } else { result = 0; } return (byte)result != 0; }); } internal static int AmountThatFits(Inventory inventory, ItemData item, int requested) { if (inventory == null || item == null || item.m_shared == null || requested <= 0) { return 0; } return SafeInventory.AmountThatFits(inventory, item, requested); } internal static IEnumerable<StorageTarget> StorageDestinations(Container[] all, Vector3 anchor, float radius, bool useNearby = true) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) IEnumerable<StorageTarget> enumerable = SpiritStorageCompat.Destinations(anchor, radius, useNearby); if (useNearby) { enumerable = enumerable.Concat(from c in Destinations(all, anchor, radius) select new StorageTarget(c)); } return enumerable.OrderBy(delegate(StorageTarget t) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_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) Vector3 val = t.Position - anchor; return ((Vector3)(ref val)).sqrMagnitude; }); } internal static IEnumerable<StorageTarget> StorageRefillDestinations(Container[] all, Vector3 anchor, float radius, bool nearby) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) HashSet<ZNetView> used = new HashSet<ZNetView>(); foreach (Container chest in RefillDestinations(all, anchor, radius, useNearby: false)) { StorageTarget target = new StorageTarget(chest); used.Add(target.View); yield return target; } foreach (StorageTarget target2 in SpiritStorageCompat.Destinations(anchor, radius, nearbyEnabled: false)) { if (used.Add(target2.View)) { yield return target2; } } if (!nearby) { yield break; } foreach (StorageTarget target3 in StorageDestinations(all, anchor, radius)) { if (used.Add(target3.View)) { yield return target3; } } } internal static IEnumerable<Container> RefillDestinations(Container[] all, Vector3 anchor, float radius, bool useNearby) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) Container[] array = all ?? CachedChests(); foreach (Container chest in array) { int num2; if ((Object)(object)chest != (Object)null && VacuumAnchors.IsVacuum(chest)) { Vector3 val = ((Component)chest).transform.position - anchor; if (((Vector3)(ref val)).sqrMagnitude < 0.25f) { num2 = (CanUse(chest, requireReady: true, CollectionAuthority.ActorFor(anchor)) ? 1 : 0); goto IL_00cf; } } num2 = 0; goto IL_00cf; IL_00cf: if (num2 != 0) { yield return chest; } } if (!useNearby) { yield break; } foreach (Container item in Destinations(all, anchor, radius)) { yield return item; } } internal static bool TryInsert(Container chest, ItemData source, int amount, out string failure, long? actor = null) { //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) failure = null; if (SaveMethod == null) { failure = "Container.Save unavailable"; return false; } if ((Object)(object)chest == (Object)null || source == null || amount <= 0 || !CanUse(chest, requireReady: true, actor)) { return false; } ZNetView component = ((Component)chest).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner()) { return false; } Inventory inventory = chest.GetInventory(); if (inventory == null) { return false; } ItemData val = source.Clone(); val.m_stack = amount; ZDOID uid = component.GetZDO().m_uid; try { if (!SafeInventory.TryInsert(inventory, val, amount)) { return false; } SaveMethod.Invoke(chest, null); return true; } catch (Exception ex) { failedDestinations.Add(uid); failure = "Destination state uncertain after attempted add/save: " + ex; return false; } } } internal sealed class CleanerAreaPlan { internal readonly List<GridPoint> Zones = new List<GridPoint>(); private readonly HashSet<GridPoint> known = new HashSet<GridPoint>(); internal int Objects { get; private set; } internal bool Contains(GridPoint zone) { return known.Contains(zone); } internal bool TryAdd(GridPoint center, int reach, int maximumZones, int maximumObjects, Func<GridPoint, int> count) { if (reach < 1 || reach > 8 || (2 * reach + 1) * (2 * reach + 1) > maximumZones) { return false; } List<GridPoint> list = new List<GridPoint>(); int num = 0; for (int i = center.Z - reach; i <= center.Z + reach; i++) { for (int j = center.X - reach; j <= center.X + reach; j++) { GridPoint gridPoint = new GridPoint(j, i); if (!known.Contains(gridPoint)) { int num2 = count(gridPoint); if (num2 < 0) { return false; } if (num > maximumObjects - num2) { return false; } num += num2; list.Add(gridPoint); } } } if (known.Count + list.Count > maximumZones || Objects > maximumObjects - num) { return false; } foreach (GridPoint item in list) { known.Add(item); Zones.Add(item); } Objects += num; return true; } } internal sealed class CleanerRegionReadiness<T> { private readonly Dictionary<GridPoint, int> groups = new Dictionary<GridPoint, int>(); private readonly Dictionary<T, int> missing = new Dictionary<T, int>(); private readonly List<int> pending = new List<int>(); internal CleanerRegionReadiness(IEnumerable<GridPoint> zones) { HashSet<GridPoint> hashSet = new HashSet<GridPoint>(zones); Queue<GridPoint> queue = new Queue<GridPoint>(); foreach (GridPoint zone in zones) { if (!hashSet.Remove(zone)) { continue; } int count = pending.Count; pending.Add(0); queue.Enqueue(zone); while (queue.Count > 0) { GridPoint key = queue.Dequeue(); groups.Add(key, count); for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { GridPoint item = new GridPoint(key.X + j, key.Z + i); if (hashSet.Remove(item)) { queue.Enqueue(item); } } } } } } internal void Add(T id, GridPoint zone) { if (!groups.TryGetValue(zone, out var value)) { throw new InvalidOperationException("Missing object outside retained region"); } if (missing.TryGetValue(id, out var value2)) { if (value2 != value) { throw new InvalidOperationException("Object occurs in unrelated retained regions"); } } else { missing.Add(id, value); pending[value]++; } } internal void Remove(T id) { if (missing.TryGetValue(id, out var value)) { missing.Remove(id); pending[value]--; } } internal bool Ready(GridPoint zone) { int value; return groups.TryGetValue(zone, out value) && pending[value] == 0; } } internal static class CollectionAuthority { internal static bool IsServer => (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer(); internal static bool PeerOwns(long owner) { if ((Object)(object)ZNet.instance == (Object)null) { return true; } foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { if (peer.IsReady() && peer.m_uid == owner) { return true; } } return false; } internal static long ActorFor(Vector3 anchor) { //IL_0078: 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_002c: 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_0032: Unknown result type (might be due to invalid IL or missing references) Container[] array = ChestTransfer.CachedChests(); foreach (Container val in array) { if (!((Object)(object)val != (Object)null) || !VacuumAnchors.IsVacuum(val)) { continue; } Vector3 val2 = ((Component)val).transform.position - anchor; if (((Vector3)(ref val2)).sqrMagnitude < 0.25f) { Piece component = ((Component)val).GetComponent<Piece>(); if ((Object)(object)component != (Object)null) { return component.GetCreator(); } } } long num = SpiritStorageCompat.CreatorAt(anchor); return (num != 0L) ? num : (((Object)(object)Player.m_localPlayer == (Object)null) ? 0 : Player.m_localPlayer.GetPlayerID()); } } internal static class CollectionSafety { internal struct Position { internal readonly float X; internal readonly float Y; internal readonly float Z; internal Position(float x, float y, float z) { X = x; Y = y; Z = z; } } internal static bool MayCollect(Position item, IEnumerable<Position> otherConnectedPlayers, bool authoritativeRosterAvailable, float exclusionMeters) { if (!authoritativeRosterAvailable || otherConnectedPlayers == null || float.IsNaN(exclusionMeters) || float.IsInfinity(exclusionMeters) || exclusionMeters < 0f) { return false; } if (exclusionMeters == 0f) { return true; } double num = (double)exclusionMeters * (double)exclusionMeters; foreach (Position otherConnectedPlayer in otherConnectedPlayers) { double num2 = (double)otherConnectedPlayer.X - (double)item.X; double num3 = (double)otherConnectedPlayer.Y - (double)item.Y; double num4 = (double)otherConnectedPlayer.Z - (double)item.Z; if (num2 * num2 + num3 * num3 + num4 * num4 <= num) { return false; } } return true; } } internal sealed class DropWorkQueue<TKey, TValue> { internal sealed class Entry { internal TKey Id; internal TValue Value; internal double Due; internal double EligibleAt; internal long Sequence; internal int Attempts; internal int Priority; } private sealed class Order : IComparer<Entry> { public int Compare(Entry a, Entry b) { int num = a.Due.CompareTo(b.Due); return (num != 0) ? num : a.Sequence.CompareTo(b.Sequence); } } private readonly Dictionary<TKey, Entry> entries = new Dictionary<TKey, Entry>(); private readonly SortedSet<Entry>[] ready = new SortedSet<Entry>[2] { new SortedSet<Entry>(new Order()), new SortedSet<Entry>(new Order()) }; private long sequence; internal int Count => entries.Count; internal long Overflow { get; private set; } internal bool TryGet(TKey id, out Entry entry) { return entries.TryGetValue(id, out entry); } internal bool Observe(TKey id, TValue value, double due, bool fast, int capacity) { if (entries.TryGetValue(id, out var value2)) { if (fast && value2.Priority != 0) { ready[1].Remove(value2); value2.Priority = 0; ready[0].Add(value2); } return true; } if (entries.Count >= capacity) { Overflow++; if (!fast || ready[1].Count == 0) { return false; } Entry max = ready[1].Max; ready[1].Remove(max); entries.Remove(max.Id); } Entry entry = new Entry { Id = id, Value = value, Due = due, EligibleAt = due, Priority = ((!fast) ? 1 : 0), Sequence = sequence++ }; entries.Add(id, entry); ready[entry.Priority].Add(entry); return true; } internal void Wake(TKey id, double now) { if (entries.TryGetValue(id, out var value) && !(value.Due <= Math.Max(now, value.EligibleAt))) { ready[value.Priority].Remove(value); value.Due = Math.Max(now, value.EligibleAt); ready[value.Priority].Add(value); } } internal bool TryTake(double now, bool backgroundTurn, out Entry entry) { for (int i = 0; i < 2; i++) { int num = (backgroundTurn ? (1 - i) : i); Entry entry2 = ((ready[num].Count == 0) ? null : ready[num].Min); if (entry2 != null && !(entry2.Due > now)) { ready[num].Remove(entry2); entries.Remove(entry2.Id); entry = entry2; return true; } } entry = null; return false; } internal void Retry(Entry entry, double due, int capacity) { entry.Due = due; entry.Attempts++; entry.Priority = 1; if (!entries.ContainsKey(entry.Id)) { if (entries.Count >= capacity) { Overflow++; return; } entries.Add(entry.Id, entry); ready[entry.Priority].Add(entry); } } internal void Clear() { entries.Clear(); ready[0].Clear(); ready[1].Clear(); sequence = 0L; Overflow = 0L; } } internal sealed class FrameWork { private IEnumerator<object> running; private readonly Func<double> clock; private double resumeAt; private double nextReport; private string stage = "scan preparation"; internal bool Busy => running != null; internal bool Suspended { get; private set; } internal FrameWork(Func<double> clock = null) { this.clock = clock ?? ((Func<double>)(() => (double)Stopwatch.GetTimestamp() * 1000.0 / (double)Stopwatch.Frequency)); } internal void Start(IEnumerable<object> work) { if (!Suspended) { if (Busy) { throw new InvalidOperationException("Collection cycle already running"); } running = work.GetEnumerator(); } } internal void Cancel() { running?.Dispose(); running = null; resumeAt = 0.0; stage = "scan preparation"; } internal void Reset() { Cancel(); Suspended = false; } internal void Tick(int maximumSteps, double milliseconds, Action<string> warn) { if (Suspended && clock() >= resumeAt) { Suspended = false; } if (!Busy || clock() < resumeAt) { return; } double num = clock(); string text = stage; try { for (int i = 0; i < maximumSteps; i++) { if (!Busy) { break; } text = stage; if (!running.MoveNext()) { Cancel(); break; } stage = (running.Current as string) ?? stage; if (clock() - num >= milliseconds) { break; } } } catch (Exception ex) { Cancel(); warn("Collection work stopped: " + ex); } double num2 = clock() - num; if (num2 > 100.0) { Cancel(); Suspended = true; resumeAt = clock() + 2000.0; warn("Performance safeguard: " + text + " took " + num2.ToString("F1") + " ms. Maintenance cooling down for two seconds, then resuming. Other mod callbacks and disk writes cannot be preempted safely."); } else if (num2 > 20.0) { resumeAt = clock() + Math.Min(2000.0, num2 * 10.0); if (clock() >= nextReport) { nextReport = clock() + 10000.0; warn("Performance: " + text + " took " + num2.ToString("F1") + " ms in one indivisible step; collection backing off. Frame budget=" + milliseconds + " ms."); } } } } internal static class GameplayInput { private static readonly MethodInfo TakeInput = typeof(Player).GetMethod("TakeInput", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); internal static bool Allowed() { try { return (Object)(object)Player.m_localPlayer != (Object)null && TakeInput != null && (bool)TakeInput.Invoke(Player.m_localPlayer, null); } catch { return false; } } } internal sealed class HybridDropScanner : IDisposable { private struct Candidate { internal bool Initialized; internal Vector3 Original; } internal const string OriginalPositionKey = "arcbyte.worldcleaner.origin.v1"; private static readonly FieldInfo SectorsField = typeof(ZDOMan).GetField("m_objectsBySector", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly FieldInfo PortalsField = typeof(ZDOMan).GetField("m_portalObjects", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private readonly DropWorkQueue<ZDOID, Candidate> queue = new DropWorkQueue<ZDOID, Candidate>(); private readonly Dictionary<int, bool> prefabs = new Dictionary<int, bool>(); private readonly Dictionary<ZDOID, Vector3> anchors = new Dictionary<ZDOID, Vector3>(); private readonly HashSet<ZDOID> quarantined = new HashSet<ZDOID>(); private readonly List<GridPoint> origins = new List<GridPoint>(); private readonly HashSet<uint> originSectors = new HashSet<uint>(); private List<ZDO>[] sectors; private Dictionary<SectorIndex, List<ZDO>> portals; private ZDOMan manager; private SectorSweep<ZDO> sweep; private int loadedCursor; private int chestCursor; private int fairness; private double nextDiscovery; private double nextAnchors; private double nextReport; private double resumeAt; private Vector3[] cachedAnchors = (Vector3[])(object)new Vector3[0]; private string manualText; private IList<Vector3> manual = (IList<Vector3>)(object)new Vector3[0]; private bool anchorsDirty = true; private bool canStage; private bool fallbackSet; private GridPoint fallback; private long completed; private long retries; private long staged; private long stale; private long failures; private double scanMs; private double transferMs; private long lastSectors; private long lastExamined; private double reportStarted; private int boundSectorCount; private bool bindingWarning; private string anchorCachePath; private bool anchorCacheLoaded; private bool anchorCacheDirty; private double nextAnchorSave; internal int Capacity = 10000; internal int MaximumRecords = 256; internal double GraceSeconds = 5.0; internal double ScanMilliseconds = 0.5; internal double TransferMilliseconds = 1.0; internal double IdleSeconds = 0.15; internal double RescanSeconds = 300.0; internal bool EventDetection = true; internal bool Adaptive = true; internal bool Suspended { get; private set; } internal Vector3[] Anchors { get { if (ZDOMan.instance != null && (anchorsDirty || Now >= nextAnchors)) { RefreshAnchors(); } return cachedAnchors; } } internal int Pending => queue.Count; private static double Now => Time.realtimeSinceStartup; internal void SetAnchorCache(string folder) { anchorCachePath = ((folder == null) ? null : Path.Combine(folder, "cleaners.wca")); anchorCacheLoaded = false; if (anchors.Count > 0) { anchorCacheDirty = true; } } internal HybridDropScanner() { LoadedObjects.DropRegistered += Registered; VacuumAnchors.Changed += ObserveAnchor; } public void Dispose() { LoadedObjects.DropRegistered -= Registered; VacuumAnchors.Changed -= ObserveAnchor; } private void Registered(ZDOID id) { //IL_0016: 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) if (EventDetection) { queue.Observe(id, default(Candidate), Now + GraceSeconds, fast: true, Capacity); queue.Wake(id, Now); } } private bool IsDrop(ZDO zdo) { int prefab = zdo.GetPrefab(); if (prefabs.TryGetValue(prefab, out var value)) { return value; } GameObject prefab2 = ZNetScene.instance.GetPrefab(prefab); if ((Object)(object)prefab2 == (Object)null) { return false; } value = (Object)(object)prefab2.GetComponent<ItemDrop>() != (Object)null && (Object)(object)prefab2.GetComponent<Container>() == (Object)null; prefabs[prefab] = value; return value; } internal void ObserveAnchor(ZDO zdo) { //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: 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_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) if (zdo == null || !zdo.IsValid()) { return; } if (zdo.GetBool("arcbyte.worldcleaner.vacuum.v1", false)) { Vector3 position = zdo.GetPosition(); if (!PersistentDropSweeper.ValidPosition(position)) { return; } if (anchors.TryGetValue(zdo.m_uid, out var value)) { Vector3 val = value - position; if (!(((Vector3)(ref val)).sqrMagnitude > 0.01f)) { return; } } anchors[zdo.m_uid] = position; anchorsDirty = true; anchorCacheDirty = true; } else if (anchors.Remove(zdo.m_uid)) { anchorsDirty = true; anchorCacheDirty = true; } } private void Inspect(ZDO zdo) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: 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) //IL_00e8: 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_011f: Unknown result type (might be due to invalid IL or missing references) if (zdo == null || !zdo.IsValid()) { return; } ObserveAnchor(zdo); if (!IsDrop(zdo) || zdo.GetBool("arcbyte.worldcleaner.leftover.v1", false) || quarantined.Contains(zdo.m_uid) || zdo.GetBool("arcbyte.worldcleaner.deposit.pending", false) || (!canStage && (Object)(object)ZNetScene.instance.FindInstance(zdo.m_uid) == (Object)null)) { return; } DropWorkQueue<ZDOID, Candidate>.Entry entry; bool flag = queue.TryGet(zdo.m_uid, out entry); if (!flag || !entry.Value.Initialized) { Candidate value = new Candidate { Initialized = true, Original = (zdo.GetBool("arcbyte.worldcleaner.staged.v1", false) ? zdo.GetVec3("arcbyte.worldcleaner.origin.v1", zdo.GetPosition()) : zdo.GetPosition()) }; if (flag) { entry.Value = value; } else { queue.Observe(zdo.m_uid, value, Now + GraceSeconds, fast: false, Capacity); } } } internal void SetManual(string text, Func<string, List<Vector3>> parse) { if (text != manualText) { manualText = text; manual = parse(text); anchorsDirty = true; } } internal void Reset() { queue.Clear(); prefabs.Clear(); anchors.Clear(); quarantined.Clear(); anchorCacheLoaded = false; anchorCacheDirty = false; nextAnchorSave = 0.0; sweep = null; manager = null; sectors = null; portals = null; loadedCursor = (chestCursor = (fairness = 0)); nextDiscovery = (nextAnchors = (nextReport = (resumeAt = 0.0))); cachedAnchors = (Vector3[])(object)new Vector3[0]; anchorsDirty = true; Suspended = false; fallbackSet = false; completed = (retries = (staged = (stale = (failures = 0L)))); scanMs = (transferMs = 0.0); lastSectors = (lastExamined = 0L); reportStarted = Now; boundSectorCount = 0; bindingWarning = false; } private bool Bind(Action<string> warn) { //IL_00f6: 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) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_010c: 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_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_019a: 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_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) if (SectorsField == null || PortalsField == null || ZDOMan.instance == null) { if (!bindingWarning) { bindingWarning = true; warn("Persistent sector API unavailable; sweep disabled, loaded detection remains active."); } return false; } sectors = SectorsField.GetValue(ZDOMan.instance) as List<ZDO>[]; portals = PortalsField.GetValue(ZDOMan.instance) as Dictionary<SectorIndex, List<ZDO>>; if (sectors == null || sectors.Length == 0 || portals == null) { return false; } if (manager == ZDOMan.instance && sweep != null && boundSectorCount == sectors.Length) { return true; } sweep = null; Vector2s val = ZoneSystem.IndexToSector(0u); Vector2s val2 = ZoneSystem.IndexToSector((uint)(sectors.Length - 1)); int sector = (int)ZoneSystem.SectorToIndex((int)val.x, (int)val.y).Sector; int sector2 = (int)ZoneSystem.SectorToIndex((int)val2.x, (int)val2.y).Sector; if (sector != 0 || sector2 != sectors.Length - 1) { if (!bindingWarning) { bindingWarning = true; warn("Sector API bounds do not round-trip; persistent sweep disabled."); } return false; } manager = ZDOMan.instance; boundSectorCount = sectors.Length; sweep = new SectorSweep<ZDO>(val.x, val.y, val2.x, val2.y, sectors.Length, (int x, int z) => (int)ZoneSystem.SectorToIndex(x, z).Sector, (int index, int layer) => (layer == 0) ? sectors[index] : (portals.TryGetValue(new SectorIndex((uint)index), out var value) ? value : null)); return true; } private void RefreshAnchors() { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0173: 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_0178: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_0227: 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_0231: Unknown result type (might be due to invalid IL or missing references) if (Now >= nextAnchors) { nextAnchors = Now + 1.0; foreach (ZDOID item in new List<ZDOID>(anchors.Keys)) { ZDO zDO = ZDOMan.instance.GetZDO(item); if (zDO == null || !zDO.IsValid() || !zDO.GetBool("arcbyte.worldcleaner.vacuum.v1", false)) { anchors.Remove(item); anchorsDirty = true; } else { ObserveAnchor(zDO); } } } bool flag = anchorsDirty || origins.Count == 0; if (anchorsDirty) { List<Vector3> list = new List<Vector3>(anchors.Values); list.AddRange(manual); cachedAnchors = list.ToArray(); anchorsDirty = false; } if (!flag) { sweep?.SetOrigins(origins); return; } origins.Clear(); originSectors.Clear(); Vector3[] array = cachedAnchors; foreach (Vector3 val in array) { SectorIndex sectorIndex = ZoneSystem.GetSectorIndex(val); if (originSectors.Add(sectorIndex.Sector)) { Vector2s val2 = ZoneSystem.IndexToSector(sectorIndex.Sector); origins.Add(new GridPoint(val2.x, val2.y)); } } if (origins.Count == 0 && (Object)(object)ZNet.instance != (Object)null) { if (!fallbackSet) { SectorIndex sectorIndex2 = ZoneSystem.GetSectorIndex(ZNet.instance.GetReferencePosition()); Vector2s val3 = ZoneSystem.IndexToSector(sectorIndex2.Sector); fallback = new GridPoint(val3.x, val3.y); fallbackSet = true; } origins.Add(fallback); } sweep?.SetOrigins(origins); } internal unsafe bool Tick(bool persistent, bool allowTransfers, bool stageUnloaded, bool maintenanceTurn, bool collectNearPlayers, float playerRadius, Func<ItemDrop, Vector3, Vector3[], LiveWorldCleaner.Outcome> transfer, Action<string> report, Action<string> warn) { //IL_09af: Unknown result type (might be due to invalid IL or missing references) //IL_09d2: Unknown result type (might be due to invalid IL or missing references) //IL_09d7: 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_016c: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_0567: Unknown result type (might be due to invalid IL or missing references) //IL_05a7: Unknown result type (might be due to invalid IL or missing references) //IL_062e: Unknown result type (might be due to invalid IL or missing references) //IL_0613: Unknown result type (might be due to invalid IL or missing references) //IL_0618: Unknown result type (might be due to invalid IL or missing references) //IL_0603: Unknown result type (might be due to invalid IL or missing references) //IL_061d: Unknown result type (might be due to invalid IL or missing references) //IL_0665: Unknown result type (might be due to invalid IL or missing references) //IL_06b8: Unknown result type (might be due to invalid IL or missing references) //IL_0721: Unknown result type (might be due to invalid IL or missing references) //IL_0788: Unknown result type (might be due to invalid IL or missing references) //IL_07eb: Unknown result type (might be due to invalid IL or missing references) //IL_07f0: Unknown result type (might be due to invalid IL or missing references) //IL_07f4: Unknown result type (might be due to invalid IL or missing references) //IL_07f9: Unknown result type (might be due to invalid IL or missing references) //IL_07fb: Unknown result type (might be due to invalid IL or missing references) //IL_0800: Unknown result type (might be due to invalid IL or missing references) //IL_0813: Unknown result type (might be due to invalid IL or missing references) //IL_0820: Unknown result type (might be due to invalid IL or missing references) //IL_0825: Unknown result type (might be due to invalid IL or missing references) //IL_082a: Unknown result type (might be due to invalid IL or missing references) //IL_08a3: Unknown result type (might be due to invalid IL or missing references) //IL_08c4: Unknown result type (might be due to invalid IL or missing references) //IL_08c9: Unknown result type (might be due to invalid IL or missing references) //IL_08ce: Unknown result type (might be due to invalid IL or missing references) //IL_08e6: Unknown result type (might be due to invalid IL or missing references) //IL_08f3: Unknown result type (might be due to invalid IL or missing references) //IL_08fd: Unknown result type (might be due to invalid IL or missing references) //IL_0902: Unknown result type (might be due to invalid IL or missing references) //IL_0904: Unknown result type (might be due to invalid IL or missing references) //IL_0909: Unknown result type (might be due to invalid IL or missing references) //IL_084e: Unknown result type (might be due to invalid IL or missing references) //IL_0853: Unknown result type (might be due to invalid IL or missing references) if (Suspended && Now >= resumeAt) { Suspended = false; } if (Suspended || Now < resumeAt || ZDOMan.instance == null || (Object)(object)ZNetScene.instance == (Object)null || !CollectionAuthority.IsServer) { return false; } Stopwatch stopwatch = Stopwatch.StartNew(); if (!anchorCacheLoaded && anchorCachePath != null) { anchorCacheLoaded = true; try { KnownCleanerId[] array = KnownCleanerCache.Load(anchorCachePath); for (int i = 0; i < array.Length; i++) { KnownCleanerId knownCleanerId = array[i]; ObserveAnchor(ZDOMan.instance.GetZDO(new ZDOID(knownCleanerId.User, knownCleanerId.Id))); } } catch (Exception ex) { warn("Cleaner location cache ignored; normal discovery continues: " + ex.Message); } } if (anchorCacheDirty && anchorCachePath != null && Now >= nextAnchorSave) { nextAnchorSave = Now + 5.0; try { List<KnownCleanerId> list = new List<KnownCleanerId>(); foreach (ZDOID key in anchors.Keys) { ZDOID current = key; list.Add(new KnownCleanerId { User = ((ZDOID)(ref current)).UserID, Id = ((ZDOID)(ref current)).ID }); } KnownCleanerCache.Save(anchorCachePath, list); anchorCacheDirty = false; } catch (Exception ex2) { warn("Could not save cleaner location cache: " + ex2.Message); } } canStage = stageUnloaded && allowTransfers; double num = ((Adaptive && Time.unscaledDeltaTime > 0.033f) ? 0.25 : 1.0); if (Now >= nextDiscovery) { nextDiscovery = Now + IdleSeconds; Stopwatch stopwatch2 = Stopwatch.StartNew(); int num2 = 0; int num3 = Math.Min(MaximumRecords / 4, LoadedObjects.DropSlotCount); while (num2 < num3 && stopwatch2.Elapsed.TotalMilliseconds < ScanMilliseconds * num * 0.35 && LoadedObjects.DropSlotCount != 0) { loadedCursor %= LoadedObjects.DropSlotCount; ItemDrop val = LoadedObjects.DropAt(loadedCursor); loadedCursor = (loadedCursor + 1) % LoadedObjects.DropSlotCount; num2++; if (!((Object)(object)val == (Object)null)) { ZNetView component = ((Component)val).GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid()) { Inspect(component.GetZDO()); } } } int num4 = Math.Min(16, LoadedObjects.ChestSlotCount); foreach (Component item in SpiritStorageCompat.All()) { ObserveAnchor(item.GetComponent<ZNetView>().GetZDO()); } for (int j = 0; j < num4; j++) { if (!(stopwatch2.Elapsed.TotalMilliseconds < ScanMilliseconds * num * 0.5)) { break; } chestCursor %= LoadedObjects.ChestSlotCount; Container val2 = LoadedObjects.ChestAt(chestCursor); chestCursor = (chestCursor + 1) % LoadedObjects.ChestSlotCount; if (!((Object)(object)val2 == (Object)null)) { ZNetView component2 = ((Component)val2).GetComponent<ZNetView>(); if ((Object)(object)component2 != (Object)null && component2.IsValid()) { ObserveAnchor(component2.GetZDO()); } } } if (persistent && stopwatch2.Elapsed.TotalMilliseconds < ScanMilliseconds * num && Bind(warn)) { RefreshAnchors(); sweep.Tick(Now, Math.Max(1, MaximumRecords - num2), MaximumRecords, Math.Max(0.0, ScanMilliseconds * num - stopwatch2.Elapsed.TotalMilliseconds), RescanSeconds, Inspect); } scanMs += stopwatch2.Elapsed.TotalMilliseconds; } RefreshAnchors(); bool result = false; if (allowTransfers && !maintenanceTurn && cachedAnchors.Length != 0) { Stopwatch stopwatch3 = Stopwatch.StartNew(); for (int k = 0; k < MaximumRecords; k++) { if (!(stopwatch3.Elapsed.TotalMilliseconds < TransferMilliseconds * num)) { break; } fairness = (fairness + 1) % 4; if (!queue.TryTake(Now, fairness == 0, out var entry)) { break; } ZDO zDO = ZDOMan.instance.GetZDO(entry.Id); if (zDO == null || !zDO.IsValid()) { stale++; } else { if (quarantined.Contains(entry.Id) || zDO.GetBool("arcbyte.worldcleaner.leftover.v1", false)) { continue; } Candidate value = entry.Value; if (!value.Initialized) { value.Initialized = true; value.Original = (zDO.GetBool("arcbyte.worldcleaner.staged.v1", false) ? zDO.GetVec3("arcbyte.worldcleaner.origin.v1", zDO.GetPosition()) : zDO.GetPosition()); entry.Value = value; } if (!PersistentDropSweeper.ValidPosition(value.Original) || !IsDrop(zDO)) { stale++; continue; } if (OtherPlayerProximity.Blocks(value.Original, playerRadius, collectNearPlayers)) { queue.Retry(entry, Now + 2.0, Capacity); retries++; continue; } GameObject val3 = ZNetScene.instance.FindInstance(entry.Id); ItemDrop val4 = (((Object)(object)val3 != (Object)null) ? val3.GetComponent<ItemDrop>() : null); if (!((Object)(object)val4 == (Object)null) || stageUnloaded) { result = true; try { if ((Object)(object)val4 != (Object)null) { switch (transfer(val4, value.Original, cachedAnchors)) { case LiveWorldCleaner.Outcome.Retry: queue.Retry(entry, Now + 2.0, Capacity); retries++; break; case LiveWorldCleaner.Outcome.Quarantined: quarantined.Add(entry.Id); failures++; break; default: completed++; break; } } else if (stageUnloaded && (Object)(object)val3 == (Object)null && !zDO.GetBool("arcbyte.worldcleaner.staged.v1", false)) { Vector3 val5 = cachedAnchors[0]; Vector3 val6 = value.Original - val5; float num5 = ((Vector3)(ref val6)).sqrMagnitude; for (int l = 1; l < cachedAnchors.Length; l++) { val6 = value.Original - cachedAnchors[l]; float sqrMagnitude = ((Vector3)(ref val6)).sqrMagnitude; if (sqrMagnitude < num5) { num5 = sqrMagnitude; val5 = cachedAnchors[l]; } } int num6 = ((object)Unsafe.As<ZDOID, ZDOID>(ref entry.Id)/*cast due to .constrained prefix*/).GetHashCode() & 0x7FFFFFFF; float num7 = (float)(num6 % 24) * (float)Math.PI * 2f / 24f; Vector3 val7 = val5 + new Vector3(Mathf.Cos(num7) * 13f, 1f, Mathf.Sin(num7) * 13f); zDO.SetOwner(ZDOMan.GetSessionID()); zDO.Set("arcbyte.worldcleaner.origin.v1", value.Original); zDO.SetPosition(val7); val6 = zDO.GetPosition() - val7; if (((Vector3)(ref val6)).sqrMagnitude > 0.25f) { throw new InvalidOperationException("Staging position verification failed"); } zDO.Set("arcbyte.worldcleaner.staged.v1", true); staged++; queue.Retry(entry, Now + 1.0, Capacity); } else { queue.Retry(entry, Now + 10.0, Capacity); retries++; } } catch (Exception ex3) { quarantined.Add(entry.Id); failures++; ZDOID id = entry.Id; warn("Drop processing quarantined " + ((object)(*(ZDOID*)(&id))/*cast due to .constrained prefix*/).ToString() + ": " + ex3); } break; } stale++; } } transferMs += stopwatch3.Elapsed.TotalMilliseconds; } if (stopwatch.Elapsed.TotalMilliseconds > 100.0) { Suspended = true; resumeAt = Now + 2.0; warn("Performance safeguard: scanner cooling down for two seconds after " + stopwatch.Elapsed.TotalMilliseconds.ToString("F1") + " ms, then resuming queued work."); } else if (stopwatch.Elapsed.TotalMilliseconds > 20.0) { resumeAt = Now + 0.5; warn("Scanner backing off after " + stopwatch.Elapsed.TotalMilliseconds.ToString("F1") + " ms."); } if (Now >= nextReport) { nextReport = Now + 30.0; long num8 = sweep?.Sectors ?? 0; long num9 = sweep?.Examined ?? 0; double num10 = Math.Max(0.001, Now - reportStarted); report("Scanner: sectors=" + (sweep?.Sectors ?? 0) + " records=" + (sweep?.Examined ?? 0) + " sectorsPerSecond=" + ((double)(num8 - lastSectors) / num10).ToString("F1") + " recordsPerSecond=" + ((double)(num9 - lastExamined) / num10).ToString("F1") + " pending=" + queue.Count + " overflow=" + queue.Overflow + " completed=" + completed + " retries=" + retries + " staged=" + staged + " stale=" + stale + " quarantined=" + failures + " scannerMs=" + scanMs.ToString("F1") + " transferMs=" + transferMs.ToString("F1")); scanMs = (transferMs = 0.0); lastSectors = num8; lastExamined = num9; reportStarted = Now; } return result; } } internal sealed class ItemArchive { internal sealed class Entry { internal string Token; internal string Source; internal string State; internal byte[] Payload; internal ItemData CachedItem; internal ItemIdentity.Snapshot CachedIdentity; internal bool DecodeAttempted; } private const int Magic = 1464027698; private const int MaxRecordBytes = 16777216; private readonly string directory; private readonly string journal; private readonly ManualLogSource log; private readonly Func<bool> debug; private readonly Dictionary<string, Entry> entries = new Dictionary<string, Entry>(); private readonly List<Entry> ordered = new List<Entry>(); private readonly Dictionary<string, string> sourceTokens = new Dictionary<string, string>(StringComparer.Ordinal); private readonly object gate = new object(); private bool recovered; private bool journalHealthy = true; internal int RecordCount { get { lock (gate) { return ordered.Count; } } } internal bool JournalHealthy { get { lock (gate) { return recovered && journalHealthy; } } } internal event Action<Entry> RecordAvailable; internal Entry FindSource(string source) { lock (gate) { string value; return sourceTokens.TryGetValue(source, out value) ? entries[value] : null; } } internal Entry RecordAt(int index) { lock (gate) { return (index < ordered.Count) ? ordered[index] : null; } } internal Entry FindRecord(string token) { lock (gate) { Entry value; return entries.TryGetValue(token, out value) ? value : null; } } internal ItemArchive(string directory, ManualLogSource log, Func<bool> debug) { this.directory = directory; this.log = log; this.debug = debug; journal = Path.Combine(directory, "recovery.wcj"); } internal void Recover() { lock (gate) { if (recovered) { return; } Directory.CreateDirectory(directory); if (File.Exists(journal)) { using FileStream fileStream = new FileStream(journal, FileMode.Open, FileAccess.Read, FileShare.Read); using BinaryReader binaryReader = new BinaryReader(fileStream, Encoding.UTF8); while (fileStream.Position + 12 <= fileStream.Length) { long position = fileStream.Position; try { if (binaryReader.ReadInt32() != 1464027698) { throw new InvalidDataException("Journal magic mismatch at " + position); } int num = binaryReader.ReadInt32(); uint num2 = binaryReader.ReadUInt32(); if (num <= 0 || num > 16777216 || fileStream.Length - fileStream.Position < num) { throw new InvalidDataException("Incomplete or invalid journal record at " + position); } byte[] array = binaryReader.ReadBytes(num); if (Checksum(array) != num2) { throw new InvalidDataException("Journal checksum mismatch at " + position); } using MemoryStream memoryStream = new MemoryStream(array); using BinaryReader binaryReader2 = new BinaryReader(memoryStream, Encoding.UTF8); string text = binaryReader2.ReadString(); string text2