using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Pipes; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using System.Threading; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Microsoft.CodeAnalysis; using Microsoft.Win32.SafeHandles; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using Spherewright.Bridge.Core.Abstractions; using Spherewright.Bridge.Core.Authentication; using Spherewright.Bridge.Core.Framing; using Spherewright.Bridge.Core.Journals; using Spherewright.Bridge.Core.Logistics; using Spherewright.Bridge.Core.Progression; using Spherewright.Bridge.Core.Routing; using Spherewright.Bridge.Core.Safety; using Spherewright.Bridge.Core.Snapshots; using Spherewright.Contracts.Actions; using Spherewright.Contracts.Celestial; using Spherewright.Contracts.Errors; using Spherewright.Contracts.Factory; using Spherewright.Contracts.Journals; using Spherewright.Contracts.Logistics; using Spherewright.Contracts.Players; using Spherewright.Contracts.Power; using Spherewright.Contracts.Progression; using Spherewright.Contracts.Protocol; using Spherewright.Contracts.Resources; using Spherewright.Contracts.Sessions; using Spherewright.Contracts.Testing; using Spherewright.Plugin.Bootstrap; using Spherewright.Plugin.Game; using Spherewright.Plugin.Hosting; using Spherewright.Plugin.RuntimeDescriptor; using Spherewright.Plugin.Security; using Spherewright.Plugin.Transport; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("Spherewright.Plugin")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.3.3.0")] [assembly: AssemblyInformationalVersion("0.3.3+f0cd11105957ae63cb4b45fd5756b0a42508857f")] [assembly: AssemblyProduct("Spherewright.Plugin")] [assembly: AssemblyTitle("Spherewright.Plugin")] [assembly: AssemblyVersion("0.3.3.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 Spherewright.Plugin { [BepInPlugin("dev.spherewright.bridge", "Spherewright", "0.3.3")] [BepInProcess("DSPGAME.exe")] public sealed class SpherewrightPlugin : BaseUnityPlugin { public const string PluginGuid = "dev.spherewright.bridge"; public const string PluginName = "Spherewright"; public const string PluginVersion = "0.3.3"; private SpherewrightBridgeHost? _host; private void Awake() { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Spherewright plugin loaded"); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Spherewright plugin version: 0.3.3"); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Spherewright protocol version: {1}"); try { SpherewrightConfiguration spherewrightConfiguration = SpherewrightConfiguration.Load(((BaseUnityPlugin)this).Config); _host = SpherewrightBridgeHost.Create(spherewrightConfiguration, ((BaseUnityPlugin)this).Logger, "0.3.3"); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Spherewright writes configured: " + (spherewrightConfiguration.AllowWrites ? "enabled" : "disabled"))); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Spherewright user-save import configured: " + (spherewrightConfiguration.AllowUserSaveImport ? "enabled" : "disabled"))); if (!spherewrightConfiguration.Enabled) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Spherewright bridge is disabled by configuration"); _host.Dispose(); _host = null; } else { _host.Start(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Spherewright bridge started"); } } catch (Exception ex) { _host?.Dispose(); _host = null; ((BaseUnityPlugin)this).Logger.LogError((object)("Spherewright bridge startup failed: " + FormatExceptionChain(ex))); ((BaseUnityPlugin)this).Logger.LogError((object)ex.ToString()); } } private void Update() { _host?.PumpMainThread(); } private void OnDestroy() { _host?.Dispose(); _host = null; } private static string FormatExceptionChain(Exception exception) { List list = new List(); for (Exception ex = exception; ex != null; ex = ex.InnerException) { list.Add(ex.GetType().Name + ": " + ex.Message); } return string.Join(" -> ", list); } } } namespace Spherewright.Plugin.Transport { internal sealed class NamedPipeBridgeServer : IDisposable { private readonly object _gate = new object(); private readonly string _pipeName; private readonly string _bridgeInstanceId; private readonly string _pluginVersion; private readonly FrameCodec _frameCodec; private readonly TimeSpan _readRequestTimeout; private readonly HandshakeAuthenticator _authenticator; private readonly BridgeStatusSnapshotProvider _statusProvider; private readonly BoundedMainThreadDispatcher _dispatcher; private readonly GameStateReader _gameStateReader; private readonly GameplayJournalManager _gameplayJournalManager; private readonly TestWorldCoordinator _testWorldCoordinator; private readonly UserSaveImportCoordinator _userSaveImportCoordinator; private readonly OwnedWorldResumeCoordinator _ownedWorldResumeCoordinator; private readonly FlightCheckpointReloadCoordinator _flightCheckpointReloadCoordinator; private readonly NormalGameActionCoordinator _normalActionCoordinator; private readonly ManualLogSource _logger; private readonly CancellationTokenSource _shutdown = new CancellationTokenSource(); private Task? _serverTask; private NamedPipeServerStream? _activePipe; private int _lastAuthWarningTick; public NamedPipeBridgeServer(BridgeIdentity identity, string pluginVersion, int maxFrameBytes, int readRequestTimeoutSeconds, BridgeStatusSnapshotProvider statusProvider, BoundedMainThreadDispatcher dispatcher, GameStateReader gameStateReader, GameplayJournalManager gameplayJournalManager, TestWorldCoordinator testWorldCoordinator, UserSaveImportCoordinator userSaveImportCoordinator, OwnedWorldResumeCoordinator ownedWorldResumeCoordinator, FlightCheckpointReloadCoordinator flightCheckpointReloadCoordinator, NormalGameActionCoordinator normalActionCoordinator, ManualLogSource logger) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected O, but got Unknown _pipeName = identity.PipeName; _bridgeInstanceId = identity.BridgeInstanceId; _pluginVersion = pluginVersion; _frameCodec = new FrameCodec(maxFrameBytes); _readRequestTimeout = TimeSpan.FromSeconds(readRequestTimeoutSeconds); _authenticator = new HandshakeAuthenticator(identity.BridgeInstanceId, identity.AuthToken); _statusProvider = statusProvider; _dispatcher = dispatcher; _gameStateReader = gameStateReader; _gameplayJournalManager = gameplayJournalManager; _testWorldCoordinator = testWorldCoordinator; _userSaveImportCoordinator = userSaveImportCoordinator; _ownedWorldResumeCoordinator = ownedWorldResumeCoordinator; _flightCheckpointReloadCoordinator = flightCheckpointReloadCoordinator; _normalActionCoordinator = normalActionCoordinator; _logger = logger; } public void Start() { lock (_gate) { if (_serverTask != null) { throw new InvalidOperationException("The Named Pipe bridge is already running."); } _serverTask = Task.Run(() => RunAsync(_shutdown.Token)); } } public void Dispose() { Task serverTask; lock (_gate) { _shutdown.Cancel(); _activePipe?.Dispose(); serverTask = _serverTask; _serverTask = null; } if (serverTask != null) { try { serverTask.Wait(TimeSpan.FromSeconds(2.0)); } catch (AggregateException ex) when (ex.InnerExceptions.All((Exception inner) => inner is OperationCanceledException || inner is ObjectDisposedException)) { } } _shutdown.Dispose(); } private async Task RunAsync(CancellationToken cancellationToken) { while (!cancellationToken.IsCancellationRequested) { using NamedPipeServerStream pipe = CreateServerPipe(); using (cancellationToken.Register(pipe.Dispose)) { lock (_gate) { _activePipe = pipe; } try { await pipe.WaitForConnectionAsync().ConfigureAwait(continueOnCapturedContext: false); await HandleConnectionAsync(pipe, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); } catch (Exception ex) when (cancellationToken.IsCancellationRequested && (ex is OperationCanceledException || ex is ObjectDisposedException || ex is IOException)) { break; } catch (FrameProtocolException ex2) { FrameProtocolException ex3 = ex2; _logger.LogWarning((object)("Spherewright rejected an invalid bridge frame: " + ((Exception)(object)ex3).Message)); } catch (JsonException ex4) { JsonException ex5 = ex4; _logger.LogWarning((object)("Spherewright rejected malformed bridge JSON: " + ((Exception)(object)ex5).Message)); } catch (IOException ex6) { _logger.LogDebug((object)("Spherewright bridge connection ended: " + ex6.Message)); } catch (Exception ex7) { _logger.LogError((object)("Spherewright bridge connection failed: " + ex7.GetType().Name + ": " + ex7.Message)); } finally { lock (_gate) { if (_activePipe == pipe) { _activePipe = null; } } } } } } private async Task HandleConnectionAsync(NamedPipeServerStream pipe, CancellationToken cancellationToken) { byte[] array = await _frameCodec.ReadFrameAsync((Stream)pipe, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); if (array == null) { return; } string json = FrameCodec.DecodeUtf8(array); BridgeError obj = ProtocolValidator.ValidateHeader(PluginJson.Deserialize(json), "handshake"); BridgeRequestEnvelope val = PluginJson.Deserialize>(json); if (obj == null) { obj = _authenticator.Authenticate(val?.Payload); } if (obj != null) { LogAuthenticationFailureWithRateLimit(); return; } BridgeResponseEnvelope envelope = new BridgeResponseEnvelope { RequestId = val.RequestId, Success = true, Result = new HandshakeResponse { Accepted = true, BridgeInstanceId = _bridgeInstanceId, PluginVersion = _pluginVersion, ProtocolVersion = 1 } }; await WriteEnvelopeAsync(pipe, envelope, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); while (!cancellationToken.IsCancellationRequested && pipe.IsConnected) { byte[] array2 = await _frameCodec.ReadFrameAsync((Stream)pipe, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); if (array2 == null) { break; } string text = FrameCodec.DecodeUtf8(array2); BridgeEnvelopeHeader header = PluginJson.Deserialize(text); BridgeError val2 = ProtocolValidator.ValidateHeader(header, "request"); if (val2 != null) { NamedPipeBridgeServer namedPipeBridgeServer = this; BridgeEnvelopeHeader obj2 = header; await namedPipeBridgeServer.WriteErrorAsync(pipe, (obj2 != null) ? obj2.RequestId : null, val2, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); continue; } switch (header.Method) { case "get_bridge_status": await WriteResultAsync(pipe, header.RequestId, null, _statusProvider.Capture(), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; case "get_session_state": await DispatchAndWriteAsync(pipe, header.RequestId, null, _gameStateReader.GetSessionStateOnMainThread, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; case "get_player_state": { BridgeRequestEnvelope request27 = PluginJson.Deserialize>(text); if (request27?.Payload == null) { await WriteInvalidPayloadAsync(pipe, header.RequestId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } await DispatchAndWriteAsync(pipe, header.RequestId, header.SessionId, () => _gameStateReader.GetPlayerStateOnMainThread(header.SessionId, request27.Payload), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } case "get_progression_state": { BridgeRequestEnvelope request17 = PluginJson.Deserialize>(text); if (request17?.Payload == null) { await WriteInvalidPayloadAsync(pipe, header.RequestId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } await DispatchAndWriteAsync(pipe, header.RequestId, header.SessionId, () => _gameStateReader.GetProgressionStateOnMainThread(header.SessionId, request17.Payload), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } case "get_gameplay_journal": await DispatchAndWriteAsync(pipe, header.RequestId, header.SessionId, () => _gameplayJournalManager.CaptureOnMainThread(header.SessionId), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; case "get_recipe_catalog": { BridgeRequestEnvelope request3 = PluginJson.Deserialize>(text); if (request3?.Payload == null) { await WriteInvalidPayloadAsync(pipe, header.RequestId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } await DispatchAndWriteAsync(pipe, header.RequestId, header.SessionId, () => _gameStateReader.GetRecipeCatalogOnMainThread(header.SessionId, request3.Payload), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } case "list_resource_nodes": { BridgeRequestEnvelope request12 = PluginJson.Deserialize>(text); if (request12?.Payload == null) { await WriteInvalidPayloadAsync(pipe, header.RequestId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } await DispatchAndWriteAsync(pipe, header.RequestId, header.SessionId, () => _gameStateReader.ListResourceNodesOnMainThread(header.SessionId, request12.Payload), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } case "inspect_resource_node": { BridgeRequestEnvelope request21 = PluginJson.Deserialize>(text); if (request21?.Payload == null) { await WriteInvalidPayloadAsync(pipe, header.RequestId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } await DispatchAndWriteAsync(pipe, header.RequestId, header.SessionId, () => _gameStateReader.InspectResourceNodeOnMainThread(header.SessionId, request21.Payload), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } case "list_factory_entities": { BridgeRequestEnvelope request4 = PluginJson.Deserialize>(text); if (request4?.Payload == null) { await WriteInvalidPayloadAsync(pipe, header.RequestId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } await DispatchAndWriteAsync(pipe, header.RequestId, header.SessionId, () => _gameStateReader.ListFactoryEntitiesOnMainThread(header.SessionId, request4.Payload), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } case "inspect_factory_entity": { BridgeRequestEnvelope request14 = PluginJson.Deserialize>(text); if (request14?.Payload == null) { await WriteInvalidPayloadAsync(pipe, header.RequestId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } await DispatchAndWriteAsync(pipe, header.RequestId, header.SessionId, () => _gameStateReader.InspectFactoryEntityOnMainThread(header.SessionId, request14.Payload), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } case "get_power_summary": { BridgeRequestEnvelope request24 = PluginJson.Deserialize>(text); if (request24?.Payload == null) { await WriteInvalidPayloadAsync(pipe, header.RequestId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } await DispatchAndWriteAsync(pipe, header.RequestId, header.SessionId, () => _gameStateReader.GetPowerSummaryOnMainThread(header.SessionId, request24.Payload), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } case "get_action_result": { BridgeRequestEnvelope request2 = PluginJson.Deserialize>(text); if (request2?.Payload == null) { await WriteInvalidPayloadAsync(pipe, header.RequestId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } await DispatchAndWriteAsync(pipe, header.RequestId, header.SessionId, () => GetActionResultOnMainThread(request2.Payload), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } case "prepare_move": { BridgeRequestEnvelope request25 = PluginJson.Deserialize>(text); if (request25?.Payload == null) { await WriteInvalidPayloadAsync(pipe, header.RequestId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } await DispatchAndWriteAsync(pipe, header.RequestId, header.SessionId, () => _normalActionCoordinator.PrepareMoveOnMainThread(header.SessionId, request25.Payload), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } case "commit_move": await DispatchNormalCommitAsync(pipe, header, text, "move", cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; case "prepare_interplanetary_flight": { BridgeRequestEnvelope request16 = PluginJson.Deserialize>(text); if (request16?.Payload == null) { await WriteInvalidPayloadAsync(pipe, header.RequestId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } await DispatchAndWriteAsync(pipe, header.RequestId, header.SessionId, () => _normalActionCoordinator.PrepareInterplanetaryFlightOnMainThread(header.SessionId, request16.Payload), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } case "commit_interplanetary_flight": await DispatchNormalCommitAsync(pipe, header, text, "interplanetary-flight", cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; case "prepare_harvest": { BridgeRequestEnvelope request32 = PluginJson.Deserialize>(text); if (request32?.Payload == null) { await WriteInvalidPayloadAsync(pipe, header.RequestId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } await DispatchAndWriteAsync(pipe, header.RequestId, header.SessionId, () => _normalActionCoordinator.PrepareHarvestOnMainThread(header.SessionId, request32.Payload), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } case "commit_harvest": await DispatchNormalCommitAsync(pipe, header, text, "harvest", cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; case "prepare_handcraft": { BridgeRequestEnvelope request20 = PluginJson.Deserialize>(text); if (request20?.Payload == null) { await WriteInvalidPayloadAsync(pipe, header.RequestId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } await DispatchAndWriteAsync(pipe, header.RequestId, header.SessionId, () => _normalActionCoordinator.PrepareHandcraftOnMainThread(header.SessionId, request20.Payload), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } case "commit_handcraft": await DispatchNormalCommitAsync(pipe, header, text, "handcraft", cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; case "prepare_select_research": { BridgeRequestEnvelope request11 = PluginJson.Deserialize>(text); if (request11?.Payload == null) { await WriteInvalidPayloadAsync(pipe, header.RequestId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } await DispatchAndWriteAsync(pipe, header.RequestId, header.SessionId, () => _normalActionCoordinator.PrepareSelectResearchOnMainThread(header.SessionId, request11.Payload), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } case "commit_select_research": await DispatchNormalCommitAsync(pipe, header, text, "select-research", cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; case "prepare_build": { BridgeRequestEnvelope request33 = PluginJson.Deserialize>(text); if (request33?.Payload == null) { await WriteInvalidPayloadAsync(pipe, header.RequestId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } await DispatchAndWriteAsync(pipe, header.RequestId, header.SessionId, () => _normalActionCoordinator.PrepareBuildOnMainThread(header.SessionId, request33.Payload), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } case "commit_build": await DispatchNormalCommitAsync(pipe, header, text, "build", cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; case "prepare_dismantle": { BridgeRequestEnvelope request29 = PluginJson.Deserialize>(text); if (request29?.Payload == null) { await WriteInvalidPayloadAsync(pipe, header.RequestId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } await DispatchAndWriteAsync(pipe, header.RequestId, header.SessionId, () => _normalActionCoordinator.PrepareDismantleOnMainThread(header.SessionId, request29.Payload), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } case "commit_dismantle": await DispatchNormalCommitAsync(pipe, header, text, "dismantle", cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; case "prepare_configure_building": { BridgeRequestEnvelope request19 = PluginJson.Deserialize>(text); if (request19?.Payload == null) { await WriteInvalidPayloadAsync(pipe, header.RequestId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } await DispatchAndWriteAsync(pipe, header.RequestId, header.SessionId, () => _normalActionCoordinator.PrepareConfigureBuildingOnMainThread(header.SessionId, request19.Payload), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } case "commit_configure_building": await DispatchNormalCommitAsync(pipe, header, text, "configure-building", cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; case "prepare_transfer": { BridgeRequestEnvelope request10 = PluginJson.Deserialize>(text); if (request10?.Payload == null) { await WriteInvalidPayloadAsync(pipe, header.RequestId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } await DispatchAndWriteAsync(pipe, header.RequestId, header.SessionId, () => _normalActionCoordinator.PrepareTransferOnMainThread(header.SessionId, request10.Payload), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } case "commit_transfer": await DispatchNormalCommitAsync(pipe, header, text, "transfer", cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; case "prepare_logistics_station_fleet_transfer": { BridgeRequestEnvelope request5 = PluginJson.Deserialize>(text); if (request5?.Payload == null) { await WriteInvalidPayloadAsync(pipe, header.RequestId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } await DispatchAndWriteAsync(pipe, header.RequestId, header.SessionId, () => _normalActionCoordinator.PrepareLogisticsStationFleetTransferOnMainThread(header.SessionId, request5.Payload), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } case "commit_logistics_station_fleet_transfer": await DispatchNormalCommitAsync(pipe, header, text, "logistics-station-fleet-transfer", cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; case "prepare_refuel": { BridgeRequestEnvelope request31 = PluginJson.Deserialize>(text); if (request31?.Payload == null) { await WriteInvalidPayloadAsync(pipe, header.RequestId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } await DispatchAndWriteAsync(pipe, header.RequestId, header.SessionId, () => _normalActionCoordinator.PrepareRefuelOnMainThread(header.SessionId, request31.Payload), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } case "commit_refuel": await DispatchNormalCommitAsync(pipe, header, text, "refuel", cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; case "prepare_save": { BridgeRequestEnvelope request28 = PluginJson.Deserialize>(text); if (request28?.Payload == null) { await WriteInvalidPayloadAsync(pipe, header.RequestId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } await DispatchAndWriteAsync(pipe, header.RequestId, header.SessionId, () => _normalActionCoordinator.PrepareSaveOnMainThread(header.SessionId, request28.Payload), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } case "commit_save": await DispatchNormalCommitAsync(pipe, header, text, "save", cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; case "prepare_quarantine_reconciliation": { BridgeRequestEnvelope request22 = PluginJson.Deserialize>(text); if (request22?.Payload == null) { await WriteInvalidPayloadAsync(pipe, header.RequestId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } await DispatchAndWriteAsync(pipe, header.RequestId, header.SessionId, () => _normalActionCoordinator.PrepareQuarantineReconciliationOnMainThread(header.SessionId, request22.Payload), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } case "get_local_star_system": { BridgeRequestEnvelope request15 = PluginJson.Deserialize>(text); if (request15?.Payload == null) { await WriteInvalidPayloadAsync(pipe, header.RequestId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } await DispatchAndWriteAsync(pipe, header.RequestId, header.SessionId, () => _gameStateReader.GetLocalStarSystemOnMainThread(header.SessionId, request15.Payload), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } case "commit_quarantine_reconciliation": { BridgeRequestEnvelope request9 = PluginJson.Deserialize>(text); if (request9?.Payload == null) { await WriteInvalidPayloadAsync(pipe, header.RequestId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } await DispatchAndWriteAsync(pipe, header.RequestId, header.SessionId, () => _normalActionCoordinator.CommitQuarantineReconciliationOnMainThread(header.SessionId, request9.Payload), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } case "list_assemblers": { BridgeRequestEnvelope request7 = PluginJson.Deserialize>(text); if (request7?.Payload == null) { await WriteInvalidPayloadAsync(pipe, header.RequestId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } await DispatchAndWriteAsync(pipe, header.RequestId, header.SessionId, () => _gameStateReader.ListAssemblersOnMainThread(header.SessionId, request7.Payload), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } case "inspect_assembler": { BridgeRequestEnvelope request34 = PluginJson.Deserialize>(text); if (request34?.Payload == null) { await WriteInvalidPayloadAsync(pipe, header.RequestId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } await DispatchAndWriteAsync(pipe, header.RequestId, header.SessionId, () => _gameStateReader.InspectAssemblerOnMainThread(header.SessionId, request34.Payload), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } case "get_build_catalog": await DispatchAndWriteAsync(pipe, header.RequestId, header.SessionId, () => _gameStateReader.GetBuildCatalogOnMainThread(header.SessionId), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; case "prepare_new_game": { BridgeRequestEnvelope request30 = PluginJson.Deserialize>(text); if (request30?.Payload == null) { await WriteInvalidPayloadAsync(pipe, header.RequestId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } await DispatchAndWriteAsync(pipe, header.RequestId, null, () => _testWorldCoordinator.PrepareOnMainThread(request30.Payload), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } case "commit_new_game": { BridgeRequestEnvelope request26 = PluginJson.Deserialize>(text); if (request26?.Payload == null) { await WriteInvalidPayloadAsync(pipe, header.RequestId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } await DispatchAndWriteAsync(pipe, header.RequestId, null, () => _testWorldCoordinator.CommitOnMainThread(request26.Payload), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } case "prepare_import_current_game": { BridgeRequestEnvelope request23 = PluginJson.Deserialize>(text); if (request23?.Payload == null) { await WriteInvalidPayloadAsync(pipe, header.RequestId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } await DispatchAndWriteAsync(pipe, header.RequestId, header.SessionId, () => _userSaveImportCoordinator.PrepareOnMainThread(header.SessionId, request23.Payload), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } case "commit_import_current_game": { BridgeRequestEnvelope request18 = PluginJson.Deserialize>(text); if (request18?.Payload == null) { await WriteInvalidPayloadAsync(pipe, header.RequestId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } await DispatchAndWriteAsync(pipe, header.RequestId, header.SessionId, () => _userSaveImportCoordinator.CommitOnMainThread(header.SessionId, request18.Payload), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } case "prepare_resume_owned_game": { BridgeRequestEnvelope request13 = PluginJson.Deserialize>(text); if (request13?.Payload == null) { await WriteInvalidPayloadAsync(pipe, header.RequestId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } await DispatchAndWriteAsync(pipe, header.RequestId, null, () => _ownedWorldResumeCoordinator.PrepareOnMainThread(request13.Payload), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } case "commit_resume_owned_game": { BridgeRequestEnvelope request8 = PluginJson.Deserialize>(text); if (request8?.Payload == null) { await WriteInvalidPayloadAsync(pipe, header.RequestId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } await DispatchAndWriteAsync(pipe, header.RequestId, null, () => _ownedWorldResumeCoordinator.CommitOnMainThread(request8.Payload), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } case "prepare_reload_flight_checkpoint": { BridgeRequestEnvelope request6 = PluginJson.Deserialize>(text); if (request6?.Payload == null) { await WriteInvalidPayloadAsync(pipe, header.RequestId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } await DispatchAndWriteAsync(pipe, header.RequestId, null, () => _flightCheckpointReloadCoordinator.PrepareOnMainThread(request6.Payload), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } case "commit_reload_flight_checkpoint": { BridgeRequestEnvelope request = PluginJson.Deserialize>(text); if (request?.Payload == null) { await WriteInvalidPayloadAsync(pipe, header.RequestId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } await DispatchAndWriteAsync(pipe, header.RequestId, null, () => _flightCheckpointReloadCoordinator.CommitOnMainThread(request.Payload), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } default: await WriteErrorAsync(pipe, header.RequestId, BridgeError.Create("INVALID_REQUEST", "The requested bridge method is not available.", false, "Call a method advertised by the current Spherewright MCP server."), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); break; } } } private GameCallResult GetActionResultOnMainThread(GetActionResultRequest request) { if (_userSaveImportCoordinator.TryGetActionResultOnMainThread(request.ActionId, out ActionResultSnapshot result) && result != null) { return GameCallResult.Succeeded(result); } if (_normalActionCoordinator.TryGetActionResultOnMainThread(request.ActionId, out ActionResultSnapshot result2) && result2 != null) { return GameCallResult.Succeeded(result2); } if (_ownedWorldResumeCoordinator.TryGetActionResultOnMainThread(request.ActionId, out ActionResultSnapshot result3) && result3 != null) { return GameCallResult.Succeeded(result3); } if (_flightCheckpointReloadCoordinator.TryGetActionResultOnMainThread(request.ActionId, out ActionResultSnapshot result4) && result4 != null) { return GameCallResult.Succeeded(result4); } return _testWorldCoordinator.GetActionResultOnMainThread(request); } private async Task DispatchNormalCommitAsync(Stream pipe, BridgeEnvelopeHeader header, string requestJson, string actionKind, CancellationToken cancellationToken) { BridgeRequestEnvelope request = PluginJson.Deserialize>(requestJson); if (request?.Payload == null) { await WriteInvalidPayloadAsync(pipe, header.RequestId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); return; } await DispatchAndWriteAsync(pipe, header.RequestId, header.SessionId, () => _normalActionCoordinator.CommitOnMainThread(actionKind, header.SessionId, request.Payload), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); } private async Task DispatchAndWriteAsync(Stream pipe, string requestId, string? sessionId, Func> operation, CancellationToken cancellationToken) { Task> completion = default(Task>); if (!_dispatcher.TryEnqueue>(operation, ref completion)) { await WriteErrorAsync(pipe, requestId, BridgeError.Create("QUEUE_FULL", "The Unity main-thread request queue is full.", true, "Retry after the game has processed pending requests."), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); return; } Task task = Task.Delay(_readRequestTimeout, cancellationToken); if (await Task.WhenAny(new Task[2] { completion, task }).ConfigureAwait(continueOnCapturedContext: false) != completion) { cancellationToken.ThrowIfCancellationRequested(); await WriteErrorAsync(pipe, requestId, BridgeError.Create("REQUEST_TIMEOUT", "The Unity main-thread read request timed out.", true, "Wait for DSP to become responsive and retry."), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); return; } GameCallResult result; try { result = await completion.ConfigureAwait(continueOnCapturedContext: false); } catch (Exception arg) { _logger.LogError((object)$"Spherewright main-thread operation failed: {arg}"); await WriteErrorAsync(pipe, requestId, BridgeError.Create("INTERNAL_ERROR", "A main-thread game-state read failed.", true, "Retry once. If it repeats, inspect the local Spherewright log."), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); return; } if (!result.Success || result.Value == null) { await WriteErrorAsync(pipe, requestId, result.Error ?? BridgeError.Create("INTERNAL_ERROR", "The game-state read returned an incomplete result.", true, "Retry the request."), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); } else { await WriteResultAsync(pipe, requestId, sessionId, result.Value, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); } } private Task WriteInvalidPayloadAsync(Stream pipe, string requestId, CancellationToken cancellationToken) { return WriteErrorAsync(pipe, requestId, BridgeError.Create("INVALID_REQUEST", "The bridge request payload is missing or invalid.", false, "Correct the request payload and retry."), cancellationToken); } private Task WriteResultAsync(Stream pipe, string requestId, string? sessionId, T result, CancellationToken cancellationToken) { return WriteEnvelopeAsync(pipe, new BridgeResponseEnvelope { RequestId = requestId, SessionId = sessionId, Success = true, Result = result }, cancellationToken); } private NamedPipeServerStream CreateServerPipe() { return WindowsCurrentUserSecurity.CreateSecurePipe(_pipeName, 4096, 4096); } private async Task WriteErrorAsync(Stream pipe, string? requestId, BridgeError error, CancellationToken cancellationToken) { BridgeResponseEnvelope obj = new BridgeResponseEnvelope(); string requestId2; if (!string.IsNullOrWhiteSpace(requestId)) { requestId2 = requestId; } else { Guid empty = Guid.Empty; requestId2 = empty.ToString("D"); } obj.RequestId = requestId2; obj.Success = false; obj.Error = error; BridgeResponseEnvelope envelope = obj; await WriteEnvelopeAsync(pipe, envelope, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); } private Task WriteEnvelopeAsync(Stream pipe, BridgeResponseEnvelope envelope, CancellationToken cancellationToken) { byte[] array = FrameCodec.EncodeUtf8(PluginJson.Serialize>(envelope)); return _frameCodec.WriteFrameAsync(pipe, array, cancellationToken); } private void LogAuthenticationFailureWithRateLimit() { int tickCount = Environment.TickCount; int num = Interlocked.Exchange(ref _lastAuthWarningTick, tickCount); if (num == 0 || tickCount - num >= 5000) { _logger.LogWarning((object)"Spherewright rejected a bridge authentication attempt."); } } } internal static class PluginJson { private static readonly JsonSerializerSettings Settings = new JsonSerializerSettings { ContractResolver = (IContractResolver)new CamelCasePropertyNamesContractResolver(), DateFormatHandling = (DateFormatHandling)0, DateParseHandling = (DateParseHandling)2, MissingMemberHandling = (MissingMemberHandling)0, NullValueHandling = (NullValueHandling)0, TypeNameHandling = (TypeNameHandling)0, MaxDepth = 64 }; public static string Serialize(T value) { return JsonConvert.SerializeObject((object)value, (Formatting)0, Settings); } public static T? Deserialize(string json) { return JsonConvert.DeserializeObject(json, Settings); } } } namespace Spherewright.Plugin.Security { internal static class WindowsCurrentUserSecurity { private struct SecurityAttributes { public int Length; public IntPtr SecurityDescriptor; public int InheritHandle; } private sealed class NativeSecurityDescriptor : IDisposable { public IntPtr Pointer { get; private set; } private NativeSecurityDescriptor(IntPtr pointer) { Pointer = pointer; } public static NativeSecurityDescriptor Create(string sddl) { if (!ConvertStringSecurityDescriptorToSecurityDescriptor(sddl, 1u, out var securityDescriptor, out var _)) { throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not create a current-user security descriptor."); } return new NativeSecurityDescriptor(securityDescriptor); } public SecurityAttributes CreateAttributes() { return new SecurityAttributes { Length = Marshal.SizeOf(typeof(SecurityAttributes)), SecurityDescriptor = Pointer, InheritHandle = 0 }; } public void Dispose() { IntPtr pointer = Pointer; Pointer = IntPtr.Zero; if (pointer != IntPtr.Zero) { LocalFree(pointer); } } } private const uint TokenQuery = 8u; private const int TokenUser = 1; private const int ErrorInsufficientBuffer = 122; private const int ErrorAlreadyExists = 183; private const uint SecurityDescriptorRevision = 1u; private const uint DaclSecurityInformation = 4u; private const uint ProtectedDaclSecurityInformation = 2147483648u; private const uint GenericWrite = 1073741824u; private const uint CreateNew = 1u; private const uint FileAttributeNormal = 128u; private const uint PipeAccessDuplex = 3u; private const uint FileFlagOverlapped = 1073741824u; private const uint PipeRejectRemoteClients = 8u; private static readonly Lazy CurrentUserSid = new Lazy(ReadCurrentUserSid); public static void EnsureSecureDirectory(string path) { if (string.IsNullOrWhiteSpace(path)) { throw new ArgumentException("A secure directory path is required.", "path"); } using NativeSecurityDescriptor nativeSecurityDescriptor = NativeSecurityDescriptor.Create(BuildDirectorySddl(CurrentUserSid.Value)); Stack stack = new Stack(); string text = path; while (!Directory.Exists(text)) { stack.Push(text); text = (Directory.GetParent(text) ?? throw new InvalidOperationException("No existing parent was found for secure directory '" + path + "'.")).FullName; } while (stack.Count > 0) { string text2 = stack.Pop(); SecurityAttributes securityAttributes = nativeSecurityDescriptor.CreateAttributes(); if (!CreateDirectory(text2, ref securityAttributes)) { int lastWin32Error = Marshal.GetLastWin32Error(); if (lastWin32Error != 183) { throw new Win32Exception(lastWin32Error, "Could not create secure directory '" + text2 + "'."); } } ApplyProtectedDacl(text2, nativeSecurityDescriptor.Pointer); } ApplyProtectedDacl(path, nativeSecurityDescriptor.Pointer); } public static void WriteSecureNewFile(string path, byte[] content) { if (string.IsNullOrWhiteSpace(path)) { throw new ArgumentException("A secure file path is required.", "path"); } if (content == null) { throw new ArgumentNullException("content"); } using NativeSecurityDescriptor nativeSecurityDescriptor = NativeSecurityDescriptor.Create(BuildFileSddl(CurrentUserSid.Value)); SecurityAttributes securityAttributes = nativeSecurityDescriptor.CreateAttributes(); using SafeFileHandle safeFileHandle = CreateFile(path, 1073741824u, 0u, ref securityAttributes, 1u, 128u, IntPtr.Zero); if (safeFileHandle.IsInvalid) { throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not create secure file '" + path + "'."); } uint numberOfBytesWritten; for (int i = 0; i < content.Length; i += checked((int)numberOfBytesWritten)) { int num = content.Length - i; byte[] array = new byte[num]; Buffer.BlockCopy(content, i, array, 0, num); if (!WriteFile(safeFileHandle, array, (uint)array.Length, out numberOfBytesWritten, IntPtr.Zero)) { throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not write secure file '" + path + "'."); } if (numberOfBytesWritten == 0) { throw new IOException("Writing secure file '" + path + "' made no progress."); } } if (!FlushFileBuffers(safeFileHandle)) { throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not flush secure file '" + path + "'."); } } public static NamedPipeServerStream CreateSecurePipe(string pipeName, int inputBufferSize, int outputBufferSize) { if (string.IsNullOrWhiteSpace(pipeName)) { throw new ArgumentException("A Pipe name is required.", "pipeName"); } using NativeSecurityDescriptor nativeSecurityDescriptor = NativeSecurityDescriptor.Create(BuildPipeSddl(CurrentUserSid.Value)); SecurityAttributes securityAttributes = nativeSecurityDescriptor.CreateAttributes(); SafePipeHandle safePipeHandle = checked(CreateNamedPipe("\\\\.\\pipe\\" + pipeName, 1073741827u, 8u, 1u, (uint)outputBufferSize, (uint)inputBufferSize, 0u, ref securityAttributes)); if (safePipeHandle.IsInvalid) { int lastWin32Error = Marshal.GetLastWin32Error(); safePipeHandle.Dispose(); throw new Win32Exception(lastWin32Error, "Could not create secure Named Pipe '" + pipeName + "'."); } try { return new NamedPipeServerStream(PipeDirection.InOut, isAsync: true, isConnected: false, safePipeHandle); } catch { safePipeHandle.Dispose(); throw; } } private static string ReadCurrentUserSid() { if (!OpenProcessToken(GetCurrentProcess(), 8u, out var tokenHandle)) { throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not open the current process token."); } try { GetTokenInformation(tokenHandle, 1, IntPtr.Zero, 0, out var returnLength); int lastWin32Error = Marshal.GetLastWin32Error(); if (returnLength <= 0 || lastWin32Error != 122) { throw new Win32Exception(lastWin32Error, "Could not determine the current process-token user size."); } IntPtr intPtr = Marshal.AllocHGlobal(returnLength); try { if (!GetTokenInformation(tokenHandle, 1, intPtr, returnLength, out var _)) { throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not read the current process-token user."); } if (!ConvertSidToStringSid(Marshal.ReadIntPtr(intPtr), out var stringSid)) { throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not convert the current user SID to text."); } try { return Marshal.PtrToStringUni(stringSid) ?? throw new InvalidOperationException("Windows returned an empty current-user SID."); } finally { LocalFree(stringSid); } } finally { Marshal.FreeHGlobal(intPtr); } } finally { CloseHandle(tokenHandle); } } private static void ApplyProtectedDacl(string path, IntPtr securityDescriptor) { if (!SetFileSecurity(path, 2147483652u, securityDescriptor)) { throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not protect the ACL for '" + path + "'."); } } private static string BuildDirectorySddl(string sid) { return "O:" + sid + "D:P(A;OICI;FA;;;" + sid + ")"; } private static string BuildFileSddl(string sid) { return "O:" + sid + "D:P(A;;FA;;;" + sid + ")"; } private static string BuildPipeSddl(string sid) { return "O:" + sid + "D:P(A;;GA;;;" + sid + ")"; } [DllImport("kernel32.dll")] private static extern IntPtr GetCurrentProcess(); [DllImport("advapi32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool OpenProcessToken(IntPtr processHandle, uint desiredAccess, out IntPtr tokenHandle); [DllImport("advapi32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool GetTokenInformation(IntPtr tokenHandle, int tokenInformationClass, IntPtr tokenInformation, int tokenInformationLength, out int returnLength); [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool ConvertSidToStringSid(IntPtr sid, out IntPtr stringSid); [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool ConvertStringSecurityDescriptorToSecurityDescriptor(string stringSecurityDescriptor, uint stringSdRevision, out IntPtr securityDescriptor, out uint securityDescriptorSize); [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool SetFileSecurity(string fileName, uint securityInformation, IntPtr securityDescriptor); [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool CreateDirectory(string pathName, ref SecurityAttributes securityAttributes); [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern SafeFileHandle CreateFile(string fileName, uint desiredAccess, uint shareMode, ref SecurityAttributes securityAttributes, uint creationDisposition, uint flagsAndAttributes, IntPtr templateFile); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool WriteFile(SafeFileHandle file, byte[] buffer, uint numberOfBytesToWrite, out uint numberOfBytesWritten, IntPtr overlapped); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool FlushFileBuffers(SafeFileHandle file); [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern SafePipeHandle CreateNamedPipe(string name, uint openMode, uint pipeMode, uint maxInstances, uint outputBufferSize, uint inputBufferSize, uint defaultTimeout, ref SecurityAttributes securityAttributes); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool CloseHandle(IntPtr handle); [DllImport("kernel32.dll")] private static extern IntPtr LocalFree(IntPtr memory); } } namespace Spherewright.Plugin.RuntimeDescriptor { internal sealed class FlightCheckpointStore { private const int TicketVersion = 1; private static readonly TimeSpan TicketLifetime = TimeSpan.FromHours(24.0); private readonly string _ticketPath; private readonly string _bridgeInstanceId; private readonly string _gameVersion; private readonly ManualLogSource _logger; private FlightCheckpointTicket? _currentTicket; public FlightCheckpointTicket? CurrentTicket { get { if (!IsReloadEligible(_currentTicket)) { return null; } return _currentTicket; } } public bool HasCurrentTicket => CurrentTicket != null; public FlightCheckpointStore(string bridgeInstanceId, string gameVersion, ManualLogSource logger) { string text = Path.Combine(Path.GetDirectoryName(typeof(FlightCheckpointStore).Assembly.Location) ?? throw new InvalidOperationException("The Spherewright Plugin directory is unavailable."), "runtime-handoff"); WindowsCurrentUserSecurity.EnsureSecureDirectory(text); _ticketPath = Path.Combine(text, "flight-checkpoint.json"); _bridgeInstanceId = bridgeInstanceId; _gameVersion = gameVersion; _logger = logger; _currentTicket = ReadFromDisk(); RetireIfCoveredByNewerPrimarySave(); _logger.LogInfo((object)"Spherewright initialized the protected reusable flight-checkpoint store"); } public FlightCheckpointTicket CreateDraft(string ownedSaveName, string sourceSessionId, long sourceRevision, int originPlanetId, int destinationPlanetId, string playerStateHash, string starSystemStateHash) { if (string.IsNullOrWhiteSpace(ownedSaveName) || string.IsNullOrWhiteSpace(sourceSessionId) || sourceRevision < 1 || originPlanetId <= 0 || destinationPlanetId <= 0 || originPlanetId == destinationPlanetId || string.IsNullOrWhiteSpace(playerStateHash) || string.IsNullOrWhiteSpace(starSystemStateHash)) { throw new InvalidOperationException("A complete owned flight identity is required to create a checkpoint."); } string text = Guid.NewGuid().ToString("N"); DateTimeOffset utcNow = DateTimeOffset.UtcNow; return new FlightCheckpointTicket { Version = 1, CheckpointId = text, ReloadToken = CreateToken(), CheckpointSaveName = "Spherewright_PreFlight_" + text, OwnedSaveName = ownedSaveName, SourceSessionId = sourceSessionId, SourceRevision = sourceRevision, SourceProcessId = Process.GetCurrentProcess().Id, SourceBridgeInstanceId = _bridgeInstanceId, GameVersion = _gameVersion, OriginPlanetId = originPlanetId, DestinationPlanetId = destinationPlanetId, PlayerStateHash = playerStateHash, StarSystemStateHash = starSystemStateHash, IssuedAtUtc = utcNow, ExpiresAtUtc = utcNow.Add(TicketLifetime), LifecycleState = "active" }; } public void PersistCompletedCheckpoint(FlightCheckpointTicket ticket, long savedGameTick) { if (ticket == null || savedGameTick < 0) { throw new InvalidOperationException("A completed flight checkpoint and game tick are required."); } ticket.SavedGameTick = savedGameTick; if (!IsStructurallyValid(ticket)) { throw new InvalidOperationException("The completed flight-checkpoint identity is invalid."); } Persist(ticket); _currentTicket = ticket; _logger.LogInfo((object)"Spherewright persisted an exact reusable pre-flight checkpoint ticket"); } public bool TryMarkAttemptStarted(string checkpointId, string actionId, long gameTick, out string rejection) { rejection = string.Empty; FlightCheckpointTicket currentTicket = _currentTicket; if (!IsReloadEligible(currentTicket) || currentTicket == null || !string.Equals(currentTicket.CheckpointId, checkpointId, StringComparison.Ordinal) || string.IsNullOrWhiteSpace(actionId) || gameTick < currentTicket.SavedGameTick) { rejection = "The flight attempt does not match the current reloadable checkpoint."; return false; } currentTicket.LifecycleState = "active"; currentTicket.LastAttemptActionId = actionId; currentTicket.LastAttemptStartedAtGameTick = gameTick; currentTicket.RecoveryRequiredAtGameTick = null; currentTicket.SuccessfulFlightAtGameTick = null; return TryPersistLifecycle(currentTicket, "start the bound flight attempt", out rejection); } public bool TryMarkRecoveryRequired(string checkpointId, string actionId, long gameTick, out string rejection) { rejection = string.Empty; FlightCheckpointTicket currentTicket = _currentTicket; if (!IsStructurallyValid(currentTicket) || currentTicket == null || !string.Equals(currentTicket.CheckpointId, checkpointId, StringComparison.Ordinal) || IsSuccessfulOrRetired(currentTicket) || string.IsNullOrWhiteSpace(actionId) || gameTick < currentTicket.SavedGameTick) { rejection = "The failed flight does not match the current checkpoint lifecycle."; return false; } currentTicket.LifecycleState = "recovery_required"; currentTicket.LastAttemptActionId = actionId; currentTicket.RecoveryRequiredAtGameTick = gameTick; return TryPersistLifecycle(currentTicket, "mark the bound flight as recovery-required", out rejection); } public bool TryMarkFlightSucceeded(string checkpointId, string actionId, long gameTick, out string rejection) { rejection = string.Empty; FlightCheckpointTicket currentTicket = _currentTicket; if (!IsStructurallyValid(currentTicket) || currentTicket == null || !string.Equals(currentTicket.CheckpointId, checkpointId, StringComparison.Ordinal) || IsSuccessfulOrRetired(currentTicket) || string.IsNullOrWhiteSpace(actionId) || gameTick < currentTicket.SavedGameTick) { rejection = "The successful flight does not match the current checkpoint lifecycle."; return false; } currentTicket.LifecycleState = "flight_succeeded"; currentTicket.LastAttemptActionId = actionId; currentTicket.SuccessfulFlightAtGameTick = gameTick; currentTicket.RecoveryRequiredAtGameTick = null; return TryPersistLifecycle(currentTicket, "seal the successful flight before its primary save", out rejection); } public bool TryRetireAfterPrimarySave(string ownedSaveName, long savedGameTick, out bool retired, out string rejection) { retired = false; rejection = string.Empty; FlightCheckpointTicket currentTicket = _currentTicket; if (!IsStructurallyValid(currentTicket) || currentTicket == null) { return true; } if (!string.Equals(EffectiveLifecycle(currentTicket), "flight_succeeded", StringComparison.Ordinal)) { return true; } if (!string.Equals(currentTicket.OwnedSaveName, ownedSaveName, StringComparison.Ordinal) || !currentTicket.SuccessfulFlightAtGameTick.HasValue || savedGameTick < currentTicket.SuccessfulFlightAtGameTick.Value) { rejection = "The primary save does not cover the successful flight checkpoint timeline."; return false; } currentTicket.LifecycleState = "retired"; currentTicket.RetiredAtGameTick = savedGameTick; currentTicket.RetiredAtUtc = DateTimeOffset.UtcNow; if (!TryPersistLifecycle(currentTicket, "retire the checkpoint after the covering primary save", out rejection)) { return false; } retired = true; _logger.LogInfo((object)"Spherewright retired the successful flight checkpoint after a covering primary save"); return true; } public bool TryGetActiveTicket(string reloadToken, out FlightCheckpointTicket? ticket, out string rejection) { ticket = null; rejection = string.Empty; if (string.IsNullOrWhiteSpace(reloadToken)) { rejection = "A flight-checkpoint reload token is required."; return false; } FlightCheckpointTicket flightCheckpointTicket = _currentTicket ?? ReadFromDisk(); if (!IsReloadEligible(flightCheckpointTicket) || flightCheckpointTicket == null || !FixedTimeEquals(flightCheckpointTicket.ReloadToken, reloadToken)) { rejection = "The flight-checkpoint ticket is missing, expired, retired, already succeeded, or belongs to another game version."; return false; } _currentTicket = flightCheckpointTicket; ticket = flightCheckpointTicket; return true; } public bool TryValidateCheckpointFile(FlightCheckpointTicket ticket, out string rejection) { rejection = string.Empty; if (!IsStructurallyValid(ticket)) { rejection = "The reusable flight-checkpoint ticket is invalid."; return false; } GameSaveHeader val = default(GameSaveHeader); GameSave.ReadHeader(ticket.CheckpointSaveName, false, ref val); if (val == null || val.gameTick != ticket.SavedGameTick) { rejection = "The exact pre-flight save is missing or its saved game tick no longer matches the protected ticket."; return false; } return true; } private bool IsStructurallyValid(FlightCheckpointTicket? ticket) { if (ticket != null && ticket.Version == 1 && string.Equals(ticket.GameVersion, _gameVersion, StringComparison.Ordinal) && !string.IsNullOrWhiteSpace(ticket.CheckpointId) && !string.IsNullOrWhiteSpace(ticket.ReloadToken) && !string.IsNullOrWhiteSpace(ticket.CheckpointSaveName) && ticket.CheckpointSaveName.StartsWith("Spherewright_PreFlight_", StringComparison.Ordinal) && ticket.CheckpointSaveName.IndexOfAny(new char[3] { '/', '\\', ':' }) < 0 && !string.IsNullOrWhiteSpace(ticket.OwnedSaveName) && !string.IsNullOrWhiteSpace(ticket.SourceSessionId) && ticket.SourceRevision >= 1 && ticket.OriginPlanetId > 0 && ticket.DestinationPlanetId > 0 && ticket.OriginPlanetId != ticket.DestinationPlanetId && ticket.SavedGameTick >= 0 && ticket.IssuedAtUtc != default(DateTimeOffset) && (ticket.ExpiresAtUtc == default(DateTimeOffset) || ticket.ExpiresAtUtc > ticket.IssuedAtUtc) && IsKnownLifecycle(ticket.LifecycleState) && !string.IsNullOrWhiteSpace(ticket.PlayerStateHash)) { return !string.IsNullOrWhiteSpace(ticket.StarSystemStateHash); } return false; } private bool IsReloadEligible(FlightCheckpointTicket? ticket) { if (IsStructurallyValid(ticket) && ticket != null && EffectiveExpiresAt(ticket) > DateTimeOffset.UtcNow) { return !IsSuccessfulOrRetired(ticket); } return false; } internal static bool IsRecoveryRequired(FlightCheckpointTicket ticket) { return string.Equals(EffectiveLifecycle(ticket), "recovery_required", StringComparison.Ordinal); } internal static bool IsAttemptInFlight(FlightCheckpointTicket ticket) { return string.Equals(EffectiveLifecycle(ticket), "active", StringComparison.Ordinal); } private static bool IsSuccessfulOrRetired(FlightCheckpointTicket ticket) { string a = EffectiveLifecycle(ticket); if (!string.Equals(a, "flight_succeeded", StringComparison.Ordinal)) { return string.Equals(a, "retired", StringComparison.Ordinal); } return true; } private static bool IsKnownLifecycle(string lifecycle) { if (!string.IsNullOrWhiteSpace(lifecycle) && !string.Equals(lifecycle, "active", StringComparison.Ordinal) && !string.Equals(lifecycle, "recovery_required", StringComparison.Ordinal) && !string.Equals(lifecycle, "flight_succeeded", StringComparison.Ordinal)) { return string.Equals(lifecycle, "retired", StringComparison.Ordinal); } return true; } private static string EffectiveLifecycle(FlightCheckpointTicket ticket) { if (!string.IsNullOrWhiteSpace(ticket.LifecycleState)) { return ticket.LifecycleState; } return "active"; } private static DateTimeOffset EffectiveExpiresAt(FlightCheckpointTicket ticket) { if (!(ticket.ExpiresAtUtc == default(DateTimeOffset))) { return ticket.ExpiresAtUtc; } return ticket.IssuedAtUtc.Add(TicketLifetime); } private bool TryPersistLifecycle(FlightCheckpointTicket ticket, string operation, out string rejection) { _currentTicket = ticket; try { Persist(ticket); rejection = string.Empty; return true; } catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException || ex is ArgumentException) { rejection = "Spherewright could not " + operation + " (" + ex.GetType().Name + ")."; _logger.LogError((object)rejection); return false; } } private FlightCheckpointTicket? ReadFromDisk() { try { string json; using (FileStream stream = new FileStream(_ticketPath, FileMode.Open, FileAccess.Read, FileShare.Read)) { using StreamReader streamReader = new StreamReader(stream, Encoding.UTF8, detectEncodingFromByteOrderMarks: true); json = streamReader.ReadToEnd(); } FlightCheckpointTicket flightCheckpointTicket = PluginJson.Deserialize(json); if (!IsStructurallyValid(flightCheckpointTicket)) { _logger.LogWarning((object)"Spherewright ignored an invalid reusable flight-checkpoint ticket"); return null; } _logger.LogInfo((object)"Spherewright loaded a reusable flight-checkpoint ticket from the protected handoff directory"); return flightCheckpointTicket; } catch (FileNotFoundException) { return null; } catch (DirectoryNotFoundException) { return null; } catch (Exception ex3) when (ex3 is IOException || ex3 is UnauthorizedAccessException || ex3 is JsonException || ex3 is ArgumentException) { _logger.LogWarning((object)("Spherewright ignored an unreadable flight-checkpoint ticket (" + ex3.GetType().Name + ")")); return null; } } private void RetireIfCoveredByNewerPrimarySave() { FlightCheckpointTicket currentTicket = _currentTicket; if (!IsStructurallyValid(currentTicket) || currentTicket == null || string.Equals(EffectiveLifecycle(currentTicket), "retired", StringComparison.Ordinal)) { return; } try { GameSaveHeader val = default(GameSaveHeader); GameSave.ReadHeader(currentTicket.OwnedSaveName, false, ref val); if (val != null && val.gameTick > currentTicket.SavedGameTick) { currentTicket.LifecycleState = "retired"; currentTicket.RetiredAtGameTick = val.gameTick; currentTicket.RetiredAtUtc = DateTimeOffset.UtcNow; if (TryPersistLifecycle(currentTicket, "retire a checkpoint superseded by a newer exact primary save", out string _)) { _logger.LogInfo((object)"Spherewright retired a flight checkpoint whose exact primary save already covered a newer timeline"); } } } catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException || ex is ArgumentException) { _logger.LogWarning((object)("Spherewright could not compare the exact primary save with its flight checkpoint (" + ex.GetType().Name + ")")); } } private void Persist(FlightCheckpointTicket ticket) { string? obj = Path.GetDirectoryName(_ticketPath) ?? throw new InvalidOperationException("The flight-checkpoint handoff directory is unavailable."); WindowsCurrentUserSecurity.EnsureSecureDirectory(obj); string text = Path.Combine(obj, $".flight-checkpoint-{Guid.NewGuid():N}.tmp"); byte[] bytes = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false).GetBytes(PluginJson.Serialize(ticket)); WindowsCurrentUserSecurity.WriteSecureNewFile(text, bytes); try { if (File.Exists(_ticketPath)) { File.Replace(text, _ticketPath, null, ignoreMetadataErrors: true); } else { File.Move(text, _ticketPath); } } finally { if (File.Exists(text)) { File.Delete(text); } } } private static string CreateToken() { byte[] array = new byte[32]; using (RandomNumberGenerator randomNumberGenerator = RandomNumberGenerator.Create()) { randomNumberGenerator.GetBytes(array); } return Convert.ToBase64String(array).TrimEnd(new char[1] { '=' }).Replace('+', '-') .Replace('/', '_'); } private static bool FixedTimeEquals(string left, string right) { byte[] bytes = Encoding.UTF8.GetBytes(left ?? string.Empty); byte[] bytes2 = Encoding.UTF8.GetBytes(right ?? string.Empty); int num = bytes.Length ^ bytes2.Length; int num2 = Math.Max(bytes.Length, bytes2.Length); for (int i = 0; i < num2; i++) { byte b = (byte)((i < bytes.Length) ? bytes[i] : 0); byte b2 = (byte)((i < bytes2.Length) ? bytes2[i] : 0); num |= b ^ b2; } return num == 0; } } internal sealed class FlightCheckpointTicket { public int Version { get; set; } public string CheckpointId { get; set; } = string.Empty; public string ReloadToken { get; set; } = string.Empty; public string CheckpointSaveName { get; set; } = string.Empty; public string OwnedSaveName { get; set; } = string.Empty; public string SourceSessionId { get; set; } = string.Empty; public long SourceRevision { get; set; } public int SourceProcessId { get; set; } public string SourceBridgeInstanceId { get; set; } = string.Empty; public string GameVersion { get; set; } = string.Empty; public int OriginPlanetId { get; set; } public int DestinationPlanetId { get; set; } public long SavedGameTick { get; set; } public string PlayerStateHash { get; set; } = string.Empty; public string StarSystemStateHash { get; set; } = string.Empty; public DateTimeOffset IssuedAtUtc { get; set; } public DateTimeOffset ExpiresAtUtc { get; set; } public string LifecycleState { get; set; } = string.Empty; public string LastAttemptActionId { get; set; } = string.Empty; public long? LastAttemptStartedAtGameTick { get; set; } public long? RecoveryRequiredAtGameTick { get; set; } public long? SuccessfulFlightAtGameTick { get; set; } public long? RetiredAtGameTick { get; set; } public DateTimeOffset? RetiredAtUtc { get; set; } } internal static class FlightCheckpointLifecycleStates { public const string Active = "active"; public const string RecoveryRequired = "recovery_required"; public const string FlightSucceeded = "flight_succeeded"; public const string Retired = "retired"; } internal sealed class OwnedWorldResumeTicketStore { private const int TicketVersion = 1; private readonly string _ticketPath; private readonly string _handoffTicketPath; private readonly string _runtimeDirectory; private readonly string _bridgeInstanceId; private readonly string _gameVersion; private readonly ManualLogSource _logger; private OwnedWorldResumeTicket? _currentTicket; private string? _currentTicketPath; public string? CurrentResumeToken => _currentTicket?.ResumeToken; public bool HasCurrentTicket => _currentTicket != null; public OwnedWorldResumeTicketStore(string configuredRuntimeDirectory, string bridgeInstanceId, string gameVersion, ManualLogSource logger) { _runtimeDirectory = RuntimeDescriptorPublisher.ResolveRuntimeDirectory(configuredRuntimeDirectory); _ticketPath = Path.Combine(_runtimeDirectory, "owned-world-resume.json"); string text = Path.Combine(Path.GetDirectoryName(typeof(OwnedWorldResumeTicketStore).Assembly.Location) ?? throw new InvalidOperationException("The Spherewright Plugin directory is unavailable."), "runtime-handoff"); WindowsCurrentUserSecurity.EnsureSecureDirectory(text); _handoffTicketPath = Path.Combine(text, "owned-world-resume.json"); _bridgeInstanceId = bridgeInstanceId; _gameVersion = gameVersion; _logger = logger; _logger.LogInfo((object)"Spherewright initialized the protected owned-world resume ticket store"); _currentTicket = ReadFromDisk(); } public void ArmFromHealthySavedOwnedSession(string ownedSaveName, string sessionId, int planetId, long minimumGameTick) { Arm(ownedSaveName, sessionId, planetId, minimumGameTick, string.Empty); _logger.LogInfo((object)"Spherewright armed a one-time exact planned-restart ticket from a healthy owned save"); } public void ArmFromQuarantinedOwnedSession(string ownedSaveName, string sessionId, int planetId, long minimumGameTick, string quarantineActionId) { if (string.IsNullOrWhiteSpace(quarantineActionId)) { throw new InvalidOperationException("A quarantined owned session requires its exact action identity."); } Arm(ownedSaveName, sessionId, planetId, minimumGameTick, quarantineActionId); _logger.LogInfo((object)"Spherewright armed a one-time exact quarantine-recovery ticket"); } private void Arm(string ownedSaveName, string sessionId, int planetId, long minimumGameTick, string quarantineActionId) { if (string.IsNullOrWhiteSpace(ownedSaveName) || string.IsNullOrWhiteSpace(sessionId) || planetId <= 0 || minimumGameTick < 0) { throw new InvalidOperationException("A complete owned-session identity is required to arm restart-resume."); } IReadOnlyList source = CaptureReplicaTokens(); DateTimeOffset utcNow = DateTimeOffset.UtcNow; OwnedWorldResumeTicket ticket = new OwnedWorldResumeTicket { Version = 1, ResumeToken = CreateToken(), OwnedSaveName = ownedSaveName, SourceSessionId = sessionId, SourceProcessId = Process.GetCurrentProcess().Id, SourceBridgeInstanceId = _bridgeInstanceId, GameVersion = _gameVersion, ExpectedPlanetId = planetId, MinimumGameTick = minimumGameTick, QuarantineActionId = quarantineActionId, IssuedAtUtc = utcNow, ExpiresAtUtc = utcNow.AddHours(24.0) }; Persist(ticket); _currentTicket = ticket; _currentTicketPath = null; foreach (string item in source.Where((string token) => !FixedTimeEquals(token, ticket.ResumeToken))) { if (!PersistConsumptionTombstone(item)) { throw new IOException("A superseded resume-ticket generation could not be durably tombstoned."); } DeleteTicketReplicaIfMatching(_ticketPath, item); DeleteTicketReplicaIfMatching(_handoffTicketPath, item); } } public bool TryGetActiveTicket(string resumeToken, out OwnedWorldResumeTicket? ticket, out string rejection) { ticket = null; rejection = string.Empty; if (string.IsNullOrWhiteSpace(resumeToken)) { rejection = "A resume token is required."; return false; } OwnedWorldResumeTicket ownedWorldResumeTicket = _currentTicket ?? ReadFromDisk(); if (ownedWorldResumeTicket == null) { rejection = "No one-time owned-world resume ticket exists."; return false; } if (IsConsumed(ownedWorldResumeTicket.ResumeToken) || ownedWorldResumeTicket.Version != 1 || !FixedTimeEquals(ownedWorldResumeTicket.ResumeToken, resumeToken) || !string.Equals(ownedWorldResumeTicket.GameVersion, _gameVersion, StringComparison.Ordinal) || ownedWorldResumeTicket.ExpiresAtUtc <= DateTimeOffset.UtcNow || string.IsNullOrWhiteSpace(ownedWorldResumeTicket.OwnedSaveName) || string.IsNullOrWhiteSpace(ownedWorldResumeTicket.SourceSessionId) || ownedWorldResumeTicket.ExpectedPlanetId <= 0 || ownedWorldResumeTicket.MinimumGameTick < 0) { rejection = "The one-time owned-world resume ticket is consumed, invalid, expired, or belongs to another game version."; return false; } _currentTicket = ownedWorldResumeTicket; ticket = ownedWorldResumeTicket; return true; } public void Consume(string resumeToken) { OwnedWorldResumeTicket ownedWorldResumeTicket = _currentTicket ?? ReadFromDisk(); if (ownedWorldResumeTicket != null && FixedTimeEquals(ownedWorldResumeTicket.ResumeToken, resumeToken)) { if (!PersistConsumptionTombstone(resumeToken)) { _logger.LogError((object)"Spherewright did not consume the owned-world resume ticket because no durable tombstone could be written"); return; } _currentTicket = null; _currentTicketPath = null; DeleteTicketReplicaIfMatching(_ticketPath, resumeToken); DeleteTicketReplicaIfMatching(_handoffTicketPath, resumeToken); } } private IReadOnlyList CaptureReplicaTokens() { List list = new List(); if (_currentTicket != null) { list.Add(_currentTicket.ResumeToken); } OwnedWorldResumeTicket ownedWorldResumeTicket = ReadFromPath(_ticketPath); OwnedWorldResumeTicket ownedWorldResumeTicket2 = ReadFromPath(_handoffTicketPath); if (ownedWorldResumeTicket != null) { list.Add(ownedWorldResumeTicket.ResumeToken); } if (ownedWorldResumeTicket2 != null) { list.Add(ownedWorldResumeTicket2.ResumeToken); } return list.Where((string token) => !string.IsNullOrWhiteSpace(token)).Distinct(StringComparer.Ordinal).ToArray(); } private void DeleteTicketReplicaIfMatching(string path, string resumeToken) { if (TicketPathMatchesToken(path, resumeToken)) { DeleteTicketPath(path); } } private bool PersistConsumptionTombstone(string resumeToken) { if (string.IsNullOrWhiteSpace(resumeToken)) { return false; } string text = HashToken(resumeToken); OwnedWorldResumeConsumptionTombstone payload = new OwnedWorldResumeConsumptionTombstone { Version = 1, ResumeTokenHash = text, GameVersion = _gameVersion, ConsumedAtUtc = DateTimeOffset.UtcNow }; string text2 = Path.GetDirectoryName(_handoffTicketPath) ?? throw new InvalidOperationException("The owned-world handoff directory is unavailable."); WindowsCurrentUserSecurity.EnsureSecureDirectory(_runtimeDirectory); WindowsCurrentUserSecurity.EnsureSecureDirectory(text2); bool num = TryPersistAtPath(GetTombstonePath(_runtimeDirectory, text), _runtimeDirectory, payload, "runtime consumption tombstone"); bool flag = TryPersistAtPath(GetTombstonePath(text2, text), text2, payload, "handoff consumption tombstone"); return num || flag; } private void DeleteTicketPath(string path) { try { if (File.Exists(path)) { File.Delete(path); } } catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException) { _logger.LogWarning((object)("Spherewright could not consume its owned-world resume ticket (" + ex.GetType().Name + ")")); } } private static bool TicketPathMatchesToken(string path, string resumeToken) { try { if (!File.Exists(path)) { return false; } OwnedWorldResumeTicket ownedWorldResumeTicket = PluginJson.Deserialize(File.ReadAllText(path)); return ownedWorldResumeTicket != null && FixedTimeEquals(ownedWorldResumeTicket.ResumeToken, resumeToken); } catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException || ex is JsonException || ex is ArgumentException) { return false; } } private OwnedWorldResumeTicket? ReadFromDisk() { OwnedWorldResumeTicket ticket = ReadFromPath(_ticketPath); OwnedWorldResumeTicket ticket2 = ReadFromPath(_handoffTicketPath); var array = (from candidate in new[] { new { Ticket = ticket, Path = _ticketPath, Priority = 1 }, new { Ticket = ticket2, Path = _handoffTicketPath, Priority = 0 } } where candidate.Ticket != null && !IsConsumed(candidate.Ticket.ResumeToken) orderby candidate.Ticket.IssuedAtUtc descending, candidate.Priority descending select candidate).ToArray(); if (array.Length == 0) { _currentTicketPath = null; return null; } _currentTicketPath = array[0].Path; return array[0].Ticket; } private bool IsConsumed(string resumeToken) { if (string.IsNullOrWhiteSpace(resumeToken)) { return false; } string tokenHash = HashToken(resumeToken); string directoryName = Path.GetDirectoryName(_handoffTicketPath); if (!TombstoneMatches(GetTombstonePath(_runtimeDirectory, tokenHash), tokenHash)) { if (!string.IsNullOrWhiteSpace(directoryName)) { return TombstoneMatches(GetTombstonePath(directoryName, tokenHash), tokenHash); } return false; } return true; } private bool TombstoneMatches(string path, string tokenHash) { try { if (!File.Exists(path)) { return false; } OwnedWorldResumeConsumptionTombstone ownedWorldResumeConsumptionTombstone = PluginJson.Deserialize(File.ReadAllText(path)); return ownedWorldResumeConsumptionTombstone != null && ownedWorldResumeConsumptionTombstone.Version == 1 && string.Equals(ownedWorldResumeConsumptionTombstone.GameVersion, _gameVersion, StringComparison.Ordinal) && FixedTimeEquals(ownedWorldResumeConsumptionTombstone.ResumeTokenHash, tokenHash); } catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException || ex is JsonException || ex is ArgumentException) { _logger.LogWarning((object)("Spherewright could not read an owned-world resume consumption tombstone (" + ex.GetType().Name + ")")); return false; } } private OwnedWorldResumeTicket? ReadFromPath(string path) { try { string json; using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) { using StreamReader streamReader = new StreamReader(stream, Encoding.UTF8, detectEncodingFromByteOrderMarks: true); json = streamReader.ReadToEnd(); } OwnedWorldResumeTicket ownedWorldResumeTicket = PluginJson.Deserialize(json); if (ownedWorldResumeTicket == null) { _logger.LogWarning((object)"Spherewright ignored an empty owned-world resume ticket payload"); return null; } _logger.LogInfo((object)"Spherewright loaded an owned-world restart-resume ticket from the protected runtime directory"); return ownedWorldResumeTicket; } catch (FileNotFoundException) { _logger.LogInfo((object)"Spherewright found no owned-world resume ticket at a fixed protected path"); return null; } catch (DirectoryNotFoundException) { _logger.LogInfo((object)"Spherewright found no owned-world resume directory at the fixed protected path"); return null; } catch (Exception ex3) when (ex3 is IOException || ex3 is UnauthorizedAccessException || ex3 is JsonException || ex3 is ArgumentException) { _logger.LogWarning((object)("Spherewright ignored an unreadable owned-world resume ticket (" + ex3.GetType().Name + ")")); return null; } } private void Persist(OwnedWorldResumeTicket ticket) { WindowsCurrentUserSecurity.EnsureSecureDirectory(_runtimeDirectory); string text = Path.GetDirectoryName(_handoffTicketPath) ?? throw new InvalidOperationException("The owned-world handoff directory is unavailable."); WindowsCurrentUserSecurity.EnsureSecureDirectory(text); bool num = TryPersistAtPath(_ticketPath, _runtimeDirectory, ticket, "runtime resume-ticket replica"); bool flag = TryPersistAtPath(_handoffTicketPath, text, ticket, "handoff resume-ticket replica"); if (!num && !flag) { throw new IOException("No protected owned-world resume ticket replica could be persisted."); } if (!num || !flag) { _logger.LogWarning((object)"Spherewright armed the resume ticket with one durable replica; startup generation selection will prefer the newest surviving ticket"); } } private static void PersistAtPath(string destinationPath, string directory, object payload) { string text = Path.Combine(directory, $".owned-world-resume-{Guid.NewGuid():N}.tmp"); byte[] bytes = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false).GetBytes(PluginJson.Serialize(payload)); WindowsCurrentUserSecurity.WriteSecureNewFile(text, bytes); try { if (File.Exists(destinationPath)) { File.Replace(text, destinationPath, null, ignoreMetadataErrors: true); } else { File.Move(text, destinationPath); } } finally { if (File.Exists(text)) { File.Delete(text); } } } private bool TryPersistAtPath(string destinationPath, string directory, object payload, string replicaName) { try { PersistAtPath(destinationPath, directory, payload); return true; } catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException || ex is ArgumentException) { _logger.LogWarning((object)("Spherewright could not persist its " + replicaName + " (" + ex.GetType().Name + ")")); return false; } } private static string GetTombstonePath(string directory, string tokenHash) { return Path.Combine(directory, "owned-world-resume-consumed-" + tokenHash + ".json"); } private static string HashToken(string token) { using SHA256 sHA = SHA256.Create(); return BitConverter.ToString(sHA.ComputeHash(Encoding.UTF8.GetBytes(token ?? string.Empty))).Replace("-", string.Empty).ToLowerInvariant(); } private static string CreateToken() { byte[] array = new byte[32]; using (RandomNumberGenerator randomNumberGenerator = RandomNumberGenerator.Create()) { randomNumberGenerator.GetBytes(array); } return Convert.ToBase64String(array).TrimEnd(new char[1] { '=' }).Replace('+', '-') .Replace('/', '_'); } private static bool FixedTimeEquals(string left, string right) { byte[] bytes = Encoding.UTF8.GetBytes(left ?? string.Empty); byte[] bytes2 = Encoding.UTF8.GetBytes(right ?? string.Empty); int num = bytes.Length ^ bytes2.Length; int num2 = Math.Max(bytes.Length, bytes2.Length); for (int i = 0; i < num2; i++) { byte b = (byte)((i < bytes.Length) ? bytes[i] : 0); byte b2 = (byte)((i < bytes2.Length) ? bytes2[i] : 0); num |= b ^ b2; } return num == 0; } } internal sealed class OwnedWorldResumeTicket { public int Version { get; set; } public string ResumeToken { get; set; } = string.Empty; public string OwnedSaveName { get; set; } = string.Empty; public string SourceSessionId { get; set; } = string.Empty; public int SourceProcessId { get; set; } public string SourceBridgeInstanceId { get; set; } = string.Empty; public string GameVersion { get; set; } = string.Empty; public int ExpectedPlanetId { get; set; } public long MinimumGameTick { get; set; } public string QuarantineActionId { get; set; } = string.Empty; public DateTimeOffset IssuedAtUtc { get; set; } public DateTimeOffset ExpiresAtUtc { get; set; } } internal sealed class OwnedWorldResumeConsumptionTombstone { public int Version { get; set; } public string ResumeTokenHash { get; set; } = string.Empty; public string GameVersion { get; set; } = string.Empty; public DateTimeOffset ConsumedAtUtc { get; set; } } internal sealed class RuntimeDescriptorPublisher : IDisposable { private readonly string _runtimeDirectory; private readonly ManualLogSource _logger; private string? _descriptorPath; public RuntimeDescriptorPublisher(string configuredDirectory, ManualLogSource logger) { try { _runtimeDirectory = ResolveRuntimeDirectory(configuredDirectory); } catch (Exception innerException) { throw new InvalidOperationException("Runtime descriptor directory normalization failed.", innerException); } _logger = logger ?? throw new ArgumentNullException("logger"); } internal static string ResolveRuntimeDirectory(string configuredDirectory) { if (configuredDirectory.StartsWith("%LOCALAPPDATA%", StringComparison.OrdinalIgnoreCase)) { string folderPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); if (string.IsNullOrWhiteSpace(folderPath)) { throw new InvalidOperationException("The local application-data directory is unavailable."); } string path = configuredDirectory.Substring("%LOCALAPPDATA%".Length).TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); return Path.GetFullPath(Path.Combine(folderPath, path).Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar)); } string path2 = Environment.ExpandEnvironmentVariables(configuredDirectory).Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); if (!Path.IsPathRooted(path2)) { throw new InvalidOperationException("The runtime descriptor directory must be an absolute path."); } return Path.GetFullPath(path2); } public void Publish(BridgeRuntimeDescriptor descriptor) { if (descriptor == null) { throw new ArgumentNullException("descriptor"); } EnsureSecureDirectory(); CleanupStaleDescriptors(); string text = Path.Combine(_runtimeDirectory, $"bridge-{descriptor.ProcessId}.json"); string text2 = Path.Combine(_runtimeDirectory, $".bridge-{descriptor.ProcessId}-{Guid.NewGuid():N}.tmp"); string s = PluginJson.Serialize(descriptor); WindowsCurrentUserSecurity.WriteSecureNewFile(text2, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false).GetBytes(s)); File.Move(text2, text); _descriptorPath = text; } public void Dispose() { string descriptorPath = _descriptorPath; _descriptorPath = null; if (descriptorPath == null) { return; } try { if (File.Exists(descriptorPath)) { File.Delete(descriptorPath); } } catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException) { _logger.LogWarning((object)("Spherewright could not remove its runtime descriptor (" + ex.GetType().Name + ")")); } } private void EnsureSecureDirectory() { WindowsCurrentUserSecurity.EnsureSecureDirectory(_runtimeDirectory); } private void CleanupStaleDescriptors() { string[] files = Directory.GetFiles(_runtimeDirectory, "bridge-*.json", SearchOption.TopDirectoryOnly); foreach (string path in files) { try { BridgeRuntimeDescriptor val = PluginJson.Deserialize(File.ReadAllText(path)); if (val == null || !IsLiveDspProcess(val.ProcessId)) { File.Delete(path); } } catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException || ex is JsonException || ex is ArgumentException) { _logger.LogWarning((object)("Spherewright ignored an unreadable stale descriptor candidate (" + ex.GetType().Name + ")")); } } } private static bool IsLiveDspProcess(int processId) { try { using Process process = Process.GetProcessById(processId); return !process.HasExited && string.Equals(process.ProcessName, "DSPGAME", StringComparison.OrdinalIgnoreCase); } catch (Exception ex) when (ex is ArgumentException || ex is InvalidOperationException || ex is Win32Exception) { return false; } } } } namespace Spherewright.Plugin.Hosting { internal sealed class BridgeIdentity { public string BridgeInstanceId { get; } public string PipeName { get; } public string AuthToken { get; } private BridgeIdentity(string bridgeInstanceId, string pipeName, string authToken) { BridgeInstanceId = bridgeInstanceId; PipeName = pipeName; AuthToken = authToken; } public static BridgeIdentity Create(string pipeNamePrefix) { int id = Process.GetCurrentProcess().Id; string arg = Base64Url(RandomBytes(12)); string authToken = Base64Url(RandomBytes(32)); return new BridgeIdentity(Guid.NewGuid().ToString("N"), $"{pipeNamePrefix}-{id}-{arg}", authToken); } private static byte[] RandomBytes(int count) { byte[] array = new byte[count]; using RandomNumberGenerator randomNumberGenerator = RandomNumberGenerator.Create(); randomNumberGenerator.GetBytes(array); return array; } private static string Base64Url(byte[] bytes) { return Convert.ToBase64String(bytes).TrimEnd(new char[1] { '=' }).Replace('+', '-') .Replace('/', '_'); } } internal sealed class BridgeStatusSnapshotProvider { private readonly object _gate = new object(); private readonly string _bridgeInstanceId; private readonly string _pluginVersion; private readonly bool _writesConfigured; private string _gameVersion; private bool _gameLoaded; public BridgeStatusSnapshotProvider(string bridgeInstanceId, string pluginVersion, string gameVersion, bool writesConfigured) { _bridgeInstanceId = bridgeInstanceId; _pluginVersion = pluginVersion; _gameVersion = gameVersion; _writesConfigured = writesConfigured; } public void UpdateGameVersionOnMainThread(string gameVersion) { lock (_gate) { _gameVersion = gameVersion; } } public void UpdateGameLoadedOnMainThread(bool gameLoaded) { lock (_gate) { _gameLoaded = gameLoaded; } } public BridgeStatus Capture() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected O, but got Unknown lock (_gate) { return new BridgeStatus { BridgeConnected = true, BridgeInstanceId = _bridgeInstanceId, PluginVersion = _pluginVersion, ProtocolVersion = 1, GameVersion = _gameVersion, GameLoaded = _gameLoaded, WritesConfigured = _writesConfigured, WriteHealth = "healthy" }; } } } internal sealed class SpherewrightBridgeHost : IDisposable { private readonly SpherewrightConfiguration _configuration; private readonly ManualLogSource _logger; private readonly GameVersionSnapshotProvider _gameVersionProvider; private readonly GameSessionTracker _sessionTracker; private readonly GameplayJournalManager _gameplayJournalManager; private readonly NormalGameActionCoordinator _normalActionCoordinator; private readonly ResearchResultAutoAcknowledger _researchResultAutoAcknowledger; private readonly BridgeStatusSnapshotProvider _statusProvider; private readonly BoundedMainThreadDispatcher _dispatcher; private readonly RuntimeDescriptorPublisher _descriptorPublisher; private readonly NamedPipeBridgeServer _pipeServer; private readonly BridgeRuntimeDescriptor _descriptor; private bool _started; private bool _pumpLogged; private int _framesSinceVersionRefresh; private SpherewrightBridgeHost(SpherewrightConfiguration configuration, ManualLogSource logger, GameVersionSnapshotProvider gameVersionProvider, GameSessionTracker sessionTracker, GameplayJournalManager gameplayJournalManager, NormalGameActionCoordinator normalActionCoordinator, ResearchResultAutoAcknowledger researchResultAutoAcknowledger, BridgeStatusSnapshotProvider statusProvider, BoundedMainThreadDispatcher dispatcher, RuntimeDescriptorPublisher descriptorPublisher, NamedPipeBridgeServer pipeServer, BridgeRuntimeDescriptor descriptor) { _configuration = configuration; _logger = logger; _gameVersionProvider = gameVersionProvider; _sessionTracker = sessionTracker; _gameplayJournalManager = gameplayJournalManager; _normalActionCoordinator = normalActionCoordinator; _researchResultAutoAcknowledger = researchResultAutoAcknowledger; _statusProvider = statusProvider; _dispatcher = dispatcher; _descriptorPublisher = descriptorPublisher; _pipeServer = pipeServer; _descriptor = descriptor; } public static SpherewrightBridgeHost Create(SpherewrightConfiguration configuration, ManualLogSource logger, string pluginVersion) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Expected O, but got Unknown BridgeIdentity bridgeIdentity = BridgeIdentity.Create(configuration.PipeNamePrefix); GameVersionSnapshotProvider gameVersionSnapshotProvider = new GameVersionSnapshotProvider(); string gameVersion = gameVersionSnapshotProvider.CaptureOnMainThread(); BridgeStatusSnapshotProvider statusProvider = new BridgeStatusSnapshotProvider(bridgeIdentity.BridgeInstanceId, pluginVersion, gameVersion, configuration.AllowWrites); BoundedMainThreadDispatcher dispatcher = new BoundedMainThreadDispatcher(configuration.MaxMainThreadQueue); OwnedWorldResumeTicketStore ownedWorldResumeTicketStore = new OwnedWorldResumeTicketStore(configuration.RuntimeDescriptorDirectory, bridgeIdentity.BridgeInstanceId, gameVersion, logger); FlightCheckpointStore flightCheckpointStore = new FlightCheckpointStore(bridgeIdentity.BridgeInstanceId, gameVersion, logger); GameSessionTracker gameSessionTracker = new GameSessionTracker(configuration.AllowWrites, configuration.AllowUserSaveImport, gameVersion, ownedWorldResumeTicketStore, flightCheckpointStore, logger); UserSaveImportCoordinator userSaveImportCoordinator = new UserSaveImportCoordinator(configuration.AllowUserSaveImport, configuration.AllowWrites, configuration.PlanTokenLifetimeSeconds, configuration.IdempotencyRetentionMinutes, configuration.MaxIdempotencyEntriesPerSession, gameSessionTracker); GameStateReader gameStateReader = new GameStateReader(gameSessionTracker); GameplayJournalManager gameplayJournalManager = new GameplayJournalManager(configuration.RuntimeDescriptorDirectory, gameVersion, gameSessionTracker, logger); NormalGameActionCoordinator normalGameActionCoordinator = new NormalGameActionCoordinator(configuration.PlanTokenLifetimeSeconds, configuration.IdempotencyRetentionMinutes, configuration.MaxIdempotencyEntriesPerSession, gameSessionTracker, gameStateReader, flightCheckpointStore); ResearchResultAutoAcknowledger researchResultAutoAcknowledger = new ResearchResultAutoAcknowledger(configuration.AutoAcknowledgeResearchResults, logger); TestWorldCoordinator testWorldCoordinator = new TestWorldCoordinator(configuration.AllowWrites, configuration.PlanTokenLifetimeSeconds, configuration.IdempotencyRetentionMinutes, configuration.MaxIdempotencyEntriesPerSession, gameSessionTracker); OwnedWorldResumeCoordinator ownedWorldResumeCoordinator = new OwnedWorldResumeCoordinator(configuration.AllowWrites, configuration.PlanTokenLifetimeSeconds, configuration.IdempotencyRetentionMinutes, configuration.MaxIdempotencyEntriesPerSession, gameSessionTracker, ownedWorldResumeTicketStore); FlightCheckpointReloadCoordinator flightCheckpointReloadCoordinator = new FlightCheckpointReloadCoordinator(configuration.AllowWrites, configuration.PlanTokenLifetimeSeconds, configuration.IdempotencyRetentionMinutes, configuration.MaxIdempotencyEntriesPerSession, gameSessionTracker, flightCheckpointStore, normalGameActionCoordinator); RuntimeDescriptorPublisher descriptorPublisher = new RuntimeDescriptorPublisher(configuration.RuntimeDescriptorDirectory, logger); NamedPipeBridgeServer pipeServer = new NamedPipeBridgeServer(bridgeIdentity, pluginVersion, configuration.MaxFrameBytes, configuration.ReadRequestTimeoutSeconds, statusProvider, dispatcher, gameStateReader, gameplayJournalManager, testWorldCoordinator, userSaveImportCoordinator, ownedWorldResumeCoordinator, flightCheckpointReloadCoordinator, normalGameActionCoordinator, logger); BridgeRuntimeDescriptor descriptor = new BridgeRuntimeDescriptor { ProcessId = Process.GetCurrentProcess().Id, BridgeInstanceId = bridgeIdentity.BridgeInstanceId, PipeName = bridgeIdentity.PipeName, AuthToken = bridgeIdentity.AuthToken, ProtocolVersion = 1, PluginVersion = pluginVersion, CreatedAtUtc = DateTimeOffset.UtcNow }; return new SpherewrightBridgeHost(configuration, logger, gameVersionSnapshotProvider, gameSessionTracker, gameplayJournalManager, normalGameActionCoordinator, researchResultAutoAcknowledger, statusProvider, dispatcher, descriptorPublisher, pipeServer, descriptor); } public void Start() { if (_started) { throw new InvalidOperationException("Spherewright bridge host is already started."); } try { _pipeServer.Start(); _descriptorPublisher.Publish(_descriptor); _started = true; } catch { _pipeServer.Dispose(); _descriptorPublisher.Dispose(); throw; } } public void PumpMainThread() { if (_started) { _sessionTracker.UpdateOnMainThread(); _statusProvider.UpdateGameLoadedOnMainThread(_sessionTracker.GameLoaded); _gameplayJournalManager.UpdateOnMainThread(); _normalActionCoordinator.UpdateOnMainThread(); _researchResultAutoAcknowledger.UpdateOnMainThread(); _dispatcher.Pump(_configuration.MaxRequestsPerFrame, TimeSpan.FromMilliseconds(_configuration.FrameBudgetMs)); _framesSinceVersionRefresh++; if (_framesSinceVersionRefresh >= 120) { _framesSinceVersionRefresh = 0; _statusProvider.UpdateGameVersionOnMainThread(_gameVersionProvider.CaptureOnMainThread()); } if (!_pumpLogged) { _pumpLogged = true; _logger.LogInfo((object)"Spherewright main-thread pump active"); } } } public void Dispose() { if (_started) { _started = false; _gameplayJournalManager.Dispose(); _pipeServer.Dispose(); _descriptorPublisher.Dispose(); _dispatcher.Dispose(); } } } } namespace Spherewright.Plugin.Game { internal static class AssemblerCursorCodec { public static string Encode(string sessionId, long revision, int nextComponentId) { string s = $"{sessionId}|{revision}|{nextComponentId}"; return Convert.ToBase64String(Encoding.UTF8.GetBytes(s)); } public static bool TryDecode(string? cursor, out string sessionId, out long revision, out int nextComponentId) { sessionId = string.Empty; revision = 0L; nextComponentId = 1; if (string.IsNullOrWhiteSpace(cursor)) { return true; } try { string[] array = Encoding.UTF8.GetString(Convert.FromBase64String(cursor)).Split(new char[1] { '|' }); if (array.Length != 3 || string.IsNullOrWhiteSpace(array[0]) || !long.TryParse(array[1], out revision) || !int.TryParse(array[2], out nextComponentId) || nextComponentId <= 0) { return false; } sessionId = array[0]; return true; } catch (FormatException) { return false; } } } internal sealed class FlightCheckpointReloadCoordinator { private sealed class ReloadPlanPayload { public FlightCheckpointTicket Ticket { get; } public string Fingerprint { get; } public ReloadPlanPayload(FlightCheckpointTicket ticket) { Ticket = ticket; Fingerprint = CanonicalStateHash.Combine("reload-flight-checkpoint", new object[13] { ticket.CheckpointId, ticket.ReloadToken, ticket.CheckpointSaveName, ticket.OwnedSaveName, ticket.SourceSessionId, ticket.SourceRevision, ticket.GameVersion, ticket.OriginPlanetId, ticket.DestinationPlanetId, ticket.SavedGameTick, ticket.PlayerStateHash, ticket.StarSystemStateHash, ticket.IssuedAtUtc }); } } private sealed class ReloadAction { public string ActionId { get; set; } = string.Empty; public FlightCheckpointTicket Ticket { get; set; } } private const string IdempotencyScope = "reload-flight-checkpoint"; private readonly bool _writesConfigured; private readonly GameSessionTracker _sessions; private readonly FlightCheckpointStore _tickets; private readonly NormalGameActionCoordinator _normalActions; private readonly PreparedPlanStore _plans; private readonly IdempotencyCache _idempotency; private readonly Dictionary _actions = new Dictionary(StringComparer.Ordinal); public FlightCheckpointReloadCoordinator(bool writesConfigured, int planLifetimeSeconds, int idempotencyRetentionMinutes, int idempotencyCapacity, GameSessionTracker sessions, FlightCheckpointStore tickets, NormalGameActionCoordinator normalActions) { _writesConfigured = writesConfigured; _sessions = sessions; _tickets = tickets; _normalActions = normalActions; _plans = new PreparedPlanStore(TimeSpan.FromSeconds(planLifetimeSeconds), 4, (Func)null); _idempotency = new IdempotencyCache(idempotencyCapacity, TimeSpan.FromMinutes(idempotencyRetentionMinutes), (Func)null); } public GameCallResult PrepareOnMainThread(PrepareFlightCheckpointReloadRequest request) { //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: 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_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Expected O, but got Unknown //IL_00a3: 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_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Expected O, but got Unknown if (!_tickets.TryGetActiveTicket(request.ReloadToken, out FlightCheckpointTicket ticket, out string rejection) || ticket == null) { return GameCallResult.Failed(BridgeError.Create("SESSION_NOT_OWNED", rejection, false, "Use only the reusable reload token exposed for the exact pre-flight checkpoint.")); } if (!TryValidateReloadContext(ticket, out string rejection2)) { return GameCallResult.Failed(BridgeError.Create("STALE_STATE", rejection2, true, "Wait for a clear flight failure or an idle main menu, then prepare the same exact checkpoint again.")); } ReloadPlanPayload reloadPlanPayload = new ReloadPlanPayload(ticket); PreparedPlan val; try { val = _plans.Add(reloadPlanPayload.Fingerprint, reloadPlanPayload); } catch (InvalidOperationException) { return GameCallResult.Failed(BridgeError.Create("SERVER_BUSY", "Too many flight-checkpoint reload plans are active.", true, "Wait for old plans to expire, then prepare the same checkpoint again.")); } List list = new List(); if (!_writesConfigured) { list.Add(new WriteBlocker { Code = "WRITES_DISABLED", Message = "Flight-checkpoint reload is blocked because Safety.AllowWrites is false." }); } return GameCallResult.Succeeded(new PreparedFlightCheckpointReloadPlan { Prepared = true, PlanToken = val.Token, ExpiresAtUtc = val.ExpiresAtUtc, CheckpointId = ticket.CheckpointId, OriginPlanetId = ticket.OriginPlanetId, DestinationPlanetId = ticket.DestinationPlanetId, SavedGameTick = ticket.SavedGameTick, CommitAllowedNow = (list.Count == 0), CommitBlockers = list, CompletionCondition = "DSP loads only the internally generated pre-flight save whose exact name and game tick match the protected reusable ticket; the embedded primary owned-save identity, origin planet, and peaceful mode must match before adoption. Sandbox state and resource multiplier are preserved and reported but do not gate adoption." }); } public GameCallResult CommitOnMainThread(CommitFlightCheckpointReloadRequest request) { //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Expected O, but got Unknown if (!Guid.TryParse(request.IdempotencyKey, out var _)) { return GameCallResult.Failed(BridgeError.Create("INVALID_REQUEST", "A UUID idempotency key is required.", false, "Generate one UUID and reuse it only for retries of this exact checkpoint reload commit.")); } string text = "commit-reload-flight-checkpoint|" + request.PlanToken; FlightCheckpointReloadResult result2 = default(FlightCheckpointReloadResult); bool flag = default(bool); if (_idempotency.TryGet("reload-flight-checkpoint", request.IdempotencyKey, text, ref result2, ref flag)) { return GameCallResult.Succeeded(CloneAsReplay(result2)); } if (flag) { return GameCallResult.Failed(BridgeError.Create("IDEMPOTENCY_CONFLICT", "The idempotency key is already bound to another checkpoint reload.", false, "Reuse it only for the original reload or generate a new UUID after preparing a new retry.")); } if (!_writesConfigured) { return GameCallResult.Failed(BridgeError.Create("WRITES_DISABLED", "Flight-checkpoint reload is blocked because Safety.AllowWrites is false.", false, "Enable writes and prepare the exact checkpoint again.")); } if (!_idempotency.HasCapacity("reload-flight-checkpoint")) { return GameCallResult.Failed(BridgeError.Create("IDEMPOTENCY_CAPACITY_EXCEEDED", "The idempotency cache has no capacity for another flight-checkpoint reload.", false, "Restart the Plugin without loading another save, then use the same protected checkpoint token.")); } PreparedPlan val = default(PreparedPlan); bool flag2 = default(bool); if (!_plans.TryTake(request.PlanToken, ref val, ref flag2) || val == null) { return GameCallResult.Failed(BridgeError.Create(flag2 ? "PLAN_EXPIRED" : "PLAN_NOT_FOUND", flag2 ? "The flight-checkpoint reload plan expired." : "The flight-checkpoint reload plan was not found or was already consumed.", true, "Prepare the same exact checkpoint again and commit it once.")); } ReloadPlanPayload payload = val.Payload; string rejection = "The reusable flight-checkpoint ticket changed after prepare."; if (!_tickets.TryGetActiveTicket(payload.Ticket.ReloadToken, out FlightCheckpointTicket ticket, out string _) || ticket == null || !string.Equals(new ReloadPlanPayload(ticket).Fingerprint, payload.Fingerprint, StringComparison.Ordinal) || !TryValidateReloadContext(ticket, out rejection)) { return GameCallResult.Failed(BridgeError.Create("STALE_STATE", rejection, true, "Do not load another save; inspect the exact checkpoint state and prepare it again.")); } ReloadAction reloadAction = new ReloadAction { ActionId = Guid.NewGuid().ToString("D"), Ticket = ticket }; try { _normalActions.NotifyFlightCheckpointReloadStartingOnMainThread(ticket); _sessions.ExpectNextSessionToBeLoadedFromFlightCheckpoint(ticket); DSPGame.StartGame(ticket.CheckpointSaveName); } catch (Exception ex) { _sessions.CancelExpectedFlightCheckpointSession(); return GameCallResult.Failed(BridgeError.Create("ACTION_FAILED", "DSP rejected the exact pre-flight checkpoint through its normal loader (" + ex.GetType().Name + ").", false, "Keep the same checkpoint token, inspect local logs, and do not load another save.")); } FlightCheckpointReloadResult val2 = new FlightCheckpointReloadResult { ActionId = reloadAction.ActionId, CheckpointId = ticket.CheckpointId, Accepted = true, IdempotentReplay = false, State = "waiting_for_game" }; if (!_idempotency.TryAdd("reload-flight-checkpoint", request.IdempotencyKey, text, val2)) { return GameCallResult.Failed(BridgeError.Create("IDEMPOTENCY_CAPACITY_EXCEEDED", "The idempotency cache reached capacity after DSP accepted the exact checkpoint load.", false, "Do not retry with a new key; inspect session state and the returned action ID.")); } _actions[reloadAction.ActionId] = reloadAction; return GameCallResult.Succeeded(val2); } public bool TryGetActionResultOnMainThread(string actionId, out ActionResultSnapshot? result) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0033: 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_0049: 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_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Expected O, but got Unknown if (!_actions.TryGetValue(actionId, out ReloadAction value)) { result = null; return false; } SessionState val = _sessions.CaptureOnMainThread(); result = new ActionResultSnapshot { ActionId = value.ActionId, ActionKind = "reload-flight-checkpoint", State = "waiting_for_game", Terminal = false, Succeeded = false, FlightCheckpointId = value.Ticket.CheckpointId, FlightCheckpointReloadToken = value.Ticket.ReloadToken, FlightCheckpointGameTick = value.Ticket.SavedGameTick, Message = "DSP accepted the exact internally named pre-flight checkpoint; Spherewright is validating its reusable provenance proof." }; if (val.OwnedBySpherewright && val.CurrentSessionLoadedFromFlightCheckpoint && string.Equals(val.FlightCheckpointId, value.Ticket.CheckpointId, StringComparison.Ordinal) && val.LocalPlanetId == value.Ticket.OriginPlanetId && val.GameTick >= value.Ticket.SavedGameTick) { result.State = "completed"; result.Terminal = true; result.Succeeded = true; result.SessionId = val.SessionId; result.PlanetId = val.LocalPlanetId; result.Message = "The exact pre-flight checkpoint passed provenance checks and is ready to retry the same flight; the primary owned save was not replaced."; } else if (!string.IsNullOrWhiteSpace(_sessions.FlightCheckpointAdoptionError)) { result.State = "action_failed"; result.Terminal = true; result.Message = _sessions.FlightCheckpointAdoptionError; } return true; } private bool TryValidateReloadContext(FlightCheckpointTicket ticket, out string rejection) { if (!_tickets.TryValidateCheckpointFile(ticket, out rejection)) { return false; } SessionState val = _sessions.CaptureOnMainThread(); if (val.GameLoaded) { if (!val.OwnedBySpherewright || !string.Equals(val.SaveName, ticket.OwnedSaveName, StringComparison.Ordinal)) { rejection = "An active game may be replaced only by a checkpoint bound to that exact owned save."; return false; } if (!FlightCheckpointStore.IsRecoveryRequired(ticket)) { rejection = "The bound flight has not reached a persisted recovery-required state."; return false; } if (!val.CurrentSessionLoadedFromFlightCheckpoint && !_normalActions.HasRecoveryRequiredFlightOnMainThread(ticket.CheckpointId)) { rejection = "The current process has no terminal failed-flight evidence for this checkpoint."; return false; } } else { BridgeError val2 = TestWorldCoordinator.ValidateMainMenuReady(); if (val2 != null) { rejection = val2.Message; return false; } if (!FlightCheckpointStore.IsRecoveryRequired(ticket) && (!FlightCheckpointStore.IsAttemptInFlight(ticket) || IsLiveDspProcess(ticket.SourceProcessId))) { rejection = "The checkpoint is neither recovery-required nor an interrupted in-flight attempt from a terminated DSP process."; return false; } } return _normalActions.CanReloadFlightCheckpointOnMainThread(ticket, out rejection); } private static bool IsLiveDspProcess(int processId) { try { using Process process = Process.GetProcessById(processId); return !process.HasExited && string.Equals(process.ProcessName, "DSPGAME", StringComparison.OrdinalIgnoreCase); } catch (Exception ex) when (ex is ArgumentException || ex is InvalidOperationException || ex is Win32Exception) { return false; } } private static FlightCheckpointReloadResult CloneAsReplay(FlightCheckpointReloadResult result) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown return new FlightCheckpointReloadResult { ActionId = result.ActionId, CheckpointId = result.CheckpointId, Accepted = result.Accepted, IdempotentReplay = true, State = result.State }; } } internal sealed class GameCallResult { public bool Success => Error == null; public T? Value { get; } public BridgeError? Error { get; } private GameCallResult(T? value, BridgeError? error) { Value = value; Error = error; } public static GameCallResult Succeeded(T value) { return new GameCallResult(value, null); } public static GameCallResult Failed(BridgeError error) { return new GameCallResult(default(T), error); } } internal sealed class GameplayJournalManager : IDisposable { private const int DocumentVersion = 1; private const int ManualRecipeFeatureBase = 2140000; private const int LifetimeProductionTotalIndex = 6; private readonly string _journalDirectory; private readonly string _gameVersion; private readonly GameSessionTracker _sessions; private readonly ManualLogSource _logger; private string? _activeSessionId; private string? _activePath; private GameplayJournalDocument? _document; private GameplayFirstOccurrenceDetector? _detector; private long _lastScannedGameTick = -1L; private long _durableThroughSequence; private bool _pendingPersist; private string? _persistenceError; public GameplayJournalManager(string configuredRuntimeDirectory, string gameVersion, GameSessionTracker sessions, ManualLogSource logger) { string path = RuntimeDescriptorPublisher.ResolveRuntimeDirectory(configuredRuntimeDirectory); _journalDirectory = Path.Combine(path, "journals"); _gameVersion = gameVersion; _sessions = sessions; _logger = logger; } public void UpdateOnMainThread() { if (!_sessions.IsCurrentSessionOwned || string.IsNullOrWhiteSpace(_sessions.SessionId) || string.IsNullOrWhiteSpace(_sessions.OwnedSaveName) || GameMain.data == null) { ResetActiveSession(); return; } if (!string.Equals(_activeSessionId, _sessions.SessionId, StringComparison.Ordinal)) { AttachToCurrentOwnedSession(); } if (_document == null || _detector == null || (_pendingPersist && !TryPersist())) { return; } long gameTick = GameMain.gameTick; if (gameTick == _lastScannedGameTick) { return; } _lastScannedGameTick = gameTick; bool flag = false; Dictionary dictionary = CaptureManualProductionCounts(); foreach (GameplayItemFirstOccurrence item in _detector.ObserveManualCounts((IReadOnlyDictionary)dictionary)) { AddItemEntry(item, "mecha-forge-feature-counter", gameTick); flag = true; } Dictionary dictionary2 = CaptureProductionLineRegisterCounts(); foreach (GameplayItemFirstOccurrence item2 in _detector.ObserveProductionLineCounts((IReadOnlyDictionary)dictionary2)) { AddItemEntry(item2, "factory-production-register", gameTick); flag = true; } GameHistoryData history = GameMain.history; if (history != null) { if (history.currentTech > 0) { flag |= TryAddResearchEntry(history.currentTech, gameTick); } if (history.techQueue != null) { int[] techQueue = history.techQueue; foreach (int num in techQueue) { if (num > 0) { flag |= TryAddResearchEntry(num, gameTick); } } } } if (flag) { _pendingPersist = true; TryPersist(); } } public GameCallResult CaptureOnMainThread(string? requestedSessionId) { //IL_00bf: 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_00d5: 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_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Expected O, but got Unknown UpdateOnMainThread(); if (!_sessions.GameLoaded) { return GameCallResult.Failed(BridgeError.Create("GAME_NOT_LOADED", "No ordinary game is loaded.", true, "Load the exact owned world and retry.")); } if (!_sessions.IsCurrentSessionOwned) { return GameCallResult.Failed(BridgeError.Create("SESSION_NOT_OWNED", "Gameplay journals are private to a Spherewright-owned world.", false, "Resume the exact owned world through its protected provenance flow.")); } if (string.IsNullOrWhiteSpace(requestedSessionId) || !string.Equals(requestedSessionId, _sessions.SessionId, StringComparison.Ordinal)) { return GameCallResult.Failed(BridgeError.Create("STALE_SESSION", "The requested journal session is stale.", true, "Read the current session state and retry with its session ID.")); } if (_document == null) { return GameCallResult.Failed(BridgeError.Create("BRIDGE_NOT_READY", "The per-save gameplay journal is unavailable.", true, (_persistenceError == null) ? "Retry after the owned world finishes loading." : "Inspect the protected journal directory and Plugin log before continuing milestone work.")); } return GameCallResult.Succeeded(new GameplayJournalSnapshot { SessionId = _sessions.SessionId, JournalId = _document.JournalId, TrackingMode = _document.TrackingMode, HistoricalCoverageComplete = _document.HistoricalCoverageComplete, CreatedAtActualTime = _document.CreatedAtActualTime, TrackingStartedAtGameTick = _document.TrackingStartedAtGameTick, TrackingStartedAtGameTime = _document.TrackingStartedAtGameTime, CapturedAtGameTick = GameMain.gameTick, DurableThroughSequence = _durableThroughSequence, PersistencePending = _pendingPersist, PersistenceError = _persistenceError, Entries = _document.Entries.Select(CloneEntry).ToList() }); } public void Dispose() { if (_pendingPersist) { TryPersist(); } ResetActiveSession(); } private void AttachToCurrentOwnedSession() { ResetActiveSession(); string sessionId = _sessions.SessionId; string text = HashOwnedIdentity(_sessions.OwnedSaveName); string text2 = text; string text3 = Path.Combine(_journalDirectory, "gameplay-" + text2 + ".json"); try { WindowsCurrentUserSecurity.EnsureSecureDirectory(_journalDirectory); GameplayJournalDocument gameplayJournalDocument = null; if (File.Exists(text3)) { gameplayJournalDocument = PluginJson.Deserialize(File.ReadAllText(text3)); if (gameplayJournalDocument == null || gameplayJournalDocument.Version != 1 || !string.Equals(gameplayJournalDocument.JournalId, text2, StringComparison.Ordinal) || !string.Equals(gameplayJournalDocument.OwnedSaveIdentityHash, text, StringComparison.Ordinal) || !string.Equals(gameplayJournalDocument.GameVersion, _gameVersion, StringComparison.Ordinal)) { throw new InvalidDataException("The protected gameplay journal identity did not match the owned save."); } } if (gameplayJournalDocument == null) { gameplayJournalDocument = CreateDocument(text2, text); } _activeSessionId = sessionId; _activePath = text3; _document = gameplayJournalDocument; _detector = CreateDetector(gameplayJournalDocument); _lastScannedGameTick = -1L; bool flag = File.Exists(text3); _durableThroughSequence = (flag ? gameplayJournalDocument.Entries.Select((GameplayJournalEntry entry) => entry.Sequence).DefaultIfEmpty(0L).Max() : 0); _pendingPersist = !flag; _persistenceError = null; if (!_pendingPersist || TryPersist()) { _logger.LogInfo((object)"Spherewright attached the protected per-save gameplay journal"); } } catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException || ex is InvalidDataException || ex is JsonException || ex is ArgumentException) { _activeSessionId = sessionId; _activePath = null; _document = null; _detector = null; _persistenceError = ex.GetType().Name; _logger.LogError((object)("Spherewright gameplay journal attachment failed (" + _persistenceError + ")")); } } private GameplayJournalDocument CreateDocument(string journalId, string identityHash) { bool currentOwnedSessionStartedAsNewGame = _sessions.CurrentOwnedSessionStartedAsNewGame; long gameTick = GameMain.gameTick; GameplayJournalDocument gameplayJournalDocument = new GameplayJournalDocument { Version = 1, JournalId = journalId, OwnedSaveIdentityHash = identityHash, GameVersion = _gameVersion, TrackingMode = (currentOwnedSessionStartedAsNewGame ? "from_new_game" : "attached_existing_save"), HistoricalCoverageComplete = currentOwnedSessionStartedAsNewGame, CreatedAtActualTime = FormatActualTime(DateTimeOffset.Now), TrackingStartedAtGameTick = gameTick, TrackingStartedAtGameTime = FormatGameTime(gameTick) }; if (!currentOwnedSessionStartedAsNewGame) { Dictionary manualCounts = CaptureManualProductionCounts(); gameplayJournalDocument.HistoricalManualItemIds = (from itemId in (from pair in manualCounts where pair.Value > 0 select pair.Key).Distinct() orderby itemId select itemId).ToList(); Dictionary source = CaptureLifetimeProductionCounts(); gameplayJournalDocument.HistoricalProductionLineItemIds = (from itemId in (from pair in source where pair.Value - GetCount(manualCounts, pair.Key) > 0 select pair.Key).Distinct() orderby itemId select itemId).ToList(); gameplayJournalDocument.HistoricalResearchIds = CaptureHistoricalResearchIds(); } return gameplayJournalDocument; } private static GameplayFirstOccurrenceDetector CreateDetector(GameplayJournalDocument document) { //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Expected O, but got Unknown IEnumerable second = from entry in document.Entries where string.Equals(entry.Kind, "manual_item_first", StringComparison.Ordinal) select entry.ItemId; IEnumerable second2 = from entry in document.Entries where string.Equals(entry.Kind, "production_line_item_first", StringComparison.Ordinal) select entry.ItemId; IEnumerable second3 = from entry in document.Entries where string.Equals(entry.Kind, "technology_first_selected", StringComparison.Ordinal) || string.Equals(entry.Kind, "upgrade_first_selected", StringComparison.Ordinal) select entry.TechId; return new GameplayFirstOccurrenceDetector(document.HistoricalManualItemIds.Concat(second), document.HistoricalProductionLineItemIds.Concat(second2), document.HistoricalResearchIds.Concat(second3)); } private void AddItemEntry(GameplayItemFirstOccurrence occurrence, string source, long gameTick) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0079: 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_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Expected O, but got Unknown List entries = _document.Entries; GameplayJournalEntry val = new GameplayJournalEntry { Sequence = (long)_document.Entries.Count + 1L, Kind = occurrence.Kind, ItemId = occurrence.ItemId }; ItemProto obj = ((ProtoSet)(object)LDB.items).Select(occurrence.ItemId); val.Name = ((obj != null) ? ((Proto)obj).name : null) ?? string.Empty; val.ObservedCount = occurrence.ObservedCount; val.ActualTime = FormatActualTime(DateTimeOffset.Now); val.GameTick = gameTick; val.GameTime = FormatGameTime(gameTick); val.Source = source; entries.Add(val); } private bool TryAddResearchEntry(int techId, long gameTick) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: 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_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Expected O, but got Unknown if (!_detector.TryObserveResearchSelection(techId)) { return false; } TechProto val = ((ProtoSet)(object)LDB.techs).Select(techId); if (val == null) { return false; } _document.Entries.Add(new GameplayJournalEntry { Sequence = (long)_document.Entries.Count + 1L, Kind = ((val.page == 0) ? "technology_first_selected" : "upgrade_first_selected"), TechId = techId, Name = (((Proto)val).name ?? string.Empty), ObservedCount = 1L, ActualTime = FormatActualTime(DateTimeOffset.Now), GameTick = gameTick, GameTime = FormatGameTime(gameTick), Source = "normal-research-queue" }); return true; } private static Dictionary CaptureManualProductionCounts() { Dictionary dictionary = new Dictionary(); GameHistoryData history = GameMain.history; if (history == null || ((ProtoSet)(object)LDB.recipes)?.dataArray == null) { return dictionary; } RecipeProto[] dataArray = ((ProtoSet)(object)LDB.recipes).dataArray; foreach (RecipeProto val in dataArray) { if (val == null || ((Proto)val).ID <= 0 || !val.Handcraft) { continue; } int featureValue = history.GetFeatureValue(2140000 + ((Proto)val).ID); if (featureValue <= 0 || val.Results == null || val.ResultCounts == null) { continue; } int num = Math.Min(val.Results.Length, val.ResultCounts.Length); for (int j = 0; j < num; j++) { int num2 = val.Results[j]; checked { long num3 = unchecked((long)featureValue) * unchecked((long)val.ResultCounts[j]); if (num2 > 0 && num3 > 0) { AddCount(dictionary, num2, num3); } } } } return dictionary; } private static Dictionary CaptureProductionLineRegisterCounts() { Dictionary dictionary = new Dictionary(); FactoryProductionStat[] array = GameMain.data?.statistics?.production?.factoryStatPool; if (array == null) { return dictionary; } FactoryProductionStat[] array2 = array; for (int i = 0; i < array2.Length; i++) { int[] array3 = array2[i]?.productRegister; if (array3 == null || ((ProtoSet)(object)LDB.items)?.dataArray == null) { continue; } ItemProto[] dataArray = ((ProtoSet)(object)LDB.items).dataArray; for (int j = 0; j < dataArray.Length; j++) { int num = ((Proto)(dataArray[j]?)).ID ?? 0; if (num > 0 && num < array3.Length && array3[num] > 0) { AddCount(dictionary, num, array3[num]); } } } return dictionary; } private static Dictionary CaptureLifetimeProductionCounts() { Dictionary dictionary = new Dictionary(); FactoryProductionStat[] array = GameMain.data?.statistics?.production?.factoryStatPool; if (array == null) { return dictionary; } FactoryProductionStat[] array2 = array; for (int i = 0; i < array2.Length; i++) { ProductStat[] array3 = array2[i]?.productPool; if (array3 == null) { continue; } ProductStat[] array4 = array3; foreach (ProductStat val in array4) { if (val != null && val.itemId > 0 && val.total != null && val.total.Length > 6 && val.total[6] > 0) { AddCount(dictionary, val.itemId, val.total[6]); } } } return dictionary; } private static List CaptureHistoricalResearchIds() { //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_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) HashSet hashSet = new HashSet(); GameHistoryData history = GameMain.history; if (history?.techStates != null) { foreach (KeyValuePair techState in history.techStates) { TechState value = techState.Value; if (techState.Key > 0 && (value.unlocked || value.hashUploaded > 0 || value.unlockTick > 0)) { hashSet.Add(techState.Key); } } } if (history != null && history.currentTech > 0) { hashSet.Add(history.currentTech); } if (history?.techQueue != null) { int[] techQueue = history.techQueue; foreach (int num in techQueue) { if (num > 0) { hashSet.Add(num); } } } return hashSet.OrderBy((int techId) => techId).ToList(); } private bool TryPersist() { if (_document == null || string.IsNullOrWhiteSpace(_activePath)) { return false; } string text = Path.Combine(_journalDirectory, $".gameplay-{Guid.NewGuid():N}.tmp"); try { byte[] bytes = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false).GetBytes(PluginJson.Serialize(_document)); WindowsCurrentUserSecurity.WriteSecureNewFile(text, bytes); if (File.Exists(_activePath)) { File.Replace(text, _activePath, null, ignoreMetadataErrors: true); } else { File.Move(text, _activePath); } _pendingPersist = false; _persistenceError = null; _durableThroughSequence = _document.Entries.Select((GameplayJournalEntry entry) => entry.Sequence).DefaultIfEmpty(0L).Max(); return true; } catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException || ex is ArgumentException) { _pendingPersist = true; _persistenceError = ex.GetType().Name; _logger.LogError((object)("Spherewright gameplay journal persistence failed (" + _persistenceError + ")")); return false; } finally { try { if (File.Exists(text)) { File.Delete(text); } } catch (Exception ex2) when (ex2 is IOException || ex2 is UnauthorizedAccessException) { _logger.LogWarning((object)("Spherewright could not remove a journal temporary file (" + ex2.GetType().Name + ")")); } } } private void ResetActiveSession() { _activeSessionId = null; _activePath = null; _document = null; _detector = null; _lastScannedGameTick = -1L; _durableThroughSequence = 0L; _pendingPersist = false; _persistenceError = null; } private static string HashOwnedIdentity(string ownedSaveName) { using SHA256 sHA = SHA256.Create(); return BitConverter.ToString(sHA.ComputeHash(Encoding.UTF8.GetBytes("spherewright-gameplay-journal-v1\n" + ownedSaveName))).Replace("-", string.Empty).ToLowerInvariant(); } private static void AddCount(IDictionary counts, int itemId, long count) { long value; long num = (counts.TryGetValue(itemId, out value) ? value : 0); counts[itemId] = checked(num + count); } private static long GetCount(IReadOnlyDictionary counts, int itemId) { if (!counts.TryGetValue(itemId, out var value)) { return 0L; } return value; } private static string FormatActualTime(DateTimeOffset value) { return value.ToString("O", CultureInfo.InvariantCulture); } private static string FormatGameTime(long gameTick) { long num = Math.Max(0L, gameTick) / 60; long num2 = num / 86400; long num3 = num % 86400 / 3600; long num4 = num % 3600 / 60; long num5 = num % 60; return string.Format(CultureInfo.InvariantCulture, "{0:D3}d {1:D2}:{2:D2}:{3:D2}", num2, num3, num4, num5); } private static GameplayJournalEntry CloneEntry(GameplayJournalEntry entry) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown return new GameplayJournalEntry { Sequence = entry.Sequence, Kind = entry.Kind, ItemId = entry.ItemId, TechId = entry.TechId, Name = entry.Name, ObservedCount = entry.ObservedCount, ActualTime = entry.ActualTime, GameTick = entry.GameTick, GameTime = entry.GameTime, Source = entry.Source }; } } internal sealed class GameplayJournalDocument { public int Version { get; set; } public string JournalId { get; set; } = string.Empty; public string OwnedSaveIdentityHash { get; set; } = string.Empty; public string GameVersion { get; set; } = string.Empty; public string TrackingMode { get; set; } = string.Empty; public bool HistoricalCoverageComplete { get; set; } public string CreatedAtActualTime { get; set; } = string.Empty; public long TrackingStartedAtGameTick { get; set; } public string TrackingStartedAtGameTime { get; set; } = string.Empty; public List HistoricalManualItemIds { get; set; } = new List(); public List HistoricalProductionLineItemIds { get; set; } = new List(); public List HistoricalResearchIds { get; set; } = new List(); public List Entries { get; set; } = new List(); } internal sealed class GameSessionTracker { private readonly bool _writesConfigured; private readonly bool _userSaveImportConfigured; private readonly string _gameVersion; private readonly ManualLogSource _logger; private readonly OwnedWorldResumeTicketStore _resumeTickets; private readonly FlightCheckpointStore _flightCheckpoints; private GameData? _observedData; private GameData? _ownedData; private string? _expectedOwnedSaveName; private string? _ownedSaveName; private string? _sessionId; private int _lastPlanetId; private long _revision; private long _ownedSessionStartTick; private long? _lastOwnedSaveGameTick; private string _ownedSaveState = "none"; private string? _ownedSaveError; private string _writeHealth = "healthy"; private string? _writeQuarantineActionId; private string? _writeQuarantineReason; private OwnedWorldResumeTicket? _expectedResumeTicket; private string? _resumeAdoptionError; private FlightCheckpointTicket? _expectedFlightCheckpoint; private string? _currentFlightCheckpointId; private bool _currentSessionLoadedFromFlightCheckpoint; private string? _flightCheckpointAdoptionError; public bool GameLoaded { get; private set; } public bool IsCurrentSessionOwned { get { if (GameLoaded && _ownedData != null) { return _ownedData == _observedData; } return false; } } public string? SessionId => _sessionId; public string? OwnedSaveName { get { if (!IsCurrentSessionOwned) { return null; } return _ownedSaveName; } } public bool CurrentOwnedSessionStartedAsNewGame { get; private set; } public long Revision => _revision; public string WriteHealth => _writeHealth; public string? WriteQuarantineActionId => _writeQuarantineActionId; public string? WriteQuarantineReason => _writeQuarantineReason; public string? ResumeAdoptionError => _resumeAdoptionError; public string? FlightCheckpointAdoptionError => _flightCheckpointAdoptionError; public string? CurrentFlightCheckpointId => _currentFlightCheckpointId; public bool CurrentSessionLoadedFromFlightCheckpoint => _currentSessionLoadedFromFlightCheckpoint; public GameSessionTracker(bool writesConfigured, bool userSaveImportConfigured, string gameVersion, OwnedWorldResumeTicketStore resumeTickets, FlightCheckpointStore flightCheckpoints, ManualLogSource logger) { _writesConfigured = writesConfigured; _userSaveImportConfigured = userSaveImportConfigured; _gameVersion = gameVersion; _resumeTickets = resumeTickets; _flightCheckpoints = flightCheckpoints; _logger = logger; } public void ExpectNextSessionToBeOwned(string saveName) { if (string.IsNullOrWhiteSpace(saveName)) { throw new ArgumentException("An owned save name is required.", "saveName"); } if (((GameMain.data != null || GameMain.isRunning) && !DSPGame.IsMenuDemo) || _expectedOwnedSaveName != null || _expectedResumeTicket != null || _expectedFlightCheckpoint != null) { throw new InvalidOperationException("An owned new world can only be armed from an idle main menu."); } _expectedOwnedSaveName = saveName; _ownedSaveState = "waiting_for_world"; _ownedSaveError = null; } public void CancelExpectedOwnedSession() { _expectedOwnedSaveName = null; if (!IsCurrentSessionOwned) { _ownedSaveState = "none"; _ownedSaveError = null; } } public void UpdateOnMainThread() { int num; object obj; if (GameMain.isRunning && GameMain.data != null) { num = ((!DSPGame.IsMenuDemo) ? 1 : 0); if (num != 0) { obj = GameMain.data; goto IL_0024; } } else { num = 0; } obj = null; goto IL_0024; IL_0024: GameData val = (GameData)obj; if (num == 0 || val == null) { if (GameLoaded || _observedData != null) { _observedData = null; _ownedData = null; _ownedSaveName = null; _sessionId = null; _lastPlanetId = 0; _revision = 0L; _lastOwnedSaveGameTick = null; _writeHealth = "healthy"; _writeQuarantineActionId = null; _writeQuarantineReason = null; _currentFlightCheckpointId = null; _currentSessionLoadedFromFlightCheckpoint = false; CurrentOwnedSessionStartedAsNewGame = false; } GameLoaded = false; return; } if (!GameLoaded || _observedData != val) { _observedData = val; _sessionId = Guid.NewGuid().ToString("D"); _revision = 1L; _writeHealth = "healthy"; _writeQuarantineActionId = null; _writeQuarantineReason = null; _lastPlanetId = 0; GameLoaded = true; if (_expectedOwnedSaveName != null) { _ownedData = val; _ownedSaveName = _expectedOwnedSaveName; _expectedOwnedSaveName = null; _ownedSaveState = "waiting_to_save"; _ownedSessionStartTick = GameMain.gameTick; _lastOwnedSaveGameTick = null; CurrentOwnedSessionStartedAsNewGame = true; _logger.LogInfo((object)"Spherewright adopted the newly created ordinary peaceful world"); } else if (_expectedResumeTicket != null) { _ownedData = null; _ownedSaveName = null; _ownedSaveState = "waiting_for_world"; _ownedSaveError = null; _logger.LogInfo((object)"Spherewright detected the exact one-time owned-world resume load and is validating provenance"); } else if (_expectedFlightCheckpoint != null) { _ownedData = null; _ownedSaveName = null; _ownedSaveState = "waiting_for_world"; _ownedSaveError = null; _logger.LogInfo((object)"Spherewright detected an exact flight-checkpoint reload and is validating provenance"); } else { _ownedData = null; _ownedSaveName = null; _ownedSaveState = "none"; _ownedSaveError = null; _currentFlightCheckpointId = null; _currentSessionLoadedFromFlightCheckpoint = false; CurrentOwnedSessionStartedAsNewGame = false; _logger.LogWarning((object)"Spherewright detected an unowned game session; save and factory reads are blocked"); } } if (_expectedFlightCheckpoint != null && !IsCurrentSessionOwned) { if (!TryValidateFlightCheckpointCandidate(val, _expectedFlightCheckpoint, out bool pending, out string rejection)) { if (!pending) { _flightCheckpointAdoptionError = rejection; _expectedFlightCheckpoint = null; _ownedSaveState = "none"; _logger.LogError((object)"Spherewright rejected a flight-checkpoint reload because provenance did not match"); } return; } FlightCheckpointTicket expectedFlightCheckpoint = _expectedFlightCheckpoint; _ownedData = val; _ownedSaveName = expectedFlightCheckpoint.OwnedSaveName; _expectedFlightCheckpoint = null; _ownedSaveState = "saved"; _ownedSaveError = null; _ownedSessionStartTick = GameMain.gameTick; _lastOwnedSaveGameTick = expectedFlightCheckpoint.SavedGameTick; _currentFlightCheckpointId = expectedFlightCheckpoint.CheckpointId; _currentSessionLoadedFromFlightCheckpoint = true; CurrentOwnedSessionStartedAsNewGame = false; _logger.LogInfo((object)"Spherewright adopted the exact reusable pre-flight checkpoint without replacing the primary owned save"); } if (_expectedResumeTicket != null && !IsCurrentSessionOwned) { if (!TryValidateResumeCandidate(val, _expectedResumeTicket, out bool pending2, out string rejection2)) { if (!pending2) { _resumeAdoptionError = rejection2; _resumeTickets.Consume(_expectedResumeTicket.ResumeToken); _expectedResumeTicket = null; _ownedSaveState = "none"; _logger.LogError((object)"Spherewright rejected an owned-world resume candidate because provenance did not match"); } return; } OwnedWorldResumeTicket expectedResumeTicket = _expectedResumeTicket; _ownedData = val; _ownedSaveName = expectedResumeTicket.OwnedSaveName; _expectedResumeTicket = null; _ownedSaveState = "waiting_to_save"; _ownedSaveError = null; _ownedSessionStartTick = GameMain.gameTick; _lastOwnedSaveGameTick = null; _resumeTickets.Consume(expectedResumeTicket.ResumeToken); CurrentOwnedSessionStartedAsNewGame = false; _logger.LogInfo((object)"Spherewright adopted the exact normally saved owned world through one-time restart-resume proof"); } if (IsCurrentSessionOwned) { int num2 = val.localPlanet?.id ?? 0; if (_lastPlanetId != 0 && num2 != _lastPlanetId) { _revision++; } _lastPlanetId = num2; TrySaveOwnedWorldOnMainThread(val); } } public SessionState CaptureOnMainThread() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006b: 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_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: 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_00cb: Expected O, but got Unknown //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_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Expected O, but got Unknown //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Unknown result type (might be due to invalid IL or missing references) //IL_0284: Unknown result type (might be due to invalid IL or missing references) //IL_028b: Unknown result type (might be due to invalid IL or missing references) //IL_0292: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Unknown result type (might be due to invalid IL or missing references) //IL_02ba: Unknown result type (might be due to invalid IL or missing references) //IL_02c6: Unknown result type (might be due to invalid IL or missing references) //IL_02d2: Unknown result type (might be due to invalid IL or missing references) //IL_02da: Unknown result type (might be due to invalid IL or missing references) //IL_02e6: Unknown result type (might be due to invalid IL or missing references) //IL_02f2: Unknown result type (might be due to invalid IL or missing references) //IL_02fe: Unknown result type (might be due to invalid IL or missing references) //IL_030f: Unknown result type (might be due to invalid IL or missing references) //IL_0320: Unknown result type (might be due to invalid IL or missing references) //IL_032c: Unknown result type (might be due to invalid IL or missing references) //IL_0338: Unknown result type (might be due to invalid IL or missing references) //IL_034d: Expected O, but got Unknown UpdateOnMainThread(); if (!GameLoaded || _observedData == null) { SessionState val = new SessionState { BridgeConnected = true, GameLoaded = false, OwnedBySpherewright = false, AccessRestricted = false, GameVersion = _gameVersion, Revision = 0L, PeacefulMode = "unknown", SandboxMode = "unknown", WritesAllowed = false, WriteHealth = _writeHealth, OwnedSaveState = _ownedSaveState, OwnedSaveError = _ownedSaveError, RestartResumeAvailable = _resumeTickets.HasCurrentTicket, RestartResumeToken = _resumeTickets.CurrentResumeToken, UserSaveImportConfigured = _userSaveImportConfigured, Capabilities = CreateIdleCapabilities() }; ApplyFlightCheckpointState(val); return val; } if (!IsCurrentSessionOwned) { return new SessionState { BridgeConnected = true, GameLoaded = true, OwnedBySpherewright = false, AccessRestricted = true, GameVersion = _gameVersion, SessionId = _sessionId, Revision = _revision, PeacefulMode = "unknown", SandboxMode = "unknown", WritesAllowed = false, WriteHealth = _writeHealth, WriteQuarantineActionId = _writeQuarantineActionId, OwnedSaveState = "none", UserSaveImportConfigured = _userSaveImportConfigured, Capabilities = CreateUnownedCapabilities() }; } GameDesc gameDesc = _observedData.gameDesc; string text = ((gameDesc == null) ? "unknown" : (gameDesc.isPeaceMode ? "confirmed_peaceful" : "confirmed_combat")); string sandboxMode = ((gameDesc == null) ? "unknown" : ((gameDesc.isSandboxMode || GameMain.sandboxToolsEnabled) ? "enabled" : "confirmed_disabled")); PlanetData localPlanet = _observedData.localPlanet; List list = CreateWriteBlockers(text); bool writesAllowed = list.Count == 0; SessionState val2 = new SessionState { BridgeConnected = true, GameLoaded = true, OwnedBySpherewright = true, AccessRestricted = false, GameVersion = _gameVersion, SessionId = _sessionId, SaveName = _ownedSaveName, GameTick = GameMain.gameTick, Revision = _revision, LocalPlanetId = localPlanet?.id, LocalPlanetName = ((localPlanet != null) ? localPlanet.displayName : null), PeacefulMode = text, SandboxMode = sandboxMode, ResourceMultiplier = gameDesc?.resourceMultiplier, WritesAllowed = writesAllowed, WriteHealth = _writeHealth, WriteQuarantineActionId = _writeQuarantineActionId, WriteBlockers = list, OwnedSaveState = _ownedSaveState, OwnedSaveError = _ownedSaveError, LastOwnedSaveGameTick = _lastOwnedSaveGameTick, RestartResumeAvailable = _resumeTickets.HasCurrentTicket, RestartResumeToken = _resumeTickets.CurrentResumeToken, CurrentSessionLoadedFromFlightCheckpoint = _currentSessionLoadedFromFlightCheckpoint, UserSaveImportConfigured = _userSaveImportConfigured, Capabilities = CreateOwnedCapabilities(writesAllowed, _writeHealth) }; ApplyFlightCheckpointState(val2); return val2; } private List CreateIdleCapabilities() { List list = new List { "bridge.status", "new-game.create", "owned-game.resume", "action.read" }; if (_flightCheckpoints.HasCurrentTicket) { list.Add("flight-checkpoint.reload"); } return list; } private List CreateUnownedCapabilities() { List list = new List { "bridge.status", "session.safe-status" }; if (_userSaveImportConfigured && string.Equals(_writeHealth, "healthy", StringComparison.Ordinal)) { list.Add("user-save.import.prepare"); } return list; } public bool TryGetCurrentUnownedImportCandidateOnMainThread(string? requestedSessionId, out GameData? data, out string rejection) { UpdateOnMainThread(); data = null; rejection = string.Empty; if (!GameLoaded || _observedData == null || GameMain.data == null) { rejection = "No ordinary game is loaded."; return false; } if (IsCurrentSessionOwned) { rejection = "The current world is already Spherewright-owned."; return false; } if (string.IsNullOrWhiteSpace(requestedSessionId) || !string.Equals(requestedSessionId, _sessionId, StringComparison.Ordinal)) { rejection = "The requested unowned session is stale."; return false; } if (_expectedOwnedSaveName != null || _expectedResumeTicket != null || _expectedFlightCheckpoint != null) { rejection = "Another protected world-adoption flow is active."; return false; } if (_observedData != GameMain.data) { rejection = "The current world identity changed."; return false; } data = _observedData; return true; } private void ApplyFlightCheckpointState(SessionState state) { FlightCheckpointTicket currentTicket = _flightCheckpoints.CurrentTicket; if (currentTicket != null && (!state.OwnedBySpherewright || string.Equals(state.SaveName, currentTicket.OwnedSaveName, StringComparison.Ordinal))) { state.FlightCheckpointAvailable = true; state.FlightCheckpointId = currentTicket.CheckpointId; state.FlightCheckpointReloadToken = currentTicket.ReloadToken; state.FlightCheckpointOriginPlanetId = currentTicket.OriginPlanetId; state.FlightCheckpointDestinationPlanetId = currentTicket.DestinationPlanetId; state.FlightCheckpointGameTick = currentTicket.SavedGameTick; if (!state.Capabilities.Contains("flight-checkpoint.reload")) { state.Capabilities.Add("flight-checkpoint.reload"); } } } public void IncrementRevisionOnMainThread() { if (IsCurrentSessionOwned) { _revision++; } } public bool TryImportCurrentSessionAsOwnedCopyOnMainThread(string expectedSessionId, long expectedRevision, GameData expectedData, string newOwnedSaveName, string actionId, out long? savedGameTick, out bool outcomeUnknown, out string? rejection) { savedGameTick = null; outcomeUnknown = false; rejection = null; if (!UserSaveImportSafetyPolicy.IsEnabled(_writesConfigured, _userSaveImportConfigured) || !string.Equals(_writeHealth, "healthy", StringComparison.Ordinal) || string.IsNullOrWhiteSpace(newOwnedSaveName) || newOwnedSaveName.Length > 96 || !Guid.TryParse(actionId, out var _)) { rejection = "The generated owned-copy identity is invalid or import is disabled."; return false; } if (!TryGetCurrentUnownedImportCandidateOnMainThread(expectedSessionId, out GameData data, out string rejection2) || data == null || !UserSaveImportSafetyPolicy.MatchesPreparedCandidate(expectedSessionId, _sessionId, expectedRevision, _revision, (object)expectedData, (object)data)) { rejection = (string.IsNullOrWhiteSpace(rejection2) ? "The exact confirmed world or revision changed before save." : rejection2); return false; } PlanetData localPlanet = data.localPlanet; if (localPlanet == null || data.localLoadedPlanetFactory == null || Object.FindObjectOfType() != null) { rejection = "The exact confirmed world is no longer ready for a normal save."; return false; } GameDesc gameDesc = data.gameDesc; if (gameDesc == null || !GameplayModePolicy.AllowsNormalActions(true, gameDesc.isPeaceMode, gameDesc.isSandboxMode, GameMain.sandboxToolsEnabled, gameDesc.resourceMultiplier)) { rejection = "The exact confirmed world no longer satisfies the confirmed peaceful-mode policy."; return false; } try { string text = GameSave.SavePath(newOwnedSaveName); if (string.IsNullOrWhiteSpace(text) || File.Exists(text)) { rejection = "The generated owned-copy identity is not unused."; return false; } } catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException || ex is ArgumentException || ex is NotSupportedException) { rejection = "The generated owned-copy target could not be checked (" + ex.GetType().Name + ")."; return false; } string gameName = data.gameName; if (string.IsNullOrWhiteSpace(gameName)) { rejection = "The loaded world's internal original identity is unavailable; no save was attempted."; return false; } long gameTick = GameMain.gameTick; bool flag = false; try { GameMain.gameName = newOwnedSaveName; if (!GameSave.SaveCurrentGame(newOwnedSaveName)) { GameMain.gameName = gameName; rejection = "DSP's normal save API returned false; the current world remains unowned."; return false; } flag = true; GameSaveHeader val = default(GameSaveHeader); GameSave.ReadHeader(newOwnedSaveName, false, ref val); if (!UserSaveImportSafetyPolicy.HasVerifiedCopyHeader(flag, gameTick, val?.gameTick)) { GameMain.gameName = gameName; outcomeUnknown = true; rejection = "The newly saved copy could not prove its exact game tick; no ownership was adopted."; QuarantineUnownedImport(actionId, rejection); return false; } _ownedData = data; _ownedSaveName = newOwnedSaveName; _ownedSaveState = "saved"; _ownedSaveError = null; _ownedSessionStartTick = gameTick; _lastOwnedSaveGameTick = gameTick; _lastPlanetId = localPlanet.id; _writeHealth = "healthy"; _writeQuarantineActionId = null; _writeQuarantineReason = null; _currentFlightCheckpointId = null; _currentSessionLoadedFromFlightCheckpoint = false; CurrentOwnedSessionStartedAsNewGame = false; _revision++; savedGameTick = gameTick; try { _resumeTickets.ArmFromHealthySavedOwnedSession(newOwnedSaveName, expectedSessionId, localPlanet.id, gameTick); } catch (Exception ex2) { _logger.LogWarning((object)("Spherewright imported the owned copy but could not arm restart-resume (" + ex2.GetType().Name + ")")); } _logger.LogInfo((object)"Spherewright adopted an explicitly confirmed normal-save copy; the original save identity was not logged or modified"); return true; } catch (Exception ex3) { if (!IsCurrentSessionOwned && GameMain.data == expectedData) { GameMain.gameName = gameName; } outcomeUnknown = flag; rejection = (flag ? ("The owned-copy save completed but verification failed (" + ex3.GetType().Name + "); no ownership was adopted.") : ("DSP rejected the normal owned-copy save (" + ex3.GetType().Name + "); the current world remains unowned.")); if (outcomeUnknown) { QuarantineUnownedImport(actionId, rejection); } _logger.LogError((object)("Spherewright user-save import failed without exposing either save identity (" + ex3.GetType().Name + ")")); return false; } } private void QuarantineUnownedImport(string actionId, string reason) { _writeHealth = "quarantined"; _writeQuarantineActionId = actionId; _writeQuarantineReason = reason; _logger.LogError((object)"Spherewright quarantined current-session save import after an unproved owned-copy outcome"); } private static List CreateOwnedCapabilities(bool writesAllowed, string writeHealth) { List list = new List { "bridge.status", "session.read", "player.read", "progression.read", "gameplay-journal.read", "assembler.read", "build-catalog.read", "recipe-catalog.read", "resource.read", "factory.read", "power.read", "action.read" }; if (writesAllowed) { list.Add("normal-game.prepare"); } if (string.Equals(writeHealth, "quarantined", StringComparison.Ordinal)) { list.Add("quarantine.reconcile"); } return list; } private void TrySaveOwnedWorldOnMainThread(GameData currentData) { if (string.Equals(_ownedSaveState, "waiting_to_save", StringComparison.Ordinal) && !string.IsNullOrWhiteSpace(_ownedSaveName) && currentData.localLoadedPlanetFactory != null && GameMain.gameTick >= _ownedSessionStartTick + 30) { TrySaveOwnedWorldNowOnMainThread(out string _); } } public bool TrySaveOwnedWorldNowOnMainThread(out string? error) { error = null; if (IsCurrentSessionOwned && !string.IsNullOrWhiteSpace(_ownedSaveName)) { GameData data = GameMain.data; if (((data != null) ? data.localLoadedPlanetFactory : null) != null) { try { GameMain.gameName = _ownedSaveName; if (!GameSave.SaveCurrentGame(_ownedSaveName)) { _ownedSaveState = "save_failed"; _ownedSaveError = "The game save API returned false."; error = _ownedSaveError; _logger.LogError((object)"Spherewright could not save the owned ordinary world"); return false; } _ownedSaveState = "saved"; _ownedSaveError = null; _lastOwnedSaveGameTick = GameMain.gameTick; if (!_flightCheckpoints.TryRetireAfterPrimarySave(_ownedSaveName, _lastOwnedSaveGameTick.Value, out bool _, out string rejection)) { _logger.LogWarning((object)("Spherewright could not finalize flight-checkpoint retirement after the covering primary save: " + rejection)); } if (string.Equals(_writeHealth, "healthy", StringComparison.Ordinal) && !string.IsNullOrWhiteSpace(_sessionId)) { int? num = GameMain.localPlanet?.id; if (num.HasValue) { int valueOrDefault = num.GetValueOrDefault(); if (valueOrDefault > 0) { try { _resumeTickets.ArmFromHealthySavedOwnedSession(_ownedSaveName, _sessionId, valueOrDefault, _lastOwnedSaveGameTick.Value); } catch (Exception ex) { _logger.LogWarning((object)("Spherewright could not arm planned restart-resume after the healthy save (" + ex.GetType().Name + ")")); } } } } _logger.LogInfo((object)"Spherewright saved the owned ordinary world"); return true; } catch (Exception ex2) { _ownedSaveState = "save_failed"; _ownedSaveError = ex2.GetType().Name; error = _ownedSaveError; _logger.LogError((object)("Spherewright owned-world save failed (" + _ownedSaveError + ")")); return false; } } } error = "The exact owned world or local factory is unavailable."; return false; } public void QuarantineWritesOnMainThread(string actionId, string reason) { if (!IsCurrentSessionOwned || string.Equals(_writeHealth, "quarantined", StringComparison.Ordinal)) { return; } _writeHealth = "quarantined"; _writeQuarantineActionId = (string.IsNullOrWhiteSpace(actionId) ? null : actionId); _writeQuarantineReason = (string.IsNullOrWhiteSpace(reason) ? "A write outcome could not be proven." : reason); _revision++; try { if (!string.IsNullOrWhiteSpace(_ownedSaveName) && !string.IsNullOrWhiteSpace(_sessionId) && _lastPlanetId > 0 && !string.IsNullOrWhiteSpace(_writeQuarantineActionId)) { _resumeTickets.ArmFromQuarantinedOwnedSession(_ownedSaveName, _sessionId, _lastPlanetId, GameMain.gameTick, _writeQuarantineActionId); } } catch (Exception ex) { _logger.LogWarning((object)("Spherewright could not arm restart-resume after quarantine (" + ex.GetType().Name + ")")); } _logger.LogError((object)"Spherewright quarantined writes for the current owned session"); } public void ExpectNextSessionToBeResumed(OwnedWorldResumeTicket ticket) { if (ticket == null) { throw new ArgumentNullException("ticket"); } if (((GameMain.data != null || GameMain.isRunning) && !DSPGame.IsMenuDemo) || _expectedOwnedSaveName != null || _expectedResumeTicket != null || _expectedFlightCheckpoint != null) { throw new InvalidOperationException("An owned world can only be resumed from an idle main menu."); } _expectedResumeTicket = ticket; _ownedSaveState = "waiting_for_world"; _ownedSaveError = null; _resumeAdoptionError = null; } public void CancelExpectedResumedSession() { _expectedResumeTicket = null; if (!IsCurrentSessionOwned) { _ownedSaveState = "none"; _ownedSaveError = null; } } public void MarkCurrentSessionFlightCheckpoint(FlightCheckpointTicket ticket) { if (ticket == null || !IsCurrentSessionOwned || !string.Equals(_sessionId, ticket.SourceSessionId, StringComparison.Ordinal) || !string.Equals(_ownedSaveName, ticket.OwnedSaveName, StringComparison.Ordinal) || _revision != ticket.SourceRevision || GameMain.localPlanet?.id != ticket.OriginPlanetId || GameMain.gameTick < ticket.SavedGameTick) { throw new InvalidOperationException("The completed flight checkpoint does not match the current owned session."); } _currentFlightCheckpointId = ticket.CheckpointId; _currentSessionLoadedFromFlightCheckpoint = false; _flightCheckpointAdoptionError = null; } public void ForgetCurrentFlightCheckpoint(string checkpointId) { if (!string.IsNullOrWhiteSpace(checkpointId) && string.Equals(_currentFlightCheckpointId, checkpointId, StringComparison.Ordinal)) { _currentFlightCheckpointId = null; _currentSessionLoadedFromFlightCheckpoint = false; _flightCheckpointAdoptionError = null; } } public bool CanReuseFlightCheckpointForCurrentSession(FlightCheckpointTicket ticket) { if (ticket == null || !IsCurrentSessionOwned || !string.Equals(_ownedSaveName, ticket.OwnedSaveName, StringComparison.Ordinal) || !string.Equals(_currentFlightCheckpointId, ticket.CheckpointId, StringComparison.Ordinal) || GameMain.localPlanet?.id != ticket.OriginPlanetId) { return false; } if (_currentSessionLoadedFromFlightCheckpoint) { if (_revision == 1) { return GameMain.gameTick >= ticket.SavedGameTick; } return false; } if (string.Equals(_sessionId, ticket.SourceSessionId, StringComparison.Ordinal) && _revision == ticket.SourceRevision + 1) { return GameMain.gameTick >= ticket.SavedGameTick; } return false; } public void ExpectNextSessionToBeLoadedFromFlightCheckpoint(FlightCheckpointTicket ticket) { if (ticket == null) { throw new ArgumentNullException("ticket"); } bool flag = (GameMain.data != null || GameMain.isRunning) && !DSPGame.IsMenuDemo; if (_expectedOwnedSaveName != null || _expectedResumeTicket != null || _expectedFlightCheckpoint != null || (flag && (!IsCurrentSessionOwned || !string.Equals(_ownedSaveName, ticket.OwnedSaveName, StringComparison.Ordinal)))) { throw new InvalidOperationException("The exact flight checkpoint can only replace its owned game or load from an idle main menu."); } _expectedFlightCheckpoint = ticket; _ownedSaveState = "waiting_for_world"; _ownedSaveError = null; _flightCheckpointAdoptionError = null; } public void CancelExpectedFlightCheckpointSession() { _expectedFlightCheckpoint = null; if (!IsCurrentSessionOwned) { _ownedSaveState = "none"; _ownedSaveError = null; } else { _ownedSaveState = (_lastOwnedSaveGameTick.HasValue ? "saved" : "waiting_to_save"); } } public bool TryClearQuarantineOnMainThread(string expectedActionId, string expectedReason, out string? rejection) { rejection = null; if (!IsCurrentSessionOwned || !string.Equals(_writeHealth, "quarantined", StringComparison.Ordinal)) { rejection = "The current owned session is not quarantined."; return false; } if (string.IsNullOrWhiteSpace(_writeQuarantineActionId) || !string.Equals(_writeQuarantineActionId, expectedActionId, StringComparison.Ordinal) || !string.Equals(_writeQuarantineReason, expectedReason, StringComparison.Ordinal)) { rejection = "The quarantined action identity or reason changed after reconciliation was prepared."; return false; } string currentResumeToken = _resumeTickets.CurrentResumeToken; _writeHealth = "healthy"; _writeQuarantineActionId = null; _writeQuarantineReason = null; _revision++; if (!string.IsNullOrWhiteSpace(currentResumeToken)) { _resumeTickets.Consume(currentResumeToken); } _logger.LogInfo((object)"Spherewright cleared write quarantine after exact action reconciliation"); return true; } private static bool TryValidateFlightCheckpointCandidate(GameData currentData, FlightCheckpointTicket ticket, out bool pending, out string rejection) { pending = false; rejection = string.Empty; if (Object.FindObjectOfType() != null) { pending = true; rejection = "DSP is still running the exact flight-checkpoint loader."; return false; } PlanetData localPlanet = currentData.localPlanet; if (localPlanet == null) { pending = true; rejection = "The flight-checkpoint origin planet is still loading."; return false; } if (!OwnedWorldProvenancePolicy.MatchesProtectedSaveIdentity(ticket.OwnedSaveName, currentData.gameName)) { rejection = "The flight checkpoint did not contain the exact primary owned-save identity."; return false; } if (GameMain.gameTick < ticket.SavedGameTick) { rejection = "The loaded flight checkpoint is older than its protected ticket."; return false; } if (GameMain.gameTick > ticket.SavedGameTick + 3600) { rejection = "The loaded flight-checkpoint candidate advanced beyond the bounded adoption window."; return false; } GameDesc gameDesc = currentData.gameDesc; if (gameDesc == null || !GameplayModePolicy.AllowsNormalActions(true, gameDesc.isPeaceMode, gameDesc.isSandboxMode, GameMain.sandboxToolsEnabled, gameDesc.resourceMultiplier)) { rejection = "The flight checkpoint did not prove a readable peaceful-mode setting."; return false; } if (localPlanet.id != ticket.OriginPlanetId) { rejection = "The loaded planet does not match the protected flight-checkpoint origin."; return false; } return true; } private static bool TryValidateResumeCandidate(GameData currentData, OwnedWorldResumeTicket ticket, out bool pending, out string rejection) { pending = false; rejection = string.Empty; if (!OwnedWorldProvenancePolicy.MatchesProtectedSaveIdentity(ticket.OwnedSaveName, currentData.gameName)) { rejection = "The resumed payload did not contain the exact high-entropy owned save identity."; return false; } if (GameMain.gameTick < ticket.MinimumGameTick) { rejection = "The resumed payload is older than the authenticated source-session ticket."; return false; } GameDesc gameDesc = currentData.gameDesc; if (gameDesc == null || !GameplayModePolicy.AllowsNormalActions(true, gameDesc.isPeaceMode, gameDesc.isSandboxMode, GameMain.sandboxToolsEnabled, gameDesc.resourceMultiplier)) { rejection = "The resumed payload did not prove a readable peaceful-mode setting."; return false; } PlanetData localPlanet = currentData.localPlanet; if (localPlanet == null) { pending = true; rejection = "The resumed local planet is still loading."; return false; } if (localPlanet.id != ticket.ExpectedPlanetId) { rejection = "The resumed local planet does not match the authenticated source-session ticket."; return false; } return true; } private List CreateWriteBlockers(string peacefulState) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Expected O, but got Unknown //IL_0044: Expected O, but got Unknown //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Expected O, but got Unknown List list = new List(); if (string.Equals(_writeHealth, "quarantined", StringComparison.Ordinal)) { list.Add(new WriteBlocker { Code = "WRITE_SUBSYSTEM_QUARANTINED", Message = (_writeQuarantineReason ?? "The current session write subsystem is quarantined.") }); } if (!_writesConfigured) { list.Add(new WriteBlocker { Code = "WRITES_DISABLED", Message = "Writes are disabled by configuration." }); } if (string.Equals(peacefulState, "unknown", StringComparison.Ordinal)) { list.Add(new WriteBlocker { Code = "PEACEFUL_MODE_UNKNOWN", Message = "Peaceful mode could not be confirmed." }); } else if (!string.Equals(peacefulState, "confirmed_peaceful", StringComparison.Ordinal)) { list.Add(new WriteBlocker { Code = "PEACEFUL_MODE_REQUIRED", Message = "M0 writes require a peaceful world." }); } return list; } } internal sealed class GameStateReader { private const int DefaultLimit = 50; private const int MaximumLimit = 100; private readonly GameSessionTracker _sessions; private readonly SnapshotPageStore _resourceSnapshots = new SnapshotPageStore(TimeSpan.FromSeconds(60.0), 16, (Func)null); private readonly SnapshotPageStore _factorySnapshots = new SnapshotPageStore(TimeSpan.FromSeconds(60.0), 16, (Func)null); private readonly SnapshotPageStore _assemblerSnapshots = new SnapshotPageStore(TimeSpan.FromSeconds(60.0), 16, (Func)null); public GameStateReader(GameSessionTracker sessions) { _sessions = sessions; } public GameCallResult GetSessionStateOnMainThread() { return GameCallResult.Succeeded(_sessions.CaptureOnMainThread()); } public GameCallResult GetPlayerStateOnMainThread(string? requestedSessionId, LocalPlanetRequest request) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0073: 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_0084: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: 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_00c3: Invalid comparison between Unknown and I4 //IL_00ca: 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_00d2: Invalid comparison between Unknown and I4 //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Expected O, but got Unknown //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_029f: 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) //IL_0261: Unknown result type (might be due to invalid IL or missing references) //IL_0266: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Expected O, but got Unknown //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_0366: Unknown result type (might be due to invalid IL or missing references) //IL_036b: Unknown result type (might be due to invalid IL or missing references) //IL_036d: Unknown result type (might be due to invalid IL or missing references) //IL_037a: Unknown result type (might be due to invalid IL or missing references) //IL_039b: Unknown result type (might be due to invalid IL or missing references) //IL_03e9: Unknown result type (might be due to invalid IL or missing references) //IL_03fe: Unknown result type (might be due to invalid IL or missing references) //IL_03ab: Unknown result type (might be due to invalid IL or missing references) //IL_03b0: Unknown result type (might be due to invalid IL or missing references) //IL_03b1: Unknown result type (might be due to invalid IL or missing references) //IL_03bd: Unknown result type (might be due to invalid IL or missing references) //IL_03be: Unknown result type (might be due to invalid IL or missing references) //IL_03d1: Expected O, but got Unknown //IL_03d3: Unknown result type (might be due to invalid IL or missing references) //IL_0476: Unknown result type (might be due to invalid IL or missing references) //IL_047b: Unknown result type (might be due to invalid IL or missing references) //IL_0487: Unknown result type (might be due to invalid IL or missing references) //IL_0498: Unknown result type (might be due to invalid IL or missing references) //IL_04a4: Unknown result type (might be due to invalid IL or missing references) //IL_04b0: Unknown result type (might be due to invalid IL or missing references) //IL_04bc: Expected O, but got Unknown //IL_06eb: Unknown result type (might be due to invalid IL or missing references) //IL_06f0: Unknown result type (might be due to invalid IL or missing references) //IL_06fd: Unknown result type (might be due to invalid IL or missing references) //IL_070a: Unknown result type (might be due to invalid IL or missing references) //IL_0717: Unknown result type (might be due to invalid IL or missing references) //IL_0724: Unknown result type (might be due to invalid IL or missing references) //IL_0731: Unknown result type (might be due to invalid IL or missing references) //IL_074c: Unknown result type (might be due to invalid IL or missing references) //IL_0759: Unknown result type (might be due to invalid IL or missing references) //IL_076b: Expected O, but got Unknown //IL_05ea: Unknown result type (might be due to invalid IL or missing references) //IL_05ef: Unknown result type (might be due to invalid IL or missing references) //IL_05f7: Unknown result type (might be due to invalid IL or missing references) //IL_0604: Unknown result type (might be due to invalid IL or missing references) //IL_053a: Unknown result type (might be due to invalid IL or missing references) //IL_053f: Unknown result type (might be due to invalid IL or missing references) //IL_054c: Unknown result type (might be due to invalid IL or missing references) //IL_055e: Unknown result type (might be due to invalid IL or missing references) //IL_056b: Unknown result type (might be due to invalid IL or missing references) //IL_057e: Unknown result type (might be due to invalid IL or missing references) //IL_0596: Expected O, but got Unknown //IL_0630: Unknown result type (might be due to invalid IL or missing references) //IL_063d: Unknown result type (might be due to invalid IL or missing references) //IL_064a: Unknown result type (might be due to invalid IL or missing references) //IL_0657: Unknown result type (might be due to invalid IL or missing references) //IL_0664: Unknown result type (might be due to invalid IL or missing references) //IL_0673: Expected O, but got Unknown PlanetFactory factory; BridgeError val = ValidateOwnedPlanetOnMainThread(requestedSessionId, request.PlanetId, out factory); if (val != null) { return GameCallResult.Failed(val); } Player mainPlayer = GameMain.mainPlayer; if (((mainPlayer != null) ? mainPlayer.package : null) == null || mainPlayer.mecha == null) { return GameCallResult.Failed(NotReady("The player inventory or mecha is not ready in the owned ordinary world.")); } PlayerStateSnapshot val2 = new PlayerStateSnapshot { SessionId = _sessions.SessionId, PlanetId = factory.planetId, CapturedAtGameTick = GameMain.gameTick, Position = CaptureVector(mainPlayer.position), MovementState = ((object)Unsafe.As(ref mainPlayer.movementState)/*cast due to .constrained prefix*/).ToString(), IsAlive = mainPlayer.isAlive, IsOnPlanet = (mainPlayer.planetId == factory.planetId), IsFlying = ((int)mainPlayer.movementState == 2), IsSailing = ((int)mainPlayer.movementState >= 3), Speed = mainPlayer.speed, CoreEnergy = mainPlayer.mecha.coreEnergy, CoreEnergyCapacity = mainPlayer.mecha.coreEnergyCap, ReactorEnergy = mainPlayer.mecha.reactorEnergy, ReactorItemId = mainPlayer.mecha.reactorItemId, ReactorItemName = ((mainPlayer.mecha.reactorItemId > 0) ? GetItemName(mainPlayer.mecha.reactorItemId) : null), ReactorItemInc = mainPlayer.mecha.reactorItemInc, AutoReplenishFuel = mainPlayer.mecha.autoReplenishFuel, FuelStorageSlotCount = (mainPlayer.mecha.reactorStorage?.size ?? 0), BuildArea = mainPlayer.mecha.buildArea, InventorySlotCount = mainPlayer.package.size, AutoManageResearchItems = (GameMain.history?.autoManageLabItems ?? false), MechaResearchPower = mainPlayer.mecha.researchPower }; Dictionary dictionary = new Dictionary(); GRID[] array = mainPlayer.package.grids ?? Array.Empty(); int num = Math.Min(mainPlayer.package.size, array.Length); for (int i = 0; i < num; i++) { GRID val3 = array[i]; if (val3.itemId > 0 && val3.count > 0) { int inventoryOccupiedSlotCount = val2.InventoryOccupiedSlotCount; val2.InventoryOccupiedSlotCount = inventoryOccupiedSlotCount + 1; if (!dictionary.TryGetValue(val3.itemId, out var value)) { value = new PlayerInventoryItem { ItemId = val3.itemId, Name = GetItemName(val3.itemId) }; dictionary.Add(val3.itemId, value); } PlayerInventoryItem obj = value; obj.Count += val3.count; PlayerInventoryItem obj2 = value; obj2.Inc += val3.inc; PlayerInventoryItem obj3 = value; inventoryOccupiedSlotCount = obj3.SlotCount; obj3.SlotCount = inventoryOccupiedSlotCount + 1; } } val2.Inventory = dictionary.Values.OrderBy((PlayerInventoryItem item) => item.ItemId).ToList(); Dictionary dictionary2 = new Dictionary(); StorageComponent reactorStorage = mainPlayer.mecha.reactorStorage; GRID[] array2 = reactorStorage?.grids ?? Array.Empty(); int num2 = Math.Min(reactorStorage?.size ?? 0, array2.Length); for (int num3 = 0; num3 < num2; num3++) { GRID val4 = array2[num3]; if (val4.itemId > 0 && val4.count > 0) { int inventoryOccupiedSlotCount = val2.FuelStorageOccupiedSlotCount; val2.FuelStorageOccupiedSlotCount = inventoryOccupiedSlotCount + 1; if (!dictionary2.TryGetValue(val4.itemId, out var value2)) { value2 = new PlayerInventoryItem { ItemId = val4.itemId, Name = GetItemName(val4.itemId) }; dictionary2.Add(val4.itemId, value2); } PlayerInventoryItem obj4 = value2; obj4.Count += val4.count; PlayerInventoryItem obj5 = value2; obj5.Inc += val4.inc; PlayerInventoryItem obj6 = value2; inventoryOccupiedSlotCount = obj6.SlotCount; obj6.SlotCount = inventoryOccupiedSlotCount + 1; } } val2.FuelStorage = dictionary2.Values.OrderBy((PlayerInventoryItem item) => item.ItemId).ToList(); if (mainPlayer.inhandItemId > 0 && mainPlayer.inhandItemCount > 0) { val2.InHandItem = new PlayerInventoryItem { ItemId = mainPlayer.inhandItemId, Name = GetItemName(mainPlayer.inhandItemId), Count = mainPlayer.inhandItemCount, Inc = mainPlayer.inhandItemInc, SlotCount = 1 }; } Dictionary dictionary3 = mainPlayer.mecha.lab?.itemPoints?.items; if (dictionary3 != null) { foreach (KeyValuePair item in dictionary3.OrderBy((KeyValuePair item) => item.Key)) { if (item.Key > 0 && item.Value > 0) { val2.MechaResearchItemBuffer.Add(new MechaResearchItemSnapshot { ItemId = item.Key, Name = GetItemName(item.Key), PointCount = item.Value, WholeItemCount = item.Value / 3600, RemainderPoints = item.Value % 3600 }); } } } List list = mainPlayer.mecha.forge?.tasks; if (list != null) { for (int num4 = 0; num4 < list.Count; num4++) { ForgeTask val5 = list[num4]; if (val5 != null) { HandcraftTaskSnapshot val6 = new HandcraftTaskSnapshot { QueueIndex = num4, RecipeId = val5.recipeId }; RecipeProto obj7 = ((ProtoSet)(object)LDB.recipes).Select(val5.recipeId); val6.RecipeName = ((obj7 != null) ? ((Proto)obj7).name : null) ?? string.Empty; val6.RemainingCraftCount = val5.count; val6.Progress = val5.tick; val6.ProgressRequired = val5.tickSpend; val6.ParentTaskIndex = val5.parentTaskIndex; val6.IngredientsReserved = val5.itemEnough; HandcraftTaskSnapshot val7 = val6; AddPlayerItemAmounts(val7.Inputs, val5.itemIds, val5.itemCounts, val5.served); AddPlayerItemAmounts(val7.Outputs, val5.productIds, val5.productCounts, val5.produced); val2.HandcraftQueue.Add(val7); } } } ConstructionModuleComponent constructionModule = mainPlayer.mecha.constructionModule; if (constructionModule != null) { val2.ConstructionDrones = new ConstructionDroneSnapshot { Enabled = constructionModule.droneEnabled, ConstructionEnabled = constructionModule.droneConstructEnabled, Total = constructionModule.droneCount, Alive = constructionModule.droneAliveCount, Idle = constructionModule.droneIdleCount, Working = Math.Max(0, constructionModule.droneAliveCount - constructionModule.droneIdleCount), PendingBuildTargets = constructionModule.buildTargetTotalCount, PendingRepairTargets = constructionModule.repairTargetTotalCount }; } val2.StateHash = CanonicalStateHash.PlayerAction(val2); val2.StateHashVersion = 1; return GameCallResult.Succeeded(val2); } public GameCallResult GetProgressionStateOnMainThread(string? requestedSessionId, LocalPlanetRequest request) { //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Expected O, but got Unknown //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Expected O, but got Unknown //IL_02af: Unknown result type (might be due to invalid IL or missing references) //IL_02db: Unknown result type (might be due to invalid IL or missing references) //IL_02e0: Unknown result type (might be due to invalid IL or missing references) //IL_02e8: Unknown result type (might be due to invalid IL or missing references) //IL_02f5: Unknown result type (might be due to invalid IL or missing references) //IL_0300: Unknown result type (might be due to invalid IL or missing references) //IL_0308: Unknown result type (might be due to invalid IL or missing references) //IL_0315: Expected O, but got Unknown //IL_0320: Unknown result type (might be due to invalid IL or missing references) //IL_0325: Unknown result type (might be due to invalid IL or missing references) //IL_032d: Unknown result type (might be due to invalid IL or missing references) //IL_033a: Unknown result type (might be due to invalid IL or missing references) //IL_0345: Unknown result type (might be due to invalid IL or missing references) //IL_0352: Expected O, but got Unknown PlanetFactory factory; BridgeError val = ValidateOwnedPlanetOnMainThread(requestedSessionId, request.PlanetId, out factory); if (val != null) { return GameCallResult.Failed(val); } GameHistoryData history = GameMain.history; if (history?.techStates == null || history.techQueue == null) { return GameCallResult.Failed(NotReady("The technology state is not ready in the owned ordinary world.")); } List list = history.techQueue.Where((int techId) => techId > 0).ToList(); ProgressionStateSnapshot val2 = new ProgressionStateSnapshot { SessionId = _sessions.SessionId, PlanetId = factory.planetId, CapturedAtGameTick = GameMain.gameTick, CurrentTechId = history.currentTech }; TechProto obj = ((ProtoSet)(object)LDB.techs).Select(history.currentTech); val2.CurrentTechName = ((obj != null) ? ((Proto)obj).name : null); val2.TechQueue = list; ProgressionStateSnapshot val3 = val2; foreach (TechProto item in ((ProtoSet)(object)LDB.techs).dataArray.OrderBy((TechProto proto) => ((Proto)proto).ID)) { if (item == null || !history.techStates.TryGetValue(((Proto)item).ID, out var value)) { continue; } TechStateSnapshot val4 = new TechStateSnapshot { TechId = ((Proto)item).ID, Name = (((Proto)item).name ?? string.Empty), Unlocked = value.unlocked, CurrentLevel = value.curLevel, MaximumLevel = value.maxLevel, HashUploaded = value.hashUploaded, HashRequired = value.hashNeeded, UnlockTick = value.unlockTick, IsLabTech = item.IsLabTech, IsQueued = list.Contains(((Proto)item).ID), PrerequisiteTechIds = (from id in (item.PreTechs ?? Array.Empty()).Concat(item.PreTechsImplicit ?? Array.Empty()).Distinct() orderby id select id).ToList(), UnlockRecipeIds = (item.UnlockRecipes ?? Array.Empty()).OrderBy((int id) => id).ToList() }; int[] array = item.Items ?? Array.Empty(); int[] array2 = item.ItemPoints ?? Array.Empty(); int num = Math.Min(array.Length, array2.Length); for (int num2 = 0; num2 < num; num2++) { int num3 = array[num2]; long requiredItemCount = value.hashNeeded * array2[num2] / 3600; bool flag = TechProto.matrixIds.Contains(num3); val4.ItemRequirements.Add(new TechItemRequirement { ItemId = num3, Name = GetItemName(num3), PointsPerHash = array2[num2], RequiredItemCount = requiredItemCount, IsMatrix = flag }); if (flag) { val4.MatrixRequirements.Add(new TechMatrixRequirement { ItemId = num3, Name = GetItemName(num3), PointsPerHash = array2[num2], RequiredItemCount = requiredItemCount }); } } val3.Technologies.Add(val4); } val3.StateHash = CanonicalStateHash.Progression(val3); val3.StateHashVersion = 1; val3.SelectionStateHash = CanonicalStateHash.ProgressionSelection(val3); val3.SelectionStateHashVersion = 1; return GameCallResult.Succeeded(val3); } public GameCallResult GetRecipeCatalogOnMainThread(string? requestedSessionId, LocalPlanetRequest request) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected O, but got Unknown //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: 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_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Expected O, but got Unknown //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Expected O, but got Unknown PlanetFactory factory; BridgeError val = ValidateOwnedPlanetOnMainThread(requestedSessionId, request.PlanetId, out factory); if (val != null) { return GameCallResult.Failed(val); } GameHistoryData history = GameMain.history; if (history == null) { return GameCallResult.Failed(NotReady("The runtime item and recipe catalog is not ready in the owned ordinary world.")); } RecipeCatalogSnapshot val2 = new RecipeCatalogSnapshot { SessionId = _sessions.SessionId, PlanetId = factory.planetId, CapturedAtGameTick = GameMain.gameTick }; foreach (ItemProto item in ((ProtoSet)(object)LDB.items).dataArray.OrderBy((ItemProto proto) => ((Proto)proto).ID)) { if (item != null) { val2.Items.Add(new ItemCatalogEntry { ItemId = ((Proto)item).ID, Name = (((Proto)item).name ?? string.Empty), StackSize = item.StackSize, IsRaw = item.isRaw, CanBuild = item.CanBuild, Unlocked = history.ItemUnlocked(((Proto)item).ID), HandcraftRecipeId = ((Proto)(item.handcraft?)).ID }); } } foreach (RecipeProto item2 in ((ProtoSet)(object)LDB.recipes).dataArray.OrderBy((RecipeProto proto) => ((Proto)proto).ID)) { if (item2 != null) { RecipeCatalogEntry val3 = new RecipeCatalogEntry { RecipeId = ((Proto)item2).ID, Name = (((Proto)item2).name ?? string.Empty), RecipeType = ((object)Unsafe.As(ref item2.Type)/*cast due to .constrained prefix*/).ToString(), Handcraft = item2.Handcraft, Unlocked = history.RecipeUnlocked(((Proto)item2).ID), TimeSpend = item2.TimeSpend, PrerequisiteTechId = ((Proto)(item2.preTech?)).ID }; TechProto preTech = item2.preTech; val3.PrerequisiteTechName = ((preTech != null) ? ((Proto)preTech).name : null); RecipeCatalogEntry val4 = val3; AddCatalogAmounts(val4.Inputs, item2.Items, item2.ItemCounts); AddCatalogAmounts(val4.Outputs, item2.Results, item2.ResultCounts); val2.Recipes.Add(val4); } } int num = ((TechProto.matrixIds.Length > 1) ? TechProto.matrixIds[1] : 0); val2.FirstRedMatrixDependencies = RuntimeDependencyGraphBuilder.Build(num, GetItemName(num), (IReadOnlyList)val2.Recipes); return GameCallResult.Succeeded(val2); } public GameCallResult ListResourceNodesOnMainThread(string? requestedSessionId, ListResourceNodesRequest request) { //IL_0124: 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_0194: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Expected O, but got Unknown PlanetFactory factory; BridgeError val = ValidateOwnedPlanetOnMainThread(requestedSessionId, request.PlanetId, out factory); if (val != null) { return GameCallResult.Failed(val); } BridgeError val2 = ValidateListLimit(request.Limit, "Resource-node"); if (val2 != null) { return GameCallResult.Failed(val2); } string text = NormalizeOptional(request.Kind); if (text != null && text != "vein" && text != "vegetation") { return GameCallResult.Failed(InvalidRequest("Resource kind must be vein, vegetation, or empty.", "Use a resource kind returned by this tool.")); } string text2 = NormalizeOptional(request.ResourceType); string text3 = ComputeFilterHash(string.Format("kind={0}|type={1}|product={2}|limit={3}", text ?? "*", text2 ?? "*", request.ProductItemId?.ToString() ?? "*", request.Limit)); SnapshotPage val3 = default(SnapshotPage); if (!string.IsNullOrWhiteSpace(request.Cursor)) { if ((int)_resourceSnapshots.TryGetPage(request.Cursor, _sessions.SessionId, factory.planetId, text3, request.Limit, ref val3) != 0 || val3 == null) { return GameCallResult.Failed(StaleCursor("The resource cursor is unknown, expired, or bound to a different session, planet, filter, or page size.")); } } else { List list = CaptureResourceNodes(factory, text, text2, request.ProductItemId); if (!_resourceSnapshots.TryCreate(_sessions.SessionId, factory.planetId, text3, (IReadOnlyList)list, request.Limit, ref val3) || val3 == null) { return GameCallResult.Failed(SnapshotCapacityExceeded("resource-node")); } } return GameCallResult.Succeeded(new ListResourceNodesResult { SessionId = _sessions.SessionId, PlanetId = factory.planetId, CapturedAtGameTick = ((val3.Items.Count > 0) ? val3.Items[0].CapturedAtGameTick : GameMain.gameTick), SnapshotId = val3.SnapshotId, SnapshotExpiresAtUtc = val3.ExpiresAtUtc, Nodes = val3.Items.ToList(), NextCursor = val3.NextCursor }); } public GameCallResult InspectResourceNodeOnMainThread(string? requestedSessionId, InspectResourceNodeRequest request) { PlanetFactory factory; BridgeError val = ValidateOwnedPlanetOnMainThread(requestedSessionId, request.PlanetId, out factory); if (val != null) { return GameCallResult.Failed(val); } if (request.NodeId <= 0) { return InvalidResource("The requested resource node ID must be positive."); } ResourceNodeSnapshot val2; if (string.Equals(request.Kind, "vein", StringComparison.OrdinalIgnoreCase)) { val2 = ((request.NodeId < factory.veinCursor) ? TryCaptureVein(factory, request.NodeId) : null); } else { if (!string.Equals(request.Kind, "vegetation", StringComparison.OrdinalIgnoreCase)) { return GameCallResult.Failed(InvalidRequest("Resource kind must be vein or vegetation.", "Use the kind and nodeId returned by spherewright_list_resource_nodes.")); } val2 = ((request.NodeId < factory.vegeCursor) ? TryCaptureVegetation(factory, request.NodeId) : null); } if (val2 != null) { return GameCallResult.Succeeded(val2); } return InvalidResource("The requested resource node no longer exists in the local factory."); } public GameCallResult ListFactoryEntitiesOnMainThread(string? requestedSessionId, ListFactoryEntitiesRequest request) { //IL_0124: 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_0194: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Expected O, but got Unknown PlanetFactory factory; BridgeError val = ValidateOwnedPlanetOnMainThread(requestedSessionId, request.PlanetId, out factory); if (val != null) { return GameCallResult.Failed(val); } BridgeError val2 = ValidateListLimit(request.Limit, "Factory-entity"); if (val2 != null) { return GameCallResult.Failed(val2); } string text = NormalizeOptional(request.ObjectKind); if (text != null && text != "entity" && text != "prebuild") { return GameCallResult.Failed(InvalidRequest("Factory object kind must be entity, prebuild, or empty.", "Use an object kind returned by this tool.")); } string text2 = NormalizeOptional(request.ComponentKind); string text3 = ComputeFilterHash(string.Format("object={0}|component={1}|item={2}|limit={3}", text ?? "*", text2 ?? "*", request.ItemId?.ToString() ?? "*", request.Limit)); SnapshotPage val3 = default(SnapshotPage); if (!string.IsNullOrWhiteSpace(request.Cursor)) { if ((int)_factorySnapshots.TryGetPage(request.Cursor, _sessions.SessionId, factory.planetId, text3, request.Limit, ref val3) != 0 || val3 == null) { return GameCallResult.Failed(StaleCursor("The factory cursor is unknown, expired, or bound to a different session, planet, filter, or page size.")); } } else { List list = CaptureFactoryEntities(factory, text, text2, request.ItemId); if (!_factorySnapshots.TryCreate(_sessions.SessionId, factory.planetId, text3, (IReadOnlyList)list, request.Limit, ref val3) || val3 == null) { return GameCallResult.Failed(SnapshotCapacityExceeded("factory-entity")); } } return GameCallResult.Succeeded(new ListFactoryEntitiesResult { SessionId = _sessions.SessionId, PlanetId = factory.planetId, CapturedAtGameTick = ((val3.Items.Count > 0) ? val3.Items[0].CapturedAtGameTick : GameMain.gameTick), SnapshotId = val3.SnapshotId, SnapshotExpiresAtUtc = val3.ExpiresAtUtc, Entities = val3.Items.ToList(), NextCursor = val3.NextCursor }); } public GameCallResult InspectFactoryEntityOnMainThread(string? requestedSessionId, InspectFactoryEntityRequest request) { PlanetFactory factory; BridgeError val = ValidateOwnedPlanetOnMainThread(requestedSessionId, request.PlanetId, out factory); if (val != null) { return GameCallResult.Failed(val); } FactoryEntitySnapshot val2 = null; if (request.ObjectId > 0 && request.ObjectId < factory.entityCursor) { val2 = TryCaptureFactoryEntity(factory, request.ObjectId); } else if (request.ObjectId < 0 && -request.ObjectId < factory.prebuildCursor) { val2 = TryCapturePrebuild(factory, -request.ObjectId); } if (val2 != null) { return GameCallResult.Succeeded(val2); } return InvalidFactoryEntity("The requested factory object no longer exists in the local factory."); } public GameCallResult GetPowerSummaryOnMainThread(string? requestedSessionId, LocalPlanetRequest request) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Expected O, but got Unknown //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Expected O, but got Unknown PlanetFactory factory; BridgeError val = ValidateOwnedPlanetOnMainThread(requestedSessionId, request.PlanetId, out factory); if (val != null) { return GameCallResult.Failed(val); } PowerSystem powerSystem = factory.powerSystem; if (powerSystem?.netPool == null) { return GameCallResult.Failed(NotReady("The local planet power system is not ready.")); } PowerSummarySnapshot val2 = new PowerSummarySnapshot { SessionId = _sessions.SessionId, PlanetId = factory.planetId, CapturedAtGameTick = GameMain.gameTick }; int num = Math.Min(powerSystem.netCursor, powerSystem.netPool.Length); for (int i = 1; i < num; i++) { PowerNetwork val3 = powerSystem.netPool[i]; if (val3 != null && val3.id == i) { PowerNetworkSnapshot val4 = new PowerNetworkSnapshot { NetworkId = i, NodeCount = (val3.nodes?.Count ?? 0), ConsumerCount = (val3.consumers?.Count ?? 0), GeneratorCount = (val3.generators?.Count ?? 0), AccumulatorCount = (val3.accumulators?.Count ?? 0), ExchangerCount = (val3.exchangers?.Count ?? 0), EnergyRequired = val3.energyRequired, EnergyServed = val3.energyServed, EnergyCapacity = val3.energyCapacity, EnergyGenerated = val3.energyExport, EnergyStored = val3.energyStored, ConsumerRatio = val3.consumerRatio, GeneratorRatio = val3.generaterRatio }; val2.Networks.Add(val4); val2.TotalEnergyRequired += val4.EnergyRequired; val2.TotalEnergyServed += val4.EnergyServed; val2.TotalEnergyCapacity += val4.EnergyCapacity; val2.TotalEnergyGenerated += val4.EnergyGenerated; } } return GameCallResult.Succeeded(val2); } public GameCallResult ListAssemblersOnMainThread(string? requestedSessionId, ListAssemblersRequest request) { //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Expected O, but got Unknown PlanetFactory factory; BridgeError val = ValidateOwnedSessionOnMainThread(requestedSessionId, out factory); if (val != null) { return GameCallResult.Failed(val); } int num = ((request.Limit == 0) ? 50 : request.Limit); if (num < 1 || num > 100) { return GameCallResult.Failed(BridgeError.Create("INVALID_REQUEST", $"Assembler list limit must be between 1 and {100}.", false, "Use a bounded limit and retry.")); } string text = ComputeFilterHash($"assemblers|limit={num}"); SnapshotPage val2 = default(SnapshotPage); if (!string.IsNullOrWhiteSpace(request.Cursor)) { if ((int)_assemblerSnapshots.TryGetPage(request.Cursor, _sessions.SessionId, factory.planetId, text, num, ref val2) != 0 || val2 == null) { return GameCallResult.Failed(StaleCursor("The assembler cursor is unknown, expired, or bound to a different session, planet, or page size.")); } } else { List list = new List(); AssemblerComponent[] assemblerPool = factory.factorySystem.assemblerPool; int num2 = Math.Min(factory.factorySystem.assemblerCursor, assemblerPool.Length); for (int i = 1; i < num2; i++) { ref AssemblerComponent reference = ref assemblerPool[i]; if (reference.id == i) { AssemblerSnapshot val3 = TryCaptureAssembler(factory, i, ref reference); if (val3 != null) { list.Add(val3); } } } if (!_assemblerSnapshots.TryCreate(_sessions.SessionId, factory.planetId, text, (IReadOnlyList)list, num, ref val2) || val2 == null) { return GameCallResult.Failed(SnapshotCapacityExceeded("assembler")); } } return GameCallResult.Succeeded(new ListAssemblersResult { Revision = _sessions.Revision, Assemblers = val2.Items.ToList(), NextCursor = val2.NextCursor }); } public GameCallResult InspectAssemblerOnMainThread(string? requestedSessionId, InspectAssemblerRequest request) { PlanetFactory factory; BridgeError val = ValidateOwnedSessionOnMainThread(requestedSessionId, out factory); if (val != null) { return GameCallResult.Failed(val); } if (request.EntityId <= 0 || request.EntityId >= factory.entityCursor) { return InvalidAssembler("The requested entity does not exist in the current factory."); } ref EntityData reference = ref factory.entityPool[request.EntityId]; if (reference.id != request.EntityId || reference.assemblerId <= 0) { return InvalidAssembler("The requested entity is missing or is not an assembler."); } int assemblerId = reference.assemblerId; if (assemblerId >= factory.factorySystem.assemblerCursor) { return InvalidAssembler("The assembler component is no longer valid."); } ref AssemblerComponent reference2 = ref factory.factorySystem.assemblerPool[assemblerId]; AssemblerSnapshot val2 = ((reference2.id == assemblerId && reference2.entityId == request.EntityId) ? TryCaptureAssembler(factory, assemblerId, ref reference2) : null); if (val2 != null) { return GameCallResult.Succeeded(val2); } return InvalidAssembler("The assembler component is no longer valid."); } public GameCallResult GetBuildCatalogOnMainThread(string? requestedSessionId) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Expected O, but got Unknown //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Expected O, but got Unknown //IL_0129: 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_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Expected O, but got Unknown //IL_027c: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_02a4: Unknown result type (might be due to invalid IL or missing references) //IL_02bc: Unknown result type (might be due to invalid IL or missing references) //IL_02cf: Unknown result type (might be due to invalid IL or missing references) //IL_02de: Expected O, but got Unknown PlanetFactory factory; BridgeError val = ValidateOwnedSessionOnMainThread(requestedSessionId, out factory); if (val != null) { return GameCallResult.Failed(val); } Player mainPlayer = GameMain.mainPlayer; GameHistoryData history = GameMain.history; if (mainPlayer == null || history == null || mainPlayer.controller?.actionBuild == null) { return GameCallResult.Failed(BridgeError.Create("BRIDGE_NOT_READY", "The player build system is not ready in the owned ordinary world.", true, "Wait until the player and local factory finish loading, then retry.")); } BuildCatalog val2 = new BuildCatalog { PlanetId = factory.planetId, Revision = _sessions.Revision, PlayerPosition = new Vector3Snapshot { X = mainPlayer.position.x, Y = mainPlayer.position.y, Z = mainPlayer.position.z }, PlayerBuildArea = mainPlayer.mecha.buildArea, SandboxToolsEnabled = GameMain.sandboxToolsEnabled }; ItemProto[] dataArray = ((ProtoSet)(object)LDB.items).dataArray; foreach (ItemProto val3 in dataArray) { if (val3 != null && val3.CanBuild && val3.prefabDesc != null) { string basicLineRole = GetBasicLineRole(val3.prefabDesc); if (basicLineRole != null) { List buildings = val2.Buildings; BuildCatalogItem val4 = new BuildCatalogItem { ItemId = ((Proto)val3).ID, Name = (((Proto)val3).name ?? string.Empty), Role = basicLineRole, ModelIndex = val3.ModelIndex, Grade = val3.Grade, BuildMode = val3.BuildMode, Unlocked = history.ItemUnlocked(((Proto)val3).ID), Available = history.ItemUnlocked(((Proto)val3).ID), RecipeType = ((object)Unsafe.As(ref val3.prefabDesc.assemblerRecipeType)/*cast due to .constrained prefix*/).ToString() }; Pose[] slotPoses = val3.prefabDesc.slotPoses; val4.SlotCount = ((slotPoses != null) ? slotPoses.Length : 0); val4.RoughRadius = val3.prefabDesc.roughRadius; val4.PowerConnectDistance = val3.prefabDesc.powerConnectDistance; val4.PowerCoverRadius = val3.prefabDesc.powerCoverRadius; buildings.Add(val4); } } } RecipeProto[] dataArray2 = ((ProtoSet)(object)LDB.recipes).dataArray; foreach (RecipeProto val5 in dataArray2) { if (val5 != null && val5.Items != null && val5.Results != null && val5.ItemCounts != null && val5.ResultCounts != null) { BuildCatalogRecipe val6 = new BuildCatalogRecipe { RecipeId = ((Proto)val5).ID, Name = (((Proto)val5).name ?? string.Empty), RecipeType = ((object)Unsafe.As(ref val5.Type)/*cast due to .constrained prefix*/).ToString(), Unlocked = history.RecipeUnlocked(((Proto)val5).ID), TimeSpend = val5.TimeSpend }; for (int j = 0; j < Math.Min(val5.Items.Length, val5.ItemCounts.Length); j++) { val6.Inputs.Add(CreateIngredient(val5.Items[j], val5.ItemCounts[j])); } for (int k = 0; k < Math.Min(val5.Results.Length, val5.ResultCounts.Length); k++) { val6.Outputs.Add(CreateIngredient(val5.Results[k], val5.ResultCounts[k])); } val2.Recipes.Add(val6); } } val2.Buildings = val2.Buildings.OrderBy((BuildCatalogItem item) => item.Role, StringComparer.Ordinal).ThenByDescending((BuildCatalogItem item) => item.Unlocked).ThenBy((BuildCatalogItem item) => item.Grade) .ThenBy((BuildCatalogItem item) => item.ItemId) .ToList(); val2.Recipes = (from recipe in val2.Recipes orderby recipe.Unlocked descending, recipe.Inputs.Any((BuildCatalogIngredient input) => input.RawMaterial) descending, recipe.RecipeId select recipe).ToList(); val2.RecommendedBasicLine = CreateRecommendation(val2); return GameCallResult.Succeeded(val2); } private List CaptureResourceNodes(PlanetFactory factory, string? kind, string? resourceType, int? productItemId) { List list = new List(); if (kind == null || kind == "vein") { int veinCursor = factory.veinCursor; VeinData[] veinPool = factory.veinPool; int num = Math.Min(veinCursor, (veinPool != null) ? veinPool.Length : 0); for (int i = 1; i < num; i++) { ResourceNodeSnapshot val = TryCaptureVein(factory, i); if (val != null && ResourceMatches(val, resourceType, productItemId)) { list.Add(val); } } } if (kind == null || kind == "vegetation") { int vegeCursor = factory.vegeCursor; VegeData[] vegePool = factory.vegePool; int num2 = Math.Min(vegeCursor, (vegePool != null) ? vegePool.Length : 0); for (int j = 1; j < num2; j++) { ResourceNodeSnapshot val2 = TryCaptureVegetation(factory, j); if (val2 != null && ResourceMatches(val2, resourceType, productItemId)) { list.Add(val2); } } } return list.OrderBy((ResourceNodeSnapshot node) => node.Kind, StringComparer.Ordinal).ThenBy((ResourceNodeSnapshot node) => node.NodeId).ToList(); } private ResourceNodeSnapshot? TryCaptureVein(PlanetFactory factory, int nodeId) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected I4, but got Unknown //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Expected I4, but got Unknown //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011a: 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_0130: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Expected O, but got Unknown //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Expected O, but got Unknown if (nodeId <= 0 || nodeId >= factory.veinCursor || nodeId >= factory.veinPool.Length) { return null; } ref VeinData reference = ref factory.veinPool[nodeId]; if (reference.id != nodeId || (int)reference.type == 0) { return null; } Player mainPlayer = GameMain.mainPlayer; float num; if (mainPlayer != null) { Vector3 val = reference.pos - mainPlayer.position; num = ((Vector3)(ref val)).magnitude; } else { num = -1f; } float num2 = num; VeinProto val2 = ((ProtoSet)(object)LDB.veins).Select((int)reference.type); ResourceNodeSnapshot val3 = new ResourceNodeSnapshot { SessionId = _sessions.SessionId, PlanetId = factory.planetId, Kind = "vein", NodeId = nodeId, ResourceType = ((object)Unsafe.As(ref reference.type)/*cast due to .constrained prefix*/).ToString(), ProtoId = (int)reference.type, Name = (((val2 != null) ? ((Proto)val2).name : null) ?? ((object)Unsafe.As(ref reference.type)/*cast due to .constrained prefix*/).ToString()), RemainingAmount = reference.amount, GroupIndex = reference.groupIndex, MinerCount = reference.minerCount, Position = CaptureVector(reference.pos), DistanceFromPlayer = num2, SameLocalPlanet = (((mainPlayer != null) ? new int?(mainPlayer.planetId) : ((int?)null)) == factory.planetId), WithinPlayerBuildArea = (((mainPlayer != null) ? mainPlayer.mecha : null) != null && num2 <= mainPlayer.mecha.buildArea), CapturedAtGameTick = GameMain.gameTick }; if (reference.productId > 0) { val3.Yields.Add(new ResourceYieldSnapshot { ItemId = reference.productId, Name = GetItemName(reference.productId), Count = 1, Chance = 1f }); } val3.StateHash = CanonicalStateHash.Resource(val3); val3.StateHashVersion = 1; return val3; } private ResourceNodeSnapshot? TryCaptureVegetation(PlanetFactory factory, int nodeId) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: 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_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Expected O, but got Unknown //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Expected O, but got Unknown if (nodeId <= 0 || nodeId >= factory.vegeCursor || nodeId >= factory.vegePool.Length) { return null; } ref VegeData reference = ref factory.vegePool[nodeId]; if (reference.id != nodeId || reference.protoId <= 0) { return null; } VegeProto val = ((ProtoSet)(object)LDB.veges).Select((int)reference.protoId); if (val == null) { return null; } Player mainPlayer = GameMain.mainPlayer; float num; if (mainPlayer != null) { Vector3 val2 = reference.pos - mainPlayer.position; num = ((Vector3)(ref val2)).magnitude; } else { num = -1f; } float num2 = num; ResourceNodeSnapshot val3 = new ResourceNodeSnapshot { SessionId = _sessions.SessionId, PlanetId = factory.planetId, Kind = "vegetation", NodeId = nodeId, ResourceType = ((object)Unsafe.As(ref val.Type)/*cast due to .constrained prefix*/).ToString(), ProtoId = reference.protoId, Name = (((Proto)val).name ?? string.Empty), RemainingAmount = 1, Position = CaptureVector(reference.pos), DistanceFromPlayer = num2, SameLocalPlanet = (((mainPlayer != null) ? new int?(mainPlayer.planetId) : ((int?)null)) == factory.planetId), WithinPlayerBuildArea = (((mainPlayer != null) ? mainPlayer.mecha : null) != null && num2 <= mainPlayer.mecha.buildArea), CapturedAtGameTick = GameMain.gameTick }; int[] array = val.MiningItem ?? Array.Empty(); int[] array2 = val.MiningCount ?? Array.Empty(); float[] array3 = val.MiningChance ?? Array.Empty(); int num3 = Math.Min(array.Length, Math.Min(array2.Length, array3.Length)); for (int i = 0; i < num3; i++) { val3.Yields.Add(new ResourceYieldSnapshot { ItemId = array[i], Name = GetItemName(array[i]), Count = array2[i], Chance = array3[i] }); } val3.StateHash = CanonicalStateHash.Resource(val3); val3.StateHashVersion = 1; return val3; } private List CaptureFactoryEntities(PlanetFactory factory, string? objectKind, string? componentKind, int? itemId) { List list = new List(); if (objectKind == null || objectKind == "entity") { int entityCursor = factory.entityCursor; EntityData[] entityPool = factory.entityPool; int num = Math.Min(entityCursor, (entityPool != null) ? entityPool.Length : 0); for (int i = 1; i < num; i++) { FactoryEntitySnapshot val = TryCaptureFactoryEntity(factory, i); if (val != null && FactoryEntityMatches(val, componentKind, itemId)) { list.Add(val); } } } if (objectKind == null || objectKind == "prebuild") { int prebuildCursor = factory.prebuildCursor; PrebuildData[] prebuildPool = factory.prebuildPool; int num2 = Math.Min(prebuildCursor, (prebuildPool != null) ? prebuildPool.Length : 0); for (int j = 1; j < num2; j++) { FactoryEntitySnapshot val2 = TryCapturePrebuild(factory, j); if (val2 != null && FactoryEntityMatches(val2, componentKind, itemId)) { list.Add(val2); } } } return list.OrderBy((FactoryEntitySnapshot snapshot) => snapshot.ObjectKind, StringComparer.Ordinal).ThenBy((FactoryEntitySnapshot snapshot) => Math.Abs(snapshot.ObjectId)).ToList(); } private FactoryEntitySnapshot? TryCaptureFactoryEntity(PlanetFactory factory, int entityId) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0062: 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_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: 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_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Expected O, but got Unknown if (entityId <= 0 || entityId >= factory.entityCursor || entityId >= factory.entityPool.Length) { return null; } ref EntityData reference = ref factory.entityPool[entityId]; if (reference.id != entityId || reference.protoId <= 0) { return null; } ItemProto val = ((ProtoSet)(object)LDB.items).Select((int)reference.protoId); FactoryEntitySnapshot val2 = new FactoryEntitySnapshot { SessionId = _sessions.SessionId, PlanetId = factory.planetId, ObjectId = entityId, ObjectKind = "entity", ItemId = reference.protoId, Name = (((val != null) ? ((Proto)val).name : null) ?? string.Empty), ComponentKind = GetComponentKind(ref reference), Position = CaptureVector(reference.pos), Rotation = CaptureQuaternion(reference.rot), CapturedAtGameTick = GameMain.gameTick }; CaptureConnections(factory, entityId, val2.Connections); CapturePower(factory, ref reference, val2); CaptureAssembler(factory, ref reference, val2); CaptureLab(factory, ref reference, val2); CaptureMiner(factory, ref reference, val2); CaptureStorage(factory, ref reference, val2); CaptureLogisticsStation(factory, ref reference, val2); CaptureTank(factory, ref reference, val2); CaptureInserter(factory, ref reference, val2); val2.StateHash = CanonicalStateHash.Factory(val2); val2.StateHashVersion = 1; val2.ConfigurationStateHash = CanonicalStateHash.FactoryConfiguration(val2); val2.ConfigurationStateHashVersion = 1; val2.EndpointStateHash = CanonicalStateHash.FactoryEndpoint(val2); val2.EndpointStateHashVersion = 1; return val2; } private FactoryEntitySnapshot? TryCapturePrebuild(PlanetFactory factory, int prebuildId) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007e: 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_0095: 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_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Expected O, but got Unknown if (prebuildId <= 0 || prebuildId >= factory.prebuildCursor || prebuildId >= factory.prebuildPool.Length) { return null; } ref PrebuildData reference = ref factory.prebuildPool[prebuildId]; if (reference.id != prebuildId || reference.protoId <= 0 || reference.isDestroyed) { return null; } ItemProto val = ((ProtoSet)(object)LDB.items).Select((int)reference.protoId); FactoryEntitySnapshot val2 = new FactoryEntitySnapshot { SessionId = _sessions.SessionId, PlanetId = factory.planetId, ObjectId = -prebuildId, ObjectKind = "prebuild", ItemId = reference.protoId, Name = (((val != null) ? ((Proto)val).name : null) ?? string.Empty), ComponentKind = GetPrefabComponentKind(val?.prefabDesc), Position = CaptureVector(reference.pos), Rotation = CaptureQuaternion(reference.rot), RecipeId = reference.recipeId }; object recipeName; if (reference.recipeId <= 0) { recipeName = null; } else { RecipeProto obj = ((ProtoSet)(object)LDB.recipes).Select(reference.recipeId); recipeName = ((obj != null) ? ((Proto)obj).name : null); } val2.RecipeName = (string)recipeName; val2.RequiredBuildItemCount = reference.itemRequired; val2.ConstructionProgress = reference.builderValue; val2.CapturedAtGameTick = GameMain.gameTick; FactoryEntitySnapshot val3 = val2; CaptureConnections(factory, -prebuildId, val3.Connections); val3.StateHash = CanonicalStateHash.Factory(val3); val3.StateHashVersion = 1; val3.ConfigurationStateHash = CanonicalStateHash.FactoryConfiguration(val3); val3.ConfigurationStateHashVersion = 1; val3.EndpointStateHash = CanonicalStateHash.FactoryEndpoint(val3); val3.EndpointStateHashVersion = 1; return val3; } private static void CaptureConnections(PlanetFactory factory, int objectId, ICollection result) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown bool isOutput = default(bool); int num = default(int); int otherSlot = default(int); for (int i = 0; i < 16; i++) { factory.ReadObjectConn(objectId, i, ref isOutput, ref num, ref otherSlot); if (num != 0) { result.Add(new FactoryConnectionSnapshot { Slot = i, IsOutput = isOutput, OtherObjectId = num, OtherSlot = otherSlot }); } } } private static void CapturePower(PlanetFactory factory, ref EntityData entity, FactoryEntitySnapshot snapshot) { //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Expected O, but got Unknown int powerConId = entity.powerConId; if (powerConId > 0 && powerConId < factory.powerSystem.consumerCursor && powerConId < factory.powerSystem.consumerPool.Length) { ref PowerConsumerComponent reference = ref factory.powerSystem.consumerPool[powerConId]; if (reference.id == powerConId && reference.entityId == entity.id) { snapshot.PowerNetworkId = reference.networkId; snapshot.PowerDemandPerTick = reference.requiredEnergy; snapshot.PowerServeRatio = GetPowerServeRatio(factory.powerSystem, reference.networkId); return; } } int powerGenId = entity.powerGenId; if (powerGenId > 0 && powerGenId < factory.powerSystem.genCursor && powerGenId < factory.powerSystem.genPool.Length) { ref PowerGeneratorComponent reference2 = ref factory.powerSystem.genPool[powerGenId]; if (reference2.id == powerGenId && reference2.entityId == entity.id) { snapshot.PowerNetworkId = reference2.networkId; snapshot.PowerServeRatio = GetPowerServeRatio(factory.powerSystem, reference2.networkId); snapshot.Buffers.Add(new FactoryBufferSnapshot { Role = "power-generation-current-tick", ItemId = reference2.curFuelId, Name = GetItemName(reference2.curFuelId), Count = (int)((reference2.generateCurrentTick > int.MaxValue) ? int.MaxValue : Math.Max(0L, reference2.generateCurrentTick)) }); } } } private static double? GetPowerServeRatio(PowerSystem powerSystem, int networkId) { if (networkId <= 0 || networkId >= powerSystem.netCursor || networkId >= powerSystem.netPool.Length) { return null; } PowerNetwork val = powerSystem.netPool[networkId]; if (val == null || val.id != networkId) { return null; } return val.consumerRatio; } private static void CaptureAssembler(PlanetFactory factory, ref EntityData entity, FactoryEntitySnapshot snapshot) { int assemblerId = entity.assemblerId; if (assemblerId <= 0 || assemblerId >= factory.factorySystem.assemblerCursor || assemblerId >= factory.factorySystem.assemblerPool.Length) { return; } ref AssemblerComponent reference = ref factory.factorySystem.assemblerPool[assemblerId]; if (reference.id == assemblerId && reference.entityId == entity.id) { snapshot.RecipeId = reference.recipeId; object recipeName; if (reference.recipeId <= 0) { recipeName = null; } else { RecipeProto obj = ((ProtoSet)(object)LDB.recipes).Select(reference.recipeId); recipeName = ((obj != null) ? ((Proto)obj).name : null); } snapshot.RecipeName = (string)recipeName; snapshot.IsWorking = reference.replicating; snapshot.Progress = reference.time; snapshot.ProgressRequired = reference.recipeExecuteData?.timeSpend ?? 0; if (reference.recipeExecuteData != null) { AddFactoryBuffers(snapshot.Buffers, "input", reference.recipeExecuteData.requires, reference.served, reference.incServed); AddFactoryBuffers(snapshot.Buffers, "output", reference.recipeExecuteData.products, reference.produced, null); } } } private static void CaptureLab(PlanetFactory factory, ref EntityData entity, FactoryEntitySnapshot snapshot) { //IL_00fc: Unknown result type (might be due to invalid IL or missing references) int labId = entity.labId; if (labId <= 0 || labId >= factory.factorySystem.labCursor || labId >= factory.factorySystem.labPool.Length) { return; } ref LabComponent reference = ref factory.factorySystem.labPool[labId]; if (reference.id == labId && reference.entityId == entity.id) { snapshot.RecipeId = reference.recipeId; object recipeName; if (reference.recipeId <= 0) { recipeName = null; } else { RecipeProto obj = ((ProtoSet)(object)LDB.recipes).Select(reference.recipeId); recipeName = ((obj != null) ? ((Proto)obj).name : null); } snapshot.RecipeName = (string)recipeName; snapshot.IsWorking = reference.replicating; snapshot.Progress = (reference.researchMode ? reference.hashBytes : reference.time); int progressRequired; if (!reference.researchMode) { progressRequired = reference.recipeExecuteData?.timeSpend ?? 0; } else { GameHistoryData history = GameMain.history; progressRequired = (int)((history != null && history.techStates.TryGetValue(reference.techId, out var value)) ? Math.Min(2147483647L, value.hashNeeded) : 0); } snapshot.ProgressRequired = progressRequired; if (reference.researchMode) { AddFactoryBuffers(snapshot.Buffers, "research-matrix", LabComponent.matrixIds, reference.matrixServed, reference.matrixIncServed); } else if (reference.recipeExecuteData != null) { AddFactoryBuffers(snapshot.Buffers, "input", reference.recipeExecuteData.requires, reference.served, reference.incServed); AddFactoryBuffers(snapshot.Buffers, "output", reference.recipeExecuteData.products, reference.produced, null); } } } private static void CaptureMiner(PlanetFactory factory, ref EntityData entity, FactoryEntitySnapshot snapshot) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Invalid comparison between Unknown and I4 //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Expected O, but got Unknown int minerId = entity.minerId; if (minerId <= 0 || minerId >= factory.factorySystem.minerCursor || minerId >= factory.factorySystem.minerPool.Length) { return; } ref MinerComponent reference = ref factory.factorySystem.minerPool[minerId]; if (reference.id != minerId || reference.entityId != entity.id) { return; } snapshot.IsWorking = (int)reference.workstate > 0; snapshot.Progress = reference.time; snapshot.ProgressRequired = reference.period; snapshot.InsertTargetObjectId = ((reference.insertTarget == 0) ? ((int?)null) : new int?(reference.insertTarget)); int[] array = reference.veins ?? Array.Empty(); int num = Math.Min(reference.veinCount, array.Length); for (int i = 0; i < num; i++) { if (array[i] > 0) { snapshot.ResourceNodeIds.Add(array[i]); } } if (reference.productId > 0 || reference.productCount > 0) { snapshot.Buffers.Add(new FactoryBufferSnapshot { Role = "mined-output", ItemId = reference.productId, Name = GetItemName(reference.productId), Count = reference.productCount }); } } private static void CaptureStorage(PlanetFactory factory, ref EntityData entity, FactoryEntitySnapshot snapshot) { //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Expected O, but got Unknown int storageId = entity.storageId; if (storageId <= 0 || storageId >= factory.factoryStorage.storageCursor || storageId >= factory.factoryStorage.storagePool.Length) { return; } StorageComponent val = factory.factoryStorage.storagePool[storageId]; if (val == null || val.id != storageId || val.entityId != entity.id) { return; } GRID[] array = val.grids ?? Array.Empty(); int num = Math.Min(val.size, array.Length); for (int i = 0; i < num; i++) { GRID val2 = array[i]; if (val2.itemId > 0 && val2.count > 0) { snapshot.Buffers.Add(new FactoryBufferSnapshot { Role = "storage", ItemId = val2.itemId, Name = GetItemName(val2.itemId), Count = val2.count, Inc = val2.inc }); } } } private unsafe void CaptureLogisticsStation(PlanetFactory factory, ref EntityData entity, FactoryEntitySnapshot snapshot) { //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_0256: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_02b0: Unknown result type (might be due to invalid IL or missing references) //IL_02bc: Unknown result type (might be due to invalid IL or missing references) //IL_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_02d4: Unknown result type (might be due to invalid IL or missing references) //IL_02e0: Unknown result type (might be due to invalid IL or missing references) //IL_02ec: Unknown result type (might be due to invalid IL or missing references) //IL_02f8: Unknown result type (might be due to invalid IL or missing references) //IL_0304: Unknown result type (might be due to invalid IL or missing references) //IL_0310: Unknown result type (might be due to invalid IL or missing references) //IL_031c: Unknown result type (might be due to invalid IL or missing references) //IL_0328: Unknown result type (might be due to invalid IL or missing references) //IL_0334: Unknown result type (might be due to invalid IL or missing references) //IL_0340: Unknown result type (might be due to invalid IL or missing references) //IL_0357: Unknown result type (might be due to invalid IL or missing references) //IL_0364: Expected O, but got Unknown //IL_03cf: Unknown result type (might be due to invalid IL or missing references) //IL_03d4: Unknown result type (might be due to invalid IL or missing references) //IL_03dd: Unknown result type (might be due to invalid IL or missing references) //IL_03e2: Unknown result type (might be due to invalid IL or missing references) //IL_03ea: Unknown result type (might be due to invalid IL or missing references) //IL_03eb: Unknown result type (might be due to invalid IL or missing references) //IL_03f7: Unknown result type (might be due to invalid IL or missing references) //IL_03f8: Unknown result type (might be due to invalid IL or missing references) //IL_0405: Unknown result type (might be due to invalid IL or missing references) //IL_0416: Unknown result type (might be due to invalid IL or missing references) //IL_0417: Unknown result type (might be due to invalid IL or missing references) //IL_0423: Unknown result type (might be due to invalid IL or missing references) //IL_0424: Unknown result type (might be due to invalid IL or missing references) //IL_0430: Unknown result type (might be due to invalid IL or missing references) //IL_0431: Unknown result type (might be due to invalid IL or missing references) //IL_043d: Unknown result type (might be due to invalid IL or missing references) //IL_043e: Unknown result type (might be due to invalid IL or missing references) //IL_044a: Unknown result type (might be due to invalid IL or missing references) //IL_044b: Unknown result type (might be due to invalid IL or missing references) //IL_0457: Unknown result type (might be due to invalid IL or missing references) //IL_0464: Unknown result type (might be due to invalid IL or missing references) //IL_0471: Unknown result type (might be due to invalid IL or missing references) //IL_047e: Unknown result type (might be due to invalid IL or missing references) //IL_048b: Unknown result type (might be due to invalid IL or missing references) //IL_0498: Unknown result type (might be due to invalid IL or missing references) //IL_04b0: Unknown result type (might be due to invalid IL or missing references) //IL_04c8: Unknown result type (might be due to invalid IL or missing references) //IL_04c9: Unknown result type (might be due to invalid IL or missing references) //IL_04d5: Unknown result type (might be due to invalid IL or missing references) //IL_04d6: Unknown result type (might be due to invalid IL or missing references) //IL_04e7: Expected O, but got Unknown //IL_0512: Unknown result type (might be due to invalid IL or missing references) //IL_0517: Unknown result type (might be due to invalid IL or missing references) //IL_0520: Unknown result type (might be due to invalid IL or missing references) //IL_0525: Unknown result type (might be due to invalid IL or missing references) //IL_052d: Unknown result type (might be due to invalid IL or missing references) //IL_0545: Unknown result type (might be due to invalid IL or missing references) //IL_0546: Unknown result type (might be due to invalid IL or missing references) //IL_0552: Unknown result type (might be due to invalid IL or missing references) //IL_0554: Unknown result type (might be due to invalid IL or missing references) //IL_0565: Unknown result type (might be due to invalid IL or missing references) //IL_0566: Unknown result type (might be due to invalid IL or missing references) //IL_0572: Unknown result type (might be due to invalid IL or missing references) //IL_0573: Unknown result type (might be due to invalid IL or missing references) //IL_0584: Expected O, but got Unknown int stationId = entity.stationId; PlanetTransport transport = factory.transport; if (stationId <= 0 || transport?.stationPool == null || stationId >= transport.stationCursor || stationId >= transport.stationPool.Length) { return; } StationComponent val = transport.stationPool[stationId]; if (val == null || val.id != stationId || val.entityId != entity.id || !LogisticsStationIdentityPolicy.MatchesLocalPlanet(val.isStellar, val.planetId, factory.planetId)) { return; } long num = 0L; int pcId = val.pcId; if (pcId > 0 && pcId == entity.powerConId && pcId < factory.powerSystem.consumerCursor && pcId < factory.powerSystem.consumerPool.Length) { ref PowerConsumerComponent reference = ref factory.powerSystem.consumerPool[pcId]; if (reference.id == pcId && reference.entityId == entity.id) { num = reference.workEnergyPerTick; } } LogisticsStationSnapshot val2 = new LogisticsStationSnapshot { SessionId = _sessions.SessionId, PlanetId = factory.planetId, EntityId = entity.id, StationId = val.id, GalacticStationId = val.gid, BuildingItemId = entity.protoId, BuildingName = GetItemName(entity.protoId), Position = CaptureVector(entity.pos), IsInterstellar = val.isStellar, IsCollector = val.isCollector, IsVeinCollector = val.isVeinCollector, PowerNetworkId = snapshot.PowerNetworkId, PowerServeRatio = snapshot.PowerServeRatio, Energy = val.energy, EnergyCapacity = val.energyMax, RequestedChargeEnergyPerTick = val.energyPerTick, RequestedChargePowerWatts = val.energyPerTick * 60, MaximumChargeEnergyPerTick = num, MaximumChargePowerWatts = num * 60, WarperCount = val.warperCount, WarperCapacity = val.warperMaxCount, IdleDroneCount = val.idleDroneCount, DroneCapacity = (((ProtoSet)(object)LDB.items).Select((int)entity.protoId)?.prefabDesc?.stationMaxDroneCount).GetValueOrDefault(), WorkingDroneCount = val.workDroneCount, IdleVesselCount = val.idleShipCount, VesselCapacity = (((ProtoSet)(object)LDB.items).Select((int)entity.protoId)?.prefabDesc?.stationMaxShipCount).GetValueOrDefault(), WorkingVesselCount = val.workShipCount, DroneTripRangeRaw = val.tripRangeDrones, VesselTripRangeRaw = val.tripRangeShips, IncludeOrbitCollectors = val.includeOrbitCollector, WarpEnableDistanceRaw = val.warpEnableDist, WarpersRequired = val.warperNecessary, DroneDeliverySetting = val.deliveryDrones, VesselDeliverySetting = val.deliveryShips, PilerCount = val.pilerCount, DroneAutoReplenish = val.droneAutoReplenish, VesselAutoReplenish = val.shipAutoReplenish, RemoteGroupMask = val.remoteGroupMask, RemoteRoutePriority = ((object)Unsafe.As(ref val.routePriority)/*cast due to .constrained prefix*/).ToString(), CapturedAtGameTick = GameMain.gameTick }; int[] array = val.needs ?? Array.Empty(); foreach (int num2 in array) { if (num2 > 0 && !val2.NeededItemIds.Contains(num2)) { val2.NeededItemIds.Add(num2); } } StationStore[] array2 = val.storage ?? Array.Empty(); for (int j = 0; j < array2.Length; j++) { StationStore val3 = array2[j]; val2.StorageSlots.Add(new LogisticsStationStorageSlotSnapshot { Index = j, ItemId = val3.itemId, ItemName = ((val3.itemId > 0) ? GetItemName(val3.itemId) : null), Count = val3.count, Inc = val3.inc, MaximumCount = val3.max, LocalOrder = val3.localOrder, RemoteOrder = val3.remoteOrder, TotalOrdered = ((StationStore)(ref val3)).totalOrdered, LocalSupplyCount = ((StationStore)(ref val3)).localSupplyCount, LocalDemandCount = ((StationStore)(ref val3)).localDemandCount, RemoteSupplyCount = ((StationStore)(ref val3)).remoteSupplyCount, RemoteDemandCount = ((StationStore)(ref val3)).remoteDemandCount, LocalLogic = ((object)(*(ELogisticStorage*)(&val3.localLogic))/*cast due to .constrained prefix*/).ToString(), RemoteLogic = ((object)(*(ELogisticStorage*)(&val3.remoteLogic))/*cast due to .constrained prefix*/).ToString(), KeepMode = val3.keepMode, KeepIncRatio = val3.keepIncRatio }); } SlotData[] array3 = val.slots ?? Array.Empty(); for (int k = 0; k < array3.Length; k++) { SlotData val4 = array3[k]; val2.BeltSlots.Add(new LogisticsStationBeltSlotSnapshot { Index = k, Direction = ((object)(*(IODir*)(&val4.dir))/*cast due to .constrained prefix*/).ToString(), BeltComponentId = val4.beltId, BeltEntityId = ResolveBeltEntityId(factory, val4.beltId), StorageIndex = val4.storageIdx, Counter = val4.counter }); } val2.NeededItemIds.Sort(); val2.StateHash = CanonicalStateHash.LogisticsStation(val2); val2.StateHashVersion = 1; val2.ConfigurationStateHash = CanonicalStateHash.LogisticsStationConfiguration(val2); val2.ConfigurationStateHashVersion = 1; val2.FleetStateHash = CanonicalStateHash.LogisticsStationFleet(val2); val2.FleetStateHashVersion = 1; snapshot.LogisticsStation = val2; } private static int ResolveBeltEntityId(PlanetFactory factory, int beltId) { CargoTraffic cargoTraffic = factory.cargoTraffic; if (beltId <= 0 || cargoTraffic?.beltPool == null || beltId >= cargoTraffic.beltCursor || beltId >= cargoTraffic.beltPool.Length) { return 0; } ref BeltComponent reference = ref cargoTraffic.beltPool[beltId]; if (reference.id != beltId) { return 0; } return reference.entityId; } public GameCallResult GetLocalStarSystemOnMainThread(string? requestedSessionId, LocalPlanetRequest request) { //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Unknown result type (might be due to invalid IL or missing references) //IL_024c: Unknown result type (might be due to invalid IL or missing references) //IL_0259: Unknown result type (might be due to invalid IL or missing references) //IL_0266: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Unknown result type (might be due to invalid IL or missing references) //IL_027b: Expected O, but got Unknown //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Invalid comparison between Unknown and I4 //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Expected O, but got Unknown //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Expected O, but got Unknown PlanetFactory factory; BridgeError val = ValidateOwnedPlanetOnMainThread(requestedSessionId, request.PlanetId, out factory); if (val != null) { return GameCallResult.Failed(val); } Player mainPlayer = GameMain.mainPlayer; GalaxyData galaxy = GameMain.galaxy; PlanetData localPlanet = GameMain.localPlanet; StarData localStar = GameMain.localStar; if (mainPlayer == null || galaxy == null || localPlanet == null || localStar?.planets == null) { return GameCallResult.Failed(NotReady("The local star system is not ready in the owned ordinary world.")); } List list = new List(); foreach (PlanetData item in from candidate in localStar.planets where candidate != null orderby candidate.id select candidate) { ThemeProto val2 = ((ProtoSet)(object)LDB.themes).Select(item.theme); List potentialResourceTypes = CapturePotentialResourceTypes(val2); VectorLF3 uPosition = item.uPosition; PlanetSnapshot val3 = new PlanetSnapshot { PlanetId = item.id, Name = item.displayName, PlanetType = ((object)Unsafe.As(ref item.type)/*cast due to .constrained prefix*/).ToString(), ThemeId = item.theme, ThemeName = (((val2 != null) ? val2.displayName : null) ?? string.Empty), IsCurrentPlanet = (item.id == localPlanet.id), IsBirthPlanet = (item.id == galaxy.birthPlanetId), IsGasGiant = ((int)item.type == 5), FactoryLoaded = item.factoryLoaded, RealRadius = item.realRadius, OrbitRadius = item.orbitRadius }; VectorLF3 val4 = item.uPosition - mainPlayer.uPosition; val3.DistanceFromPlayer = ((VectorLF3)(ref val4)).magnitude; val3.UniversalPosition = new UniversalPositionSnapshot { X = uPosition.x, Y = uPosition.y, Z = uPosition.z }; val3.PotentialResourceTypes = potentialResourceTypes; list.Add(val3); } LocalStarSystemSnapshot val5 = new LocalStarSystemSnapshot { SessionId = _sessions.SessionId, LocalPlanetId = localPlanet.id, StarId = localStar.id, StarName = localStar.displayName, CapturedAtGameTick = GameMain.gameTick, Planets = list }; val5.StateHash = CanonicalStateHash.Combine("local-star-system", new object[3] { val5.SessionId, val5.StarId, string.Join("|", list.Select((PlanetSnapshot planet) => string.Format("{0}:{1}:{2}:{3}:{4}:{5}", planet.PlanetId, planet.Name, planet.PlanetType, planet.ThemeId, planet.IsGasGiant, string.Join(",", planet.PotentialResourceTypes)))) }); return GameCallResult.Succeeded(val5); } private static void CaptureTank(PlanetFactory factory, ref EntityData entity, FactoryEntitySnapshot snapshot) { //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Expected O, but got Unknown int tankId = entity.tankId; if (tankId > 0 && tankId < factory.factoryStorage.tankCursor && tankId < factory.factoryStorage.tankPool.Length) { ref TankComponent reference = ref factory.factoryStorage.tankPool[tankId]; if (reference.id == tankId && reference.entityId == entity.id && reference.fluidId > 0 && reference.fluidCount > 0) { snapshot.Buffers.Add(new FactoryBufferSnapshot { Role = "tank-fluid", ItemId = reference.fluidId, Name = GetItemName(reference.fluidId), Count = reference.fluidCount, Inc = reference.fluidInc }); } } } private static void CaptureInserter(PlanetFactory factory, ref EntityData entity, FactoryEntitySnapshot snapshot) { //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Expected O, but got Unknown int inserterId = entity.inserterId; if (inserterId <= 0 || inserterId >= factory.factorySystem.inserterCursor || inserterId >= factory.factorySystem.inserterPool.Length) { return; } ref InserterComponent reference = ref factory.factorySystem.inserterPool[inserterId]; if (reference.id == inserterId && reference.entityId == entity.id) { snapshot.PickTargetObjectId = ((reference.pickTarget == 0) ? ((int?)null) : new int?(reference.pickTarget)); snapshot.InsertTargetObjectId = ((reference.insertTarget == 0) ? ((int?)null) : new int?(reference.insertTarget)); snapshot.FilterItemId = ((reference.filter == 0) ? ((int?)null) : new int?(reference.filter)); snapshot.FilterItemName = ((reference.filter > 0) ? GetItemName(reference.filter) : null); snapshot.InserterStage = ((object)Unsafe.As(ref reference.stage)/*cast due to .constrained prefix*/).ToString(); snapshot.InserterStackCount = reference.stackCount; snapshot.IsWorking = reference.pickTarget != 0 && reference.insertTarget != 0 && (reference.itemCount > 0 || reference.time > 0); snapshot.Progress = reference.time; snapshot.ProgressRequired = reference.stt; if (reference.itemId > 0 && reference.itemCount > 0) { snapshot.Buffers.Add(new FactoryBufferSnapshot { Role = "inserter-held", ItemId = reference.itemId, Name = GetItemName(reference.itemId), Count = reference.itemCount, Inc = reference.itemInc }); } } } private static void AddFactoryBuffers(ICollection target, string role, int[]? itemIds, int[]? counts, int[]? incs) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0029: 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_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown int num = Math.Min((itemIds != null) ? itemIds.Length : 0, (counts != null) ? counts.Length : 0); for (int i = 0; i < num; i++) { target.Add(new FactoryBufferSnapshot { Role = role, ItemId = itemIds[i], Name = GetItemName(itemIds[i]), Count = counts[i], Inc = ((i < ((incs != null) ? incs.Length : 0)) ? incs[i] : 0) }); } } private static string GetComponentKind(ref EntityData entity) { if (entity.minerId > 0) { return "miner"; } if (entity.assemblerId > 0) { return "assembler"; } if (entity.labId > 0) { return "lab"; } if (entity.inserterId > 0) { return "inserter"; } if (entity.beltId > 0) { return "belt"; } if (entity.storageId > 0) { return "storage"; } if (entity.tankId > 0) { return "tank"; } if (entity.powerGenId > 0) { return "power-generator"; } if (entity.powerNodeId > 0) { return "power-node"; } if (entity.stationId > 0) { return "station"; } if (entity.splitterId > 0) { return "splitter"; } if (entity.fractionatorId > 0) { return "fractionator"; } if (entity.spraycoaterId > 0) { return "spray-coater"; } if (entity.pilerId > 0) { return "piler"; } return "other"; } private static string GetPrefabComponentKind(PrefabDesc? descriptor) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (descriptor == null) { return "other"; } if (descriptor.veinMiner || descriptor.oilMiner || (int)descriptor.minerType != 0) { return "miner"; } if (descriptor.isLab) { return "lab"; } if (descriptor.isAssembler) { return "assembler"; } if (descriptor.isInserter) { return "inserter"; } if (descriptor.isBelt) { return "belt"; } if (descriptor.isStorage) { return "storage"; } if (descriptor.isPowerGen) { return "power-generator"; } if (descriptor.isPowerNode) { return "power-node"; } if (descriptor.isStation) { return "station"; } if (descriptor.isSplitter) { return "splitter"; } if (descriptor.isFractionator) { return "fractionator"; } return "other"; } private BridgeError? ValidateOwnedPlanetOnMainThread(string? requestedSessionId, int requestedPlanetId, out PlanetFactory? factory) { BridgeError val = ValidateOwnedSessionOnMainThread(requestedSessionId, out factory); if (val != null) { return val; } if (requestedPlanetId <= 0 || factory.planetId != requestedPlanetId) { factory = null; return BridgeError.Create("STALE_STATE", "The requested planet does not match the currently loaded local planet.", true, "Call get_session_state and retry with its current localPlanetId."); } return null; } private BridgeError? ValidateOwnedSessionOnMainThread(string? requestedSessionId, out PlanetFactory? factory) { factory = null; SessionState val = _sessions.CaptureOnMainThread(); if (!val.GameLoaded) { return BridgeError.Create("GAME_NOT_LOADED", "No game session is currently loaded.", true, "Create and load a Spherewright-owned ordinary world, then retry."); } if (!val.OwnedBySpherewright) { return BridgeError.Create("SESSION_NOT_OWNED", "The loaded game session was not created by this Spherewright Plugin process, so its contents are restricted.", false, "Return to the main menu and create a Spherewright-owned ordinary world."); } if (string.IsNullOrWhiteSpace(requestedSessionId) || !string.Equals(requestedSessionId, val.SessionId, StringComparison.Ordinal)) { return BridgeError.Create("STALE_SESSION", "The supplied session ID does not match the active owned session.", true, "Call get_session_state and retry with its sessionId."); } GameData data = GameMain.data; factory = ((data != null) ? data.localLoadedPlanetFactory : null); if (factory == null) { return BridgeError.Create("NO_LOCAL_PLANET", "The owned session does not currently have a loaded local factory.", true, "Wait for the local planet factory to load and retry."); } return null; } private AssemblerSnapshot? TryCaptureAssembler(PlanetFactory factory, int componentId, ref AssemblerComponent assembler) { //IL_0065: 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_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0084: 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_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Expected O, but got Unknown //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Expected O, but got Unknown int entityId = assembler.entityId; if (entityId <= 0 || entityId >= factory.entityCursor) { return null; } ref EntityData reference = ref factory.entityPool[entityId]; if (reference.id != entityId || reference.assemblerId != componentId) { return null; } ItemProto val = ((ProtoSet)(object)LDB.items).Select((int)reference.protoId); RecipeProto val2 = ((assembler.recipeId > 0) ? ((ProtoSet)(object)LDB.recipes).Select(assembler.recipeId) : null); return new AssemblerSnapshot { PlanetId = factory.planetId, EntityId = entityId, ComponentId = componentId, BuildingItemId = reference.protoId, BuildingName = (((val != null) ? ((Proto)val).name : null) ?? string.Empty), RecipeId = assembler.recipeId, RecipeName = ((val2 != null) ? ((Proto)val2).name : null), TimeSpent = assembler.time, TimeRequired = (assembler.recipeExecuteData?.timeSpend ?? 0), IsWorking = assembler.replicating, Position = new Vector3Snapshot { X = reference.pos.x, Y = reference.pos.y, Z = reference.pos.z }, Revision = _sessions.Revision }; } private static void AddPlayerItemAmounts(ICollection target, int[]? itemIds, int[]? counts, int[]? bufferedCounts) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Expected O, but got Unknown int num = Math.Min((itemIds != null) ? itemIds.Length : 0, (counts != null) ? counts.Length : 0); for (int i = 0; i < num; i++) { target.Add(new PlayerItemAmount { ItemId = itemIds[i], Name = GetItemName(itemIds[i]), Count = counts[i], BufferedCount = ((i < ((bufferedCounts != null) ? bufferedCounts.Length : 0)) ? bufferedCounts[i] : 0) }); } } private static void AddCatalogAmounts(ICollection target, int[]? itemIds, int[]? counts) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown int num = Math.Min((itemIds != null) ? itemIds.Length : 0, (counts != null) ? counts.Length : 0); for (int i = 0; i < num; i++) { target.Add(new CatalogItemAmount { ItemId = itemIds[i], Name = GetItemName(itemIds[i]), Count = counts[i] }); } } private static bool ResourceMatches(ResourceNodeSnapshot snapshot, string? resourceType, int? productItemId) { if (resourceType == null || string.Equals(snapshot.ResourceType, resourceType, StringComparison.OrdinalIgnoreCase)) { if (productItemId.HasValue) { return snapshot.Yields.Any((ResourceYieldSnapshot item) => item.ItemId == productItemId.Value); } return true; } return false; } private static bool FactoryEntityMatches(FactoryEntitySnapshot snapshot, string? componentKind, int? itemId) { if (componentKind == null || string.Equals(snapshot.ComponentKind, componentKind, StringComparison.OrdinalIgnoreCase)) { if (itemId.HasValue) { return snapshot.ItemId == itemId.Value; } return true; } return false; } private static List CapturePotentialResourceTypes(ThemeProto? theme) { if (theme == null) { return new List(); } SortedSet sortedSet = new SortedSet(); int[] array = theme.VeinSpot ?? Array.Empty(); for (int i = 0; i < array.Length && i + 1 < 15; i++) { if (array[i] > 0) { sortedSet.Add(i + 1); } } int[] array2 = theme.RareVeins ?? Array.Empty(); foreach (int num in array2) { if (num > 0 && num < 15) { sortedSet.Add(num); } } return sortedSet.Select((int value) => ((object)(EVeinType)(byte)value/*cast due to .constrained prefix*/).ToString()).ToList(); } private static Vector3Snapshot CaptureVector(Vector3 value) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown return new Vector3Snapshot { X = value.x, Y = value.y, Z = value.z }; } private static QuaternionSnapshot CaptureQuaternion(Quaternion value) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown return new QuaternionSnapshot { X = value.x, Y = value.y, Z = value.z, W = value.w }; } private static string GetItemName(int itemId) { if (itemId <= 0) { return string.Empty; } ItemProto obj = ((ProtoSet)(object)LDB.items).Select(itemId); return ((obj != null) ? ((Proto)obj).name : null) ?? string.Empty; } private static string? NormalizeOptional(string? value) { if (!string.IsNullOrWhiteSpace(value)) { return value.Trim().ToLowerInvariant(); } return null; } private static string ComputeFilterHash(string canonicalFilter) { using SHA256 sHA = SHA256.Create(); byte[] array = sHA.ComputeHash(Encoding.UTF8.GetBytes(canonicalFilter)); StringBuilder stringBuilder = new StringBuilder(array.Length * 2); byte[] array2 = array; foreach (byte b in array2) { stringBuilder.Append(b.ToString("x2")); } return "sha256:" + stringBuilder; } private static BridgeError? ValidateListLimit(int limit, string label) { if (limit < 1 || limit > 100) { return BridgeError.Create("INVALID_REQUEST", $"{label} list limit must be between 1 and {100}.", false, "Use a bounded limit and retry."); } return null; } private static BridgeError InvalidRequest(string message, string recovery) { return BridgeError.Create("INVALID_REQUEST", message, false, recovery); } private static BridgeError NotReady(string message) { return BridgeError.Create("BRIDGE_NOT_READY", message, true, "Wait until the owned ordinary world finishes loading, then retry."); } private static BridgeError StaleCursor(string message) { return BridgeError.Create("STALE_CURSOR", message, true, "Discard the cursor and start a new listing with the current session, planet, and filters."); } private static BridgeError SnapshotCapacityExceeded(string label) { return BridgeError.Create("SERVER_BUSY", "The bounded " + label + " snapshot capacity is temporarily full.", true, "Wait for an existing snapshot to expire, then start a new listing."); } private static GameCallResult InvalidResource(string message) { return GameCallResult.Failed(BridgeError.Create("INVALID_ENTITY", message, false, "Refresh the resource-node list and use a current kind and node ID.")); } private static GameCallResult InvalidFactoryEntity(string message) { return GameCallResult.Failed(BridgeError.Create("INVALID_ENTITY", message, false, "Refresh the factory-entity list and use a current object ID.")); } private static string? GetBasicLineRole(PrefabDesc descriptor) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Invalid comparison between Unknown and I4 //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Invalid comparison between Unknown and I4 //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Invalid comparison between Unknown and I4 //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Invalid comparison between Unknown and I4 if ((int)descriptor.minerType == 1) { return "water-pump"; } if (descriptor.oilMiner || (int)descriptor.minerType == 3) { return "oil-extractor"; } if (descriptor.veinMiner || (int)descriptor.minerType == 2) { return "vein-miner"; } if (descriptor.isBelt) { return "belt"; } if (descriptor.isStorage && !descriptor.isTank && !descriptor.isStation && !descriptor.isBattleBase) { return "storage"; } if (descriptor.isTank) { return "tank"; } if (descriptor.isAssembler && (int)descriptor.assemblerRecipeType == 1) { return "smelter"; } if (descriptor.isAssembler && (int)descriptor.assemblerRecipeType == 3) { return "refinery"; } if (descriptor.isAssembler) { return "assembler"; } if (descriptor.isLab) { return "matrix-lab"; } if (descriptor.isInserter) { return "inserter"; } if (descriptor.isPowerGen && descriptor.windForcedPower && descriptor.isPowerNode) { return "wind-power"; } if (descriptor.isPowerGen) { return "power-generator"; } if (descriptor.isPowerNode) { return "power-node"; } return null; } private static BuildCatalogIngredient CreateIngredient(int itemId, int count) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown ItemProto val = ((ProtoSet)(object)LDB.items).Select(itemId); return new BuildCatalogIngredient { ItemId = itemId, Name = (((val != null) ? ((Proto)val).name : null) ?? string.Empty), Count = count, RawMaterial = (val?.isRaw ?? false) }; } private static BasicLineRecommendation? CreateRecommendation(BuildCatalog catalog) { //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011d: 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_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Expected O, but got Unknown BuildCatalogItem val = ((IEnumerable)catalog.Buildings).FirstOrDefault((Func)((BuildCatalogItem item) => item.Available && item.Role == "storage")); BuildCatalogItem val2 = ((IEnumerable)catalog.Buildings).FirstOrDefault((Func)((BuildCatalogItem item) => item.Available && item.Role == "smelter")); BuildCatalogItem val3 = ((IEnumerable)catalog.Buildings).FirstOrDefault((Func)((BuildCatalogItem item) => item.Available && item.Role == "inserter")); BuildCatalogItem val4 = ((IEnumerable)catalog.Buildings).FirstOrDefault((Func)((BuildCatalogItem item) => item.Available && item.Role == "wind-power")); BuildCatalogRecipe val5 = ((IEnumerable)catalog.Recipes).FirstOrDefault((Func)((BuildCatalogRecipe item) => item.Unlocked && item.Inputs.Count > 0 && item.Inputs[0].RawMaterial)) ?? ((IEnumerable)catalog.Recipes).FirstOrDefault((Func)((BuildCatalogRecipe item) => item.Unlocked && item.Inputs.Count > 0 && item.Outputs.Count > 0)); if (val == null || val2 == null || val3 == null || val4 == null || val5 == null) { return null; } return new BasicLineRecommendation { StorageItemId = val.ItemId, AssemblerItemId = val2.ItemId, InserterItemId = val3.ItemId, PowerGeneratorItemId = val4.ItemId, RecipeId = val5.RecipeId, InputItemId = val5.Inputs[0].ItemId, OutputItemId = val5.Outputs[0].ItemId }; } private static GameCallResult InvalidAssembler(string message) { return GameCallResult.Failed(BridgeError.Create("INVALID_ENTITY", message, false, "Refresh the assembler list and use a current assembler entity ID.")); } } internal sealed class GameVersionSnapshotProvider { private string _lastKnownVersion = "unknown"; public unsafe string CaptureOnMainThread() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) Version gameVersion = GameConfig.gameVersion; int build = GameConfig.build; if (build > 0) { _lastKnownVersion = $"{gameVersion.Major}.{gameVersion.Minor}.{gameVersion.Release}.{build}"; return _lastKnownVersion; } if (gameVersion.Build > 0) { _lastKnownVersion = ((Version)(ref gameVersion)).ToFullString(); return _lastKnownVersion; } string text = TryReadLatestVersionFile(Paths.GameRootPath); if (!string.IsNullOrWhiteSpace(text)) { _lastKnownVersion = text; } else { _lastKnownVersion = ((object)(*(Version*)(&gameVersion))/*cast due to .constrained prefix*/).ToString(); } return _lastKnownVersion; } private static string? TryReadLatestVersionFile(string gameRoot) { try { string path = Path.Combine(gameRoot, "Updates", "Versions.txt"); if (!File.Exists(path)) { return null; } string? text = (from line in File.ReadLines(path) where !string.IsNullOrWhiteSpace(line) select line).LastOrDefault(); return (text != null) ? text.Split(new char[1] { ',' })[0].Trim() : null; } catch (IOException) { return null; } catch (UnauthorizedAccessException) { return null; } } } internal sealed class NormalGameActionCoordinator { private sealed class CommonPrepareResult { public SessionState? Session { get; } public BridgeError? Error { get; } private CommonPrepareResult(SessionState? session, BridgeError? error) { Session = session; Error = error; } public static CommonPrepareResult Succeeded(SessionState session) { return new CommonPrepareResult(session, null); } public static CommonPrepareResult Failed(BridgeError error) { return new CommonPrepareResult(null, error); } } private sealed class ActionRecord { public string ActionId { get; set; } = string.Empty; public string ActionKind { get; set; } = string.Empty; public string SessionId { get; set; } = string.Empty; public int PlanetId { get; set; } public string IdempotencyKey { get; set; } = string.Empty; public string State { get; set; } = string.Empty; public bool Terminal { get; set; } public bool Succeeded { get; set; } public long StartedAtGameTick { get; set; } public long? CompletedAtGameTick { get; set; } public string BeforeStateHash { get; set; } = string.Empty; public string? AfterStateHash { get; set; } public int? TargetObjectId { get; set; } public List TargetObjectIds { get; set; } = new List(); public int? TargetItemId { get; set; } public int? RequestedCount { get; set; } public int? BeforeTargetAmount { get; set; } public int? AfterTargetAmount { get; set; } public string? Message { get; set; } public string? OriginalOutcomeMessage { get; set; } public bool ReconciledFromOutcomeUnknown { get; set; } public long? ReconciledAtGameTick { get; set; } public Dictionary BeforeInventory { get; set; } = new Dictionary(); public Dictionary? AfterInventory { get; set; } public int[] ExpectedYieldItemIds { get; set; } = Array.Empty(); public ForgeTask? ForgeTask { get; set; } public OrderNode? PlayerOrder { get; set; } public long? PowerStarvedAtGameTick { get; set; } public MovementProgressWatchdog? MovementProgress { get; set; } public long FlightLastControlGameTick { get; set; } public double FlightBestDistance { get; set; } public long FlightBestDistanceAtGameTick { get; set; } public long FlightDestinationContactAtGameTick { get; set; } public long FlightStableLandingAtGameTick { get; set; } public int FlightLandingOrderCount { get; set; } public long? FlightLandingOrderReachedAtGameTick { get; set; } public bool FlightAscentInputOwned { get; set; } public float FlightOriginalVerticalInput { get; set; } public float FlightOriginalForwardInput { get; set; } public string? FlightCheckpointId { get; set; } public string? FlightCheckpointReloadToken { get; set; } public long? FlightCheckpointGameTick { get; set; } public bool Stalled { get; set; } public bool RecoveryRequired { get; set; } public string? FailureKind { get; set; } public long? StalledGameTicks { get; set; } public double? RemainingDistance { get; set; } public bool DoNotRetrySameTarget { get; set; } public string? RecommendedRecovery { get; set; } public double? RecommendedShortMoveDistanceMeters { get; set; } public double? OrthogonalProbeDistanceMeters { get; set; } public int? MaximumOrthogonalProbeAttempts { get; set; } public List PrebuildIds { get; set; } = new List(); public List ExpectedBuildEntities { get; set; } = new List(); public HashSet PreexistingBuildEntityIds { get; } = new HashSet(); public NormalActionPlanPayload Plan { get; set; } } private sealed class NormalActionPlanPayload { public string ActionKind { get; private set; } = string.Empty; public string SessionId { get; private set; } = string.Empty; public int PlanetId { get; private set; } public string ExpectedStateHash { get; private set; } = string.Empty; public string PlayerStateHash { get; private set; } = string.Empty; public string ResourceStateHash { get; private set; } = string.Empty; public string ProgressionSelectionStateHash { get; private set; } = string.Empty; public string StarSystemStateHash { get; private set; } = string.Empty; public Vector3 TargetPosition { get; private set; } public float ArrivalTolerance { get; private set; } public double EstimatedDistance { get; private set; } public int DestinationPlanetId { get; private set; } public double MinimumCoreEnergyRatio { get; private set; } public double RequiredFlightEnergy { get; private set; } public long EstimatedTicks { get; set; } public string ResourceKind { get; private set; } = string.Empty; public int ResourceNodeId { get; private set; } public int ResourceRemaining { get; private set; } public List YieldItemIds { get; } = new List(); public int RecipeId { get; private set; } public int TechId { get; private set; } public int BuildingItemId { get; private set; } public string BuildKind { get; private set; } = string.Empty; public string BuildResourceStateHash { get; private set; } = string.Empty; public int BuildResourceNodeId { get; private set; } public string SourceFactoryStateHash { get; private set; } = string.Empty; public string DestinationFactoryStateHash { get; private set; } = string.Empty; public int SourceObjectId { get; private set; } public int DestinationObjectId { get; private set; } public int SourceSlot { get; private set; } = -1; public int DestinationSlot { get; private set; } = -1; public List BuildSteps { get; } = new List(); public Vector3 BuildPosition { get; private set; } public Quaternion BuildRotation { get; private set; } public float BuildYaw { get; private set; } public string FactoryStateHash { get; private set; } = string.Empty; public int EntityId { get; private set; } public int ConfigureRecipeId { get; private set; } public string ConfigureMode { get; private set; } = "production"; public int ConfigureTechId { get; private set; } public int ConfigureFilterItemId { get; private set; } public string StationConfigurationStateHash { get; private set; } = string.Empty; public int ConfigureStationStorageIndex { get; private set; } = -1; public int ConfigureStationBeltSlotIndex { get; private set; } = -1; public int ConfigureStationBeltStorageIndex { get; private set; } = -1; public int ConfigureStationBeltItemId { get; private set; } public int ConfigureStationItemId { get; private set; } public int ConfigureStationMaximumCount { get; private set; } public string ConfigureStationLocalLogic { get; private set; } = "none"; public string ConfigureStationRemoteLogic { get; private set; } = "none"; public long ConfigureStationMaximumChargePowerWatts { get; private set; } public string TransferDirection { get; private set; } = string.Empty; public int TransferStorageEntityId { get; private set; } public int TransferItemId { get; private set; } public string TransferStorageStateHash { get; private set; } = string.Empty; public string StationFleetStateHash { get; private set; } = string.Empty; public string FleetTransferDirection { get; private set; } = string.Empty; public int FleetTransferStationEntityId { get; private set; } public int FleetTransferItemId { get; private set; } public int Count { get; private set; } public string ReconcileActionId { get; private set; } = string.Empty; public string ReconcileReason { get; private set; } = string.Empty; public long ReconcileExpectedRevision { get; private set; } public List ReconcileEntityIds { get; } = new List(); public int FuelItemId { get; private set; } public int FuelGrid { get; private set; } public long SaveExpectedRevision { get; private set; } public string SaveOwnedName { get; private set; } = string.Empty; public static NormalActionPlanPayload Move(string sessionId, int planetId, string expectedStateHash, string playerStateHash, Vector3 target, float tolerance, double distance) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) return new NormalActionPlanPayload { ActionKind = "move", SessionId = sessionId, PlanetId = planetId, ExpectedStateHash = expectedStateHash, PlayerStateHash = playerStateHash, TargetPosition = target, ArrivalTolerance = tolerance, EstimatedDistance = distance }; } public static NormalActionPlanPayload InterplanetaryFlight(string sessionId, int planetId, int destinationPlanetId, string expectedStateHash, string playerStateHash, string starSystemStateHash, double distance, double minimumCoreEnergyRatio, double requiredFlightEnergy) { return new NormalActionPlanPayload { ActionKind = "interplanetary-flight", SessionId = sessionId, PlanetId = planetId, DestinationPlanetId = destinationPlanetId, ExpectedStateHash = expectedStateHash, PlayerStateHash = playerStateHash, StarSystemStateHash = starSystemStateHash, EstimatedDistance = distance, MinimumCoreEnergyRatio = minimumCoreEnergyRatio, RequiredFlightEnergy = requiredFlightEnergy }; } public static NormalActionPlanPayload Harvest(string sessionId, int planetId, string expectedStateHash, string playerStateHash, ResourceNodeSnapshot resource, int count) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) NormalActionPlanPayload normalActionPlanPayload = new NormalActionPlanPayload(); normalActionPlanPayload.ActionKind = "harvest"; normalActionPlanPayload.SessionId = sessionId; normalActionPlanPayload.PlanetId = planetId; normalActionPlanPayload.ExpectedStateHash = expectedStateHash; normalActionPlanPayload.PlayerStateHash = playerStateHash; normalActionPlanPayload.ResourceStateHash = resource.StateHash; normalActionPlanPayload.TargetPosition = ToVector(resource.Position); normalActionPlanPayload.EstimatedDistance = resource.DistanceFromPlayer; normalActionPlanPayload.ResourceKind = resource.Kind; normalActionPlanPayload.ResourceNodeId = resource.NodeId; normalActionPlanPayload.ResourceRemaining = resource.RemainingAmount; normalActionPlanPayload.Count = count; normalActionPlanPayload.YieldItemIds.AddRange(resource.Yields.Select((ResourceYieldSnapshot yield) => yield.ItemId)); return normalActionPlanPayload; } public static NormalActionPlanPayload Handcraft(string sessionId, int planetId, string expectedStateHash, string playerStateHash, int recipeId, int count) { return new NormalActionPlanPayload { ActionKind = "handcraft", SessionId = sessionId, PlanetId = planetId, ExpectedStateHash = expectedStateHash, PlayerStateHash = playerStateHash, RecipeId = recipeId, Count = count }; } public static NormalActionPlanPayload Research(string sessionId, int planetId, string expectedStateHash, string progressionSelectionStateHash, int techId) { return new NormalActionPlanPayload { ActionKind = "select-research", SessionId = sessionId, PlanetId = planetId, ExpectedStateHash = expectedStateHash, ProgressionSelectionStateHash = progressionSelectionStateHash, TechId = techId }; } public static NormalActionPlanPayload Build(string sessionId, int planetId, string expectedStateHash, string playerStateHash, int buildingItemId, Vector3 position, Quaternion rotation, float yaw) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) return new NormalActionPlanPayload { ActionKind = "build", SessionId = sessionId, PlanetId = planetId, ExpectedStateHash = expectedStateHash, PlayerStateHash = playerStateHash, BuildingItemId = buildingItemId, BuildPosition = position, BuildRotation = rotation, BuildYaw = yaw }; } public static NormalActionPlanPayload Configure(string sessionId, int planetId, string expectedStateHash, string factoryStateHash, int entityId, int recipeId, string mode, int techId, int filterItemId, string stationConfigurationStateHash, int stationStorageIndex, int stationBeltSlotIndex, int stationBeltStorageIndex, int stationBeltItemId, int stationItemId, int stationMaximumCount, string stationLocalLogic, string stationRemoteLogic, long stationMaximumChargePowerWatts) { return new NormalActionPlanPayload { ActionKind = "configure-building", SessionId = sessionId, PlanetId = planetId, ExpectedStateHash = expectedStateHash, FactoryStateHash = factoryStateHash, EntityId = entityId, ConfigureRecipeId = recipeId, ConfigureMode = mode, ConfigureTechId = techId, ConfigureFilterItemId = filterItemId, StationConfigurationStateHash = stationConfigurationStateHash, ConfigureStationStorageIndex = stationStorageIndex, ConfigureStationBeltSlotIndex = stationBeltSlotIndex, ConfigureStationBeltStorageIndex = stationBeltStorageIndex, ConfigureStationBeltItemId = stationBeltItemId, ConfigureStationItemId = stationItemId, ConfigureStationMaximumCount = stationMaximumCount, ConfigureStationLocalLogic = stationLocalLogic, ConfigureStationRemoteLogic = stationRemoteLogic, ConfigureStationMaximumChargePowerWatts = stationMaximumChargePowerWatts }; } public static NormalActionPlanPayload Dismantle(string sessionId, int planetId, string expectedStateHash, string playerStateHash, string endpointStateHash, int entityId, int buildingItemId) { return new NormalActionPlanPayload { ActionKind = "dismantle", SessionId = sessionId, PlanetId = planetId, ExpectedStateHash = expectedStateHash, PlayerStateHash = playerStateHash, FactoryStateHash = endpointStateHash, EntityId = entityId, BuildingItemId = buildingItemId, Count = 1, EstimatedTicks = 1L }; } public static NormalActionPlanPayload StationFleetTransfer(string sessionId, int planetId, string expectedStateHash, string playerStateHash, string stationFleetStateHash, int stationEntityId, string direction, int itemId, int count) { return new NormalActionPlanPayload { ActionKind = "logistics-station-fleet-transfer", SessionId = sessionId, PlanetId = planetId, ExpectedStateHash = expectedStateHash, PlayerStateHash = playerStateHash, StationFleetStateHash = stationFleetStateHash, FleetTransferStationEntityId = stationEntityId, FleetTransferDirection = direction, FleetTransferItemId = itemId, Count = count, EstimatedTicks = 1L }; } public static NormalActionPlanPayload QuarantineReconciliation(string sessionId, int planetId, string proofHash, string actionId, string reason, long expectedRevision, IReadOnlyList entityIds) { NormalActionPlanPayload normalActionPlanPayload = new NormalActionPlanPayload(); normalActionPlanPayload.ActionKind = "reconcile-quarantine"; normalActionPlanPayload.SessionId = sessionId; normalActionPlanPayload.PlanetId = planetId; normalActionPlanPayload.ExpectedStateHash = proofHash; normalActionPlanPayload.ReconcileActionId = actionId; normalActionPlanPayload.ReconcileReason = reason; normalActionPlanPayload.ReconcileExpectedRevision = expectedRevision; normalActionPlanPayload.EstimatedTicks = 1L; normalActionPlanPayload.ReconcileEntityIds.AddRange(entityIds); return normalActionPlanPayload; } public static NormalActionPlanPayload StructuredBuild(string sessionId, int planetId, string expectedStateHash, string playerStateHash, int buildingItemId, BuildPreparation preparation) { NormalActionPlanPayload normalActionPlanPayload = new NormalActionPlanPayload(); normalActionPlanPayload.ActionKind = "build"; normalActionPlanPayload.SessionId = sessionId; normalActionPlanPayload.PlanetId = planetId; normalActionPlanPayload.ExpectedStateHash = expectedStateHash; normalActionPlanPayload.PlayerStateHash = playerStateHash; normalActionPlanPayload.BuildingItemId = buildingItemId; normalActionPlanPayload.BuildKind = preparation.Kind; normalActionPlanPayload.BuildResourceNodeId = preparation.ResourceNodeId; normalActionPlanPayload.BuildResourceStateHash = preparation.ResourceStateHash; normalActionPlanPayload.SourceObjectId = preparation.SourceObjectId; normalActionPlanPayload.SourceFactoryStateHash = preparation.SourceEndpointHash; normalActionPlanPayload.DestinationObjectId = preparation.DestinationObjectId; normalActionPlanPayload.DestinationFactoryStateHash = preparation.DestinationEndpointHash; normalActionPlanPayload.Count = preparation.Steps.Count; normalActionPlanPayload.EstimatedTicks = Math.Max(3600L, (long)preparation.Steps.Count * 900L); normalActionPlanPayload.BuildSteps.AddRange(preparation.Steps); return normalActionPlanPayload; } public static NormalActionPlanPayload Transfer(string sessionId, int planetId, string expectedStateHash, string playerStateHash, string storageStateHash, int storageEntityId, string direction, int itemId, int count) { return new NormalActionPlanPayload { ActionKind = "transfer", SessionId = sessionId, PlanetId = planetId, ExpectedStateHash = expectedStateHash, PlayerStateHash = playerStateHash, TransferStorageStateHash = storageStateHash, TransferStorageEntityId = storageEntityId, TransferDirection = direction, TransferItemId = itemId, Count = count, EstimatedTicks = 1L }; } public static NormalActionPlanPayload Refuel(string sessionId, int planetId, string expectedStateHash, string playerStateHash, int itemId, int count, int grid) { return new NormalActionPlanPayload { ActionKind = "refuel", SessionId = sessionId, PlanetId = planetId, ExpectedStateHash = expectedStateHash, PlayerStateHash = playerStateHash, FuelItemId = itemId, Count = count, FuelGrid = grid, EstimatedTicks = 1L }; } public static NormalActionPlanPayload Save(string sessionId, int planetId, string expectedStateHash, string saveOwnedName, long expectedRevision) { return new NormalActionPlanPayload { ActionKind = "save", SessionId = sessionId, PlanetId = planetId, ExpectedStateHash = expectedStateHash, SaveOwnedName = saveOwnedName, SaveExpectedRevision = expectedRevision, EstimatedTicks = 1L }; } } private readonly struct WorldBuildCollider { public Vector3 Center { get; } public Vector3 AxisX { get; } public Vector3 AxisY { get; } public Vector3 AxisZ { get; } public Vector3 Extents { get; } public WorldBuildCollider(Vector3 center, Vector3 axisX, Vector3 axisY, Vector3 axisZ, Vector3 extents) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) Center = center; AxisX = axisX; AxisY = axisY; AxisZ = axisZ; Extents = extents; } } private sealed class StorageCopy : IDisposable { public StorageComponent Value { get; } public StorageCopy(StorageComponent source) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) Value = new StorageComponent(source.size); Array.Copy(source.grids, Value.grids, Math.Min(source.size, source.grids.Length)); Value.type = source.type; Value.bans = source.bans; Value.isPlayerInventory = source.isPlayerInventory; } public void Dispose() { Value.Free(); } } private sealed class BuildPreparation { public bool Success { get; private set; } public string ErrorCode { get; private set; } = "BUILD_LOCATION_INVALID"; public string Rejection { get; private set; } = string.Empty; public string Kind { get; private set; } = string.Empty; public List Steps { get; } = new List(); public int ResourceNodeId { get; set; } public string ResourceStateHash { get; set; } = string.Empty; public List ResourceNodeIds { get; } = new List(); public int SourceObjectId { get; set; } public string SourceEndpointHash { get; set; } = string.Empty; public int DestinationObjectId { get; set; } public string DestinationEndpointHash { get; set; } = string.Empty; public static BuildPreparation Succeeded(string kind, IEnumerable steps) { BuildPreparation buildPreparation = new BuildPreparation(); buildPreparation.Success = true; buildPreparation.Kind = kind; buildPreparation.Steps.AddRange(steps); return buildPreparation; } public static BuildPreparation Failed(string code, string rejection) { return new BuildPreparation { ErrorCode = code, Rejection = rejection }; } } private sealed class BuildStepPlan { public int ItemId { get; private set; } public Vector3 Position { get; private set; } public Quaternion Rotation { get; private set; } public Vector3 Position2 { get; private set; } public Quaternion Rotation2 { get; private set; } public float Yaw { get; private set; } public float Tilt { get; private set; } public int InputStepIndex { get; set; } = -1; public int OutputStepIndex { get; set; } = -1; public int InputObjectId { get; set; } public int OutputObjectId { get; set; } public int InputFromSlot { get; set; } public int InputToSlot { get; set; } public int OutputFromSlot { get; set; } public int OutputToSlot { get; set; } public int InputOffset { get; set; } public int OutputOffset { get; set; } public bool IsConnectionNode { get; private set; } public List Parameters { get; } = new List(); public static BuildStepPlan Core(int itemId, Vector3 position, Quaternion rotation, float yaw) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) return new BuildStepPlan { ItemId = itemId, Position = position, Position2 = position, Rotation = rotation, Rotation2 = rotation, Yaw = yaw }; } public static BuildStepPlan Belt(int itemId, Vector3 position) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002c: 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) return new BuildStepPlan { ItemId = itemId, Position = position, Position2 = position, Rotation = Maths.SphericalRotation(position, 0f), Rotation2 = Maths.SphericalRotation(position, 0f), IsConnectionNode = true, InputToSlot = 1, OutputFromSlot = 0, OutputToSlot = 1 }; } public static BuildStepPlan Inserter(int itemId, Pose source, Pose destination, int sourceObjectId, int sourceSlot, int destinationObjectId, int destinationSlot) { //IL_000d: 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) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0031: 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_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) return new BuildStepPlan { ItemId = itemId, Position = source.position, Rotation = source.rotation, Position2 = destination.position, Rotation2 = destination.rotation * Quaternion.Euler(0f, 180f, 0f), InputObjectId = sourceObjectId, InputFromSlot = sourceSlot, InputToSlot = 1, OutputObjectId = destinationObjectId, OutputFromSlot = 0, OutputToSlot = destinationSlot }; } public static BuildStepPlan FromPreview(BuildStepPlan template, BuildPreview preview) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_002b: 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) BuildStepPlan buildStepPlan = new BuildStepPlan { ItemId = template.ItemId, Position = preview.lpos, Rotation = preview.lrot, Position2 = preview.lpos2, Rotation2 = preview.lrot2, Yaw = template.Yaw, Tilt = preview.tilt, InputStepIndex = template.InputStepIndex, OutputStepIndex = template.OutputStepIndex, InputObjectId = preview.inputObjId, OutputObjectId = preview.outputObjId, InputFromSlot = preview.inputFromSlot, InputToSlot = preview.inputToSlot, OutputFromSlot = preview.outputFromSlot, OutputToSlot = preview.outputToSlot, InputOffset = preview.inputOffset, OutputOffset = preview.outputOffset, IsConnectionNode = preview.isConnNode }; if (preview.parameters != null && preview.paramCount > 0) { buildStepPlan.Parameters.AddRange(preview.parameters.Take(Math.Min(preview.paramCount, preview.parameters.Length))); } return buildStepPlan; } public bool EquivalentTo(BuildStepPlan other) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: 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) if (ItemId == other.ItemId && Vector3.Distance(Position, other.Position) <= 0.01f && Vector3.Distance(Position2, other.Position2) <= 0.01f && Quaternion.Angle(Rotation, other.Rotation) <= 0.1f && Quaternion.Angle(Rotation2, other.Rotation2) <= 0.1f && Math.Abs(Tilt - other.Tilt) <= 0.01f && InputStepIndex == other.InputStepIndex && OutputStepIndex == other.OutputStepIndex && InputObjectId == other.InputObjectId && OutputObjectId == other.OutputObjectId && InputFromSlot == other.InputFromSlot && InputToSlot == other.InputToSlot && OutputFromSlot == other.OutputFromSlot && OutputToSlot == other.OutputToSlot && InputOffset == other.InputOffset && OutputOffset == other.OutputOffset && IsConnectionNode == other.IsConnectionNode) { return Parameters.SequenceEqual(other.Parameters); } return false; } public void AppendFingerprint(ICollection fields) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) fields.Add(ItemId); fields.Add(Position.x); fields.Add(Position.y); fields.Add(Position.z); fields.Add(Rotation.x); fields.Add(Rotation.y); fields.Add(Rotation.z); fields.Add(Rotation.w); fields.Add(Position2.x); fields.Add(Position2.y); fields.Add(Position2.z); fields.Add(Rotation2.x); fields.Add(Rotation2.y); fields.Add(Rotation2.z); fields.Add(Rotation2.w); fields.Add(Tilt); fields.Add(InputStepIndex); fields.Add(OutputStepIndex); fields.Add(InputObjectId); fields.Add(OutputObjectId); fields.Add(InputFromSlot); fields.Add(InputToSlot); fields.Add(OutputFromSlot); fields.Add(OutputToSlot); foreach (int parameter in Parameters) { fields.Add(parameter); } } } private sealed class BuildExpectedEntity { public int ItemId { get; set; } public Vector3 Position { get; set; } public int InputObjectId { get; set; } public int OutputObjectId { get; set; } public int InputStepIndex { get; set; } public int OutputStepIndex { get; set; } } private readonly struct EndpointPoint { public int ObjectId { get; } public int Slot { get; } public Pose Pose { get; } public EndpointPoint(int objectId, int slot, Pose pose) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) ObjectId = objectId; Slot = slot; Pose = pose; } } private const int StateHashVersion = 1; private const long PowerStarvationGraceTicks = 600L; private readonly GameSessionTracker _sessions; private readonly GameStateReader _reader; private readonly FlightCheckpointStore _flightCheckpoints; private readonly PreparedPlanStore _plans; private readonly IdempotencyCache _idempotency; private readonly Dictionary _actions = new Dictionary(StringComparer.Ordinal); private const long FlightLaunchTimeoutTicks = 3600L; private const long MinimumFlightTimeoutTicks = 216000L; private const long MinimumFlightProgressStallTicks = 18000L; private const long FlightLandingStableTicks = 600L; private const long FlightLandingTimeoutTicks = 7200L; private const long FlightShoreTransitionGraceTicks = 120L; private const int FlightShoreMaximumOrders = 3; private const float FlightShoreSearchMinimumDistance = 1f; private const float FlightShoreSearchMaximumDistance = 120f; private const float FlightShoreMinimumTerrainClearance = 0.2f; private const float FlightShoreNeighborhoodMinimumClearance = -0.05f; private const float FlightShoreNeighborhoodProbeDistance = 2f; private const float NativeSailEntryTargetAltitude = 100f; private const double FlightDetourMaximumRelativeSpeed = 200.0; public NormalGameActionCoordinator(int planLifetimeSeconds, int idempotencyRetentionMinutes, int idempotencyCapacity, GameSessionTracker sessions, GameStateReader reader, FlightCheckpointStore flightCheckpoints) { _sessions = sessions; _reader = reader; _flightCheckpoints = flightCheckpoints; _plans = new PreparedPlanStore(TimeSpan.FromSeconds(planLifetimeSeconds), 128, (Func)null); _idempotency = new IdempotencyCache(idempotencyCapacity, TimeSpan.FromMinutes(idempotencyRetentionMinutes), (Func)null); } public GameCallResult PrepareMoveOnMainThread(string? requestedSessionId, PrepareMoveRequest request) { //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Expected O, but got Unknown //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) CommonPrepareResult commonPrepareResult = ValidatePrepareCommon(requestedSessionId, request.PlanetId, request.StateHashVersion); if (commonPrepareResult.Error != null) { return GameCallResult.Failed(commonPrepareResult.Error); } if (!IsFinite(request.Target.X) || !IsFinite(request.Target.Y) || !IsFinite(request.Target.Z) || request.ArrivalTolerance < 0.5f || request.ArrivalTolerance > 5f) { return InvalidPlan("Move target must be finite and arrival tolerance must be from 0.5 through 5 metres."); } GameCallResult playerStateOnMainThread = _reader.GetPlayerStateOnMainThread(requestedSessionId, new LocalPlanetRequest { PlanetId = request.PlanetId }); if (!playerStateOnMainThread.Success || playerStateOnMainThread.Value == null) { return GameCallResult.Failed(playerStateOnMainThread.Error); } PlayerStateSnapshot value = playerStateOnMainThread.Value; if (!string.Equals(request.ExpectedPlayerStateHash, value.StateHash, StringComparison.Ordinal)) { return StalePlan("Player state changed after inspection; inspect the player and prepare again."); } Player mainPlayer = GameMain.mainPlayer; Vector3 val = ToVector(request.Target); Vector3 position = mainPlayer.position; float magnitude = ((Vector3)(ref position)).magnitude; if (magnitude < 1f || Math.Abs(((Vector3)(ref val)).magnitude - magnitude) > 8f) { return InvalidPlan("Move target is not on the current planet surface."); } val = ((Vector3)(ref val)).normalized * magnitude; float num = Vector3.Distance(mainPlayer.position, val); string text = CanonicalStateHash.PlayerAction(value); string expectedStateHash = CanonicalStateHash.Combine("move", new object[7] { _sessions.SessionId, request.PlanetId, text, val.x, val.y, val.z, request.ArrivalTolerance }); NormalActionPlanPayload payload = NormalActionPlanPayload.Move(_sessions.SessionId, request.PlanetId, expectedStateHash, text, val, request.ArrivalTolerance, num); return AddPreparedPlan(payload, commonPrepareResult.Session, Math.Max(1L, (long)Math.Ceiling(num / 6f * 60f)), "Player remains on the same planet and reaches the target within the requested tolerance."); } public GameCallResult PrepareHarvestOnMainThread(string? requestedSessionId, PrepareHarvestRequest request) { //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Expected O, but got Unknown //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Expected O, but got Unknown //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_02b6: Unknown result type (might be due to invalid IL or missing references) //IL_02c3: Unknown result type (might be due to invalid IL or missing references) //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_02f2: Unknown result type (might be due to invalid IL or missing references) //IL_0302: Expected O, but got Unknown CommonPrepareResult commonPrepareResult = ValidatePrepareCommon(requestedSessionId, request.PlanetId, request.StateHashVersion); if (commonPrepareResult.Error != null) { return GameCallResult.Failed(commonPrepareResult.Error); } if (request.RequestedYieldCount <= 0 || request.RequestedYieldCount > 1000) { return InvalidPlan("Requested harvest yield must be from 1 through 1000 items."); } string text = request.ResourceKind?.Trim().ToLowerInvariant(); if (text != "vein" && text != "vegetation") { return InvalidPlan("Harvest resource kind must be vein or vegetation."); } GameCallResult gameCallResult = _reader.InspectResourceNodeOnMainThread(requestedSessionId, new InspectResourceNodeRequest { PlanetId = request.PlanetId, Kind = text, NodeId = request.NodeId }); if (!gameCallResult.Success || gameCallResult.Value == null) { return GameCallResult.Failed(gameCallResult.Error); } GameCallResult playerStateOnMainThread = _reader.GetPlayerStateOnMainThread(requestedSessionId, new LocalPlanetRequest { PlanetId = request.PlanetId }); if (!playerStateOnMainThread.Success || playerStateOnMainThread.Value == null) { return GameCallResult.Failed(playerStateOnMainThread.Error); } ResourceNodeSnapshot value = gameCallResult.Value; PlayerStateSnapshot value2 = playerStateOnMainThread.Value; if (!string.Equals(request.ExpectedResourceStateHash, value.StateHash, StringComparison.Ordinal) || !string.Equals(request.ExpectedPlayerStateHash, value2.StateHash, StringComparison.Ordinal)) { return StalePlan("Player or resource state changed after inspection; inspect both and prepare again."); } if (text == "vein" && string.Equals(value.ResourceType, ((object)(EVeinType)7/*cast due to .constrained prefix*/).ToString(), StringComparison.OrdinalIgnoreCase)) { return InvalidPlan("Crude-oil veins cannot be harvested by the player's manual mining action."); } if (!value.WithinPlayerBuildArea) { return GameCallResult.Failed(BridgeError.Create("TARGET_OUT_OF_RANGE", "The selected resource is outside the player's current normal interaction area.", true, "Move through bounded surface waypoints, then inspect a resource with withinPlayerBuildArea=true and prepare again.")); } if (value.Yields.Count == 0) { return InvalidPlan("The selected runtime resource has no normal manual-harvest yield."); } string text2 = CanonicalStateHash.PlayerAction(value2); string expectedStateHash = CanonicalStateHash.Combine("harvest", new object[5] { _sessions.SessionId, request.PlanetId, value.StateHash, text2, request.RequestedYieldCount }); NormalActionPlanPayload payload = NormalActionPlanPayload.Harvest(_sessions.SessionId, request.PlanetId, expectedStateHash, text2, value, request.RequestedYieldCount); GameCallResult gameCallResult2 = AddPreparedPlan(payload, commonPrepareResult.Session, EstimateHarvestTicks(value, request.RequestedYieldCount), "The normal player mining order reduces the bound node and the corresponding inventory yield is reread."); if (gameCallResult2.Success && gameCallResult2.Value != null) { gameCallResult2.Value.EstimatedDistance = value.DistanceFromPlayer; foreach (ResourceYieldSnapshot yield in value.Yields) { gameCallResult2.Value.ItemBudget.Add(new ActionItemBudget { ItemId = yield.ItemId, Name = yield.Name, Count = ((text == "vegetation") ? yield.Count : request.RequestedYieldCount), Direction = "output" }); } } return gameCallResult2; } public GameCallResult PrepareHandcraftOnMainThread(string? requestedSessionId, PrepareHandcraftRequest request) { //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_00f2: Expected O, but got Unknown CommonPrepareResult commonPrepareResult = ValidatePrepareCommon(requestedSessionId, request.PlanetId, request.StateHashVersion); if (commonPrepareResult.Error != null) { return GameCallResult.Failed(commonPrepareResult.Error); } if (request.Count <= 0 || request.Count > 1000) { return InvalidPlan("Handcraft count must be from 1 through 1000 recipe executions."); } RecipeProto val = ((ProtoSet)(object)LDB.recipes).Select(request.RecipeId); GameHistoryData history = GameMain.history; Player mainPlayer = GameMain.mainPlayer; if (val == null || !val.Handcraft) { return InvalidPlan("The requested runtime recipe does not support normal handcrafting."); } if (history == null || !history.RecipeUnlocked(request.RecipeId)) { return GameCallResult.Failed(BridgeError.Create("INVALID_RECIPE", "The requested handcraft recipe is not unlocked.", false, "Select an unlocked handcraft recipe or complete its prerequisite technology.")); } if (((mainPlayer == null) ? null : mainPlayer.mecha?.forge) == null || mainPlayer.package == null) { return NotReadyPlan("The player's normal replicator is not ready."); } GameCallResult playerStateOnMainThread = _reader.GetPlayerStateOnMainThread(requestedSessionId, new LocalPlanetRequest { PlanetId = request.PlanetId }); if (!playerStateOnMainThread.Success || playerStateOnMainThread.Value == null) { return GameCallResult.Failed(playerStateOnMainThread.Error); } PlayerStateSnapshot value = playerStateOnMainThread.Value; if (!string.Equals(request.ExpectedPlayerStateHash, value.StateHash, StringComparison.Ordinal)) { return StalePlan("Player inventory or forge state changed after inspection; inspect and prepare again."); } if (!mainPlayer.mecha.forge.TryAddTask(request.RecipeId, request.Count, false)) { return GameCallResult.Failed(BridgeError.Create("ACTION_REJECTED", "The normal replicator cannot reserve the requested recipe from the current inventory and unlocked dependency recipes.", true, "Harvest or produce the missing ingredients, ensure dependency recipes are unlocked, then inspect and prepare again.")); } string text = CanonicalStateHash.PlayerAction(value); string expectedStateHash = CanonicalStateHash.Combine("handcraft", new object[5] { _sessions.SessionId, request.PlanetId, text, request.RecipeId, request.Count }); NormalActionPlanPayload payload = NormalActionPlanPayload.Handcraft(_sessions.SessionId, request.PlanetId, expectedStateHash, text, request.RecipeId, request.Count); GameCallResult gameCallResult = AddPreparedPlan(payload, commonPrepareResult.Session, (long)val.TimeSpend * (long)request.Count, "The accepted normal replicator task leaves the forge queue and its runtime recipe products are reread in inventory."); if (gameCallResult.Success && gameCallResult.Value != null) { AddRecipeBudget(gameCallResult.Value, val, request.Count); } return gameCallResult; } public GameCallResult PrepareSelectResearchOnMainThread(string? requestedSessionId, PrepareSelectResearchRequest request) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected O, but got Unknown //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Expected O, but got Unknown CommonPrepareResult commonPrepareResult = ValidatePrepareCommon(requestedSessionId, request.PlanetId, request.StateHashVersion); if (commonPrepareResult.Error != null) { return GameCallResult.Failed(commonPrepareResult.Error); } GameCallResult progressionStateOnMainThread = _reader.GetProgressionStateOnMainThread(requestedSessionId, new LocalPlanetRequest { PlanetId = request.PlanetId }); if (!progressionStateOnMainThread.Success || progressionStateOnMainThread.Value == null) { return GameCallResult.Failed(progressionStateOnMainThread.Error); } ProgressionStateSnapshot value = progressionStateOnMainThread.Value; if (!string.Equals(request.ExpectedSelectionStateHash, value.SelectionStateHash, StringComparison.Ordinal)) { return StalePlan("Technology queue or state changed after inspection; inspect progression and prepare again."); } TechProto obj = ((ProtoSet)(object)LDB.techs).Select(request.TechId); GameHistoryData history = GameMain.history; TechStateSnapshot val = ((IEnumerable)value.Technologies).FirstOrDefault((Func)((TechStateSnapshot candidate) => candidate.TechId == request.TechId)); if (obj == null || val == null) { return InvalidPlan("The requested technology does not exist in the current runtime catalog."); } if (val.Unlocked) { return InvalidPlan("The requested technology is already unlocked."); } if (history == null || !history.CanEnqueueTech(request.TechId)) { return GameCallResult.Failed(BridgeError.Create("ACTION_REJECTED", "DSP cannot enqueue the requested technology with the current prerequisites and queue.", true, "Complete prerequisite technology or free a research queue slot, then inspect and prepare again.")); } string expectedStateHash = CanonicalStateHash.Combine("select-research", new object[4] { _sessions.SessionId, request.PlanetId, value.SelectionStateHash, request.TechId }); NormalActionPlanPayload payload = NormalActionPlanPayload.Research(_sessions.SessionId, request.PlanetId, expectedStateHash, value.SelectionStateHash, request.TechId); GameCallResult gameCallResult = AddPreparedPlan(payload, commonPrepareResult.Session, val.HashRequired - val.HashUploaded, "DSP's normal technology queue contains the requested technology and currentTech reflects the queue head."); if (gameCallResult.Success && gameCallResult.Value != null) { foreach (TechItemRequirement itemRequirement in val.ItemRequirements) { gameCallResult.Value.ItemBudget.Add(new ActionItemBudget { ItemId = itemRequirement.ItemId, Name = itemRequirement.Name, Count = checked((int)Math.Min(2147483647L, itemRequirement.RequiredItemCount)), Direction = "research-consumption" }); } } return gameCallResult; } public GameCallResult PrepareBuildOnMainThread(string? requestedSessionId, PrepareBuildRequest request) { return PrepareStructuredBuildOnMainThread(requestedSessionId, request); } public GameCallResult PrepareDismantleOnMainThread(string? requestedSessionId, PrepareDismantleRequest request) { return PrepareDismantlePlanOnMainThread(requestedSessionId, request); } public GameCallResult PrepareConfigureBuildingOnMainThread(string? requestedSessionId, PrepareConfigureBuildingRequest request) { return PrepareStructuredConfigurationOnMainThread(requestedSessionId, request); } public GameCallResult PrepareTransferOnMainThread(string? requestedSessionId, PrepareTransferRequest request) { return PrepareStorageTransferOnMainThread(requestedSessionId, request); } public GameCallResult PrepareLogisticsStationFleetTransferOnMainThread(string? requestedSessionId, PrepareLogisticsStationFleetTransferRequest request) { return PrepareStationFleetTransferOnMainThread(requestedSessionId, request); } public GameCallResult PrepareRefuelOnMainThread(string? requestedSessionId, PrepareRefuelRequest request) { return PrepareRefuelPlanOnMainThread(requestedSessionId, request); } public GameCallResult PrepareSaveOnMainThread(string? requestedSessionId, PrepareSaveRequest request) { return PrepareSavePlanOnMainThread(requestedSessionId, request); } public GameCallResult CommitOnMainThread(string expectedActionKind, string? requestedSessionId, CommitNormalActionRequest request) { if (!Guid.TryParse(request.IdempotencyKey, out var _)) { return GameCallResult.Failed(BridgeError.Create("INVALID_REQUEST", "A UUID idempotency key is required.", false, "Generate one UUID and reuse it for retries of this exact commit.")); } if (!string.Equals(requestedSessionId, request.SessionId, StringComparison.Ordinal)) { return GameCallResult.Failed(BridgeError.Create("STALE_SESSION", "Envelope and commit payload session IDs do not match.", false, "Use the exact current owned session ID in both locations.")); } string text = CanonicalStateHash.Combine("commit-" + expectedActionKind, new object[3] { request.SessionId, request.PlanetId, request.PlanToken }); NormalActionCommitResult val = default(NormalActionCommitResult); bool flag = default(bool); if (_idempotency.TryGet(request.SessionId, request.IdempotencyKey, text, ref val, ref flag)) { NormalActionCommitResult val2 = val; val2 = ((!_actions.TryGetValue(val2.ActionId, out ActionRecord value)) ? CloneCommitResult(val2, replay: true) : CreateCommitResult(value, replay: true)); return GameCallResult.Succeeded(val2); } if (flag) { return GameCallResult.Failed(BridgeError.Create("IDEMPOTENCY_CONFLICT", "The idempotency key is already bound to a different normal-game commit.", false, "Reuse it only for the original commit or generate a new UUID for a newly prepared action.")); } PreparedPlan val3 = default(PreparedPlan); bool expired = default(bool); if (!_plans.TryGet(request.PlanToken, ref val3, ref expired) || val3 == null) { return MissingPlan(expired); } NormalActionPlanPayload payload = val3.Payload; if (!string.Equals(payload.ActionKind, expectedActionKind, StringComparison.Ordinal)) { return GameCallResult.Failed(BridgeError.Create("INVALID_REQUEST", "The plan token belongs to a different action method.", false, "Commit the plan through its matching action method.")); } BridgeError val4 = ValidateCommitCommon(_sessions.CaptureOnMainThread(), payload, request); if (val4 != null) { return GameCallResult.Failed(val4); } BridgeError val5 = RevalidatePlanOnMainThread(payload); if (val5 != null) { return GameCallResult.Failed(val5); } ActionRecord actionRecord = _actions.Values.FirstOrDefault((ActionRecord action) => !action.Terminal && IsPlayerOrderAction(action.ActionKind)); if (IsPlayerOrderAction(payload.ActionKind) && actionRecord != null) { return GameCallResult.Failed(BridgeError.Create("SERVER_BUSY", "Player movement action " + actionRecord.ActionId + " is still active; a second move, harvest, or flight would replace or race DSP's single player controller.", true, "Wait for the active player-order action to become terminal, then inspect and prepare again.")); } ActionRecord actionRecord2 = new ActionRecord { ActionId = Guid.NewGuid().ToString("D"), ActionKind = payload.ActionKind, SessionId = payload.SessionId, PlanetId = payload.PlanetId, IdempotencyKey = request.IdempotencyKey, State = "executing", StartedAtGameTick = GameMain.gameTick, BeforeStateHash = payload.ExpectedStateHash, TargetObjectId = ((payload.DestinationPlanetId > 0) ? new int?(payload.DestinationPlanetId) : ((payload.ResourceNodeId > 0) ? new int?(payload.ResourceNodeId) : ((int?)null))), TargetItemId = ((payload.RecipeId > 0) ? new int?(payload.RecipeId) : ((payload.TechId > 0) ? new int?(payload.TechId) : ((payload.BuildingItemId > 0) ? new int?(payload.BuildingItemId) : ((payload.TransferItemId > 0) ? new int?(payload.TransferItemId) : ((payload.FleetTransferItemId > 0) ? new int?(payload.FleetTransferItemId) : ((payload.FuelItemId > 0) ? new int?(payload.FuelItemId) : ((payload.ConfigureStationItemId > 0) ? new int?(payload.ConfigureStationItemId) : ((payload.ConfigureRecipeId > 0) ? new int?(payload.ConfigureRecipeId) : ((payload.ConfigureFilterItemId > 0) ? new int?(payload.ConfigureFilterItemId) : ((payload.ConfigureTechId > 0) ? new int?(payload.ConfigureTechId) : ((int?)null))))))))))), RequestedCount = ((payload.Count > 0) ? new int?(payload.Count) : ((int?)null)), BeforeTargetAmount = ((payload.ResourceRemaining > 0) ? new int?(payload.ResourceRemaining) : ((int?)null)), BeforeInventory = CaptureInventory(GameMain.mainPlayer), ExpectedYieldItemIds = payload.YieldItemIds.ToArray(), Plan = payload }; NormalActionCommitResult val6 = CreateCommitResult(actionRecord2, replay: false); if (!_idempotency.TryAdd(request.SessionId, request.IdempotencyKey, text, val6)) { return GameCallResult.Failed(BridgeError.Create("IDEMPOTENCY_CAPACITY_EXCEEDED", "The Plugin idempotency cache has reached its configured capacity.", false, "Start a new Plugin process before attempting further writes.")); } _plans.Remove(request.PlanToken); _actions.Add(actionRecord2.ActionId, actionRecord2); try { StartActionOnMainThread(actionRecord2); } catch (Exception ex) { actionRecord2.State = "outcome_unknown"; actionRecord2.Terminal = true; actionRecord2.Message = "The action start outcome could not be proven after " + ex.GetType().Name + "."; actionRecord2.OriginalOutcomeMessage = actionRecord2.Message; actionRecord2.CompletedAtGameTick = GameMain.gameTick; _sessions.QuarantineWritesOnMainThread(actionRecord2.ActionId, actionRecord2.Message); } return GameCallResult.Succeeded(CreateCommitResult(actionRecord2, replay: false)); } public void UpdateOnMainThread() { ActionRecord[] array = _actions.Values.Where((ActionRecord actionRecord) => !actionRecord.Terminal).ToArray(); foreach (ActionRecord action in array) { UpdateActionOnMainThread(action); } } public bool TryGetActionResultOnMainThread(string actionId, out ActionResultSnapshot? result) { if (!_actions.TryGetValue(actionId, out ActionRecord value)) { result = null; return false; } result = CreateActionSnapshot(value); return true; } public bool CanReloadFlightCheckpointOnMainThread(FlightCheckpointTicket ticket, out string rejection) { ActionRecord[] array = _actions.Values.Where((ActionRecord action) => !action.Terminal).ToArray(); if (array.Length == 0) { rejection = string.Empty; return true; } if (array.Length == 1 && array[0].ActionKind == "interplanetary-flight" && string.Equals(array[0].FlightCheckpointId, ticket.CheckpointId, StringComparison.Ordinal)) { rejection = string.Empty; return true; } rejection = "A non-flight normal-game action is still active, so an exact checkpoint reload would interrupt an unproved outcome."; return false; } public bool HasRecoveryRequiredFlightOnMainThread(string checkpointId) { if (!string.IsNullOrWhiteSpace(checkpointId)) { return _actions.Values.Any((ActionRecord action) => action.Terminal && action.RecoveryRequired && action.ActionKind == "interplanetary-flight" && string.Equals(action.FlightCheckpointId, checkpointId, StringComparison.Ordinal)); } return false; } public void NotifyFlightCheckpointReloadStartingOnMainThread(FlightCheckpointTicket ticket) { foreach (ActionRecord item in _actions.Values.Where((ActionRecord action) => !action.Terminal && action.ActionKind == "interplanetary-flight" && string.Equals(action.FlightCheckpointId, ticket.CheckpointId, StringComparison.Ordinal))) { Fail(item, "The exact bound pre-flight checkpoint reload was accepted; this flight attempt is superseded."); } } private void StartActionOnMainThread(ActionRecord action) { //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Expected O, but got Unknown //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_027b: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_0283: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Unknown result type (might be due to invalid IL or missing references) //IL_028d: Unknown result type (might be due to invalid IL or missing references) //IL_028f: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_0527: Unknown result type (might be due to invalid IL or missing references) //IL_052c: Unknown result type (might be due to invalid IL or missing references) //IL_0538: Unknown result type (might be due to invalid IL or missing references) //IL_0549: Expected O, but got Unknown Player mainPlayer = GameMain.mainPlayer; NormalActionPlanPayload plan = action.Plan; switch (action.ActionKind) { case "move": action.MovementProgress = new MovementProgressWatchdog(GameMain.gameTick, (double)mainPlayer.position.x, (double)mainPlayer.position.y, (double)mainPlayer.position.z, (double)Vector3.Distance(mainPlayer.position, plan.TargetPosition), 180L, 600L, 0.75, 1.0); action.PlayerOrder = OrderNode.MoveTo(plan.TargetPosition); mainPlayer.Order(action.PlayerOrder, false); action.State = "waiting_for_game"; action.Message = "DSP accepted a normal player movement order."; break; case "interplanetary-flight": StartInterplanetaryFlightOnMainThread(action); break; case "harvest": { EObjectType val = (EObjectType)((!(plan.ResourceKind == "vein")) ? 1 : 2); Vector3 val2 = CalculateMiningApproach(mainPlayer.position, plan.TargetPosition); action.PlayerOrder = OrderNode.MineTarget(val2, val, plan.ResourceNodeId, plan.TargetPosition); mainPlayer.Order(action.PlayerOrder, false); action.State = "waiting_for_game"; action.Message = "DSP accepted a normal player mining order; walking, energy use, and mining remain game-tick driven."; break; } case "handcraft": action.ForgeTask = mainPlayer.mecha.forge.AddTask(plan.RecipeId, plan.Count); if (action.ForgeTask == null) { Fail(action, "DSP's normal replicator rejected the task without changing the verified player state."); break; } action.State = "waiting_for_game"; action.Message = "DSP accepted the recipe into the normal replicator queue."; break; case "select-research": GameMain.history.EnqueueTech(plan.TechId); if (!GameMain.history.techQueue.Contains(plan.TechId)) { Fail(action, "DSP did not add the technology to its normal research queue."); } else { Complete(action, "DSP's normal technology queue accepted the requested technology."); } break; case "build": CreatePreparedPrebuildsOnMainThread(action); action.TargetObjectId = ((action.PrebuildIds.Count == 1) ? new int?(-action.PrebuildIds[0]) : ((int?)null)); action.TargetObjectIds = action.PrebuildIds.Select((int id) => -id).ToList(); action.TargetItemId = plan.BuildingItemId; action.State = "waiting_for_game"; action.Message = $"DSP created {action.PrebuildIds.Count} ordinary prebuild(s) and consumed the owned building items; construction drones now own completion."; break; case "dismantle": ExecuteDismantleOnMainThread(action); break; case "transfer": ExecuteStorageTransferOnMainThread(action); break; case "logistics-station-fleet-transfer": ExecuteStationFleetTransferOnMainThread(action); break; case "refuel": ExecuteRefuelOnMainThread(action); break; case "save": ExecuteSaveOnMainThread(action); break; case "configure-building": { ApplyBuildingConfigurationOnMainThread(plan); action.TargetObjectId = plan.EntityId; action.TargetItemId = ((plan.ConfigureMode == "sorter-filter") ? new int?(plan.ConfigureFilterItemId) : ((plan.ConfigureMode == "research") ? new int?(plan.ConfigureTechId) : ((plan.ConfigureMode == "logistics-station-storage") ? new int?(plan.ConfigureStationItemId) : ((plan.ConfigureMode == "logistics-station-belt") ? new int?(plan.ConfigureStationBeltItemId) : ((plan.ConfigureMode == "logistics-station-charge") ? ((int?)null) : new int?(plan.ConfigureRecipeId)))))); GameCallResult gameCallResult = _reader.InspectFactoryEntityOnMainThread(plan.SessionId, new InspectFactoryEntityRequest { PlanetId = plan.PlanetId, ObjectId = plan.EntityId }); if (!gameCallResult.Success || gameCallResult.Value == null || (plan.ConfigureMode == "production" && gameCallResult.Value.RecipeId != plan.ConfigureRecipeId) || (plan.ConfigureMode == "research" && !IsLabInResearchMode(plan.EntityId, plan.ConfigureTechId)) || (plan.ConfigureMode == "sorter-filter" && (gameCallResult.Value.FilterItemId.GetValueOrDefault() != plan.ConfigureFilterItemId || !IsSorterFilterApplied(plan.EntityId, plan.ConfigureFilterItemId))) || (plan.ConfigureMode == "logistics-station-storage" && !IsLogisticsStationStorageConfigurationApplied(gameCallResult.Value, plan)) || (plan.ConfigureMode == "logistics-station-belt" && !IsLogisticsStationBeltConfigurationApplied(gameCallResult.Value, plan)) || (plan.ConfigureMode == "logistics-station-charge" && !IsLogisticsStationChargeConfigurationApplied(gameCallResult.Value, plan))) { throw new InvalidOperationException("The configured device mode could not be proven by immediate readback."); } Complete(action, (plan.ConfigureMode == "sorter-filter") ? "The current-version sorter UI setting path applied the item filter and component/sign readback matched." : ((plan.ConfigureMode == "research") ? "The current-version lab setting path applied research mode and active-technology readback matched." : ((plan.ConfigureMode == "logistics-station-storage") ? "PlanetTransport.SetStationStorage applied the unlocked item, capacity, and local/remote logic once; immediate readback matched and the call preserved slot inventory." : ((plan.ConfigureMode == "logistics-station-belt") ? "The current-version station UI field path selected the configured item for the exact output port; immediate topology and inventory readback matched." : ((plan.ConfigureMode == "logistics-station-charge") ? "The current-version station UI field path applied the maximum charge power once; immediate power-consumer readback matched and station/player inventory remained unchanged." : "The current-version device configuration path applied the unlocked recipe and readback matched."))))); object afterStateHash; if (!(plan.ConfigureMode == "logistics-station-storage") && !(plan.ConfigureMode == "logistics-station-belt") && !(plan.ConfigureMode == "logistics-station-charge")) { afterStateHash = gameCallResult.Value.StateHash; } else { LogisticsStationSnapshot logisticsStation = gameCallResult.Value.LogisticsStation; afterStateHash = ((logisticsStation != null) ? logisticsStation.ConfigurationStateHash : null); } action.AfterStateHash = (string?)afterStateHash; break; } default: throw new InvalidOperationException("Unsupported normal-game action kind."); } _sessions.IncrementRevisionOnMainThread(); } private void UpdateActionOnMainThread(ActionRecord action) { bool flag = action.ActionKind == "interplanetary-flight"; if (!_sessions.IsCurrentSessionOwned || !string.Equals(_sessions.SessionId, action.SessionId, StringComparison.Ordinal) || (!flag && GameMain.localPlanet?.id != action.PlanetId)) { if (flag) { Fail(action, "The owned session ended before the normal flight completed; its bound checkpoint requires recovery."); return; } action.State = "action_failed"; action.Terminal = true; action.CompletedAtGameTick = GameMain.gameTick; action.Message = "The owned session or local planet ended before the normal game action completed."; return; } switch (action.ActionKind) { case "move": UpdateMove(action); break; case "interplanetary-flight": UpdateInterplanetaryFlight(action); break; case "harvest": UpdateHarvest(action); break; case "handcraft": UpdateHandcraft(action); break; case "build": UpdateBuild(action); break; } } private void UpdateMove(ActionRecord action) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Expected O, but got Unknown //IL_00df: Expected O, but got Unknown //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Invalid comparison between Unknown and I4 Player mainPlayer = GameMain.mainPlayer; float num = Vector3.Distance(mainPlayer.position, action.Plan.TargetPosition); if (num <= action.Plan.ArrivalTolerance) { AbortPlayerOrderIfOwned(action); Complete(action, $"Player reached the surface target within {num:F2} metres through normal movement ticks."); return; } bool hasValue = action.PowerStarvedAtGameTick.HasValue; if (!FailPowerStarvedPlayerOrder(action, "movement") && !action.PowerStarvedAtGameTick.HasValue) { if (action.MovementProgress == null) { MovementProgressWatchdog val = new MovementProgressWatchdog(action.StartedAtGameTick, (double)mainPlayer.position.x, (double)mainPlayer.position.y, (double)mainPlayer.position.z, (double)num, 180L, 600L, 0.75, 1.0); MovementProgressWatchdog val2 = val; action.MovementProgress = val; } if (hasValue) { action.MovementProgress.ResetWindow(GameMain.gameTick, (double)mainPlayer.position.x, (double)mainPlayer.position.y, (double)mainPlayer.position.z, (double)num); } MovementProgressObservation val3 = action.MovementProgress.Observe(GameMain.gameTick, (double)mainPlayer.position.x, (double)mainPlayer.position.y, (double)mainPlayer.position.z, (double)num); if ((int)((MovementProgressObservation)(ref val3)).Status != 0) { AbortPlayerOrderIfOwned(action); action.Stalled = true; ApplyMovementFailureAdvice(action, MovementFailureRecoveryAdvisor.ForStall(val3)); string arg = (((int)((MovementProgressObservation)(ref val3)).Status == 1) ? $"made less than {0.75:F2} metres of physical progress" : $"did not reduce its best remaining distance by {1.0:F2} metres"); Fail(action, $"The normal movement order {arg} for {((MovementProgressObservation)(ref val3)).StalledGameTicks} game ticks " + $"while {((MovementProgressObservation)(ref val3)).RemainingDistance:F2} metres remained; Spherewright stopped only its exact owned order before the global timeout or energy exhaustion."); } else if (GameMain.gameTick > action.StartedAtGameTick + Math.Max(3600L, action.Plan.EstimatedTicks * 8)) { AbortPlayerOrderIfOwned(action); ApplyMovementFailureAdvice(action, MovementFailureRecoveryAdvisor.ForBoundedTimeout(GameMain.gameTick - action.StartedAtGameTick, (double)num)); Fail(action, "The normal movement order did not reach its target within the bounded game-tick window."); } } } private static void ApplyMovementFailureAdvice(ActionRecord action, MovementFailureRecoveryAdvice advice) { action.FailureKind = advice.FailureKind; action.StalledGameTicks = advice.StalledGameTicks; action.RemainingDistance = advice.RemainingDistance; action.DoNotRetrySameTarget = advice.DoNotRetrySameTarget; action.RecommendedRecovery = advice.RecommendedRecovery; action.RecommendedShortMoveDistanceMeters = advice.RecommendedShortMoveDistanceMeters; action.OrthogonalProbeDistanceMeters = advice.OrthogonalProbeDistanceMeters; action.MaximumOrthogonalProbeAttempts = advice.MaximumOrthogonalProbeAttempts; } private void UpdateHarvest(ActionRecord action) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005e: 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_007b: Expected O, but got Unknown NormalActionPlanPayload plan = action.Plan; Dictionary afterInventory = CaptureInventory(GameMain.mainPlayer); int num = plan.YieldItemIds.Sum((int itemId) => GetCount(afterInventory, itemId) - GetCount(action.BeforeInventory, itemId)); GameCallResult gameCallResult = _reader.InspectResourceNodeOnMainThread(plan.SessionId, new InspectResourceNodeRequest { PlanetId = plan.PlanetId, Kind = plan.ResourceKind, NodeId = plan.ResourceNodeId }); int num2; if (!gameCallResult.Success) { BridgeError? error = gameCallResult.Error; num2 = ((((error != null) ? error.Code : null) == "INVALID_ENTITY") ? 1 : 0); } else { num2 = 0; } bool flag = (byte)num2 != 0; int num3 = ((gameCallResult.Success && gameCallResult.Value != null) ? gameCallResult.Value.RemainingAmount : 0); int num4 = plan.ResourceRemaining - num3; if ((plan.ResourceKind == "vegetation") ? flag : (num >= plan.Count || flag)) { AbortPlayerOrderIfOwned(action); action.AfterTargetAmount = num3; Complete(action, $"Normal manual harvesting completed: node reduction {num4}, observed inventory yield {num}."); } else if (!FailPowerStarvedPlayerOrder(action, "mining") && GameMain.gameTick > action.StartedAtGameTick + Math.Max(7200L, plan.EstimatedTicks * 8)) { AbortPlayerOrderIfOwned(action); Fail(action, "The normal mining order did not produce the requested observed yield within the bounded game-tick window."); } } private bool FailPowerStarvedPlayerOrder(ActionRecord action, string orderKind) { Player mainPlayer = GameMain.mainPlayer; Mecha val = ((mainPlayer != null) ? mainPlayer.mecha : null); if (val == null || val.coreEnergy > 0.5 || val.reactorEnergy > 0.5 || val.reactorItemId > 0 || HasUsableFuel(val.reactorStorage)) { action.PowerStarvedAtGameTick = null; return false; } long? powerStarvedAtGameTick = action.PowerStarvedAtGameTick; long valueOrDefault = powerStarvedAtGameTick.GetValueOrDefault(); if (!powerStarvedAtGameTick.HasValue) { valueOrDefault = GameMain.gameTick; long? powerStarvedAtGameTick2 = valueOrDefault; action.PowerStarvedAtGameTick = powerStarvedAtGameTick2; } if (GameMain.gameTick < action.PowerStarvedAtGameTick.Value + 600) { return false; } AbortPlayerOrderIfOwned(action); Fail(action, $"The normal {orderKind} order stopped after the mecha had no core energy, reactor energy, current reactor item, or usable fuel for {600L} game ticks."); return true; } private static bool HasUsableFuel(StorageComponent? storage) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) GRID[] array = storage?.grids; if (storage == null || array == null) { return false; } int num = Math.Min(storage.size, array.Length); for (int i = 0; i < num; i++) { GRID val = array[i]; ItemProto val2 = ((val.itemId > 0 && val.count > 0) ? ((ProtoSet)(object)LDB.items).Select(val.itemId) : null); if (val2 != null && val2.HeatValue > 0 && val2.FuelType > 0) { return true; } } return false; } private static void AbortPlayerOrderIfOwned(ActionRecord action) { Player mainPlayer = GameMain.mainPlayer; if (mainPlayer != null && action.PlayerOrder != null && mainPlayer.currentOrder == action.PlayerOrder) { mainPlayer.AbortOrder(); } } private static bool IsPlayerOrderAction(string actionKind) { if (!(actionKind == "move") && !(actionKind == "harvest")) { return actionKind == "interplanetary-flight"; } return true; } private void UpdateHandcraft(ActionRecord action) { Player mainPlayer = GameMain.mainPlayer; if (action.ForgeTask == null || !mainPlayer.mecha.forge.tasks.Contains(action.ForgeTask)) { Dictionary after = CaptureInventory(mainPlayer); if (GetRecipeProducts(action.Plan.RecipeId, action.Plan.Count).All((KeyValuePair pair) => GetCount(after, pair.Key) - GetCount(action.BeforeInventory, pair.Key) >= pair.Value)) { Complete(action, "The normal replicator task completed and all runtime recipe products were reread in player inventory."); } else { Fail(action, "The replicator task left the queue, but the expected products were not all present in player inventory."); } } } private void UpdateBuild(ActionRecord action) { UpdatePreparedBuildOnMainThread(action); } private BridgeError? RevalidatePlanOnMainThread(NormalActionPlanPayload plan) { //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Unknown result type (might be due to invalid IL or missing references) //IL_02a5: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_02c2: Expected O, but got Unknown //IL_02cf: Unknown result type (might be due to invalid IL or missing references) //IL_02d4: Unknown result type (might be due to invalid IL or missing references) //IL_02e5: Expected O, but got Unknown //IL_035f: Unknown result type (might be due to invalid IL or missing references) //IL_0364: Unknown result type (might be due to invalid IL or missing references) //IL_0375: Expected O, but got Unknown //IL_0401: Unknown result type (might be due to invalid IL or missing references) //IL_0406: Unknown result type (might be due to invalid IL or missing references) //IL_0412: Unknown result type (might be due to invalid IL or missing references) //IL_0423: Expected O, but got Unknown //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Expected O, but got Unknown switch (plan.ActionKind) { case "interplanetary-flight": return RevalidateInterplanetaryFlightPlanOnMainThread(plan); case "move": case "handcraft": { GameCallResult playerStateOnMainThread2 = _reader.GetPlayerStateOnMainThread(plan.SessionId, new LocalPlanetRequest { PlanetId = plan.PlanetId }); if (!playerStateOnMainThread2.Success || playerStateOnMainThread2.Value == null) { return playerStateOnMainThread2.Error; } if (!string.Equals(CanonicalStateHash.PlayerAction(playerStateOnMainThread2.Value), plan.PlayerStateHash, StringComparison.Ordinal)) { return Stale("Player state no longer matches the prepared action."); } if (plan.ActionKind == "handcraft") { RecipeProto val = ((ProtoSet)(object)LDB.recipes).Select(plan.RecipeId); if (val == null || !val.Handcraft || !GameMain.history.RecipeUnlocked(plan.RecipeId) || !GameMain.mainPlayer.mecha.forge.TryAddTask(plan.RecipeId, plan.Count, false)) { return Stale("Handcraft recipe, unlock, or material availability changed after prepare."); } } return null; } case "harvest": { GameCallResult gameCallResult2 = _reader.InspectResourceNodeOnMainThread(plan.SessionId, new InspectResourceNodeRequest { PlanetId = plan.PlanetId, Kind = plan.ResourceKind, NodeId = plan.ResourceNodeId }); GameCallResult playerStateOnMainThread = _reader.GetPlayerStateOnMainThread(plan.SessionId, new LocalPlanetRequest { PlanetId = plan.PlanetId }); if (!gameCallResult2.Success || gameCallResult2.Value == null) { return gameCallResult2.Error; } if (!playerStateOnMainThread.Success || playerStateOnMainThread.Value == null) { return playerStateOnMainThread.Error; } if (!string.Equals(gameCallResult2.Value.StateHash, plan.ResourceStateHash, StringComparison.Ordinal) || !string.Equals(CanonicalStateHash.PlayerAction(playerStateOnMainThread.Value), plan.PlayerStateHash, StringComparison.Ordinal)) { return Stale("Player or bound resource state changed after prepare."); } return null; } case "select-research": { GameCallResult progressionStateOnMainThread = _reader.GetProgressionStateOnMainThread(plan.SessionId, new LocalPlanetRequest { PlanetId = plan.PlanetId }); if (!progressionStateOnMainThread.Success || progressionStateOnMainThread.Value == null) { return progressionStateOnMainThread.Error; } if (!string.Equals(progressionStateOnMainThread.Value.SelectionStateHash, plan.ProgressionSelectionStateHash, StringComparison.Ordinal) || !GameMain.history.CanEnqueueTech(plan.TechId)) { return Stale("Technology state, prerequisites, or queue changed after prepare."); } return null; } case "build": return RevalidateStructuredBuildOnMainThread(plan); case "dismantle": return RevalidateDismantlePlanOnMainThread(plan); case "transfer": return RevalidateStorageTransferOnMainThread(plan); case "logistics-station-fleet-transfer": return RevalidateStationFleetTransferOnMainThread(plan); case "refuel": return RevalidateRefuelOnMainThread(plan); case "save": return RevalidateSaveOnMainThread(plan); case "configure-building": { GameCallResult gameCallResult = _reader.InspectFactoryEntityOnMainThread(plan.SessionId, new InspectFactoryEntityRequest { PlanetId = plan.PlanetId, ObjectId = plan.EntityId }); if (!gameCallResult.Success || gameCallResult.Value == null) { return gameCallResult.Error; } bool flag = plan.ConfigureMode == "sorter-filter"; if (!string.Equals(flag ? gameCallResult.Value.ConfigurationStateHash : gameCallResult.Value.StateHash, plan.FactoryStateHash, StringComparison.Ordinal) || (!flag && plan.ConfigureMode != "logistics-station-storage" && plan.ConfigureMode != "logistics-station-belt" && plan.ConfigureMode != "logistics-station-charge" && (gameCallResult.Value.Progress != 0 || gameCallResult.Value.IsWorking || gameCallResult.Value.Buffers.Any((FactoryBufferSnapshot buffer) => buffer.Count != 0)))) { return Stale("Device identity, buffers, progress, unlock, or recipe state changed after prepare."); } return RevalidateStructuredConfigurationOnMainThread(plan); } default: return BridgeError.Create("INVALID_REQUEST", "Unsupported prepared action kind.", false, "Prepare one of the public normal-game action types."); } } private CommonPrepareResult ValidatePrepareCommon(string? requestedSessionId, int planetId, int stateHashVersion) { if (stateHashVersion != 1) { return CommonPrepareResult.Failed(BridgeError.Create("STALE_STATE", "Unsupported action state-hash version.", false, "Inspect current state and use the returned stateHashVersion.")); } SessionState val = _sessions.CaptureOnMainThread(); if (!val.GameLoaded) { return CommonPrepareResult.Failed(BridgeError.Create("GAME_NOT_LOADED", "No game is loaded.", true, "Create and wait for a fresh Spherewright-owned ordinary world.")); } if (!val.OwnedBySpherewright) { return CommonPrepareResult.Failed(BridgeError.Create("SESSION_NOT_OWNED", "Normal-game actions are restricted to the exact world created by this Plugin process.", false, "Return to the main menu and create a fresh world through Spherewright.")); } if (!string.Equals(requestedSessionId, val.SessionId, StringComparison.Ordinal)) { return CommonPrepareResult.Failed(BridgeError.Create("STALE_SESSION", "The requested session is not the current owned session.", false, "Inspect current session state and retry with its exact session ID.")); } if (planetId <= 0 || val.LocalPlanetId != planetId) { return CommonPrepareResult.Failed(BridgeError.Create("NO_LOCAL_PLANET", "The requested planet is not the current local planet.", false, "Use the current localPlanetId returned by session state.")); } return CommonPrepareResult.Succeeded(val); } private static BridgeError? ValidateCommitCommon(SessionState session, NormalActionPlanPayload plan, CommitNormalActionRequest request) { if (!session.OwnedBySpherewright || !string.Equals(session.SessionId, plan.SessionId, StringComparison.Ordinal) || !string.Equals(request.SessionId, plan.SessionId, StringComparison.Ordinal)) { return BridgeError.Create("STALE_SESSION", "The prepared action does not belong to the current owned session.", false, "Inspect the current session and prepare a fresh action."); } if (request.PlanetId != plan.PlanetId || session.LocalPlanetId != plan.PlanetId) { return BridgeError.Create("STALE_STATE", "Commit planet, planned planet, and current local planet do not match.", false, "Return to the planned planet and prepare a fresh action."); } if (session.WriteBlockers.Count > 0) { WriteBlocker val = session.WriteBlockers[0]; return BridgeError.Create(val.Code, val.Message, false, "Resolve every current session write blocker, then prepare a fresh action."); } return null; } private GameCallResult AddPreparedPlan(NormalActionPlanPayload payload, SessionState session, long estimatedTicks, string completionCondition) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Expected O, but got Unknown payload.EstimatedTicks = estimatedTicks; PreparedPlan val; try { val = _plans.Add(payload.ExpectedStateHash, payload); } catch (InvalidOperationException) { return GameCallResult.Failed(BridgeError.Create("SERVER_BUSY", "Too many normal-game plans are active.", true, "Wait for old plans to expire, then inspect and prepare again.")); } return GameCallResult.Succeeded(new PreparedNormalAction { Prepared = true, ActionKind = payload.ActionKind, PlanToken = val.Token, ExpiresAtUtc = val.ExpiresAtUtc, ExpectedStateHash = payload.ExpectedStateHash, StateHashVersion = 1, CommitAllowedNow = (session.WriteBlockers.Count == 0), EstimatedDistance = payload.EstimatedDistance, EstimatedGameTicks = estimatedTicks, CommitBlockers = session.WriteBlockers.Select(CloneBlocker).ToList(), CompletionCondition = completionCondition }); } private void Complete(ActionRecord action, string message) { if (action.ActionKind == "interplanetary-flight") { AbortPlayerOrderIfOwned(action); ReleaseNativeAscentInput(action); string rejection = "The bound checkpoint identity is missing."; if (string.IsNullOrWhiteSpace(action.FlightCheckpointId) || !_flightCheckpoints.TryMarkFlightSucceeded(action.FlightCheckpointId, action.ActionId, GameMain.gameTick, out rejection)) { action.State = "outcome_unknown"; action.Terminal = true; action.Succeeded = false; action.CompletedAtGameTick = GameMain.gameTick; action.Message = "The physical flight completed, but its rollback checkpoint could not be sealed before the primary save: " + rejection; action.AfterInventory = CaptureInventory(GameMain.mainPlayer); if (action.AfterStateHash == null) { string text = (action.AfterStateHash = CaptureAfterStateHash(action)); } _sessions.QuarantineWritesOnMainThread(action.ActionId, action.Message); return; } _sessions.ForgetCurrentFlightCheckpoint(action.FlightCheckpointId); } action.State = "completed"; action.Terminal = true; action.Succeeded = true; action.CompletedAtGameTick = GameMain.gameTick; action.Message = message; action.AfterInventory = CaptureInventory(GameMain.mainPlayer); action.AfterStateHash = CaptureAfterStateHash(action); _sessions.IncrementRevisionOnMainThread(); } private void Fail(ActionRecord action, string message) { if (action.ActionKind == "interplanetary-flight") { AbortPlayerOrderIfOwned(action); ReleaseNativeAscentInput(action); if (!string.IsNullOrWhiteSpace(action.FlightCheckpointId)) { action.RecoveryRequired = true; if (!_flightCheckpoints.TryMarkRecoveryRequired(action.FlightCheckpointId, action.ActionId, GameMain.gameTick, out string rejection)) { message = message + " Checkpoint lifecycle persistence also failed: " + rejection; } } } action.State = (action.RecoveryRequired ? "recovery_required" : "action_failed"); action.Terminal = true; action.Succeeded = false; action.CompletedAtGameTick = GameMain.gameTick; action.Message = message; action.AfterInventory = CaptureInventory(GameMain.mainPlayer); action.AfterStateHash = CaptureAfterStateHash(action); } private string? CaptureAfterStateHash(ActionRecord action) { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Expected O, but got Unknown //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown string text = CaptureStructuredAfterStateHash(action); if (text != null) { return text; } if (action.ActionKind == "select-research") { ProgressionStateSnapshot? value = _reader.GetProgressionStateOnMainThread(action.SessionId, new LocalPlanetRequest { PlanetId = action.PlanetId }).Value; if (value == null) { return null; } return value.StateHash; } PlayerStateSnapshot? value2 = _reader.GetPlayerStateOnMainThread(action.SessionId, new LocalPlanetRequest { PlanetId = action.PlanetId }).Value; if (value2 == null) { return null; } return value2.StateHash; } private static ActionResultSnapshot CreateActionSnapshot(ActionRecord action) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_005e: 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_0076: 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_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: 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_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Expected O, but got Unknown //IL_0233: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_0265: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_0275: Unknown result type (might be due to invalid IL or missing references) //IL_0285: Expected O, but got Unknown ActionResultSnapshot val = new ActionResultSnapshot { ActionId = action.ActionId, ActionKind = action.ActionKind, State = action.State, Terminal = action.Terminal, Succeeded = action.Succeeded, SessionId = action.SessionId, PlanetId = action.PlanetId, Message = action.Message, IdempotencyKey = action.IdempotencyKey, StartedAtGameTick = action.StartedAtGameTick, CompletedAtGameTick = action.CompletedAtGameTick, BeforeStateHash = action.BeforeStateHash, AfterStateHash = action.AfterStateHash, TargetObjectId = action.TargetObjectId, TargetObjectIds = action.TargetObjectIds.ToList(), TargetItemId = action.TargetItemId, RequestedCount = action.RequestedCount, BeforeTargetAmount = action.BeforeTargetAmount, AfterTargetAmount = action.AfterTargetAmount, ReconciledFromOutcomeUnknown = action.ReconciledFromOutcomeUnknown, ReconciledAtGameTick = action.ReconciledAtGameTick, FlightCheckpointId = action.FlightCheckpointId, FlightCheckpointReloadToken = action.FlightCheckpointReloadToken, FlightCheckpointGameTick = action.FlightCheckpointGameTick, Stalled = action.Stalled, RecoveryRequired = action.RecoveryRequired, FailureKind = action.FailureKind, StalledGameTicks = action.StalledGameTicks, RemainingDistance = action.RemainingDistance, DoNotRetrySameTarget = action.DoNotRetrySameTarget, RecommendedRecovery = action.RecommendedRecovery, RecommendedShortMoveDistanceMeters = action.RecommendedShortMoveDistanceMeters, OrthogonalProbeDistanceMeters = action.OrthogonalProbeDistanceMeters, MaximumOrthogonalProbeAttempts = action.MaximumOrthogonalProbeAttempts }; Dictionary dictionary = action.AfterInventory ?? CaptureInventory(GameMain.mainPlayer); foreach (int item in from id in action.BeforeInventory.Keys.Concat(dictionary.Keys).Distinct() orderby id select id) { int count = GetCount(action.BeforeInventory, item); int count2 = GetCount(dictionary, item); if (count != count2) { List itemDeltas = val.ItemDeltas; ActionItemDelta val2 = new ActionItemDelta { ItemId = item }; ItemProto obj = ((ProtoSet)(object)LDB.items).Select(item); val2.Name = ((obj != null) ? ((Proto)obj).name : null) ?? string.Empty; val2.BeforeCount = count; val2.AfterCount = count2; val2.Delta = count2 - count; itemDeltas.Add(val2); } } return val; } private static NormalActionCommitResult CreateCommitResult(ActionRecord action, bool replay) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown return new NormalActionCommitResult { ActionId = action.ActionId, ActionKind = action.ActionKind, IdempotencyKey = action.IdempotencyKey, State = action.State, Accepted = true, IdempotentReplay = replay }; } private static NormalActionCommitResult CloneCommitResult(NormalActionCommitResult result, bool replay) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown return new NormalActionCommitResult { ActionId = result.ActionId, ActionKind = result.ActionKind, IdempotencyKey = result.IdempotencyKey, State = result.State, Accepted = result.Accepted, IdempotentReplay = replay }; } private static Dictionary CaptureInventory(Player player) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: 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_005b: Unknown result type (might be due to invalid IL or missing references) Dictionary dictionary = new Dictionary(); if (((player == null) ? null : player.package?.grids) != null) { for (int i = 0; i < Math.Min(player.package.size, player.package.grids.Length); i++) { GRID val = player.package.grids[i]; if (val.itemId > 0 && val.count > 0) { dictionary[val.itemId] = GetCount(dictionary, val.itemId) + val.count; } } } if (player != null && player.inhandItemId > 0 && player.inhandItemCount > 0) { dictionary[player.inhandItemId] = GetCount(dictionary, player.inhandItemId) + player.inhandItemCount; } return dictionary; } private static string CapturePlayerPackageState(Player player) { //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) List list = new List(); GRID[] array = ((player == null) ? null : player.package?.grids) ?? Array.Empty(); int valueOrDefault = ((player == null) ? ((int?)null) : player.package?.size).GetValueOrDefault(); list.Add(valueOrDefault); for (int i = 0; i < Math.Min(valueOrDefault, array.Length); i++) { GRID val = array[i]; list.Add(i); list.Add(val.itemId); list.Add(val.count); list.Add(val.inc); } list.Add((player != null) ? player.inhandItemId : 0); list.Add((player != null) ? player.inhandItemCount : 0); list.Add((player != null) ? player.inhandItemInc : 0); return CanonicalStateHash.Combine("player-package-v1", list.ToArray()); } private static Dictionary GetRecipeProducts(int recipeId, int count) { Dictionary dictionary = new Dictionary(); RecipeProto val = ((ProtoSet)(object)LDB.recipes).Select(recipeId); if (val == null) { return dictionary; } for (int i = 0; i < Math.Min(val.Results.Length, val.ResultCounts.Length); i++) { dictionary[val.Results[i]] = val.ResultCounts[i] * count; } return dictionary; } private static bool TryFindCoreBuildCandidate(PlanetFactory factory, Player player, ItemProto item, float preferredDistance, out Vector3 position, out Quaternion rotation, out float yaw, out string rejection) { //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_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0083: 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_008e: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: 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_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) position = Vector3.zero; rotation = Quaternion.identity; yaw = 0f; rejection = "No candidate was tested."; float[] array = new float[3] { preferredDistance, Math.Min(30f, preferredDistance + 5f), Math.Max(5f, preferredDistance - 4f) }.Distinct().ToArray(); float[] array2 = new float[7] { 0f, 5f, -5f, 10f, -10f, 15f, -15f }; for (float num = 0f; num < 360f; num += 30f) { Quaternion val = Maths.SphericalRotation(player.position, num); Vector3 val2 = val * Vector3.forward; Vector3 val3 = val * Vector3.right; float[] array3 = array; foreach (float num2 in array3) { float[] array4 = array2; foreach (float num3 in array4) { Vector3 val4 = factory.planet.aux.Snap(player.position + val2 * num2 + val3 * num3, true); Quaternion val5 = Maths.SphericalRotation(val4, num); if (ValidateExactCoreBuildCandidate(factory, player, item, val4, val5, num, out rejection)) { position = val4; rotation = val5; yaw = num; return true; } } } } return false; } private static bool ValidateExactCoreBuildCandidate(PlanetFactory factory, Player player, ItemProto item, Vector3 position, Quaternion rotation, float yaw, out string rejection) { //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Invalid comparison between Unknown and I4 rejection = string.Empty; PlayerAction_Build actionBuild = player.controller.actionBuild; if (actionBuild.active || actionBuild.templatePreviews.Count != 0 || ((BuildTool)actionBuild.clickTool).buildPreviews.Count != 0) { rejection = "The player's normal build UI owns preview state."; return false; } actionBuild.SetFactoryReferences(); SpherewrightClickBuildTool spherewrightClickBuildTool = new SpherewrightClickBuildTool(); ((BuildTool)spherewrightClickBuildTool)._Init(GameMain.data); ((BuildTool)spherewrightClickBuildTool).SetFactoryReferences(); try { if (((BuildTool)spherewrightClickBuildTool).factory != factory) { rejection = "The isolated DSP click-build validator is not bound to the local factory."; return false; } ((BuildTool_Click)spherewrightClickBuildTool).handItem = item; ((BuildTool_Click)spherewrightClickBuildTool).handPrefabDesc = item.prefabDesc; ((BuildTool_Click)spherewrightClickBuildTool).yaw = yaw; if (!spherewrightClickBuildTool.SnapshotPlayerInventory()) { rejection = "The player inventory could not be copied for DSP build validation."; return false; } BuildPreview val = CreateCorePreview(item, position, rotation); ((BuildTool)spherewrightClickBuildTool).buildPreviews.Add(val); bool flag = ((BuildTool_Click)spherewrightClickBuildTool).CheckBuildConditions(); rejection = ((flag && (int)val.condition == 0) ? string.Empty : $"DSP returned {val.condition}."); return flag && (int)val.condition == 0; } finally { ((BuildTool)spherewrightClickBuildTool).buildPreviews.Clear(); spherewrightClickBuildTool.ReleaseSnapshot(); ((BuildTool)spherewrightClickBuildTool)._Free(); } } private static int CreateCorePrebuildOnMainThread(ActionRecord action) { //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0176: 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) PlanetFactory val = GameMain.localPlanet?.factory ?? throw new InvalidOperationException("The local factory is unavailable."); Player val2 = GameMain.mainPlayer ?? throw new InvalidOperationException("The player is unavailable."); ItemProto val3 = ((ProtoSet)(object)LDB.items).Select(action.Plan.BuildingItemId) ?? throw new InvalidOperationException("The planned building prototype disappeared."); int itemCount = val2.package.GetItemCount(((Proto)val3).ID); if (itemCount <= 0) { throw new InvalidOperationException("The planned building item is no longer in inventory."); } PlayerAction_Build actionBuild = val2.controller.actionBuild; if (actionBuild.active || actionBuild.templatePreviews.Count != 0 || ((BuildTool)actionBuild.clickTool).buildPreviews.Count != 0) { throw new InvalidOperationException("The normal build UI acquired preview state during commit."); } actionBuild.SetFactoryReferences(); SpherewrightClickBuildTool spherewrightClickBuildTool = new SpherewrightClickBuildTool(); ((BuildTool)spherewrightClickBuildTool)._Init(GameMain.data); ((BuildTool)spherewrightClickBuildTool).SetFactoryReferences(); try { if (((BuildTool)spherewrightClickBuildTool).factory != val) { throw new InvalidOperationException("The DSP click-build tool is no longer bound to the local factory."); } ((BuildTool_Click)spherewrightClickBuildTool).handItem = val3; ((BuildTool_Click)spherewrightClickBuildTool).handPrefabDesc = val3.prefabDesc; ((BuildTool_Click)spherewrightClickBuildTool).yaw = action.Plan.BuildYaw; if (!spherewrightClickBuildTool.SnapshotPlayerInventory()) { throw new InvalidOperationException("The player inventory could not be copied for commit validation."); } BuildPreview val4 = CreateCorePreview(val3, action.Plan.BuildPosition, action.Plan.BuildRotation); ((BuildTool)spherewrightClickBuildTool).buildPreviews.Add(val4); if (!((BuildTool_Click)spherewrightClickBuildTool).CheckBuildConditions() || (int)val4.condition != 0) { throw new InvalidOperationException($"DSP rejected the prepared building with {val4.condition}."); } ((BuildTool_Click)spherewrightClickBuildTool).CreatePrebuilds(); if (val4.objId >= 0) { throw new InvalidOperationException("DSP did not return an ordinary prebuild object ID."); } if (val2.package.GetItemCount(((Proto)val3).ID) != itemCount - 1) { throw new InvalidOperationException("The accepted prebuild did not consume exactly one owned building item."); } return -val4.objId; } finally { ((BuildTool)spherewrightClickBuildTool).buildPreviews.Clear(); spherewrightClickBuildTool.ReleaseSnapshot(); ((BuildTool)spherewrightClickBuildTool)._Free(); } } private static BuildPreview CreateCorePreview(ItemProto item, Vector3 position, Quaternion rotation) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown return new BuildPreview { item = item, desc = item.prefabDesc, lpos = position, lpos2 = position, lrot = rotation, lrot2 = rotation, condition = (EBuildCondition)0, needModel = false }; } private static int FindBuiltEntity(PlanetFactory factory, int itemId, Vector3 position) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) int num = Math.Min(factory.entityCursor, factory.entityPool.Length); for (int i = 1; i < num; i++) { ref EntityData reference = ref factory.entityPool[i]; if (reference.id == i && reference.protoId == itemId && Vector3.Distance(reference.pos, position) <= 0.25f) { return i; } } return 0; } private static bool CanDeviceRunRecipe(PlanetFactory factory, int entityId, RecipeProto recipe, out string reason) { //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Invalid comparison between Unknown and I4 //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) reason = "The exact built device does not support the requested runtime recipe type."; if (entityId <= 0 || entityId >= factory.entityCursor || entityId >= factory.entityPool.Length) { return false; } ref EntityData reference = ref factory.entityPool[entityId]; if (reference.id != entityId || reference.protoId <= 0) { return false; } ItemProto val = ((ProtoSet)(object)LDB.items).Select((int)reference.protoId); if (val?.prefabDesc == null) { return false; } if (reference.labId > 0 && val.prefabDesc.isLab) { return (int)recipe.Type == 15; } if (reference.assemblerId > 0 && val.prefabDesc.isAssembler) { return val.prefabDesc.assemblerRecipeType == recipe.Type; } return false; } private static void ApplyBuildingConfigurationOnMainThread(NormalActionPlanPayload plan) { //IL_02da: Unknown result type (might be due to invalid IL or missing references) //IL_02dc: Unknown result type (might be due to invalid IL or missing references) //IL_0464: Unknown result type (might be due to invalid IL or missing references) //IL_0469: Unknown result type (might be due to invalid IL or missing references) //IL_04d3: Unknown result type (might be due to invalid IL or missing references) //IL_04d8: Unknown result type (might be due to invalid IL or missing references) //IL_031e: Unknown result type (might be due to invalid IL or missing references) //IL_0323: Unknown result type (might be due to invalid IL or missing references) //IL_0350: Unknown result type (might be due to invalid IL or missing references) //IL_0352: Unknown result type (might be due to invalid IL or missing references) //IL_036b: Unknown result type (might be due to invalid IL or missing references) //IL_0370: Unknown result type (might be due to invalid IL or missing references) //IL_037e: Unknown result type (might be due to invalid IL or missing references) //IL_04de: Unknown result type (might be due to invalid IL or missing references) //IL_04e4: Invalid comparison between Unknown and I4 //IL_038d: Unknown result type (might be due to invalid IL or missing references) //IL_039c: Unknown result type (might be due to invalid IL or missing references) //IL_039e: Unknown result type (might be due to invalid IL or missing references) //IL_03a3: Unknown result type (might be due to invalid IL or missing references) //IL_03a7: Unknown result type (might be due to invalid IL or missing references) //IL_03a9: Unknown result type (might be due to invalid IL or missing references) //IL_03ae: Unknown result type (might be due to invalid IL or missing references) //IL_03b2: Unknown result type (might be due to invalid IL or missing references) //IL_03b9: Unknown result type (might be due to invalid IL or missing references) //IL_03c2: Unknown result type (might be due to invalid IL or missing references) //IL_03c9: Unknown result type (might be due to invalid IL or missing references) PlanetFactory val = GameMain.localPlanet?.factory ?? throw new InvalidOperationException("The local factory is unavailable."); ref EntityData reference = ref val.entityPool[plan.EntityId]; if (plan.ConfigureMode == "research") { if (!CanLabEnterResearchMode(val, plan.EntityId, plan.ConfigureTechId, out string reason)) { throw new InvalidOperationException(reason); } ((LabComponent)(ref val.factorySystem.labPool[reference.labId])).SetFunction(true, 0, plan.ConfigureTechId, val.entitySignPool); val.factorySystem.SyncLabFunctions(GameMain.mainPlayer, reference.labId); val.factorySystem.SyncLabForceAccMode(GameMain.mainPlayer, reference.labId); return; } if (plan.ConfigureMode == "sorter-filter") { if (!CanSetSorterFilter(val, plan.EntityId, plan.ConfigureFilterItemId, out string reason2)) { throw new InvalidOperationException(reason2); } val.factorySystem.inserterPool[reference.inserterId].filter = plan.ConfigureFilterItemId; ref SignData reference2 = ref val.entitySignPool[reference.id]; reference2.iconId0 = (uint)plan.ConfigureFilterItemId; reference2.iconType = ((plan.ConfigureFilterItemId > 0) ? 1u : 0u); return; } if (plan.ConfigureMode == "logistics-station-charge") { if (!CanConfigureLogisticsStationCharge(val, plan.EntityId, plan.ConfigureStationMaximumChargePowerWatts, out long maximumChargeEnergyPerTick, out string reason3)) { throw new InvalidOperationException(reason3); } StationComponent val2 = val.transport.GetStationComponent(reference.stationId) ?? throw new InvalidOperationException("The logistics station disappeared before charge configuration."); ref PowerConsumerComponent reference3 = ref val.powerSystem.consumerPool[val2.pcId]; string a = CapturePlayerPackageState(GameMain.mainPlayer); string a2 = CaptureLogisticsStationStorageState(val2); long energy = val2.energy; long energyPerTick = val2.energyPerTick; long requiredEnergy = reference3.requiredEnergy; long idleEnergyPerTick = reference3.idleEnergyPerTick; int networkId = reference3.networkId; reference3.workEnergyPerTick = maximumChargeEnergyPerTick; if (reference3.workEnergyPerTick == maximumChargeEnergyPerTick && reference3.id == val2.pcId && reference3.entityId == plan.EntityId && reference3.networkId == networkId && reference3.requiredEnergy == requiredEnergy && reference3.idleEnergyPerTick == idleEnergyPerTick && val2.energy == energy && val2.energyPerTick == energyPerTick && string.Equals(a2, CaptureLogisticsStationStorageState(val2), StringComparison.Ordinal) && string.Equals(a, CapturePlayerPackageState(GameMain.mainPlayer), StringComparison.Ordinal)) { return; } throw new InvalidOperationException("The station maximum-charge assignment did not preserve and prove the exact power-consumer, station inventory, and player inventory state."); } if (plan.ConfigureMode == "logistics-station-storage") { if (!TryParseLogisticsStorageLogic(plan.ConfigureStationLocalLogic, out var logic) || !TryParseLogisticsStorageLogic(plan.ConfigureStationRemoteLogic, out var logic2)) { throw new InvalidOperationException("The logistics-station storage logic is invalid."); } if (!CanConfigureLogisticsStationStorage(val, plan.EntityId, plan.ConfigureStationStorageIndex, plan.ConfigureStationItemId, plan.ConfigureStationMaximumCount, logic, logic2, out string reason4)) { throw new InvalidOperationException(reason4); } StationComponent val3 = val.transport.GetStationComponent(reference.stationId) ?? throw new InvalidOperationException("The logistics station disappeared before configuration."); StationStore val4 = val3.storage[plan.ConfigureStationStorageIndex]; string a3 = CapturePlayerPackageState(GameMain.mainPlayer); val.transport.SetStationStorage(val3.id, plan.ConfigureStationStorageIndex, plan.ConfigureStationItemId, plan.ConfigureStationMaximumCount, logic, logic2, GameMain.mainPlayer); StationStore val5 = val3.storage[plan.ConfigureStationStorageIndex]; string b = CapturePlayerPackageState(GameMain.mainPlayer); if (val5.itemId == plan.ConfigureStationItemId && val5.max == plan.ConfigureStationMaximumCount && val5.localLogic == logic && val5.remoteLogic == logic2 && val5.count == val4.count && val5.inc == val4.inc && string.Equals(a3, b, StringComparison.Ordinal)) { return; } throw new InvalidOperationException("The station configuration call did not preserve and prove the exact slot and player inventory state."); } if (plan.ConfigureMode == "logistics-station-belt") { if (!CanConfigureLogisticsStationBelt(val, plan.EntityId, plan.ConfigureStationBeltSlotIndex, plan.ConfigureStationBeltStorageIndex, out int selectedItemId, out string reason5) || selectedItemId != plan.ConfigureStationBeltItemId) { throw new InvalidOperationException(reason5); } StationComponent val6 = val.transport.GetStationComponent(reference.stationId) ?? throw new InvalidOperationException("The logistics station disappeared before output-selector configuration."); ref SlotData reference4 = ref val6.slots[plan.ConfigureStationBeltSlotIndex]; IODir dir = reference4.dir; int beltId = reference4.beltId; int counter = reference4.counter; string a4 = CaptureLogisticsStationStorageState(val6); string a5 = CaptureLogisticsStationBeltSelectorInvariantState(val6, plan.ConfigureStationBeltSlotIndex); string a6 = CapturePlayerPackageState(GameMain.mainPlayer); val6.slots[plan.ConfigureStationBeltSlotIndex].storageIdx = plan.ConfigureStationBeltStorageIndex + 1; ref SlotData reference5 = ref val6.slots[plan.ConfigureStationBeltSlotIndex]; if (reference5.dir == dir && (int)reference5.dir == 1 && reference5.beltId == beltId && reference5.counter == counter && reference5.storageIdx == plan.ConfigureStationBeltStorageIndex + 1 && string.Equals(a4, CaptureLogisticsStationStorageState(val6), StringComparison.Ordinal) && string.Equals(a5, CaptureLogisticsStationBeltSelectorInvariantState(val6, plan.ConfigureStationBeltSlotIndex), StringComparison.Ordinal) && string.Equals(a6, CapturePlayerPackageState(GameMain.mainPlayer), StringComparison.Ordinal)) { return; } throw new InvalidOperationException("The station output-selector assignment did not preserve and prove port topology, station inventory, and player inventory."); } RecipeProto val7 = ((ProtoSet)(object)LDB.recipes).Select(plan.ConfigureRecipeId) ?? throw new InvalidOperationException("The configured recipe disappeared."); if (!CanDeviceRunRecipe(val, plan.EntityId, val7, out string reason6)) { throw new InvalidOperationException(reason6); } if (reference.labId > 0) { ((LabComponent)(ref val.factorySystem.labPool[reference.labId])).SetFunction(false, ((Proto)val7).ID, 0, val.entitySignPool); val.factorySystem.SyncLabFunctions(GameMain.mainPlayer, reference.labId); val.factorySystem.SyncLabForceAccMode(GameMain.mainPlayer, reference.labId); return; } ref AssemblerComponent reference6 = ref val.factorySystem.assemblerPool[reference.assemblerId]; ((AssemblerComponent)(ref reference6)).SetRecipe(((Proto)val7).ID, val.entitySignPool); RecipeExecuteData recipeExecuteData = reference6.recipeExecuteData; GameScenarioLogic gameScenario = GameMain.gameScenario; if (gameScenario != null) { gameScenario.NotifyOnAssemblerRecipePick(val.index, reference6.id, reference6.recipeId, recipeExecuteData?.requires, recipeExecuteData?.requireCounts, recipeExecuteData?.products, recipeExecuteData?.productCounts); } } private static int GetCount(IReadOnlyDictionary inventory, int itemId) { if (!inventory.TryGetValue(itemId, out var value)) { return 0; } return value; } private static void AddRecipeBudget(PreparedNormalAction result, RecipeProto recipe, int count) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Expected O, but got Unknown //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Expected O, but got Unknown for (int i = 0; i < Math.Min(recipe.Items.Length, recipe.ItemCounts.Length); i++) { List itemBudget = result.ItemBudget; ActionItemBudget val = new ActionItemBudget { ItemId = recipe.Items[i] }; ItemProto obj = ((ProtoSet)(object)LDB.items).Select(recipe.Items[i]); val.Name = ((obj != null) ? ((Proto)obj).name : null) ?? string.Empty; val.Count = recipe.ItemCounts[i] * count; val.Direction = "input"; itemBudget.Add(val); } for (int j = 0; j < Math.Min(recipe.Results.Length, recipe.ResultCounts.Length); j++) { List itemBudget2 = result.ItemBudget; ActionItemBudget val2 = new ActionItemBudget { ItemId = recipe.Results[j] }; ItemProto obj2 = ((ProtoSet)(object)LDB.items).Select(recipe.Results[j]); val2.Name = ((obj2 != null) ? ((Proto)obj2).name : null) ?? string.Empty; val2.Count = recipe.ResultCounts[j] * count; val2.Direction = "output"; itemBudget2.Add(val2); } } private static Vector3 CalculateMiningApproach(Vector3 playerPosition, Vector3 objectPosition) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_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_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: 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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) Vector3 val = objectPosition - playerPosition; if (((Vector3)(ref val)).sqrMagnitude < 0.01f) { return objectPosition; } Vector3 val2 = objectPosition - ((Vector3)(ref val)).normalized * 1.2f; return ((Vector3)(ref val2)).normalized * ((Vector3)(ref objectPosition)).magnitude; } private static long EstimateHarvestTicks(ResourceNodeSnapshot resource, int count) { if (resource.Kind == "vein") { VeinProto val = ((ProtoSet)(object)LDB.veins).Select(resource.ProtoId); if (val != null) { return (long)val.MiningTime * (long)count; } return 3600L; } VegeProto val2 = ((ProtoSet)(object)LDB.veges).Select(resource.ProtoId); if (val2 != null) { return val2.MiningTime; } return 3600L; } private static Vector3 ToVector(Vector3Snapshot snapshot) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) return new Vector3(snapshot.X, snapshot.Y, snapshot.Z); } private static bool IsFinite(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } private static WriteBlocker CloneBlocker(WriteBlocker blocker) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown return new WriteBlocker { Code = blocker.Code, Message = blocker.Message }; } private static BridgeError Stale(string message) { return BridgeError.Create("STALE_STATE", message, true, "Inspect current state and prepare a fresh action."); } private static GameCallResult InvalidPlan(string message) { return GameCallResult.Failed(BridgeError.Create("INVALID_REQUEST", message, false, "Correct the request using current structured observations.")); } private static GameCallResult StalePlan(string message) { return GameCallResult.Failed(Stale(message)); } private static GameCallResult NotReadyPlan(string message) { return GameCallResult.Failed(BridgeError.Create("BRIDGE_NOT_READY", message, true, "Wait for the owned world and player systems to finish loading, then retry.")); } private static GameCallResult MissingPlan(bool expired) { return GameCallResult.Failed(BridgeError.Create(expired ? "PLAN_EXPIRED" : "PLAN_NOT_FOUND", expired ? "The normal-game plan expired." : "The normal-game plan was not found or was already accepted.", true, "Inspect current state, prepare a fresh plan, and commit it once.")); } private GameCallResult PrepareDismantlePlanOnMainThread(string? requestedSessionId, PrepareDismantleRequest request) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: 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_00dd: Expected O, but got Unknown //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Expected O, but got Unknown CommonPrepareResult commonPrepareResult = ValidatePrepareCommon(requestedSessionId, request.PlanetId, request.StateHashVersion); if (commonPrepareResult.Error != null) { return GameCallResult.Failed(commonPrepareResult.Error); } if (request.ObjectId <= 0 || string.IsNullOrWhiteSpace(request.ExpectedEndpointStateHash) || string.IsNullOrWhiteSpace(request.ExpectedPlayerStateHash)) { return InvalidPlan("Dismantle requires one positive inspected entity ID plus exact endpoint and player state hashes."); } GameCallResult playerStateOnMainThread = _reader.GetPlayerStateOnMainThread(requestedSessionId, new LocalPlanetRequest { PlanetId = request.PlanetId }); if (!playerStateOnMainThread.Success || playerStateOnMainThread.Value == null) { return GameCallResult.Failed(playerStateOnMainThread.Error); } if (!string.Equals(request.ExpectedPlayerStateHash, playerStateOnMainThread.Value.StateHash, StringComparison.Ordinal)) { return StalePlan("Player position, package, hand, queue, or construction state changed after inspection."); } GameCallResult gameCallResult = _reader.InspectFactoryEntityOnMainThread(requestedSessionId, new InspectFactoryEntityRequest { PlanetId = request.PlanetId, ObjectId = request.ObjectId }); if (!gameCallResult.Success || gameCallResult.Value == null) { return GameCallResult.Failed(gameCallResult.Error); } FactoryEntitySnapshot value = gameCallResult.Value; BridgeError val = ValidateDismantleTarget(playerStateOnMainThread.Value, value, request.ExpectedEndpointStateHash); if (val != null) { return GameCallResult.Failed(val); } string text = CanonicalStateHash.PlayerAction(playerStateOnMainThread.Value); string expectedStateHash = CanonicalStateHash.Combine("dismantle", new object[6] { _sessions.SessionId, request.PlanetId, text, value.EndpointStateHash, value.ObjectId, value.ItemId }); NormalActionPlanPayload payload = NormalActionPlanPayload.Dismantle(_sessions.SessionId, request.PlanetId, expectedStateHash, text, value.EndpointStateHash, value.ObjectId, value.ItemId); GameCallResult gameCallResult2 = AddPreparedPlan(payload, commonPrepareResult.Session, 1L, "DSP's normal PlayerAction_Build.DoDismantleObject removes the exact resource miner, returns its building item and live internal cargo, and readback proves both recovery and disappearance."); if (gameCallResult2.Success && gameCallResult2.Value != null) { gameCallResult2.Value.TargetObjectId = value.ObjectId; gameCallResult2.Value.ItemBudget.Add(new ActionItemBudget { ItemId = value.ItemId, Name = value.Name, Count = 1, Direction = "dismantle-recovery" }); } return gameCallResult2; } private BridgeError? RevalidateDismantlePlanOnMainThread(NormalActionPlanPayload plan) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown GameCallResult playerStateOnMainThread = _reader.GetPlayerStateOnMainThread(plan.SessionId, new LocalPlanetRequest { PlanetId = plan.PlanetId }); if (!playerStateOnMainThread.Success || playerStateOnMainThread.Value == null) { return playerStateOnMainThread.Error; } if (!string.Equals(CanonicalStateHash.PlayerAction(playerStateOnMainThread.Value), plan.PlayerStateHash, StringComparison.Ordinal)) { return Stale("Player position, package, hand, queue, or construction state changed after dismantle preparation."); } GameCallResult gameCallResult = _reader.InspectFactoryEntityOnMainThread(plan.SessionId, new InspectFactoryEntityRequest { PlanetId = plan.PlanetId, ObjectId = plan.EntityId }); if (!gameCallResult.Success || gameCallResult.Value == null) { return gameCallResult.Error; } if (gameCallResult.Value.ItemId != plan.BuildingItemId) { return Stale("The dismantle target item identity changed after preparation."); } return ValidateDismantleTarget(playerStateOnMainThread.Value, gameCallResult.Value, plan.FactoryStateHash); } private static BridgeError? ValidateDismantleTarget(PlayerStateSnapshot player, FactoryEntitySnapshot target, string expectedEndpointStateHash) { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Invalid comparison between Unknown and I4 //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Invalid comparison between Unknown and I4 //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) if (target.ObjectKind != "entity" || target.ObjectId <= 0 || target.ItemId <= 0 || !string.Equals(target.ComponentKind, "miner", StringComparison.Ordinal)) { return BridgeError.Create("INVALID_REQUEST", "The current dismantle slice accepts only a completed resource-miner entity.", false, "Inspect a positive resource-miner entity and prepare again."); } ItemProto val = ((ProtoSet)(object)LDB.items).Select(target.ItemId); if (val?.prefabDesc == null || (!val.prefabDesc.veinMiner && !val.prefabDesc.oilMiner && (int)val.prefabDesc.minerType != 2 && (int)val.prefabDesc.minerType != 3)) { return BridgeError.Create("INVALID_REQUEST", "The inspected entity is not a current-version solid-vein miner or oil extractor.", false, "Use a supported resource-miner entity."); } if (!string.Equals(target.EndpointStateHash, expectedEndpointStateHash, StringComparison.Ordinal)) { return Stale("Dismantle target identity, pose, or connections changed after inspection."); } if (!player.IsAlive || !player.IsOnPlanet || player.MovementState != "Walk" || player.Speed > 0.1f) { return BridgeError.Create("PLAYER_BUSY", "Dismantle requires a living, settled player on the local planet.", true, "Wait for Walk state at no more than 0.1 m/s, inspect again, and prepare a new plan."); } float num = Vector3.Distance(ToVector(player.Position), ToVector(target.Position)); if (num > player.BuildArea + 0.1f) { return BridgeError.Create("TARGET_OUT_OF_RANGE", $"The dismantle target is {num:F2} metres away, outside the player's {player.BuildArea:F2}-metre build area.", true, "Move into normal construction range and prepare again."); } int num2 = CountConservativeRecoverySlots(target); int num3 = player.InventorySlotCount - player.InventoryOccupiedSlotCount; if (num3 < num2) { return BridgeError.Create("INVENTORY_FULL", $"Normal dismantle recovery may require {num2} empty package slots, but only {num3} are free.", true, "Free package slots, inspect the player and target again, then prepare a new dismantle plan."); } return null; } private static int CountConservativeRecoverySlots(FactoryEntitySnapshot target) { Dictionary dictionary = CaptureExpectedDismantleRecovery(target); int num = 0; foreach (KeyValuePair item in dictionary) { int num2 = Math.Max(1, ((ProtoSet)(object)LDB.items).Select(item.Key)?.StackSize ?? 1); num += (item.Value + num2 - 1) / num2; } return num; } private static Dictionary CaptureExpectedDismantleRecovery(FactoryEntitySnapshot target) { Dictionary dictionary = new Dictionary { [target.ItemId] = 1 }; foreach (FactoryBufferSnapshot item in target.Buffers.Where((FactoryBufferSnapshot buffer) => buffer.ItemId > 0 && buffer.Count > 0)) { dictionary[item.ItemId] = GetCount(dictionary, item.ItemId) + item.Count; } return dictionary; } private void ExecuteDismantleOnMainThread(ActionRecord action) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown //IL_00a3: 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_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Expected O, but got Unknown Player obj = GameMain.mainPlayer ?? throw new InvalidOperationException("The player is unavailable during dismantle."); GameCallResult gameCallResult = _reader.InspectFactoryEntityOnMainThread(action.SessionId, new InspectFactoryEntityRequest { PlanetId = action.PlanetId, ObjectId = action.Plan.EntityId }); if (!gameCallResult.Success || gameCallResult.Value == null) { throw new InvalidOperationException("The exact dismantle target disappeared before execution."); } Dictionary dictionary = CaptureExpectedDismantleRecovery(gameCallResult.Value); if (!obj.controller.actionBuild.DoDismantleObject(action.Plan.EntityId)) { throw new InvalidOperationException("DSP's normal dismantle path rejected the exact entity."); } GameCallResult gameCallResult2 = _reader.InspectFactoryEntityOnMainThread(action.SessionId, new InspectFactoryEntityRequest { PlanetId = action.PlanetId, ObjectId = action.Plan.EntityId }); if (!gameCallResult2.Success) { BridgeError? error = gameCallResult2.Error; if (!(((error != null) ? error.Code : null) != "INVALID_ENTITY")) { Dictionary dictionary2 = CaptureInventory(obj); int[] array = action.BeforeInventory.Keys.Concat(dictionary2.Keys).Concat(dictionary.Keys).Distinct() .ToArray(); foreach (int num in array) { int num2 = GetCount(dictionary2, num) - GetCount(action.BeforeInventory, num); int count = GetCount(dictionary, num); if (num2 != count) { throw new InvalidOperationException($"Normal dismantle inventory recovery for item {num} was {num2}, not the expected {count}."); } } action.TargetObjectId = action.Plan.EntityId; action.TargetItemId = action.Plan.BuildingItemId; Complete(action, $"DSP's normal dismantle path removed resource miner {action.Plan.EntityId} and returned its building item plus all live internal cargo with exact inventory conservation."); return; } } throw new InvalidOperationException("The target entity still exists or its disappearance could not be proven after dismantle."); } public GameCallResult PrepareInterplanetaryFlightOnMainThread(string? requestedSessionId, PrepareInterplanetaryFlightRequest request) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Expected O, but got Unknown //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Expected O, but got Unknown //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Invalid comparison between Unknown and I4 //IL_0334: Unknown result type (might be due to invalid IL or missing references) //IL_033b: Unknown result type (might be due to invalid IL or missing references) //IL_0340: Unknown result type (might be due to invalid IL or missing references) //IL_0345: Unknown result type (might be due to invalid IL or missing references) CommonPrepareResult commonPrepareResult = ValidatePrepareCommon(requestedSessionId, request.PlanetId, request.StateHashVersion); if (commonPrepareResult.Error != null) { return GameCallResult.Failed(commonPrepareResult.Error); } if (request.MinimumCoreEnergyRatio < 0.8 || request.MinimumCoreEnergyRatio > 1.0) { return InvalidPlan("Minimum core-energy ratio must be from 0.8 through 1.0 for an interplanetary flight."); } GameCallResult playerStateOnMainThread = _reader.GetPlayerStateOnMainThread(requestedSessionId, new LocalPlanetRequest { PlanetId = request.PlanetId }); if (!playerStateOnMainThread.Success || playerStateOnMainThread.Value == null) { return GameCallResult.Failed(playerStateOnMainThread.Error); } GameCallResult localStarSystemOnMainThread = _reader.GetLocalStarSystemOnMainThread(requestedSessionId, new LocalPlanetRequest { PlanetId = request.PlanetId }); if (!localStarSystemOnMainThread.Success || localStarSystemOnMainThread.Value == null) { return GameCallResult.Failed(localStarSystemOnMainThread.Error); } PlayerStateSnapshot value = playerStateOnMainThread.Value; LocalStarSystemSnapshot value2 = localStarSystemOnMainThread.Value; if (!string.Equals(request.ExpectedPlayerStateHash, value.StateHash, StringComparison.Ordinal) || !string.Equals(request.ExpectedStarSystemStateHash, value2.StateHash, StringComparison.Ordinal)) { return StalePlan("Player or local-star identity changed after inspection; inspect both and prepare again."); } Player mainPlayer = GameMain.mainPlayer; PlanetData localPlanet = GameMain.localPlanet; GalaxyData galaxy = GameMain.galaxy; PlanetData val = ((galaxy != null) ? galaxy.PlanetById(request.DestinationPlanetId) : null); if (((mainPlayer != null) ? mainPlayer.mecha : null) == null || mainPlayer.controller == null || localPlanet == null || val == null) { return NotReadyPlan("The player, local planet, or destination planet is not ready."); } if (!mainPlayer.isAlive || (int)mainPlayer.movementState != 0 || mainPlayer.planetId != request.PlanetId) { return GameCallResult.Failed(BridgeError.Create("ACTION_REJECTED", "Interplanetary flight must start alive and grounded on the inspected origin planet.", true, "Land and stop on the current owned planet, then inspect the player and prepare again.")); } if (mainPlayer.currentOrder != null) { return GameCallResult.Failed(BridgeError.Create("SERVER_BUSY", "A DSP player order is still active, so launch would replace or race it.", true, "Wait for the exact move or harvest order to end, then inspect and prepare again.")); } if (!BuildUiIsIdle(mainPlayer)) { return GameCallResult.Failed(BridgeError.Create("SERVER_BUSY", "The normal build UI still owns an active preview, so native flight controls are not isolated.", true, "Finish or cancel the current build preview, then inspect and prepare the flight again.")); } if (val.id == localPlanet.id || val.star?.id != localPlanet.star?.id) { return InvalidPlan("Destination must be a different planet in the current star system."); } if ((int)val.type == 5) { return InvalidPlan("The bounded first interplanetary-flight action does not land on gas giants."); } if (mainPlayer.mecha.thrusterLevel < 2) { return GameCallResult.Failed(BridgeError.Create("ACTION_REJECTED", "Drive Engine level 2 is required before normal sail mode can begin.", true, "Complete the runtime technology that raises mecha thrusterLevel to at least 2, then inspect and prepare again.")); } double num = ((mainPlayer.mecha.coreEnergyCap > 0.0) ? (mainPlayer.mecha.coreEnergy / mainPlayer.mecha.coreEnergyCap) : 0.0); if (num + 1E-09 < request.MinimumCoreEnergyRatio) { return GameCallResult.Failed(BridgeError.Create("ACTION_REJECTED", $"Core energy ratio {num:F3} is below the prepared minimum {request.MinimumCoreEnergyRatio:F3}.", true, "Recharge at a verified wireless tower, then inspect and prepare again.")); } VectorLF3 val2 = val.uPosition - mainPlayer.uPosition; double num2 = Math.Max(0.0, ((VectorLF3)(ref val2)).magnitude - (double)val.realRadius); double num3 = Math.Max(mainPlayer.mecha.coreEnergyCap * 1.5, num2 * 1000.0); double num4 = CalculateAvailableFlightEnergy(mainPlayer.mecha); if (num4 + 1.0 < num3 || (mainPlayer.mecha.reactorEnergy <= 0.5 && mainPlayer.mecha.reactorItemId <= 0 && !HasUsableFuel(mainPlayer.mecha.reactorStorage))) { return GameCallResult.Failed(BridgeError.Create("ACTION_REJECTED", $"Normal core and fuel energy reserve {num4:F0} J is below the conservative flight budget {num3:F0} J, or no usable fuel remains after the core.", true, "Transfer ordinary fuel into the player inventory, refuel through the normal refuel action, recharge the core, then inspect and prepare again.")); } string text = CanonicalStateHash.PlayerAction(value); string expectedStateHash = CanonicalStateHash.Combine("interplanetary-flight", new object[7] { _sessions.SessionId, request.PlanetId, request.DestinationPlanetId, text, value2.StateHash, request.MinimumCoreEnergyRatio, num3 }); long estimatedTicks = Math.Max(7200L, (long)Math.Ceiling(num2 / Math.Max(300.0, mainPlayer.mecha.maxSailSpeed) * 60.0) + 7200); NormalActionPlanPayload payload = NormalActionPlanPayload.InterplanetaryFlight(_sessions.SessionId, request.PlanetId, request.DestinationPlanetId, expectedStateHash, text, value2.StateHash, num2, request.MinimumCoreEnergyRatio, num3); return AddPreparedPlan(payload, commonPrepareResult.Session, estimatedTicks, $"DSP enters native sail mode, approaches planet {val.id}, and returns the living player to Walk state on that planet without fast travel or teleportation."); } private BridgeError? RevalidateInterplanetaryFlightPlanOnMainThread(NormalActionPlanPayload plan) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown //IL_0155: Unknown result type (might be due to invalid IL or missing references) GameCallResult playerStateOnMainThread = _reader.GetPlayerStateOnMainThread(plan.SessionId, new LocalPlanetRequest { PlanetId = plan.PlanetId }); GameCallResult localStarSystemOnMainThread = _reader.GetLocalStarSystemOnMainThread(plan.SessionId, new LocalPlanetRequest { PlanetId = plan.PlanetId }); if (!playerStateOnMainThread.Success || playerStateOnMainThread.Value == null) { return playerStateOnMainThread.Error; } if (!localStarSystemOnMainThread.Success || localStarSystemOnMainThread.Value == null) { return localStarSystemOnMainThread.Error; } if (!string.Equals(CanonicalStateHash.PlayerAction(playerStateOnMainThread.Value), plan.PlayerStateHash, StringComparison.Ordinal) || !string.Equals(localStarSystemOnMainThread.Value.StateHash, plan.StarSystemStateHash, StringComparison.Ordinal)) { return BridgeError.Create("STALE_STATE", "Player or local-star state changed after the flight plan was prepared.", true, "Inspect the current player and star system, then prepare a new flight plan."); } Player mainPlayer = GameMain.mainPlayer; GalaxyData galaxy = GameMain.galaxy; PlanetData val = ((galaxy != null) ? galaxy.PlanetById(plan.DestinationPlanetId) : null); double num = ((mainPlayer != null && mainPlayer.mecha?.coreEnergyCap > 0.0) ? (mainPlayer.mecha.coreEnergy / mainPlayer.mecha.coreEnergyCap) : 0.0); if (((mainPlayer != null) ? mainPlayer.mecha : null) == null || val == null || (int)mainPlayer.movementState != 0 || mainPlayer.currentOrder != null || mainPlayer.mecha.thrusterLevel < 2 || !BuildUiIsIdle(mainPlayer) || num + 1E-09 < plan.MinimumCoreEnergyRatio || CalculateAvailableFlightEnergy(mainPlayer.mecha) + 1.0 < plan.RequiredFlightEnergy) { return BridgeError.Create("STALE_STATE", "Flight prerequisites changed before commit.", true, "Land, recharge, refuel, inspect the current states, and prepare again."); } return null; } private void StartInterplanetaryFlightOnMainThread(ActionRecord action) { if (EnsureFlightCheckpointOnMainThread(action)) { if (!_flightCheckpoints.TryMarkAttemptStarted(action.FlightCheckpointId, action.ActionId, GameMain.gameTick, out string rejection)) { Fail(action, "Native launch was not started because its checkpoint lifecycle could not be armed: " + rejection); return; } Player mainPlayer = GameMain.mainPlayer; action.FlightBestDistance = action.Plan.EstimatedDistance; action.FlightBestDistanceAtGameTick = GameMain.gameTick; action.FlightLastControlGameTick = -1L; action.FlightDestinationContactAtGameTick = -1L; action.FlightStableLandingAtGameTick = -1L; mainPlayer.controller.actionBuild.blueprintMode = (EBlueprintMode)0; EnterNativeFlight(mainPlayer); action.State = "waiting_for_game"; action.Message = $"A separate pre-flight checkpoint was confirmed at tick {action.FlightCheckpointGameTick}; DSP then accepted native launch toward planet {action.Plan.DestinationPlanetId}."; } } private bool EnsureFlightCheckpointOnMainThread(ActionRecord action) { FlightCheckpointTicket currentTicket = _flightCheckpoints.CurrentTicket; if (currentTicket != null && currentTicket.OriginPlanetId == action.PlanetId && currentTicket.DestinationPlanetId == action.Plan.DestinationPlanetId && _sessions.CanReuseFlightCheckpointForCurrentSession(currentTicket) && _flightCheckpoints.TryValidateCheckpointFile(currentTicket, out string _)) { BindFlightCheckpoint(action, currentTicket); return true; } SessionState val = _sessions.CaptureOnMainThread(); if (!val.OwnedBySpherewright || string.IsNullOrWhiteSpace(val.SessionId) || string.IsNullOrWhiteSpace(val.SaveName) || val.LocalPlanetId != action.PlanetId) { Fail(action, "Native launch was not started because the exact primary owned-save identity was unavailable for a pre-flight checkpoint."); return false; } try { FlightCheckpointTicket flightCheckpointTicket = _flightCheckpoints.CreateDraft(val.SaveName, val.SessionId, val.Revision, action.PlanetId, action.Plan.DestinationPlanetId, action.Plan.PlayerStateHash, action.Plan.StarSystemStateHash); GameMain.gameName = val.SaveName; if (!GameSave.SaveCurrentGame(flightCheckpointTicket.CheckpointSaveName)) { Fail(action, "Native launch was not started because DSP did not confirm the separate pre-flight save."); return false; } long gameTick = GameMain.gameTick; GameSaveHeader val2 = default(GameSaveHeader); GameSave.ReadHeader(flightCheckpointTicket.CheckpointSaveName, false, ref val2); if (val2 == null || val2.gameTick != gameTick) { Fail(action, "Native launch was not started because the pre-flight save header did not prove the exact saved game tick."); return false; } _flightCheckpoints.PersistCompletedCheckpoint(flightCheckpointTicket, gameTick); _sessions.MarkCurrentSessionFlightCheckpoint(flightCheckpointTicket); BindFlightCheckpoint(action, flightCheckpointTicket); return true; } catch (Exception ex) { Fail(action, "Native launch was not started because the protected pre-flight checkpoint could not be completed (" + ex.GetType().Name + ")."); return false; } } private static void BindFlightCheckpoint(ActionRecord action, FlightCheckpointTicket ticket) { action.FlightCheckpointId = ticket.CheckpointId; action.FlightCheckpointReloadToken = ticket.ReloadToken; action.FlightCheckpointGameTick = ticket.SavedGameTick; } private void UpdateInterplanetaryFlight(ActionRecord action) { //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_02d7: Unknown result type (might be due to invalid IL or missing references) //IL_02dd: Invalid comparison between Unknown and I4 //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_05bb: Unknown result type (might be due to invalid IL or missing references) //IL_05c1: Invalid comparison between Unknown and I4 //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_0256: Invalid comparison between Unknown and I4 //IL_0618: Unknown result type (might be due to invalid IL or missing references) //IL_061d: Unknown result type (might be due to invalid IL or missing references) //IL_0621: 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_034f: Unknown result type (might be due to invalid IL or missing references) //IL_0354: Unknown result type (might be due to invalid IL or missing references) //IL_0364: Unknown result type (might be due to invalid IL or missing references) //IL_0369: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Expected O, but got Unknown //IL_03ad: Unknown result type (might be due to invalid IL or missing references) //IL_03b2: Unknown result type (might be due to invalid IL or missing references) //IL_03b4: Unknown result type (might be due to invalid IL or missing references) //IL_03b6: Unknown result type (might be due to invalid IL or missing references) //IL_03b9: Unknown result type (might be due to invalid IL or missing references) //IL_03be: Unknown result type (might be due to invalid IL or missing references) //IL_03c2: Unknown result type (might be due to invalid IL or missing references) //IL_03cd: Unknown result type (might be due to invalid IL or missing references) //IL_03d2: Unknown result type (might be due to invalid IL or missing references) //IL_03d6: Unknown result type (might be due to invalid IL or missing references) //IL_03db: Unknown result type (might be due to invalid IL or missing references) //IL_03e0: Unknown result type (might be due to invalid IL or missing references) //IL_03e5: Unknown result type (might be due to invalid IL or missing references) //IL_0641: Unknown result type (might be due to invalid IL or missing references) //IL_0646: Unknown result type (might be due to invalid IL or missing references) //IL_064b: Unknown result type (might be due to invalid IL or missing references) //IL_041d: Unknown result type (might be due to invalid IL or missing references) //IL_043d: Unknown result type (might be due to invalid IL or missing references) //IL_0442: Unknown result type (might be due to invalid IL or missing references) //IL_04b6: Unknown result type (might be due to invalid IL or missing references) //IL_04dc: Unknown result type (might be due to invalid IL or missing references) //IL_03f6: Unknown result type (might be due to invalid IL or missing references) //IL_03fb: Unknown result type (might be due to invalid IL or missing references) //IL_03ff: Unknown result type (might be due to invalid IL or missing references) //IL_0404: Unknown result type (might be due to invalid IL or missing references) //IL_0409: Unknown result type (might be due to invalid IL or missing references) //IL_040e: Unknown result type (might be due to invalid IL or missing references) //IL_06bf: Unknown result type (might be due to invalid IL or missing references) //IL_06c5: Unknown result type (might be due to invalid IL or missing references) //IL_06ca: Unknown result type (might be due to invalid IL or missing references) //IL_06cf: Unknown result type (might be due to invalid IL or missing references) //IL_0654: Unknown result type (might be due to invalid IL or missing references) //IL_06f7: Unknown result type (might be due to invalid IL or missing references) //IL_051c: Unknown result type (might be due to invalid IL or missing references) //IL_0521: Unknown result type (might be due to invalid IL or missing references) //IL_0525: Unknown result type (might be due to invalid IL or missing references) //IL_0545: Unknown result type (might be due to invalid IL or missing references) //IL_054a: Unknown result type (might be due to invalid IL or missing references) //IL_054f: Unknown result type (might be due to invalid IL or missing references) //IL_0558: Unknown result type (might be due to invalid IL or missing references) Player mainPlayer = GameMain.mainPlayer; GalaxyData galaxy = GameMain.galaxy; PlanetData val = ((galaxy != null) ? galaxy.PlanetById(action.Plan.DestinationPlanetId) : null); if (((mainPlayer != null) ? mainPlayer.mecha : null) == null || mainPlayer.controller == null || val == null || !mainPlayer.isAlive) { Fail(action, "The player or bound destination became unavailable during interplanetary flight."); } else { if (action.FlightLastControlGameTick == GameMain.gameTick) { return; } action.FlightLastControlGameTick = GameMain.gameTick; PlanetData localPlanet = GameMain.localPlanet; bool flag = localPlanet?.id == val.id || mainPlayer.planetId == val.id; if (flag) { ReleaseNativeAscentInput(action); if (action.FlightDestinationContactAtGameTick < 0) { action.FlightDestinationContactAtGameTick = GameMain.gameTick; } if (GameMain.gameTick > action.FlightDestinationContactAtGameTick + 7200) { Fail(action, $"Native landing on planet {val.id} did not remain grounded within the bounded settling window; reload the bound pre-flight checkpoint before retrying."); return; } if ((int)mainPlayer.movementState == 0) { AbortPlayerOrderIfOwned(action); if (mainPlayer.speed <= 0.1f) { if (action.FlightStableLandingAtGameTick < 0) { action.FlightStableLandingAtGameTick = GameMain.gameTick; } long num = GameMain.gameTick - action.FlightStableLandingAtGameTick; action.Message = $"Native landing on planet {val.id} is grounded at {mainPlayer.speed:F2} m/s for {num}/{600L} verification ticks."; if (num >= 600) { GameCallResult playerStateOnMainThread = _reader.GetPlayerStateOnMainThread(action.SessionId, new LocalPlanetRequest { PlanetId = val.id }); if (playerStateOnMainThread.Success && playerStateOnMainThread.Value != null) { action.AfterStateHash = playerStateOnMainThread.Value.StateHash; Complete(action, $"Normal flight remained alive, grounded, and in Walk state on planet {val.id} for {600L} verification ticks."); } } } else { action.FlightStableLandingAtGameTick = -1L; action.Message = $"Native landing touched planet {val.id} in Walk state but is still settling at {mainPlayer.speed:F2} m/s."; } return; } action.FlightStableLandingAtGameTick = -1L; if ((int)mainPlayer.movementState == 1) { UpdateNativeShoreLanding(action, mainPlayer, val); return; } } else { action.FlightStableLandingAtGameTick = -1L; } if ((int)mainPlayer.movementState == 0) { if (localPlanet != null && localPlanet.id != action.PlanetId && localPlanet.id != val.id) { Fail(action, $"Native flight landed on unexpected planet {localPlanet.id}; reload the bound pre-flight checkpoint before retrying."); } else if (GameMain.gameTick > action.StartedAtGameTick + 3600) { Fail(action, "DSP did not enter native flight mode within the bounded launch window; the bound pre-flight checkpoint remains reusable."); } else { EnterNativeFlight(mainPlayer); } return; } if ((int)mainPlayer.movementState == 2) { if (localPlanet?.id == val.id || mainPlayer.planetId == val.id) { ReleaseNativeAscentInput(action); mainPlayer.controller.actionFly.targetAltitude = 1f; mainPlayer.controller.actionFly.moveVelocity = Vector3.zero; mainPlayer.controller.actionFly.rtsVelocity = Vector3.zero; return; } if (GameMain.gameTick > action.StartedAtGameTick + 3600) { Fail(action, "DSP did not enter native sail mode within the bounded launch window; the bound pre-flight checkpoint remains reusable."); return; } ApplyNativeAscentInput(action, mainPlayer); mainPlayer.controller.actionFly.targetAltitude = 100f; Vector3 val2 = mainPlayer.forward; Vector3 val3 = val2; Vector3 val4 = val2; Vector3 position = mainPlayer.position; float num2 = Vector3.Dot(val4, ((Vector3)(ref position)).normalized); position = mainPlayer.position; val2 = val3 - num2 * ((Vector3)(ref position)).normalized; if (((Vector3)(ref val2)).sqrMagnitude < 0.01f) { position = mainPlayer.position; val2 = Vector3.Cross(((Vector3)(ref position)).normalized, Vector3.up); } mainPlayer.controller.actionFly.moveVelocity = ((Vector3)(ref val2)).normalized * Math.Max(13f, mainPlayer.mecha.walkSpeed * 2.5f); action.Message = $"Native fly launch is at {mainPlayer.controller.actionFly.currentAltitude:F1}/{mainPlayer.controller.actionFly.targetAltitude:F1} m with {mainPlayer.controller.horzSpeed:F1} m/s horizontal and {mainPlayer.controller.vertSpeed:F1} m/s vertical speed; blueprint={mainPlayer.controller.actionBuild.blueprintMode}, thruster={mainPlayer.mecha.thrusterLevel}, frame-state={mainPlayer.controller.movementStateInFrame}."; if (TryEnterCurrentVersionNativeSail(mainPlayer)) { ReleaseNativeAscentInput(action); GalaxyData galaxy2 = GameMain.galaxy; PlanetData val5 = ((galaxy2 != null) ? galaxy2.PlanetById(action.PlanetId) : null); VectorLF3 navigationTarget = val.uPosition; FlightPathDetour detour = default(FlightPathDetour); bool flag2 = val5 != null && TrySelectNativeSailDetour(mainPlayer, val5, val, out detour); if (flag2) { navigationTarget = ToVectorLf3(((FlightPathDetour)(ref detour)).AimPoint); } if (val5 != null && ControlNativeSailDeparture(mainPlayer, val5, navigationTarget, out var surfaceDistance, out var relativeSpeed)) { action.Message = (flag2 ? $"DSP's current-version native Fly-to-Sail branch accepted; immediate origin clearance began at {surfaceDistance:F0} m and {relativeSpeed:F1} m/s toward a verified detour around body {((FlightPathDetour)(ref detour)).ObstacleBodyId}." : $"DSP's current-version native Fly-to-Sail branch accepted; immediate origin clearance began at {surfaceDistance:F0} m and {relativeSpeed:F1} m/s."); } else { action.Message = "DSP's current-version native Fly-to-Sail branch accepted the verified altitude, horizontal-speed, and thruster conditions."; } } return; } if ((int)mainPlayer.movementState < 3) { if (flag && GameMain.gameTick % 120 == 0L) { action.Message = $"Native landing has contacted planet {val.id} in {mainPlayer.movementState} state and is waiting for a stable grounded Walk state."; } return; } ReleaseNativeAscentInput(action); GalaxyData galaxy3 = GameMain.galaxy; PlanetData val6 = ((galaxy3 != null) ? galaxy3.PlanetById(action.PlanetId) : null); VectorLF3 navigationTarget2 = val.uPosition; FlightPathDetour detour2 = default(FlightPathDetour); bool flag3 = val6 != null && TrySelectNativeSailDetour(mainPlayer, val6, val, out detour2); if (flag3) { navigationTarget2 = ToVectorLf3(((FlightPathDetour)(ref detour2)).AimPoint); } if (val6 != null && ControlNativeSailDeparture(mainPlayer, val6, navigationTarget2, out var surfaceDistance2, out var relativeSpeed2)) { action.Message = (flag3 ? $"Native sail is clearing the origin planet at {surfaceDistance2:F0} m above its surface and {relativeSpeed2:F1} m/s relative speed toward a verified detour around body {((FlightPathDetour)(ref detour2)).ObstacleBodyId}." : $"Native sail is clearing the origin planet at {surfaceDistance2:F0} m above its surface and {relativeSpeed2:F1} m/s relative speed before turning toward planet {val.id}."); return; } VectorLF3 val7 = val.uPosition - mainPlayer.uPosition; double surfaceDistance3 = Math.Max(0.0, ((VectorLF3)(ref val7)).magnitude - (double)val.realRadius); double waypointDistance = 0.0; double relativeSpeed3; if (flag3) { ControlNativeSailTowardDetour(mainPlayer, detour2, out waypointDistance, out relativeSpeed3); } else { ControlNativeSailTowardPlanet(mainPlayer, val, out surfaceDistance3, out relativeSpeed3); } if (surfaceDistance3 + 1.0 < action.FlightBestDistance) { action.FlightBestDistance = surfaceDistance3; action.FlightBestDistanceAtGameTick = GameMain.gameTick; } if (GameMain.gameTick % 300 == 0L) { action.Message = (flag3 ? $"Native sail is taking a {waypointDistance:F0} m waypoint around body {((FlightPathDetour)(ref detour2)).ObstacleBodyId}; its direct route clearance was {((FlightPathDetour)(ref detour2)).DirectClearance:F0}/{((FlightPathDetour)(ref detour2)).RequiredClearance:F0} m, destination surface distance is {surfaceDistance3:F0} m, and relative speed is {relativeSpeed3:F1} m/s." : $"Native sail is {surfaceDistance3:F0} m from planet {val.id}'s surface at {relativeSpeed3:F1} m/s; core energy {mainPlayer.mecha.coreEnergy:F0}/{mainPlayer.mecha.coreEnergyCap:F0} J."); } long num3 = Math.Max(216000L, action.Plan.EstimatedTicks * 6); if (GameMain.gameTick > action.StartedAtGameTick + num3) { action.Stalled = true; Fail(action, $"Native sail exceeded its bounded timeout at {surfaceDistance3:F0} m from planet {val.id}; the bound checkpoint must be reloaded before another attempt."); return; } long num4 = Math.Max(18000L, action.Plan.EstimatedTicks * 2); if (surfaceDistance3 > (double)val.realRadius && GameMain.gameTick > action.FlightBestDistanceAtGameTick + num4) { action.Stalled = true; Fail(action, $"Native sail made no new best-distance progress for {num4} game ticks while {surfaceDistance3:F0} m from planet {val.id}; the bound checkpoint must be reloaded before another attempt."); } } } private void UpdateNativeShoreLanding(ActionRecord action, Player player, PlanetData destination) { //IL_02bf: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Expected O, but got Unknown //IL_00d0: Expected O, but got Unknown //IL_0328: Unknown result type (might be due to invalid IL or missing references) //IL_035c: Unknown result type (might be due to invalid IL or missing references) //IL_0368: Unknown result type (might be due to invalid IL or missing references) //IL_0374: Unknown result type (might be due to invalid IL or missing references) //IL_039f: Unknown result type (might be due to invalid IL or missing references) //IL_03a9: Expected O, but got Unknown //IL_0116: 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_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) if (action.PlayerOrder != null) { ActionRecord actionRecord; if (player.currentOrder == action.PlayerOrder) { bool hasValue = action.PowerStarvedAtGameTick.HasValue; if (!FailPowerStarvedPlayerOrder(action, "shore-landing movement") && !action.PowerStarvedAtGameTick.HasValue) { float num = SurfaceDistance(player.position, action.PlayerOrder.target, destination.realRadius); actionRecord = action; if (actionRecord.MovementProgress == null) { ActionRecord actionRecord2 = actionRecord; MovementProgressWatchdog val = new MovementProgressWatchdog(GameMain.gameTick, (double)player.position.x, (double)player.position.y, (double)player.position.z, (double)num, 180L, 600L, 0.75, 1.0); MovementProgressWatchdog val2 = val; actionRecord2.MovementProgress = val; } if (hasValue) { action.MovementProgress.ResetWindow(GameMain.gameTick, (double)player.position.x, (double)player.position.y, (double)player.position.z, (double)num); } MovementProgressObservation val3 = action.MovementProgress.Observe(GameMain.gameTick, (double)player.position.x, (double)player.position.y, (double)player.position.z, (double)num); if ((int)((MovementProgressObservation)(ref val3)).Status != 0) { AbortPlayerOrderIfOwned(action); Fail(action, $"Native Drift shore recovery stopped because its exact owned movement order made no safe physical progress for {((MovementProgressObservation)(ref val3)).StalledGameTicks} game ticks; reload the bound pre-flight checkpoint before retrying."); } else if (GameMain.gameTick % 120 == 0L) { action.Message = $"Native Drift shore recovery is walking toward dry terrain on planet {destination.id}; {num:F1} m remains on bounded order {action.FlightLandingOrderCount}/{3}."; } } return; } if (player.currentOrder != null) { Fail(action, "A different player order replaced the exact owned Drift shore-recovery order; the bound pre-flight checkpoint must be reloaded before retrying."); return; } if (!action.PlayerOrder.targetReached) { Fail(action, "DSP cleared the exact owned Drift shore-recovery order before it reached the selected terrain; the bound pre-flight checkpoint must be reloaded before retrying."); return; } actionRecord = action; long? flightLandingOrderReachedAtGameTick = actionRecord.FlightLandingOrderReachedAtGameTick; long valueOrDefault = flightLandingOrderReachedAtGameTick.GetValueOrDefault(); if (!flightLandingOrderReachedAtGameTick.HasValue) { valueOrDefault = GameMain.gameTick; ActionRecord actionRecord3 = actionRecord; long? flightLandingOrderReachedAtGameTick2 = valueOrDefault; actionRecord3.FlightLandingOrderReachedAtGameTick = flightLandingOrderReachedAtGameTick2; } if (GameMain.gameTick <= action.FlightLandingOrderReachedAtGameTick.Value + 120) { if (GameMain.gameTick % 30 == 0L) { action.Message = $"Native Drift shore recovery reached its dry-terrain order and is waiting for DSP's ordinary Drift-to-Walk transition on planet {destination.id}."; } return; } action.PlayerOrder = null; action.MovementProgress = null; action.FlightLandingOrderReachedAtGameTick = null; } if (action.FlightLandingOrderCount >= 3) { Fail(action, $"DSP remained in Drift after {3} bounded dry-terrain movement orders; reload the bound pre-flight checkpoint before retrying."); return; } if (player.currentOrder != null) { Fail(action, "A player order appeared before Drift shore recovery could claim the native movement channel; the bound pre-flight checkpoint must be reloaded before retrying."); return; } Vector3 target; float surfaceDistance; float terrainClearance; try { if (!TryFindNearestDryLandingTarget(destination, player.position, out target, out surfaceDistance, out terrainClearance)) { Fail(action, $"No terrain with a verified dry neighborhood was found within {120f:F0} m of the ocean contact point on planet {destination.id}; reload the bound pre-flight checkpoint before retrying."); return; } } catch (Exception ex) { Fail(action, "The current-version terrain query failed safely with " + ex.GetType().Name + " before a Drift shore-recovery order was issued; reload the bound pre-flight checkpoint before retrying."); return; } action.PlayerOrder = OrderNode.MoveTo(target); action.FlightLandingOrderCount++; action.FlightLandingOrderReachedAtGameTick = null; action.MovementProgress = new MovementProgressWatchdog(GameMain.gameTick, (double)player.position.x, (double)player.position.y, (double)player.position.z, (double)surfaceDistance, 180L, 600L, 0.75, 1.0); player.Order(action.PlayerOrder, false); action.Message = $"Native landing contacted ocean on planet {destination.id}; DSP accepted bounded Drift movement order {action.FlightLandingOrderCount}/{3} toward the nearest verified dry neighborhood {surfaceDistance:F1} m away with {terrainClearance:F2} m terrain clearance."; } private static bool TryFindNearestDryLandingTarget(PlanetData planet, Vector3 currentPosition, out Vector3 target, out float surfaceDistance, out float terrainClearance) { //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_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Expected O, but got Unknown //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) target = Vector3.zero; surfaceDistance = 0f; terrainClearance = 0f; PlanetRawData data = planet.data; Vector3[] array = data?.vertices; if (data == null || array == null || array.Length == 0 || data.heightData == null || data.indexMap == null || data.modData == null || planet.realRadius <= 0f || planet.scale <= 0f) { return false; } Vector3 normalized = ((Vector3)(ref currentPosition)).normalized; if (((Vector3)(ref normalized)).sqrMagnitude < 0.99f) { return false; } LandingShoreCandidateScore val = null; Vector3 val2 = Vector3.zero; float num = 0f; double num2 = Math.Cos(120f / planet.realRadius); double num3 = Math.Cos(1f / planet.realRadius); for (int i = 0; i < array.Length; i++) { Vector3 val3 = array[i]; if (((Vector3)(ref val3)).sqrMagnitude < 0.99f) { continue; } ((Vector3)(ref val3)).Normalize(); double num4 = Math.Max(-1.0, Math.Min(1.0, Vector3.Dot(normalized, val3))); if (!(num4 < num2) && !(num4 > num3)) { double surfaceDistance2 = Math.Acos(num4) * (double)planet.realRadius; float num5 = data.QueryModifiedHeight(val3) * planet.scale; LandingShoreCandidateScore val4 = new LandingShoreCandidateScore { Index = i, SurfaceDistance = surfaceDistance2, TerrainClearance = num5 - planet.realRadius }; if (LandingShoreSelection.IsEligible(val4, 1.0, 120.0, 0.20000000298023224) && LandingShoreSelection.IsPreferred(val4, val) && HasDryLandingNeighborhood(planet, val3)) { val = val4; val2 = val3; num = num5; } } } if (val == null) { return false; } target = val2 * (num + 0.2f); surfaceDistance = (float)val.SurfaceDistance; terrainClearance = (float)val.TerrainClearance; return true; } private static bool HasDryLandingNeighborhood(PlanetData planet, Vector3 normal) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) PlanetRawData data = planet.data; if (data == null || planet.realRadius <= 0f) { return false; } Vector3 val = Vector3.Cross(normal, (Math.Abs(normal.y) < 0.9f) ? Vector3.up : Vector3.right); Vector3 normalized = ((Vector3)(ref val)).normalized; val = Vector3.Cross(normal, normalized); Vector3 normalized2 = ((Vector3)(ref val)).normalized; float num = 2f / planet.realRadius; float num2 = Mathf.Cos(num); float num3 = Mathf.Sin(num); for (int i = 0; i < 8; i++) { float num4 = (float)i * (float)Math.PI * 0.25f; Vector3 val2 = normalized * Mathf.Cos(num4) + normalized2 * Mathf.Sin(num4); val = normal * num2 + val2 * num3; Vector3 normalized3 = ((Vector3)(ref val)).normalized; float num5 = data.QueryModifiedHeight(normalized3) * planet.scale - planet.realRadius; if (float.IsNaN(num5) || float.IsInfinity(num5) || num5 < -0.05f) { return false; } } return true; } private static float SurfaceDistance(Vector3 first, Vector3 second, float radius) { //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_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) Vector3 normalized = ((Vector3)(ref first)).normalized; Vector3 normalized2 = ((Vector3)(ref second)).normalized; return (float)(Math.Acos(Math.Max(-1.0, Math.Min(1.0, Vector3.Dot(normalized, normalized2)))) * (double)radius); } private static bool TrySelectNativeSailDetour(Player player, PlanetData origin, PlanetData destination, out FlightPathDetour detour) { //IL_0001: 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_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) detour = default(FlightPathDetour); PlanetData[] array = origin.star?.planets; if (array == null) { return false; } FlightPathPoint val = default(FlightPathPoint); ((FlightPathPoint)(ref val))..ctor(player.uPosition.x, player.uPosition.y, player.uPosition.z); FlightPathPoint val2 = default(FlightPathPoint); ((FlightPathPoint)(ref val2))..ctor(destination.uPosition.x, destination.uPosition.y, destination.uPosition.z); FlightPathDetour? val3 = null; PlanetData[] array2 = array; FlightPathPoint val5 = default(FlightPathPoint); FlightPathDetour val6 = default(FlightPathDetour); foreach (PlanetData val4 in array2) { if (val4 != null && val4.id != origin.id && val4.id != destination.id) { ((FlightPathPoint)(ref val5))..ctor(val4.uPosition.x, val4.uPosition.y, val4.uPosition.z); if (InterplanetaryFlightPathAvoidance.TryCreateDetour(val, val2, val4.id, val5, (double)val4.realRadius, ref val6) && InterplanetaryFlightPathAvoidance.IsPreferred(val6, val3)) { val3 = val6; } } } if (!val3.HasValue) { return false; } detour = val3.Value; return true; } private static VectorLF3 ToVectorLf3(FlightPathPoint point) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) return new VectorLF3(((FlightPathPoint)(ref point)).X, ((FlightPathPoint)(ref point)).Y, ((FlightPathPoint)(ref point)).Z); } private static void ControlNativeSailTowardDetour(Player player, FlightPathDetour detour, out double waypointDistance, out double relativeSpeed) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: 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_008e: 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_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) PlayerMove_Sail actionSail = player.controller.actionSail; VectorLF3 val = ToVectorLf3(((FlightPathDetour)(ref detour)).AimPoint) - player.uPosition; waypointDistance = ((VectorLF3)(ref val)).magnitude; VectorLF3 val2 = ((waypointDistance > 1E-06) ? (val / waypointDistance) : ((VectorLF3)(ref player.uVelocity)).normalized); AstroData val3 = GameMain.galaxy.astrosData[((FlightPathDetour)(ref detour)).ObstacleBodyId]; VectorLF3 val4 = (val3.uPosNext - val3.uPos) * 60.0; VectorLF3 val5 = player.uVelocity - val4; relativeSpeed = ((VectorLF3)(ref val5)).magnitude; if (relativeSpeed > 1E-06) { double val6 = VectorLF3.AngleDEG(val5, val2); float num = (float)(1.6 / Math.Max(10.0, val6)); VectorLF3 val7 = val2 * relativeSpeed; VectorLF3 val8 = VectorLF3.op_Implicit(Vector3.Slerp(VectorLF3.op_Implicit(val5), VectorLF3.op_Implicit(val7), num)) - val5; actionSail.UseSailEnergy(ref val8, 0.36); player.uVelocity += val8; val5 = player.uVelocity - val4; relativeSpeed = ((VectorLF3)(ref val5)).magnitude; } VectorLF3 val10; if (relativeSpeed > 210.0) { VectorLF3 val9 = val5 * 0.008; actionSail.UseSailEnergy(ref val9, 1.5); player.uVelocity -= val9; val10 = player.uVelocity - val4; relativeSpeed = ((VectorLF3)(ref val10)).magnitude; } else if (relativeSpeed < 200.0) { double num2 = Math.Min(7.0, 200.0 - relativeSpeed); if (num2 > 0.0) { double num3 = actionSail.UseSailEnergy(num2, 1.0); player.uVelocity += val2 * (num2 * num3); val10 = player.uVelocity - val4; relativeSpeed = ((VectorLF3)(ref val10)).magnitude; } } } private static void ControlNativeSailTowardPlanet(Player player, PlanetData destination, out double surfaceDistance, out double relativeSpeed) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: 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_00e9: 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_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: 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_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010d: 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_0114: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_0263: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) PlayerMove_Sail actionSail = player.controller.actionSail; VectorLF3 val = destination.uPosition - player.uPosition; double magnitude = ((VectorLF3)(ref val)).magnitude; surfaceDistance = Math.Max(0.0, magnitude - (double)destination.realRadius); VectorLF3 val2 = ((magnitude > 1E-06) ? (val / magnitude) : ((VectorLF3)(ref player.uVelocity)).normalized); AstroData val3 = GameMain.galaxy.astrosData[destination.id]; VectorLF3 val4 = (val3.uPosNext - val3.uPos) * 60.0; VectorLF3 val5 = player.uVelocity - val4; relativeSpeed = ((VectorLF3)(ref val5)).magnitude; if (relativeSpeed > 1E-06) { double val6 = VectorLF3.AngleDEG(val5, val2); float num = (float)(1.6 / Math.Max(10.0, val6)); VectorLF3 val7 = val2 * relativeSpeed; VectorLF3 val8 = VectorLF3.op_Implicit(Vector3.Slerp(VectorLF3.op_Implicit(val5), VectorLF3.op_Implicit(val7), num)) - val5; actionSail.UseSailEnergy(ref val8, 0.36); player.uVelocity += val8; val5 = player.uVelocity - val4; relativeSpeed = ((VectorLF3)(ref val5)).magnitude; } double num2 = Math.Max(1500.0, relativeSpeed * 6.0); double num3 = Math.Max(25.0, Math.Min(200.0, surfaceDistance * 0.15)); if (surfaceDistance <= num2 && relativeSpeed > num3) { VectorLF3 val9 = val5 * 0.008; actionSail.UseSailEnergy(ref val9, 1.5); player.uVelocity -= val9; } else if (surfaceDistance > num2 && relativeSpeed < (double)actionSail.maxSailSpeed) { double val10 = Math.Max(7.0, Math.Min(actionSail.max_acc, Math.Max(1.0, relativeSpeed) * 0.02)); val10 = Math.Min(val10, (double)actionSail.maxSailSpeed - relativeSpeed); if (val10 > 0.0) { double num4 = actionSail.UseSailEnergy(val10, 1.0); player.uVelocity += val2 * (val10 * num4); } } } private static bool ControlNativeSailDeparture(Player player, PlanetData origin, VectorLF3 navigationTarget, out double surfaceDistance, out double relativeSpeed) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0084: 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_0079: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0184: 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_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_0255: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_027c: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_0283: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Unknown result type (might be due to invalid IL or missing references) //IL_0295: Unknown result type (might be due to invalid IL or missing references) //IL_029a: Unknown result type (might be due to invalid IL or missing references) //IL_0303: Unknown result type (might be due to invalid IL or missing references) //IL_0308: Unknown result type (might be due to invalid IL or missing references) //IL_030a: Unknown result type (might be due to invalid IL or missing references) //IL_0314: Unknown result type (might be due to invalid IL or missing references) //IL_0319: Unknown result type (might be due to invalid IL or missing references) //IL_031e: Unknown result type (might be due to invalid IL or missing references) VectorLF3 val = player.uPosition - origin.uPosition; double magnitude = ((VectorLF3)(ref val)).magnitude; surfaceDistance = Math.Max(0.0, magnitude - (double)origin.realRadius); if (magnitude <= 1E-06) { relativeSpeed = 0.0; return false; } Vector3 val2 = VectorLF3.op_Implicit(val / magnitude); VectorLF3 val3 = navigationTarget - player.uPosition; Vector3 val4 = ((((VectorLF3)(ref val3)).magnitude > 1E-06) ? VectorLF3.op_Implicit(val3 / ((VectorLF3)(ref val3)).magnitude) : val2); float num = Vector3.Dot(val4, val2); double num2 = ((num < 0f) ? (magnitude * Math.Sqrt(Math.Max(0.0, 1.0 - (double)(num * num)))) : double.MaxValue); bool flag = num < 0f && num2 < (double)origin.realRadius + 100.0; if (surfaceDistance >= 500.0 && !flag) { relativeSpeed = 0.0; return false; } Vector3 val5 = val4 - val2 * num; if (((Vector3)(ref val5)).sqrMagnitude < 0.01f) { val5 = Vector3.Cross(val2, player.forward); if (((Vector3)(ref val5)).sqrMagnitude < 0.01f) { val5 = Vector3.Cross(val2, Vector3.up); } } float num3 = ((surfaceDistance < 500.0) ? 1f : 0.25f); Vector3 val6 = val2 * num3 + ((Vector3)(ref val5)).normalized; Vector3 normalized = ((Vector3)(ref val6)).normalized; AstroData val7 = GameMain.galaxy.astrosData[origin.id]; VectorLF3 val8 = (val7.uPosNext - val7.uPos) * 60.0; VectorLF3 val9 = player.uVelocity - val8; relativeSpeed = ((VectorLF3)(ref val9)).magnitude; if (relativeSpeed > 1E-06) { double val10 = VectorLF3.AngleDEG(val9, VectorLF3.op_Implicit(normalized)); float num4 = (float)(1.6 / Math.Max(10.0, val10)); VectorLF3 val11 = VectorLF3.op_Implicit(normalized) * relativeSpeed; VectorLF3 val12 = VectorLF3.op_Implicit(Vector3.Slerp(VectorLF3.op_Implicit(val9), VectorLF3.op_Implicit(val11), num4)) - val9; player.controller.actionSail.UseSailEnergy(ref val12, 0.36); player.uVelocity += val12; val9 = player.uVelocity - val8; relativeSpeed = ((VectorLF3)(ref val9)).magnitude; } double num5 = Math.Min(200.0, player.controller.actionSail.maxSailSpeed); if (relativeSpeed < num5) { double num6 = Math.Min(7.0, num5 - relativeSpeed); double num7 = player.controller.actionSail.UseSailEnergy(num6, 1.0); player.uVelocity += VectorLF3.op_Implicit(normalized) * (num6 * num7); } return true; } private static void EnterNativeFlight(Player player) { //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_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: 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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) EMovementState movementState = player.movementState; player.controller.actionWalk.SwitchToFly(); EMovementState val = (player.movementState = player.controller.movementStateInFrame); if (val != movementState) { player.controller.NotifyMovementStateChange(movementState, val); } } private static bool TryEnterCurrentVersionNativeSail(Player player) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Invalid comparison between Unknown and I4 //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Invalid comparison between Unknown and I4 //IL_0082: 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_008a: 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_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: 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_00c6: Unknown result type (might be due to invalid IL or missing references) PlayerController controller = player.controller; PlayerMove_Fly actionFly = controller.actionFly; if ((int)player.movementState != 2 || actionFly.targetAltitude < 50f || actionFly.currentAltitude <= 49f || controller.horzSpeed <= 12.5f || player.mecha.thrusterLevel < 2 || GameCamera.instance == null || GameMain.gameScenario == null) { return false; } if ((int)controller.cmd.type == 5) { ((CommandState)(ref controller.cmd)).SetNoneCommand(); controller.actionBuild.blueprintMode = (EBlueprintMode)0; } EMovementState movementState = player.movementState; controller.movementStateInFrame = (EMovementState)3; controller.actionSail.ResetSailState(); GameCamera.instance.SyncForSailMode(); GameMain.gameScenario.NotifyOnSailModeEnter(); player.movementState = controller.movementStateInFrame; if (player.movementState != movementState) { controller.NotifyMovementStateChange(movementState, player.movementState); } return true; } private static void ApplyNativeAscentInput(ActionRecord action, Player player) { if (!action.FlightAscentInputOwned) { action.FlightOriginalVerticalInput = player.controller.input1.y; action.FlightOriginalForwardInput = player.controller.input0.y; action.FlightAscentInputOwned = true; } player.controller.input1.y = 1f; player.controller.input0.y = 1f; } private static void ReleaseNativeAscentInput(ActionRecord action) { if (action.FlightAscentInputOwned) { Player mainPlayer = GameMain.mainPlayer; PlayerController val = ((mainPlayer != null) ? mainPlayer.controller : null); if (val != null && Math.Abs(val.input1.y - 1f) < 0.0001f) { val.input1.y = action.FlightOriginalVerticalInput; } if (val != null && Math.Abs(val.input0.y - 1f) < 0.0001f) { val.input0.y = action.FlightOriginalForwardInput; } action.FlightAscentInputOwned = false; } } private static double CalculateAvailableFlightEnergy(Mecha mecha) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) double num = Math.Max(0.0, mecha.coreEnergy) + Math.Max(0.0, mecha.reactorEnergy); StorageComponent reactorStorage = mecha.reactorStorage; GRID[] array = reactorStorage?.grids ?? Array.Empty(); int num2 = Math.Min(reactorStorage?.size ?? 0, array.Length); for (int i = 0; i < num2; i++) { GRID val = array[i]; ItemProto val2 = ((val.itemId > 0 && val.count > 0) ? ((ProtoSet)(object)LDB.items).Select(val.itemId) : null); if (val2 != null && val2.HeatValue > 0 && val2.FuelType > 0) { num += (double)val2.HeatValue * (double)val.count; } } return num; } private GameCallResult PrepareStationFleetTransferOnMainThread(string? requestedSessionId, PrepareLogisticsStationFleetTransferRequest request) { //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Expected O, but got Unknown //IL_00bf: 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_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Expected O, but got Unknown //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_04ae: Unknown result type (might be due to invalid IL or missing references) //IL_04b3: Unknown result type (might be due to invalid IL or missing references) //IL_04bf: Unknown result type (might be due to invalid IL or missing references) //IL_04ea: Unknown result type (might be due to invalid IL or missing references) //IL_04f6: Unknown result type (might be due to invalid IL or missing references) //IL_0507: Expected O, but got Unknown CommonPrepareResult commonPrepareResult = ValidatePrepareCommon(requestedSessionId, request.PlanetId, request.StateHashVersion); if (commonPrepareResult.Error != null) { return GameCallResult.Failed(commonPrepareResult.Error); } if (request.Direction != "player-to-station" && request.Direction != "station-to-player") { return InvalidPlan("Fleet transfer direction must be player-to-station or station-to-player."); } if (request.ItemId != 5001 && request.ItemId != 5002) { return InvalidPlan("Only logistics drones (5001) and logistics vessels (5002) are valid fleet items."); } if (request.Count <= 0 || request.Count > 100) { return InvalidPlan("Fleet transfer count must be from 1 through 100."); } GameCallResult playerStateOnMainThread = _reader.GetPlayerStateOnMainThread(requestedSessionId, new LocalPlanetRequest { PlanetId = request.PlanetId }); GameCallResult gameCallResult = _reader.InspectFactoryEntityOnMainThread(requestedSessionId, new InspectFactoryEntityRequest { PlanetId = request.PlanetId, ObjectId = request.StationEntityId }); if (!playerStateOnMainThread.Success || playerStateOnMainThread.Value == null) { return GameCallResult.Failed(playerStateOnMainThread.Error); } if (gameCallResult.Success) { FactoryEntitySnapshot? value = gameCallResult.Value; if (((value != null) ? value.LogisticsStation : null) != null) { LogisticsStationSnapshot logisticsStation = gameCallResult.Value.LogisticsStation; if (!string.Equals(playerStateOnMainThread.Value.StateHash, request.ExpectedPlayerStateHash, StringComparison.Ordinal) || !string.Equals(logisticsStation.FleetStateHash, request.ExpectedStationFleetStateHash, StringComparison.Ordinal)) { return StalePlan("Player inventory or the exact station fleet changed after inspection."); } PlanetFactory val = GameMain.localPlanet?.factory; Player mainPlayer = GameMain.mainPlayer; if (val == null || ((mainPlayer != null) ? mainPlayer.package : null) == null || !TryGetFleetStation(val, request.StationEntityId, out StationComponent station, out int droneCapacity, out int vesselCapacity)) { return NotReadyPlan("The exact logistics-station fleet component is unavailable."); } float num = Vector3.Distance(mainPlayer.position, ToVector(logisticsStation.Position)); if (num > mainPlayer.mecha.buildArea) { return GameCallResult.Failed(BridgeError.Create("TARGET_OUT_OF_RANGE", $"The station is {num:F2} metres away, outside the current normal interaction/build area.", true, "Move into range through spherewright_prepare_move, then inspect and prepare again.")); } if (mainPlayer.inhandItemId != 0 || mainPlayer.inhandItemCount != 0 || mainPlayer.inhandItemInc != 0) { return GameCallResult.Failed(BridgeError.Create("PLAYER_BUSY", "The player's hand must be empty before a bounded station fleet transfer.", true, "Finish the current hand-item interaction, then inspect and prepare again.")); } int num2 = default(int); int itemCount = mainPlayer.package.GetItemCount(request.ItemId, ref num2); bool flag = CanPlayerPackageAcceptExactly(mainPlayer.package, request.ItemId, request.Count); string text = default(string); if (!LogisticsStationFleetTransferPolicy.TryValidate(station.isStellar, station.isCollector, station.isVeinCollector, request.Direction, request.ItemId, request.Count, itemCount, num2, station.idleDroneCount, station.workDroneCount, droneCapacity, station.idleShipCount, station.workShipCount, vesselCapacity, flag, ref text)) { bool num3 = text.IndexOf("fewer", StringComparison.OrdinalIgnoreCase) >= 0; bool flag2 = text.IndexOf("capacity", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("cannot accept", StringComparison.OrdinalIgnoreCase) >= 0; return GameCallResult.Failed(BridgeError.Create(num3 ? "INVENTORY_INSUFFICIENT" : (flag2 ? "INVENTORY_FULL" : "INVALID_REQUEST"), text, true, "Inspect the current player and station fleet, then adjust the direction or count.")); } string text2 = CanonicalStateHash.PlayerAction(playerStateOnMainThread.Value); string expectedStateHash = CanonicalStateHash.Combine("logistics-station-fleet-transfer", new object[8] { _sessions.SessionId, request.PlanetId, text2, logisticsStation.FleetStateHash, request.StationEntityId, request.Direction, request.ItemId, request.Count }); NormalActionPlanPayload payload = NormalActionPlanPayload.StationFleetTransfer(_sessions.SessionId, request.PlanetId, expectedStateHash, text2, logisticsStation.FleetStateHash, request.StationEntityId, request.Direction, request.ItemId, request.Count); GameCallResult gameCallResult2 = AddPreparedPlan(payload, commonPrepareResult.Session, 1L, "The player package and matching idle fleet count change by equal-and-opposite amounts; working craft, the other fleet slot, station storage, and station energy remain unchanged."); if (gameCallResult2.Success && gameCallResult2.Value != null) { gameCallResult2.Value.SourceObjectId = ((request.Direction == "station-to-player") ? new int?(request.StationEntityId) : ((int?)null)); gameCallResult2.Value.DestinationObjectId = ((request.Direction == "player-to-station") ? new int?(request.StationEntityId) : ((int?)null)); gameCallResult2.Value.EstimatedDistance = num; List itemBudget = gameCallResult2.Value.ItemBudget; ActionItemBudget val2 = new ActionItemBudget { ItemId = request.ItemId }; ItemProto obj = ((ProtoSet)(object)LDB.items).Select(request.ItemId); val2.Name = ((obj != null) ? ((Proto)obj).name : null) ?? string.Empty; val2.Count = request.Count; val2.Direction = request.Direction; itemBudget.Add(val2); } return gameCallResult2; } } return GameCallResult.Failed(gameCallResult.Error ?? BridgeError.Create("INVALID_ENTITY", "The target is not an exact completed logistics station.", false, "Inspect a completed planetary or interstellar logistics station and use its positive entity ID.")); } private BridgeError? RevalidateStationFleetTransferOnMainThread(NormalActionPlanPayload plan) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown GameCallResult playerStateOnMainThread = _reader.GetPlayerStateOnMainThread(plan.SessionId, new LocalPlanetRequest { PlanetId = plan.PlanetId }); GameCallResult gameCallResult = _reader.InspectFactoryEntityOnMainThread(plan.SessionId, new InspectFactoryEntityRequest { PlanetId = plan.PlanetId, ObjectId = plan.FleetTransferStationEntityId }); if (!playerStateOnMainThread.Success || playerStateOnMainThread.Value == null) { return playerStateOnMainThread.Error; } if (gameCallResult.Success) { FactoryEntitySnapshot? value = gameCallResult.Value; if (((value != null) ? value.LogisticsStation : null) != null) { LogisticsStationSnapshot logisticsStation = gameCallResult.Value.LogisticsStation; if (!string.Equals(CanonicalStateHash.PlayerAction(playerStateOnMainThread.Value), plan.PlayerStateHash, StringComparison.Ordinal) || !string.Equals(logisticsStation.FleetStateHash, plan.StationFleetStateHash, StringComparison.Ordinal)) { return Stale("Player inventory or station fleet changed after transfer preparation."); } PlanetFactory val = GameMain.localPlanet?.factory; Player mainPlayer = GameMain.mainPlayer; if (val == null || ((mainPlayer != null) ? mainPlayer.package : null) == null || mainPlayer.inhandItemId != 0 || mainPlayer.inhandItemCount != 0 || mainPlayer.inhandItemInc != 0 || !TryGetFleetStation(val, plan.FleetTransferStationEntityId, out StationComponent station, out int droneCapacity, out int vesselCapacity)) { return Stale("The player hand or exact station identity changed after preparation."); } int num = default(int); int itemCount = mainPlayer.package.GetItemCount(plan.FleetTransferItemId, ref num); string text = default(string); if (!LogisticsStationFleetTransferPolicy.TryValidate(station.isStellar, station.isCollector, station.isVeinCollector, plan.FleetTransferDirection, plan.FleetTransferItemId, plan.Count, itemCount, num, station.idleDroneCount, station.workDroneCount, droneCapacity, station.idleShipCount, station.workShipCount, vesselCapacity, CanPlayerPackageAcceptExactly(mainPlayer.package, plan.FleetTransferItemId, plan.Count), ref text)) { return Stale("Fleet source count, destination capacity, idle availability, or current-version station capacity changed."); } return null; } } return gameCallResult.Error ?? Stale("The exact logistics station disappeared after preparation."); } private void ExecuteStationFleetTransferOnMainThread(ActionRecord action) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: 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_0088: Expected O, but got Unknown //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Unknown result type (might be due to invalid IL or missing references) //IL_0263: Unknown result type (might be due to invalid IL or missing references) //IL_0274: Expected O, but got Unknown //IL_04e5: Unknown result type (might be due to invalid IL or missing references) //IL_04ea: Unknown result type (might be due to invalid IL or missing references) //IL_04fb: Expected O, but got Unknown PlanetFactory factory = GameMain.localPlanet?.factory ?? throw new InvalidOperationException("The local factory is unavailable."); Player val = GameMain.mainPlayer ?? throw new InvalidOperationException("The player is unavailable."); NormalActionPlanPayload plan = action.Plan; if (!TryGetFleetStation(factory, plan.FleetTransferStationEntityId, out StationComponent station, out int _, out int _)) { throw new InvalidOperationException("The exact logistics station disappeared."); } FactoryEntitySnapshot? value = _reader.InspectFactoryEntityOnMainThread(plan.SessionId, new InspectFactoryEntityRequest { PlanetId = plan.PlanetId, ObjectId = plan.FleetTransferStationEntityId }).Value; LogisticsStationSnapshot val2 = ((value != null) ? value.LogisticsStation : null) ?? throw new InvalidOperationException("The station fleet could not be captured before transfer."); int num = default(int); int itemCount = val.package.GetItemCount(plan.FleetTransferItemId, ref num); int num2 = ((plan.FleetTransferItemId == 5001) ? station.idleDroneCount : station.idleShipCount); int num3 = ((plan.FleetTransferItemId == 5001) ? station.workDroneCount : station.workShipCount); int num4 = ((plan.FleetTransferItemId == 5001) ? station.idleShipCount : station.idleDroneCount); int num5 = ((plan.FleetTransferItemId == 5001) ? station.workShipCount : station.workDroneCount); string a = CapturePlayerPackageStateExcludingItem(val.package, plan.FleetTransferItemId); string a2 = CaptureLogisticsStationStorageState(station); long energy = station.energy; int warperCount = station.warperCount; if (plan.FleetTransferDirection == "player-to-station") { int num7 = default(int); int num6 = val.package.TakeItem(plan.FleetTransferItemId, plan.Count, ref num7); if (num6 != plan.Count || num7 != 0) { throw new InvalidOperationException("The player package did not remove the prepared unproliferated fleet count."); } if (plan.FleetTransferItemId == 5001) { StationComponent obj = station; obj.idleDroneCount += num6; } else { StationComponent obj2 = station; obj2.idleShipCount += num6; } } else { int num9 = default(int); int num8 = val.package.AddItemStacked(plan.FleetTransferItemId, plan.Count, 0, ref num9); if (num8 != plan.Count || num9 != 0) { throw new InvalidOperationException("The player package did not accept the prepared idle fleet count."); } if (plan.FleetTransferItemId == 5001) { StationComponent obj3 = station; obj3.idleDroneCount -= num8; } else { StationComponent obj4 = station; obj4.idleShipCount -= num8; } val.NotifyPackageAddItem(plan.FleetTransferItemId, num8, 0); } FactoryEntitySnapshot? value2 = _reader.InspectFactoryEntityOnMainThread(plan.SessionId, new InspectFactoryEntityRequest { PlanetId = plan.PlanetId, ObjectId = plan.FleetTransferStationEntityId }).Value; LogisticsStationSnapshot val3 = ((value2 != null) ? value2.LogisticsStation : null) ?? throw new InvalidOperationException("The station fleet could not be captured after transfer."); int num10 = default(int); int itemCount2 = val.package.GetItemCount(plan.FleetTransferItemId, ref num10); int num11 = ((plan.FleetTransferItemId == 5001) ? station.idleDroneCount : station.idleShipCount); int num12 = ((plan.FleetTransferItemId == 5001) ? station.workDroneCount : station.workShipCount); int num13 = ((plan.FleetTransferDirection == "player-to-station") ? (-plan.Count) : plan.Count); bool num14; if (itemCount2 - itemCount == num13 && num11 - num2 == -num13 && num12 == num3 && itemCount + num2 + num3 == itemCount2 + num11 + num12 && num10 == num) { if (plan.FleetTransferItemId != 5001) { if (station.idleDroneCount == num4) { num14 = station.workDroneCount != num5; goto IL_038b; } } else if (station.idleShipCount == num4) { num14 = station.workShipCount != num5; goto IL_038b; } } goto IL_03f9; IL_03f9: throw new InvalidOperationException("Post-transfer readback did not prove exact fleet conservation and preservation of unrelated station/player state."); IL_038b: if (!num14 && val.inhandItemId == 0 && val.inhandItemCount == 0 && val.inhandItemInc == 0 && station.energy == energy && station.warperCount == warperCount && string.Equals(a, CapturePlayerPackageStateExcludingItem(val.package, plan.FleetTransferItemId), StringComparison.Ordinal) && string.Equals(a2, CaptureLogisticsStationStorageState(station), StringComparison.Ordinal) && string.Equals(val2.ConfigurationStateHash, val3.ConfigurationStateHash, StringComparison.Ordinal)) { action.TargetObjectId = plan.FleetTransferStationEntityId; action.TargetItemId = plan.FleetTransferItemId; action.BeforeTargetAmount = num2; action.AfterTargetAmount = num11; action.Message = $"Normal station fleet transfer conserved item {plan.FleetTransferItemId}: player {itemCount}->{itemCount2}, idle fleet {num2}->{num11}, working fleet {num3}."; action.State = "completed"; action.Terminal = true; action.Succeeded = true; action.CompletedAtGameTick = GameMain.gameTick; action.AfterInventory = CaptureInventory(val); action.AfterStateHash = CanonicalStateHash.Combine("logistics-station-fleet-transfer", new object[4] { CanonicalStateHash.PlayerAction(_reader.GetPlayerStateOnMainThread(plan.SessionId, new LocalPlanetRequest { PlanetId = plan.PlanetId }).Value), val3.FleetStateHash, plan.FleetTransferItemId, plan.Count }); return; } goto IL_03f9; } private static bool TryGetFleetStation(PlanetFactory factory, int entityId, out StationComponent? station, out int droneCapacity, out int vesselCapacity) { station = null; droneCapacity = 0; vesselCapacity = 0; if (entityId <= 0 || entityId >= factory.entityCursor || entityId >= factory.entityPool.Length) { return false; } ref EntityData reference = ref factory.entityPool[entityId]; PrefabDesc val = ((reference.id != entityId) ? null : ((ProtoSet)(object)LDB.items).Select((int)reference.protoId)?.prefabDesc); if (val == null || reference.stationId <= 0) { return false; } PlanetTransport transport = factory.transport; station = ((transport != null) ? transport.GetStationComponent(reference.stationId) : null); if (station == null || station.id != reference.stationId || station.entityId != entityId || !LogisticsStationIdentityPolicy.MatchesLocalPlanet(station.isStellar, station.planetId, factory.planetId)) { station = null; return false; } droneCapacity = val.stationMaxDroneCount; vesselCapacity = val.stationMaxShipCount; return true; } private static bool CanPlayerPackageAcceptExactly(StorageComponent package, int itemId, int count) { using StorageCopy storageCopy = new StorageCopy(package); int num = default(int); return storageCopy.Value.AddItemStacked(itemId, count, 0, ref num) == count && num == 0; } private static string CapturePlayerPackageStateExcludingItem(StorageComponent package, int excludedItemId) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0084: 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) List list = new List { package.size, package.bans, package.isPlayerInventory }; GRID[] array = package.grids ?? Array.Empty(); for (int i = 0; i < array.Length; i++) { GRID val = array[i]; if (val.itemId != 0 && val.itemId != excludedItemId) { list.Add(i); list.Add(val.itemId); list.Add(val.count); list.Add(val.inc); } } return CanonicalStateHash.Combine("player-package-excluding-item-v1", list.ToArray()); } public GameCallResult PrepareQuarantineReconciliationOnMainThread(string? requestedSessionId, PrepareQuarantineReconciliationRequest request) { //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_0243: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_0265: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_027c: Unknown result type (might be due to invalid IL or missing references) //IL_0284: Unknown result type (might be due to invalid IL or missing references) //IL_028f: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) //IL_02ac: Expected O, but got Unknown CommonPrepareResult commonPrepareResult = ValidatePrepareCommon(requestedSessionId, request.PlanetId, request.StateHashVersion); if (commonPrepareResult.Error != null) { return GameCallResult.Failed(commonPrepareResult.Error); } SessionState session = commonPrepareResult.Session; if (session.Revision != request.ExpectedRevision) { return GameCallResult.Failed(BridgeError.Create("STALE_REVISION", "The session revision changed before quarantine reconciliation was prepared.", true, "Read session state and the quarantined action again, then prepare against that exact revision.")); } if (!string.Equals(session.WriteHealth, "quarantined", StringComparison.Ordinal) || string.IsNullOrWhiteSpace(session.WriteQuarantineActionId) || !string.Equals(session.WriteQuarantineActionId, request.ActionId, StringComparison.Ordinal)) { return GameCallResult.Failed(BridgeError.Create("WRITE_SUBSYSTEM_QUARANTINED", "The requested action is not the exact action currently responsible for write quarantine.", false, "Use writeQuarantineActionId from the current owned-session state.")); } if (!_actions.TryGetValue(request.ActionId, out ActionRecord value) || !string.Equals(value.SessionId, session.SessionId, StringComparison.Ordinal) || value.PlanetId != request.PlanetId || !value.Terminal || !string.Equals(value.State, "outcome_unknown", StringComparison.Ordinal) || !string.Equals(value.ActionKind, "build", StringComparison.Ordinal)) { return GameCallResult.Failed(BridgeError.Create("ACTION_OUTCOME_UNKNOWN", "Only the retained, exact outcome-unknown build action that caused this quarantine can be reconciled.", false, "Keep the session running and inspect the writeQuarantineActionId action; restart-resume is required if its proof record is unavailable.")); } if (!TryProveQuarantinedBuild(value, out IReadOnlyList resolvedEntityIds, out string proofHash, out string rejection)) { return GameCallResult.Failed(BridgeError.Create("ACTION_OUTCOME_UNKNOWN", "The quarantined build still cannot be proved: " + rejection, true, "Leave writes quarantined, inspect the exact entities and topology, and retry only after the world itself provides unambiguous proof.")); } string reason = _sessions.WriteQuarantineReason ?? value.OriginalOutcomeMessage ?? value.Message ?? string.Empty; NormalActionPlanPayload normalActionPlanPayload = NormalActionPlanPayload.QuarantineReconciliation(session.SessionId, request.PlanetId, proofHash, request.ActionId, reason, session.Revision, resolvedEntityIds); PreparedPlan val; try { val = _plans.Add(proofHash, normalActionPlanPayload); } catch (InvalidOperationException) { return GameCallResult.Failed(BridgeError.Create("SERVER_BUSY", "Too many normal-game plans are active.", true, "Wait for old plans to expire, then prepare this reconciliation again.")); } List list = session.WriteBlockers.Where((WriteBlocker blocker) => !string.Equals(blocker.Code, "WRITE_SUBSYSTEM_QUARANTINED", StringComparison.Ordinal)).Select(CloneBlocker).ToList(); return GameCallResult.Succeeded(new PreparedNormalAction { Prepared = true, ActionKind = "reconcile-quarantine", PlanToken = val.Token, ExpiresAtUtc = val.ExpiresAtUtc, ExpectedStateHash = proofHash, StateHashVersion = 1, CommitAllowedNow = (list.Count == 0), CommitBlockers = list, CompletionCondition = "The exact retained outcome-unknown build still has the same item-cost, entity identities, components, and directed topology; only then is its quarantine cleared.", ReconcilesActionId = request.ActionId, ProvedObjectIds = resolvedEntityIds.ToList() }); } public GameCallResult CommitQuarantineReconciliationOnMainThread(string? requestedSessionId, CommitNormalActionRequest request) { //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Expected O, but got Unknown if (!Guid.TryParse(request.IdempotencyKey, out var _)) { return GameCallResult.Failed(BridgeError.Create("INVALID_REQUEST", "A UUID idempotency key is required.", false, "Generate one UUID and reuse it for retries of this exact reconciliation commit.")); } if (!string.Equals(requestedSessionId, request.SessionId, StringComparison.Ordinal)) { return GameCallResult.Failed(BridgeError.Create("STALE_SESSION", "Envelope and commit payload session IDs do not match.", false, "Use the exact current owned session ID in both locations.")); } string text = CanonicalStateHash.Combine("commit-reconcile-quarantine", new object[3] { request.SessionId, request.PlanetId, request.PlanToken }); NormalActionCommitResult result2 = default(NormalActionCommitResult); bool flag = default(bool); if (_idempotency.TryGet(request.SessionId, request.IdempotencyKey, text, ref result2, ref flag)) { return GameCallResult.Succeeded(CloneCommitResult(result2, replay: true)); } if (flag) { return GameCallResult.Failed(BridgeError.Create("IDEMPOTENCY_CONFLICT", "The idempotency key is already bound to a different normal-game commit.", false, "Reuse it only for the original commit or generate a new UUID for a newly prepared reconciliation.")); } if (!_idempotency.HasCapacity(request.SessionId)) { return GameCallResult.Failed(BridgeError.Create("IDEMPOTENCY_CAPACITY_EXCEEDED", "The Plugin idempotency cache has no capacity for another reconciliation result.", false, "Restart and resume the exact owned world before attempting another reconciliation; quarantine was not changed.")); } PreparedPlan val = default(PreparedPlan); bool expired = default(bool); if (!_plans.TryGet(request.PlanToken, ref val, ref expired) || val == null) { return MissingPlan(expired); } NormalActionPlanPayload payload = val.Payload; if (!string.Equals(payload.ActionKind, "reconcile-quarantine", StringComparison.Ordinal)) { return GameCallResult.Failed(BridgeError.Create("INVALID_REQUEST", "The plan token does not belong to quarantine reconciliation.", false, "Commit the plan through its matching reconciliation method.")); } SessionState session = _sessions.CaptureOnMainThread(); BridgeError val2 = ValidateQuarantineReconciliationCommit(session, payload, request); if (val2 != null) { return GameCallResult.Failed(val2); } string rejection = "The retained quarantine action is unavailable."; IReadOnlyList resolvedEntityIds = Array.Empty(); string proofHash = string.Empty; if (!_actions.TryGetValue(payload.ReconcileActionId, out ActionRecord value) || !TryProveQuarantinedBuild(value, out resolvedEntityIds, out proofHash, out rejection) || !string.Equals(proofHash, payload.ExpectedStateHash, StringComparison.Ordinal) || !resolvedEntityIds.SequenceEqual(payload.ReconcileEntityIds)) { return GameCallResult.Failed(BridgeError.Create("STALE_STATE", "The exact quarantine proof changed after prepare: " + rejection, true, "Read the quarantined action and prepare a fresh reconciliation proof.")); } NormalActionCommitResult val3 = new NormalActionCommitResult { ActionId = value.ActionId, ActionKind = "reconcile-quarantine", IdempotencyKey = request.IdempotencyKey, State = "completed", Accepted = true, IdempotentReplay = false }; _plans.Remove(request.PlanToken); if (!_sessions.TryClearQuarantineOnMainThread(payload.ReconcileActionId, payload.ReconcileReason, out string rejection2)) { return GameCallResult.Failed(BridgeError.Create("STALE_STATE", rejection2 ?? "The exact quarantine identity changed before it could be cleared.", false, "Read current session state; do not retry the old action with a new idempotency key.")); } if (!_idempotency.TryAdd(request.SessionId, request.IdempotencyKey, text, val3)) { _sessions.QuarantineWritesOnMainThread(value.ActionId, "Quarantine reconciliation changed write health but its idempotent result could not be retained."); return GameCallResult.Failed(BridgeError.Create("ACTION_OUTCOME_UNKNOWN", "Quarantine reconciliation completed its state transition but its idempotent result could not be retained.", false, "Do not retry with a new key; inspect session write health and the exact action result.")); } value.State = "completed"; value.Succeeded = true; value.TargetObjectIds = resolvedEntityIds.ToList(); value.TargetObjectId = ((resolvedEntityIds.Count == 1) ? new int?(resolvedEntityIds[0]) : ((int?)null)); value.ReconciledFromOutcomeUnknown = true; value.ReconciledAtGameTick = GameMain.gameTick; value.Message = "The prior outcome-unknown build was reconciled from exact cost, entity, component, and directed-topology proof. Original quarantine: " + value.OriginalOutcomeMessage; value.AfterStateHash = CaptureStructuredAfterStateHash(value); return GameCallResult.Succeeded(val3); } private BridgeError? ValidateQuarantineReconciliationCommit(SessionState session, NormalActionPlanPayload plan, CommitNormalActionRequest request) { if (!session.OwnedBySpherewright || !string.Equals(session.SessionId, plan.SessionId, StringComparison.Ordinal) || !string.Equals(request.SessionId, plan.SessionId, StringComparison.Ordinal)) { return BridgeError.Create("STALE_SESSION", "The reconciliation plan does not belong to the current owned session.", false, "Inspect the current owned session and its quarantine action again."); } if (request.PlanetId != plan.PlanetId || session.LocalPlanetId != plan.PlanetId) { return Stale("Commit planet, planned planet, and current local planet do not match."); } if (session.Revision != plan.ReconcileExpectedRevision || !string.Equals(session.WriteHealth, "quarantined", StringComparison.Ordinal) || !string.Equals(session.WriteQuarantineActionId, plan.ReconcileActionId, StringComparison.Ordinal) || !string.Equals(_sessions.WriteQuarantineReason, plan.ReconcileReason, StringComparison.Ordinal)) { return Stale("The exact quarantined action, reason, or session revision changed after prepare."); } WriteBlocker val = ((IEnumerable)session.WriteBlockers).FirstOrDefault((Func)((WriteBlocker blocker) => !string.Equals(blocker.Code, "WRITE_SUBSYSTEM_QUARANTINED", StringComparison.Ordinal))); if (val != null) { return BridgeError.Create(val.Code, val.Message, false, "Resolve every non-quarantine write blocker before reconciling this action."); } return null; } private bool TryProveQuarantinedBuild(ActionRecord action, out IReadOnlyList resolvedEntityIds, out string proofHash, out string rejection) { resolvedEntityIds = Array.Empty(); proofHash = string.Empty; rejection = string.Empty; if (!string.Equals(action.ActionKind, "build", StringComparison.Ordinal) || action.AfterInventory == null || action.Plan.BuildSteps.Count == 0 || action.ExpectedBuildEntities.Count != action.Plan.BuildSteps.Count) { rejection = "The retained action lacks a complete build plan or quarantine-time inventory snapshot."; return false; } int num = -action.Plan.BuildSteps.Count; int num2 = GetCount(action.AfterInventory, action.Plan.BuildingItemId) - GetCount(action.BeforeInventory, action.Plan.BuildingItemId); if (num2 != num) { rejection = $"The retained building-item delta is {num2}, not {num}."; return false; } PlanetFactory factory = GameMain.localPlanet?.factory; if (factory == null) { rejection = "The current local factory is unavailable."; return false; } if (action.PrebuildIds.Any((int prebuildId) => prebuildId > 0 && prebuildId < factory.prebuildCursor && prebuildId < factory.prebuildPool.Length && factory.prebuildPool[prebuildId].id == prebuildId && !factory.prebuildPool[prebuildId].isDestroyed)) { rejection = "At least one accepted ordinary prebuild is still alive."; return false; } List resolved; if (string.Equals(action.Plan.BuildKind, "belt", StringComparison.Ordinal)) { if (!TryResolveUniqueBeltPath(factory, action, out resolved)) { rejection = "No unique directed belt path matches every retained step and endpoint."; return false; } } else { resolved = new List(); foreach (BuildExpectedEntity expectedBuildEntity in action.ExpectedBuildEntities) { List list = FindTopologyMatchingCandidates(factory, action, expectedBuildEntity, resolved); if (list.Count != 1) { rejection = $"Build step at the retained pose has {list.Count} topology-matching candidates, not exactly one."; return false; } resolved.Add(list[0]); } } if (!VerifyBuiltTopology(factory, action.Plan, resolved, out rejection)) { return false; } List list2 = new List { action.SessionId, action.PlanetId, action.ActionId, action.BeforeStateHash, action.OriginalOutcomeMessage ?? action.Message, action.Plan.BuildKind, action.Plan.BuildingItemId, action.Plan.BuildSteps.Count, num2 }; list2.AddRange(resolved.Cast()); proofHash = CanonicalStateHash.Combine("quarantine-build-reconciliation", list2.ToArray()); resolvedEntityIds = resolved; return true; } private static bool TryResolveUniqueBeltPath(PlanetFactory factory, ActionRecord action, out List resolved) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) List> list = new List>(); bool flag = default(bool); int num2 = default(int); int num3 = default(int); bool flag2 = default(bool); int num4 = default(int); foreach (BuildExpectedEntity expectedBuildEntity in action.ExpectedBuildEntities) { List list2 = new List(); int num = Math.Min(factory.entityCursor, factory.entityPool.Length); for (int i = 1; i < num; i++) { ref EntityData reference = ref factory.entityPool[i]; Vector3 val = reference.pos - expectedBuildEntity.Position; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (reference.id == i && reference.protoId == expectedBuildEntity.ItemId && !(sqrMagnitude >= 0.09f)) { factory.ReadObjectConn(i, 1, ref flag, ref num2, ref num3); factory.ReadObjectConn(i, 0, ref flag2, ref num4, ref num3); list2.Add(new DirectedBuildEntityCandidate(i, (!flag) ? num2 : 0, flag2 ? num4 : 0, sqrMagnitude)); } } list.Add(list2); } IReadOnlyList source = default(IReadOnlyList); bool flag3 = BuildEntityAttribution.TrySelectUniqueDirectedPath((IReadOnlyList>)list, (IReadOnlyCollection)action.PreexistingBuildEntityIds, action.Plan.SourceObjectId, action.Plan.DestinationObjectId, 0.09f, ref source); resolved = (flag3 ? source.ToList() : new List()); return flag3; } private static List FindTopologyMatchingCandidates(PlanetFactory factory, ActionRecord action, BuildExpectedEntity expected, IReadOnlyCollection alreadyResolved) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) List list = new List(); int num = Math.Min(factory.entityCursor, factory.entityPool.Length); for (int i = 1; i < num; i++) { ref EntityData reference = ref factory.entityPool[i]; if (reference.id != i || reference.protoId != expected.ItemId) { continue; } Vector3 val = reference.pos - expected.Position; if (((Vector3)(ref val)).sqrMagnitude >= 0.09f || action.PreexistingBuildEntityIds.Contains(i) || alreadyResolved.Contains(i)) { continue; } if (string.Equals(action.Plan.BuildKind, "inserter", StringComparison.Ordinal)) { if (reference.inserterId <= 0 || reference.inserterId >= factory.factorySystem.inserterCursor || reference.inserterId >= factory.factorySystem.inserterPool.Length) { continue; } ref InserterComponent reference2 = ref factory.factorySystem.inserterPool[reference.inserterId]; if (reference2.id != reference.inserterId || reference2.entityId != i || reference2.pickTarget != action.Plan.SourceObjectId || reference2.insertTarget != action.Plan.DestinationObjectId) { continue; } } list.Add(i); } return list; } private GameCallResult PrepareStructuredBuildOnMainThread(string? requestedSessionId, PrepareBuildRequest request) { //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Expected O, but got Unknown //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Invalid comparison between Unknown and I4 //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Invalid comparison between Unknown and I4 //IL_0430: Unknown result type (might be due to invalid IL or missing references) //IL_04c2: Unknown result type (might be due to invalid IL or missing references) //IL_04c7: Unknown result type (might be due to invalid IL or missing references) //IL_04d3: Unknown result type (might be due to invalid IL or missing references) //IL_04e8: Unknown result type (might be due to invalid IL or missing references) //IL_04fa: Unknown result type (might be due to invalid IL or missing references) //IL_050a: Expected O, but got Unknown CommonPrepareResult commonPrepareResult = ValidatePrepareCommon(requestedSessionId, request.PlanetId, request.StateHashVersion); if (commonPrepareResult.Error != null) { return GameCallResult.Failed(commonPrepareResult.Error); } if (request.PreferredDistance < 5f || request.PreferredDistance > 30f) { return InvalidPlan("Preferred build distance must be from 5 through 30 metres."); } if (request.PathLength < 1.5f || request.PathLength > 30f) { return InvalidPlan("A belt path length must be from 1.5 through 30 metres."); } ItemProto val = ((ProtoSet)(object)LDB.items).Select(request.BuildingItemId); if (val?.prefabDesc == null || !val.CanBuild) { return InvalidPlan("The requested runtime item is not a placeable building."); } Player mainPlayer = GameMain.mainPlayer; PlanetFactory val2 = GameMain.localPlanet?.factory; if (((mainPlayer != null) ? mainPlayer.package : null) == null || val2 == null || mainPlayer.controller?.actionBuild == null) { return NotReadyPlan("The local player build system or factory is not ready."); } if (!GameMain.history.ItemUnlocked(((Proto)val).ID)) { return GameCallResult.Failed(BridgeError.Create("ACTION_REJECTED", "The requested building item is not unlocked in the current ordinary world.", false, "Complete the normal prerequisite technology before preparing construction.")); } GameCallResult playerStateOnMainThread = _reader.GetPlayerStateOnMainThread(requestedSessionId, new LocalPlanetRequest { PlanetId = request.PlanetId }); if (!playerStateOnMainThread.Success || playerStateOnMainThread.Value == null) { return GameCallResult.Failed(playerStateOnMainThread.Error); } if (!string.Equals(request.ExpectedPlayerStateHash, playerStateOnMainThread.Value.StateHash, StringComparison.Ordinal)) { return StalePlan("Player inventory, construction queue, or position changed after inspection."); } BuildPreparation buildPreparation = (val.prefabDesc.isBelt ? TryPrepareBeltBuild(val2, mainPlayer, val, request) : (val.prefabDesc.isInserter ? TryPrepareInserterBuild(val2, mainPlayer, val, request) : ((!val.prefabDesc.veinMiner && !val.prefabDesc.oilMiner && (int)val.prefabDesc.minerType != 2 && (int)val.prefabDesc.minerType != 3) ? TryPrepareCoreBuild(val2, mainPlayer, val, request) : TryPrepareResourceBuild(val2, mainPlayer, val, request, requestedSessionId)))); if (!buildPreparation.Success) { return GameCallResult.Failed(BridgeError.Create(buildPreparation.ErrorCode, buildPreparation.Rejection, true, "Inspect the bound state, move into construction range or choose another candidate, then prepare again.")); } if (buildPreparation.Steps.Count == 0) { return InvalidPlan("DSP did not produce any validated construction step."); } if (mainPlayer.package.GetItemCount(((Proto)val).ID) < buildPreparation.Steps.Count) { return GameCallResult.Failed(BridgeError.Create("ACTION_REJECTED", $"The validated construction requires {buildPreparation.Steps.Count} {((Proto)val).name}, but the player owns fewer.", true, "Handcraft the exact missing building count through normal gameplay and prepare again.")); } string text = CanonicalStateHash.PlayerAction(playerStateOnMainThread.Value); string text2 = BuildPlanFingerprint(buildPreparation); string expectedStateHash = CanonicalStateHash.Combine("build", new object[9] { _sessions.SessionId, request.PlanetId, text, ((Proto)val).ID, buildPreparation.Kind, buildPreparation.ResourceStateHash, buildPreparation.SourceEndpointHash, buildPreparation.DestinationEndpointHash, text2 }); NormalActionPlanPayload payload = NormalActionPlanPayload.StructuredBuild(_sessions.SessionId, request.PlanetId, expectedStateHash, text, ((Proto)val).ID, buildPreparation); GameCallResult gameCallResult = AddPreparedPlan(payload, commonPrepareResult.Session, Math.Max(3600L, (long)buildPreparation.Steps.Count * 900L), $"DSP creates {buildPreparation.Steps.Count} ordinary {buildPreparation.Kind} prebuild(s), consumes exactly that many owned items, and construction drones replace every prebuild with a reread matching entity."); if (gameCallResult.Success && gameCallResult.Value != null) { gameCallResult.Value.BuildKind = buildPreparation.Kind; gameCallResult.Value.SourceObjectId = ((buildPreparation.SourceObjectId > 0) ? new int?(buildPreparation.SourceObjectId) : ((int?)null)); gameCallResult.Value.DestinationObjectId = ((buildPreparation.DestinationObjectId > 0) ? new int?(buildPreparation.DestinationObjectId) : ((int?)null)); gameCallResult.Value.PlannedPosition = Snapshot(buildPreparation.Steps[0].Position); gameCallResult.Value.PlannedYaw = buildPreparation.Steps[0].Yaw; gameCallResult.Value.PlannedPath = buildPreparation.Steps.Select((BuildStepPlan step) => Snapshot(step.Position)).ToList(); gameCallResult.Value.PlannedResourceNodeIds = buildPreparation.ResourceNodeIds.ToList(); gameCallResult.Value.ItemBudget.Add(new ActionItemBudget { ItemId = ((Proto)val).ID, Name = (((Proto)val).name ?? string.Empty), Count = buildPreparation.Steps.Count, Direction = "construction-consumption" }); } return gameCallResult; } private BuildPreparation TryPrepareCoreBuild(PlanetFactory factory, Player player, ItemProto item, PrepareBuildRequest request) { //IL_0065: 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_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: 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_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) if (request.ResourceNodeId.HasValue || request.SourceObjectId.HasValue || request.DestinationObjectId.HasValue || request.PathEnd != null) { return BuildPreparation.Failed("INVALID_REQUEST", "A core building request cannot bind resource, connection, or belt-path targets."); } List list = new List(); if (request.PreferredPosition != null) { Vector3 val = ToVector(request.PreferredPosition); if (!IsFinite(val.x) || !IsFinite(val.y) || !IsFinite(val.z) || ((Vector3)(ref val)).sqrMagnitude < 1f) { return BuildPreparation.Failed("INVALID_REQUEST", "Preferred building coordinates are invalid."); } Vector3 val2 = factory.planet.aux.Snap(val, true); float num = Mathf.Repeat(request.PreferredYaw.GetValueOrDefault(), 360f); list.Add(BuildStepPlan.Core(((Proto)item).ID, val2, Maths.SphericalRotation(val2, num), num)); } else { float[] array = new float[3] { request.PreferredDistance, Math.Min(30f, request.PreferredDistance + 5f), Math.Max(5f, request.PreferredDistance - 4f) }.Distinct().ToArray(); float[] array2 = new float[7] { 0f, 5f, -5f, 10f, -10f, 15f, -15f }; for (float num2 = 0f; num2 < 360f; num2 += 30f) { Quaternion val3 = Maths.SphericalRotation(player.position, num2); float[] array3 = array; foreach (float num3 in array3) { float[] array4 = array2; foreach (float num4 in array4) { Vector3 val4 = factory.planet.aux.Snap(player.position + val3 * Vector3.forward * num3 + val3 * Vector3.right * num4, true); list.Add(BuildStepPlan.Core(((Proto)item).ID, val4, Maths.SphericalRotation(val4, num2), num2)); } } } } string rejection = "No core-building candidate was accepted."; foreach (BuildStepPlan item2 in list) { if (TryValidateClickBuild(factory, player, item, item2, 0, out BuildStepPlan accepted, out rejection)) { return BuildPreparation.Succeeded("core", new BuildStepPlan[1] { accepted }); } } return BuildPreparation.Failed("BUILD_LOCATION_INVALID", rejection); } private BuildPreparation TryPrepareResourceBuild(PlanetFactory factory, Player player, ItemProto item, PrepareBuildRequest request, string requestedSessionId) { //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: 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_00c6: Expected O, but got Unknown //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Invalid comparison between Unknown and I4 //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_0226: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Unknown result type (might be due to invalid IL or missing references) //IL_029a: Unknown result type (might be due to invalid IL or missing references) //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_02bd: Unknown result type (might be due to invalid IL or missing references) //IL_02c2: Unknown result type (might be due to invalid IL or missing references) //IL_02c4: Unknown result type (might be due to invalid IL or missing references) //IL_02c9: Unknown result type (might be due to invalid IL or missing references) //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_02d5: Unknown result type (might be due to invalid IL or missing references) //IL_02db: Unknown result type (might be due to invalid IL or missing references) //IL_02e0: Unknown result type (might be due to invalid IL or missing references) //IL_02ea: Unknown result type (might be due to invalid IL or missing references) //IL_02ec: Unknown result type (might be due to invalid IL or missing references) //IL_02f0: Unknown result type (might be due to invalid IL or missing references) if (!request.ResourceNodeId.HasValue || request.ResourceNodeId.Value <= 0 || string.IsNullOrWhiteSpace(request.ExpectedResourceStateHash)) { return BuildPreparation.Failed("INVALID_REQUEST", "A vein miner or oil extractor requires one inspected vein node and its exact state hash."); } if (request.SourceObjectId.HasValue || request.DestinationObjectId.HasValue || request.PathEnd != null) { return BuildPreparation.Failed("INVALID_REQUEST", "A resource-building request cannot also be a connection or belt-path request."); } GameCallResult gameCallResult = _reader.InspectResourceNodeOnMainThread(requestedSessionId, new InspectResourceNodeRequest { PlanetId = request.PlanetId, Kind = "vein", NodeId = request.ResourceNodeId.Value }); if (!gameCallResult.Success || gameCallResult.Value == null) { BridgeError? error = gameCallResult.Error; string code = ((error != null) ? error.Code : null) ?? "INVALID_RESOURCE_TARGET"; BridgeError? error2 = gameCallResult.Error; return BuildPreparation.Failed(code, ((error2 != null) ? error2.Message : null) ?? "The bound vein no longer exists."); } ResourceNodeSnapshot value = gameCallResult.Value; if (!string.Equals(value.StateHash, request.ExpectedResourceStateHash, StringComparison.Ordinal)) { return BuildPreparation.Failed("STALE_STATE", "The bound vein amount, identity, group, or miner count changed after inspection."); } bool flag = string.Equals(value.ResourceType, ((object)(EVeinType)7/*cast due to .constrained prefix*/).ToString(), StringComparison.OrdinalIgnoreCase); if ((item.prefabDesc.oilMiner || (int)item.prefabDesc.minerType == 3) != flag) { return BuildPreparation.Failed("INVALID_RESOURCE_TARGET", flag ? "The selected building is not an oil extractor." : "An oil extractor cannot target a solid mineral vein."); } Vector3 target = ToVector(value.Position); List list = new List(); if (request.PreferredPosition != null) { Vector3 val = factory.planet.aux.Snap(ToVector(request.PreferredPosition), true); float num = Mathf.Repeat(request.PreferredYaw.GetValueOrDefault(), 360f); list.Add(BuildStepPlan.Core(((Proto)item).ID, val, Maths.SphericalRotation(val, num), num)); } else if (flag) { Vector3 val2 = factory.planet.aux.Snap(target, true); for (float num2 = 0f; num2 < 360f; num2 += 30f) { list.Add(BuildStepPlan.Core(((Proto)item).ID, val2, Maths.SphericalRotation(val2, num2), num2)); } } else { float[] array = new float[5] { 3.5f, 4.5f, 5.5f, 6.5f, 7.25f }; for (float num3 = 0f; num3 < 360f; num3 += 15f) { Quaternion val3 = Maths.SphericalRotation(target, num3); float[] array2 = array; foreach (float num4 in array2) { Vector3 val4 = factory.planet.aux.Snap(target + val3 * Vector3.forward * num4, true); list.Add(BuildStepPlan.Core(((Proto)item).ID, val4, Maths.SphericalRotation(val4, num3), num3)); } } } string rejection = "No resource-building candidate was accepted."; List list2 = new List(); foreach (BuildStepPlan item2 in list) { if (TryValidateClickBuild(factory, player, item, item2, value.NodeId, out BuildStepPlan accepted, out rejection)) { list2.Add(accepted); } } if (list2.Count > 0) { int index = ResourceCoverageSelection.SelectBestIndex((IReadOnlyList)((IEnumerable)list2).Select((Func)((BuildStepPlan candidate, int index2) => new ResourceCoverageCandidateScore { Index = index2, CoveredNodeCount = candidate.Parameters.Where((int nodeId) => nodeId > 0).Distinct().Count(), DistanceToBoundNode = Vector3.Distance(candidate.Position, target), Yaw = candidate.Yaw })).ToArray()); BuildStepPlan buildStepPlan = list2[index]; BuildPreparation buildPreparation = BuildPreparation.Succeeded("resource", new BuildStepPlan[1] { buildStepPlan }); buildPreparation.ResourceNodeId = value.NodeId; buildPreparation.ResourceStateHash = value.StateHash; buildPreparation.ResourceNodeIds.AddRange(from nodeId in buildStepPlan.Parameters.Where((int nodeId) => nodeId > 0).Distinct() orderby nodeId select nodeId); return buildPreparation; } return BuildPreparation.Failed("BUILD_LOCATION_INVALID", rejection); } private BuildPreparation TryPrepareInserterBuild(PlanetFactory factory, Player player, ItemProto item, PrepareBuildRequest request) { //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) if (!request.SourceObjectId.HasValue || request.SourceObjectId.Value <= 0 || !request.DestinationObjectId.HasValue || request.DestinationObjectId.Value <= 0 || string.IsNullOrWhiteSpace(request.ExpectedSourceStateHash) || string.IsNullOrWhiteSpace(request.ExpectedDestinationStateHash)) { return BuildPreparation.Failed("INVALID_REQUEST", "An inserter requires exact inspected source and destination entities plus both state hashes."); } if (request.SourceObjectId == request.DestinationObjectId) { return BuildPreparation.Failed("BUILD_CONNECTION_INVALID", "An inserter cannot connect an entity to itself."); } string error = null; string error2 = null; if (!TryReadBuildEndpoint(request, request.SourceObjectId.Value, request.ExpectedSourceStateHash, out FactoryEntitySnapshot snapshot, out error) || !TryReadBuildEndpoint(request, request.DestinationObjectId.Value, request.ExpectedDestinationStateHash, out FactoryEntitySnapshot snapshot2, out error2)) { return BuildPreparation.Failed("STALE_STATE", error ?? error2 ?? "A bound inserter endpoint changed after inspection."); } List inserterEndpointPoints = GetInserterEndpointPoints(factory, snapshot); List inserterEndpointPoints2 = GetInserterEndpointPoints(factory, snapshot2); if (inserterEndpointPoints.Count == 0 || inserterEndpointPoints2.Count == 0) { return BuildPreparation.Failed("BUILD_CONNECTION_INVALID", "One bound endpoint exposes no current-version inserter slot or belt attachment pose."); } string rejection = "DSP rejected every bounded inserter endpoint pair."; foreach (EndpointPoint item2 in inserterEndpointPoints) { foreach (EndpointPoint item3 in inserterEndpointPoints2) { BuildStepPlan candidate = BuildStepPlan.Inserter(((Proto)item).ID, item2.Pose, item3.Pose, item2.ObjectId, item2.Slot, item3.ObjectId, item3.Slot); if (TryValidateInserterBuild(factory, player, item, candidate, out BuildStepPlan accepted, out rejection)) { BuildPreparation buildPreparation = BuildPreparation.Succeeded("inserter", new BuildStepPlan[1] { accepted }); buildPreparation.SourceObjectId = snapshot.ObjectId; buildPreparation.DestinationObjectId = snapshot2.ObjectId; buildPreparation.SourceEndpointHash = BuildEndpointHash(snapshot); buildPreparation.DestinationEndpointHash = BuildEndpointHash(snapshot2); return buildPreparation; } } } return BuildPreparation.Failed("BUILD_CONNECTION_INVALID", rejection); } private BuildPreparation TryPrepareBeltBuild(PlanetFactory factory, Player player, ItemProto item, PrepareBuildRequest request) { //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_0243: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_027c: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Unknown result type (might be due to invalid IL or missing references) //IL_0295: Unknown result type (might be due to invalid IL or missing references) //IL_029c: Unknown result type (might be due to invalid IL or missing references) //IL_02a8: Unknown result type (might be due to invalid IL or missing references) //IL_02ad: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Unknown result type (might be due to invalid IL or missing references) //IL_02be: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_02c7: Unknown result type (might be due to invalid IL or missing references) //IL_02cc: Unknown result type (might be due to invalid IL or missing references) FactoryEntitySnapshot snapshot = null; FactoryEntitySnapshot snapshot2 = null; if (request.SourceObjectId.HasValue) { string error = null; if (request.SourceObjectId.Value <= 0 || string.IsNullOrWhiteSpace(request.ExpectedSourceStateHash) || !TryReadBuildEndpoint(request, request.SourceObjectId.Value, request.ExpectedSourceStateHash, out snapshot, out error)) { return BuildPreparation.Failed("STALE_STATE", error ?? "The bound belt source is invalid or changed after inspection."); } } if (request.DestinationObjectId.HasValue) { string error2 = null; if (request.DestinationObjectId.Value <= 0 || string.IsNullOrWhiteSpace(request.ExpectedDestinationStateHash) || !TryReadBuildEndpoint(request, request.DestinationObjectId.Value, request.ExpectedDestinationStateHash, out snapshot2, out error2)) { return BuildPreparation.Failed("STALE_STATE", error2 ?? "The bound belt destination is invalid or changed after inspection."); } } List list = ((snapshot == null) ? new List { new EndpointPoint(0, -1, ResolveFreeBeltStart(factory, player, request)) } : GetFreePortPoints(factory, snapshot, requireOutput: true)); List list2 = ((snapshot2 == null) ? new List() : GetFreePortPoints(factory, snapshot2, requireOutput: false)); if (list.Count == 0 || (snapshot2 != null && list2.Count == 0)) { return BuildPreparation.Failed("BUILD_CONNECTION_INVALID", "The bound source or destination exposes no free current-version belt port."); } string rejection = "DSP rejected every bounded belt path candidate."; foreach (EndpointPoint item2 in list) { List list3 = new List(); if (snapshot2 != null) { list3.AddRange(list2); } else if (request.PathEnd != null) { Vector3 val = factory.planet.aux.Snap(ToVector(request.PathEnd), true); list3.Add(new EndpointPoint(0, -1, new Pose(val, Maths.SphericalRotation(val, 0f)))); } else { Vector3 val2 = ProjectTangent(item2.Pose.rotation * Vector3.forward, item2.Pose.position); Vector3 val3 = ProjectTangent(item2.Pose.rotation * Vector3.right, item2.Pose.position); foreach (Vector3 item3 in ((IEnumerable)(object)new Vector3[4] { val2, -val2, val3, -val3 }).Where((Vector3 direction) => ((Vector3)(ref direction)).sqrMagnitude > 0.5f)) { Vector3 current2 = item3; Vector3 val4 = factory.planet.aux.Snap(item2.Pose.position + ((Vector3)(ref current2)).normalized * request.PathLength, true); list3.Add(new EndpointPoint(0, -1, new Pose(val4, Maths.SphericalRotation(val4, 0f)))); } } foreach (EndpointPoint item4 in list3) { if (TryCreateBeltSteps(factory, item, item2, item4, out List steps, out rejection) && TryValidateBeltBuild(factory, player, item, steps, out List accepted, out rejection)) { BuildPreparation buildPreparation = BuildPreparation.Succeeded("belt", accepted); if (snapshot != null) { buildPreparation.SourceObjectId = snapshot.ObjectId; buildPreparation.SourceEndpointHash = BuildEndpointHash(snapshot); } if (snapshot2 != null) { buildPreparation.DestinationObjectId = snapshot2.ObjectId; buildPreparation.DestinationEndpointHash = BuildEndpointHash(snapshot2); } return buildPreparation; } } } return BuildPreparation.Failed("BUILD_LOCATION_INVALID", rejection); } private bool TryReadBuildEndpoint(PrepareBuildRequest request, int objectId, string expectedStateHash, out FactoryEntitySnapshot? snapshot, out string? error) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown GameCallResult gameCallResult = _reader.InspectFactoryEntityOnMainThread(_sessions.SessionId, new InspectFactoryEntityRequest { PlanetId = request.PlanetId, ObjectId = objectId }); snapshot = gameCallResult.Value; BridgeError? error2 = gameCallResult.Error; error = ((error2 != null) ? error2.Message : null); if (!gameCallResult.Success || snapshot == null || snapshot.ObjectKind != "entity") { return false; } if (!string.Equals(snapshot.EndpointStateHash, expectedStateHash, StringComparison.Ordinal) && !string.Equals(snapshot.StateHash, expectedStateHash, StringComparison.Ordinal)) { error = $"Bound endpoint {objectId} identity, pose, or connections changed after inspection."; return false; } return true; } private static Pose ResolveFreeBeltStart(PlanetFactory factory, Player player, PrepareBuildRequest request) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: 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_008c: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) if (request.PreferredPosition != null) { Vector3 val = factory.planet.aux.Snap(ToVector(request.PreferredPosition), true); return new Pose(val, Maths.SphericalRotation(val, request.PreferredYaw.GetValueOrDefault())); } float valueOrDefault = request.PreferredYaw.GetValueOrDefault(); Quaternion val2 = Maths.SphericalRotation(player.position, valueOrDefault); Vector3 val3 = factory.planet.aux.Snap(player.position + val2 * Vector3.forward * request.PreferredDistance, true); return new Pose(val3, Maths.SphericalRotation(val3, valueOrDefault)); } private static bool TryCreateBeltSteps(PlanetFactory factory, ItemProto item, EndpointPoint source, EndpointPoint destination, out List steps, out string rejection) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0082: 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_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) steps = new List(); rejection = string.Empty; Vector3[] array = (Vector3[])(object)new Vector3[256]; float num = 0f; int num2 = factory.planet.aux.SnapLineNonAlloc(source.Pose.position, destination.Pose.position, 1, false, source.ObjectId == 0, array, false, ref num, false); if (num2 < 2) { rejection = "DSP's terrain grid did not return a belt path with at least two segments."; return false; } array[0] = source.Pose.position; array[num2 - 1] = destination.Pose.position; for (int i = 0; i < num2; i++) { BuildStepPlan buildStepPlan = BuildStepPlan.Belt(((Proto)item).ID, array[i]); buildStepPlan.InputStepIndex = ((i > 0) ? (i - 1) : (-1)); buildStepPlan.OutputStepIndex = ((i + 1 < num2) ? (i + 1) : (-1)); if (i == 0 && source.ObjectId > 0) { buildStepPlan.InputObjectId = source.ObjectId; buildStepPlan.InputFromSlot = source.Slot; buildStepPlan.InputToSlot = 1; } if (i == num2 - 1 && destination.ObjectId > 0) { buildStepPlan.OutputObjectId = destination.ObjectId; buildStepPlan.OutputFromSlot = 0; buildStepPlan.OutputToSlot = destination.Slot; } steps.Add(buildStepPlan); } return true; } private static bool TryValidateClickBuild(PlanetFactory factory, Player player, ItemProto item, BuildStepPlan candidate, int requiredResourceNodeId, out BuildStepPlan accepted, out string rejection) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) accepted = candidate; rejection = string.Empty; if (!BuildUiIsIdle(player)) { rejection = "The player's normal build UI owns preview state."; return false; } if (OverlapsExistingFactoryObject(factory, item.prefabDesc, candidate.Position, candidate.Rotation, out var occupiedObjectId)) { rejection = $"The exact build-collider volume overlaps existing factory object {occupiedObjectId}."; return false; } SpherewrightClickBuildTool spherewrightClickBuildTool = new SpherewrightClickBuildTool(); ((BuildTool)spherewrightClickBuildTool)._Init(GameMain.data); ((BuildTool)spherewrightClickBuildTool).SetFactoryReferences(); try { if (((BuildTool)spherewrightClickBuildTool).factory != factory) { rejection = "The isolated click-build validator is not bound to the local factory."; return false; } ((BuildTool_Click)spherewrightClickBuildTool).handItem = item; ((BuildTool_Click)spherewrightClickBuildTool).handPrefabDesc = item.prefabDesc; ((BuildTool_Click)spherewrightClickBuildTool).yaw = candidate.Yaw; spherewrightClickBuildTool.SnapshotPlayerInventory(); BuildPreview val = CreatePreview(candidate, item); val.parameters = null; val.paramCount = 0; ((BuildTool)spherewrightClickBuildTool).buildPreviews.Add(val); if (!((BuildTool_Click)spherewrightClickBuildTool).CheckBuildConditions() || (int)val.condition != 0 || val.coverObjId != 0) { rejection = $"DSP click-build validation returned {val.condition}."; return false; } if (requiredResourceNodeId > 0 && (val.parameters == null || !val.parameters.Take(val.paramCount).Contains(requiredResourceNodeId))) { rejection = "DSP accepted the position but did not bind the requested exact resource node."; return false; } accepted = BuildStepPlan.FromPreview(candidate, val); return true; } finally { ((BuildTool)spherewrightClickBuildTool).buildPreviews.Clear(); spherewrightClickBuildTool.ReleaseSnapshot(); ((BuildTool)spherewrightClickBuildTool)._Free(); } } private static bool OverlapsExistingFactoryObject(PlanetFactory factory, PrefabDesc candidateDescription, Vector3 candidatePosition, Quaternion candidateRotation, out int occupiedObjectId) { //IL_0005: 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_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) occupiedObjectId = 0; List list = CreateWorldBuildColliders(candidateDescription, candidatePosition, candidateRotation); if (list.Count == 0) { return false; } int num = Math.Min(factory.entityCursor, factory.entityPool.Length); for (int i = 1; i < num; i++) { ref EntityData reference = ref factory.entityPool[i]; if (reference.id == i && reference.protoId > 0) { PrefabDesc val = ((ProtoSet)(object)LDB.items).Select((int)reference.protoId)?.prefabDesc; if (val != null && BuildColliderSetsOverlap(list, CreateWorldBuildColliders(val, reference.pos, reference.rot))) { occupiedObjectId = i; return true; } } } int num2 = Math.Min(factory.prebuildCursor, factory.prebuildPool.Length); for (int j = 1; j < num2; j++) { ref PrebuildData reference2 = ref factory.prebuildPool[j]; if (reference2.id == j && !reference2.isDestroyed && reference2.protoId > 0) { PrefabDesc val2 = ((ProtoSet)(object)LDB.items).Select((int)reference2.protoId)?.prefabDesc; if (val2 != null && BuildColliderSetsOverlap(list, CreateWorldBuildColliders(val2, reference2.pos, reference2.rot))) { occupiedObjectId = -j; return true; } } } return false; } private static List CreateWorldBuildColliders(PrefabDesc description, Vector3 position, Quaternion rotation) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected I4, but got Unknown //IL_00d7: 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_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_0101: 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_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: 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_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_016b: 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_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) List list = new List(); ColliderData[] array = description.buildColliders; if (array == null || array.Length == 0) { if (!description.hasBuildCollider) { return list; } array = (ColliderData[])(object)new ColliderData[1] { description.buildCollider }; } ColliderData[] array2 = array; Vector3 val4 = default(Vector3); for (int i = 0; i < array2.Length; i++) { ColliderData val = array2[i]; Quaternion val2 = ((Quaternion.Dot(val.q, val.q) > 0.01f) ? val.q : Quaternion.identity); Quaternion val3 = rotation * val2; EColliderShape shape = ((ColliderData)(ref val)).shape; switch (shape - 1) { case 2: ((Vector3)(ref val4))..ctor(Math.Abs(val.ext.x), Math.Abs(val.ext.y), Math.Abs(val.ext.z)); break; case 0: val4 = Vector3.one * Math.Abs(val.radius); break; case 1: { float num = Math.Abs(val.radius); ((Vector3)(ref val4))..ctor(Math.Abs(val.ext.x) + num, Math.Abs(val.ext.y) + num, Math.Abs(val.ext.z) + num); break; } default: continue; } if (!(((Vector3)(ref val4)).sqrMagnitude < 0.0001f)) { Vector3 center = position + rotation * val.pos; Vector3 val5 = val3 * Vector3.right; Vector3 normalized = ((Vector3)(ref val5)).normalized; val5 = val3 * Vector3.up; Vector3 normalized2 = ((Vector3)(ref val5)).normalized; val5 = val3 * Vector3.forward; list.Add(new WorldBuildCollider(center, normalized, normalized2, ((Vector3)(ref val5)).normalized, val4 + Vector3.one * 0.01f)); } } return list; } private static bool BuildColliderSetsOverlap(IReadOnlyList left, IReadOnlyList right) { for (int i = 0; i < left.Count; i++) { for (int j = 0; j < right.Count; j++) { if (OrientedBoxesOverlap(left[i], right[j])) { return true; } } } return false; } private static bool OrientedBoxesOverlap(WorldBuildCollider left, WorldBuildCollider right) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) Vector3[] array = (Vector3[])(object)new Vector3[3] { left.AxisX, left.AxisY, left.AxisZ }; Vector3[] array2 = (Vector3[])(object)new Vector3[3] { right.AxisX, right.AxisY, right.AxisZ }; float[] array3 = new float[3] { left.Extents.x, left.Extents.y, left.Extents.z }; float[] array4 = new float[3] { right.Extents.x, right.Extents.y, right.Extents.z }; float[,] array5 = new float[3, 3]; float[,] array6 = new float[3, 3]; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { array5[i, j] = Vector3.Dot(array[i], array2[j]); array6[i, j] = Math.Abs(array5[i, j]) + 1E-05f; } } Vector3 val = right.Center - left.Center; float[] array7 = new float[3] { Vector3.Dot(val, array[0]), Vector3.Dot(val, array[1]), Vector3.Dot(val, array[2]) }; for (int k = 0; k < 3; k++) { float num = array4[0] * array6[k, 0] + array4[1] * array6[k, 1] + array4[2] * array6[k, 2]; if (Math.Abs(array7[k]) > array3[k] + num) { return false; } } for (int l = 0; l < 3; l++) { float num2 = array3[0] * array6[0, l] + array3[1] * array6[1, l] + array3[2] * array6[2, l]; if (Math.Abs(array7[0] * array5[0, l] + array7[1] * array5[1, l] + array7[2] * array5[2, l]) > num2 + array4[l]) { return false; } } for (int m = 0; m < 3; m++) { int num3 = (m + 1) % 3; int num4 = (m + 2) % 3; for (int n = 0; n < 3; n++) { int num5 = (n + 1) % 3; int num6 = (n + 2) % 3; float num7 = array3[num3] * array6[num4, n] + array3[num4] * array6[num3, n]; float num8 = array4[num5] * array6[m, num6] + array4[num6] * array6[m, num5]; if (Math.Abs(array7[num4] * array5[num3, n] - array7[num3] * array5[num4, n]) > num7 + num8) { return false; } } } return true; } private static bool TryValidateInserterBuild(PlanetFactory factory, Player player, ItemProto item, BuildStepPlan candidate, out BuildStepPlan accepted, out string rejection) { //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) accepted = candidate; rejection = string.Empty; if (!BuildUiIsIdle(player)) { rejection = "The player's normal build UI owns preview state."; return false; } SpherewrightInserterBuildTool spherewrightInserterBuildTool = new SpherewrightInserterBuildTool(); ((BuildTool)spherewrightInserterBuildTool)._Init(GameMain.data); ((BuildTool)spherewrightInserterBuildTool).SetFactoryReferences(); try { if (((BuildTool)spherewrightInserterBuildTool).factory != factory) { rejection = "The isolated inserter validator is not bound to the local factory."; return false; } ((BuildTool_Inserter)spherewrightInserterBuildTool).handItem = item; ((BuildTool_Inserter)spherewrightInserterBuildTool).handPrefabDesc = item.prefabDesc; ((BuildTool_Inserter)spherewrightInserterBuildTool).startObjectId = candidate.InputObjectId; ((BuildTool_Inserter)spherewrightInserterBuildTool).castObjectId = candidate.OutputObjectId; spherewrightInserterBuildTool.SnapshotPlayerInventory(); BuildPreview val = CreatePreview(candidate, item); ((BuildTool)spherewrightInserterBuildTool).buildPreviews.Add(val); if (!((BuildTool_Inserter)spherewrightInserterBuildTool).CheckBuildConditions() || (int)val.condition != 0 || val.coverObjId != 0) { rejection = $"DSP inserter validation returned {val.condition}."; return false; } accepted = BuildStepPlan.FromPreview(candidate, val); return true; } finally { ((BuildTool)spherewrightInserterBuildTool).buildPreviews.Clear(); spherewrightInserterBuildTool.ReleaseSnapshot(); ((BuildTool)spherewrightInserterBuildTool)._Free(); } } private static bool TryValidateBeltBuild(PlanetFactory factory, Player player, ItemProto item, IReadOnlyList candidates, out List accepted, out string rejection) { accepted = new List(); rejection = string.Empty; if (!BuildUiIsIdle(player)) { rejection = "The player's normal build UI owns preview state."; return false; } SpherewrightPathBuildTool spherewrightPathBuildTool = new SpherewrightPathBuildTool(); ((BuildTool)spherewrightPathBuildTool)._Init(GameMain.data); ((BuildTool)spherewrightPathBuildTool).SetFactoryReferences(); List list = CreateLinkedPreviews(candidates, item); try { if (((BuildTool)spherewrightPathBuildTool).factory != factory) { rejection = "The isolated path-build validator is not bound to the local factory."; return false; } ((BuildTool_Path)spherewrightPathBuildTool).handItem = item; ((BuildTool_Path)spherewrightPathBuildTool).handPrefabDesc = item.prefabDesc; ((BuildTool_Path)spherewrightPathBuildTool).startObjectId = candidates[0].InputObjectId; spherewrightPathBuildTool.SnapshotPlayerInventory(); ((BuildTool)spherewrightPathBuildTool).buildPreviews.AddRange(list); bool num = ((BuildTool_Path)spherewrightPathBuildTool).CheckBuildConditions(); BuildPreview val = ((IEnumerable)list).FirstOrDefault((Func)((BuildPreview preview) => (int)preview.condition != 0 || preview.coverObjId != 0)); if (!num || val != null) { rejection = "DSP belt-path validation returned " + (((object)Unsafe.As(ref val?.condition)/*cast due to .constrained prefix*/).ToString() ?? "rejected") + "."; return false; } for (int num2 = 0; num2 < list.Count; num2++) { accepted.Add(BuildStepPlan.FromPreview(candidates[num2], list[num2])); } return true; } finally { ((BuildTool)spherewrightPathBuildTool).buildPreviews.Clear(); spherewrightPathBuildTool.ReleaseSnapshot(); ((BuildTool)spherewrightPathBuildTool)._Free(); } } private BridgeError? RevalidateStructuredBuildOnMainThread(NormalActionPlanPayload plan) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Expected O, but got Unknown GameCallResult playerStateOnMainThread = _reader.GetPlayerStateOnMainThread(plan.SessionId, new LocalPlanetRequest { PlanetId = plan.PlanetId }); if (!playerStateOnMainThread.Success || playerStateOnMainThread.Value == null) { return playerStateOnMainThread.Error; } ItemProto val = ((ProtoSet)(object)LDB.items).Select(plan.BuildingItemId); PlanetFactory val2 = GameMain.localPlanet?.factory; Player mainPlayer = GameMain.mainPlayer; if (val?.prefabDesc == null || val2 == null || ((mainPlayer != null) ? mainPlayer.package : null) == null || !GameMain.history.ItemUnlocked(plan.BuildingItemId) || mainPlayer.package.GetItemCount(plan.BuildingItemId) < plan.BuildSteps.Count || !string.Equals(CanonicalStateHash.PlayerAction(playerStateOnMainThread.Value), plan.PlayerStateHash, StringComparison.Ordinal)) { return Stale("Building unlock, owned item count, player, or construction queue changed after prepare."); } if (plan.BuildResourceNodeId > 0) { GameCallResult gameCallResult = _reader.InspectResourceNodeOnMainThread(plan.SessionId, new InspectResourceNodeRequest { PlanetId = plan.PlanetId, Kind = "vein", NodeId = plan.BuildResourceNodeId }); if (!gameCallResult.Success || gameCallResult.Value == null || !string.Equals(gameCallResult.Value.StateHash, plan.BuildResourceStateHash, StringComparison.Ordinal)) { return Stale("The exact resource target changed after build preparation."); } } if (!RevalidateBuildEndpoint(plan, plan.SourceObjectId, plan.SourceFactoryStateHash) || !RevalidateBuildEndpoint(plan, plan.DestinationObjectId, plan.DestinationFactoryStateHash)) { return Stale("A bound build endpoint identity or connection changed after preparation."); } if (!((plan.BuildKind == "belt") ? (TryValidateBeltBuild(val2, mainPlayer, val, plan.BuildSteps, out List accepted, out string rejection) && BuildStepsEqual(plan.BuildSteps, accepted)) : ((!(plan.BuildKind == "inserter")) ? (TryValidateClickBuild(val2, mainPlayer, val, plan.BuildSteps[0], plan.BuildResourceNodeId, out BuildStepPlan accepted2, out rejection) && BuildStepsEqual(plan.BuildSteps, new BuildStepPlan[1] { accepted2 })) : (TryValidateInserterBuild(val2, mainPlayer, val, plan.BuildSteps[0], out BuildStepPlan accepted3, out rejection) && BuildStepsEqual(plan.BuildSteps, new BuildStepPlan[1] { accepted3 }))))) { return Stale("DSP no longer accepts the exact prepared construction plan: " + rejection); } return null; } private bool RevalidateBuildEndpoint(NormalActionPlanPayload plan, int objectId, string endpointHash) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown if (objectId <= 0) { return string.IsNullOrEmpty(endpointHash); } GameCallResult gameCallResult = _reader.InspectFactoryEntityOnMainThread(plan.SessionId, new InspectFactoryEntityRequest { PlanetId = plan.PlanetId, ObjectId = objectId }); if (gameCallResult.Success && gameCallResult.Value != null) { return string.Equals(BuildEndpointHash(gameCallResult.Value), endpointHash, StringComparison.Ordinal); } return false; } private static void CreatePreparedPrebuildsOnMainThread(ActionRecord action) { //IL_0473: Unknown result type (might be due to invalid IL or missing references) //IL_04b9: Unknown result type (might be due to invalid IL or missing references) //IL_0542: Unknown result type (might be due to invalid IL or missing references) PlanetFactory factory = GameMain.localPlanet?.factory ?? throw new InvalidOperationException("The local factory is unavailable."); Player val = GameMain.mainPlayer ?? throw new InvalidOperationException("The player is unavailable."); ItemProto val2 = ((ProtoSet)(object)LDB.items).Select(action.Plan.BuildingItemId) ?? throw new InvalidOperationException("The planned building prototype disappeared."); int itemCount = val.package.GetItemCount(((Proto)val2).ID); if (itemCount < action.Plan.BuildSteps.Count) { throw new InvalidOperationException("The planned building items are no longer in inventory."); } if (!BuildUiIsIdle(val)) { throw new InvalidOperationException("The normal build UI acquired preview state during commit."); } List list; Action action2; Action action3; if (action.Plan.BuildKind == "belt") { SpherewrightPathBuildTool tool = new SpherewrightPathBuildTool(); ((BuildTool)tool)._Init(GameMain.data); ((BuildTool)tool).SetFactoryReferences(); ((BuildTool_Path)tool).handItem = val2; ((BuildTool_Path)tool).handPrefabDesc = val2.prefabDesc; ((BuildTool_Path)tool).startObjectId = action.Plan.BuildSteps[0].InputObjectId; tool.SnapshotPlayerInventory(); list = CreateLinkedPreviews(action.Plan.BuildSteps, val2); ((BuildTool)tool).buildPreviews.AddRange(list); if (!((BuildTool_Path)tool).CheckBuildConditions() || !PreviewsExactlyMatch(action.Plan.BuildSteps, list)) { ((BuildTool)tool).buildPreviews.Clear(); tool.ReleaseSnapshot(); ((BuildTool)tool)._Free(); throw new InvalidOperationException("DSP rejected or changed the exact prepared belt path at commit."); } action2 = ((BuildTool_Path)tool).CreatePrebuilds; action3 = delegate { ((BuildTool)tool).buildPreviews.Clear(); tool.ReleaseSnapshot(); ((BuildTool)tool)._Free(); }; } else if (action.Plan.BuildKind == "inserter") { SpherewrightInserterBuildTool tool2 = new SpherewrightInserterBuildTool(); ((BuildTool)tool2)._Init(GameMain.data); ((BuildTool)tool2).SetFactoryReferences(); ((BuildTool_Inserter)tool2).handItem = val2; ((BuildTool_Inserter)tool2).handPrefabDesc = val2.prefabDesc; ((BuildTool_Inserter)tool2).startObjectId = action.Plan.SourceObjectId; ((BuildTool_Inserter)tool2).castObjectId = action.Plan.DestinationObjectId; tool2.SnapshotPlayerInventory(); list = CreateLinkedPreviews(action.Plan.BuildSteps, val2); ((BuildTool)tool2).buildPreviews.AddRange(list); if (!((BuildTool_Inserter)tool2).CheckBuildConditions() || !PreviewsExactlyMatch(action.Plan.BuildSteps, list)) { ((BuildTool)tool2).buildPreviews.Clear(); tool2.ReleaseSnapshot(); ((BuildTool)tool2)._Free(); throw new InvalidOperationException("DSP rejected or changed the exact prepared inserter at commit."); } action2 = ((BuildTool_Inserter)tool2).CreatePrebuilds; action3 = delegate { ((BuildTool)tool2).buildPreviews.Clear(); tool2.ReleaseSnapshot(); ((BuildTool)tool2)._Free(); }; } else { SpherewrightClickBuildTool tool3 = new SpherewrightClickBuildTool(); ((BuildTool)tool3)._Init(GameMain.data); ((BuildTool)tool3).SetFactoryReferences(); ((BuildTool_Click)tool3).handItem = val2; ((BuildTool_Click)tool3).handPrefabDesc = val2.prefabDesc; ((BuildTool_Click)tool3).yaw = action.Plan.BuildSteps[0].Yaw; tool3.SnapshotPlayerInventory(); list = CreateLinkedPreviews(action.Plan.BuildSteps, val2); ((BuildTool)tool3).buildPreviews.AddRange(list); if (!((BuildTool_Click)tool3).CheckBuildConditions() || !PreviewsExactlyMatch(action.Plan.BuildSteps, list)) { ((BuildTool)tool3).buildPreviews.Clear(); tool3.ReleaseSnapshot(); ((BuildTool)tool3)._Free(); throw new InvalidOperationException("DSP rejected or changed the exact prepared building at commit."); } action2 = ((BuildTool_Click)tool3).CreatePrebuilds; action3 = delegate { ((BuildTool)tool3).buildPreviews.Clear(); tool3.ReleaseSnapshot(); ((BuildTool)tool3)._Free(); }; } try { action.PreexistingBuildEntityIds.Clear(); if (action.Plan.BuildKind == "inserter") { CaptureBuiltEntityIds(factory, ((Proto)val2).ID, list[0].lpos, action.PreexistingBuildEntityIds); } else if (action.Plan.BuildKind == "belt") { foreach (BuildPreview item in list) { CaptureBuiltEntityIds(factory, ((Proto)val2).ID, item.lpos, action.PreexistingBuildEntityIds); } } action2(); foreach (BuildPreview item2 in list) { if (item2.objId >= 0) { throw new InvalidOperationException("DSP did not return an ordinary prebuild object ID for every step."); } action.PrebuildIds.Add(-item2.objId); action.ExpectedBuildEntities.Add(new BuildExpectedEntity { ItemId = ((Proto)val2).ID, Position = item2.lpos, InputObjectId = item2.inputObjId, OutputObjectId = item2.outputObjId, InputStepIndex = action.Plan.BuildSteps[list.IndexOf(item2)].InputStepIndex, OutputStepIndex = action.Plan.BuildSteps[list.IndexOf(item2)].OutputStepIndex }); } if (val.package.GetItemCount(((Proto)val2).ID) != itemCount - list.Count) { throw new InvalidOperationException("The accepted prebuild set did not consume exactly the planned owned items."); } } finally { action3(); } } private void UpdatePreparedBuildOnMainThread(ActionRecord action) { //IL_00a0: Unknown result type (might be due to invalid IL or missing references) PlanetFactory factory = GameMain.localPlanet?.factory; if (factory == null) { return; } if (action.PrebuildIds.Any((int prebuildId) => prebuildId > 0 && prebuildId < factory.prebuildCursor && prebuildId < factory.prebuildPool.Length && factory.prebuildPool[prebuildId].id == prebuildId && !factory.prebuildPool[prebuildId].isDestroyed)) { if (GameMain.gameTick > action.StartedAtGameTick + Math.Max(72000L, action.Plan.EstimatedTicks * 20)) { QuarantineBuildOutcome(action, "Ordinary prebuilds remained unfinished beyond the bounded game-tick window."); } return; } List list = new List(); foreach (BuildExpectedEntity expectedBuildEntity in action.ExpectedBuildEntities) { int num = FindBuiltEntityExcluding(factory, expectedBuildEntity.ItemId, expectedBuildEntity.Position, action.PreexistingBuildEntityIds, list); if (num <= 0) { QuarantineBuildOutcome(action, "An accepted prebuild disappeared without a provable matching built entity."); return; } list.Add(num); } if (!VerifyBuiltTopology(factory, action.Plan, list, out string rejection)) { QuarantineBuildOutcome(action, "Built-entity topology readback failed: " + rejection); return; } action.TargetObjectIds = list; action.TargetObjectId = ((list.Count == 1) ? new int?(list[0]) : ((int?)null)); Complete(action, $"Construction drones completed all {list.Count} ordinary prebuild(s), and entity/component/connection readback matched the plan."); } private void QuarantineBuildOutcome(ActionRecord action, string message) { action.State = "outcome_unknown"; action.Terminal = true; action.CompletedAtGameTick = GameMain.gameTick; action.Message = message; action.OriginalOutcomeMessage = message; action.AfterInventory = CaptureInventory(GameMain.mainPlayer); _sessions.QuarantineWritesOnMainThread(action.ActionId, message); } private static bool VerifyBuiltTopology(PlanetFactory factory, NormalActionPlanPayload plan, IReadOnlyList entityIds, out string rejection) { rejection = string.Empty; if (plan.BuildKind == "resource") { ref EntityData reference = ref factory.entityPool[entityIds[0]]; if (reference.minerId <= 0 || reference.minerId >= factory.factorySystem.minerCursor) { rejection = "The resource building has no valid miner component."; return false; } ref MinerComponent reference2 = ref factory.factorySystem.minerPool[reference.minerId]; int[] array = ((reference2.veins == null) ? Array.Empty() : (from nodeId in (from nodeId in reference2.veins.Take(Math.Min(reference2.veinCount, reference2.veins.Length)) where nodeId > 0 select nodeId).Distinct() orderby nodeId select nodeId).ToArray()); int[] second = (from nodeId in plan.BuildSteps[0].Parameters.Where((int nodeId) => nodeId > 0).Distinct() orderby nodeId select nodeId).ToArray(); if (!array.Contains(plan.BuildResourceNodeId) || !array.SequenceEqual(second)) { rejection = "The built miner did not retain the exact prepared resource-node coverage."; return false; } } if (plan.BuildKind == "inserter") { ref EntityData reference3 = ref factory.entityPool[entityIds[0]]; if (reference3.inserterId <= 0 || reference3.inserterId >= factory.factorySystem.inserterCursor) { rejection = "The built sorter has no valid inserter component."; return false; } ref InserterComponent reference4 = ref factory.factorySystem.inserterPool[reference3.inserterId]; if (reference4.pickTarget != plan.SourceObjectId || reference4.insertTarget != plan.DestinationObjectId) { rejection = $"Sorter readback was {reference4.pickTarget}->{reference4.insertTarget}, not {plan.SourceObjectId}->{plan.DestinationObjectId}."; return false; } BuildStepPlan buildStepPlan = plan.BuildSteps[0]; if (!ObjectConnectionMatches(factory, plan.SourceObjectId, buildStepPlan.InputFromSlot, expectedIsOutput: true, entityIds[0])) { rejection = $"Prepared source slot {buildStepPlan.InputFromSlot} does not point to the built sorter {entityIds[0]}."; return false; } if (!ObjectConnectionMatches(factory, plan.DestinationObjectId, buildStepPlan.OutputToSlot, expectedIsOutput: false, entityIds[0])) { rejection = $"Prepared destination slot {buildStepPlan.OutputToSlot} does not point to the built sorter {entityIds[0]}."; return false; } } if (plan.BuildKind == "belt") { bool flag = default(bool); int num3 = default(int); int num4 = default(int); for (int num = 0; num < entityIds.Count; num++) { if (factory.entityPool[entityIds[num]].beltId <= 0) { rejection = $"Path entity {entityIds[num]} has no belt component."; return false; } int num2 = ((num + 1 < entityIds.Count) ? entityIds[num + 1] : plan.DestinationObjectId); factory.ReadObjectConn(entityIds[num], 0, ref flag, ref num3, ref num4); if (!BeltConnectionProof.OutputMatches(num2, flag, num3)) { rejection = ((num2 > 0) ? $"Belt segment {entityIds[num]} output is not connected to {num2}." : $"Belt segment {entityIds[num]} unexpectedly has an output-side connection to object {num3}."); return false; } } if (plan.SourceObjectId > 0) { bool flag2 = default(bool); int num5 = default(int); factory.ReadObjectConn(entityIds[0], 1, ref flag2, ref num5, ref num4); if (flag2 || num5 != plan.SourceObjectId) { rejection = "The first belt segment is not connected to the prepared source port."; return false; } } } return true; } private static bool ObjectConnectionMatches(PlanetFactory factory, int objectId, int slot, bool expectedIsOutput, int expectedOtherObjectId) { if (objectId <= 0) { return false; } bool flag = default(bool); int num = default(int); int num2 = default(int); foreach (int item in BuildConnectionSlots.SelectVerificationCandidates(slot, 16)) { factory.ReadObjectConn(objectId, item, ref flag, ref num, ref num2); if (flag == expectedIsOutput && num == expectedOtherObjectId) { return true; } } return false; } private GameCallResult PrepareStorageTransferOnMainThread(string? requestedSessionId, PrepareTransferRequest request) { //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Expected O, but got Unknown //IL_00a6: 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_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Expected O, but got Unknown //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_03d7: Unknown result type (might be due to invalid IL or missing references) //IL_03dc: Unknown result type (might be due to invalid IL or missing references) //IL_03e8: Unknown result type (might be due to invalid IL or missing references) //IL_0413: Unknown result type (might be due to invalid IL or missing references) //IL_041f: Unknown result type (might be due to invalid IL or missing references) //IL_0430: Expected O, but got Unknown CommonPrepareResult commonPrepareResult = ValidatePrepareCommon(requestedSessionId, request.PlanetId, request.StateHashVersion); if (commonPrepareResult.Error != null) { return GameCallResult.Failed(commonPrepareResult.Error); } if (request.Direction != "player-to-storage" && request.Direction != "storage-to-player") { return InvalidPlan("Transfer direction must be player-to-storage or storage-to-player."); } if (request.ItemId <= 0 || request.Count <= 0 || request.Count > 10000) { return InvalidPlan("Transfer item and count must be positive; count is bounded to 10000 per action."); } GameCallResult playerStateOnMainThread = _reader.GetPlayerStateOnMainThread(requestedSessionId, new LocalPlanetRequest { PlanetId = request.PlanetId }); GameCallResult gameCallResult = _reader.InspectFactoryEntityOnMainThread(requestedSessionId, new InspectFactoryEntityRequest { PlanetId = request.PlanetId, ObjectId = request.StorageEntityId }); if (!playerStateOnMainThread.Success || playerStateOnMainThread.Value == null) { return GameCallResult.Failed(playerStateOnMainThread.Error); } if (!gameCallResult.Success || gameCallResult.Value == null) { return GameCallResult.Failed(gameCallResult.Error); } FactoryEntitySnapshot value = gameCallResult.Value; if (!string.Equals(playerStateOnMainThread.Value.StateHash, request.ExpectedPlayerStateHash, StringComparison.Ordinal) || !string.Equals(value.StateHash, request.ExpectedStorageStateHash, StringComparison.Ordinal)) { return StalePlan("Player inventory or exact storage contents changed after inspection."); } if (value.ObjectKind != "entity" || !string.Equals(value.ComponentKind, "storage", StringComparison.Ordinal)) { return GameCallResult.Failed(BridgeError.Create("INVALID_ENTITY", "The transfer target is not an exact built storage component.", false, "Inspect a built storage entity and use its object ID.")); } PlanetFactory val = GameMain.localPlanet?.factory; Player mainPlayer = GameMain.mainPlayer; if (val == null || ((mainPlayer != null) ? mainPlayer.package : null) == null || !TryGetStorage(val, request.StorageEntityId, out StorageComponent storage)) { return NotReadyPlan("The exact storage component is unavailable."); } float num = Vector3.Distance(mainPlayer.position, ToVector(value.Position)); if (num > mainPlayer.mecha.buildArea) { return GameCallResult.Failed(BridgeError.Create("TARGET_OUT_OF_RANGE", $"The storage is {num:F2} metres away, outside the current normal interaction/build area.", true, "Move into range through spherewright_prepare_move, then inspect and prepare again.")); } if (!CanTransferExactly(mainPlayer.package, storage, request.Direction, request.ItemId, request.Count, out string rejection)) { return GameCallResult.Failed(BridgeError.Create((rejection.IndexOf("source", StringComparison.OrdinalIgnoreCase) >= 0) ? "INVENTORY_INSUFFICIENT" : "INVENTORY_FULL", rejection, true, "Adjust the count or free destination capacity, then inspect and prepare again.")); } string text = CanonicalStateHash.PlayerAction(playerStateOnMainThread.Value); string expectedStateHash = CanonicalStateHash.Combine("transfer", new object[8] { _sessions.SessionId, request.PlanetId, text, value.StateHash, request.StorageEntityId, request.Direction, request.ItemId, request.Count }); NormalActionPlanPayload payload = NormalActionPlanPayload.Transfer(_sessions.SessionId, request.PlanetId, expectedStateHash, text, value.StateHash, request.StorageEntityId, request.Direction, request.ItemId, request.Count); GameCallResult gameCallResult2 = AddPreparedPlan(payload, commonPrepareResult.Session, 1L, "The source decreases and destination increases by the exact requested count while their combined item count is conserved."); if (gameCallResult2.Success && gameCallResult2.Value != null) { gameCallResult2.Value.SourceObjectId = ((request.Direction == "storage-to-player") ? new int?(request.StorageEntityId) : ((int?)null)); gameCallResult2.Value.DestinationObjectId = ((request.Direction == "player-to-storage") ? new int?(request.StorageEntityId) : ((int?)null)); gameCallResult2.Value.EstimatedDistance = num; List itemBudget = gameCallResult2.Value.ItemBudget; ActionItemBudget val2 = new ActionItemBudget { ItemId = request.ItemId }; ItemProto obj = ((ProtoSet)(object)LDB.items).Select(request.ItemId); val2.Name = ((obj != null) ? ((Proto)obj).name : null) ?? string.Empty; val2.Count = request.Count; val2.Direction = request.Direction; itemBudget.Add(val2); } return gameCallResult2; } private BridgeError? RevalidateStorageTransferOnMainThread(NormalActionPlanPayload plan) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown GameCallResult playerStateOnMainThread = _reader.GetPlayerStateOnMainThread(plan.SessionId, new LocalPlanetRequest { PlanetId = plan.PlanetId }); GameCallResult gameCallResult = _reader.InspectFactoryEntityOnMainThread(plan.SessionId, new InspectFactoryEntityRequest { PlanetId = plan.PlanetId, ObjectId = plan.TransferStorageEntityId }); if (!playerStateOnMainThread.Success || playerStateOnMainThread.Value == null) { return playerStateOnMainThread.Error; } if (!gameCallResult.Success || gameCallResult.Value == null) { return gameCallResult.Error; } if (!string.Equals(CanonicalStateHash.PlayerAction(playerStateOnMainThread.Value), plan.PlayerStateHash, StringComparison.Ordinal) || !string.Equals(gameCallResult.Value.StateHash, plan.TransferStorageStateHash, StringComparison.Ordinal)) { return Stale("Player inventory or storage contents changed after transfer preparation."); } PlanetFactory val = GameMain.localPlanet?.factory; Player mainPlayer = GameMain.mainPlayer; if (val == null || ((mainPlayer != null) ? mainPlayer.package : null) == null || !TryGetStorage(val, plan.TransferStorageEntityId, out StorageComponent storage) || !CanTransferExactly(mainPlayer.package, storage, plan.TransferDirection, plan.TransferItemId, plan.Count, out string _)) { return Stale("Transfer source count, destination capacity, or exact storage identity changed."); } return null; } private static void ExecuteStorageTransferOnMainThread(ActionRecord action) { PlanetFactory factory = GameMain.localPlanet?.factory ?? throw new InvalidOperationException("The local factory is unavailable."); Player val = GameMain.mainPlayer ?? throw new InvalidOperationException("The player is unavailable."); NormalActionPlanPayload plan = action.Plan; if (!TryGetStorage(factory, plan.TransferStorageEntityId, out StorageComponent storage)) { throw new InvalidOperationException("The exact storage component disappeared."); } int itemCount = val.package.GetItemCount(plan.TransferItemId); int itemCount2 = storage.GetItemCount(plan.TransferItemId); StorageComponent obj = ((plan.TransferDirection == "player-to-storage") ? val.package : storage); StorageComponent val2 = ((plan.TransferDirection == "player-to-storage") ? storage : val.package); int num2 = default(int); int num = obj.TakeItem(plan.TransferItemId, plan.Count, ref num2); if (num != plan.Count) { throw new InvalidOperationException("The exact transfer source did not remove the prepared count."); } int num4 = default(int); int num3 = val2.AddItemStacked(plan.TransferItemId, num, num2, ref num4); if (num3 != num || num4 != 0) { throw new InvalidOperationException("The exact transfer destination did not accept the prepared count."); } if (val2 == val.package) { val.NotifyPackageAddItem(plan.TransferItemId, num3, num2); } int itemCount3 = val.package.GetItemCount(plan.TransferItemId); int itemCount4 = storage.GetItemCount(plan.TransferItemId); int num5 = ((plan.TransferDirection == "player-to-storage") ? (-plan.Count) : plan.Count); if (itemCount3 - itemCount != num5 || itemCount4 - itemCount2 != -num5 || itemCount + itemCount2 != itemCount3 + itemCount4) { throw new InvalidOperationException("Post-transfer readback did not prove exact bilateral conservation."); } action.TargetObjectId = plan.TransferStorageEntityId; action.TargetItemId = plan.TransferItemId; action.BeforeTargetAmount = itemCount2; action.AfterTargetAmount = itemCount4; action.Message = $"Normal storage transfer conserved item {plan.TransferItemId}: player {itemCount}->{itemCount3}, storage {itemCount2}->{itemCount4}."; action.State = "completed"; action.Terminal = true; action.Succeeded = true; action.CompletedAtGameTick = GameMain.gameTick; action.AfterInventory = CaptureInventory(val); action.AfterStateHash = CanonicalStateHash.Combine("transfer", new object[4] { itemCount3, itemCount4, plan.TransferItemId, plan.Count }); } private GameCallResult PrepareStructuredConfigurationOnMainThread(string? requestedSessionId, PrepareConfigureBuildingRequest request) { //IL_00a0: 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_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Expected O, but got Unknown //IL_047b: Unknown result type (might be due to invalid IL or missing references) //IL_0483: Unknown result type (might be due to invalid IL or missing references) //IL_03cc: Unknown result type (might be due to invalid IL or missing references) //IL_03cd: Unknown result type (might be due to invalid IL or missing references) CommonPrepareResult commonPrepareResult = ValidatePrepareCommon(requestedSessionId, request.PlanetId, request.StateHashVersion); if (commonPrepareResult.Error != null) { return GameCallResult.Failed(commonPrepareResult.Error); } if (request.Mode != "production" && request.Mode != "research" && request.Mode != "sorter-filter" && request.Mode != "logistics-station-storage" && request.Mode != "logistics-station-belt" && request.Mode != "logistics-station-charge") { return InvalidPlan("Configuration mode must be production, research, sorter-filter, logistics-station-storage, logistics-station-belt, or logistics-station-charge."); } ELogisticStorage logic = (ELogisticStorage)0; ELogisticStorage logic2 = (ELogisticStorage)0; if (request.Mode == "logistics-station-storage" && (!TryParseLogisticsStorageLogic(request.StationLocalLogic, out logic) || !TryParseLogisticsStorageLogic(request.StationRemoteLogic, out logic2))) { return InvalidPlan("Station local and remote logic must each be none, supply, or demand."); } GameCallResult gameCallResult = _reader.InspectFactoryEntityOnMainThread(requestedSessionId, new InspectFactoryEntityRequest { PlanetId = request.PlanetId, ObjectId = request.EntityId }); if (!gameCallResult.Success || gameCallResult.Value == null) { return GameCallResult.Failed(gameCallResult.Error); } FactoryEntitySnapshot value = gameCallResult.Value; bool flag = request.Mode == "sorter-filter"; string text = (flag ? value.ConfigurationStateHash : value.StateHash); if (!string.Equals(request.ExpectedFactoryStateHash, text, StringComparison.Ordinal)) { return StalePlan(flag ? "Sorter identity, topology, current filter, or carried cargo changed after inspection." : "Building mode, recipe, progress, buffers, or identity changed after inspection."); } bool flag2 = request.Mode == "logistics-station-storage" || request.Mode == "logistics-station-belt" || request.Mode == "logistics-station-charge"; if (value.ObjectKind != "entity" || (!flag2 && !flag && (value.Progress != 0 || value.IsWorking || value.Buffers.Any((FactoryBufferSnapshot buffer) => buffer.Count != 0)))) { return GameCallResult.Failed(BridgeError.Create("ACTION_REJECTED", flag2 ? "The logistics-station target is not a completed built entity." : "Only a fully idle built device with empty input, output, and internal buffers can be configured.", true, flag2 ? "Wait for normal construction to finish, then inspect the exact station entity again." : "Wait for the exact device to become idle and empty, then inspect and prepare again.")); } PlanetFactory val = GameMain.localPlanet?.factory; if (val == null) { return NotReadyPlan("The local factory is unavailable."); } RecipeProto val2 = null; int selectedItemId = 0; if (request.Mode == "production") { val2 = ((ProtoSet)(object)LDB.recipes).Select(request.RecipeId); if (val2 == null || !GameMain.history.RecipeUnlocked(request.RecipeId)) { return GameCallResult.Failed(BridgeError.Create("INVALID_RECIPE", "The requested runtime recipe does not exist or is not unlocked.", false, "Complete the normal prerequisite technology and choose an unlocked recipe.")); } if (!CanDeviceRunRecipe(val, request.EntityId, val2, out string reason)) { return GameCallResult.Failed(BridgeError.Create("RECIPE_NOT_SUPPORTED_BY_BUILDING", reason, false, "Choose a recipe whose runtime type matches the exact built device.")); } } else { if (request.Mode == "research" && !CanLabEnterResearchMode(val, request.EntityId, request.TechId, out string reason2)) { return GameCallResult.Failed(BridgeError.Create("INVALID_TECHNOLOGY", reason2, false, "Select an active matrix technology through the normal research queue, then configure an empty matrix lab.")); } if (request.Mode == "sorter-filter" && !CanSetSorterFilter(val, request.EntityId, request.FilterItemId, out string reason3)) { return GameCallResult.Failed(BridgeError.Create("ACTION_REJECTED", reason3, true, "Wait until the exact sorter is idle and carrying no cargo, then inspect and prepare again with an unlocked filter item or zero to clear it.")); } if (flag2) { if (value.LogisticsStation == null || !string.Equals(request.ExpectedStationConfigurationStateHash, value.LogisticsStation.ConfigurationStateHash, StringComparison.Ordinal)) { return StalePlan("The logistics-station identity, storage-slot configuration, route settings, or belt topology changed after inspection."); } if (request.Mode == "logistics-station-storage" && !CanConfigureLogisticsStationStorage(val, request.EntityId, request.StationStorageIndex, request.StationItemId, request.StationMaximumCount, logic, logic2, out string reason4)) { return GameCallResult.Failed(BridgeError.Create("ACTION_REJECTED", reason4, true, "Choose an unlocked item and an empty or same-item slot with no outstanding orders; use 100-item limit steps within the station's current researched capacity.")); } if (request.Mode == "logistics-station-charge" && !CanConfigureLogisticsStationCharge(val, request.EntityId, request.StationMaximumChargePowerWatts, out long _, out string reason5)) { return GameCallResult.Failed(BridgeError.Create("ACTION_REJECTED", reason5, true, "Choose a different 3 MW UI step within one-half through five times this exact station prefab's default charging energy.")); } if (request.Mode == "logistics-station-belt" && !CanConfigureLogisticsStationBelt(val, request.EntityId, request.StationBeltSlotIndex, request.StationBeltStorageIndex, out selectedItemId, out string reason6)) { return GameCallResult.Failed(BridgeError.Create("ACTION_REJECTED", reason6, true, "Choose an empty connected output port and a configured unlocked station storage slot; existing nonzero output selectors are never replaced.")); } } } string text2 = ToContractLogisticsStorageLogic(logic); string text3 = ToContractLogisticsStorageLogic(logic2); string expectedStateHash = CanonicalStateHash.Combine("configure-building", new object[18] { _sessions.SessionId, request.PlanetId, text, request.EntityId, request.Mode, request.RecipeId, request.TechId, request.FilterItemId, request.ExpectedStationConfigurationStateHash, request.StationStorageIndex, request.StationBeltSlotIndex, request.StationBeltStorageIndex, selectedItemId, request.StationItemId, request.StationMaximumCount, text2, text3, request.StationMaximumChargePowerWatts }); NormalActionPlanPayload payload = NormalActionPlanPayload.Configure(_sessions.SessionId, request.PlanetId, expectedStateHash, text, request.EntityId, request.RecipeId, request.Mode, request.TechId, request.FilterItemId, request.ExpectedStationConfigurationStateHash, request.StationStorageIndex, request.StationBeltSlotIndex, request.StationBeltStorageIndex, selectedItemId, request.StationItemId, request.StationMaximumCount, text2, text3, request.StationMaximumChargePowerWatts); GameCallResult gameCallResult2 = AddPreparedPlan(payload, commonPrepareResult.Session, 1L, (request.Mode == "research") ? "The exact empty matrix lab reports research mode and the active technology after the UI/business setting path is called once." : ((request.Mode == "sorter-filter") ? "The exact connected cargo-free sorter reports the target item filter and matching entity sign after the current-version UI setting path is applied once." : ((request.Mode == "logistics-station-storage") ? "The exact station slot reports the selected unlocked item, 100-step limit, and local/remote logic after PlanetTransport.SetStationStorage is called once; item count and proliferator points remain unchanged by the call." : ((request.Mode == "logistics-station-belt") ? "The exact connected station output port reports the selected storage slot after the current-version UI field path is applied once; station inventory, player inventory, port topology, and every unrelated selector remain unchanged." : ((request.Mode == "logistics-station-charge") ? "The exact station power consumer reports the requested UI-step maximum charging power after the current-version UI field path is applied once; station and player inventory remain unchanged." : "The exact idle device reports the target recipe after the current-version UI/business setting path is called once."))))); if (gameCallResult2.Success && gameCallResult2.Value != null && val2 != null) { AddRecipeBudget(gameCallResult2.Value, val2, 1); } return gameCallResult2; } private BridgeError? RevalidateStructuredConfigurationOnMainThread(NormalActionPlanPayload plan) { //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Expected O, but got Unknown //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Expected O, but got Unknown //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Unknown result type (might be due to invalid IL or missing references) PlanetFactory val = GameMain.localPlanet?.factory; if (val == null) { return Stale("The local factory disappeared after configuration preparation."); } string reason; if (plan.ConfigureMode == "research") { if (!CanLabEnterResearchMode(val, plan.EntityId, plan.ConfigureTechId, out reason)) { return Stale("The exact lab or active matrix technology changed after preparation."); } return null; } if (plan.ConfigureMode == "sorter-filter") { GameCallResult gameCallResult = _reader.InspectFactoryEntityOnMainThread(plan.SessionId, new InspectFactoryEntityRequest { PlanetId = plan.PlanetId, ObjectId = plan.EntityId }); if (!gameCallResult.Success || gameCallResult.Value == null || !string.Equals(gameCallResult.Value.ConfigurationStateHash, plan.FactoryStateHash, StringComparison.Ordinal)) { return Stale("The exact sorter identity, topology, current filter, or carried cargo changed after preparation."); } if (!CanSetSorterFilter(val, plan.EntityId, plan.ConfigureFilterItemId, out reason)) { return Stale("The exact sorter is no longer connected and cargo-free, or the filter item changed after preparation."); } return null; } if (plan.ConfigureMode == "logistics-station-storage" || plan.ConfigureMode == "logistics-station-belt" || plan.ConfigureMode == "logistics-station-charge") { GameCallResult gameCallResult2 = _reader.InspectFactoryEntityOnMainThread(plan.SessionId, new InspectFactoryEntityRequest { PlanetId = plan.PlanetId, ObjectId = plan.EntityId }); FactoryEntitySnapshot? value = gameCallResult2.Value; LogisticsStationSnapshot val2 = ((value != null) ? value.LogisticsStation : null); if (!gameCallResult2.Success || val2 == null || !string.Equals(val2.ConfigurationStateHash, plan.StationConfigurationStateHash, StringComparison.Ordinal)) { return Stale("The exact station identity or configuration changed after preparation."); } if (plan.ConfigureMode == "logistics-station-charge") { if (!CanConfigureLogisticsStationCharge(val, plan.EntityId, plan.ConfigureStationMaximumChargePowerWatts, out long _, out reason)) { return Stale("The exact station prefab, power-consumer identity, charging bound, or current maximum changed after preparation."); } return null; } if (plan.ConfigureMode == "logistics-station-belt") { if (!CanConfigureLogisticsStationBelt(val, plan.EntityId, plan.ConfigureStationBeltSlotIndex, plan.ConfigureStationBeltStorageIndex, out int selectedItemId, out reason) || selectedItemId != plan.ConfigureStationBeltItemId) { return Stale("The exact station output port, connected belt, selected storage item, or selector state changed after preparation."); } return null; } if (!TryParseLogisticsStorageLogic(plan.ConfigureStationLocalLogic, out var logic) || !TryParseLogisticsStorageLogic(plan.ConfigureStationRemoteLogic, out var logic2) || !CanConfigureLogisticsStationStorage(val, plan.EntityId, plan.ConfigureStationStorageIndex, plan.ConfigureStationItemId, plan.ConfigureStationMaximumCount, logic, logic2, out reason)) { return Stale("The exact station slot, item unlock, capacity, current item, or outstanding orders changed after preparation."); } return null; } RecipeProto val3 = ((ProtoSet)(object)LDB.recipes).Select(plan.ConfigureRecipeId); if (val3 == null || !GameMain.history.RecipeUnlocked(plan.ConfigureRecipeId) || !CanDeviceRunRecipe(val, plan.EntityId, val3, out reason)) { return Stale("The exact device no longer supports the prepared unlocked recipe."); } return null; } private static bool CanLabEnterResearchMode(PlanetFactory factory, int entityId, int techId, out string reason) { reason = "The exact entity is not a matrix lab or the requested matrix technology is not the current normal research target."; if (entityId <= 0 || entityId >= factory.entityCursor || entityId >= factory.entityPool.Length) { return false; } ref EntityData reference = ref factory.entityPool[entityId]; ItemProto obj = ((reference.id == entityId) ? ((ProtoSet)(object)LDB.items).Select((int)reference.protoId) : null); TechProto val = ((ProtoSet)(object)LDB.techs).Select(techId); if (obj != null && obj.prefabDesc?.isLab == true && reference.labId > 0 && val != null && val.IsLabTech && GameMain.history.currentTech == techId) { return !GameMain.history.TechUnlocked(techId); } return false; } private static bool TryParseLogisticsStorageLogic(string? value, out ELogisticStorage logic) { if (string.Equals(value, "none", StringComparison.OrdinalIgnoreCase)) { logic = (ELogisticStorage)0; return true; } if (string.Equals(value, "supply", StringComparison.OrdinalIgnoreCase)) { logic = (ELogisticStorage)1; return true; } if (string.Equals(value, "demand", StringComparison.OrdinalIgnoreCase)) { logic = (ELogisticStorage)2; return true; } logic = (ELogisticStorage)0; return false; } private static string ToContractLogisticsStorageLogic(ELogisticStorage logic) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 if ((int)logic != 1) { if ((int)logic == 2) { return "demand"; } return "none"; } return "supply"; } private static bool CanConfigureLogisticsStationCharge(PlanetFactory factory, int entityId, long maximumChargePowerWatts, out long maximumChargeEnergyPerTick, out string reason) { maximumChargeEnergyPerTick = 0L; reason = "The exact logistics-station power consumer is unavailable for this configuration."; if (entityId <= 0 || entityId >= factory.entityCursor || entityId >= factory.entityPool.Length) { return false; } ref EntityData reference = ref factory.entityPool[entityId]; ItemProto val = ((reference.id == entityId) ? ((ProtoSet)(object)LDB.items).Select((int)reference.protoId) : null); if (val?.prefabDesc == null || reference.stationId <= 0) { return false; } PlanetTransport transport = factory.transport; StationComponent val2 = ((transport != null) ? transport.GetStationComponent(reference.stationId) : null); if (val2 == null || val2.id != reference.stationId || val2.entityId != entityId || !LogisticsStationIdentityPolicy.MatchesLocalPlanet(val2.isStellar, val2.planetId, factory.planetId) || val2.isCollector || val2.isVeinCollector || val2.pcId <= 0 || val2.pcId != reference.powerConId || val2.pcId >= factory.powerSystem.consumerCursor || val2.pcId >= factory.powerSystem.consumerPool.Length) { return false; } ref PowerConsumerComponent reference2 = ref factory.powerSystem.consumerPool[val2.pcId]; if (reference2.id != val2.pcId || reference2.entityId != entityId) { return false; } long num = default(long); long num2 = default(long); if (!LogisticsStationChargePolicy.TryNormalizeUiPower(val.prefabDesc.workEnergyPerTick, maximumChargePowerWatts, ref maximumChargeEnergyPerTick, ref num, ref num2)) { reason = $"The requested maximum charge power must be a 3 MW UI step from {num * 60} through {num2 * 60} watts for this station prefab."; return false; } if (reference2.workEnergyPerTick == maximumChargeEnergyPerTick) { reason = "The requested station maximum charge power is already applied."; return false; } return true; } private static bool CanConfigureLogisticsStationStorage(PlanetFactory factory, int entityId, int storageIndex, int itemId, int maximumCount, ELogisticStorage localLogic, ELogisticStorage remoteLogic, out string reason) { //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_0254: Unknown result type (might be due to invalid IL or missing references) //IL_0258: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_025f: Unknown result type (might be due to invalid IL or missing references) reason = "The exact logistics-station storage slot is unavailable for this configuration."; if (entityId <= 0 || entityId >= factory.entityCursor || entityId >= factory.entityPool.Length || itemId <= 0 || maximumCount <= 0 || maximumCount % 100 != 0) { return false; } ref EntityData reference = ref factory.entityPool[entityId]; if (reference.id != entityId || reference.stationId <= 0) { return false; } PlanetTransport transport = factory.transport; StationComponent val = ((transport != null) ? transport.GetStationComponent(reference.stationId) : null); if (val == null || val.id != reference.stationId || val.entityId != entityId || !LogisticsStationIdentityPolicy.MatchesLocalPlanet(val.isStellar, val.planetId, factory.planetId) || val.isCollector || val.isVeinCollector || val.storage == null || storageIndex < 0 || storageIndex >= val.storage.Length) { return false; } if (!val.isStellar && (int)remoteLogic != 0) { reason = "A planetary logistics station requires remote logic none."; return false; } if (((ProtoSet)(object)LDB.items).Select(itemId) == null || !GameMain.history.ItemUnlocked(itemId)) { reason = "The requested station item does not exist or is not normally unlocked."; return false; } int valueOrDefault = (((ProtoSet)(object)LDB.models).Select((int)reference.modelIndex)?.prefabDesc?.stationMaxItemCount).GetValueOrDefault(); int num = (val.isStellar ? GameMain.history.remoteStationExtraStorage : GameMain.history.localStationExtraStorage); int num2 = valueOrDefault + num; if (num2 <= 0 || maximumCount > num2) { reason = $"The requested maximum {maximumCount} exceeds the station's current researched capacity {num2}."; return false; } for (int i = 0; i < val.storage.Length; i++) { if (i != storageIndex && val.storage[i].itemId == itemId) { reason = "The requested item is already assigned to another slot in this station."; return false; } } StationStore val2 = val.storage[storageIndex]; if (val2.itemId != 0 && val2.itemId != itemId) { reason = "This action never replaces or clears an occupied station slot; choose an empty slot or keep the same item."; return false; } if (val2.localOrder != 0 || val2.remoteOrder != 0) { reason = "The station slot has outstanding logistics orders and must become idle before configuration."; return false; } if (val2.itemId == 0 && (val2.count != 0 || val2.inc != 0)) { reason = "The nominally empty station slot contains unexplained inventory state."; return false; } if (val2.itemId == itemId && val2.max == maximumCount && val2.localLogic == localLogic && val2.remoteLogic == remoteLogic) { reason = "The requested station storage configuration is already applied."; return false; } return true; } private static bool CanConfigureLogisticsStationBelt(PlanetFactory factory, int entityId, int beltSlotIndex, int storageIndex, out int selectedItemId, out string reason) { //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Invalid comparison between Unknown and I4 selectedItemId = 0; reason = "The exact logistics-station output port or storage slot is unavailable for this configuration."; if (entityId <= 0 || entityId >= factory.entityCursor || entityId >= factory.entityPool.Length) { return false; } ref EntityData reference = ref factory.entityPool[entityId]; if (reference.id != entityId || reference.stationId <= 0) { return false; } PlanetTransport transport = factory.transport; StationComponent val = ((transport != null) ? transport.GetStationComponent(reference.stationId) : null); if (val == null || val.id != reference.stationId || val.entityId != entityId || !LogisticsStationIdentityPolicy.MatchesLocalPlanet(val.isStellar, val.planetId, factory.planetId) || val.isCollector || val.isVeinCollector || val.storage == null || val.slots == null || beltSlotIndex < 0 || beltSlotIndex >= val.slots.Length || storageIndex < 0 || storageIndex >= val.storage.Length) { return false; } ref SlotData reference2 = ref val.slots[beltSlotIndex]; int num = storageIndex + 1; if ((int)reference2.dir != 1 || reference2.beltId <= 0 || reference2.counter != 0) { reason = "The requested station port must be a connected output with no pending port cargo."; return false; } CargoTraffic cargoTraffic = factory.cargoTraffic; if (cargoTraffic?.beltPool == null || reference2.beltId >= cargoTraffic.beltCursor || reference2.beltId >= cargoTraffic.beltPool.Length) { reason = "The output port's connected belt component is no longer current."; return false; } ref BeltComponent reference3 = ref cargoTraffic.beltPool[reference2.beltId]; if (reference3.id != reference2.beltId || reference3.entityId <= 0 || reference3.entityId >= factory.entityCursor || reference3.entityId >= factory.entityPool.Length) { reason = "The output port's connected belt identity is invalid."; return false; } ref EntityData reference4 = ref factory.entityPool[reference3.entityId]; if (reference4.id != reference3.entityId || reference4.beltId != reference2.beltId) { reason = "The output port no longer resolves back to the same built belt entity."; return false; } selectedItemId = val.storage[storageIndex].itemId; if (selectedItemId <= 0 || ((ProtoSet)(object)LDB.items).Select(selectedItemId) == null || !GameMain.history.ItemUnlocked(selectedItemId)) { reason = "The requested station storage slot must contain a normally unlocked configured item."; return false; } if (reference2.storageIdx == num) { reason = "The requested station output selector is already applied."; return false; } if (reference2.storageIdx != 0) { reason = "This action never replaces an existing nonzero station output selector."; return false; } return true; } private static bool CanSetSorterFilter(PlanetFactory factory, int entityId, int filterItemId, out string reason) { reason = "The exact entity is not a connected cargo-free sorter, or the requested filter item is unavailable."; if (entityId <= 0 || entityId >= factory.entityCursor || entityId >= factory.entityPool.Length || entityId >= factory.entitySignPool.Length || filterItemId < 0) { return false; } ref EntityData reference = ref factory.entityPool[entityId]; if (reference.id != entityId || reference.inserterId <= 0 || reference.inserterId >= factory.factorySystem.inserterCursor || reference.inserterId >= factory.factorySystem.inserterPool.Length) { return false; } ref InserterComponent reference2 = ref factory.factorySystem.inserterPool[reference.inserterId]; if (reference2.id != reference.inserterId || reference2.entityId != entityId || !SorterFilterPolicy.IsSafeAssignmentWindow(filterItemId, reference2.pickTarget, reference2.insertTarget, reference2.itemId, (int)reference2.itemCount, reference2.stackCount, (int)reference2.itemInc)) { return false; } if (filterItemId == 0) { return true; } if (((ProtoSet)(object)LDB.items).Select(filterItemId) != null) { return GameMain.history.ItemUnlocked(filterItemId); } return false; } private static bool IsLabInResearchMode(int entityId, int techId) { PlanetFactory val = GameMain.localPlanet?.factory; if (val == null || entityId <= 0 || entityId >= val.entityCursor) { return false; } ref EntityData reference = ref val.entityPool[entityId]; if (reference.id != entityId || reference.labId <= 0 || reference.labId >= val.factorySystem.labCursor) { return false; } ref LabComponent reference2 = ref val.factorySystem.labPool[reference.labId]; if (reference2.id == reference.labId && reference2.researchMode && reference2.techId == techId) { return reference2.recipeId == 0; } return false; } private static bool IsSorterFilterApplied(int entityId, int filterItemId) { PlanetFactory val = GameMain.localPlanet?.factory; if (val == null || entityId <= 0 || entityId >= val.entityCursor || entityId >= val.entityPool.Length || entityId >= val.entitySignPool.Length) { return false; } ref EntityData reference = ref val.entityPool[entityId]; if (reference.id != entityId || reference.inserterId <= 0 || reference.inserterId >= val.factorySystem.inserterCursor || reference.inserterId >= val.factorySystem.inserterPool.Length) { return false; } ref InserterComponent reference2 = ref val.factorySystem.inserterPool[reference.inserterId]; ref SignData reference3 = ref val.entitySignPool[entityId]; if (reference2.id == reference.inserterId && reference2.entityId == entityId && reference2.filter == filterItemId && reference3.iconId0 == (uint)filterItemId) { return reference3.iconType == ((filterItemId > 0) ? 1u : 0u); } return false; } private static bool IsLogisticsStationStorageConfigurationApplied(FactoryEntitySnapshot snapshot, NormalActionPlanPayload plan) { LogisticsStationSnapshot logisticsStation = snapshot.LogisticsStation; LogisticsStationStorageSlotSnapshot val = ((logisticsStation != null) ? ((IEnumerable)logisticsStation.StorageSlots).FirstOrDefault((Func)((LogisticsStationStorageSlotSnapshot candidate) => candidate.Index == plan.ConfigureStationStorageIndex)) : null); if (val != null && val.ItemId == plan.ConfigureStationItemId && val.MaximumCount == plan.ConfigureStationMaximumCount && string.Equals(val.LocalLogic, plan.ConfigureStationLocalLogic, StringComparison.OrdinalIgnoreCase)) { return string.Equals(val.RemoteLogic, plan.ConfigureStationRemoteLogic, StringComparison.OrdinalIgnoreCase); } return false; } private static bool IsLogisticsStationChargeConfigurationApplied(FactoryEntitySnapshot snapshot, NormalActionPlanPayload plan) { if (snapshot.LogisticsStation != null) { return snapshot.LogisticsStation.MaximumChargePowerWatts == plan.ConfigureStationMaximumChargePowerWatts; } return false; } private static bool IsLogisticsStationBeltConfigurationApplied(FactoryEntitySnapshot snapshot, NormalActionPlanPayload plan) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) LogisticsStationSnapshot logisticsStation = snapshot.LogisticsStation; LogisticsStationBeltSlotSnapshot val = ((logisticsStation != null) ? ((IEnumerable)logisticsStation.BeltSlots).FirstOrDefault((Func)((LogisticsStationBeltSlotSnapshot candidate) => candidate.Index == plan.ConfigureStationBeltSlotIndex)) : null); LogisticsStationStorageSlotSnapshot val2 = ((logisticsStation != null) ? ((IEnumerable)logisticsStation.StorageSlots).FirstOrDefault((Func)((LogisticsStationStorageSlotSnapshot candidate) => candidate.Index == plan.ConfigureStationBeltStorageIndex)) : null); if (val != null && val2 != null && string.Equals(val.Direction, ((object)(IODir)1/*cast due to .constrained prefix*/).ToString(), StringComparison.Ordinal) && val.BeltComponentId > 0 && val.BeltEntityId > 0 && val.StorageIndex == plan.ConfigureStationBeltStorageIndex + 1) { return val2.ItemId == plan.ConfigureStationBeltItemId; } return false; } private static string CaptureLogisticsStationBeltSelectorInvariantState(StationComponent station, int targetBeltSlotIndex) { //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_0263: Unknown result type (might be due to invalid IL or missing references) //IL_027a: Unknown result type (might be due to invalid IL or missing references) //IL_028f: Unknown result type (might be due to invalid IL or missing references) List list = new List { station.id, station.gid, station.entityId, station.planetId, station.isStellar, station.isCollector, station.isVeinCollector, station.energy, station.energyPerTick, station.energyMax, station.warperCount, station.idleDroneCount, station.workDroneCount, station.idleShipCount, station.workShipCount, station.tripRangeDrones, station.tripRangeShips, station.includeOrbitCollector, station.warpEnableDist, station.warperNecessary, station.deliveryDrones, station.deliveryShips, station.pilerCount, station.droneAutoReplenish, station.shipAutoReplenish, station.remoteGroupMask, station.routePriority }; int[] array = station.needs ?? Array.Empty(); list.Add(array.Length); int[] array2 = array; foreach (int num in array2) { list.Add(num); } SlotData[] array3 = station.slots ?? Array.Empty(); list.Add(array3.Length); for (int j = 0; j < array3.Length; j++) { SlotData val = array3[j]; list.Add(j); list.Add(val.dir); list.Add(val.beltId); list.Add((j != targetBeltSlotIndex) ? val.storageIdx : 0); list.Add(val.counter); } return CanonicalStateHash.Combine("logistics-station-belt-selector-invariant-v1", list.ToArray()); } private static string CaptureLogisticsStationStorageState(StationComponent station) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0084: 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_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) StationStore[] array = station.storage ?? Array.Empty(); List list = new List { station.id, station.entityId, station.planetId, array.Length }; for (int i = 0; i < array.Length; i++) { StationStore val = array[i]; list.Add(i); list.Add(val.itemId); list.Add(val.count); list.Add(val.inc); list.Add(val.max); list.Add(val.localOrder); list.Add(val.remoteOrder); list.Add(((StationStore)(ref val)).totalOrdered); list.Add(((StationStore)(ref val)).localSupplyCount); list.Add(((StationStore)(ref val)).localDemandCount); list.Add(((StationStore)(ref val)).remoteSupplyCount); list.Add(((StationStore)(ref val)).remoteDemandCount); list.Add(val.localLogic); list.Add(val.remoteLogic); list.Add(val.keepMode); list.Add(val.keepIncRatio); } return CanonicalStateHash.Combine("logistics-station-storage-runtime-v1", list.ToArray()); } private string? CaptureStructuredAfterStateHash(ActionRecord action) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Expected O, but got Unknown if (action.ActionKind == "configure-building") { GameCallResult gameCallResult = _reader.InspectFactoryEntityOnMainThread(action.SessionId, new InspectFactoryEntityRequest { PlanetId = action.PlanetId, ObjectId = action.Plan.EntityId }); if (!(action.Plan.ConfigureMode == "logistics-station-storage") && !(action.Plan.ConfigureMode == "logistics-station-belt") && !(action.Plan.ConfigureMode == "logistics-station-charge")) { FactoryEntitySnapshot? value = gameCallResult.Value; if (value == null) { return null; } return value.StateHash; } FactoryEntitySnapshot? value2 = gameCallResult.Value; if (value2 == null) { return null; } LogisticsStationSnapshot logisticsStation = value2.LogisticsStation; if (logisticsStation == null) { return null; } return logisticsStation.ConfigurationStateHash; } if (action.ActionKind == "build" && action.TargetObjectIds.Count > 0) { List list = new List { action.Plan.BuildKind, action.TargetObjectIds.Count }; foreach (int targetObjectId in action.TargetObjectIds) { GameCallResult gameCallResult2 = _reader.InspectFactoryEntityOnMainThread(action.SessionId, new InspectFactoryEntityRequest { PlanetId = action.PlanetId, ObjectId = targetObjectId }); FactoryEntitySnapshot? value3 = gameCallResult2.Value; list.Add((value3 != null) ? value3.StateHash : null); } return CanonicalStateHash.Combine("build", list.ToArray()); } return null; } private static bool CanTransferExactly(StorageComponent playerPackage, StorageComponent storage, string direction, int itemId, int count, out string rejection) { rejection = string.Empty; StorageComponent source = ((direction == "player-to-storage") ? playerPackage : storage); StorageComponent source2 = ((direction == "player-to-storage") ? storage : playerPackage); using StorageCopy storageCopy = new StorageCopy(source); using StorageCopy storageCopy2 = new StorageCopy(source2); int num = default(int); if (storageCopy.Value.TakeItem(itemId, count, ref num) != count) { rejection = $"The exact transfer source contains fewer than {count} of item {itemId}."; return false; } int num2 = default(int); if (storageCopy2.Value.AddItemStacked(itemId, count, num, ref num2) != count || num2 != 0) { rejection = $"The exact transfer destination cannot accept {count} of item {itemId}."; return false; } return true; } private static bool TryGetStorage(PlanetFactory factory, int entityId, out StorageComponent? storage) { storage = null; if (entityId <= 0 || entityId >= factory.entityCursor || entityId >= factory.entityPool.Length) { return false; } ref EntityData reference = ref factory.entityPool[entityId]; if (reference.id != entityId || reference.storageId <= 0 || reference.storageId >= factory.factoryStorage.storageCursor || reference.storageId >= factory.factoryStorage.storagePool.Length) { return false; } storage = factory.factoryStorage.storagePool[reference.storageId]; if (storage != null && storage.id == reference.storageId) { return storage.entityId == entityId; } return false; } private static List GetFreePortPoints(PlanetFactory factory, FactoryEntitySnapshot snapshot, bool requireOutput) { //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) List list = new List(); if (snapshot.ObjectId <= 0 || snapshot.ObjectId >= factory.entityCursor) { return list; } ref EntityData reference = ref factory.entityPool[snapshot.ObjectId]; ItemProto val = ((ProtoSet)(object)LDB.items).Select((int)reference.protoId); bool flag = default(bool); int num3 = default(int); if (val != null && val.prefabDesc?.isBelt == true) { int num = ((!requireOutput) ? 1 : 0); int num2 = default(int); factory.ReadObjectConn(snapshot.ObjectId, num, ref flag, ref num2, ref num3); if (num2 == 0) { Quaternion val2 = Quaternion.AngleAxis(reference.tilt, reference.rot * Vector3.forward) * reference.rot; if (!requireOutput) { val2 *= Quaternion.Euler(0f, 180f, 0f); } list.Add(new EndpointPoint(snapshot.ObjectId, num, new Pose(reference.pos, val2))); } return list; } Pose[] array = val?.prefabDesc?.portPoses ?? Array.Empty(); int num4 = default(int); for (int i = 0; i < array.Length; i++) { factory.ReadObjectConn(snapshot.ObjectId, i, ref flag, ref num4, ref num3); if (num4 == 0) { Pose transformedBy = ((Pose)(ref array[i])).GetTransformedBy(new Pose(reference.pos, reference.rot)); list.Add(new EndpointPoint(snapshot.ObjectId, i, transformedBy)); } } return list; } private static List GetInserterEndpointPoints(PlanetFactory factory, FactoryEntitySnapshot snapshot) { //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_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010d: 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_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) List list = new List(); if (snapshot.ObjectId <= 0 || snapshot.ObjectId >= factory.entityCursor) { return list; } ref EntityData reference = ref factory.entityPool[snapshot.ObjectId]; ItemProto val = ((ProtoSet)(object)LDB.items).Select((int)reference.protoId); if (val?.prefabDesc == null) { return list; } if (val.prefabDesc.isBelt) { Quaternion val2 = Quaternion.AngleAxis(reference.tilt, reference.rot * Vector3.forward) * reference.rot; Quaternion[] array = (Quaternion[])(object)new Quaternion[4] { Quaternion.identity, Quaternion.Euler(0f, 90f, 0f), Quaternion.Euler(0f, 180f, 0f), Quaternion.Euler(0f, -90f, 0f) }; foreach (Quaternion val3 in array) { list.Add(new EndpointPoint(snapshot.ObjectId, -1, new Pose(reference.pos, val2 * val3))); } return list; } Pose[] array2 = val.prefabDesc.slotPoses ?? Array.Empty(); List list2 = new List(); bool flag = default(bool); int num = default(int); int i = default(int); for (int j = 0; j < array2.Length; j++) { factory.ReadObjectConn(snapshot.ObjectId, j, ref flag, ref num, ref i); if (num != 0) { list2.Add(j); } } foreach (int item in BuildConnectionSlots.SelectAvailable(array2.Length, (IEnumerable)list2)) { Pose transformedBy = ((Pose)(ref array2[item])).GetTransformedBy(new Pose(reference.pos, reference.rot)); list.Add(new EndpointPoint(snapshot.ObjectId, item, transformedBy)); } return list; } private static string BuildEndpointHash(FactoryEntitySnapshot snapshot) { return CanonicalStateHash.FactoryEndpoint(snapshot); } private static string BuildPlanFingerprint(BuildPreparation preparation) { List list = new List { preparation.Kind, preparation.ResourceNodeId, preparation.SourceObjectId, preparation.DestinationObjectId, preparation.Steps.Count }; foreach (BuildStepPlan step in preparation.Steps) { step.AppendFingerprint(list); } return CanonicalStateHash.Combine("build-steps", list.ToArray()); } private static bool BuildStepsEqual(IReadOnlyList expected, IReadOnlyList actual) { if (expected.Count != actual.Count) { return false; } for (int i = 0; i < expected.Count; i++) { if (!expected[i].EquivalentTo(actual[i])) { return false; } } return true; } private static bool PreviewsExactlyMatch(IReadOnlyList plan, IReadOnlyList previews) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) if (plan.Count != previews.Count) { return false; } for (int i = 0; i < previews.Count; i++) { if ((int)previews[i].condition != 0 || previews[i].coverObjId != 0 || !plan[i].EquivalentTo(BuildStepPlan.FromPreview(plan[i], previews[i]))) { return false; } } return true; } private static List CreateLinkedPreviews(IReadOnlyList steps, ItemProto item) { List list = steps.Select((BuildStepPlan step) => CreatePreview(step, item)).ToList(); for (int num = 0; num < steps.Count; num++) { if (steps[num].InputStepIndex >= 0) { list[num].input = list[steps[num].InputStepIndex]; } if (steps[num].OutputStepIndex >= 0) { list[num].output = list[steps[num].OutputStepIndex]; } } return list; } private static BuildPreview CreatePreview(BuildStepPlan step, ItemProto item) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_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_003c: 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_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0084: 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_009c: 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_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Expected O, but got Unknown BuildPreview val = new BuildPreview { item = item, desc = item.prefabDesc, lpos = step.Position, lpos2 = step.Position2, lrot = step.Rotation, lrot2 = step.Rotation2, tilt = step.Tilt, inputObjId = step.InputObjectId, outputObjId = step.OutputObjectId, inputFromSlot = step.InputFromSlot, inputToSlot = step.InputToSlot, outputFromSlot = step.OutputFromSlot, outputToSlot = step.OutputToSlot, inputOffset = step.InputOffset, outputOffset = step.OutputOffset, condition = (EBuildCondition)0, isConnNode = step.IsConnectionNode, needModel = false }; if (step.Parameters.Count > 0) { val.parameters = step.Parameters.ToArray(); val.paramCount = val.parameters.Length; } return val; } private static bool BuildUiIsIdle(Player player) { PlayerAction_Build val = player.controller?.actionBuild; if (val != null && !val.active && val.templatePreviews.Count == 0 && ((BuildTool)val.clickTool).buildPreviews.Count == 0 && ((BuildTool)val.pathTool).buildPreviews.Count == 0) { return ((BuildTool)val.inserterTool).buildPreviews.Count == 0; } return false; } private static int FindBuiltEntityExcluding(PlanetFactory factory, int itemId, Vector3 position, IReadOnlyCollection preexistingEntityIds, IReadOnlyCollection alreadySelectedEntityIds) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) List list = new List(); int num = Math.Min(factory.entityCursor, factory.entityPool.Length); for (int i = 1; i < num; i++) { ref EntityData reference = ref factory.entityPool[i]; if (reference.id == i && reference.protoId == itemId) { Vector3 val = reference.pos - position; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude < 0.09f) { list.Add(new BuildEntityCandidate(i, sqrMagnitude)); } } } return BuildEntityAttribution.SelectNearestNewCandidate((IEnumerable)list, preexistingEntityIds, alreadySelectedEntityIds, 0.09f); } private static void CaptureBuiltEntityIds(PlanetFactory factory, int itemId, Vector3 position, ISet destination) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) int num = Math.Min(factory.entityCursor, factory.entityPool.Length); for (int i = 1; i < num; i++) { ref EntityData reference = ref factory.entityPool[i]; if (reference.id == i && reference.protoId == itemId) { Vector3 val = reference.pos - position; if (((Vector3)(ref val)).sqrMagnitude < 0.09f) { destination.Add(i); } } } } private static Vector3 ProjectTangent(Vector3 direction, Vector3 surfacePosition) { //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_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: 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_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) Vector3 normalized = ((Vector3)(ref surfacePosition)).normalized; return direction - normalized * Vector3.Dot(direction, normalized); } private static Vector3Snapshot Snapshot(Vector3 value) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown return new Vector3Snapshot { X = value.x, Y = value.y, Z = value.z }; } private GameCallResult PrepareRefuelPlanOnMainThread(string? requestedSessionId, PrepareRefuelRequest request) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown //IL_0280: Unknown result type (might be due to invalid IL or missing references) //IL_0285: Unknown result type (might be due to invalid IL or missing references) //IL_0291: Unknown result type (might be due to invalid IL or missing references) //IL_02a6: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Unknown result type (might be due to invalid IL or missing references) //IL_02c2: Expected O, but got Unknown CommonPrepareResult commonPrepareResult = ValidatePrepareCommon(requestedSessionId, request.PlanetId, request.StateHashVersion); if (commonPrepareResult.Error != null) { return GameCallResult.Failed(commonPrepareResult.Error); } if (request.ItemId <= 0 || request.Count <= 0) { return InvalidPlan("Fuel item and count must be positive."); } GameCallResult playerStateOnMainThread = _reader.GetPlayerStateOnMainThread(requestedSessionId, new LocalPlanetRequest { PlanetId = request.PlanetId }); if (!playerStateOnMainThread.Success || playerStateOnMainThread.Value == null) { return GameCallResult.Failed(playerStateOnMainThread.Error); } if (!string.Equals(request.ExpectedPlayerStateHash, playerStateOnMainThread.Value.StateHash, StringComparison.Ordinal)) { return StalePlan("Player inventory or mecha fuel state changed after inspection."); } Player mainPlayer = GameMain.mainPlayer; ItemProto val = ((ProtoSet)(object)LDB.items).Select(request.ItemId); if (((mainPlayer != null) ? mainPlayer.package : null) == null || mainPlayer.mecha?.reactorStorage == null) { return NotReadyPlan("The player package or mecha fuel chamber is unavailable."); } if (val == null || val.HeatValue <= 0 || val.FuelType <= 0 || request.ItemId >= StorageComponent.itemIsFuel.Length || !StorageComponent.itemIsFuel[request.ItemId]) { return GameCallResult.Failed(BridgeError.Create("INVALID_REQUEST", "The requested runtime item is not accepted as ordinary mecha fuel.", false, "Inspect player inventory and choose an item whose current ItemProto has positive HeatValue and FuelType.")); } if (!TryResolveRefuelTransfer(mainPlayer, request.ItemId, out int gridIndex, out int exactCount, out string rejection)) { return GameCallResult.Failed(BridgeError.Create((rejection.IndexOf("package", StringComparison.OrdinalIgnoreCase) >= 0) ? "INVENTORY_INSUFFICIENT" : "INVENTORY_FULL", rejection, true, "Acquire ordinary fuel or wait for fuel-chamber capacity, then inspect and prepare again.")); } if (request.Count != exactCount) { return GameCallResult.Failed(BridgeError.Create("INVALID_REQUEST", $"DSP's native one-stack fuel transfer will move exactly {exactCount} item(s) into grid {gridIndex}; the requested count was {request.Count}.", true, "Use the exact count reported by current package and fuel-grid capacity, then prepare again.")); } string text = CanonicalStateHash.PlayerAction(playerStateOnMainThread.Value); string expectedStateHash = CanonicalStateHash.Combine("refuel", new object[6] { _sessions.SessionId, request.PlanetId, text, request.ItemId, request.Count, gridIndex }); NormalActionPlanPayload payload = NormalActionPlanPayload.Refuel(_sessions.SessionId, request.PlanetId, expectedStateHash, text, request.ItemId, request.Count, gridIndex); GameCallResult gameCallResult = AddPreparedPlan(payload, commonPrepareResult.Session, 1L, "Mecha.AutoReplenishFuel moves the exact prepared stack from the player package into the bound fuel grid, and combined item count is conserved."); if (gameCallResult.Success && gameCallResult.Value != null) { gameCallResult.Value.ItemBudget.Add(new ActionItemBudget { ItemId = request.ItemId, Name = (((Proto)val).name ?? string.Empty), Count = request.Count, Direction = "player-to-mecha-fuel" }); } return gameCallResult; } private BridgeError? RevalidateRefuelOnMainThread(NormalActionPlanPayload plan) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown GameCallResult playerStateOnMainThread = _reader.GetPlayerStateOnMainThread(plan.SessionId, new LocalPlanetRequest { PlanetId = plan.PlanetId }); if (!playerStateOnMainThread.Success || playerStateOnMainThread.Value == null) { return playerStateOnMainThread.Error; } if (!string.Equals(CanonicalStateHash.PlayerAction(playerStateOnMainThread.Value), plan.PlayerStateHash, StringComparison.Ordinal)) { return Stale("Player inventory or mecha fuel state changed after refuel preparation."); } if (!TryResolveRefuelTransfer(GameMain.mainPlayer, plan.FuelItemId, out int gridIndex, out int exactCount, out string _) || gridIndex != plan.FuelGrid || exactCount != plan.Count) { return Stale("The exact native fuel transfer count or destination grid changed after prepare."); } return null; } private static void ExecuteRefuelOnMainThread(ActionRecord action) { Player val = GameMain.mainPlayer ?? throw new InvalidOperationException("The player is unavailable."); NormalActionPlanPayload plan = action.Plan; StorageComponent obj = val.mecha?.reactorStorage ?? throw new InvalidOperationException("The mecha fuel chamber is unavailable."); int num = default(int); int itemCount = val.package.GetItemCount(plan.FuelItemId, ref num); int num2 = default(int); int itemCount2 = obj.GetItemCount(plan.FuelItemId, ref num2); if (!val.mecha.AutoReplenishFuel(plan.FuelItemId, plan.FuelGrid)) { throw new InvalidOperationException("DSP's native mecha fuel transfer rejected the prepared stack."); } int num3 = default(int); int itemCount3 = val.package.GetItemCount(plan.FuelItemId, ref num3); int num4 = default(int); int itemCount4 = obj.GetItemCount(plan.FuelItemId, ref num4); if (itemCount - itemCount3 != plan.Count || itemCount4 - itemCount2 != plan.Count || itemCount + itemCount2 != itemCount3 + itemCount4 || num + num2 != num3 + num4) { throw new InvalidOperationException("Mecha refuel readback did not prove exact bilateral item conservation."); } action.TargetItemId = plan.FuelItemId; action.BeforeTargetAmount = itemCount2; action.AfterTargetAmount = itemCount4; action.Message = $"DSP's native mecha fuel transfer conserved item {plan.FuelItemId}: player {itemCount}->{itemCount3}, fuel chamber {itemCount2}->{itemCount4}."; action.State = "completed"; action.Terminal = true; action.Succeeded = true; action.CompletedAtGameTick = GameMain.gameTick; action.AfterInventory = CaptureInventory(val); action.AfterStateHash = CanonicalStateHash.Combine("refuel", new object[7] { itemCount3, itemCount4, num3, num4, plan.FuelItemId, plan.Count, plan.FuelGrid }); } private static bool TryResolveRefuelTransfer(Player? player, int itemId, out int gridIndex, out int exactCount, out string rejection) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Invalid comparison between Unknown and I4 //IL_00bf: 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_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) gridIndex = -1; exactCount = 0; rejection = string.Empty; StorageComponent val = ((player != null) ? player.package : null); StorageComponent val2 = ((player == null) ? null : player.mecha?.reactorStorage); if (val == null || val2?.grids == null || (int)val2.type != 1) { rejection = "The player package or native fuel-typed chamber is unavailable."; return false; } int itemCount = val.GetItemCount(itemId); if (itemCount <= 0) { rejection = "The player package contains no requested fuel item."; return false; } if (itemId >= StorageComponent.itemStackCount.Length || itemId >= StorageComponent.itemIsFuel.Length || !StorageComponent.itemIsFuel[itemId]) { rejection = "The runtime item is not accepted by the current fuel-storage type."; return false; } int num = StorageComponent.itemStackCount[itemId]; int num2 = Math.Min(val2.size, val2.grids.Length); for (int i = 0; i < num2; i++) { GRID val3 = val2.grids[i]; int num3 = ((val3.stackSize > 0) ? val3.stackSize : num); int num4 = Math.Min(num, num3 - val3.count); if (val3.itemId == itemId && num4 > 0) { gridIndex = i; exactCount = Math.Min(itemCount, num4); return exactCount > 0; } } for (int j = 0; j < num2; j++) { GRID val4 = val2.grids[j]; if (val4.itemId <= 0 && (val4.filter <= 0 || val4.filter == itemId)) { int val5 = ((val4.filter > 0 && val4.stackSize > 0) ? val4.stackSize : num); gridIndex = j; exactCount = Math.Min(itemCount, Math.Min(num, val5)); return exactCount > 0; } } rejection = "The mecha fuel chamber has no compatible free stack capacity."; return false; } private GameCallResult PrepareSavePlanOnMainThread(string? requestedSessionId, PrepareSaveRequest request) { CommonPrepareResult commonPrepareResult = ValidatePrepareCommon(requestedSessionId, request.PlanetId, request.StateHashVersion); if (commonPrepareResult.Error != null) { return GameCallResult.Failed(commonPrepareResult.Error); } if (request.ExpectedRevision != commonPrepareResult.Session.Revision) { return StalePlan("The owned session revision changed after inspection."); } if (!string.IsNullOrWhiteSpace(commonPrepareResult.Session.SaveName)) { GameData data = GameMain.data; if (((data != null) ? data.localLoadedPlanetFactory : null) != null) { string expectedStateHash = CanonicalStateHash.Combine("save", new object[4] { _sessions.SessionId, request.PlanetId, request.ExpectedRevision, commonPrepareResult.Session.SaveName }); NormalActionPlanPayload payload = NormalActionPlanPayload.Save(_sessions.SessionId, request.PlanetId, expectedStateHash, commonPrepareResult.Session.SaveName, request.ExpectedRevision); return AddPreparedPlan(payload, commonPrepareResult.Session, 1L, "GameSave.SaveCurrentGame returns true for the exact high-entropy save name owned by this session, and the saved game tick is recorded."); } } return NotReadyPlan("The exact Spherewright-owned save identity or local factory is unavailable."); } private BridgeError? RevalidateSaveOnMainThread(NormalActionPlanPayload plan) { SessionState val = _sessions.CaptureOnMainThread(); if (val.OwnedBySpherewright && val.LocalPlanetId == plan.PlanetId && val.Revision == plan.SaveExpectedRevision && string.Equals(val.SaveName, plan.SaveOwnedName, StringComparison.Ordinal)) { GameData data = GameMain.data; if (((data != null) ? data.localLoadedPlanetFactory : null) != null) { return null; } } return Stale("The owned save identity, planet, factory, or session revision changed after prepare."); } private void ExecuteSaveOnMainThread(ActionRecord action) { if (!_sessions.TrySaveOwnedWorldNowOnMainThread(out string error)) { throw new InvalidOperationException(error ?? "DSP's normal save API did not confirm success."); } SessionState val = _sessions.CaptureOnMainThread(); if (!val.LastOwnedSaveGameTick.HasValue) { throw new InvalidOperationException("The owned save completed without a recorded game tick."); } action.State = "completed"; action.Terminal = true; action.Succeeded = true; action.CompletedAtGameTick = GameMain.gameTick; action.Message = $"DSP's normal save API confirmed the exact owned save at game tick {val.LastOwnedSaveGameTick.Value}."; action.AfterInventory = CaptureInventory(GameMain.mainPlayer); action.AfterStateHash = CanonicalStateHash.Combine("save", new object[4] { action.SessionId, action.PlanetId, val.LastOwnedSaveGameTick.Value, val.Revision }); } } internal sealed class OwnedWorldResumeCoordinator { private sealed class OwnedWorldResumePlanPayload { public OwnedWorldResumeTicket Ticket { get; } public OwnedWorldResumeSourceKind ResumeSource { get; } public string Fingerprint { get; } public OwnedWorldResumePlanPayload(OwnedWorldResumeTicket ticket, OwnedWorldResumeSourceKind resumeSource) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) Ticket = ticket; ResumeSource = resumeSource; Fingerprint = CanonicalStateHash.Combine("resume-owned-world", new object[12] { ticket.ResumeToken, ticket.OwnedSaveName, ticket.SourceSessionId, ticket.SourceProcessId, ticket.SourceBridgeInstanceId, ticket.GameVersion, ticket.ExpectedPlanetId, ticket.MinimumGameTick, ticket.QuarantineActionId, ticket.IssuedAtUtc, ticket.ExpiresAtUtc, resumeSource }); } } private sealed class OwnedWorldResumeAction { public string ActionId { get; set; } = string.Empty; public OwnedWorldResumeTicket Ticket { get; set; } public OwnedWorldResumeSourceKind ResumeSource { get; set; } } private const string IdempotencyScope = "resume-owned-world"; private readonly bool _writesConfigured; private readonly GameSessionTracker _sessions; private readonly OwnedWorldResumeTicketStore _tickets; private readonly PreparedPlanStore _plans; private readonly IdempotencyCache _idempotency; private readonly Dictionary _actions = new Dictionary(StringComparer.Ordinal); public OwnedWorldResumeCoordinator(bool writesConfigured, int planLifetimeSeconds, int idempotencyRetentionMinutes, int idempotencyCapacity, GameSessionTracker sessions, OwnedWorldResumeTicketStore tickets) { _writesConfigured = writesConfigured; _sessions = sessions; _tickets = tickets; _plans = new PreparedPlanStore(TimeSpan.FromSeconds(planLifetimeSeconds), 4, (Func)null); _idempotency = new IdempotencyCache(idempotencyCapacity, TimeSpan.FromMinutes(idempotencyRetentionMinutes), (Func)null); } public GameCallResult PrepareOnMainThread(PrepareOwnedWorldResumeRequest request) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0117: 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) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Expected O, but got Unknown //IL_0153: Expected O, but got Unknown BridgeError val = TestWorldCoordinator.ValidateMainMenuReady(); if (val != null) { return GameCallResult.Failed(val); } if (!_tickets.TryGetActiveTicket(request.ResumeToken, out OwnedWorldResumeTicket ticket, out string rejection) || ticket == null) { return GameCallResult.Failed(BridgeError.Create("SESSION_NOT_OWNED", rejection, false, "Use only the one-time restartResumeToken issued for the exact quarantined Spherewright-owned session.")); } if (!TryResolveResumeSource(ticket, out OwnedWorldResumeSourceKind resumeSource, out string rejection2)) { return GameCallResult.Failed(BridgeError.Create("STALE_STATE", rejection2, false, "Keep the ticket and inspect the exact normal shutdown or latest healthy owned-save evidence.")); } OwnedWorldResumePlanPayload ownedWorldResumePlanPayload = new OwnedWorldResumePlanPayload(ticket, resumeSource); PreparedPlan val2; try { val2 = _plans.Add(ownedWorldResumePlanPayload.Fingerprint, ownedWorldResumePlanPayload); } catch (InvalidOperationException) { return GameCallResult.Failed(BridgeError.Create("SERVER_BUSY", "Too many owned-world resume plans are active.", true, "Wait for old plans to expire, then prepare the one-time resume again.")); } List list = new List(); if (!_writesConfigured) { list.Add(new WriteBlocker { Code = "WRITES_DISABLED", Message = "Owned-world resume is blocked because Safety.AllowWrites is false." }); } return GameCallResult.Succeeded(new PreparedOwnedWorldResumePlan { Prepared = true, PlanToken = val2.Token, ExpiresAtUtc = val2.ExpiresAtUtc, ExpectedPlanetId = ticket.ExpectedPlanetId, MinimumGameTick = ticket.MinimumGameTick, CommitAllowedNow = (list.Count == 0), CommitBlockers = list, CompletionCondition = (string.IsNullOrWhiteSpace(ticket.QuarantineActionId) ? "A healthy planned restart loads only the exact primary owned save named inside the protected ticket after its header proves the minimum game tick; adoption still requires the embedded high-entropy owned name, planet, and peaceful mode. Sandbox state and resource multiplier are preserved and reported but do not gate adoption." : "Quarantine recovery loads only the fresh fixed LastExit slot after its header proves the minimum game tick; adoption still requires the embedded high-entropy owned name, planet, and peaceful mode. Sandbox state and resource multiplier are preserved and reported but do not gate adoption.") }); } public GameCallResult CommitOnMainThread(CommitOwnedWorldResumeRequest request) { //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Invalid comparison between Unknown and I4 //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_0254: Unknown result type (might be due to invalid IL or missing references) //IL_0261: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_027c: Expected O, but got Unknown if (!Guid.TryParse(request.IdempotencyKey, out var _)) { return GameCallResult.Failed(BridgeError.Create("INVALID_REQUEST", "A UUID idempotency key is required.", false, "Generate one UUID and reuse it for retries of this exact resume commit.")); } string text = "commit-resume-owned-world|" + request.PlanToken; OwnedWorldResumeResult result2 = default(OwnedWorldResumeResult); bool flag = default(bool); if (_idempotency.TryGet("resume-owned-world", request.IdempotencyKey, text, ref result2, ref flag)) { return GameCallResult.Succeeded(CloneAsReplay(result2)); } if (flag) { return GameCallResult.Failed(BridgeError.Create("IDEMPOTENCY_CONFLICT", "The idempotency key is already bound to a different owned-world resume request.", false, "Reuse it only for the original resume commit.")); } if (!_writesConfigured) { return GameCallResult.Failed(BridgeError.Create("WRITES_DISABLED", "Owned-world resume is blocked because Safety.AllowWrites is false.", false, "Enable writes, restart DSP at the main menu, and prepare the one-time resume again.")); } if (!_idempotency.HasCapacity("resume-owned-world")) { return GameCallResult.Failed(BridgeError.Create("IDEMPOTENCY_CAPACITY_EXCEEDED", "The idempotency cache has no capacity for another owned-world resume action.", false, "Restart the Plugin at the main menu before preparing the one-time resume again; no LastExit load was started.")); } PreparedPlan val = default(PreparedPlan); bool flag2 = default(bool); if (!_plans.TryTake(request.PlanToken, ref val, ref flag2) || val == null) { return GameCallResult.Failed(BridgeError.Create(flag2 ? "PLAN_EXPIRED" : "PLAN_NOT_FOUND", flag2 ? "The owned-world resume plan expired." : "The owned-world resume plan was not found or was already consumed.", true, "Prepare the exact one-time resume again and commit it once.")); } BridgeError val2 = TestWorldCoordinator.ValidateMainMenuReady(); OwnedWorldResumePlanPayload payload = val.Payload; string rejection = "The one-time resume ticket changed after prepare."; if (val2 != null || !_tickets.TryGetActiveTicket(payload.Ticket.ResumeToken, out OwnedWorldResumeTicket ticket, out string _) || ticket == null || !TryResolveResumeSource(ticket, out OwnedWorldResumeSourceKind resumeSource, out rejection) || resumeSource != payload.ResumeSource || !string.Equals(new OwnedWorldResumePlanPayload(ticket, resumeSource).Fingerprint, payload.Fingerprint, StringComparison.Ordinal)) { return GameCallResult.Failed(BridgeError.Create("STALE_STATE", ((val2 != null) ? val2.Message : null) ?? rejection, false, "Do not load a save; return to an idle main menu and prepare from the exact current ticket.")); } OwnedWorldResumeAction ownedWorldResumeAction = new OwnedWorldResumeAction { ActionId = Guid.NewGuid().ToString("D"), Ticket = ticket, ResumeSource = resumeSource }; try { _sessions.ExpectNextSessionToBeResumed(ticket); DSPGame.StartGame(((int)resumeSource == 1) ? GameSave.LastExit : ticket.OwnedSaveName); } catch (Exception ex) { _sessions.CancelExpectedResumedSession(); return GameCallResult.Failed(BridgeError.Create("ACTION_FAILED", "DSP rejected the exact protected owned-world resume through its normal loader (" + ex.GetType().Name + ").", false, "Inspect the local Spherewright and Unity logs; do not load another save.")); } OwnedWorldResumeResult val3 = new OwnedWorldResumeResult { ActionId = ownedWorldResumeAction.ActionId, Accepted = true, IdempotentReplay = false, State = "waiting_for_game" }; if (!_idempotency.TryAdd("resume-owned-world", request.IdempotencyKey, text, val3)) { return GameCallResult.Failed(BridgeError.Create("IDEMPOTENCY_CAPACITY_EXCEEDED", "The idempotency cache reached capacity after DSP accepted the resume.", false, "Do not retry with a new key; poll session state and the returned action ID.")); } _actions[ownedWorldResumeAction.ActionId] = ownedWorldResumeAction; return GameCallResult.Succeeded(val3); } public bool TryGetActionResultOnMainThread(string actionId, out ActionResultSnapshot? result) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0033: 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_0049: 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_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Invalid comparison between Unknown and I4 //IL_0073: Expected O, but got Unknown //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Invalid comparison between Unknown and I4 if (!_actions.TryGetValue(actionId, out OwnedWorldResumeAction value)) { result = null; return false; } SessionState val = _sessions.CaptureOnMainThread(); result = new ActionResultSnapshot { ActionId = value.ActionId, ActionKind = "resume-owned-game", State = "waiting_for_game", Terminal = false, Succeeded = false, Message = (((int)value.ResumeSource == 1) ? "DSP accepted the fixed LastExit load; Spherewright is validating the one-time owned-world provenance proof." : "DSP accepted the exact ticket-bound primary owned save because LastExit was not refreshed; Spherewright is validating the same one-time provenance proof.") }; if (val.OwnedBySpherewright && val.LocalPlanetId == value.Ticket.ExpectedPlanetId && val.GameTick >= value.Ticket.MinimumGameTick) { result.SessionId = val.SessionId; result.PlanetId = val.LocalPlanetId; if (string.Equals(val.OwnedSaveState, "saved", StringComparison.Ordinal)) { result.State = "completed"; result.Terminal = true; result.Succeeded = true; result.Message = (((int)value.ResumeSource == 1) ? "The exact owned LastExit payload passed provenance checks and was resaved under its high-entropy Spherewright name." : "The exact ticket-bound primary owned save passed provenance checks and was resaved under the same high-entropy Spherewright name."); } else { result.Message = "The exact owned payload was adopted and is waiting for its high-entropy normal save to complete."; } } else if (!string.IsNullOrWhiteSpace(_sessions.ResumeAdoptionError)) { result.State = "action_failed"; result.Terminal = true; result.Message = _sessions.ResumeAdoptionError; } return true; } private static bool TryResolveResumeSource(OwnedWorldResumeTicket ticket, out OwnedWorldResumeSourceKind resumeSource, out string rejection) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected I4, but got Unknown resumeSource = (OwnedWorldResumeSourceKind)0; rejection = string.Empty; if (IsLiveDspProcess(ticket.SourceProcessId)) { rejection = "The source DSP process is still running; no restart source can yet prove a completed shutdown."; return false; } TryReadSaveEvidence(GameSave.LastExit, out var writtenAtUtc, out var gameTick); TryReadSaveEvidence(ticket.OwnedSaveName, out var writtenAtUtc2, out var gameTick2); resumeSource = (OwnedWorldResumeSourceKind)(int)OwnedWorldResumeSourceSelector.Select(!string.IsNullOrWhiteSpace(ticket.QuarantineActionId), ticket.MinimumGameTick, ticket.IssuedAtUtc, writtenAtUtc, gameTick, writtenAtUtc2, gameTick2, TimeSpan.FromSeconds(2.0)); if ((int)resumeSource == 0) { rejection = (string.IsNullOrWhiteSpace(ticket.QuarantineActionId) ? "The exact ticket-bound primary owned save is not fresh enough or its header is older than the planned-restart minimum game tick." : "DSP's fixed LastExit slot is not fresh enough or its header is older than the quarantine-recovery minimum game tick."); return false; } return true; } private static void TryReadSaveEvidence(string saveName, out DateTimeOffset? writtenAtUtc, out long? gameTick) { writtenAtUtc = null; gameTick = null; try { string text = GameSave.SavePath(saveName); if (!string.IsNullOrWhiteSpace(text) && File.Exists(text)) { GameSaveHeader val = default(GameSaveHeader); GameSave.ReadHeader(saveName, false, ref val); if (val != null && val.gameTick >= 0) { writtenAtUtc = new DateTimeOffset(File.GetLastWriteTimeUtc(text), TimeSpan.Zero); gameTick = val.gameTick; } } } catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException || ex is ArgumentException || ex is NotSupportedException) { writtenAtUtc = null; gameTick = null; } } private static bool IsLiveDspProcess(int processId) { try { using Process process = Process.GetProcessById(processId); return !process.HasExited && string.Equals(process.ProcessName, "DSPGAME", StringComparison.OrdinalIgnoreCase); } catch (Exception ex) when (ex is ArgumentException || ex is InvalidOperationException || ex is Win32Exception) { return false; } } private static OwnedWorldResumeResult CloneAsReplay(OwnedWorldResumeResult result) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown return new OwnedWorldResumeResult { ActionId = result.ActionId, Accepted = result.Accepted, IdempotentReplay = true, State = result.State }; } } internal sealed class ResearchResultAutoAcknowledger { private readonly bool _enabled; private readonly ManualLogSource _logger; public ResearchResultAutoAcknowledger(bool enabled, ManualLogSource logger) { _enabled = enabled; _logger = logger ?? throw new ArgumentNullException("logger"); } public void UpdateOnMainThread() { if (_enabled) { UIResearchResultWindow val = UIRoot.instance?.uiGame?.researchResultTip; if (val != null && ((ManualBehaviour)val).active && val.ready) { val.FadeOut(); _logger.LogDebug((object)"Spherewright acknowledged a ready DSP research-result window through its native FadeOut flow."); } } } } internal sealed class SpherewrightClickBuildTool : BuildTool_Click { public bool SnapshotPlayerInventory(int additionalItemId = 0, int additionalItemCount = 0) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown if (((BuildTool)this).tmpPackage == null) { ((BuildTool)this).tmpPackage = new StorageComponent(((BuildTool)this).player.package.size); } if (((BuildTool)this).tmpPackage.size != ((BuildTool)this).player.package.size) { ((BuildTool)this).tmpPackage.SetSize(((BuildTool)this).player.package.size); } Array.Copy(((BuildTool)this).player.package.grids, ((BuildTool)this).tmpPackage.grids, ((BuildTool)this).tmpPackage.size); ((BuildTool)this).tmpInhandId = ((BuildTool)this).player.inhandItemId; ((BuildTool)this).tmpInhandCount = ((BuildTool)this).player.inhandItemCount; if (additionalItemId <= 0 || additionalItemCount <= 0) { return true; } int num = default(int); if (((BuildTool)this).tmpPackage.AddItemStacked(additionalItemId, additionalItemCount, 0, ref num) == additionalItemCount) { return num == 0; } return false; } public void ReleaseSnapshot() { StorageComponent tmpPackage = ((BuildTool)this).tmpPackage; if (tmpPackage != null) { tmpPackage.Free(); } ((BuildTool)this).tmpPackage = null; } } internal sealed class SpherewrightInserterBuildTool : BuildTool_Inserter { public bool SnapshotPlayerInventory() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown if (((BuildTool)this).tmpPackage == null) { ((BuildTool)this).tmpPackage = new StorageComponent(((BuildTool)this).player.package.size); } if (((BuildTool)this).tmpPackage.size != ((BuildTool)this).player.package.size) { ((BuildTool)this).tmpPackage.SetSize(((BuildTool)this).player.package.size); } Array.Copy(((BuildTool)this).player.package.grids, ((BuildTool)this).tmpPackage.grids, ((BuildTool)this).tmpPackage.size); ((BuildTool)this).tmpInhandId = ((BuildTool)this).player.inhandItemId; ((BuildTool)this).tmpInhandCount = ((BuildTool)this).player.inhandItemCount; return true; } public void ReleaseSnapshot() { StorageComponent tmpPackage = ((BuildTool)this).tmpPackage; if (tmpPackage != null) { tmpPackage.Free(); } ((BuildTool)this).tmpPackage = null; } } internal sealed class SpherewrightPathBuildTool : BuildTool_Path { public bool SnapshotPlayerInventory() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown if (((BuildTool)this).tmpPackage == null) { ((BuildTool)this).tmpPackage = new StorageComponent(((BuildTool)this).player.package.size); } if (((BuildTool)this).tmpPackage.size != ((BuildTool)this).player.package.size) { ((BuildTool)this).tmpPackage.SetSize(((BuildTool)this).player.package.size); } Array.Copy(((BuildTool)this).player.package.grids, ((BuildTool)this).tmpPackage.grids, ((BuildTool)this).tmpPackage.size); ((BuildTool)this).tmpInhandId = ((BuildTool)this).player.inhandItemId; ((BuildTool)this).tmpInhandCount = ((BuildTool)this).player.inhandItemCount; return true; } public void ReleaseSnapshot() { StorageComponent tmpPackage = ((BuildTool)this).tmpPackage; if (tmpPackage != null) { tmpPackage.Free(); } ((BuildTool)this).tmpPackage = null; } } internal sealed class TestWorldCoordinator { private sealed class TestWorldPlanPayload { public string SaveName { get; } public int GalaxySeed { get; } public int StarCount { get; } public string Fingerprint { get; } public TestWorldPlanPayload(string saveName, int galaxySeed, int starCount) { SaveName = saveName; GalaxySeed = galaxySeed; StarCount = starCount; Fingerprint = $"new-world|{saveName}|{galaxySeed}|{starCount}|peaceful|standard|resources-1x"; } } private const string IdempotencyScope = "new-game"; private readonly bool _writesConfigured; private readonly GameSessionTracker _sessions; private readonly PreparedPlanStore _plans; private readonly IdempotencyCache _idempotency; private readonly Dictionary _actions = new Dictionary(StringComparer.Ordinal); public TestWorldCoordinator(bool writesConfigured, int planLifetimeSeconds, int idempotencyRetentionMinutes, int idempotencyCapacity, GameSessionTracker sessions) { _writesConfigured = writesConfigured; _sessions = sessions; _plans = new PreparedPlanStore(TimeSpan.FromSeconds(planLifetimeSeconds), 16, (Func)null); _idempotency = new IdempotencyCache(idempotencyCapacity, TimeSpan.FromMinutes(idempotencyRetentionMinutes), (Func)null); } public GameCallResult PrepareOnMainThread(PrepareTestWorldRequest request) { //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Expected O, but got Unknown if (request.GalaxySeed < 0 || request.GalaxySeed > 99999999) { return GameCallResult.Failed(BridgeError.Create("INVALID_REQUEST", "Galaxy seed must be between 0 and 99999999.", false, "Choose an eight-digit non-negative seed.")); } if (request.StarCount < 20 || request.StarCount > 80) { return GameCallResult.Failed(BridgeError.Create("INVALID_REQUEST", "Star count must be between 20 and 80.", false, "Choose a supported star count.")); } BridgeError val = ValidateMainMenuReady(); if (val != null) { return GameCallResult.Failed(val); } string saveName = SpherewrightSaveNameFactory.CreateNewWorldName(DateTimeOffset.UtcNow, Guid.NewGuid()); TestWorldPlanPayload testWorldPlanPayload = new TestWorldPlanPayload(saveName, request.GalaxySeed, request.StarCount); PreparedPlan val2; try { val2 = _plans.Add(testWorldPlanPayload.Fingerprint, testWorldPlanPayload); } catch (InvalidOperationException) { return GameCallResult.Failed(BridgeError.Create("SERVER_BUSY", "Too many unconsumed new-world plans are active.", true, "Wait for existing plans to expire and retry.")); } PreparedTestWorldPlan val3 = new PreparedTestWorldPlan { PlanToken = val2.Token, ExpiresAtUtc = val2.ExpiresAtUtc, SaveName = saveName, GalaxySeed = request.GalaxySeed, StarCount = request.StarCount, ResourceMultiplier = 1f, PeacefulMode = true, SandboxMode = false, CommitAllowed = _writesConfigured }; val3.Warnings.Add("This plan creates a standard peaceful 1x world with DSP sandbox tools disabled."); if (!_writesConfigured) { val3.Warnings.Add("Commit is blocked because Safety.AllowWrites is false."); } return GameCallResult.Succeeded(val3); } public GameCallResult CommitOnMainThread(CommitTestWorldRequest request) { //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_018a: 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_019f: Expected O, but got Unknown //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_0245: Expected O, but got Unknown if (!Guid.TryParse(request.IdempotencyKey, out var _)) { return GameCallResult.Failed(BridgeError.Create("INVALID_REQUEST", "A UUID idempotency key is required.", false, "Generate one UUID and reuse it for retries of this exact commit.")); } string text = "commit-new-world|" + request.PlanToken; TestWorldCreationResult result2 = default(TestWorldCreationResult); bool flag = default(bool); if (_idempotency.TryGet("new-game", request.IdempotencyKey, text, ref result2, ref flag)) { return GameCallResult.Succeeded(CloneAsReplay(result2)); } if (flag) { return GameCallResult.Failed(BridgeError.Create("IDEMPOTENCY_CONFLICT", "The idempotency key is already bound to a different request.", false, "Use the original request or generate a new idempotency key.")); } if (!_writesConfigured) { return GameCallResult.Failed(BridgeError.Create("WRITES_DISABLED", "New-world creation is blocked because Safety.AllowWrites is false.", false, "Enable writes in the Spherewright Plugin config, restart DSP, prepare a new plan, and retry.")); } if (!_idempotency.HasCapacity("new-game")) { return GameCallResult.Failed(BridgeError.Create("IDEMPOTENCY_CAPACITY_EXCEEDED", "The idempotency cache has no capacity for another new-world action.", false, "Restart the Plugin before preparing another new-world action; no game load was started.")); } PreparedPlan val = default(PreparedPlan); bool flag2 = default(bool); if (!_plans.TryTake(request.PlanToken, ref val, ref flag2)) { return GameCallResult.Failed(BridgeError.Create(flag2 ? "PLAN_EXPIRED" : "PLAN_NOT_FOUND", flag2 ? "The new-world plan expired." : "The new-world plan was not found or was already consumed.", true, "Prepare a fresh new-world plan and commit it once.")); } if (ValidateMainMenuReady() != null) { return GameCallResult.Failed(BridgeError.Create("ACTION_REJECTED", "Game or main-menu loader state changed after prepare; new-world creation is no longer safe to start.", true, "Wait for the main menu to become idle, then prepare a fresh plan.")); } TestWorldPlanPayload payload = val.Payload; try { _sessions.ExpectNextSessionToBeOwned(payload.SaveName); GameDesc val2 = new GameDesc(); val2.SetForNewGame(UniverseGen.algoVersion, payload.GalaxySeed, payload.StarCount, 1, 1f); val2.isPeaceMode = true; val2.isSandboxMode = false; val2.goalLevel = (EGoalLevel)1; ((CombatSettings)(ref val2.combatSettings)).SetDefault(); DSPGame.StartGameSkipPrologue(val2); } catch (Exception ex) { _sessions.CancelExpectedOwnedSession(); return GameCallResult.Failed(BridgeError.Create("ACTION_FAILED", "The game rejected ordinary peaceful new-world creation (" + ex.GetType().Name + ").", false, "Inspect the local Spherewright and Unity logs before preparing another plan.")); } TestWorldCreationResult val3 = new TestWorldCreationResult { ActionId = Guid.NewGuid().ToString("D"), Accepted = true, IdempotentReplay = false, SaveName = payload.SaveName, GalaxySeed = payload.GalaxySeed, StarCount = payload.StarCount, State = "waiting_for_world" }; if (!_idempotency.TryAdd("new-game", request.IdempotencyKey, text, val3)) { return GameCallResult.Failed(BridgeError.Create("IDEMPOTENCY_CAPACITY_EXCEEDED", "The idempotency cache reached its configured capacity after the action started.", false, "Do not retry with a new key; poll session state for the accepted world creation.")); } _actions[val3.ActionId] = val3; return GameCallResult.Succeeded(val3); } public GameCallResult GetActionResultOnMainThread(GetActionResultRequest request) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Expected O, but got Unknown if (string.IsNullOrWhiteSpace(request.ActionId) || !_actions.TryGetValue(request.ActionId, out TestWorldCreationResult value)) { return GameCallResult.Failed(BridgeError.Create("ACTION_NOT_FOUND", "The requested action is not retained by this Plugin process.", false, "Use the actionId returned by a commit accepted during the current Plugin process.")); } SessionState val = _sessions.CaptureOnMainThread(); ActionResultSnapshot val2 = new ActionResultSnapshot { ActionId = value.ActionId, ActionKind = "new-game", State = "executing", Terminal = false, Succeeded = false }; if (val.OwnedBySpherewright && string.Equals(val.SaveName, value.SaveName, StringComparison.Ordinal)) { val2.SessionId = val.SessionId; val2.PlanetId = val.LocalPlanetId; if (string.Equals(val.OwnedSaveState, "saved", StringComparison.Ordinal)) { val2.State = "completed"; val2.Terminal = true; val2.Succeeded = true; val2.Message = "The ordinary peaceful world loaded and was saved under its Spherewright-owned name."; } else if (string.Equals(val.OwnedSaveState, "save_failed", StringComparison.Ordinal)) { val2.State = "failed"; val2.Terminal = true; val2.Message = "The ordinary world loaded, but its initial owned save could not be persisted."; } else { val2.Message = "The owned ordinary world is loading or waiting for its initial save."; } } else { val2.Message = "DSP accepted the new-game action and the Plugin is waiting to adopt the exact GameData instance."; } return GameCallResult.Succeeded(val2); } private static TestWorldCreationResult CloneAsReplay(TestWorldCreationResult result) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected O, but got Unknown return new TestWorldCreationResult { ActionId = result.ActionId, Accepted = result.Accepted, IdempotentReplay = true, SaveName = result.SaveName, GalaxySeed = result.GalaxySeed, StarCount = result.StarCount, State = result.State }; } internal static BridgeError? ValidateMainMenuReady() { if ((GameMain.data != null || GameMain.isRunning || (Object)(object)DSPGame.Game != (Object)null) && !DSPGame.IsMenuDemo) { return BridgeError.Create("ACTION_REJECTED", "A Spherewright-owned new world can only be created with no loaded or loading game.", false, "Return to the main menu without loading a save, then retry."); } ModelProto[] array = LDB.models?.modelArray; if (!VFPreload.done || !VFPreload.dbDone || array == null || array.Length == 0) { return BridgeError.Create("BRIDGE_NOT_READY", "DSP prototype and model preloading has not completed yet.", true, "Wait for the DSP startup preload to finish, then retry."); } if (UIRoot.instance == null || UIRoot.instance.uiMainMenu == null || !((ManualBehaviour)UIRoot.instance.uiMainMenu).active || (Object)(object)Object.FindObjectOfType() != (Object)null) { return BridgeError.Create("BRIDGE_NOT_READY", "The DSP main menu is still initializing or another game loader is active.", true, "Wait for the main menu to finish loading, then retry."); } return null; } } internal sealed class UserSaveImportCoordinator { private sealed class UserSaveImportPlanPayload { public string SessionId { get; } public long Revision { get; } public GameData Data { get; } public string GeneratedSaveName { get; } public string Fingerprint { get; } public UserSaveImportPlanPayload(string sessionId, long revision, GameData data, string generatedSaveName) { SessionId = sessionId; Revision = revision; Data = data; GeneratedSaveName = generatedSaveName; Fingerprint = CanonicalStateHash.Combine("user-save-import", new object[3] { sessionId, revision, generatedSaveName }); } } private const string ConfirmationPrompt = "Please confirm in this conversation: import the currently loaded world as a new Spherewright-managed copy. The original save will not be overwritten, renamed, or deleted. The gameplay journal begins at the import point and will not reconstruct earlier first-time events. Shall I continue?"; private readonly bool _enabled; private readonly bool _writesConfigured; private readonly GameSessionTracker _sessions; private readonly PreparedPlanStore _plans; private readonly IdempotencyCache _idempotency; private readonly Dictionary _actions = new Dictionary(StringComparer.Ordinal); public UserSaveImportCoordinator(bool enabled, bool writesConfigured, int planLifetimeSeconds, int idempotencyRetentionMinutes, int idempotencyCapacity, GameSessionTracker sessions) { _enabled = enabled; _writesConfigured = writesConfigured; _sessions = sessions; _plans = new PreparedPlanStore(TimeSpan.FromSeconds(planLifetimeSeconds), 8, (Func)null); _idempotency = new IdempotencyCache(idempotencyCapacity, TimeSpan.FromMinutes(idempotencyRetentionMinutes), (Func)null); } public GameCallResult PrepareOnMainThread(string? requestedSessionId, PrepareUserSaveImportRequest request) { //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Expected O, but got Unknown //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Expected O, but got Unknown if (!_enabled) { return GameCallResult.Failed(BridgeError.Create("ACTION_REJECTED", "User-save import is disabled by configuration.", false, "Set Safety.AllowUserSaveImport to true and restart DSP before preparing an import.")); } if (!_writesConfigured) { return GameCallResult.Failed(BridgeError.Create("WRITES_DISABLED", "User-save import is blocked because Safety.AllowWrites is false.", false, "Enable writes and restart DSP before preparing an import.")); } if (!_sessions.TryGetCurrentUnownedImportCandidateOnMainThread(requestedSessionId, out GameData data, out string rejection) || data == null) { return GameCallResult.Failed(BridgeError.Create("SESSION_NOT_OWNED", rejection, true, "Manually load the intended save, read its restricted session state, and prepare the exact session.")); } if (string.Equals(_sessions.WriteHealth, "quarantined", StringComparison.Ordinal)) { return GameCallResult.Failed(BridgeError.Create("WRITE_SUBSYSTEM_QUARANTINED", "Save import is quarantined after an earlier unproved copy outcome in this loaded session.", false, "Do not retry the import in this session; inspect the retained action and manually reload the intended original world before starting a new flow.")); } if (request.ExpectedRevision != _sessions.Revision) { return GameCallResult.Failed(BridgeError.Create("STALE_REVISION", "The unowned session revision changed after it was inspected.", true, "Read restricted session state and prepare a fresh plan for its exact revision.")); } string generatedSaveName = SpherewrightSaveNameFactory.CreateImportedWorldName(DateTimeOffset.UtcNow, Guid.NewGuid()); UserSaveImportPlanPayload userSaveImportPlanPayload = new UserSaveImportPlanPayload(requestedSessionId, request.ExpectedRevision, data, generatedSaveName); PreparedPlan val; try { val = _plans.Add(userSaveImportPlanPayload.Fingerprint, userSaveImportPlanPayload); } catch (InvalidOperationException) { return GameCallResult.Failed(BridgeError.Create("SERVER_BUSY", "Too many unconsumed save-import plans are active.", true, "Wait for existing plans to expire, then prepare this exact loaded session again.")); } return GameCallResult.Succeeded(new PreparedUserSaveImportPlan { Prepared = true, PlanToken = val.Token, ExpiresAtUtc = val.ExpiresAtUtc, ExpectedRevision = request.ExpectedRevision, OriginalSavePreserved = true, JournalTrackingMode = "attached_existing_save", HistoricalCoverageComplete = false, UserConfirmationRequired = true, ConfirmationPrompt = "Please confirm in this conversation: import the currently loaded world as a new Spherewright-managed copy. The original save will not be overwritten, renamed, or deleted. The gameplay journal begins at the import point and will not reconstruct earlier first-time events. Shall I continue?", CommitAllowedNow = false, CommitBlockers = new List { new WriteBlocker { Code = "USER_CONFIRMATION_REQUIRED", Message = "A subsequent explicit confirmation from the user in the current conversation is required." } }, CompletionCondition = "After a subsequent explicit user confirmation, DSP's normal save API creates a new internally named copy and its exact header tick must be reread before the current GameData becomes Spherewright-owned. The original save is never addressed or overwritten, and journal coverage starts at import." }); } public GameCallResult CommitOnMainThread(string? requestedSessionId, CommitUserSaveImportRequest request) { //IL_02a5: Unknown result type (might be due to invalid IL or missing references) //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Unknown result type (might be due to invalid IL or missing references) //IL_02b9: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_02cb: Unknown result type (might be due to invalid IL or missing references) //IL_02d2: Unknown result type (might be due to invalid IL or missing references) //IL_02dd: Unknown result type (might be due to invalid IL or missing references) //IL_02e6: Expected O, but got Unknown //IL_0318: Unknown result type (might be due to invalid IL or missing references) //IL_031d: Unknown result type (might be due to invalid IL or missing references) //IL_0325: Unknown result type (might be due to invalid IL or missing references) //IL_0330: Unknown result type (might be due to invalid IL or missing references) //IL_033b: Unknown result type (might be due to invalid IL or missing references) //IL_0342: 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_0356: Unknown result type (might be due to invalid IL or missing references) //IL_0363: Unknown result type (might be due to invalid IL or missing references) //IL_036f: Unknown result type (might be due to invalid IL or missing references) //IL_037f: Unknown result type (might be due to invalid IL or missing references) //IL_038c: Expected O, but got Unknown if (!Guid.TryParse(request.IdempotencyKey, out var _)) { return GameCallResult.Failed(BridgeError.Create("INVALID_REQUEST", "A UUID idempotency key is required.", false, "Generate one UUID and reuse it for retries of this exact import commit.")); } if (string.IsNullOrWhiteSpace(requestedSessionId)) { return GameCallResult.Failed(BridgeError.Create("STALE_SESSION", "The import commit requires the exact prepared session ID.", true, "Read restricted session state and repeat the confirmation flow for that exact session.")); } string text = CanonicalStateHash.Combine("commit-user-save-import", new object[2] { requestedSessionId, request.PlanToken }); UserSaveImportResult result2 = default(UserSaveImportResult); bool flag = default(bool); if (_idempotency.TryGet(requestedSessionId, request.IdempotencyKey, text, ref result2, ref flag)) { return GameCallResult.Succeeded(CloneAsReplay(result2)); } if (flag) { return GameCallResult.Failed(BridgeError.Create("IDEMPOTENCY_CONFLICT", "The idempotency key is already bound to another save-import request.", false, "Reuse it only for the original import commit.")); } if (!_enabled) { return GameCallResult.Failed(BridgeError.Create("ACTION_REJECTED", "User-save import is disabled by configuration.", false, "Enable it, restart DSP, and repeat the explicit conversation-confirmation flow.")); } if (!_writesConfigured) { return GameCallResult.Failed(BridgeError.Create("WRITES_DISABLED", "User-save import is blocked because Safety.AllowWrites is false.", false, "Enable writes, restart DSP, and repeat the explicit conversation-confirmation flow.")); } if (string.Equals(_sessions.WriteHealth, "quarantined", StringComparison.Ordinal)) { return GameCallResult.Failed(BridgeError.Create("WRITE_SUBSYSTEM_QUARANTINED", "Save import is quarantined after an earlier unproved copy outcome in this loaded session.", false, "Do not retry with a new key; inspect the retained action and manually reload the intended original world before starting a new flow.")); } if (!_idempotency.HasCapacity(requestedSessionId)) { return GameCallResult.Failed(BridgeError.Create("IDEMPOTENCY_CAPACITY_EXCEEDED", "The idempotency cache has no capacity for another import action.", false, "Restart the Plugin before preparing another import; no save was attempted.")); } PreparedPlan val = default(PreparedPlan); bool flag2 = default(bool); if (!_plans.TryGet(request.PlanToken, ref val, ref flag2) || val == null) { return GameCallResult.Failed(BridgeError.Create(flag2 ? "PLAN_EXPIRED" : "PLAN_NOT_FOUND", flag2 ? "The save-import plan expired." : "The save-import plan was not found or was already consumed.", true, "Prepare a fresh import plan and obtain a new explicit confirmation in the conversation.")); } if (!string.Equals(val.Payload.SessionId, requestedSessionId, StringComparison.Ordinal)) { return GameCallResult.Failed(BridgeError.Create("STALE_SESSION", "The import plan belongs to another loaded-world session.", false, "Do not reuse the plan; prepare and confirm the current loaded session.")); } if (!UserSaveImportConfirmationPolicy.IsCommitDeclared(request.UserConfirmedInConversation, request.AcknowledgeOriginalSaveRemainsUnchanged, request.AcknowledgeJournalStartsAtImport)) { return GameCallResult.Failed(BridgeError.Create("USER_CONFIRMATION_REQUIRED", "The import requires a subsequent explicit user confirmation in the current conversation plus both boundary acknowledgements.", false, "Please confirm in this conversation: import the currently loaded world as a new Spherewright-managed copy. The original save will not be overwritten, renamed, or deleted. The gameplay journal begins at the import point and will not reconstruct earlier first-time events. Shall I continue?")); } PreparedPlan val2 = default(PreparedPlan); bool flag3 = default(bool); if (!_plans.TryTake(request.PlanToken, ref val2, ref flag3) || val2 == null) { return GameCallResult.Failed(BridgeError.Create(flag3 ? "PLAN_EXPIRED" : "PLAN_NOT_FOUND", flag3 ? "The save-import plan expired." : "The save-import plan was already consumed.", true, "Prepare a fresh import plan and obtain a new explicit confirmation in the conversation.")); } UserSaveImportPlanPayload payload = val2.Payload; BridgeError val3 = ValidateConfirmedWorldOnMainThread(payload.SessionId, payload.Revision, payload.Data); if (val3 != null) { return GameCallResult.Failed(val3); } int id = payload.Data.localPlanet.id; string text2 = Guid.NewGuid().ToString("D"); UserSaveImportResult val4 = new UserSaveImportResult { ActionId = text2, Accepted = true, IdempotentReplay = false, State = "executing", OriginalSavePreserved = true, JournalTrackingMode = "attached_existing_save", HistoricalCoverageComplete = false }; if (!_idempotency.TryAdd(requestedSessionId, request.IdempotencyKey, text, val4)) { return GameCallResult.Failed(BridgeError.Create("IDEMPOTENCY_CAPACITY_EXCEEDED", "The idempotency cache reached capacity before the save attempt.", false, "Do not retry with a new key until the Plugin is restarted.")); } ActionResultSnapshot val5 = new ActionResultSnapshot { ActionId = text2, ActionKind = "user-save-import", State = "executing", Terminal = false, Succeeded = false, SessionId = payload.SessionId, PlanetId = id, IdempotencyKey = request.IdempotencyKey, StartedAtGameTick = GameMain.gameTick, Message = "The explicitly confirmed normal-save copy is being created and verified." }; _actions.Add(text2, val5); long? savedGameTick; bool outcomeUnknown; string rejection; bool flag4 = _sessions.TryImportCurrentSessionAsOwnedCopyOnMainThread(payload.SessionId, payload.Revision, payload.Data, payload.GeneratedSaveName, text2, out savedGameTick, out outcomeUnknown, out rejection); val5.CompletedAtGameTick = GameMain.gameTick; val5.Terminal = true; val5.Succeeded = flag4; val5.State = (flag4 ? "completed" : (outcomeUnknown ? "outcome_unknown" : "action_failed")); val5.Message = (flag4 ? "The explicitly confirmed world was normally saved under a new internal owned identity, its exact header tick was proved, and the original save remained unchanged." : rejection); val4.State = val5.State; val4.SessionId = (flag4 ? payload.SessionId : null); val4.PlanetId = (flag4 ? new int?(id) : ((int?)null)); val4.SavedGameTick = (flag4 ? savedGameTick : ((long?)null)); return GameCallResult.Succeeded(CloneAsReplay(val4, replay: false)); } public bool TryGetActionResultOnMainThread(string actionId, out ActionResultSnapshot? result) { if (_actions.TryGetValue(actionId, out ActionResultSnapshot value)) { result = value; return true; } result = null; return false; } private BridgeError? ValidateConfirmedWorldOnMainThread(string sessionId, long revision, GameData expectedData) { if (!_sessions.TryGetCurrentUnownedImportCandidateOnMainThread(sessionId, out GameData data, out string rejection) || data == null || data != expectedData) { return BridgeError.Create("STALE_SESSION", rejection, true, "The confirmation cannot cross a loaded-world change; prepare the current session and ask again."); } if (_sessions.Revision != revision) { return BridgeError.Create("STALE_REVISION", "The exact unowned session revision changed after prepare.", true, "Prepare a fresh plan for the current revision and ask for confirmation again."); } if (Object.FindObjectOfType() != null || data.localPlanet == null || data.localLoadedPlanetFactory == null) { return BridgeError.Create("BRIDGE_NOT_READY", "The confirmed world is loading or has no ready local factory.", true, "Wait until the world is stable, then prepare and confirm again."); } GameDesc gameDesc = data.gameDesc; if (gameDesc == null) { return BridgeError.Create("PEACEFUL_MODE_UNKNOWN", "The confirmed world has no readable game descriptor.", false, "Do not import this world."); } if (!GameplayModePolicy.AllowsNormalActions(true, gameDesc.isPeaceMode, gameDesc.isSandboxMode, GameMain.sandboxToolsEnabled, gameDesc.resourceMultiplier)) { return BridgeError.Create("PEACEFUL_MODE_REQUIRED", "Only a confirmed peaceful world can become Spherewright-owned.", false, "Load a peaceful world manually, then prepare and confirm it."); } return null; } private static UserSaveImportResult CloneAsReplay(UserSaveImportResult result, bool replay = true) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown return new UserSaveImportResult { ActionId = result.ActionId, Accepted = result.Accepted, IdempotentReplay = replay, State = result.State, SessionId = result.SessionId, PlanetId = result.PlanetId, SavedGameTick = result.SavedGameTick, OriginalSavePreserved = result.OriginalSavePreserved, JournalTrackingMode = result.JournalTrackingMode, HistoricalCoverageComplete = result.HistoricalCoverageComplete }; } } } namespace Spherewright.Plugin.Bootstrap { internal sealed class SpherewrightConfiguration { public bool Enabled { get; private set; } public string PipeNamePrefix { get; private set; } = "Spherewright"; public int MaxConnections { get; private set; } public int MaxQueuedRequests { get; private set; } public int MaxInFlightRequests { get; private set; } public int MaxMainThreadQueue { get; private set; } public int MaxRequestsPerFrame { get; private set; } public int FrameBudgetMs { get; private set; } public int MaxFrameBytes { get; private set; } public int ReadRequestTimeoutSeconds { get; private set; } public int CommitWaitTimeoutSeconds { get; private set; } public bool RequireCurrentUserAcl { get; private set; } public string RuntimeDescriptorDirectory { get; private set; } = string.Empty; public bool RotateBridgeTokenOnStart { get; private set; } public bool AllowWrites { get; private set; } public bool AllowUserSaveImport { get; private set; } public bool RequirePeacefulSave { get; private set; } public int PlanTokenLifetimeSeconds { get; private set; } public int IdempotencyRetentionMinutes { get; private set; } public int MaxIdempotencyEntriesPerSession { get; private set; } public bool AutoAcknowledgeResearchResults { get; private set; } private SpherewrightConfiguration() { } public static SpherewrightConfiguration Load(ConfigFile config) { if (config == null) { throw new ArgumentNullException("config"); } SpherewrightConfiguration spherewrightConfiguration = new SpherewrightConfiguration(); spherewrightConfiguration.Enabled = config.Bind("Bridge", "Enabled", true, "Enable the local Spherewright bridge.").Value; spherewrightConfiguration.PipeNamePrefix = config.Bind("Bridge", "PipeNamePrefix", "Spherewright", "Prefix for the randomized local Named Pipe.").Value; spherewrightConfiguration.MaxConnections = config.Bind("Bridge", "MaxConnections", 1, "Maximum authenticated Pipe connections.").Value; spherewrightConfiguration.MaxQueuedRequests = config.Bind("Bridge", "MaxQueuedRequests", 64, "Maximum queued bridge requests.").Value; spherewrightConfiguration.MaxInFlightRequests = config.Bind("Bridge", "MaxInFlightRequests", 8, "Maximum in-flight requests per connection.").Value; spherewrightConfiguration.MaxMainThreadQueue = config.Bind("Bridge", "MaxMainThreadQueue", 32, "Maximum Unity main-thread work items.").Value; spherewrightConfiguration.MaxRequestsPerFrame = config.Bind("Bridge", "MaxRequestsPerFrame", 4, "Maximum main-thread requests pumped per frame.").Value; spherewrightConfiguration.FrameBudgetMs = config.Bind("Bridge", "FrameBudgetMs", 2, "Unity main-thread bridge budget in milliseconds.").Value; spherewrightConfiguration.MaxFrameBytes = config.Bind("Bridge", "MaxFrameBytes", 1048576, "Maximum bridge frame payload size.").Value; spherewrightConfiguration.ReadRequestTimeoutSeconds = config.Bind("Bridge", "ReadRequestTimeoutSeconds", 10, "Read request timeout in seconds.").Value; spherewrightConfiguration.CommitWaitTimeoutSeconds = config.Bind("Bridge", "CommitWaitTimeoutSeconds", 15, "Commit result wait timeout in seconds.").Value; spherewrightConfiguration.RequireCurrentUserAcl = config.Bind("Security", "RequireCurrentUserAcl", true, "Require current-user-only ACLs for Pipe and descriptor.").Value; spherewrightConfiguration.RuntimeDescriptorDirectory = config.Bind("Security", "RuntimeDescriptorDirectory", "%LOCALAPPDATA%/Spherewright/runtime", "Directory used for protected runtime descriptors. Use forward slashes so BepInEx does not interpret backslash escapes.").Value; spherewrightConfiguration.RotateBridgeTokenOnStart = config.Bind("Security", "RotateBridgeTokenOnStart", true, "Rotate the bridge token on each Plugin start.").Value; spherewrightConfiguration.AllowWrites = config.Bind("Safety", "AllowWrites", false, "Allow explicitly committed game writes. The default remains read-only.").Value; spherewrightConfiguration.AllowUserSaveImport = config.Bind("Safety", "AllowUserSaveImport", false, "Allow a player-loaded unowned world to be cloned into a new Spherewright-owned save after an explicit confirmation in the Agent conversation.").Value; spherewrightConfiguration.RequirePeacefulSave = config.Bind("Safety", "RequirePeacefulSave", true, "Require confirmed peaceful mode before any future write.").Value; spherewrightConfiguration.PlanTokenLifetimeSeconds = config.Bind("Safety", "PlanTokenLifetimeSeconds", 60, "Lifetime of a dry-run plan token in seconds.").Value; spherewrightConfiguration.IdempotencyRetentionMinutes = config.Bind("Safety", "IdempotencyRetentionMinutes", 30, "Configured action-result retention window in minutes.").Value; spherewrightConfiguration.MaxIdempotencyEntriesPerSession = config.Bind("Safety", "MaxIdempotencyEntriesPerSession", 1024, "Maximum cached idempotent action results per Plugin process.").Value; spherewrightConfiguration.AutoAcknowledgeResearchResults = config.Bind("Experience", "AutoAcknowledgeResearchResults", true, "Dismiss DSP's research-result modal through its native FadeOut flow after it becomes ready.").Value; spherewrightConfiguration.Validate(); return spherewrightConfiguration; } private void Validate() { if (string.IsNullOrWhiteSpace(PipeNamePrefix) || PipeNamePrefix.Length > 32 || PipeNamePrefix.Any((char character) => !char.IsLetterOrDigit(character) && character != '-' && character != '_' && character != '.')) { throw new InvalidOperationException("Bridge PipeNamePrefix contains unsupported characters."); } if (MaxConnections != 1) { throw new InvalidOperationException("Gate A supports exactly one authenticated Pipe connection."); } if (MaxQueuedRequests <= 0 || MaxInFlightRequests <= 0 || MaxMainThreadQueue <= 0 || MaxRequestsPerFrame <= 0 || FrameBudgetMs <= 0 || MaxFrameBytes <= 0 || MaxFrameBytes > 1048576 || ReadRequestTimeoutSeconds <= 0 || CommitWaitTimeoutSeconds <= 0) { throw new InvalidOperationException("One or more Bridge capacity settings are invalid."); } if (!RequireCurrentUserAcl) { throw new InvalidOperationException("Gate A does not allow disabling current-user ACL protection."); } if (!RotateBridgeTokenOnStart) { throw new InvalidOperationException("Gate A requires bridge token rotation on every start."); } if (string.IsNullOrWhiteSpace(RuntimeDescriptorDirectory)) { throw new InvalidOperationException("RuntimeDescriptorDirectory is required."); } if (PlanTokenLifetimeSeconds <= 0 || IdempotencyRetentionMinutes <= 0 || MaxIdempotencyEntriesPerSession <= 0) { throw new InvalidOperationException("One or more Safety lifetime or capacity settings are invalid."); } } } }