#if PLUGIN_SESSION_RECOVERY
using System.IO.Pipes;
using System.Text;
namespace XFEEDToolBox.Plugin;
internal static unsafe partial class SessionRecoveryRuntime
{
private sealed class ResetWork
{
public string id="",owner="",issue="",phase="preparing",failureStage="";
public ulong generation,sequence,deadline,entity,utc,publishedAt;public uint market;
public bool pending,applied,failed,called,cancelRequested,startRequested,startAttempted,startCalled;
public ulong startAt;
public string? startFailure;
public float? before,sourceBefore,after,source,actualAfter,controllerAfter,publishedBefore;
public Navigation.RecoveryResetBinding? proof;
}
private static readonly object resetGate=new();
private static readonly Dictionary<string,ResetWork> resetReceipts=new(StringComparer.Ordinal);
private static ResetWork? lastReset;
[ThreadStatic]private static string? resetBridgeStage;
private static int WaitResetRead(ValueTask<int> operation)=>operation.AsTask().GetAwaiter().GetResult();
private static void WaitResetWrite(ValueTask operation)=>operation.AsTask().GetAwaiter().GetResult();
private static bool ResetId(string value)=>value.Length==32&&value.All(c=>c is >= '0' and <= '9' or >= 'a' and <= 'f');
private static bool ResetDeadline(ulong deadline,ulong now,int ttl)=>ttl is >0 and <=250&&deadline>now&&deadline-now<=(ulong)ttl;
private static JsonObject ResetDescription(ResetWork? selected=null)
{
lock(resetGate)
{
var value=selected??lastReset;var expired=value!=null&&!value.applied&&value.deadline<=Utc();
return Obj(("requestId",value?.id),("nativeGeneration",value?.generation??0),("pending",value?.pending==true&&!expired),
("applied",value?.applied==true),("failed",value?.failed==true||expired),("expired",expired),("issue",value?.issue),
("phase",value?.phase),("failureStage",value?.failureStage),("cancelRequested",value?.cancelRequested==true),("entityId",value?.entity.ToString()),("marketId",value?.market??0),("observedAtUnixMilliseconds",value?.utc??0),
("node",value?.proof?.node.ToString("x")),("source",value?.proof?.source.ToString("x")),
("registry",value?.proof?.registry.ToString("x")),
("publishedSourceBefore",value?.publishedBefore),("publishedAtUnixMilliseconds",value?.publishedAt??0),
("accumulatorBefore",value?.before),("sourceBefore",value?.sourceBefore),("accumulatorAfter",value?.after),("sourceAfter",value?.source),
("actualThrottleAfter",value?.actualAfter),("controllerThrottleAfter",value?.controllerAfter),("originalResetCalled",value?.called==true),
("dockingStartRequested",value?.startRequested==true),("originalDockingStartAttempted",value?.startAttempted==true),
("originalDockingStartCalled",value?.startCalled==true),("dockingStartAtUnixMilliseconds",value?.startAt??0),("dockingStartFailure",value?.startFailure),
("expiresAtUnixMilliseconds",value?.deadline??0),("gameAccumulatorWrittenBySdk",false),("gameOutputWrittenBySdk",false),("activeFlagWritten",false),("aiWritten",false));
}
}
private static JsonElement ResetNav(JsonObject request,ulong deadline)
{
var operation=request["op"]!.GetValue<string>();resetBridgeStage=operation+".deadline";
var remaining=deadline>Utc()?deadline-Utc():0;if(remaining==0)throw new TimeoutException("Original reset intent expired");
using var timeout=new CancellationTokenSource(TimeSpan.FromMilliseconds(Math.Min(150,remaining)));
using var pipe=new NamedPipeClientStream(".",$"XFEEDToolBox.Navigation.{ProcessId}",PipeDirection.InOut,PipeOptions.Asynchronous);
resetBridgeStage=operation+".connect";pipe.ConnectAsync(timeout.Token).GetAwaiter().GetResult();
var data=Encoding.UTF8.GetBytes(request.ToJsonString()+"\n");resetBridgeStage=operation+".write";
// A pending IValueTaskSource.GetResult does not block. Convert to Task
// before a synchronous wait on this dedicated SDK pipe worker.
WaitResetWrite(pipe.WriteAsync(data.AsMemory(),timeout.Token));
resetBridgeStage=operation+".flush";pipe.FlushAsync(timeout.Token).GetAwaiter().GetResult();
var buffer=new byte[65536];var count=0;
while(count<buffer.Length)
{
resetBridgeStage=operation+".read";var read=WaitResetRead(pipe.ReadAsync(buffer.AsMemory(count),timeout.Token));if(read==0)break;count+=read;if(buffer[count-1]=='\n')break;
}
if(count is 0 or 65536)throw new IOException("Invalid original reset bridge response");
resetBridgeStage=operation+".parse";using var parsed=JsonDocument.Parse(buffer.AsMemory(0,count));var root=parsed.RootElement;
if(!root.GetProperty("ok").GetBoolean())throw new InvalidOperationException(root.GetProperty("error").GetString());
var result=root.GetProperty("result").Clone();resetBridgeStage=operation+".complete";return result;
}
private static JsonObject ResetBridgeProbe()
{
lock(resetGate)if(lastReset?.pending==true||lastReset?.phase=="dispatching")throw new InvalidOperationException("Cannot probe during a reset intent");
JsonElement? read=null,health=null,local=null;string? error=null,localIssue=null;var began=Utc();
try
{
read=ResetNav(Obj(("op","read")),began+350);health=ResetNav(Obj(("op","health.read")),began+350);
try{local=ResetNav(Obj(("op","local.read")),began+350);}catch(Exception failure){localIssue=failure.ToString();}
}
catch(Exception failure){error=failure.ToString();}
return Obj(("service",Service),("processId",ProcessId),("gameSha256",GameHash),("bridgePassed",read!=null&&health!=null&&error==null),
("stage",resetBridgeStage),("error",error),("localIssue",localIssue),("read",read is {} r?JsonNode.Parse(r.GetRawText()):null),
("health",health is {} h?JsonNode.Parse(h.GetRawText()):null),("local",local is {} l?JsonNode.Parse(l.GetRawText()):null),
("startedAtUnixMilliseconds",began),("finishedAtUnixMilliseconds",Utc()),("gameInputsSent",0),("resetCalled",false));
}
private static bool ResetFresh(JsonElement value,ulong now)
{var at=value.GetProperty("observedAtUnixMilliseconds").GetUInt64();return at<=now&&now-at<=200;}
private static bool SameResetTarget(JsonElement a,JsonElement b)=>a.GetProperty("key").GetInt32()==b.GetProperty("key").GetInt32()
&&a.GetProperty("kind").GetUInt32()==b.GetProperty("kind").GetUInt32()&&a.GetProperty("marketId").GetUInt32()==b.GetProperty("marketId").GetUInt32()
&&a.GetProperty("bodyAddress").GetString()==b.GetProperty("bodyAddress").GetString()&&a.GetProperty("name").GetString()==b.GetProperty("name").GetString();
private static void CheckResetTelemetry(JsonElement frame,JsonElement health,JsonElement local,ulong sequence)
{
var now=Utc();var h=health.GetProperty("shipHealth");var dock=local.GetProperty("docking");var hull=h.GetProperty("hullFraction").GetDouble();
if(!ResetFresh(frame,now)||!ResetFresh(health,now)||!ResetFresh(local,now)||!frame.GetProperty("inGame").GetBoolean()
||!frame.GetProperty("localPlayerShipVerified").GetBoolean()||!health.GetProperty("localPlayerShipVerified").GetBoolean()
||!h.GetProperty("verified").GetBoolean()||!double.IsFinite(hull)||hull is <=0 or >1||h.GetProperty("damageObserved").GetBoolean()||h.GetProperty("emergency").GetBoolean()
||frame.GetProperty("entityId").GetString()!=health.GetProperty("entityId").GetString()||frame.GetProperty("entityId").GetString()!=local.GetProperty("entityId").GetString()
||frame.GetProperty("playerOverride").GetBoolean()||frame.GetProperty("fsd").GetProperty("ownedCharging").GetBoolean()
||frame.GetProperty("rawFsdState").GetInt32() is not(1 or 2)||frame.GetProperty("sequence").GetUInt64()<sequence||frame.GetProperty("sequence").GetUInt64()-sequence>32
||!local.GetProperty("geometryVerified").GetBoolean()||!local.GetProperty("selected").GetBoolean()||local.GetProperty("inSupercruise").GetBoolean()
||local.GetProperty("distanceMetres").GetDouble()>7500||!dock.GetProperty("verified").GetBoolean()||!dock.GetProperty("computerAvailable").GetBoolean()
// The optional station interface is absent on the actual Homer
// entity, so assistAllowed defaults false without a getter result.
// Original action 10 does not use it. ATC and module readiness are
// the prerequisites; real zero and AI takeover are checked later.
||!dock.GetProperty("clearanceGranted").GetBoolean()||dock.GetProperty("nativeLaunchActive").GetBoolean()
||dock.GetProperty("nativeDutyActive").GetBoolean()||local.GetProperty("rawRequestState").GetInt32()!=2||local.GetProperty("rawDockingState").GetInt32() is not(3 or 4)
||local.GetProperty("rawPad").GetInt32()==255)throw new InvalidOperationException("Original reset telemetry, main ship, ownership or ATC is not eligible");
}
private static JsonNode ResetRequest(string op,JsonElement request)
{
var id=request.Str("requestId");if(!ResetId(id))throw new InvalidOperationException("Explicit reset request identity required");
ResetWork value;
lock(resetGate)
{
if(resetReceipts.TryGetValue(id,out var known))
{if(op=="docking.reset.cancel"){known.cancelRequested=true;known.pending=false;if(known.phase!="dispatching"){known.failed|=!known.applied;known.phase="cancelled";}}return ResetDescription(known);}
if(op!="docking.reset.arm")throw new InvalidOperationException("No matching original reset request");
var owner=request.Str("owner");var deadline=request.U64("expiresAtUnixMilliseconds");var ttl=request.Int("ttlMilliseconds");
if(!enabled||!ResetId(owner)||!ResetDeadline(deadline,Utc(),ttl)||resetReceipts.Count>=32||lastReset?.pending==true&&lastReset.deadline>Utc())
throw new InvalidOperationException("Reset owner, original deadline or one-use boundary differs");
if(request.TryGetProperty("startDockingAfterZero",out var startValue)&&startValue.ValueKind is not(JsonValueKind.True or JsonValueKind.False))
throw new InvalidOperationException("Explicit boolean original docking start intent required");
value=new(){id=id,owner=owner,deadline=deadline,sequence=request.U64("sequence"),generation=0,startRequested=startValue.ValueKind==JsonValueKind.True};
resetReceipts.Add(id,value);lastReset=value;
}
try
{
Root context;lock(gate)context=root;
if(!context.valid||context.state!="InGame"||context.next!=context.state||!Fresh(context.tick,GetTickCount64()))throw new InvalidOperationException("Stable original InGame context required");
value.phase="initial-native-reads";
var frame=ResetNav(Obj(("op","read")),value.deadline);var health=ResetNav(Obj(("op","health.read")),value.deadline);
var local=ResetNav(Obj(("op","local.read")),value.deadline);value.phase="initial-telemetry-schema";CheckResetTelemetry(frame,health,local,value.sequence);
var oldGeneration=request.U64("generation");if(oldGeneration==0||value.sequence==0)throw new InvalidOperationException("Reset original reference is missing");
value.phase="initial-selection-status";var old=ResetNav(Obj(("op","local.status"),("owner",value.owner),("generation",oldGeneration)),value.deadline);
var target=local.GetProperty("target").Clone();
if(!old.GetProperty("selected").GetBoolean()||!old.GetProperty("telemetryReady").GetBoolean()||!SameResetTarget(old.GetProperty("target"),target))throw new InvalidOperationException("Reset original selection differs");
value.entity=ulong.Parse(frame.GetProperty("entityId").GetString()!);value.market=target.GetProperty("marketId").GetUInt32();
// The original selection operation rejects any active control lease
// and holds its owner for 300 ms. The original intent stays <=250 ms.
value.phase="native-selection-intent";
var selected=ResetNav(Obj(("op","local.select"),("owner",value.owner),("key",target.GetProperty("key").GetInt32()),
("bodyAddress",target.GetProperty("bodyAddress").GetString()),("kind",target.GetProperty("kind").GetUInt32()),("marketId",value.market),("name",target.GetProperty("name").GetString())),value.deadline);
value.generation=selected.GetProperty("generation").GetUInt64();
while(!selected.GetProperty("selected").GetBoolean())
{
if(!selected.GetProperty("pending").GetBoolean())throw new InvalidOperationException("Reset native selection failed");
Thread.Sleep(1);selected=ResetNav(Obj(("op","local.status"),("owner",value.owner),("generation",value.generation)),value.deadline);
}
if(!SameResetTarget(selected.GetProperty("target"),target))throw new InvalidOperationException("Reset native selection identity changed");
value.phase="native-zero-intent";
var zero=ResetNav(Obj(("op","local.action"),("owner",value.owner),("generation",value.generation),("sequence",value.sequence),
("action","zeroThrottleForDocking"),("expiresAtUnixMilliseconds",value.deadline)),value.deadline);
var actionGeneration=zero.GetProperty("actionGeneration").GetUInt64();
do
{
zero=ResetNav(Obj(("op","local.action.status"),("owner",value.owner),("generation",value.generation),("actionGeneration",actionGeneration)),value.deadline);
if(zero.GetProperty("failed").GetBoolean())throw new InvalidOperationException("Original zero input failed");
if(zero.GetProperty("applied").GetBoolean())break;Thread.Sleep(1);
}while(true);
value.phase="post-zero-native-reads";
frame=ResetNav(Obj(("op","read")),value.deadline);health=ResetNav(Obj(("op","health.read")),value.deadline);local=ResetNav(Obj(("op","local.read")),value.deadline);
value.phase="post-zero-telemetry-schema";CheckResetTelemetry(frame,health,local,value.sequence);
if(ulong.Parse(frame.GetProperty("entityId").GetString()!)!=value.entity||!SameResetTarget(local.GetProperty("target"),target))throw new InvalidOperationException("Reset main ship changed after original zero input");
JsonObject[] candidates;lock(gate)candidates=mapperNodes.Values.Where(row=>row["expectedType"]?.GetValue<bool>()==true
&&Utc()>=row["observedAtUnixMilliseconds"]!.GetValue<ulong>()&&Utc()-row["observedAtUnixMilliseconds"]!.GetValue<ulong>()<=200).ToArray();
var h=health.GetProperty("shipHealth");Navigation.RecoveryResetBinding? proof=null;
foreach(var candidate in candidates)
{
Navigation.RecoveryResetBinding bound;
try{bound=Navigation.BindRecoveryReset(value.entity,ulong.Parse(frame.GetProperty("referenceWorldAddress").GetString()!),target,
h.GetProperty("hullFraction").GetDouble(),h.GetProperty("shieldFraction").ValueKind==JsonValueKind.Number?h.GetProperty("shieldFraction").GetDouble():null,
(nuint)Convert.ToUInt64(candidate["node"]!.GetValue<string>(),16));}catch{continue;}
if(candidate["source"]!.GetValue<string>()!=bound.source.ToString("x")||candidate["registry"]!.GetValue<string>()!=bound.registry.ToString("x"))continue;
if(proof!=null)throw new InvalidOperationException("Reset current mapper is ambiguous");proof=bound;
value.publishedBefore=candidate["sourceAfter"]!.GetValue<float>();value.publishedAt=candidate["observedAtUnixMilliseconds"]!.GetValue<ulong>();
}
if(proof==null)throw new InvalidOperationException("Reset current owned mapper not observed");
lock(resetGate)
{
if(!enabled||Utc()>=value.deadline||value.phase=="cancelled")throw new TimeoutException("Original reset deadline expired before mapper dispatch");
value.proof=proof;value.pending=true;value.phase="armed";
}
}
catch(Exception error){lock(resetGate){value.pending=false;value.failed=true;value.failureStage=value.phase+" | "+resetBridgeStage;value.issue=error.ToString();value.phase="failed-no-replay";}}
return ResetDescription(value);
}
private static ResetWork? BeginOriginalReset(nuint node,float dt)
{
ResetWork? wanted;lock(resetGate){wanted=lastReset;if(wanted?.pending!=true)return null;}
Root context;lock(gate)context=root;
if(!enabled||GetCurrentThreadId()!=expectedThread||!float.IsFinite(dt)||dt<=0||dt>.25f||!context.valid||context.thread!=expectedThread
||context.state!="InGame"||context.next!=context.state||!Fresh(context.tick,GetTickCount64())||Utc()>=wanted.deadline)return null;
if(wanted.proof==null||wanted.proof.node!=node)return null;
lock(resetGate){if(!wanted.pending||Utc()>=wanted.deadline)return null;wanted.pending=false;wanted.phase="dispatching";}
Navigation.CallRecoveryReset(wanted.proof,node,wanted.deadline,()=>ResetCanCommit(wanted));
lock(resetGate){wanted.called=true;wanted.before=wanted.proof.before;wanted.sourceBefore=wanted.proof.sourceBefore;}return wanted;
}
private static void FinishOriginalReset(ResetWork? wanted,nuint node)
{
if(wanted?.called!=true||wanted.proof==null)return;
var bound=wanted.proof.baseline;var controller=Pointer(bound.inputRoot+0x2F8);
if(node!=wanted.proof.node||Pointer(node+0x78)!=wanted.proof.source||Pointer(wanted.proof.computer+0x260)!=wanted.proof.source
||Read<uint>(bound.life+0xC0)!=8||Read<ulong>(bound.life+0xB0)!=wanted.entity
||LocalPlayerIdentity.ReadLife(bound.inputRoot,image,end)!=bound.life||controller==0||Pointer(wanted.proof.computer+0x240)!=controller)
throw new InvalidOperationException("Reset output owner changed");
var accumulator=Read<float>(node+0xD0);var output=Read<float>(wanted.proof.source+0x18);
var actual=Read<float>(bound.inputRoot+0x70);var throttle=Read<float>(controller+0x680);
var valid=float.IsFinite(accumulator)&&float.IsFinite(output)&&float.IsFinite(actual)&&float.IsFinite(throttle)
&&Math.Abs(accumulator)<=.001f&&Math.Abs(output)<=.001f&&Math.Abs(actual)<=.001f&&Math.Abs(throttle)<=.001f;
lock(resetGate){wanted.after=float.IsFinite(accumulator)?accumulator:null;wanted.source=float.IsFinite(output)?output:null;
wanted.actualAfter=float.IsFinite(actual)?actual:null;wanted.controllerAfter=float.IsFinite(throttle)?throttle:null;wanted.utc=Utc();}
if(valid&&wanted.startRequested)
{
try
{
Navigation.CallRecoveryDockingStart(wanted.proof,node,wanted.deadline,()=>ResetCanCommit(wanted),()=>
{
lock(resetGate)
{
if(!ResetCanCommit(wanted)||wanted.startAttempted)throw new InvalidOperationException("Original docking start intent expired, was cancelled or already dispatched");
wanted.startAttempted=true;wanted.startAt=Utc();
}
});
lock(resetGate)wanted.startCalled=true;
}
catch(Exception error){lock(resetGate)wanted.startFailure=error.ToString();throw;}
}
lock(resetGate){wanted.applied=valid;wanted.failed=!valid;wanted.phase=valid?(wanted.startCalled?"original-zero-and-docking-start-requested":"original-reset-and-output-zero"):"original-output-not-zero";
if(!valid)wanted.issue="Original mapper did not publish zero; callback will not be repeated";}
}
private static void FailOriginalReset(string issue)
{lock(resetGate)if(lastReset is {} value&&value.phase=="dispatching"){value.pending=false;value.failed=true;value.issue=issue;value.phase="mapper-rejected-no-replay";}}
private static bool ResetCanCommit(ResetWork wanted)
{lock(resetGate)return enabled&&!wanted.cancelRequested&&!wanted.failed&&wanted.phase=="dispatching"&&Utc()<wanted.deadline;}
private static void CancelOriginalReset(){lock(resetGate)if(lastReset is {} value){value.pending=false;value.cancelRequested=true;value.failed|=!value.applied;value.phase="deactivated";}}
private static bool DelayedResetIoSelfTest()
{
try
{
var name="XFEEDToolBox.ResetFixture."+Guid.NewGuid().ToString("N");
using var timeout=new CancellationTokenSource(TimeSpan.FromSeconds(2));
using var server=new NamedPipeServerStream(name,PipeDirection.InOut,1,PipeTransmissionMode.Byte,PipeOptions.Asynchronous);
using var readIssued=new ManualResetEventSlim();
var worker=new Thread(()=>
{
try{server.WaitForConnection();if(server.ReadByte()!=0x41)return;readIssued.Wait(timeout.Token);Thread.Sleep(20);server.WriteByte(0x5A);server.Flush();}catch{}
}){IsBackground=true};worker.Start();
using var client=new NamedPipeClientStream(".",name,PipeDirection.InOut,PipeOptions.Asynchronous);
client.ConnectAsync(timeout.Token).GetAwaiter().GetResult();WaitResetWrite(client.WriteAsync(new byte[]{0x41}.AsMemory(),timeout.Token));
var bytes=new byte[1];var pending=client.ReadAsync(bytes.AsMemory(),timeout.Token);var asynchronous=!pending.IsCompleted;readIssued.Set();
var length=WaitResetRead(pending);return asynchronous&&length==1&&bytes[0]==0x5A&&worker.Join(1000);
}
catch{return false;}
}
internal static uint ResetSelfTest()
{
if(started||ImageHash(ModulePath())==GameHash)return 0;uint mask=0;
if(ResetId(new string('a',32))&&!ResetId(new string('A',32))&&!ResetId(new string('a',31)))mask|=1;
if(ResetDeadline(1200,1000,250)&&!ResetDeadline(1251,1000,250))mask|=2;
if(!ResetDeadline(1000,1000,250)&&!ResetDeadline(999,1000,250)&&!ResetDeadline(1100,1000,0))mask|=4;
if(ResetDeadline(1100,1000,100)&&!ResetDeadline(1101,1000,100)&&!ResetDeadline(1100,1000,251))mask|=8;
var entry=new ResetWork{id=new string('b',32),deadline=1};var expired=ResetDescription(entry);
if(expired["expired"]!.GetValue<bool>()&&expired["failed"]!.GetValue<bool>()&&!expired["applied"]!.GetValue<bool>())mask|=16;
entry.applied=true;if(!ResetDescription(entry)["expired"]!.GetValue<bool>())mask|=32;
entry.applied=false;entry.deadline=ulong.MaxValue;entry.pending=true;if(ResetDescription(entry)["pending"]!.GetValue<bool>()&&!ResetDescription(entry)["applied"]!.GetValue<bool>())mask|=64;
entry.pending=false;entry.failed=true;var failed=!ResetDescription(entry)["pending"]!.GetValue<bool>()&&ResetDescription(entry)["failed"]!.GetValue<bool>();
var previous=enabled;
try
{
enabled=true;entry.failed=false;entry.phase="dispatching";var allowed=ResetCanCommit(entry);
entry.cancelRequested=true;var cancelled=!ResetCanCommit(entry);entry.cancelRequested=false;entry.deadline=1;
if(failed&&allowed&&cancelled&&!ResetCanCommit(entry)&&DelayedResetIoSelfTest())mask|=128;
}
finally{enabled=previous;}
return mask;
}
internal static uint ResetTelemetrySelfTest()
{
if(started||ImageHash(ModulePath())==GameHash)return 0;
static JsonElement Element(JsonObject value){using var document=JsonDocument.Parse(value.ToJsonString());return document.RootElement.Clone();}
var now=Utc();var frame=Obj(("observedAtUnixMilliseconds",now),("inGame",true),("localPlayerShipVerified",true),("entityId","7"),
("playerOverride",false),("fsd",Obj(("ownedCharging",false))),("rawFsdState",2),("sequence",8));
var ship=Obj(("verified",true),("hullFraction",1d),("damageObserved",false),("emergency",false));
var health=Obj(("observedAtUnixMilliseconds",now),("localPlayerShipVerified",true),("entityId","7"),("shipHealth",ship));
var dock=Obj(("verified",true),("computerAvailable",true),("clearanceGranted",true),("assistAllowed",false),("nativeLaunchActive",false),("nativeDutyActive",false));
var local=Obj(("observedAtUnixMilliseconds",now),("entityId","7"),("geometryVerified",true),("selected",true),("inSupercruise",false),
("distanceMetres",6000d),("docking",dock),("rawRequestState",2),("rawDockingState",3),("rawPad",7));
bool Eligible(){try{CheckResetTelemetry(Element(frame),Element(health),Element(local),8);return true;}catch{return false;}}
uint mask=0;var published=Obj(("sourceAfter",(float?).05f));
if(Eligible()&&published["sourceAfter"]!.GetValue<float>()==.05f)mask|=1;
dock.Remove("assistAllowed");if(Eligible())mask|=2;
dock["clearanceGranted"]=false;if(!Eligible())mask|=4;dock["clearanceGranted"]=true;
dock["computerAvailable"]=false;if(!Eligible())mask|=8;dock["computerAvailable"]=true;
ship["hullFraction"]=.4d;var historical=Eligible();ship["damageObserved"]=true;var damageRejected=!Eligible();ship["damageObserved"]=false;
ship["emergency"]=true;var emergencyRejected=!Eligible();ship["emergency"]=false;ship["hullFraction"]=0d;var deadRejected=!Eligible();
ship["hullFraction"]=1.1d;var invalidRejected=!Eligible();ship["hullFraction"]=1d;
if(historical&&damageRejected&&emergencyRejected&&deadRejected&&invalidRejected)mask|=16;
frame["playerOverride"]=true;if(!Eligible())mask|=32;frame["playerOverride"]=false;
local["entityId"]="8";if(!Eligible())mask|=64;local["entityId"]="7";
local["observedAtUnixMilliseconds"]=now-201;if(!Eligible())mask|=128;
return mask;
}
}
#endif
#if PLUGIN_SESSION_RECOVERY
using System.IO.Pipes;
using System.Text;
namespace XFEEDToolBox.Plugin;
internal static unsafe partial class SessionRecoveryRuntime
{
private sealed class ResetWork
{
public string id="",owner="",issue="",phase="preparing",failureStage="";
public ulong generation,sequence,deadline,entity,utc,publishedAt;public uint market;
public bool pending,applied,failed,called,cancelRequested,startRequested,startAttempted,startCalled;
public ulong startAt;
public string? startFailure;
public float? before,sourceBefore,after,source,actualAfter,controllerAfter,publishedBefore;
public Navigation.RecoveryResetBinding? proof;
}
private static readonly object resetGate=new();
private static readonly Dictionary<string,ResetWork> resetReceipts=new(StringComparer.Ordinal);
private static ResetWork? lastReset;
[ThreadStatic]private static string? resetBridgeStage;
private static int WaitResetRead(ValueTask<int> operation)=>operation.AsTask().GetAwaiter().GetResult();
private static void WaitResetWrite(ValueTask operation)=>operation.AsTask().GetAwaiter().GetResult();
private static bool ResetId(string value)=>value.Length==32&&value.All(c=>c is >= '0' and <= '9' or >= 'a' and <= 'f');
private static bool ResetDeadline(ulong deadline,ulong now,int ttl)=>ttl is >0 and <=250&&deadline>now&&deadline-now<=(ulong)ttl;
private static JsonObject ResetDescription(ResetWork? selected=null)
{
lock(resetGate)
{
var value=selected??lastReset;var expired=value!=null&&!value.applied&&value.deadline<=Utc();
return Obj(("requestId",value?.id),("nativeGeneration",value?.generation??0),("pending",value?.pending==true&&!expired),
("applied",value?.applied==true),("failed",value?.failed==true||expired),("expired",expired),("issue",value?.issue),
("phase",value?.phase),("failureStage",value?.failureStage),("cancelRequested",value?.cancelRequested==true),("entityId",value?.entity.ToString()),("marketId",value?.market??0),("observedAtUnixMilliseconds",value?.utc??0),
("node",value?.proof?.node.ToString("x")),("source",value?.proof?.source.ToString("x")),
("registry",value?.proof?.registry.ToString("x")),
("publishedSourceBefore",value?.publishedBefore),("publishedAtUnixMilliseconds",value?.publishedAt??0),
("accumulatorBefore",value?.before),("sourceBefore",value?.sourceBefore),("accumulatorAfter",value?.after),("sourceAfter",value?.source),
("actualThrottleAfter",value?.actualAfter),("controllerThrottleAfter",value?.controllerAfter),("originalResetCalled",value?.called==true),
("dockingStartRequested",value?.startRequested==true),("originalDockingStartAttempted",value?.startAttempted==true),
("originalDockingStartCalled",value?.startCalled==true),("dockingStartAtUnixMilliseconds",value?.startAt??0),("dockingStartFailure",value?.startFailure),
("expiresAtUnixMilliseconds",value?.deadline??0),("gameAccumulatorWrittenBySdk",false),("gameOutputWrittenBySdk",false),("activeFlagWritten",false),("aiWritten",false));
}
}
private static JsonElement ResetNav(JsonObject request,ulong deadline)
{
var operation=request["op"]!.GetValue<string>();resetBridgeStage=operation+".deadline";
var remaining=deadline>Utc()?deadline-Utc():0;if(remaining==0)throw new TimeoutException("Original reset intent expired");
using var timeout=new CancellationTokenSource(TimeSpan.FromMilliseconds(Math.Min(150,remaining)));
using var pipe=new NamedPipeClientStream(".",$"XFEEDToolBox.Navigation.{ProcessId}",PipeDirection.InOut,PipeOptions.Asynchronous);
resetBridgeStage=operation+".connect";pipe.ConnectAsync(timeout.Token).GetAwaiter().GetResult();
var data=Encoding.UTF8.GetBytes(request.ToJsonString()+"\n");resetBridgeStage=operation+".write";
// A pending IValueTaskSource.GetResult does not block. Convert to Task
// before a synchronous wait on this dedicated SDK pipe worker.
WaitResetWrite(pipe.WriteAsync(data.AsMemory(),timeout.Token));
resetBridgeStage=operation+".flush";pipe.FlushAsync(timeout.Token).GetAwaiter().GetResult();
var buffer=new byte[65536];var count=0;
while(count<buffer.Length)
{
resetBridgeStage=operation+".read";var read=WaitResetRead(pipe.ReadAsync(buffer.AsMemory(count),timeout.Token));if(read==0)break;count+=read;if(buffer[count-1]=='\n')break;
}
if(count is 0 or 65536)throw new IOException("Invalid original reset bridge response");
resetBridgeStage=operation+".parse";using var parsed=JsonDocument.Parse(buffer.AsMemory(0,count));var root=parsed.RootElement;
if(!root.GetProperty("ok").GetBoolean())throw new InvalidOperationException(root.GetProperty("error").GetString());
var result=root.GetProperty("result").Clone();resetBridgeStage=operation+".complete";return result;
}
private static JsonObject ResetBridgeProbe()
{
lock(resetGate)if(lastReset?.pending==true||lastReset?.phase=="dispatching")throw new InvalidOperationException("Cannot probe during a reset intent");
JsonElement? read=null,health=null,local=null;string? error=null,localIssue=null;var began=Utc();
try
{
read=ResetNav(Obj(("op","read")),began+350);health=ResetNav(Obj(("op","health.read")),began+350);
try{local=ResetNav(Obj(("op","local.read")),began+350);}catch(Exception failure){localIssue=failure.ToString();}
}
catch(Exception failure){error=failure.ToString();}
return Obj(("service",Service),("processId",ProcessId),("gameSha256",GameHash),("bridgePassed",read!=null&&health!=null&&error==null),
("stage",resetBridgeStage),("error",error),("localIssue",localIssue),("read",read is {} r?JsonNode.Parse(r.GetRawText()):null),
("health",health is {} h?JsonNode.Parse(h.GetRawText()):null),("local",local is {} l?JsonNode.Parse(l.GetRawText()):null),
("startedAtUnixMilliseconds",began),("finishedAtUnixMilliseconds",Utc()),("gameInputsSent",0),("resetCalled",false));
}
private static bool ResetFresh(JsonElement value,ulong now)
{var at=value.GetProperty("observedAtUnixMilliseconds").GetUInt64();return at<=now&&now-at<=200;}
private static bool SameResetTarget(JsonElement a,JsonElement b)=>a.GetProperty("key").GetInt32()==b.GetProperty("key").GetInt32()
&&a.GetProperty("kind").GetUInt32()==b.GetProperty("kind").GetUInt32()&&a.GetProperty("marketId").GetUInt32()==b.GetProperty("marketId").GetUInt32()
&&a.GetProperty("bodyAddress").GetString()==b.GetProperty("bodyAddress").GetString()&&a.GetProperty("name").GetString()==b.GetProperty("name").GetString();
private static void CheckResetTelemetry(JsonElement frame,JsonElement health,JsonElement local,ulong sequence)
{
var now=Utc();var h=health.GetProperty("shipHealth");var dock=local.GetProperty("docking");var hull=h.GetProperty("hullFraction").GetDouble();
if(!ResetFresh(frame,now)||!ResetFresh(health,now)||!ResetFresh(local,now)||!frame.GetProperty("inGame").GetBoolean()
||!frame.GetProperty("localPlayerShipVerified").GetBoolean()||!health.GetProperty("localPlayerShipVerified").GetBoolean()
||!h.GetProperty("verified").GetBoolean()||!double.IsFinite(hull)||hull is <=0 or >1||h.GetProperty("damageObserved").GetBoolean()||h.GetProperty("emergency").GetBoolean()
||frame.GetProperty("entityId").GetString()!=health.GetProperty("entityId").GetString()||frame.GetProperty("entityId").GetString()!=local.GetProperty("entityId").GetString()
||frame.GetProperty("playerOverride").GetBoolean()||frame.GetProperty("fsd").GetProperty("ownedCharging").GetBoolean()
||frame.GetProperty("rawFsdState").GetInt32() is not(1 or 2)||frame.GetProperty("sequence").GetUInt64()<sequence||frame.GetProperty("sequence").GetUInt64()-sequence>32
||!local.GetProperty("geometryVerified").GetBoolean()||!local.GetProperty("selected").GetBoolean()||local.GetProperty("inSupercruise").GetBoolean()
||local.GetProperty("distanceMetres").GetDouble()>7500||!dock.GetProperty("verified").GetBoolean()||!dock.GetProperty("computerAvailable").GetBoolean()
// The optional station interface is absent on the actual Homer
// entity, so assistAllowed defaults false without a getter result.
// Original action 10 does not use it. ATC and module readiness are
// the prerequisites; real zero and AI takeover are checked later.
||!dock.GetProperty("clearanceGranted").GetBoolean()||dock.GetProperty("nativeLaunchActive").GetBoolean()
||dock.GetProperty("nativeDutyActive").GetBoolean()||local.GetProperty("rawRequestState").GetInt32()!=2||local.GetProperty("rawDockingState").GetInt32() is not(3 or 4)
||local.GetProperty("rawPad").GetInt32()==255)throw new InvalidOperationException("Original reset telemetry, main ship, ownership or ATC is not eligible");
}
private static JsonNode ResetRequest(string op,JsonElement request)
{
var id=request.Str("requestId");if(!ResetId(id))throw new InvalidOperationException("Explicit reset request identity required");
ResetWork value;
lock(resetGate)
{
if(resetReceipts.TryGetValue(id,out var known))
{if(op=="docking.reset.cancel"){known.cancelRequested=true;known.pending=false;if(known.phase!="dispatching"){known.failed|=!known.applied;known.phase="cancelled";}}return ResetDescription(known);}
if(op!="docking.reset.arm")throw new InvalidOperationException("No matching original reset request");
var owner=request.Str("owner");var deadline=request.U64("expiresAtUnixMilliseconds");var ttl=request.Int("ttlMilliseconds");
if(!enabled||!ResetId(owner)||!ResetDeadline(deadline,Utc(),ttl)||resetReceipts.Count>=32||lastReset?.pending==true&&lastReset.deadline>Utc())
throw new InvalidOperationException("Reset owner, original deadline or one-use boundary differs");
if(request.TryGetProperty("startDockingAfterZero",out var startValue)&&startValue.ValueKind is not(JsonValueKind.True or JsonValueKind.False))
throw new InvalidOperationException("Explicit boolean original docking start intent required");
value=new(){id=id,owner=owner,deadline=deadline,sequence=request.U64("sequence"),generation=0,startRequested=startValue.ValueKind==JsonValueKind.True};
resetReceipts.Add(id,value);lastReset=value;
}
try
{
Root context;lock(gate)context=root;
if(!context.valid||context.state!="InGame"||context.next!=context.state||!Fresh(context.tick,GetTickCount64()))throw new InvalidOperationException("Stable original InGame context required");
value.phase="initial-native-reads";
var frame=ResetNav(Obj(("op","read")),value.deadline);var health=ResetNav(Obj(("op","health.read")),value.deadline);
var local=ResetNav(Obj(("op","local.read")),value.deadline);value.phase="initial-telemetry-schema";CheckResetTelemetry(frame,health,local,value.sequence);
var oldGeneration=request.U64("generation");if(oldGeneration==0||value.sequence==0)throw new InvalidOperationException("Reset original reference is missing");
value.phase="initial-selection-status";var old=ResetNav(Obj(("op","local.status"),("owner",value.owner),("generation",oldGeneration)),value.deadline);
var target=local.GetProperty("target").Clone();
if(!old.GetProperty("selected").GetBoolean()||!old.GetProperty("telemetryReady").GetBoolean()||!SameResetTarget(old.GetProperty("target"),target))throw new InvalidOperationException("Reset original selection differs");
value.entity=ulong.Parse(frame.GetProperty("entityId").GetString()!);value.market=target.GetProperty("marketId").GetUInt32();
// The original selection operation rejects any active control lease
// and holds its owner for 300 ms. The original intent stays <=250 ms.
value.phase="native-selection-intent";
var selected=ResetNav(Obj(("op","local.select"),("owner",value.owner),("key",target.GetProperty("key").GetInt32()),
("bodyAddress",target.GetProperty("bodyAddress").GetString()),("kind",target.GetProperty("kind").GetUInt32()),("marketId",value.market),("name",target.GetProperty("name").GetString())),value.deadline);
value.generation=selected.GetProperty("generation").GetUInt64();
while(!selected.GetProperty("selected").GetBoolean())
{
if(!selected.GetProperty("pending").GetBoolean())throw new InvalidOperationException("Reset native selection failed");
Thread.Sleep(1);selected=ResetNav(Obj(("op","local.status"),("owner",value.owner),("generation",value.generation)),value.deadline);
}
if(!SameResetTarget(selected.GetProperty("target"),target))throw new InvalidOperationException("Reset native selection identity changed");
value.phase="native-zero-intent";
var zero=ResetNav(Obj(("op","local.action"),("owner",value.owner),("generation",value.generation),("sequence",value.sequence),
("action","zeroThrottleForDocking"),("expiresAtUnixMilliseconds",value.deadline)),value.deadline);
var actionGeneration=zero.GetProperty("actionGeneration").GetUInt64();
do
{
zero=ResetNav(Obj(("op","local.action.status"),("owner",value.owner),("generation",value.generation),("actionGeneration",actionGeneration)),value.deadline);
if(zero.GetProperty("failed").GetBoolean())throw new InvalidOperationException("Original zero input failed");
if(zero.GetProperty("applied").GetBoolean())break;Thread.Sleep(1);
}while(true);
value.phase="post-zero-native-reads";
frame=ResetNav(Obj(("op","read")),value.deadline);health=ResetNav(Obj(("op","health.read")),value.deadline);local=ResetNav(Obj(("op","local.read")),value.deadline);
value.phase="post-zero-telemetry-schema";CheckResetTelemetry(frame,health,local,value.sequence);
if(ulong.Parse(frame.GetProperty("entityId").GetString()!)!=value.entity||!SameResetTarget(local.GetProperty("target"),target))throw new InvalidOperationException("Reset main ship changed after original zero input");
JsonObject[] candidates;lock(gate)candidates=mapperNodes.Values.Where(row=>row["expectedType"]?.GetValue<bool>()==true
&&Utc()>=row["observedAtUnixMilliseconds"]!.GetValue<ulong>()&&Utc()-row["observedAtUnixMilliseconds"]!.GetValue<ulong>()<=200).ToArray();
var h=health.GetProperty("shipHealth");Navigation.RecoveryResetBinding? proof=null;
foreach(var candidate in candidates)
{
Navigation.RecoveryResetBinding bound;
try{bound=Navigation.BindRecoveryReset(value.entity,ulong.Parse(frame.GetProperty("referenceWorldAddress").GetString()!),target,
h.GetProperty("hullFraction").GetDouble(),h.GetProperty("shieldFraction").ValueKind==JsonValueKind.Number?h.GetProperty("shieldFraction").GetDouble():null,
(nuint)Convert.ToUInt64(candidate["node"]!.GetValue<string>(),16));}catch{continue;}
if(candidate["source"]!.GetValue<string>()!=bound.source.ToString("x")||candidate["registry"]!.GetValue<string>()!=bound.registry.ToString("x"))continue;
if(proof!=null)throw new InvalidOperationException("Reset current mapper is ambiguous");proof=bound;
value.publishedBefore=candidate["sourceAfter"]!.GetValue<float>();value.publishedAt=candidate["observedAtUnixMilliseconds"]!.GetValue<ulong>();
}
if(proof==null)throw new InvalidOperationException("Reset current owned mapper not observed");
lock(resetGate)
{
if(!enabled||Utc()>=value.deadline||value.phase=="cancelled")throw new TimeoutException("Original reset deadline expired before mapper dispatch");
value.proof=proof;value.pending=true;value.phase="armed";
}
}
catch(Exception error){lock(resetGate){value.pending=false;value.failed=true;value.failureStage=value.phase+" | "+resetBridgeStage;value.issue=error.ToString();value.phase="failed-no-replay";}}
return ResetDescription(value);
}
private static ResetWork? BeginOriginalReset(nuint node,float dt)
{
ResetWork? wanted;lock(resetGate){wanted=lastReset;if(wanted?.pending!=true)return null;}
Root context;lock(gate)context=root;
if(!enabled||GetCurrentThreadId()!=expectedThread||!float.IsFinite(dt)||dt<=0||dt>.25f||!context.valid||context.thread!=expectedThread
||context.state!="InGame"||context.next!=context.state||!Fresh(context.tick,GetTickCount64())||Utc()>=wanted.deadline)return null;
if(wanted.proof==null||wanted.proof.node!=node)return null;
lock(resetGate){if(!wanted.pending||Utc()>=wanted.deadline)return null;wanted.pending=false;wanted.phase="dispatching";}
Navigation.CallRecoveryReset(wanted.proof,node,wanted.deadline,()=>ResetCanCommit(wanted));
lock(resetGate){wanted.called=true;wanted.before=wanted.proof.before;wanted.sourceBefore=wanted.proof.sourceBefore;}return wanted;
}
private static void FinishOriginalReset(ResetWork? wanted,nuint node)
{
if(wanted?.called!=true||wanted.proof==null)return;
var bound=wanted.proof.baseline;var controller=Pointer(bound.inputRoot+0x2F8);
if(node!=wanted.proof.node||Pointer(node+0x78)!=wanted.proof.source||Pointer(wanted.proof.computer+0x260)!=wanted.proof.source
||Read<uint>(bound.life+0xC0)!=8||Read<ulong>(bound.life+0xB0)!=wanted.entity
||LocalPlayerIdentity.ReadLife(bound.inputRoot,image,end)!=bound.life||controller==0||Pointer(wanted.proof.computer+0x240)!=controller)
throw new InvalidOperationException("Reset output owner changed");
var accumulator=Read<float>(node+0xD0);var output=Read<float>(wanted.proof.source+0x18);
var actual=Read<float>(bound.inputRoot+0x70);var throttle=Read<float>(controller+0x680);
var valid=float.IsFinite(accumulator)&&float.IsFinite(output)&&float.IsFinite(actual)&&float.IsFinite(throttle)
&&Math.Abs(accumulator)<=.001f&&Math.Abs(output)<=.001f&&Math.Abs(actual)<=.001f&&Math.Abs(throttle)<=.001f;
lock(resetGate){wanted.after=float.IsFinite(accumulator)?accumulator:null;wanted.source=float.IsFinite(output)?output:null;
wanted.actualAfter=float.IsFinite(actual)?actual:null;wanted.controllerAfter=float.IsFinite(throttle)?throttle:null;wanted.utc=Utc();}
if(valid&&wanted.startRequested)
{
try
{
Navigation.CallRecoveryDockingStart(wanted.proof,node,wanted.deadline,()=>ResetCanCommit(wanted),()=>
{
lock(resetGate)
{
if(!ResetCanCommit(wanted)||wanted.startAttempted)throw new InvalidOperationException("Original docking start intent expired, was cancelled or already dispatched");
wanted.startAttempted=true;wanted.startAt=Utc();
}
});
lock(resetGate)wanted.startCalled=true;
}
catch(Exception error){lock(resetGate)wanted.startFailure=error.ToString();throw;}
}
lock(resetGate){wanted.applied=valid;wanted.failed=!valid;wanted.phase=valid?(wanted.startCalled?"original-zero-and-docking-start-requested":"original-reset-and-output-zero"):"original-output-not-zero";
if(!valid)wanted.issue="Original mapper did not publish zero; callback will not be repeated";}
}
private static void FailOriginalReset(string issue)
{lock(resetGate)if(lastReset is {} value&&value.phase=="dispatching"){value.pending=false;value.failed=true;value.issue=issue;value.phase="mapper-rejected-no-replay";}}
private static bool ResetCanCommit(ResetWork wanted)
{lock(resetGate)return enabled&&!wanted.cancelRequested&&!wanted.failed&&wanted.phase=="dispatching"&&Utc()<wanted.deadline;}
private static void CancelOriginalReset(){lock(resetGate)if(lastReset is {} value){value.pending=false;value.cancelRequested=true;value.failed|=!value.applied;value.phase="deactivated";}}
private static bool DelayedResetIoSelfTest()
{
try
{
var name="XFEEDToolBox.ResetFixture."+Guid.NewGuid().ToString("N");
using var timeout=new CancellationTokenSource(TimeSpan.FromSeconds(2));
using var server=new NamedPipeServerStream(name,PipeDirection.InOut,1,PipeTransmissionMode.Byte,PipeOptions.Asynchronous);
using var readIssued=new ManualResetEventSlim();
var worker=new Thread(()=>
{
try{server.WaitForConnection();if(server.ReadByte()!=0x41)return;readIssued.Wait(timeout.Token);Thread.Sleep(20);server.WriteByte(0x5A);server.Flush();}catch{}
}){IsBackground=true};worker.Start();
using var client=new NamedPipeClientStream(".",name,PipeDirection.InOut,PipeOptions.Asynchronous);
client.ConnectAsync(timeout.Token).GetAwaiter().GetResult();WaitResetWrite(client.WriteAsync(new byte[]{0x41}.AsMemory(),timeout.Token));
var bytes=new byte[1];var pending=client.ReadAsync(bytes.AsMemory(),timeout.Token);var asynchronous=!pending.IsCompleted;readIssued.Set();
var length=WaitResetRead(pending);return asynchronous&&length==1&&bytes[0]==0x5A&&worker.Join(1000);
}
catch{return false;}
}
internal static uint ResetSelfTest()
{
if(started||ImageHash(ModulePath())==GameHash)return 0;uint mask=0;
if(ResetId(new string('a',32))&&!ResetId(new string('A',32))&&!ResetId(new string('a',31)))mask|=1;
if(ResetDeadline(1200,1000,250)&&!ResetDeadline(1251,1000,250))mask|=2;
if(!ResetDeadline(1000,1000,250)&&!ResetDeadline(999,1000,250)&&!ResetDeadline(1100,1000,0))mask|=4;
if(ResetDeadline(1100,1000,100)&&!ResetDeadline(1101,1000,100)&&!ResetDeadline(1100,1000,251))mask|=8;
var entry=new ResetWork{id=new string('b',32),deadline=1};var expired=ResetDescription(entry);
if(expired["expired"]!.GetValue<bool>()&&expired["failed"]!.GetValue<bool>()&&!expired["applied"]!.GetValue<bool>())mask|=16;
entry.applied=true;if(!ResetDescription(entry)["expired"]!.GetValue<bool>())mask|=32;
entry.applied=false;entry.deadline=ulong.MaxValue;entry.pending=true;if(ResetDescription(entry)["pending"]!.GetValue<bool>()&&!ResetDescription(entry)["applied"]!.GetValue<bool>())mask|=64;
entry.pending=false;entry.failed=true;var failed=!ResetDescription(entry)["pending"]!.GetValue<bool>()&&ResetDescription(entry)["failed"]!.GetValue<bool>();
var previous=enabled;
try
{
enabled=true;entry.failed=false;entry.phase="dispatching";var allowed=ResetCanCommit(entry);
entry.cancelRequested=true;var cancelled=!ResetCanCommit(entry);entry.cancelRequested=false;entry.deadline=1;
if(failed&&allowed&&cancelled&&!ResetCanCommit(entry)&&DelayedResetIoSelfTest())mask|=128;
}
finally{enabled=previous;}
return mask;
}
internal static uint ResetTelemetrySelfTest()
{
if(started||ImageHash(ModulePath())==GameHash)return 0;
static JsonElement Element(JsonObject value){using var document=JsonDocument.Parse(value.ToJsonString());return document.RootElement.Clone();}
var now=Utc();var frame=Obj(("observedAtUnixMilliseconds",now),("inGame",true),("localPlayerShipVerified",true),("entityId","7"),
("playerOverride",false),("fsd",Obj(("ownedCharging",false))),("rawFsdState",2),("sequence",8));
var ship=Obj(("verified",true),("hullFraction",1d),("damageObserved",false),("emergency",false));
var health=Obj(("observedAtUnixMilliseconds",now),("localPlayerShipVerified",true),("entityId","7"),("shipHealth",ship));
var dock=Obj(("verified",true),("computerAvailable",true),("clearanceGranted",true),("assistAllowed",false),("nativeLaunchActive",false),("nativeDutyActive",false));
var local=Obj(("observedAtUnixMilliseconds",now),("entityId","7"),("geometryVerified",true),("selected",true),("inSupercruise",false),
("distanceMetres",6000d),("docking",dock),("rawRequestState",2),("rawDockingState",3),("rawPad",7));
bool Eligible(){try{CheckResetTelemetry(Element(frame),Element(health),Element(local),8);return true;}catch{return false;}}
uint mask=0;var published=Obj(("sourceAfter",(float?).05f));
if(Eligible()&&published["sourceAfter"]!.GetValue<float>()==.05f)mask|=1;
dock.Remove("assistAllowed");if(Eligible())mask|=2;
dock["clearanceGranted"]=false;if(!Eligible())mask|=4;dock["clearanceGranted"]=true;
dock["computerAvailable"]=false;if(!Eligible())mask|=8;dock["computerAvailable"]=true;
ship["hullFraction"]=.4d;var historical=Eligible();ship["damageObserved"]=true;var damageRejected=!Eligible();ship["damageObserved"]=false;
ship["emergency"]=true;var emergencyRejected=!Eligible();ship["emergency"]=false;ship["hullFraction"]=0d;var deadRejected=!Eligible();
ship["hullFraction"]=1.1d;var invalidRejected=!Eligible();ship["hullFraction"]=1d;
if(historical&&damageRejected&&emergencyRejected&&deadRejected&&invalidRejected)mask|=16;
frame["playerOverride"]=true;if(!Eligible())mask|=32;frame["playerOverride"]=false;
local["entityId"]="8";if(!Eligible())mask|=64;local["entityId"]="7";
local["observedAtUnixMilliseconds"]=now-201;if(!Eligible())mask|=128;
return mask;
}
}
#endif