Some mods target the Mono version of the game, which is available by opting into the Steam beta branch "alternate"
Decompiled source of OrganizedCrime v1.0.0
Mods/OrganizedCrime.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Buffers.Binary; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; using System.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using System.Text.Json; using System.Text.Json.Serialization; using System.Text.RegularExpressions; using HarmonyLib; using Il2Cpp; using Il2CppFishNet; using Il2CppFishNet.Connection; using Il2CppFishNet.Managing; using Il2CppFishNet.Managing.Client; using Il2CppFishNet.Managing.Object; using Il2CppFishNet.Managing.Server; using Il2CppFishNet.Object; using Il2CppInterop.Runtime; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppScheduleOne; using Il2CppScheduleOne.Calling; using Il2CppScheduleOne.Cartel; using Il2CppScheduleOne.Core.Items.Framework; using Il2CppScheduleOne.Delivery; using Il2CppScheduleOne.DevUtilities; using Il2CppScheduleOne.Doors; using Il2CppScheduleOne.Economy; using Il2CppScheduleOne.Employees; using Il2CppScheduleOne.EntityFramework; using Il2CppScheduleOne.GameTime; using Il2CppScheduleOne.Interaction; using Il2CppScheduleOne.ItemFramework; using Il2CppScheduleOne.Law; using Il2CppScheduleOne.Management; using Il2CppScheduleOne.Map; using Il2CppScheduleOne.Messaging; using Il2CppScheduleOne.NPCs; using Il2CppScheduleOne.NPCs.Behaviour; using Il2CppScheduleOne.ObjectScripts; using Il2CppScheduleOne.Persistence; using Il2CppScheduleOne.Persistence.Datas; using Il2CppScheduleOne.Persistence.Loaders; using Il2CppScheduleOne.PlayerScripts; using Il2CppScheduleOne.Police; using Il2CppScheduleOne.Product; using Il2CppScheduleOne.Product.Packaging; using Il2CppScheduleOne.Property; using Il2CppScheduleOne.ScriptableObjects; using Il2CppScheduleOne.Storage; using Il2CppScheduleOne.Tiles; using Il2CppScheduleOne.UI; using Il2CppScheduleOne.UI.Management; using Il2CppScheduleOne.UI.Phone; using Il2CppScheduleOne.UI.Phone.Delivery; using Il2CppScheduleOne.Vehicles; using Il2CppSystem; using Il2CppSystem.Collections.Generic; using Il2CppSystem.Reflection; using MelonLoader; using MelonLoader.Preferences; using Microsoft.CodeAnalysis; using OrganizedCrime; using OrganizedCrime.Model; using OrganizedCrime.Persistence; using OrganizedCrime.Runtime; using S1API.Building; using S1API.DeadDrops; using S1API.Entities; using S1API.GameTime; using S1API.Items; using S1API.Lifecycle; using S1API.Messaging; using S1API.Money; using S1API.PhoneCalls; using S1API.Products; using S1API.Quests; using S1API.Quests.Constants; using S1API.Storages; using UnityEngine; using UnityEngine.AI; using UnityEngine.Events; using UnityEngine.Rendering; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(OrganizedCrimeMod), "Organized Crime", "1.0.0", "MadJag Studios", null)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyVersion("0.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace OrganizedCrime { public sealed class OrganizedCrimeMod : MelonMod { private sealed class FishWarehousePersistenceReplayOperations : IFishWarehousePersistenceReplayOperations { private readonly RuntimePropertyHost _propertyHost; private readonly FishWarehouseRuntimeService _runtimeService; private readonly FishWarehousePersistenceService _persistenceService; private readonly FishWarehousePropertyCaptureService _captureService; private readonly Action<string> _log; private FishWarehousePropertyReplayHost? _objectReplay; private FishWarehouseEmployeeReplayHost? _employeeReplay; public bool IsRuntimeReady => _propertyHost.PersistenceRuntimeReady; public bool IsNavigationReady => _runtimeService.EmployeeNavigationReady; public FishWarehousePersistenceReplayOperations(RuntimePropertyHost propertyHost, FishWarehouseRuntimeService runtimeService, FishWarehousePersistenceService persistenceService, FishWarehousePropertyCaptureService captureService, Action<string> log) { _propertyHost = propertyHost; _runtimeService = runtimeService; _persistenceService = persistenceService; _captureService = captureService; _log = log; } public void ConfigureReplay(bool objectReplayRequired, int? employeeAgentTypeId) { _propertyHost.ConfigurePersistenceReplay(objectReplayRequired, employeeAgentTypeId); } public void RequestOwnedRestore() { _runtimeService.RequestLoadedOwnedRestore(); } public void ResetRuntimeReferences() { _objectReplay = null; _employeeReplay = null; } public FishWarehouseReplayOperationResult ReplayObjects() { PropertyData capturedPropertyData = _captureService.CapturedPropertyData; Property currentProperty = _propertyHost.CurrentProperty; if (capturedPropertyData == null || currentProperty == null) { return FishWarehouseReplayOperationResult.Failed("captured PropertyData or runtime Property was unavailable."); } if (_objectReplay == null) { if (!FishWarehouseNativePropertyReplayAdapter.TryCreateDescriptors(capturedPropertyData, out IReadOnlyList<FishWarehouseSavedObjectDescriptor> descriptors, out string failureReason)) { return FishWarehouseReplayOperationResult.Failed(failureReason ?? "object replay descriptors were unavailable."); } _objectReplay = new FishWarehousePropertyReplayHost(new FishWarehouseNativePropertyReplayAdapter(capturedPropertyData, currentProperty, _log), descriptors, null, _log); } FishWarehousePropertyReplayResult fishWarehousePropertyReplayResult = _objectReplay.Replay(); if (fishWarehousePropertyReplayResult.State == FishWarehousePropertyReplayState.Failed) { return FishWarehouseReplayOperationResult.Failed(fishWarehousePropertyReplayResult.FailureReason ?? "native object replay failed."); } if (fishWarehousePropertyReplayResult.State != FishWarehousePropertyReplayState.Succeeded) { return FishWarehouseReplayOperationResult.Pending(); } return FishWarehouseReplayOperationResult.Succeeded(fishWarehousePropertyReplayResult.ResolvedObjectCount); } public FishWarehouseReplayOperationResult MarkObjectsReplayed() { FishWarehousePropertyReplayHost? objectReplay = _objectReplay; if (objectReplay == null || objectReplay.Result.State != FishWarehousePropertyReplayState.Succeeded) { return FishWarehouseReplayOperationResult.Failed("native object replay was not complete before the runtime gate was marked."); } _runtimeService.MarkPersistenceObjectsReplayed(); string[] savedHomeGuids = (from record in _captureService.CapturedEmployeeRecords select record.BedGuid into guid where !string.IsNullOrWhiteSpace(guid) select guid).ToArray(); switch (_propertyHost.AssessRestoredEmployeeHome((IReadOnlyCollection<string>?)(object)savedHomeGuids)) { case FishWarehouseEmployeeHomeAdoptionResult.MultipleFound: return FishWarehouseReplayOperationResult.Failed("multiple restored Fish Warehouse employee homes were found; authored fallback was not permitted."); case FishWarehouseEmployeeHomeAdoptionResult.Failed: return FishWarehouseReplayOperationResult.Failed("restored Fish Warehouse employee-home adoption failed."); case FishWarehouseEmployeeHomeAdoptionResult.Adopted: _runtimeService.MarkPersistenceEmployeeHomeRestored(); break; default: { FishWarehouseSaveState? currentState = _persistenceService.CurrentState; if ((object)currentState != null && currentState.EmployeeHomePlaced && !_runtimeService.TryPlaceEmployeeHome()) { return FishWarehouseReplayOperationResult.Failed("saved Fish Warehouse employee home was not restored and authored fallback placement failed."); } break; } } return FishWarehouseReplayOperationResult.Succeeded(_objectReplay.Result.ResolvedObjectCount); } public FishWarehouseReplayOperationResult ReplayEmployees() { PropertyData capturedPropertyData = _captureService.CapturedPropertyData; Property currentProperty = _propertyHost.CurrentProperty; if (capturedPropertyData == null || currentProperty == null) { return FishWarehouseReplayOperationResult.Failed("captured PropertyData or runtime Property was unavailable."); } if (_employeeReplay == null) { IReadOnlyList<FishWarehouseEmployeeReplayDescriptor> capturedEmployees = FishWarehousePropertyCaptureService.CreateEmployeeReplayDescriptors(_captureService.CapturedEmployeeRecords); if (!_propertyHost.TryCreateEmployeeReplayAdapter(capturedPropertyData, out IFishWarehouseNativeEmployeeReplayAdapter adapter, out string failureReason, _persistenceService.CurrentState?.Replay?.InventoryRestoredEmployeeGuids)) { return FishWarehouseReplayOperationResult.Failed(failureReason ?? "employee replay adapter was unavailable."); } _employeeReplay = new FishWarehouseEmployeeReplayHost(adapter, capturedEmployees, _persistenceService.CurrentState?.UnsupportedEmployees ?? Array.Empty<FishWarehouseUnsupportedEmployeeRecord>(), null, _log); } FishWarehouseEmployeeReplayResult fishWarehouseEmployeeReplayResult = _employeeReplay.Replay(IsNavigationReady); if (fishWarehouseEmployeeReplayResult.State == FishWarehouseEmployeeReplayState.Pending) { return new FishWarehouseReplayOperationResult(FishWarehouseReplayOperationState.Pending, 0, null, fishWarehouseEmployeeReplayResult.InventoryRestoredEmployeeGuids); } if (fishWarehouseEmployeeReplayResult.State == FishWarehouseEmployeeReplayState.Failed || !fishWarehouseEmployeeReplayResult.CanAdvanceEmployeesReplayed) { return new FishWarehouseReplayOperationResult(FishWarehouseReplayOperationState.Failed, 0, fishWarehouseEmployeeReplayResult.FailureReason ?? fishWarehouseEmployeeReplayResult.PrimaryFailureReason ?? "supported employee replay did not complete.", fishWarehouseEmployeeReplayResult.InventoryRestoredEmployeeGuids); } if (!_persistenceService.TryMergeUnsupportedEmployees(fishWarehouseEmployeeReplayResult.UnsupportedEmployees)) { return FishWarehouseReplayOperationResult.Failed("unsupported employee records could not be persisted."); } _log($"Fish Warehouse employee replay summary: {fishWarehouseEmployeeReplayResult.ReplayedEmployeeCount}/{fishWarehouseEmployeeReplayResult.SupportedCapturedEmployeeCount} supported employees replayed."); return new FishWarehouseReplayOperationResult(FishWarehouseReplayOperationState.Succeeded, fishWarehouseEmployeeReplayResult.ReplayedEmployeeCount, null, fishWarehouseEmployeeReplayResult.InventoryRestoredEmployeeGuids); } public FishWarehouseDeliveryRestoreFlushResult ReleaseDeliveries() { return FishWarehouseDeliveryRestorePatch.FlushIfReady(); } } private FishWarehouseRuntimeService? _fishWarehouseRuntimeService; private RuntimePropertyHost? _runtimePropertyHost; private FishWarehousePersistenceService? _fishWarehousePersistenceService; private FishWarehousePropertyCaptureService? _fishWarehousePropertyCaptureService; private FishWarehousePersistenceReplayService? _fishWarehousePersistenceReplayService; private LocalPressureRuntimeComposition? _localPressureRuntime; private NativeLawResponseModComposition? _nativeLawResponseComposition; private NativeLawResponseController? _nativeLawResponseController; private PoliceCustodyEvidenceBridge? _policeCustodyEvidenceBridge; private SyndicateHqHostContextAdapter? _syndicateHqHostContext; private Release1StoryRuntimeService? _release1StoryRuntime; private Release1ProductionComposition? _release1ProductionComposition; private Release1ChiefComposition? _release1ChiefComposition; private SyndicateHqRuntimeComposition? _syndicateHqComposition; private SyndicateHqNativeStorageRuntime? _syndicateHqStorageRuntime; private IRelease1SmallCourtesyWorld? _release1SmallCourtesyWorld; private bool _initialized; private bool _ownerQaKeysEnabled; private bool _theEnvelopeCashGateDumpNext = true; private bool _theEnvelopeClosetCashGateDumpNext = true; private bool _keepTheLightsOffProductionGateDumpNext = true; private OrganizedCrimeTimingReceipts _timing = OrganizedCrimeTimingReceipts.Disabled; public override void OnInitializeMelon() { if (_initialized) { MelonLogger.Warning("[Organized Crime] duplicate initialization was ignored."); return; } _initialized = true; OrganizedCrimeLog.Warning = delegate(string message) { MelonLogger.Warning("[Organized Crime] " + message); }; OrganizedCrimeLog.Receipt = delegate(string message) { MelonLogger.Msg("[Organized Crime] " + message); }; MelonLogger.Msg("[Organized Crime] production runtime shell loaded."); _ownerQaKeysEnabled = OwnerQaKeysPreference.Read(); _timing = new OrganizedCrimeTimingReceipts((Action<string>?)MelonLogger.Msg, TimingReceiptThresholdPreference.Read()); if (_timing.IsEnabled) { MelonLogger.Msg($"[Organized Crime] Timing receipts report any phase at or above {_timing.ThresholdMs} ms."); } if (_ownerQaKeysEnabled) { MelonLogger.Msg("[Organized Crime] Owner QA keys are enabled by preference; F8 recognition and fish warehouse developer keys are live."); } SyndicateHqHostContextAdapter syndicateHqHostContextAdapter = (_syndicateHqHostContext = new SyndicateHqHostContextAdapter()); _release1StoryRuntime = new Release1StoryRuntimeService(syndicateHqHostContextAdapter, CreateRelease1StoryRepository); Release1PresentationMode release1PresentationMode = Release1PresentationModePreference.Read(); S1ApiRelease1NativePresentation native = ((release1PresentationMode == Release1PresentationMode.Native) ? new S1ApiRelease1NativePresentation(Release1QuestPersistencePolicyPreference.Read(), delegate(string message) { MelonLogger.Warning("[Organized Crime] " + message); }) : null); SyndicateHqNativeStorageRuntime syndicateHqNativeStorageRuntime = (_syndicateHqStorageRuntime = new SyndicateHqNativeStorageRuntime(new SyndicateHqNativeStorageBoundary { Timing = _timing }, delegate(string message) { MelonLogger.Warning("[Organized Crime] " + message); }, OrganizedCrimeLog.Receipt)); S1ApiRelease1SmallCourtesyWorld s1ApiRelease1SmallCourtesyWorld = (S1ApiRelease1SmallCourtesyWorld)(_release1SmallCourtesyWorld = new S1ApiRelease1SmallCourtesyWorld(syndicateHqHostContextAdapter, syndicateHqNativeStorageRuntime, null, ((MelonBase)this).HarmonyInstance)); SyndicateHqDoorObserver hqObserver = null; _release1ProductionComposition = new Release1ProductionComposition(_release1StoryRuntime, new Release1PostBenziesUnlockReader(syndicateHqHostContextAdapter, new S1CartelStatusSource()), new S1ApiRelease1PhoneCallQueue(), s1ApiRelease1SmallCourtesyWorld, delegate(string message) { MelonLogger.Warning("[Organized Crime] " + message); }, null, null, null, release1PresentationMode, native, delegate { SyndicateHqDoorFingerprint syndicateHqDoorFingerprint = hqObserver?.CurrentFingerprint; return ((object)syndicateHqDoorFingerprint == null || !syndicateHqDoorFingerprint.Position.IsFinite) ? null : new Release1WorldPoint(syndicateHqDoorFingerprint.Position.X, syndicateHqDoorFingerprint.Position.Y, syndicateHqDoorFingerprint.Position.Z); }); _release1StoryRuntime.Timing = _timing; _release1ProductionComposition.Timing = _timing; _release1ProductionComposition.KeepTheLightsOff.Service.Timing = _timing; _release1ProductionComposition.TheEnvelope.Service.Timing = _timing; if (!SyndicateHqStorageLoadPatch.Apply(((MelonBase)this).HarmonyInstance, syndicateHqNativeStorageRuntime, new SyndicateHqStorageLoadContextAdapter(), delegate(string message) { MelonLogger.Warning("[Organized Crime] " + message); }, OrganizedCrimeLog.Receipt)) { MelonLogger.Warning("[Organized Crime] Native Syndicate HQ storage will remain inert because its exact vanilla load prefix was unavailable."); } SyndicateHqRuntimeService hqRuntime = null; hqObserver = new SyndicateHqDoorObserver(delegate(SyndicateHqDoorFingerprint fingerprint, long generation) { hqRuntime?.HandleDoorInteraction(fingerprint, generation); }, delegate(string message) { MelonLogger.Warning("[Organized Crime] " + message); }) { Timing = _timing }; SyndicateHqInteriorRuntime interior = new SyndicateHqInteriorRuntime(delegate(string message) { MelonLogger.Warning("[Organized Crime] " + message); }, syndicateHqNativeStorageRuntime) { Timing = _timing }; hqRuntime = new SyndicateHqRuntimeService(syndicateHqHostContextAdapter, new Release1StorySyndicateHqUnlockAuthority(syndicateHqHostContextAdapter, _release1StoryRuntime), hqObserver, interior, new SyndicateHqNativePlayerTransport(delegate(string message) { MelonLogger.Warning("[Organized Crime] " + message); }), delegate(string message) { MelonLogger.Warning("[Organized Crime] " + message); }); _syndicateHqComposition = new SyndicateHqRuntimeComposition(hqRuntime, delegate { _syndicateHqHostContext?.BeginLoad(); }); FishWarehouseManagementCanvasPatch.Apply(((MelonBase)this).HarmonyInstance); FishWarehouseNativeGridPlacementPatches.Apply(((MelonBase)this).HarmonyInstance); FishWarehouseDockOccupantRefreshPatch.Apply(((MelonBase)this).HarmonyInstance); RuntimePropertyHost propertyHost = new RuntimePropertyHost(); _runtimePropertyHost = propertyHost; FishWarehouseDeliveryRestorePatch.Apply(((MelonBase)this).HarmonyInstance, () => propertyHost.CanRestoreDeliveries, delegate(string message) { MelonLogger.Msg("[Organized Crime] " + message); }); _fishWarehouseRuntimeService = new FishWarehouseRuntimeService(propertyHost, RuntimePropertyReadiness.IsFishWarehouseReady, propertyHost.TryPlaceEmployeeHome, delegate(string message) { MelonLogger.Msg("[Organized Crime] " + message); }); FishWarehousePropertySnapshotStore snapshotStore = new FishWarehousePropertySnapshotStore(); FishWarehousePropertyCaptureService captureService = null; FishWarehouseReplayLifecycle fishWarehouseReplayLifecycle = new FishWarehouseReplayLifecycle((FishWarehouseReplayCheckpoint checkpoint) => captureService?.GetRecoveryPrerequisites(checkpoint) ?? new FishWarehouseCaptureRecoveryPrerequisites(ByteProtectionSucceeded: false, InspectionSucceeded: false, TypedPayloadRetentionSucceeded: false, CheckpointPersistenceSucceeded: false)); _fishWarehousePersistenceService = new FishWarehousePersistenceService(new FishWarehouseSaveStore(), GetActiveSaveFolder, () => _fishWarehouseRuntimeService?.CaptureSaveState() ?? FishWarehouseSaveState.UnownedState(), ApplyLoadedSaveState, delegate(string message) { MelonLogger.Msg("[Organized Crime] " + message); }, snapshotStore, fishWarehouseReplayLifecycle); captureService = new FishWarehousePropertyCaptureService(snapshotStore, new FishWarehouseNativePropertySnapshotInspector(), _fishWarehousePersistenceService, fishWarehouseReplayLifecycle, delegate(string message) { MelonLogger.Msg("[Organized Crime] " + message); }); _fishWarehousePropertyCaptureService = captureService; FishWarehouseRuntimeService runtimeService = _fishWarehouseRuntimeService; FishWarehousePersistenceService persistenceService = _fishWarehousePersistenceService; FishWarehousePersistenceReplayOperations replayOperations = new FishWarehousePersistenceReplayOperations(propertyHost, runtimeService, persistenceService, captureService, delegate(string message) { MelonLogger.Msg("[Organized Crime] " + message); }); _fishWarehousePersistenceReplayService = new FishWarehousePersistenceReplayService(fishWarehouseReplayLifecycle, GetActiveSaveFolder, captureService.TryRecoverAtLoadComplete, persistenceService.HandleLoadComplete, () => persistenceService.CurrentState, replayOperations, persistenceService.TryPersistReplayCheckpoint, delegate { captureService.ResetRuntimeReferences(); replayOperations.ResetRuntimeReferences(); persistenceService.PrimeStateForLoad(); }, FishWarehouseDeliveryRestorePatch.Reset, delegate { if (!runtimeService.PrepareForLoad()) { MelonLogger.Warning("[Organized Crime] Fish Warehouse runtime Property could not be fully prepared for the next save load."); } }, null, delegate(string message) { MelonLogger.Msg("[Organized Crime] " + message); }); FishWarehousePropertyLoadCapturePatch.Apply(((MelonBase)this).HarmonyInstance, IsAuthoritativeHost, GetActiveSaveFolder, captureService, delegate(string message) { MelonLogger.Msg("[Organized Crime] " + message); }); FishWarehouseNativePropertyWriteGuardPatch.Apply(((MelonBase)this).HarmonyInstance, IsAuthoritativeHost, () => captureService.IsDegraded); GameLifecycle.OnSaveComplete += HandleSaveComplete; GameLifecycle.OnSaveStart += HandleSaveStart; GameLifecycle.OnPreLoad += HandlePreLoad; GameLifecycle.OnLoadComplete += HandleLoadComplete; GameLifecycle.OnPreSceneChange += HandlePreSceneChange; _nativeLawResponseComposition = new NativeLawResponseModComposition(CreateLocalPressureRepository, delegate(string message) { MelonLogger.Warning("[Organized Crime] " + message); }, delegate(string message) { MelonLogger.Msg("[Organized Crime] " + message); }, OrganizedCrimeLog.Receipt); _nativeLawResponseController = _nativeLawResponseComposition.Controller; _localPressureRuntime = _nativeLawResponseComposition.LocalPressureRuntime; _policeCustodyEvidenceBridge = new PoliceCustodyEvidenceBridge(new CustodyEntryGate(), _localPressureRuntime.Service, delegate(string message) { MelonLogger.Warning("[Organized Crime] " + message); }); PoliceCustodyPatch.Apply(((MelonBase)this).HarmonyInstance, _policeCustodyEvidenceBridge, delegate(string message) { MelonLogger.Warning("[Organized Crime] " + message); }); S1ApiRelease1NativePresentation native2 = ((release1PresentationMode == Release1PresentationMode.Native) ? new S1ApiRelease1NativePresentation(Release1QuestPersistencePolicyPreference.Read(), "oc_release1_chief_campbell", () => (NPC)(object)new Release1ChiefCampbellNpc(), (NPC npc) => npc is Release1ChiefCampbellNpc, delegate(string message) { MelonLogger.Warning("[Organized Crime] " + message); }) : null); LocalPressureRuntimeService localPressureService = _localPressureRuntime.Service; _release1ChiefComposition = new Release1ChiefComposition(_release1StoryRuntime, s1ApiRelease1SmallCourtesyWorld, _nativeLawResponseComposition.ChiefObserver, (string playerId) => (!localPressureService.TryGetState(playerId, out LocalPressureState state)) ? null : state, (string playerId) => localPressureService.TryApplyRecordWipe(playerId, localPressureService.SessionEpoch, localPressureService.LoadEpoch), delegate(out Guid sessionEpoch, out long loadEpoch) { sessionEpoch = localPressureService.SessionEpoch; loadEpoch = localPressureService.LoadEpoch; return localPressureService.Phase == LocalPressureRuntimePhase.Active; }, release1PresentationMode, native2, delegate(string message) { MelonLogger.Warning("[Organized Crime] " + message); }); } public override void OnDeinitializeMelon() { Release1LockdownGatePatch.Reset(); _syndicateHqStorageRuntime?.MarkTeardown(); if (_syndicateHqComposition != null && !_syndicateHqComposition.TryDispose()) { MelonLogger.Warning("[Organized Crime] Syndicate HQ deinitialization remains pending until exact listener cleanup succeeds."); } _syndicateHqComposition = null; SyndicateHqStorageLoadPatch.Reset(); _syndicateHqStorageRuntime?.Dispose(); _syndicateHqStorageRuntime = null; _release1ProductionComposition?.Dispose(); _release1ProductionComposition = null; _release1ChiefComposition?.Dispose(); _release1ChiefComposition = null; _release1SmallCourtesyWorld = null; _release1StoryRuntime?.Dispose(); _release1StoryRuntime = null; _syndicateHqHostContext = null; PoliceCustodyPatch.Reset(); _policeCustodyEvidenceBridge?.Dispose(); _policeCustodyEvidenceBridge = null; _nativeLawResponseComposition?.Dispose(); _nativeLawResponseComposition = null; _nativeLawResponseController = null; _localPressureRuntime = null; FishWarehouseManagementCanvasPatch.SetTargetProperty(null); FishWarehouseDeliveryRestorePatch.Reset(); FishWarehousePropertyLoadCapturePatch.Reset(); FishWarehouseNativePropertyWriteGuardPatch.Reset(); GameLifecycle.OnSaveComplete -= HandleSaveComplete; GameLifecycle.OnSaveStart -= HandleSaveStart; GameLifecycle.OnPreLoad -= HandlePreLoad; GameLifecycle.OnLoadComplete -= HandleLoadComplete; GameLifecycle.OnPreSceneChange -= HandlePreSceneChange; _fishWarehousePersistenceReplayService = null; _fishWarehousePersistenceService = null; _fishWarehousePropertyCaptureService?.Reset(); _fishWarehousePropertyCaptureService = null; _fishWarehouseRuntimeService = null; _runtimePropertyHost = null; _initialized = false; } public override void OnUpdate() { //IL_05c9: Unknown result type (might be due to invalid IL or missing references) //IL_05e3: Unknown result type (might be due to invalid IL or missing references) //IL_056f: Unknown result type (might be due to invalid IL or missing references) //IL_0349: Unknown result type (might be due to invalid IL or missing references) //IL_0426: Unknown result type (might be due to invalid IL or missing references) _syndicateHqComposition?.Update(); _release1ProductionComposition?.Update(); _release1ChiefComposition?.Update(); _localPressureRuntime?.Service.PumpReadiness(); if (IsAuthoritativeHost()) { _fishWarehouseRuntimeService?.Update(); _fishWarehousePersistenceReplayService?.Update(); } _runtimePropertyHost?.EnsureManagementWorldspaceUiContainerForOpenCanvas(); if (!_ownerQaKeysEnabled) { return; } if (Input.GetKeyDown((KeyCode)92)) { _fishWarehouseRuntimeService?.ToggleDeveloperLifecycle(); } if (Input.GetKeyDown((KeyCode)111)) { _fishWarehouseRuntimeService?.TryUnlockDeveloperLifecycle(); } if (Input.GetKeyDown((KeyCode)112)) { _fishWarehouseRuntimeService?.TryPlaceEmployeeHome(); } if (Input.GetKeyDown((KeyCode)289) && _syndicateHqHostContext != null && _release1StoryRuntime != null) { Release1StoryOwnerQaRecognitionResult release1StoryOwnerQaRecognitionResult = Release1StoryOwnerQaRecognitionHarness.TryRecognize(_syndicateHqHostContext, _release1StoryRuntime); MelonLogger.Msg($"[Organized Crime] OC-48 owner QA recognition: {release1StoryOwnerQaRecognitionResult.Status}: {release1StoryOwnerQaRecognitionResult.Message}"); } if (Input.GetKeyDown((KeyCode)290) && _release1SmallCourtesyWorld != null) { Release1StagingHarnessResult release1StagingHarnessResult = Release1WrongAddressStagingHarness.TryStage(_release1SmallCourtesyWorld); MelonLogger.Msg($"[Organized Crime] OC-52 staging proof: stage status {release1StagingHarnessResult.Status}"); foreach (string line in release1StagingHarnessResult.Lines) { MelonLogger.Msg("[Organized Crime] OC-52 staging proof: " + line); } } if (Input.GetKeyDown((KeyCode)291) && _release1SmallCourtesyWorld != null) { Release1StagingHarnessResult release1StagingHarnessResult2 = Release1WrongAddressStagingHarness.TryDump(_release1SmallCourtesyWorld); MelonLogger.Msg($"[Organized Crime] OC-52 staging proof: dump status {release1StagingHarnessResult2.Status}"); foreach (string line2 in release1StagingHarnessResult2.Lines) { MelonLogger.Msg("[Organized Crime] OC-52 staging proof: " + line2); } try { List<WorldStorageEntity> all = WorldStorageEntity.All; int value = all?.Count ?? 0; MelonLogger.Msg($"[Organized Crime] OC-52 staging proof: world storage entities: {value}"); if (all != null) { Enumerator<WorldStorageEntity> enumerator2 = all.GetEnumerator(); while (enumerator2.MoveNext()) { WorldStorageEntity current3 = enumerator2.Current; if ((Object)(object)current3 == (Object)null) { continue; } List<ItemSlot> itemSlots = ((StorageEntity)current3).ItemSlots; int value2 = itemSlots?.Count ?? 0; int num = 0; if (itemSlots != null) { Enumerator<ItemSlot> enumerator3 = itemSlots.GetEnumerator(); while (enumerator3.MoveNext()) { ItemSlot current4 = enumerator3.Current; if (current4 != null && current4.Quantity > 0) { num++; } } } MelonLogger.Msg($"[Organized Crime] OC-52 staging proof: entity {current3.GUID} name {((Object)((Component)current3).gameObject).name} changed {current3.HasChanged} slots {value2} occupied {num}"); if (itemSlots == null) { continue; } for (int i = 0; i < itemSlots.Count; i++) { ItemSlot val = itemSlots[i]; if (val != null && val.Quantity > 0) { ItemInstance itemInstance = val.ItemInstance; string value3 = ((itemInstance == null) ? "null" : ((BaseItemInstance)itemInstance).ID); MelonLogger.Msg($"[Organized Crime] OC-52 staging proof: entity {current3.GUID} slot {i} id {value3} quantity {val.Quantity}"); } } } } } catch (Exception ex) { MelonLogger.Msg("[Organized Crime] OC-52 staging proof: world storage dump failed: " + ex.Message); } try { List<DeadDrop> deadDrops = DeadDrop.DeadDrops; int value4 = deadDrops?.Count ?? 0; MelonLogger.Msg($"[Organized Crime] OC-52 staging proof: dead drops: {value4}"); if (deadDrops != null) { Enumerator<DeadDrop> enumerator4 = deadDrops.GetEnumerator(); while (enumerator4.MoveNext()) { DeadDrop current5 = enumerator4.Current; if (!((Object)(object)current5 == (Object)null)) { WorldStorageEntity storage = current5.Storage; if ((Object)(object)storage == (Object)null) { MelonLogger.Msg($"[Organized Crime] OC-52 staging proof: drop {current5.DeadDropName} guid {current5.GUID} storage null"); } else { MelonLogger.Msg($"[Organized Crime] OC-52 staging proof: drop {current5.DeadDropName} guid {current5.GUID} storage {storage.GUID} storageName {((Object)((Component)storage).gameObject).name}"); } } } } } catch (Exception ex2) { MelonLogger.Msg("[Organized Crime] OC-52 staging proof: dead drop dump failed: " + ex2.Message); } } if (Input.GetKeyDown((KeyCode)292) && _release1SmallCourtesyWorld != null) { Release1StagingHarnessResult release1StagingHarnessResult3 = Release1RoomWithNoNameHoldRoomHarness.TryDump(_release1SmallCourtesyWorld); MelonLogger.Msg($"[Organized Crime] OC-57 hold room proof: dump status {release1StagingHarnessResult3.Status}"); foreach (string line3 in release1StagingHarnessResult3.Lines) { MelonLogger.Msg("[Organized Crime] OC-57 hold room proof: " + line3); } } if (Input.GetKeyDown((KeyCode)287) && _release1SmallCourtesyWorld != null) { Release1StagingHarnessResult release1StagingHarnessResult4 = Release1ShortNoticeQuantityHarness.TryDecrementByTwo(_release1SmallCourtesyWorld); MelonLogger.Msg($"[Organized Crime] OC-58 quantity proof: status {release1StagingHarnessResult4.Status}"); foreach (string line4 in release1StagingHarnessResult4.Lines) { MelonLogger.Msg("[Organized Crime] OC-58 quantity proof: " + line4); } } if (Input.GetKeyDown((KeyCode)282) && _release1SmallCourtesyWorld != null) { Release1StagingHarnessResult release1StagingHarnessResult5 = (_theEnvelopeCashGateDumpNext ? Release1TheEnvelopeCashGateHarness.TryDumpCashSlots(_release1SmallCourtesyWorld) : Release1TheEnvelopeCashGateHarness.TryDecrementFirstCashSlot(_release1SmallCourtesyWorld)); string value5 = (_theEnvelopeCashGateDumpNext ? "dump" : "decrement"); MelonLogger.Msg($"[Organized Crime] OC-60 cash gate proof ({value5}): status {release1StagingHarnessResult5.Status}"); foreach (string line5 in release1StagingHarnessResult5.Lines) { MelonLogger.Msg("[Organized Crime] OC-60 cash gate proof: " + line5); } _theEnvelopeCashGateDumpNext = !_theEnvelopeCashGateDumpNext; } if (Input.GetKeyDown((KeyCode)283) && _release1SmallCourtesyWorld != null) { Release1StagingHarnessResult release1StagingHarnessResult6 = (_theEnvelopeClosetCashGateDumpNext ? Release1TheEnvelopeClosetCashGateHarness.TryDumpClosetCashSlots(_release1SmallCourtesyWorld) : Release1TheEnvelopeClosetCashGateHarness.TryDecrementFirstClosetCashSlot(_release1SmallCourtesyWorld)); string value6 = (_theEnvelopeClosetCashGateDumpNext ? "dump" : "decrement"); MelonLogger.Msg($"[Organized Crime] OC-61 closet cash gate proof ({value6}): status {release1StagingHarnessResult6.Status}"); foreach (string line6 in release1StagingHarnessResult6.Lines) { MelonLogger.Msg("[Organized Crime] OC-61 closet cash gate proof: " + line6); } _theEnvelopeClosetCashGateDumpNext = !_theEnvelopeClosetCashGateDumpNext; } if (Input.GetKeyDown((KeyCode)278) && _release1SmallCourtesyWorld != null) { Release1StagingHarnessResult release1StagingHarnessResult7 = (_keepTheLightsOffProductionGateDumpNext ? Release1KeepTheLightsOffProductionGateHarness.TryDumpProductionActivity(_release1SmallCourtesyWorld) : Release1KeepTheLightsOffProductionGateHarness.TryCrossCheckUnpaidEmployees(_release1SmallCourtesyWorld)); string value7 = (_keepTheLightsOffProductionGateDumpNext ? "dump" : "cross check"); MelonLogger.Msg($"[Organized Crime] OC-65 production gate proof ({value7}): status {release1StagingHarnessResult7.Status}"); foreach (string line7 in release1StagingHarnessResult7.Lines) { MelonLogger.Msg("[Organized Crime] OC-65 production gate proof: " + line7); } _keepTheLightsOffProductionGateDumpNext = !_keepTheLightsOffProductionGateDumpNext; } if (Input.GetKeyDown((KeyCode)279) && _release1SmallCourtesyWorld != null) { string reason; Release1SmallCourtesyWorldMutationStatus value8 = (Release1LockdownGatePatch.LockdownActive ? _release1SmallCourtesyWorld.TryReleaseLockdown(out reason) : _release1SmallCourtesyWorld.TryEngageLockdown(out reason)); MelonLogger.Msg($"[Organized Crime] OC-73 lockdown gate: status {value8}"); if (!string.IsNullOrEmpty(reason)) { MelonLogger.Msg("[Organized Crime] OC-73 lockdown gate: " + reason); } } if (!Input.GetKeyDown((KeyCode)277)) { return; } Release1StagingHarnessResult release1StagingHarnessResult8 = Release1NpcRegistryDumpHarness.TryDump(); MelonLogger.Msg($"[Organized Crime] OC-56 npc registry: status {release1StagingHarnessResult8.Status}"); foreach (string line8 in release1StagingHarnessResult8.Lines) { MelonLogger.Msg("[Organized Crime] OC-56 npc registry: " + line8); } } public override void OnGUI() { _syndicateHqComposition?.OnGUI(); _release1ProductionComposition?.OnGUI(); } private void HandleSaveComplete() { _timing.Measure("save-complete", delegate { FishWarehousePersistenceReplayService.RunIfAuthoritativeHost(IsAuthoritativeHost(), delegate { _timing.Measure("save-complete/story", delegate { Release1StoryLifecycleLogging.LogIfRejected("OnSaveComplete", _release1StoryRuntime?.OnSaveComplete()); }); _timing.Measure("save-complete/production", delegate { _release1ProductionComposition?.OnSaveComplete(); }); _timing.Measure("save-complete/chief", delegate { _release1ChiefComposition?.OnSaveComplete(); }); _timing.Measure("save-complete/hq", delegate { _syndicateHqComposition?.OnSaveComplete(); }); _timing.Measure("save-complete/fish-warehouse", delegate { _fishWarehousePersistenceService?.HandleSaveComplete(); }); }); }); } private void HandleSaveStart() { _timing.Measure("save-start", delegate { _timing.Measure("save-start/story", delegate { Release1StoryLifecycleLogging.LogIfRejected("OnSaveStart", _release1StoryRuntime?.OnSaveStart()); }); _timing.Measure("save-start/production", delegate { _release1ProductionComposition?.OnSaveStart(); }); _timing.Measure("save-start/chief", delegate { _release1ChiefComposition?.OnSaveStart(); }); _timing.Measure("save-start/hq", delegate { _syndicateHqComposition?.OnSaveStart(); }); }); } private void HandlePreLoad() { _timing.Measure("pre-load", delegate { SyndicateHqStorageLoadPatch.BeginLoadCycle(); _timing.Measure("pre-load/hq", delegate { _syndicateHqComposition?.OnPreLoad(); }); _timing.Measure("pre-load/production", delegate { _release1ProductionComposition?.OnPreLoad(); }); _timing.Measure("pre-load/chief", delegate { _release1ChiefComposition?.OnPreLoad(); }); _timing.Measure("pre-load/story", delegate { Release1StoryLifecycleLogging.LogIfRejected("OnPreLoad", _release1StoryRuntime?.OnPreLoad()); }); FishWarehousePersistenceReplayService.RunIfAuthoritativeHost(IsAuthoritativeHost(), delegate { _timing.Measure("pre-load/fish-warehouse", delegate { _fishWarehousePersistenceReplayService?.PrepareForLoad(); }); }); }); } private void HandleLoadComplete() { _timing.Measure("load-complete", delegate { bool hqLoadPrepared = true; _timing.Measure("load-complete/hq-prepare", delegate { hqLoadPrepared = _syndicateHqComposition?.PrepareLoadComplete() ?? true; }); _timing.Measure("load-complete/story", delegate { Release1StoryLifecycleLogging.LogIfRejected("OnLoadComplete", _release1StoryRuntime?.OnLoadComplete()); }); _timing.Measure("load-complete/production", delegate { _release1ProductionComposition?.OnLoadComplete(); }); _timing.Measure("load-complete/chief", delegate { _release1ChiefComposition?.OnLoadComplete(); }); _timing.Measure("load-complete/hq-storage", delegate { SyndicateHqStorageLoadPatch.CompleteAfterVanillaLoad(); }); if (hqLoadPrepared) { _timing.Measure("load-complete/hq", delegate { _syndicateHqComposition?.OnLoadComplete(); }); } FishWarehousePersistenceReplayService.RunIfAuthoritativeHost(IsAuthoritativeHost(), delegate { _timing.Measure("load-complete/fish-warehouse", delegate { _fishWarehousePersistenceReplayService?.HandleLoadComplete(); }); }); }); if (!_ownerQaKeysEnabled || _release1SmallCourtesyWorld == null) { return; } try { foreach (string line in Release1WrongAddressStagingHarness.TryDump(_release1SmallCourtesyWorld).Lines) { if (line.StartsWith("dead drops read: ", StringComparison.Ordinal) || line.Contains(" quantity ", StringComparison.Ordinal)) { MelonLogger.Msg("[Organized Crime] OC-52 staging proof at load: " + line); } } } catch (Exception ex) { MelonLogger.Warning("[Organized Crime] OC-52 staging proof at load failed: " + ex.Message); } } private void HandlePreSceneChange() { _timing.Measure("pre-scene-change", delegate { _timing.Measure("pre-scene-change/production", delegate { _release1ProductionComposition?.OnPreSceneChange(); }); _timing.Measure("pre-scene-change/hq", delegate { _syndicateHqComposition?.OnPreSceneChange(); }); }); } private static string? GetActiveSaveFolder() { try { LoadManager instance = Singleton<LoadManager>.Instance; return (instance != null) ? instance.LoadedGameFolderPath : null; } catch (Exception ex) { MelonLogger.Warning("[Organized Crime] Could not resolve the active save folder: " + ex.Message); return null; } } private static ILocalPressureStateRepository? CreateLocalPressureRepository(string? activeSaveFolder) { if (!LocalPressureSavePath.TryCreate(activeSaveFolder, out LocalPressureSavePath path, out LocalPressureSavePathResult _)) { return null; } return new LocalPressureStateStoreRepository(new LocalPressureStateStore(path)); } private static IRelease1StoryRepository CreateRelease1StoryRepository(string activeSaveFolder) { if (!Release1StorySavePath.TryCreate(activeSaveFolder, out Release1StorySavePath path, out Release1StorySavePathResult result)) { throw new InvalidOperationException(result.Message); } return new Release1StoryStateStoreRepository(new Release1StoryStateStore(path)); } private void ApplyLoadedSaveState(FishWarehouseSaveState state) { _fishWarehouseRuntimeService?.ApplyLoadedSaveState(state); } private static bool IsAuthoritativeHost() { try { ServerManager serverManager = InstanceFinder.ServerManager; return serverManager != null && serverManager.OneServerStarted(); } catch { return false; } } } } namespace OrganizedCrime.Runtime { public sealed class FishWarehouseBuildSurfaceHost { private const float GridPlaneOffset = 0.02f; private const BindingFlags MemberFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; private GameObject? _gridProxy; private Grid? _grid; private BuildableItem? _employeeHome; private EmployeeHome? _employeeHomeComponent; public bool IsReady { get { if (_gridProxy != null) { return _grid != null; } return false; } } public string GridGuid { get; private set; } = string.Empty; public int TileCount { get; private set; } public EmployeeHome? CurrentEmployeeHome => _employeeHomeComponent; public bool TryAdoptRestoredEmployeeHome(Property parentProperty, BuildableItem buildable, EmployeeHome employeeHome, Action<string>? log = null) { if (_employeeHome != null) { if ((Object)(object)_employeeHome == (Object)(object)buildable) { return (Object)(object)_employeeHomeComponent == (Object)(object)employeeHome; } return false; } if (!IsReady || parentProperty == null || buildable == null || employeeHome == null) { log?.Invoke("Fish Warehouse restored employee-home adoption rejected because the native Grid, Property, BuildableItem, or EmployeeHome was unavailable."); return false; } try { if ((Object)(object)buildable.ParentProperty != (Object)(object)parentProperty || (Object)(object)((Component)employeeHome).GetComponent<BuildableItem>() != (Object)(object)buildable) { log?.Invoke("Fish Warehouse restored employee-home adoption rejected because the locker did not belong to the runtime Property."); return false; } _employeeHome = buildable; _employeeHomeComponent = employeeHome; return true; } catch (Exception ex) { log?.Invoke("Fish Warehouse restored employee-home adoption failed safely: " + ex.Message); return false; } } public bool TryPlaceEmployeeHome(Property parentProperty, FishWarehouseEmployeeHomeDefinition definition, Action<string>? log = null) { //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) if (_employeeHome != null) { return true; } if (!IsReady || parentProperty == null || (object)definition == null) { log?.Invoke("Fish Warehouse employee-home placement rejected because the native Grid or Property was unavailable."); return false; } BuildableItem val = null; try { if (!Guid.TryParse(definition.PlacementGuid, out var result) || result == Guid.Empty) { throw new InvalidOperationException("Employee-home placement GUID was invalid: " + definition.PlacementGuid); } GameObject obj = BuildManager.CreateGridItem((ItemManager.GetDefinition(definition.ItemId) ?? throw new InvalidOperationException("Vanilla buildable item was not found: " + definition.ItemId)).CreateInstance(1), _grid, new Vector2((float)definition.GridX, (float)definition.GridY), definition.Rotation, result.ToString()); BuildableItem val2 = ((obj != null) ? obj.GetComponent<BuildableItem>() : null); val = val2; EmployeeHome val3 = ((obj != null) ? obj.GetComponent<EmployeeHome>() : null); if (val2 == null || val3 == null) { throw new InvalidOperationException("Vanilla locker did not produce both BuildableItem and EmployeeHome components."); } if ((Object)(object)val2.ParentProperty != (Object)(object)parentProperty) { Property parentProperty2 = val2.ParentProperty; throw new InvalidOperationException("Vanilla locker ParentProperty was not Fish Warehouse (actual=" + (((parentProperty2 != null) ? parentProperty2.PropertyCode : null) ?? "null") + ")."); } if (!Guid.TryParse(((object)val2.GUID/*cast due to .constrained prefix*/).ToString(), out var result2) || result2 == Guid.Empty) { throw new InvalidOperationException($"Vanilla locker returned an invalid placement GUID: {val2.GUID}"); } _employeeHome = val2; _employeeHomeComponent = val3; log?.Invoke($"Fish Warehouse employee locker placed (itemId={definition.ItemId}, guid={result2}, grid=({definition.GridX},{definition.GridY}), ParentProperty={parentProperty.PropertyCode})."); return true; } catch (Exception ex) { try { if (val != null) { val.Destroy_Server(); } } catch { } log?.Invoke("Fish Warehouse employee locker placement failed safely: " + ex.Message); return false; } } public bool TryAttach(Property parentProperty, Transform anchor, string gridRootName, string gridGuid, Action<string>? log = null) { //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Expected O, but got Unknown //IL_0291: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_02af: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Unknown result type (might be due to invalid IL or missing references) if (IsReady) { return true; } if (parentProperty == null || anchor == null || string.IsNullOrWhiteSpace(gridRootName) || string.IsNullOrWhiteSpace(gridGuid)) { return false; } GameObject val = null; GameObject val2 = null; Grid val3 = null; try { if (!Guid.TryParse(gridGuid, out var _)) { throw new InvalidOperationException("Fish Warehouse build Grid GUID was invalid: " + gridGuid); } int tileCount; Grid val4 = FindLargestOwnedGrid(out tileCount); if (val4 == null || ((Component)val4).gameObject == null) { throw new InvalidOperationException("No owned native Grid template was available."); } if (GridAlreadyUsesGuid(gridGuid)) { throw new InvalidOperationException("Fish Warehouse build Grid GUID was already present: " + gridGuid); } val = new GameObject(gridRootName + "_Staging"); val.transform.SetParent(((Component)parentProperty).transform, false); val.SetActive(false); val2 = Object.Instantiate<GameObject>(((Component)val4).gameObject, val.transform, false); ((Object)val2).name = gridRootName; val2.SetActive(false); Grid component = val2.GetComponent<Grid>(); if (component == null) { throw new InvalidOperationException("Owned Grid template clone did not retain its Grid component."); } val3 = component; if (!TrySetMember(component, "_guid", gridGuid) || !TrySetMember(component, "_parentProperty", parentProperty)) { throw new InvalidOperationException("Could not prepare the Grid GUID and ParentProperty before Awake."); } Il2CppArrayBase<Tile> componentsInChildren = val2.GetComponentsInChildren<Tile>(true); if (componentsInChildren.Length == 0) { throw new InvalidOperationException("Owned Grid template clone contained no Tile components."); } PrepareTiles(component, Il2CppArrayBase<Tile>.op_Implicit(componentsInChildren)); PositionGrid(val2.transform, ((Component)parentProperty).transform, Il2CppArrayBase<Tile>.op_Implicit(componentsInChildren)); int rejectedTileCount; Tile[] array = BuildMeasuredTileSet(val2.transform, ((Component)parentProperty).transform, component, Il2CppArrayBase<Tile>.op_Implicit(componentsInChildren), Grid.TileSize, out rejectedTileCount); if (array.Length == 0) { throw new InvalidOperationException("The measured Fish Warehouse footprint retained no native Grid cells."); } FishWarehouseEmployeeHomeDefinition employeeHomeDefinition = FishWarehouseEmployeeHomeDefinition.Default; if (!array.Any((Tile tile) => tile.x == employeeHomeDefinition.GridX && tile.y == employeeHomeDefinition.GridY)) { throw new InvalidOperationException($"The measured Fish Warehouse footprint excluded the restored employee-home cell ({employeeHomeDefinition.GridX},{employeeHomeDefinition.GridY})."); } DisableNonTileColliders(val2); AddBuildHoverCollider(val2.transform, array, Grid.TileSize); val2.SetActive(true); RebuildNativeTopology(component, array); Tile val5 = ((IEnumerable<Tile>)array).FirstOrDefault((Func<Tile, bool>)((Tile tile) => tile != null && tile.x == 0 && tile.y == 0)); if (val5 == null || ((Component)val5).transform == null) { throw new InvalidOperationException("The rebuilt Fish Warehouse Grid lost its existing (0,0) reference cell."); } FishWarehouseNativeGridPlacementPatches.Register(component, ((Component)component).transform.InverseTransformPoint(((Component)val5).transform.position), Grid.TileSize); RegisterPropertyGrid(parentProperty, component); string text = ((object)component.GUID/*cast due to .constrained prefix*/).ToString(); if (!text.Equals(gridGuid, StringComparison.OrdinalIgnoreCase) || (Object)(object)component.ParentProperty != (Object)(object)parentProperty) { throw new InvalidOperationException($"Grid identity validation failed (actualGuid={text}, expectedGuid={gridGuid}, parent={((component.ParentProperty == null) ? "null" : component.ParentProperty.PropertyCode)})."); } _gridProxy = val2; _grid = component; GridGuid = text; TileCount = array.Length; val2 = null; Object.DestroyImmediate((Object)(object)val); val = null; Physics.SyncTransforms(); log?.Invoke($"Fish Warehouse native build Grid enabled (guid={GridGuid}, tiles={TileCount}, sourceTiles={tileCount}, rejectedTiles={rejectedTileCount}, ParentProperty={parentProperty.PropertyCode})."); return true; } catch (Exception ex) { log?.Invoke("Fish Warehouse native build Grid attachment failed safely: " + ex.Message); if (val3 != null) { try { FishWarehouseNativeGridPlacementPatches.Unregister(val3); parentProperty.Grids?.Remove(val3); } catch { } } if (val2 != null) { Object.DestroyImmediate((Object)(object)val2); } if (val != null) { Object.DestroyImmediate((Object)(object)val); } return false; } } public void Dispose() { if (_employeeHome != null) { try { _employeeHome.Destroy_Server(); } catch { } } _employeeHome = null; _employeeHomeComponent = null; if (_gridProxy != null) { try { FishWarehouseNativeGridPlacementPatches.Unregister(_grid); if (_grid != null && _grid.ParentProperty != null && _grid.ParentProperty.Grids != null) { _grid.ParentProperty.Grids.Remove(_grid); } } catch { } try { Object.DestroyImmediate((Object)(object)_gridProxy); } catch { } } _gridProxy = null; _grid = null; GridGuid = string.Empty; TileCount = 0; } private static Grid? FindLargestOwnedGrid(out int tileCount) { tileCount = 0; Grid result = null; Il2CppArrayBase<Grid> val = Object.FindObjectsOfType<Grid>(true); for (int i = 0; i < val.Length; i++) { Grid val2 = val[i]; Property val3 = ((val2 != null) ? val2.ParentProperty : null); if (val2 != null && ((Component)val2).gameObject != null && val3 != null && val3.IsOwned) { int length = ((Component)val2).GetComponentsInChildren<Tile>(true).Length; if (length > tileCount) { result = val2; tileCount = length; } } } return result; } private static bool GridAlreadyUsesGuid(string gridGuid) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) Il2CppArrayBase<Grid> val = Object.FindObjectsOfType<Grid>(true); for (int i = 0; i < val.Length; i++) { if (val[i] != null && ((object)val[i].GUID/*cast due to .constrained prefix*/).ToString().Equals(gridGuid, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } private static void PrepareTiles(Grid ownerGrid, Tile[] tiles) { foreach (Tile val in tiles) { if (val != null && ((Component)val).gameObject != null) { val.OwnerGrid = ownerGrid; ClearMember(val, "BuildableOccupants"); ClearMember(val, "OccupantTiles"); Renderer component = ((Component)val).GetComponent<Renderer>(); if (component != null) { component.enabled = false; } } } } private static void PositionGrid(Transform grid, Transform propertyRoot, Tile[] tiles) { //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_006a: 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_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: 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) //IL_0037: 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_003e: 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) Bounds val = default(Bounds); ((Bounds)(ref val))..ctor(Vector3.zero, Vector3.zero); bool flag = false; foreach (Tile val2 in tiles) { if (val2 != null && ((Component)val2).transform != null) { Vector3 val3 = grid.InverseTransformPoint(((Component)val2).transform.position); if (!flag) { ((Bounds)(ref val))..ctor(val3, Vector3.zero); flag = true; } else { ((Bounds)(ref val)).Encapsulate(val3); } } } grid.SetParent(propertyRoot, false); grid.localRotation = Quaternion.identity; grid.localPosition = new Vector3(0f - ((Bounds)(ref val)).center.x, 0.02f - ((Bounds)(ref val)).center.y, 0f - ((Bounds)(ref val)).center.z); } private static void DisableNonTileColliders(GameObject root) { Il2CppArrayBase<Collider> componentsInChildren = root.GetComponentsInChildren<Collider>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Collider val = componentsInChildren[i]; if (val != null && ((Component)val).GetComponent<Tile>() == null) { val.enabled = false; } } } private static void RebuildNativeTopology(Grid grid, Tile[] tiles) { grid.Tiles.Clear(); grid.CoordinateTilePairs.Clear(); foreach (Tile val in tiles) { if (val != null) { val.OwnerGrid = grid; grid.RegisterTile(val); } } if (!Invoke(GetMember(grid, "_coordinateToTile"), "Clear") || !Invoke(grid, "ProcessCoordinateDataPairs") || !Invoke(grid, "SetGridSize")) { throw new InvalidOperationException("Native Grid coordinate topology could not be rebuilt."); } if (grid.Tiles.Count != tiles.Length) { throw new InvalidOperationException($"Native Grid tile registration mismatch (actual={grid.Tiles.Count}, expected={tiles.Length})."); } } private static object? GetMember(object target, string name) { Type type = target.GetType(); PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if ((object)property != null) { return property.GetValue(target); } return type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(target); } private static bool TrySetMember(object target, string name, object value) { try { Type type = target.GetType(); PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if ((object)property != null && property.CanWrite) { property.SetValue(target, value); return true; } FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if ((object)field == null) { return false; } field.SetValue(target, value); return true; } catch { return false; } } private static bool ClearMember(object target, string name) { object member = GetMember(target, name); if (member != null) { return Invoke(member, "Clear"); } return false; } private static bool Invoke(object? target, string name) { if (target == null) { return false; } try { MethodInfo method = target.GetType().GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); if ((object)method == null) { return false; } method.Invoke(target, null); return true; } catch { return false; } } private static void AddBuildHoverCollider(Transform gridRoot, Tile[] tiles, float gridCellSize) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) if (gridRoot == null) { throw new ArgumentNullException("gridRoot"); } if (tiles == null || tiles.Length == 0) { throw new ArgumentException("The measured Grid had no retained cells for its hover collider.", "tiles"); } if (!float.IsFinite(gridCellSize) || gridCellSize <= 0f) { throw new ArgumentOutOfRangeException("gridCellSize"); } bool flag = false; Bounds val = default(Bounds); foreach (Tile val2 in tiles) { if (val2 != null && ((Component)val2).transform != null) { Vector3 val3 = gridRoot.InverseTransformPoint(((Component)val2).transform.position); if (!flag) { ((Bounds)(ref val))..ctor(val3, Vector3.zero); flag = true; } else { ((Bounds)(ref val)).Encapsulate(val3); } } } if (!flag) { throw new InvalidOperationException("The measured Grid had no valid retained tile transforms."); } GameObject val4 = new GameObject("OC_FishWarehouse_BuildGridCollider"); val4.transform.SetParent(gridRoot, false); val4.layer = 7; val4.transform.localPosition = ((Bounds)(ref val)).center; val4.transform.localRotation = Quaternion.identity; val4.transform.localScale = Vector3.one; BoxCollider obj = val4.AddComponent<BoxCollider>(); ((Collider)obj).isTrigger = false; obj.center = Vector3.zero; obj.size = new Vector3(((Bounds)(ref val)).size.x + gridCellSize, 0.2f, ((Bounds)(ref val)).size.z + gridCellSize); } private static void RegisterPropertyGrid(Property parentProperty, Grid grid) { List<Grid> grids = parentProperty.Grids; if (grids == null) { throw new InvalidOperationException("Fish Warehouse Property did not expose its native Grid list."); } if (!grids.Contains(grid)) { grids.Add(grid); } } private static Tile[] BuildMeasuredTileSet(Transform gridRoot, Transform propertyRoot, Grid ownerGrid, Tile[] tiles, float gridCellSize, out int rejectedTileCount) { //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_02fa: Unknown result type (might be due to invalid IL or missing references) if (gridRoot == null) { throw new ArgumentNullException("gridRoot"); } if (propertyRoot == null) { throw new ArgumentNullException("propertyRoot"); } if (ownerGrid == null) { throw new ArgumentNullException("ownerGrid"); } if (tiles == null || tiles.Length == 0) { throw new ArgumentException("The source Grid did not contain any Tile components.", "tiles"); } FishWarehouseBuildableFootprintDefinition fishWarehouseBuildableFootprintDefinition = FishWarehouseBuildableFootprintDefinition.CreateMeasured(gridCellSize); Tile val = ((IEnumerable<Tile>)tiles).FirstOrDefault((Func<Tile, bool>)((Tile tile) => tile != null && ((Component)tile).transform != null && tile.x == 0 && tile.y == 0)); if (val == null || ((Component)val).transform == null) { throw new InvalidOperationException("The source Grid did not contain the existing (0,0) reference cell."); } Vector3 val2 = propertyRoot.InverseTransformPoint(((Component)val).transform.position); IReadOnlyList<FishWarehouseGridCellCoordinate> allowedCellCoordinates = fishWarehouseBuildableFootprintDefinition.GetAllowedCellCoordinates(val.x, val.y, val2.x, val2.z); if (allowedCellCoordinates.Count == 0) { throw new InvalidOperationException("The measured Fish Warehouse footprint produced no native cell coordinates."); } Dictionary<(int, int), Tile> dictionary = new Dictionary<(int, int), Tile>(); Vector3 val4 = default(Vector3); foreach (Tile val3 in tiles) { if (val3 != null && ((Component)val3).transform != null && ((Component)val3).gameObject != null) { if (!dictionary.TryAdd((val3.x, val3.y), val3)) { throw new InvalidOperationException($"The source Grid contained duplicate native cell ({val3.x},{val3.y})."); } ((Vector3)(ref val4))..ctor(val2.x + (float)(val3.x - val.x) * gridCellSize, val2.y, val2.z + (float)(val3.y - val.y) * gridCellSize); if (Vector3.Distance(propertyRoot.InverseTransformPoint(((Component)val3).transform.position), val4) > 0.02f) { throw new InvalidOperationException($"The source Grid coordinate spacing was not representable from the (0,0) cell ({val3.x},{val3.y})."); } } } List<Tile> list = new List<Tile>(allowedCellCoordinates.Count); HashSet<(int, int)> hashSet = new HashSet<(int, int)>(); for (int num2 = 0; num2 < allowedCellCoordinates.Count; num2++) { FishWarehouseGridCellCoordinate coordinate = allowedCellCoordinates[num2]; if (!hashSet.Add((coordinate.X, coordinate.Y))) { throw new InvalidOperationException($"The measured footprint produced duplicate native cell ({coordinate.X},{coordinate.Y})."); } if (dictionary.TryGetValue((coordinate.X, coordinate.Y), out var value)) { list.Add(value); continue; } Tile item = CreateGeneratedTile(val, gridRoot, ownerGrid, coordinate, val2, gridCellSize); list.Add(item); } rejectedTileCount = 0; foreach (Tile val5 in tiles) { if (val5 != null && ((Component)val5).transform != null && ((Component)val5).gameObject != null && !hashSet.Contains((val5.x, val5.y))) { ((Component)val5).gameObject.SetActive(false); rejectedTileCount++; } } return list.ToArray(); } private static Tile CreateGeneratedTile(Tile reference, Transform gridRoot, Grid ownerGrid, FishWarehouseGridCellCoordinate coordinate, Vector3 referenceLocal, float gridCellSize) { //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) GameObject obj = Object.Instantiate<GameObject>(((Component)reference).gameObject, gridRoot, false); ((Object)obj).name = $"Grid [{coordinate.X},{coordinate.Y}]"; obj.SetActive(false); Tile component = obj.GetComponent<Tile>(); if (component == null || ((Component)component).transform == null) { throw new InvalidOperationException($"Generated native Grid cell ({coordinate.X},{coordinate.Y}) did not retain its Tile component."); } Vector3 localPosition = gridRoot.InverseTransformPoint(gridRoot.parent.TransformPoint(referenceLocal)); localPosition.x += (float)(coordinate.X - reference.x) * gridCellSize; localPosition.z += (float)(coordinate.Y - reference.y) * gridCellSize; ((Component)component).transform.localPosition = localPosition; component.InitializePropertyTile(coordinate.X, coordinate.Y, reference.AvailableOffset, ownerGrid); component.OwnerGrid = ownerGrid; ClearMember(component, "BuildableOccupants"); ClearMember(component, "OccupantTiles"); Renderer component2 = ((Component)component).GetComponent<Renderer>(); if (component2 != null) { component2.enabled = false; } obj.SetActive(true); return component; } } public enum FishWarehouseContinuousNavigationState { Inactive, Settling, Ready, Failed } public interface IFishWarehouseContinuousNavigationActions { bool TryPreflightGeometry(); bool TryActivateRoom(); bool TryOpenGarage(); string GetBuildableAndConfigurableSignature(); FishWarehouseNativeNavigationBuildResult TryBuildNavigation(); bool ValidateNavigation(); bool RemoveNavigation(); void RestoreGarage(); void DisposeRoom(); } public sealed class FishWarehouseContinuousNavigationCoordinator { public const float StableSettleSeconds = 0.5f; public const float SettleTimeoutSeconds = 5f; private readonly IFishWarehouseContinuousNavigationActions _actions; private string? _lastSignature; private float _startedAt; private float _signatureStableSince; private bool _rollbackRequired; private bool _rolledBack; private bool _hasPostStartTick; public FishWarehouseContinuousNavigationState State { get; private set; } public bool HasPendingCleanup { get { if (_rollbackRequired) { return !_rolledBack; } return false; } } public FishWarehouseContinuousNavigationCoordinator(IFishWarehouseContinuousNavigationActions actions) { _actions = actions ?? throw new ArgumentNullException("actions"); } public void Start(float now) { if (State == FishWarehouseContinuousNavigationState.Inactive) { ResetRun(now); if (!_actions.TryPreflightGeometry()) { State = FishWarehouseContinuousNavigationState.Failed; return; } if (!_actions.TryActivateRoom() || !_actions.TryOpenGarage()) { FailAfterMutation(); return; } _rollbackRequired = true; _lastSignature = _actions.GetBuildableAndConfigurableSignature(); _signatureStableSince = now; State = FishWarehouseContinuousNavigationState.Settling; } } public void Tick(float now) { if (State != FishWarehouseContinuousNavigationState.Settling) { return; } if (!_hasPostStartTick) { _hasPostStartTick = true; if (now - _startedAt > 5f) { _startedAt = now; _signatureStableSince = now; } } if (now - _startedAt >= 5f) { FailAfterMutation(); return; } string buildableAndConfigurableSignature = _actions.GetBuildableAndConfigurableSignature(); if (!string.Equals(buildableAndConfigurableSignature, _lastSignature, StringComparison.Ordinal)) { _lastSignature = buildableAndConfigurableSignature; _signatureStableSince = now; } else { if (now - _signatureStableSince < 0.5f) { return; } switch (_actions.TryBuildNavigation()) { case FishWarehouseNativeNavigationBuildResult.Pending: break; case FishWarehouseNativeNavigationBuildResult.Succeeded: if (_actions.ValidateNavigation()) { State = FishWarehouseContinuousNavigationState.Ready; break; } goto default; default: FailAfterMutation(); break; } } } public bool Stop() { if (!_rollbackRequired) { return true; } if (!Rollback()) { return false; } if (State != FishWarehouseContinuousNavigationState.Failed) { State = FishWarehouseContinuousNavigationState.Inactive; } return true; } private void FailAfterMutation() { _rollbackRequired = true; Rollback(); State = FishWarehouseContinuousNavigationState.Failed; } private void ResetRun(float now) { _lastSignature = null; _startedAt = now; _signatureStableSince = now; _rollbackRequired = false; _rolledBack = false; _hasPostStartTick = false; } private bool Rollback() { if (_rolledBack) { return true; } if (!_actions.RemoveNavigation()) { return false; } _actions.RestoreGarage(); _actions.DisposeRoom(); _rolledBack = true; return true; } } public enum FishWarehouseDeliveryActionKind { Dispatch, Status, StatusDisplay } public sealed record FishWarehousePendingDelivery<TDelivery>(string DeliveryId, TDelivery Delivery, FishWarehouseDeliveryActionKind ActionKind = FishWarehouseDeliveryActionKind.Dispatch) where TDelivery : class; public sealed class FishWarehouseDeliveryRestoreGate<TDelivery> where TDelivery : class { private readonly record struct DeliveryActionKey(string DeliveryId, FishWarehouseDeliveryActionKind ActionKind); private readonly string _targetPropertyCode; private readonly Dictionary<DeliveryActionKey, TDelivery> _pending = new Dictionary<DeliveryActionKey, TDelivery>(); private readonly Dictionary<DeliveryActionKey, long> _sequence = new Dictionary<DeliveryActionKey, long>(); private readonly HashSet<DeliveryActionKey> _attempted = new HashSet<DeliveryActionKey>(); private readonly HashSet<DeliveryActionKey> _replayed = new HashSet<DeliveryActionKey>(); private long _nextSequence; public int PendingCount => _pending.Count; public FishWarehouseDeliveryRestoreGate(string targetPropertyCode) { _targetPropertyCode = targetPropertyCode; } public bool ShouldSuppress(TDelivery delivery, string destinationCode, string deliveryId, FishWarehouseDeliveryActionKind actionKind, bool targetReady, bool isLoading) { if (!string.Equals(destinationCode, _targetPropertyCode, StringComparison.Ordinal)) { return false; } if (string.IsNullOrWhiteSpace(deliveryId)) { throw new ArgumentException("Fish Warehouse delivery identity is required.", "deliveryId"); } DeliveryActionKey deliveryActionKey = new DeliveryActionKey(deliveryId, actionKind); if (actionKind != FishWarehouseDeliveryActionKind.Status && _replayed.Contains(deliveryActionKey)) { return true; } if (!ShouldDefer(actionKind, targetReady, isLoading)) { return false; } if (_pending.TryAdd(deliveryActionKey, delivery)) { _sequence[deliveryActionKey] = _nextSequence++; } return true; } public bool ShouldSuppress(TDelivery delivery, string destinationCode, string deliveryId, bool targetReady, bool isRestoreContext) { if (!isRestoreContext) { return false; } return ShouldSuppress(delivery, destinationCode, deliveryId, FishWarehouseDeliveryActionKind.Dispatch, targetReady, isLoading: false); } public IReadOnlyList<FishWarehousePendingDelivery<TDelivery>> BeginReadyReplay(bool targetReady) { if (!targetReady) { return Array.Empty<FishWarehousePendingDelivery<TDelivery>>(); } return (from entry in _pending where _attempted.Add(entry.Key) orderby ActionOrder(entry.Key.ActionKind), _sequence[entry.Key] select new FishWarehousePendingDelivery<TDelivery>(entry.Key.DeliveryId, entry.Value, entry.Key.ActionKind)).ToArray(); } public void MarkReplayed(string deliveryId, FishWarehouseDeliveryActionKind actionKind) { DeliveryActionKey deliveryActionKey = new DeliveryActionKey(deliveryId, actionKind); _pending.Remove(deliveryActionKey); _sequence.Remove(deliveryActionKey); _attempted.Remove(deliveryActionKey); _replayed.Add(deliveryActionKey); } public void MarkReplayed(string deliveryId) { MarkReplayed(deliveryId, FishWarehouseDeliveryActionKind.Dispatch); } public bool HasPending(string deliveryId) { return _pending.Keys.Any((DeliveryActionKey key) => string.Equals(key.DeliveryId, deliveryId, StringComparison.Ordinal)); } public bool HasPending(string deliveryId, FishWarehouseDeliveryActionKind actionKind) { return _pending.ContainsKey(new DeliveryActionKey(deliveryId, actionKind)); } public bool IsReplayed(string deliveryId, FishWarehouseDeliveryActionKind actionKind) { return _replayed.Contains(new DeliveryActionKey(deliveryId, actionKind)); } public void Reset() { _pending.Clear(); _sequence.Clear(); _attempted.Clear(); _replayed.Clear(); _nextSequence = 0L; } private static bool ShouldDefer(FishWarehouseDeliveryActionKind actionKind, bool targetReady, bool isLoading) { return actionKind switch { FishWarehouseDeliveryActionKind.Dispatch => !targetReady, FishWarehouseDeliveryActionKind.Status => isLoading && !targetReady, FishWarehouseDeliveryActionKind.StatusDisplay => isLoading && !targetReady, _ => throw new ArgumentOutOfRangeException("actionKind", actionKind, null), }; } private static int ActionOrder(FishWarehouseDeliveryActionKind actionKind) { return actionKind switch { FishWarehouseDeliveryActionKind.Dispatch => 0, FishWarehouseDeliveryActionKind.Status => 1, FishWarehouseDeliveryActionKind.StatusDisplay => 2, _ => throw new ArgumentOutOfRangeException("actionKind", actionKind, null), }; } } public sealed record FishWarehouseDeliveryRestoreFlushResult(int PendingCount, string? Failure) { public string? FailureReason => Failure; } internal static class FishWarehouseDeliveryRestorePatch { private abstract record PendingDeliveryPayload; private sealed record PendingDispatch(DeliveryManager Manager, DeliveryInstance Delivery) : PendingDeliveryPayload(); private sealed record PendingStatus(DeliveryInstance Delivery, EDeliveryStatus Status) : PendingDeliveryPayload() { [CompilerGenerated] public void Deconstruct(out DeliveryInstance Delivery, out EDeliveryStatus Status) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected I4, but got Unknown Delivery = this.Delivery; Status = (EDeliveryStatus)(int)this.Status; } } private sealed record PendingStatusDisplay(DeliveryApp App, DeliveryInstance Delivery) : PendingDeliveryPayload(); private static readonly FishWarehouseDeliveryRestoreGate<PendingDeliveryPayload> Gate = new FishWarehouseDeliveryRestoreGate<PendingDeliveryPayload>("oc_fishwarehouse"); private static Func<bool> _isReady = () => false; private static Action<string> _log = delegate { }; private static bool _replaying; private static string? _statusReplayDeliveryId; private static bool _nestedStatusDisplayObserved; private static bool _replayFailureReported; public static FishWarehouseDeliveryRestoreFlushResult LastFlushResult { get; private set; } = new FishWarehouseDeliveryRestoreFlushResult(0, null); public static void Apply(Harmony harmony, Func<bool> isReady, Action<string>? log = null) { _isReady = isReady; _log = log ?? ((Action<string>)delegate { }); MethodInfo methodInfo = AccessTools.Method(typeof(DeliveryManager), "SendDelivery", new Type[1] { typeof(DeliveryInstance) }, (Type[])null) ?? throw new MissingMethodException(typeof(DeliveryManager).FullName, "SendDelivery"); MethodInfo methodInfo2 = AccessTools.Method(typeof(DeliveryInstance), "SetStatus", new Type[1] { typeof(EDeliveryStatus) }, (Type[])null) ?? throw new MissingMethodException(typeof(DeliveryInstance).FullName, "SetStatus"); MethodInfo methodInfo3 = AccessTools.Method(typeof(DeliveryApp), "CreateDeliveryStatusDisplay", new Type[1] { typeof(DeliveryInstance) }, (Type[])null) ?? throw new MissingMethodException(typeof(DeliveryApp).FullName, "CreateDeliveryStatusDisplay"); harmony.Patch((MethodBase)methodInfo, HarmonyMethod("DispatchPrefix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo2, HarmonyMethod("StatusPrefix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo3, HarmonyMethod("StatusDisplayPrefix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } private static HarmonyMethod HarmonyMethod(string methodName) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown return new HarmonyMethod(AccessTools.Method(typeof(FishWarehouseDeliveryRestorePatch), methodName, (Type[])null, (Type[])null) ?? throw new MissingMethodException(typeof(FishWarehouseDeliveryRestorePatch).FullName, methodName)); } private static bool DispatchPrefix(DeliveryManager __instance, DeliveryInstance __0) { if (_replaying || __0 == null) { return true; } return ApplyGate(new PendingDispatch(__instance, __0), __0, FishWarehouseDeliveryActionKind.Dispatch, IsLoading()); } private static bool StatusPrefix(DeliveryInstance __instance, EDeliveryStatus __0) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) if (_replaying || __instance == null) { return true; } return ApplyGate(new PendingStatus(__instance, __0), __instance, FishWarehouseDeliveryActionKind.Status, IsLoading()); } private static bool StatusDisplayPrefix(DeliveryApp __instance, DeliveryInstance __0) { if (__0 == null) { return true; } if (_replaying) { if (string.Equals(_statusReplayDeliveryId, __0.DeliveryID, StringComparison.Ordinal) && Gate.HasPending(__0.DeliveryID ?? string.Empty, FishWarehouseDeliveryActionKind.StatusDisplay)) { _nestedStatusDisplayObserved = true; } return true; } return ApplyGate(new PendingStatusDisplay(__instance, __0), __0, FishWarehouseDeliveryActionKind.StatusDisplay, IsLoading()); } private static bool ApplyGate(PendingDeliveryPayload payload, DeliveryInstance delivery, FishWarehouseDeliveryActionKind actionKind, bool isLoading) { try { string text = delivery.DeliveryID ?? string.Empty; bool num = Gate.ShouldSuppress(payload, delivery.DestinationCode ?? string.Empty, text, actionKind, _isReady(), isLoading); if (num) { _log($"Fish Warehouse delivery action deferred (delivery={text}, action={actionKind})."); } return !num; } catch (Exception ex) { _log("Fish Warehouse saved-delivery gate failed safely; vanilla action will continue: " + ex.Message); return true; } } internal static void ReplayUntilFailure<TDelivery>(IEnumerable<FishWarehousePendingDelivery<TDelivery>> pendingActions, Action<FishWarehousePendingDelivery<TDelivery>> replay, Action<FishWarehousePendingDelivery<TDelivery>, Exception> onFailure) where TDelivery : class { foreach (FishWarehousePendingDelivery<TDelivery> pendingAction in pendingActions) { try { replay(pendingAction); } catch (Exception arg) { onFailure(pendingAction, arg); break; } } } public static FishWarehouseDeliveryRestoreFlushResult FlushIfReady() { IReadOnlyList<FishWarehousePendingDelivery<PendingDeliveryPayload>> ready = Gate.BeginReadyReplay(_isReady()); string failure = null; ReplayUntilFailure(ready.Where((FishWarehousePendingDelivery<PendingDeliveryPayload> pending) => !Gate.IsReplayed(pending.DeliveryId, pending.ActionKind)), delegate(FishWarehousePendingDelivery<PendingDeliveryPayload> pending) { try { _replaying = true; Replay(pending, ready); } finally { _statusReplayDeliveryId = null; _nestedStatusDisplayObserved = false; _replaying = false; } }, delegate(FishWarehousePendingDelivery<PendingDeliveryPayload> pending, Exception ex) { if (failure == null) { failure = $"delivery={pending.DeliveryId}, action={pending.ActionKind}: {ex.Message}"; } if (!_replayFailureReported) { _replayFailureReported = true; _log("Fish Warehouse saved delivery action remains pending after replay failure (" + failure + ")."); } }); return StoreFlushResult(new FishWarehouseDeliveryRestoreFlushResult(Gate.PendingCount, failure)); } private static void Replay(FishWarehousePendingDelivery<PendingDeliveryPayload> pending, IReadOnlyList<FishWarehousePendingDelivery<PendingDeliveryPayload>> ready) { //IL_00c5: Unknown result type (might be due to invalid IL or missing references) switch (pending.ActionKind) { case FishWarehouseDeliveryActionKind.Dispatch: { PendingDispatch pendingDispatch = (PendingDispatch)pending.Delivery; pendingDispatch.Manager.SendDelivery(pendingDispatch.Delivery); Gate.MarkReplayed(pending.DeliveryId, pending.ActionKind); _log("Fish Warehouse delivery action replayed (delivery=" + pending.DeliveryId + ", action=Dispatch)."); break; } case FishWarehouseDeliveryActionKind.Status: { PendingStatus pendingStatus = (PendingStatus)pending.Delivery; _statusReplayDeliveryId = pending.DeliveryId; _nestedStatusDisplayObserved = false; pendingStatus.Delivery.SetStatus(pendingStatus.Status); Gate.MarkReplayed(pending.DeliveryId, pending.ActionKind); FishWarehousePendingDelivery<PendingDeliveryPayload> fishWarehousePendingDelivery = ready.FirstOrDefault((FishWarehousePendingDelivery<PendingDeliveryPayload> candidate) => candidate.DeliveryId == pending.DeliveryId && candidate.ActionKind == FishWarehouseDeliveryActionKind.StatusDisplay); if ((object)fishWarehousePendingDelivery != null && Gate.HasPending(pending.DeliveryId, FishWarehouseDeliveryActionKind.StatusDisplay)) { if (_nestedStatusDisplayObserved) { Gate.MarkReplayed(pending.DeliveryId, FishWarehouseDeliveryActionKind.StatusDisplay); _log("Fish Warehouse delivery action replayed (delivery=" + pending.DeliveryId + ", action=StatusDisplay, mode=nested)."); } else { ReplayStatusDisplay(fishWarehousePendingDelivery); } } _log("Fish Warehouse delivery action replayed (delivery=" + pending.DeliveryId + ", action=Status)."); break; } case FishWarehouseDeliveryActionKind.StatusDisplay: ReplayStatusDisplay(pending); break; default: throw new ArgumentOutOfRangeException("ActionKind", pending.ActionKind, null); } } private static void ReplayStatusDisplay(FishWarehousePendingDelivery<PendingDeliveryPayload> pending) { PendingStatusDisplay pendingStatusDisplay = (PendingStatusDisplay)pending.Delivery; pendingStatusDisplay.App.CreateDeliveryStatusDisplay(pendingStatusDisplay.Delivery); Gate.MarkReplayed(pending.DeliveryId, pending.ActionKind); _log("Fish Warehouse delivery action replayed (delivery=" + pending.DeliveryId + ", action=StatusDisplay, mode=explicit)."); } internal static FishWarehouseDeliveryRestoreFlushResult StoreFlushResult(FishWarehouseDeliveryRestoreFlushResult result) { if (result.Failure == null && LastFlushResult.Failure != null) { return LastFlushResult; } LastFlushResult = result; return result; } public static void Reset() { Gate.Reset(); _isReady = () => false; _log = delegate { }; _replaying = false; _statusReplayDeliveryId = null; _nestedStatusDisplayObserved = false; _replayFailureReported = false; LastFlushResult = new FishWarehouseDeliveryRestoreFlushResult(0, null); } private static bool IsLoading() { LoadManager instance = Singleton<LoadManager>.Instance; if (instance == null) { return false; } return instance.IsLoading; } } public sealed class FishWarehouseDockDeliveryBridgeHost { private readonly FishWarehouseDockDeliveryPopulationLatch _populationLatch = new FishWarehouseDockDeliveryPopulationLatch(); public void Tick(Property property, bool hostAuthority, Action<string>? log = null) { //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Invalid comparison between Unknown and I4 if (!hostAuthority || property == null || (Object)(object)property == (Object)null) { return; } try { DeliveryInstance val = ResolveActiveDelivery(property); if (val == null) { _populationLatch.ObserveActiveDelivery(null); return; } string text = SafeDeliveryId(val); _populationLatch.ObserveActiveDelivery(text); if (string.IsNullOrWhiteSpace(text) || _populationLatch.HasPopulated(text)) { return; } LoadingDock val2 = SafeDock(val); if (val2 == null || HasOccupant(val2)) { return; } TryRefresh(val2); if (HasOccupant(val2)) { _populationLatch.MarkPopulated(text); log?.Invoke("[oc7-bridge] dock populated via native RefreshOccupant."); } else { if ((int)SafeStatus(val) != 2) { return; } LandVehicle val3 = SafeVan(val); if (val3 != null && !((Object)(object)val3 == (Object)null)) { val2.SetOccupant(val3); if (HasOccupant(val2)) { _populationLatch.MarkPopulated(text); log?.Invoke("[oc7-bridge] dock populated via direct SetOccupant (arrived delivery van)."); } } } } catch { } } private static DeliveryInstance? ResolveActiveDelivery(Property property) { try { if (!NetworkSingleton<DeliveryManager>.InstanceExists) { return null; } DeliveryInstance delivery = NetworkSingleton<DeliveryManager>.Instance.GetDelivery(property); return (delivery != null && delivery != null) ? delivery : null; } catch { return null; } } private static LoadingDock? SafeDock(DeliveryInstance delivery) { try { LoadingDock loadingDock = delivery.LoadingDock; return (loadingDock != null && (Object)(object)loadingDock != (Object)null) ? loadingDock : null; } catch { return null; } } private static string SafeDeliveryId(DeliveryInstance delivery) { try { return delivery.DeliveryID ?? string.Empty; } catch { return string.Empty; } } private static LandVehicle? SafeVan(DeliveryInstance delivery) { try { DeliveryVehicle activeVehicle = delivery.ActiveVehicle; if (activeVehicle == null || (Object)(object)activeVehicle == (Object)null) { return null; } LandVehicle vehicle = activeVehicle.Vehicle; return (vehicle != null && (Object)(object)vehicle != (Object)null) ? vehicle : null; } catch { return null; } } private static EDeliveryStatus SafeStatus(DeliveryInstance delivery) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) try { return delivery.Status; } catch { return (EDeliveryStatus)0; } } private static bool HasOccupant(LoadingDock dock) { try { LandVehicle dynamicOccupant = dock.DynamicOccupant; return dynamicOccupant != null && (Object)(object)dynamicOccupant != (Object)null; } catch { return true; } } private static void TryRefresh(LoadingDock dock) { try { dock.RefreshOccupant(); } catch { } } } public sealed class FishWarehouseDockDeliveryPopulationLatch { private string? _populatedDeliveryId; public bool HasPopulated(string deliveryId) { if (!string.IsNullOrWhiteSpace(deliveryId)) { return string.Equals(_populatedDeliveryId, deliveryId, StringComparison.Ordinal); } return false; } public void MarkPopulated(string deliveryId) { if (!string.IsNullOrWhiteSpace(deliveryId)) { _populatedDeliveryId = deliveryId; } } public void ObserveActiveDelivery(string? deliveryId) { if (!string.Equals(_populatedDeliveryId, deliveryId, StringComparison.Ordinal)) { _populatedDeliveryId = null; } } public void Reset() { _populatedDeliveryId = null; } } internal static class FishWarehouseDockOccupantRefreshPatch { public static void Apply(Harmony harmony) { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(LoadingDock), "SetOccupant", new Type[1] { typeof(LandVehicle) }, (Type[])null); if ((object)methodInfo == null) { throw new MissingMethodException(typeof(LoadingDock).FullName, "SetOccupant"); } MethodInfo methodInfo2 = AccessTools.Method(typeof(FishWarehouseDockOccupantRefreshPatch), "Prefix", (Type[])null, (Type[])null); if ((object)methodInfo2 == null) { throw new MissingMethodException(typeof(FishWarehouseDockOccupantRefreshPatch).FullName, "Prefix"); } harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } private static bool Prefix(LoadingDock __instance, LandVehicle? __0) { try { if (__0 != null && (Object)(object)__0 != (Object)null) { return true; } return !FishWarehouseDockOccupantRefreshPolicy.ShouldSuppressOccupantClear(IsFishWarehouseDock(__instance), HasDynamicOccupant(__instance), HasOutputItems(__instance)); } catch { return true; } } private static bool IsFishWarehouseDock(LoadingDock dock) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) string guid = ((object)dock.GUID/*cast due to .constrained prefix*/).ToString(); return FishWarehouseLoadingDockDefinition.Docks.Any((FishWarehouseDockDefinition definition) => string.Equals(definition.DockGuid, guid, StringComparison.OrdinalIgnoreCase)); } private static bool HasDynamicOccupant(LoadingDock dock) { LandVehicle dynamicOccupant = dock.DynamicOccupant; if (dynamicOccupant != null) { return (Object)(object)dynamicOccupant != (Object)null; } return false; } private static bool HasOutputItems(LoadingDock dock) { Enumerator<ItemSlot> enumerator = dock.OutputSlots.GetEnumerator(); while (enumerator.MoveNext()) { ItemSlot current = enumerator.Current; if (current.ItemInstance != null && current.ItemInstance != null && current.Quantity > 0) { return true; } } return false; } } internal static class FishWarehouseDockOccupantRefreshPolicy { public static bool ShouldSuppressOccupantClear(bool isFishWarehouseDock, bool hasDynamicOccupant, bool hasOutputItems) { return isFishWarehouseDock && hasDynamicOccupant && hasOutputItems; } } public sealed class FishWarehouseEmployeeInfrastructureHost { private GameObject? _root; public bool IsReady => _root != null; public bool TryAttach(Property property, Action<string>? log = null) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown if (IsReady) { return true; } if (property == null) { return false; } GameObject val = null; try { if (!FishWarehouseEmployeeInfrastructureDefinition.HasValidLayout()) { throw new InvalidOperationException("Fish Warehouse employee point definition failed its bounds/capacity contract."); } val = new GameObject("OC_FishWarehouse_EmployeeInfrastructure"); val.transform.SetParent(((Component)property).transform, false); Transform val2 = CreatePoint(val.transform, FishWarehouseEmployeeInfrastructureDefinition.NpcSpawnPoint); Il2CppReferenceArray<Transform> val3 = new Il2CppReferenceArray<Transform>(10L); for (int i = 0; i < FishWarehouseEmployeeInfrastructureDefinition.IdlePoints.Count; i++) { ((Il2CppArrayBase<Transform>)(object)val3)[i] = CreatePoint(val.transform, FishWarehouseEmployeeInfrastructureDefinition.IdlePoints[i]); } property.EmployeeCapacity = 10; property.NPCSpawnPoint = val2; property.EmployeeIdlePoints = val3; if (property.EmployeeCapacity != 10 || (Object)(object)property.NPCSpawnPoint != (Object)(object)val2 || property.EmployeeIdlePoints == null || ((Il2CppArrayBase<Transform>)(object)property.EmployeeIdlePoints).Length != 10) { throw new InvalidOperationException("Fish Warehouse Property did not retain employee infrastructure references."); } _root = val; val = null; log?.Invoke($"Fish Warehouse employee infrastructure enabled (capacity={property.EmployeeCapacity}, idlePoints={((Il2CppArrayBase<Transform>)(object)property.EmployeeIdlePoints).Length}, npcSpawn={((Object)property.NPCSpawnPoint).name})."); return true; } catch (Exception ex) { if (val != null) { Object.DestroyImmediate((Object)(object)val); } log?.Invoke("Fish Warehouse employee infrastructure failed safely: " + ex.Message); return false; } } public void Dispose() { if (_root != null) { Object.DestroyImmediate((Object)(object)_root); } _root = null; } private static Transform CreatePoint(Transform parent, FishWarehouseEmployeePointDefinition definition) { //IL_0006: 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_0036: Unknown result type (might be due to invalid IL or missing references) Transform transform = new GameObject(definition.Name).transform; transform.SetParent(parent, false); transform.localPosition = new Vector3(definition.X, definition.Y, definition.Z); transform.localRotation = Quaternion.identity; return transform; } } public enum FishWarehouseEmployeeReplayState { Pending, Succeeded, Failed } public sealed record FishWarehouseEmployeeReplayResult(FishWarehouseEmployeeReplayState State, int CapturedEmployeeCount, int SupportedCapturedEmployeeCount, int ReplayedEmployeeCount, IReadOnlyList<FishWarehouseUnsupportedEmployeeRecord> UnsupportedEmployees, bool CanAdvanceEmployeesReplayed, string? PrimaryFailureReason, string? FailureReason, IReadOnlyList<string>? InventoryRestoredEmployeeGuids = null); public sealed class FishWarehouseEmployeeReplayHost { private enum ReplayStage { NotStarted, PrimaryVerification, FallbackVerification } private sealed class Entry { public FishWarehouseEmployeeReplayDescriptor Descriptor { get; } public FishWarehouseEmployeeReplayExpectedState? Expected { get; set; } public ReplayStage Stage { get; set; } public bool GuidWasRegistered { get; set; } public bool FallbackAttempted { get; set; } public bool IsReplayed { get; set; } public bool IsUnsupported { get; set; } public float PrimaryStartedAt { get; set; } public float FallbackStartedAt { get; set; } public string? PrimaryFailureReason { get; set; } public string? LastVerificationReason { get; set; } public Entry(FishWarehouseEmployeeReplayDescriptor descriptor) { Descriptor = descriptor; } } public const float ConfigurationVerificationTimeoutSeconds = 3f; private readonly IFishWarehouseNativeEmployeeReplayAdapter _adapter; private readonly IReadOnlyList<Entry> _entries; private readonly Dictionary<string, FishWarehouseUnsupportedEmployeeRecord> _unsupportedByGuid; private readonly Func<float> _realtimeSinceStartup; private readonly Action<string> _log; public FishWarehouseEmployeeReplayResult Result { get; private set; } public FishWarehouseEmployeeReplayHost(IFishWarehouseNativeEmployeeReplayAdapter adapter, IReadOnlyList<FishWarehouseEmployeeReplayDescriptor> capturedEmployees, IReadOnlyList<FishWarehouseUnsupportedEmployeeRecord> existingUnsupportedEmployees, Func<float>? realtimeSinceStartup = null, Action<string>? log = null) { _adapter = adapter ?? throw new ArgumentNullException("adapter"); _entries = (capturedEmployees ?? throw new ArgumentNullException("capturedEmployees")).Select((FishWarehouseEmployeeReplayDescriptor descriptor) => new Entry(descriptor)).ToArray(); _unsupportedByGuid = new Dictionary<string, FishWarehouseUns