XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
using System.Globalization;
using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;
using static XFEEDToolBox.Plugin.JsonWire;

namespace XFEEDToolBox.Plugin;

internal static unsafe partial class Navigation
{
    private struct LocalIdentity { public int key; public uint kind, market; public ulong body; public fixed byte name[513]; }
    private struct LocalSelection { public LocalIdentity target; public ulong generation, expires, entity, epoch; public nuint life, fsd, inputRoot; }
    private struct LocalTargetObservation
    {
        public LocalIdentity target;
        public ulong tick, entity, epoch, world;
        public nuint life, fsd, inputRoot;
        public bool valid;
    }
    private struct LocalFlightObservation
    {
        public ulong tick, utc, sequence, entity, world;
        public LocalIdentity target;
        public AffinePose ship, destination;
        public Vector velocity, targetVelocity, angularVelocity;
        public double distance, speed, throttle, normalSpeedLimit, cruiseSpeedLimit, accelerationLowerBound;
        public double safeDropDistance, safeDropSpeed, safeDropAngle, cruiseApproachSeconds, cruiseApproachThrottle;
        public bool safeDisengage, cruiseParametersVerified, valid, velocityValid, selected, angularVelocityValid;
        public uint dockingState, requestState, pad;
        public nuint stationLife;
        public bool inSupercruise, cruiseAssistAvailable, cruiseAssistEnabled, cruiseAssistEngaged, cruiseAssistMatches, cruiseAssistObscured;
        public bool dockingVerified, dockingGranted, dockingAssistAllowed, dockingAssistEnabled, dockingAssistEngaged;
        public bool dockingComputerAvailable, nativeDockingActive, nativeLaunchActive, nativeLaunchRequested, dockingThrottleZero, dockingZeroInputSent, speedZeroInputSent;
    }
    private struct LocalActionRequest { public ulong generation, selection, expires, sequence, entity, epoch, world; public nuint life, inputRoot; public uint action; }
    private static readonly object localLock = new();
    private static LocalSelection localSelection = new() { target = new() { key = -1 } };
    private static LocalTargetObservation localTargetObservation = new() { target = new() { key = -1 } };
    private static LocalFlightObservation localObservation = EmptyLocalObservation();
    private static string localSampleStage = "notSampled";
    private static ulong localGenerationValue, localConsumedValue, localConfirmedValue, localFailedValue;
    private static ulong localGeneration { get => Volatile.Read(ref localGenerationValue); set => Volatile.Write(ref localGenerationValue, value); }
    private static ulong localConsumed { get => Volatile.Read(ref localConsumedValue); set => Volatile.Write(ref localConsumedValue, value); }
    private static ulong localConfirmed { get => Volatile.Read(ref localConfirmedValue); set => Volatile.Write(ref localConfirmedValue, value); }
    private static ulong localFailed { get => Volatile.Read(ref localFailedValue); set => Volatile.Write(ref localFailedValue, value); }
    private static LocalActionRequest localAction;
    private static ulong localActionGenerationValue, localActionConsumedValue, localActionAppliedValue, localActionFailedValue;
    private static ulong localActionGeneration { get => Volatile.Read(ref localActionGenerationValue); set => Volatile.Write(ref localActionGenerationValue, value); }
    private static ulong localActionConsumed { get => Volatile.Read(ref localActionConsumedValue); set => Volatile.Write(ref localActionConsumedValue, value); }
    private static ulong localActionApplied { get => Volatile.Read(ref localActionAppliedValue); set => Volatile.Write(ref localActionAppliedValue, value); }
    private static ulong localActionFailed { get => Volatile.Read(ref localActionFailedValue); set => Volatile.Write(ref localActionFailedValue, value); }
    private struct DockingZeroInputReceipt { public ulong entity, tick; public nuint life, binding, inputService; public uint market; }
    private static DockingZeroInputReceipt dockingZeroInputReceipt;
    private static LocalFlightObservation EmptyLocalObservation() => new() { target = new() { key = -1 }, pad = 255 };
    private static void ExpireLocal() { lock (localLock) { localSelection.expires = 0; localAction.expires = 0; dockingZeroUpdate.command.expires=0; } lock(normalBoostLock)if(normalBoostPulse is {} pulse)pulse.until=0; ExpireDockingFixture(); }
    private static nuint LocalDocking(in Snapshot frame)
    {
        var value = RegisteredComponent(Pointer(frame.life + 0xC8) - 0x30, Read<uint>(image + 0x5F306C8));
        return value != 0 && Pointer(value) == image + 0x5315D28 ? value : 0;
    }
    private static bool YieldForNativeDocking(in Lease control, in Snapshot frame)
    {
        if (!control.yieldOnDockingGrant || control.throttle != 0 || control.localMarket == 0 || control.localMarket == uint.MaxValue) return false;
        var dock = LocalDocking(frame);
        if (dock == 0 || Read<uint>(dock + 0x614) != 2 || Read<byte>(dock + 0x4E9) == 255 || Read<uint>(dock + 0x4C0) is not (3 or 4)) return false;
        var station = Pointer(dock + 0x4E0); var computer = LocalDockingComputer(frame);
        return station != 0 && Read<uint>(station + 0xC0) == 8 && Read<ulong>(station + 0xB0) == control.localMarket && computer != 0 && (byte)Call(image + 0xED6620, computer) != 0;
    }
    private static nuint LocalCruiseAssist(in Snapshot frame)
    {
        var value = RegisteredComponent(Pointer(frame.life + 0xC8) - 0x30, Read<uint>(image + 0x5F53170));
        return value != 0 && Pointer(value) == image + 0x5164800 ? value : 0;
    }
    private static nuint LocalDockingComputer(in Snapshot frame)
    {
        var value = RegisteredComponent(Pointer(frame.life + 0xC8) - 0x30, Read<uint>(image + 0x5F5317C));
        return value != 0 && Pointer(value) == image + 0x5165248 && Pointer(Pointer(value) + 0x30) == image + 0xED7D10 && Pointer(Pointer(value) + 0x58) == image + 0xED7E10 && Pointer(Pointer(value) + 0x88) == image + 0xEF8A60 ? value : 0;
    }
    private static bool ReadLocalDockingAvailability(nuint computer, nuint expectedTable, nuint expectedGetter)
    {
        if (computer < 0x10000 || Pointer(computer) != expectedTable || Pointer(expectedTable + 0x58) != expectedGetter) return false;
        // The original docking update (0xE9A160) resolves its own module, asks
        // the module power/health predicate (+0x70), and publishes +0x377 on
        // this interface. Slot +0x58 reads that result. The SCA predicate at
        // 0xED7E20 belongs to another class and cannot receive this interface.
        return (byte)Call(expectedGetter, computer) != 0;
    }
    private static bool LocalDockingAvailable(nuint computer) => ReadLocalDockingAvailability(computer, image + 0x5165248, image + 0xED7E10);
    private static nuint LocalCruiseArrival(in Snapshot frame)
    {
        var value = RegisteredComponent(Pointer(frame.life + 0xC8) - 0x30, Read<uint>(image + 0x5F34640));
        return value != 0 && Pointer(value) == image + 0x533DBF0 ? value : 0;
    }
    private static nuint LocalStationUniversalPose(nuint life)
    {
        var pose = RegisteredComponent(Pointer(life + 0xC8) - 0x30, Read<uint>(image + 0x5F05D3C)); if (pose == 0) return 0;
        var table = Pointer(pose);
        if (table == image + 0x553DF60 && Pointer(table + 0x28) == image + 0xF84760 && Pointer(table + 0x60) == image + 0x3CBC040) return pose + 0xA8;
        if (IsPose(pose) && Pointer(table + 0x60) == image + 0x2D9C200) return pose + 0xE8;
        return 0;
    }
    private static nuint LocalRecord(nuint navigation, int key)
    {
        var count = Read<ulong>(navigation + 0x2C0); var capacity = Read<ulong>(navigation + 0x2C8); var storage = Pointer(navigation + 0x2D0);
        if (storage == 0 || capacity < 8 || capacity > 16384 || (capacity & (capacity - 1)) != 0 || count > 1024 || count > capacity) return 0;
        var entries = storage + (nuint)(((capacity >> 3) + 7) & ~7UL);
        for (ulong i = 0; i < capacity; i++)
            if (((Read<byte>(storage + (nuint)(i >> 3)) >> (int)(i & 7)) & 1) != 0)
            { var entry = entries + (nuint)i * 16; if (Read<int>(entry) == key) return Pointer(entry + 8); }
        return 0;
    }
    private static bool ReadLocalIdentity(nuint record, int key, out LocalIdentity output)
    {
        output = new() { key = -1 };
        if (record == 0 || Read<uint>(record + 0x188) != 1) return false;
        LocalIdentity value = new() { key = key, body = Read<ulong>(record + 0x20), kind = Read<uint>(record + 0x184), market = Read<uint>(record + 0x130) };
        var text = Pointer(record + 0x140); if (text == 0) return false;
        var length = Read<ulong>(text); if (length == 0 || length >= 513) return false;
        var used = 0;
        for (ulong i = 0; i < length; i++)
        {
            var c = Read<byte>(text + 0x14 + (nuint)i); if (c == 0) return false;
            if (c >= 32 && c != 127) value.name[used++] = c;
        }
        while (used != 0 && value.name[used - 1] == (byte)' ') value.name[--used] = 0;
        var leading = 0; while (leading < used && value.name[leading] == (byte)' ') leading++;
        if (leading != 0) { new Span<byte>(value.name + leading, used - leading).CopyTo(new Span<byte>(value.name, 513)); used -= leading; value.name[used] = 0; }
        if (value.body == 0 || value.kind == 0 || used == 0) return false;
        output = value; return true;
    }
    private static bool SameLocal(in LocalIdentity a, in LocalIdentity b)
    {
        if (a.key != b.key || a.body != b.body || a.kind != b.kind || a.market != b.market) return false;
        fixed (byte* left = a.name) fixed (byte* right = b.name) return new ReadOnlySpan<byte>(left, 513).SequenceEqual(new ReadOnlySpan<byte>(right, 513));
    }
    private static bool LocalRecordMatches(nuint navigation, in LocalIdentity wanted) => ReadLocalIdentity(LocalRecord(navigation, wanted.key), wanted.key, out var actual) && SameLocal(actual, wanted);
    private static LocalTargetObservation ObserveLocalTarget(in Snapshot frame)
    {
        var result = new LocalTargetObservation { target = new() { key = -1 } };
        try
        {
            if (!frame.valid || GetTickCount64() - frame.tick > 200 || !BoundFsd(frame, frame.fsd)) return result;
            var nav = Pointer(frame.fsd + 0x338);
            if (Pointer(Pointer(nav) + 0x20) != image + 0x2EC8100 || Pointer(Pointer(nav) + 0xB8) != image + 0x2EC8D60) return result;
            var key = Read<int>(nav + 0x38C);
            if (!ReadLocalIdentity(LocalRecord(nav, key), key, out result.target) || (result.target.body & 0x007FFFFFFFFFFFFFUL) != (frame.referenceWorld & 0x007FFFFFFFFFFFFFUL)) return result;
            result.tick = frame.tick; result.entity = frame.entity; result.epoch = controllerEpoch; result.world = frame.referenceWorld;
            result.life = frame.life; result.fsd = frame.fsd; result.inputRoot = frame.inputRoot;
            result.valid = Read<int>(nav + 0x38C) == key && LocalRecordMatches(nav, result.target) && Read<ulong>(frame.transform + 0xE8) == frame.referenceWorld;
        }
        catch { result.valid = false; }
        return result;
    }
    private static bool LocalSelectionAcknowledged(in LocalSelection wanted, in LocalTargetObservation observed, ulong confirmedGeneration, ulong now, ulong epoch, bool playerOverridden) =>
        !playerOverridden && wanted.generation != 0 && confirmedGeneration == wanted.generation && observed.valid &&
        observed.tick <= now && now - observed.tick <= 200 && observed.epoch == epoch && wanted.epoch == epoch &&
        observed.entity == wanted.entity && observed.life == wanted.life && observed.fsd == wanted.fsd && observed.inputRoot == wanted.inputRoot &&
        (observed.world & 0x007FFFFFFFFFFFFFUL) == (wanted.target.body & 0x007FFFFFFFFFFFFFUL) && SameLocal(observed.target, wanted.target);
    private static bool LocalControlMatches(in Lease control, in Snapshot frame)
    {
        try
        {
            var navigation = Pointer(frame.fsd + 0x338); var record = LocalRecord(navigation, control.localKey);
            return control.local && control.world == frame.referenceWorld && Read<int>(navigation + 0x38C) == control.localKey && record != 0 && Read<uint>(record + 0x188) == 1 && Read<ulong>(record + 0x20) == control.localBody && Read<uint>(record + 0x184) == control.localKind && Read<uint>(record + 0x130) == control.localMarket;
        }
        catch { return false; }
    }
    private static bool SelectLocalTargetImpl(in Snapshot frame, in LocalSelection wanted)
    {
        try
        {
            var now = GetTickCount64();
            if (!Enabled() || !inGame || !frame.valid || !frame.healthValid || frame.healthEmergency || now - frame.tick > 200 || wanted.expires <= now || wanted.epoch != controllerEpoch || overridden || wanted.entity != frame.entity || wanted.life != frame.life || wanted.fsd != frame.fsd || wanted.inputRoot != frame.inputRoot || !BoundFsd(frame, frame.fsd) || !LocalSelectionFsdReady(frame.rawFsdState,fsdOwned)) return false;
            var nav = Pointer(frame.fsd + 0x338);
            if (Pointer(Pointer(nav) + 0x20) != image + 0x2EC8100 || Pointer(Pointer(nav) + 0x90) != image + 0x2ED6840 || Pointer(Pointer(nav) + 0xB8) != image + 0x2EC8D60 || (wanted.target.body & 0x007FFFFFFFFFFFFFUL) != (frame.referenceWorld & 0x007FFFFFFFFFFFFFUL) || !LocalRecordMatches(nav, wanted.target)) return false;
            if (Read<int>(nav + 0x38C) != wanted.target.key) Call(image + 0x2ED6840, nav, unchecked((ulong)wanted.target.key), 1, 0);
            return Read<int>(nav + 0x38C) == wanted.target.key && LocalRecordMatches(nav, wanted.target);
        }
        catch { return false; }
    }
    private static void SelectLocalTarget(in Snapshot frame)
    {
        LocalSelection wanted; lock (localLock) wanted = localSelection;
        if (wanted.generation == 0 || localConsumed == wanted.generation) return;
        if (SelectLocalTargetImpl(frame, wanted)) localConfirmed = wanted.generation; else localFailed = wanted.generation;
        localConsumed = wanted.generation;
    }
    private static double LocalDecodeFloat(nuint at)
    {
        var bits = Read<ulong>(at); return BitConverter.UInt32BitsToSingle((uint)bits ^ (uint)(bits >> 32));
    }
    private static bool LocalBodyPose(nuint body, nuint universal, nuint resource, out AffinePose output)
    {
        AffinePose value = default; var valid = BodyPose(body, universal, resource, &value); output = value; return valid;
    }
    private static bool LocalEncodedFlag(nuint at) { var bits = Read<ushort>(at); return (bits & 255) != (bits >> 8); }
    private static bool SampleLocalFlight(in Snapshot frame, out LocalFlightObservation output, out string stage)
    {
        output = EmptyLocalObservation();
        var next = EmptyLocalObservation();
        stage = "snapshot";
        try
        {
            if (!frame.valid || GetTickCount64() - frame.tick > 200 || !BoundFsd(frame, frame.fsd)) return false;
            stage = "navigationInterface";
            var nav = Pointer(frame.fsd + 0x338);
            if (Pointer(Pointer(nav) + 0x20) != image + 0x2EC8100 || Pointer(Pointer(nav) + 0xB8) != image + 0x2EC8D60) return false;
            stage = "selectedIdentity";
            var key = Read<int>(nav + 0x38C); var record = LocalRecord(nav, key);
            if (!ReadLocalIdentity(record, key, out next.target) || (next.target.body & 0x007FFFFFFFFFFFFFUL) != (frame.referenceWorld & 0x007FFFFFFFFFFFFFUL)) return false;
            stage = "loadedSystem";
            var service = Pointer(frame.fsd + 0x6A0); var resource = LoadedSystem(service, frame.referenceWorld);
            if (resource == 0 || Pointer(Pointer(service) + 0x60) != image + BodyLookup) return false;
            stage = "bodyGeometry";
            var bodies = Pointer(resource + 0x140); var capacity = Read<ulong>(resource + 0x148);
            var shipBody = BodyMapEntry(bodies, capacity, frame.referenceWorld, 16, false); var targetBody = BodyMapEntry(bodies, capacity, next.target.body, 16, false);
            if (shipBody == 0 || targetBody == 0 || !LocalBodyPose(shipBody, frame.transform + 0xE8, resource, out next.ship) || !LocalBodyPose(targetBody, record + 0x20, resource, out next.destination)) return false;
            var delta = Subtract(next.destination.position, next.ship.position); next.distance = Math.Sqrt(Dot(delta, delta));
            next.speed = frame.speed; next.throttle = Read<float>(frame.inputRoot + 0x70); next.angularVelocity = frame.angularVelocityLocal; next.angularVelocityValid = frame.angularVelocityValid;
            stage = "distanceAndThrottle";
            if (!double.IsFinite(next.distance) || next.distance < 0 || !double.IsFinite(next.throttle) || Math.Abs(next.throttle) > 1.001) return false;
            stage = "dockingState";
            var computer = LocalDockingComputer(frame);
            if (computer != 0)
            {
                next.dockingComputerAvailable = LocalDockingAvailable(computer);
                next.nativeDockingActive = (byte)Call(image + 0xED6620, computer) != 0;
                next.nativeLaunchActive = (byte)Call(image + 0xED7D10, computer) != 0;
                next.nativeLaunchRequested = Read<byte>(computer + 0x374) != 0;
                var controller = Pointer(frame.inputRoot + 0x2F8);
                next.dockingThrottleZero = controller != 0 && Pointer(computer + 0x240) == controller && Pointer(Pointer(controller) + 0x158) == image + ThrottleSetter
                    &&Read<float>(controller + 0x680)==0&&ReadOriginalDockingThrottle(computer,out var sourceThrottle)&&Math.Abs(sourceThrottle)<=.001f;
                next.speedZeroInputSent = dockingZeroInputReceipt.entity == frame.entity && dockingZeroInputReceipt.life == frame.life && dockingZeroInputReceipt.inputService == Pointer(computer + 0x230) && frame.tick >= dockingZeroInputReceipt.tick && frame.tick - dockingZeroInputReceipt.tick < 30000;
                next.dockingZeroInputSent = next.speedZeroInputSent && dockingZeroInputReceipt.market == next.target.market;
            }
            var dock = LocalDocking(frame);
            if (dock != 0)
            {
                next.dockingState = Read<uint>(dock + 0x4C0); next.requestState = Read<uint>(dock + 0x614); next.pad = Read<byte>(dock + 0x4E9);
                var station = Pointer(dock + 0x4E0); if (station != 0 && Read<uint>(station + 0xC0) == 8) next.stationLife = station;
                next.dockingAssistEnabled = Read<byte>(dock + 0x5BB) != 0;
                if (next.stationLife != 0 && Read<ulong>(next.stationLife + 0xB0) == next.target.market)
                {
                    next.dockingVerified = true; next.dockingGranted = next.dockingState is 3 or 4 && next.requestState == 2 && next.pad != 255;
                    var stationService = RegisteredComponent(Pointer(next.stationLife + 0xC8) - 0x30, Read<uint>(image + 0x5F771D0));
                    if (stationService != 0)
                    {
                        var table = Pointer(stationService); var activeFunction = Pointer(table + 0x28); var allowed = Pointer(table + 0x58);
                        if (InImage(activeFunction) && InImage(allowed)) { next.dockingAssistAllowed = (byte)Call(allowed, stationService) != 0; next.dockingAssistEngaged = (byte)Call(activeFunction, stationService) != 0; }
                    }
                }
            }
            stage = "motionLimits";
            next.inSupercruise = LocalCruiseArrival(frame) != 0;
            next.normalSpeedLimit = (double)Read<float>(frame.physics + 0x750) * Read<float>(frame.physics + 0x910);
            var x = (double)Read<float>(frame.physics + 0x600); var y = (double)Read<float>(frame.physics + 0x604); var z = (double)Read<float>(frame.physics + 0x608);
            next.accelerationLowerBound = Math.Min(x, Math.Min(y, z)) * .25;
            next.cruiseSpeedLimit = next.inSupercruise && frame.speedFraction > .001 ? frame.speed / frame.speedFraction : next.normalSpeedLimit;
            var arrival = LocalCruiseArrival(frame);
            if (arrival != 0)
            {
                stage = "cruiseInterface";
                var table = Pointer(arrival);
                if (Pointer(table + 0x38) != image + 0x2EA4EE0 || Pointer(table + 0x118) != image + 0x2EA4EC0 || Pointer(table + 0x68) != image + 0x2EAD330) return false;
                next.cruiseSpeedLimit = CallFloat(image + 0x2EA4EE0, arrival); var limits = (nuint)Call(image + 0x2EA4EC0, arrival); if (limits != arrival + 0x5A8) return false;
                next.safeDropDistance = LocalDecodeFloat(limits + 0x28); next.safeDropSpeed = LocalDecodeFloat(limits + 0x48); next.safeDropAngle = LocalDecodeFloat(limits + 0x68);
                var alignment = next.distance > 0 ? Math.Acos(Math.Clamp(Dot(next.ship.forward, Scale(delta, 1 / next.distance)), -1, 1)) : Math.PI;
                next.safeDisengage = LocalEncodedFlag(limits + 0xE8) && LocalEncodedFlag(limits + 0x108) && LocalEncodedFlag(limits + 0x128) && double.IsFinite(next.safeDropDistance) && next.safeDropDistance > 0 && next.distance < next.safeDropDistance && double.IsFinite(next.safeDropSpeed) && next.safeDropSpeed > 0 && next.speed < next.safeDropSpeed && double.IsFinite(next.safeDropAngle) && next.safeDropAngle > 0 && next.safeDropAngle < 1.571 && alignment < next.safeDropAngle;
                var helper = RegisteredComponent(Pointer(frame.life + 0xC8) - 0x30, Read<uint>(image + 0x5F53174)); var assist = LocalCruiseAssist(frame);
                if (helper != 0 && Pointer(helper) == image + 0x5164C78 && assist != 0)
                {
                    next.cruiseApproachSeconds = Read<double>(Pointer(helper - 8) + 0x50); next.cruiseApproachThrottle = Read<float>(Pointer(assist - 8) + 0x10);
                    next.cruiseParametersVerified = double.IsFinite(next.cruiseApproachSeconds) && next.cruiseApproachSeconds > 0 && next.cruiseApproachSeconds <= 120 && double.IsFinite(next.cruiseApproachThrottle) && next.cruiseApproachThrottle > 0 && next.cruiseApproachThrottle <= 1;
                }
            }
            stage = "motionLimits";
            if (!double.IsFinite(next.normalSpeedLimit) || next.normalSpeedLimit <= 0 || !double.IsFinite(next.cruiseSpeedLimit) || next.cruiseSpeedLimit <= 0 || !double.IsFinite(next.accelerationLowerBound) || next.accelerationLowerBound <= 0) return false;
            stage = "cruiseAssist";
            var cruiseAssist = LocalCruiseAssist(frame);
            if (cruiseAssist != 0)
            {
                next.cruiseAssistAvailable = (byte)Call(image + 0xECAF00, cruiseAssist) != 0; next.cruiseAssistEnabled = Read<byte>(cruiseAssist + 0x256) != 0; next.cruiseAssistEngaged = Read<byte>(cruiseAssist + 0x257) != 0;
                next.cruiseAssistMatches = (byte)Call(image + 0xED8760, cruiseAssist, record) != 0; next.cruiseAssistObscured = (byte)Call(image + 0xED8A50, cruiseAssist, record) != 0;
            }
            next.tick = frame.tick; next.utc = frame.utcMilliseconds; next.sequence = frame.sequence; next.entity = frame.entity; next.world = frame.referenceWorld; next.selected = true;
            next.valid = Read<int>(nav + 0x38C) == key && LocalRecordMatches(nav, next.target) && Read<ulong>(frame.transform + 0xE8) == frame.referenceWorld;
            stage = next.valid ? "ready" : "identityChanged";
            return next.valid;
        }
        catch (Exception error) { stage += ":" + error.GetType().Name; return false; }
        finally { output = next; }
    }
    private static void PollLocalFlight(in Snapshot frame)
    {
        LocalFlightObservation before; lock (localLock) before = localObservation;
        if (before.sequence == frame.sequence && before.tick != 0 && GetTickCount64() - before.tick < 100) return;
        var selected = ObserveLocalTarget(frame);
        var next = EmptyLocalObservation();
        if (SampleLocalFlight(frame, out next, out var stage))
        {
            var seconds = ((double)next.tick - before.tick) * .001;
            if (before.valid && before.entity == next.entity && before.world == next.world && SameLocal(before.target, next.target) && seconds >= .005 && seconds <= .3)
            {
                next.velocity = Scale(Subtract(next.ship.position, before.ship.position), 1 / seconds); next.targetVelocity = Scale(Subtract(next.destination.position, before.destination.position), 1 / seconds); next.velocityValid = Finite(next.velocity) && Finite(next.targetVelocity);
            }
        }
        lock (localLock) { localObservation = next; localTargetObservation = selected; localSampleStage = stage; }
    }
    private static nuint LocalEntityFromDirectory(nuint context, nuint playerLife, ulong playerEntity, ulong wanted)
    {
        try
        {
            var count = Read<ulong>(context + 0x148); var capacity = Read<ulong>(context + 0x150); var storage = Pointer(context + 0x158);
            if (storage == 0 || capacity < 8 || capacity > 65536 || (capacity & (capacity - 1)) != 0 || count > capacity) return 0;
            var entries = storage + (nuint)(((capacity >> 3) + 7) & ~7UL); var own = false; nuint found = 0;
            for (ulong i = 0; i < capacity; i++)
                if (((Read<byte>(storage + (nuint)(i >> 3)) >> (int)(i & 7)) & 1) != 0)
                { var at = entries + (nuint)i * 16; var key = Read<ulong>(at); var life = Pointer(at + 8); if (key == playerEntity) own = life == playerLife; if (key == wanted) found = life; }
            if (!own || found == 0 || Read<ulong>(context + 0x148) != count || Read<ulong>(context + 0x150) != capacity || Pointer(context + 0x158) != storage || Read<uint>(found + 0xC0) != 8 || Read<ulong>(found + 0xB0) != wanted) return 0;
            return found;
        }
        catch { return 0; }
    }
    private static bool LocalDockingTargetKind(uint kind)=>XFEEDToolBox.Core.Navigation.NativeDockingTargetKinds.SupportsDocking(kind);
    private static bool RequestLocalDocking(in Snapshot frame, in LocalFlightObservation observed)
    {
        var nav = Pointer(frame.fsd + 0x338); var dock = LocalDocking(frame); var record = LocalRecord(nav, observed.target.key);
        if (dock == 0 || record == 0 || observed.inSupercruise || observed.distance > 7500 || observed.target.market == 0 || observed.target.market == uint.MaxValue || !LocalDockingTargetKind(observed.target.kind) || Pointer(Pointer(dock) + 0xF8) != image + 0x2C65C30) return false;
        var context = Pointer(frame.life + 0x38); var token = (ulong)Read<uint>(record + 0x130); if (context == 0 || token == 0 || token == uint.MaxValue) return false;
        var existing = LocalEntityFromDirectory(context, frame.life, frame.entity, token); if (existing == 0) return false;
        nuint station = 0; Call(image + 0x62D0A0, (ulong)(nuint)(&station), (ulong)(nuint)(&existing));
        try
        {
            if (station == 0 || Read<uint>(station + 0xC0) != 8 || Read<ulong>(station + 0xB0) != token) return false;
            var stationPose = LocalStationUniversalPose(station); var resource = LoadedSystem(Pointer(frame.fsd + 0x6A0), frame.referenceWorld); if (stationPose == 0 || resource == 0) return false;
            var stationWorld = Read<ulong>(stationPose); if ((stationWorld & 0x007FFFFFFFFFFFFFUL) != (frame.referenceWorld & 0x007FFFFFFFFFFFFFUL)) return false;
            var body = BodyMapEntry(Pointer(resource + 0x140), Read<ulong>(resource + 0x148), stationWorld, 16, false); if (body == 0 || !LocalBodyPose(body, stationPose, resource, out var pose)) return false;
            var delta = Subtract(pose.position, observed.ship.position); if (Dot(delta, delta) > 7500.0 * 7500.0 || !LocalRecordMatches(nav, observed.target) || Read<int>(nav + 0x38C) != observed.target.key) return false;
            EndNormalBoostPulse();
            if(observed.dockingComputerAvailable)
            {
                var controller=Pointer(frame.inputRoot+0x2F8);
                if(controller==0||Pointer(Pointer(controller)+0x158)!=image+ThrottleSetter||!SendOriginalDockingZeroInput(frame,controller,observed.target.market))return false;
            }
            return (byte)Call(image + 0x2C65C30, dock, (ulong)(nuint)(&station)) != 0;
        }
        finally { Call(image + 0x62F3A0, (ulong)(nuint)(&station)); }
    }
    private static bool SendOriginalDockingZeroInput(in Snapshot frame, nuint controller, uint market)
    {
        try
        {
            var computer = LocalDockingComputer(frame); var actions = computer != 0 ? Pointer(computer + 0x230) : 0;
            if (computer == 0 || Pointer(computer + 0x240) != controller || actions == 0 || Pointer(actions) != image + 0x512FD90 || Pointer(Pointer(actions) + 0x40) != image + 0x8FEDC0) return false;
            var scratch = stackalloc byte[47]; var temporary = AlignServiceScratch(scratch); new Span<byte>(temporary, 32).Clear();
            try
            {
                Call(image + 0x8FEDC0, actions, (ulong)(nuint)temporary, image + 0x531A568);
                var input = Pointer((nuint)temporary); if (input == 0 || Read<int>(input) <= 0 || Read<uint>(input + 0x1C) == uint.MaxValue) return false;
                Write(input + 0x24, (byte)(Read<byte>(input + 0x24) | 1)); Write(input + 0x1C, unchecked(Read<uint>(input + 0x1C) + 1)); Call(image + ThrottleSetter, controller, F32(0));
                dockingZeroInputReceipt = new() { entity = frame.entity, tick = frame.tick, life = frame.life, binding = input, inputService = actions, market = market }; return true;
            }
            finally { Call(image + 0x204010, (ulong)(nuint)temporary); }
        }
        catch { return false; }
    }
    private static bool LocalDockingZeroConfirmed(bool nativeDuty,bool inputSent,float controllerThrottle,double actualThrottle)
        =>nativeDuty||inputSent&&controllerThrottle==0&&double.IsFinite(actualThrottle)&&Math.Abs(actualThrottle)<=.001;
    private static bool ApplyLocalAction(in Snapshot frame, in LocalActionRequest command, in LocalSelection selection, in LocalFlightObservation observed)
    {
        try
        {
            var now = GetTickCount64();
            if (GetCurrentThreadId() != owningThread || !Enabled() || !inGame || !frame.valid || !frame.healthValid || frame.hullFraction<=0 || frame.healthEmergency || overridden || command.expires <= now || command.entity != frame.entity || command.life != frame.life || command.inputRoot != frame.inputRoot || command.world != frame.referenceWorld || command.epoch != controllerEpoch || command.selection != selection.generation || localConfirmed != selection.generation || !observed.valid || !SameLocal(observed.target, selection.target) || now - observed.tick > 200 || now - frame.tick > 200 || !BoundFsd(frame, frame.fsd) || !LocalRecordMatches(Pointer(frame.fsd + 0x338), selection.target)) return false;
            if (command.action == 1) return RequestLocalDocking(frame, observed);
            if(command.action==13)return RequestNormalBoost(frame);
            if (command.action == 12)
            {
                if (!observed.nativeDockingActive) return true;
                if (observed.nativeLaunchActive || observed.inSupercruise) return false;
                var computer = LocalDockingComputer(frame); var activity = RegisteredComponent(Pointer(frame.life + 0xC8) - 0x30, Read<uint>(image + 0x5F44C98));
                if (computer == 0 || activity == 0 || Pointer(activity) != image + 0x5165E08 || Pointer(Pointer(activity) + 0x30) != image + 0xEACAD0 || (byte)Call(image + 0xED6620, computer) == 0) return false;
                Call(image + 0xEACAD0, activity); var controller = Pointer(frame.inputRoot + 0x2F8);
                if (controller == 0 || Pointer(computer + 0x240) != controller || Pointer(Pointer(controller) + 0x158) != image + ThrottleSetter) return false;
                Call(image + ThrottleSetter, controller, F32(0)); return true;
            }
            if (command.action == 9)
            {
                var computer = LocalDockingComputer(frame); var dock = LocalDocking(frame); var activity = RegisteredComponent(Pointer(frame.life + 0xC8) - 0x30, Read<uint>(image + 0x5F44C98));
                if (computer == 0 || dock == 0 || activity == 0 || !observed.nativeLaunchActive && !observed.nativeLaunchRequested || !observed.dockingVerified || observed.inSupercruise || Pointer(activity) != image + 0x5165E08 || Pointer(Pointer(activity) + 0x30) != image + 0xEACAD0 || Pointer(Pointer(computer) + 0x80) != image + 0xEE8710) return false;
                if (observed.nativeLaunchActive) Call(image + 0xEACAD0, activity);
                if (Read<byte>(computer + 0x374) != 0) { nuint empty = 0; Call(image + 0xEE8710, computer, ulong.MaxValue, (ulong)(nuint)(&empty)); }
                var controller = Pointer(frame.inputRoot + 0x2F8);
                if (controller == 0 || Pointer(computer + 0x240) != controller || Pointer(Pointer(controller) + 0x158) != image + ThrottleSetter) return false;
                Call(image + ThrottleSetter, controller, F32(0)); return true;
            }
            if (command.action == 8)
            {
                var dock = LocalDocking(frame); var state = dock != 0 ? Read<uint>(dock + 0x4C0) : 0; var computer = LocalDockingComputer(frame);
                if (dock == 0 || computer == 0 || !observed.dockingComputerAvailable || !LocalDockingAvailable(computer) || observed.inSupercruise || state is not (5 or 7) || observed.distance > 7500 || Pointer(Pointer(dock) + 0xF0) != image + 0x2C65CD0) return false;
                var station = Pointer(dock + 0x4E0);
                if (station == 0 || Read<uint>(station + 0xC0) != 8 || Read<ulong>(station + 0xB0) != observed.target.market) return false;
                Call(image + 0xEF8A60, computer); return (byte)Call(image + 0x2C65CD0, dock, (ulong)(nuint)(&station)) != 0;
            }
            if (command.action == 7)
            {
                var arrival = LocalCruiseArrival(frame);
                if (arrival == 0 || !observed.safeDisengage || !observed.inSupercruise || frame.rawFsdState != 2 || fsdOwned || observed.target.kind <= 3 || observed.target.kind == 39) return false;
                Call(image + 0x2EAD330, arrival); return true;
            }
            if (command.action == 6)
            {
                if (!observed.inSupercruise || frame.rawFsdState != 2 || fsdOwned || frame.speed > 100000 || observed.cruiseAssistEngaged) return false;
                Lease control; lock (leaseLock) control = lease;
                if (control.expires <= now || !LocalControlMatches(control, frame) || control.throttle != 0) return false;
                var next = new FsdLease { expires = command.expires, sequence = command.sequence, generation = NextFsdGeneration(), entity = frame.entity, fsd = frame.fsd, inputRoot = frame.inputRoot, life = frame.life, command = 4, heatCeiling = 80, local = true };
                lock (leaseLock) fsdLease = next; return true;
            }
            if (command.action == 5)
            {
                if (observed.inSupercruise || frame.rawFsdState != 2 || fsdOwned || HeatHudPercent(frame) >= 90 || Read<byte>(frame.inputRoot + 0x60 + 0xA9) != 0 || Read<byte>(frame.inputRoot + 0x60 + 0xB1) != 0 || Read<byte>(frame.inputRoot + 0x60 + 0xBB) != 0) return false;
                Lease control; lock (leaseLock) control = lease;
                if (control.expires <= now || !LocalControlMatches(control, frame) || control.throttle < .75f) return false;
                var next = new FsdLease { expires = command.expires, sequence = command.sequence, generation = NextFsdGeneration(), entity = frame.entity, fsd = frame.fsd, inputRoot = frame.inputRoot, life = frame.life, command = 1, heatCeiling = 90, supercruiseEntry = true, local = true };
                lock (leaseLock) fsdLease = next; return true;
            }
            if (command.action == 10)
            {
                var dock = LocalDocking(frame); var computer = LocalDockingComputer(frame); var controller = Pointer(frame.inputRoot + 0x2F8);
                if (dock == 0 || computer == 0 || !observed.dockingComputerAvailable || !LocalDockingAvailable(computer) || controller == 0 || Pointer(computer + 0x240) != controller || !observed.dockingVerified || !observed.dockingGranted || observed.inSupercruise || observed.distance > 7500 || Read<uint>(dock + 0x614) != 2 || Read<uint>(dock + 0x4C0) is not (3 or 4) || Read<byte>(dock + 0x4E9) == 255 || Pointer(Pointer(controller) + 0x158) != image + ThrottleSetter) return false;
                var station = Pointer(dock + 0x4E0);
                if (station == 0 || Read<uint>(station + 0xC0) != 8 || Read<ulong>(station + 0xB0) != observed.target.market) return false;
                var actualThrottle=Read<float>(frame.inputRoot+0x70);
                if((byte)Call(image+0xED6620,computer)!=0)return true;
                bool released;lock(leaseLock)released=lease.expires<=now&&fsdLease.expires<=now;
                if(!released||fsdOwned)return false;
                var sourceVerified=ReadOriginalDockingThrottle(computer,out var sourceThrottle);
                if(!LocalDockingSourceZeroConfirmed(false,observed.dockingZeroInputSent,Read<float>(controller+0x680),actualThrottle,sourceVerified?sourceThrottle:double.NaN)
                    &&!SendOriginalDockingZeroInput(frame,controller,observed.target.market))return false;
                if(!CommitOriginalDockingZeroAxis(frame.inputRoot,controller,actualThrottle,true,released,out _))return false;
                lock(localLock)dockingZeroUpdate=new(){command=command,computer=computer,controller=controller,fsd=frame.fsd,market=observed.target.market,throttle=actualThrottle};
                return true;
            }
            if (command.action == 11)
            {
                var controller = Pointer(frame.inputRoot + 0x2F8);
                if (observed.inSupercruise || frame.rawFsdState != 2 || fsdOwned || controller == 0 || Pointer(Pointer(controller) + 0x158) != image + ThrottleSetter) return false;
                return SendOriginalDockingZeroInput(frame, controller, 0);
            }
            var assist = LocalCruiseAssist(frame);
            if (command.action == 2)
            {
                if (assist == 0 || !observed.inSupercruise || !observed.cruiseAssistAvailable || (byte)Call(image + 0xECAF00, assist) == 0 || observed.cruiseAssistObscured || observed.distance < 1) return false;
                if (observed.cruiseAssistEnabled && observed.cruiseAssistMatches) return true;
                var direction = Scale(Subtract(observed.destination.position, observed.ship.position), 1 / observed.distance);
                if (Dot(direction, observed.ship.forward) < Math.Cos(5.0 * Math.PI / 180)) return false;
                var controller = Pointer(frame.inputRoot + 0x2F8);
                if (controller == 0 || Pointer(Pointer(controller) + 0x158) != image + ThrottleSetter || !observed.cruiseParametersVerified) return false;
                Call(image + ThrottleSetter, controller, F32((float)observed.cruiseApproachThrottle)); Call(image + 0xEEA430, assist, 1); return true;
            }
            if (command.action == 3)
            {
                if (assist == 0 || !observed.cruiseAssistMatches || !observed.cruiseAssistEnabled && !observed.cruiseAssistEngaged) return true;
                Call(image + 0xEEA430, assist, 0); return true;
            }
            return false;
        }
        catch { return false; }
    }
    private static void PollLocalAction(in Snapshot frame)
    {
        PollNormalBoostPulse(frame);
        LocalActionRequest command; LocalSelection selection; LocalFlightObservation observed;
        lock (localLock) { command = localAction; selection = localSelection; observed = localObservation; }
        if (command.generation == 0 || command.generation == localActionConsumed) return;
        if (ApplyLocalAction(frame, command, selection, observed)) localActionApplied = command.generation; else localActionFailed = command.generation;
        localActionConsumed = command.generation;
    }
    private static string LocalIdentityName(in LocalIdentity value)
    {
        fixed (byte* text = value.name) { var length = 0; while (length < 513 && text[length] != 0) length++; return Encoding.UTF8.GetString(new ReadOnlySpan<byte>(text, length)); }
    }
    private static JsonObject LocalIdentityJson(in LocalIdentity value) => Obj(("key", value.key), ("bodyAddress", value.body.ToString(CultureInfo.InvariantCulture)), ("kind", value.kind), ("marketId", value.market), ("name", LocalIdentityName(value)));
    private static JsonArray LocalVector(Vector value) => Arr(value.x, value.y, value.z);
    private static JsonObject LocalFlightRead(in Snapshot frame)
    {
        LocalFlightObservation value;DockingMapperReceipt mapper;
        lock(localLock){value=localObservation;mapper=dockingInputMapperReceipt;}var now=GetTickCount64();
        if (!frame.valid || !value.valid || value.entity != frame.entity || value.world != frame.referenceWorld || now - value.tick > 200) throw new InvalidOperationException("Local target telemetry unavailable or stale");
        return Obj(("sequence", value.sequence), ("observedAtUnixMilliseconds", value.utc), ("entityId", value.entity.ToString(CultureInfo.InvariantCulture)), ("referenceWorldAddress", value.world.ToString(CultureInfo.InvariantCulture)),
            ("geometryVerified", true), ("selected", value.selected), ("target", LocalIdentityJson(value.target)), ("position", LocalVector(value.ship.position)), ("forward", LocalVector(value.ship.forward)), ("up", LocalVector(value.ship.up)), ("targetPosition", LocalVector(value.destination.position)),
            ("velocity", LocalVector(value.velocity)), ("targetVelocity", LocalVector(value.targetVelocity)), ("velocityVerified", value.velocityValid), ("angularVelocity", LocalVector(value.angularVelocity)), ("angularVelocityVerified", value.angularVelocityValid), ("speedZeroInputSent", value.speedZeroInputSent),
            ("distanceMetres", value.distance), ("speedMetresPerSecond", value.speed), ("throttle", value.throttle), ("rawDockingState", value.dockingState), ("rawRequestState", value.requestState), ("rawPad", value.pad), ("normalSpeedLimit", value.normalSpeedLimit), ("cruiseSpeedLimit", value.cruiseSpeedLimit), ("accelerationLowerBound", value.accelerationLowerBound),
            ("safeDisengage", value.safeDisengage), ("safeDropDistance", value.safeDropDistance), ("safeDropSpeed", value.safeDropSpeed), ("cruiseParametersVerified", value.cruiseParametersVerified), ("cruiseApproachSeconds", value.cruiseApproachSeconds), ("cruiseApproachThrottle", value.cruiseApproachThrottle),
            ("rawFsdState", frame.rawFsdState), ("rawFsdMode", frame.rawFsdMode), ("rawFsdStage", frame.rawFsdStage), ("inSupercruise", value.inSupercruise),
            ("normalBoostAvailable",TryNormalBoostBinding(frame,out _,out _)),("normalBoostInputs",normalBoostInputs),("normalBoostReleased",normalBoostReleased),
            ("normalBoostPressed",normalBoostPulse is not null),("normalBoostLastTick",lastNormalBoostAt),
            ("dockingZeroAxisCommits", dockingZeroAxisCommits), ("dockingZeroAxisRestoresSkipped", dockingZeroAxisRestoresSkipped),
            ("dockingZeroUpdateCalls",dockingZeroUpdateCalls),("dockingZeroUpdateMatched",dockingZeroUpdateMatched),("dockingZeroUpdateApplied",dockingZeroUpdateApplied),
            ("dockingInputMapperCalls",dockingInputMapperCalls),("dockingInputMapperMatched",dockingInputMapperMatched),("dockingInputMapperApplied",dockingInputMapperApplied),
            ("dockingInputMapper",Obj(("verified",mapper.verified),("sequence",mapper.sequence),("entityId",mapper.entity.ToString(CultureInfo.InvariantCulture)),
                ("observedAtUnixMilliseconds",mapper.utc),("accumulatorBefore",mapper.before),("accumulatorAfter",mapper.after),("sourceAfter",mapper.source))),
            ("supercruiseAssist", Obj(("available", value.cruiseAssistAvailable), ("enabled", value.cruiseAssistEnabled), ("engaged", value.cruiseAssistEngaged), ("matchesTarget", value.cruiseAssistMatches), ("obscured", value.cruiseAssistObscured))),
            ("docking", Obj(("verified", value.dockingVerified), ("computerAvailable", value.dockingComputerAvailable), ("clearanceGranted", value.dockingGranted), ("assistAllowed", value.dockingAssistAllowed), ("assistEnabled", value.dockingAssistEnabled), ("assistEngaged", value.dockingAssistEngaged), ("nativeDutyActive", value.nativeDockingActive), ("nativeLaunchActive", value.nativeLaunchActive), ("nativeLaunchRequested", value.nativeLaunchRequested), ("throttleZero", value.dockingThrottleZero), ("zeroThrottleInputSent", value.dockingZeroInputSent))));
    }
    private static JsonObject LocalFlightRequest(string op, JsonElement request, string owner, in Snapshot frame)
    {
        var now = GetTickCount64();
        if (op == "local.suspend")
        {
            if (clientOwner != owner) throw new InvalidOperationException("Local control belongs to another controller");
            lock (leaseLock) { if (lease.local) lease.expires = 0; if (fsdLease.local) fsdLease.expires = 0; }
            lock(localLock)dockingZeroUpdate.command.expires=0;
            return Obj(("suspended", true));
        }
        if (!Enabled() || !inGame || !frame.valid || !frame.healthValid || frame.hullFraction<=0 || frame.healthEmergency || now - frame.tick > 200) throw new InvalidOperationException("Fresh healthy player ship required for local navigation");
        ulong expiry; lock (leaseLock) expiry = Math.Max(lease.expires, Math.Max(fsdLease.expires, targetLease.expires));
        LocalSelection wanted; lock (localLock) wanted = localSelection;
        if (expiry <= now && wanted.expires <= now && !fsdOwned && op == "local.select") clientOwner = "";
        if (clientOwner.Length != 0 && clientOwner != owner) throw new InvalidOperationException("Another controller owns local navigation");
        if (op == "local.select")
        {
            if (expiry > now || !LocalSelectionFsdReady(frame.rawFsdState,fsdOwned)) throw new InvalidOperationException("Stop flight control before selecting a local destination");
            LocalIdentity identity = new() { key = request.Required("key").GetInt32(), body = ulong.Parse(request.Required("bodyAddress").GetString()!, CultureInfo.InvariantCulture), kind = request.Required("kind").GetUInt32(), market = request.Required("marketId").GetUInt32() };
            var name = request.Required("name").GetString()!; var encoded = Encoding.UTF8.GetBytes(name);
            if (identity.key < 0 || identity.body == 0 || identity.kind == 0 || encoded.Length == 0 || encoded.Length >= 513 || name.Contains('\0')) throw new InvalidOperationException("Invalid local target identity");
            encoded.CopyTo(new Span<byte>(identity.name, 513));
            if (clientOwner.Length == 0) overridden = false;
            ClaimController(owner); wanted = new() { target = identity, generation = ++localGeneration, expires = now + 300, entity = frame.entity, epoch = controllerEpoch, life = frame.life, fsd = frame.fsd, inputRoot = frame.inputRoot };
            lock (localLock) localSelection = wanted;
        }
        else if (clientOwner != owner || wanted.generation == 0 || request.Required("generation").GetUInt64() != wanted.generation) throw new InvalidOperationException("No matching local target request");
        if (op == "local.action")
        {
            var reference = Reference(request.Required("sequence").GetUInt64(), frame, now); var utc = UtcMilliseconds(); var deadline = request.Required("expiresAtUnixMilliseconds").GetUInt64();
            var action = request.Required("action").GetString() switch { "requestDocking" => 1u, "enableSupercruiseAssist" => 2u, "cancelSupercruiseAssist" => 3u, "enterSupercruise" => 5u, "leaveSupercruiseSlowly" => 6u, "safeDisengage" => 7u, "launch" => 8u, "cancelLaunch" => 9u, "zeroThrottleForDocking" => 10u, "setNormalThrottleZero" => 11u, "cancelDockingAssist" => 12u, "boostThrusters"=>13u, _ => 0u };
            if (action == 0 || deadline <= utc || deadline > utc + 300 || overridden || localConfirmed != wanted.generation) throw new InvalidOperationException("Invalid or expired local action");
            var next = new LocalActionRequest { generation = ++localActionGeneration, selection = wanted.generation, expires = Math.Min(now + deadline - utc, reference.tick + 300), sequence = reference.sequence, entity = frame.entity, epoch = controllerEpoch, world = frame.referenceWorld, life = frame.life, inputRoot = frame.inputRoot, action = action };
            lock (localLock) localAction = next; return Obj(("queued", true), ("actionGeneration", next.generation));
        }
        if (op == "local.action.status")
        {
            var generation = request.Required("actionGeneration").GetUInt64(); LocalActionRequest command; lock (localLock) command = localAction;
            if (generation != command.generation || command.selection != wanted.generation) throw new InvalidOperationException("No matching local action");
            var applied = localActionApplied == generation; var failed = localActionFailed == generation;
            return Obj(("applied", applied), ("failed", failed || !applied && command.expires <= now), ("pending", !applied && !failed && command.expires > now), ("actionGeneration", generation));
        }
        if (op == "local.axes.release") { lock (leaseLock) if (lease.local) lease.expires = 0; return Obj(("released", true)); }
        if (op == "local.apply")
        {
            RequirePhysicalInputSources(frame,now);
            var reference = Reference(request.Required("sequence").GetUInt64(), frame, now); var utc = UtcMilliseconds(); var deadline = request.Required("expiresAtUnixMilliseconds").GetUInt64();
            if (deadline <= utc || deadline > utc + 300 || overridden || localConfirmed != wanted.generation) throw new InvalidOperationException("Local control frame expired or selection changed");
            var values = request.Required("axes"); if (values.GetArrayLength() != 6) throw new InvalidOperationException("Invalid local control axes");
            Float6 axes = default; var invalidAxes = false;
            for (var index = 0; index < 6; index++) { axes[index] = values[index].GetSingle(); invalidAxes |= !float.IsFinite(axes[index]) || Math.Abs(axes[index]) > 1; }
            var throttle = request.TryGetProperty("throttle", out var throttleValue) ? throttleValue.GetSingle() : -1;
            if (!float.IsFinite(throttle) || throttle != -1 && (throttle < 0 || throttle > 1) || invalidAxes) throw new InvalidOperationException("Invalid local control axes");
            var next = new Lease { expires = Math.Min(now + deadline - utc, reference.tick + 300), sequence = reference.sequence, inputRoot = frame.inputRoot, axes = axes, throttle = throttle, epoch = controllerEpoch, local = true, localKey = wanted.target.key, localKind = wanted.target.kind, localBody = wanted.target.body, localMarket = wanted.target.market, world = frame.referenceWorld, yieldOnDockingGrant = request.Bool("yieldOnDockingGrant") };
            if (!LocalControlMatches(next, frame)) throw new InvalidOperationException("Local target changed before applying controls");
            lock (leaseLock)
            {
                lease = next;
                if (fsdLease.local && fsdLease.entity == frame.entity && fsdLease.life == frame.life && fsdLease.command == 1 && fsdLease.expires != 0 && frame.rawFsdState == 3) { fsdLease.expires = next.expires; fsdLease.sequence = reference.sequence; }
            }
            return Obj(("accepted", true), ("generation", wanted.generation), ("sequence", reference.sequence));
        }
        LocalFlightObservation observed; LocalTargetObservation selected; string stage;
        lock (localLock) { observed = localObservation; selected = localTargetObservation; stage = localSampleStage; }
        // The original navigation selection is observable before a remote body's
        // full flight geometry is ready. Confirm that selection independently;
        // local.read and all flight actions still require complete telemetry.
        var confirmed = wanted.entity == frame.entity && wanted.life == frame.life && wanted.fsd == frame.fsd && wanted.inputRoot == frame.inputRoot &&
            LocalSelectionAcknowledged(wanted, selected, localConfirmed, now, controllerEpoch, overridden);
        var telemetryReady = observed.valid && observed.entity == frame.entity && observed.world == frame.referenceWorld && SameLocal(observed.target, wanted.target) && observed.tick <= now && now - observed.tick <= 200;
        return Obj(("generation", wanted.generation), ("selected", confirmed), ("pending", !confirmed && localFailed != wanted.generation && wanted.expires > now),
            ("target", LocalIdentityJson(selected.target)), ("flightInputsSent", 0), ("telemetryReady", telemetryReady), ("sampleStage", stage),
            ("sampleLimits", Obj(("normalSpeed", double.IsFinite(observed.normalSpeedLimit) ? observed.normalSpeedLimit : 0),
                ("cruiseSpeed", double.IsFinite(observed.cruiseSpeedLimit) ? observed.cruiseSpeedLimit : 0),
                ("acceleration", double.IsFinite(observed.accelerationLowerBound) ? observed.accelerationLowerBound : 0))));
    }
}