#if PLUGIN_SESSION_RECOVERY || PLUGIN_CRUISE_OBSERVATION || PLUGIN_CRUISE_CONTROL
using System.Text;
namespace XFEEDToolBox.Plugin;
internal static unsafe partial class Navigation
{
internal sealed class RecoveryResetBinding
{
internal Snapshot baseline;
internal JsonElement target;
internal nuint node,source,registry,computer,events;
internal float before,sourceBefore;
}
internal static void ConfigureRecoveryReadOnlyImage(){image=Platform.ImageBase;imageEnd=Platform.ImageEnd;}
private static Snapshot RecoveryPlayer(ulong expectedEntity)
{
var pool=image+FsdPool;
if(expectedEntity==0||Read<ulong>(pool+0x68)!=0xEC0||Read<ulong>(pool+0x90)>128)throw new InvalidOperationException("Reset player pool differs");
var visited=new HashSet<nuint>();var block=Pointer(pool+0x30);Snapshot result=default;var found=0;
while(block!=0&&visited.Add(block)&&visited.Count<=128)
{
var count=Read<ulong>(block+0x38);if(count is 0 or >128)throw new InvalidOperationException("Reset player pool bound");
for(nuint i=0;i<(nuint)count;i++)
{
var fsd=block+0x80+i*0xEC0;
if(Pointer(fsd)!=image+0x5316CC8||Pointer(fsd+0x58)!=image+0x5316DF8)continue;
var owner=Pointer(fsd+0x20);var table=Pointer(owner);if(!InImage(table))continue;
var reference=Leaf(owner,Pointer(table+0x20));if(reference==0)continue;var life=Pointer(reference);
if(Read<uint>(life+0xC0)!=8||Read<ulong>(life+0xB0)!=expectedEntity)continue;
if(++found!=1)throw new InvalidOperationException("Reset player is ambiguous");
var physics=Pointer(fsd+0x2A8)-0x58;var input=Pointer(physics+0x3B0)-0x60;
result=new(){entity=expectedEntity,life=life,fsd=fsd,physics=physics,inputRoot=input};
if(!BoundFsd(result,fsd))throw new InvalidOperationException("Reset controlled actor changed");
}
block=Pointer(block+0x20);
}
if(block!=0||found!=1)throw new InvalidOperationException("Reset player is unavailable");return result;
}
internal static RecoveryResetBinding BindRecoveryReset(ulong entity,ulong world,JsonElement target,double hull,double? shield,nuint node)
{
var frame=RecoveryPlayer(entity);frame.referenceWorld=world;frame.healthValid=true;frame.hullFraction=hull;
frame.shieldKnown=shield is not null;frame.shieldFraction=shield??0;
var computer=LocalDockingComputer(frame);
if(computer==0||Pointer(node)!=image+0x512E330||Pointer(node+0x40)!=Pointer(computer+0x230)
||Pointer(node+0x78)!=Pointer(computer+0x260)||Pointer(frame.fsd+0x6F8)!=Pointer(computer+0x230))throw new InvalidOperationException("Reset node does not belong to current main ship");
return new(){baseline=frame,target=target.Clone(),node=node,source=Pointer(node+0x78),registry=Pointer(node+0x40),computer=computer,events=Pointer(node+0x68)};
}
private static bool RecoverySubscriber(RecoveryResetBinding proof)
{
var events=proof.events;var node=proof.node;
if(events<0x10000||Pointer(node+0x68)!=events||Pointer(events)!=image+0x512EC98||Pointer(Pointer(events)+0x18)!=image+0x90C170
||Pointer(node+0x20)!=image+0x512E3A0||Pointer(Pointer(node+0x20))!=image+0x8F5320)return false;
var set=events+0x9E0;var buckets=Pointer(set);var capacity=Read<ulong>(set+8);var used=Read<ulong>(set+0x18);
if(buckets<0x10000||capacity is 0 or >8192||used is 0 or >4096)return false;
var seen=new HashSet<nuint>();var matches=0;
for(nuint i=0;i<(nuint)capacity;i++)
{
var head=buckets+i*8;var item=Pointer(head);
while(item!=head)
{
if(item<0x10000||!seen.Add(item)||seen.Count>4096)return false;
if(Pointer(item+8)==node+0x20)matches++;item=Pointer(item);
}
}
return matches==1&&(ulong)seen.Count==used&&Pointer(set)==buckets&&Read<ulong>(set+8)==capacity&&Read<ulong>(set+0x18)==used;
}
private static bool RecoveryResetHealthEligible(Snapshot previous,Snapshot current)
=>previous.healthValid&¤t.healthValid&&previous.entity==current.entity&&previous.life==current.life
&&double.IsFinite(current.hullFraction)&¤t.hullFraction is >0 and <=1
&&!HealthDamageEmergency(previous,current);
private static Snapshot ReadRecoveryResetFrame(RecoveryResetBinding proof,nuint node)
{
if(node!=proof.node)throw new InvalidOperationException("Reset mapper identity differs");
var current=RecoveryPlayer(proof.baseline.entity);
if(current.life!=proof.baseline.life||current.fsd!=proof.baseline.fsd||current.physics!=proof.baseline.physics||current.inputRoot!=proof.baseline.inputRoot
||!Sample(current.physics,out var frame)||frame.entity!=proof.baseline.entity||frame.life!=current.life||frame.fsd!=current.fsd||frame.inputRoot!=current.inputRoot
||frame.referenceWorld!=proof.baseline.referenceWorld||!RecoveryResetHealthEligible(proof.baseline,frame)
||frame.rawFsdState is not(1 or 2)||!BoundFsd(frame,frame.fsd))throw new InvalidOperationException("Reset actual main ship or health changed");
if(!SampleLocalFlight(frame,out var local,out var stage))throw new InvalidOperationException("Reset original flight telemetry unavailable: "+stage);
var target=proof.target;
if(local.target.key!=target.GetProperty("key").GetInt32()||local.target.body.ToString()!=target.GetProperty("bodyAddress").GetString()
||local.target.kind!=target.GetProperty("kind").GetUInt32()||local.target.market!=target.GetProperty("marketId").GetUInt32()
||LocalIdentityName(local.target)!=target.GetProperty("name").GetString()||!local.selected||local.inSupercruise||local.distance>7500
||!local.dockingVerified||!local.dockingGranted||local.nativeDockingActive||local.nativeLaunchActive||local.cruiseAssistEngaged)
throw new InvalidOperationException("Reset actual target, ATC or native duty changed");
var computer=LocalDockingComputer(frame);var dock=LocalDocking(frame);var controller=Pointer(frame.inputRoot+0x2F8);
if(computer!=proof.computer||!LocalDockingAvailable(computer)||Pointer(computer+0x240)!=controller||Pointer(node+0x40)!=Pointer(computer+0x230)
||Pointer(node+0x40)!=Pointer(frame.fsd+0x6F8)||Pointer(node+0x78)!=proof.source||Pointer(computer+0x260)!=proof.source
||!FixtureBindingName(Pointer(node+0xB0),"ForwardReverseThrust_Set")||!FixtureBindingName(Pointer(node+0xB8),"SetSpeedZero")
||!FixtureBindingName(Pointer(node+0x90),"Bindings_Flight_Active")||dock==0||Read<uint>(dock+0x614)!=2||Read<uint>(dock+0x4C0)is not(3 or 4)||Read<byte>(dock+0x4E9)==255)
throw new InvalidOperationException("Reset original input ownership or ATC differs");
var registry=Pointer(node+0x40);
if(Pointer(registry)!=image+0x512FD90||Pointer(Pointer(registry)+0x40)!=image+0x8FEDC0
||Pointer(Pointer(node+0xB0)+0x10)!=registry+0xB8||Pointer(Pointer(node+0xB8)+0x10)!=registry+0xB8||Pointer(proof.source+0x10)!=registry+0xB8)
throw new InvalidOperationException("Reset exact registry aliases differ");
var station=Pointer(dock+0x4E0);
if(station==0||Read<uint>(station+0xC0)!=8||Read<ulong>(station+0xB0)!=local.target.market||!RecoverySubscriber(proof)
||!Platform.ReadBytes(image+0x8F5320,18).AsSpan().SequenceEqual(new byte[]{0xC6,0x81,0xC0,0,0,0,0,0xC7,0x81,0xB0,0,0,0,0,0,0,0,0xC3}))
throw new InvalidOperationException("Reset original callback or subscription differs");
return frame;
}
internal static void CallRecoveryReset(RecoveryResetBinding proof,nuint node,ulong deadline,Func<bool> stillAuthorized)
{
var frame=ReadRecoveryResetFrame(proof,node);var controller=Pointer(frame.inputRoot+0x2F8);
proof.before=Read<float>(node+0xD0);
proof.sourceBefore=Read<float>(proof.source+0x18);
var actualBefore=Read<float>(frame.inputRoot+0x70);var controllerBefore=Read<float>(controller+0x680);var checkedAt=UtcMilliseconds();
if(!float.IsFinite(proof.before)||Math.Abs(proof.before)>1.001f||!float.IsFinite(proof.sourceBefore)||Math.Abs(proof.sourceBefore)>1.001f||UtcMilliseconds()>=deadline||!stillAuthorized()
||!float.IsFinite(controllerBefore)||Math.Abs(controllerBefore)>.001f||!float.IsFinite(actualBefore)||Math.Abs(actualBefore)>.001f)
throw new InvalidOperationException($"Reset pre-call refused: accumulator={proof.before:R}, source={proof.sourceBefore:R}, actual={actualBefore:R}, controller={controllerBefore:R}, observedAt={checkedAt}, originalDeadline={deadline}");
// This original registered callback alone clears its own accumulator.
// The following original mapper invocation computes the real output.
Call(image+0x8F5320,(ulong)(node+0x20));
}
}
#endif
#if PLUGIN_SESSION_RECOVERY || PLUGIN_CRUISE_OBSERVATION || PLUGIN_CRUISE_CONTROL
using System.Text;
namespace XFEEDToolBox.Plugin;
internal static unsafe partial class Navigation
{
internal sealed class RecoveryResetBinding
{
internal Snapshot baseline;
internal JsonElement target;
internal nuint node,source,registry,computer,events;
internal float before,sourceBefore;
}
internal static void ConfigureRecoveryReadOnlyImage(){image=Platform.ImageBase;imageEnd=Platform.ImageEnd;}
private static Snapshot RecoveryPlayer(ulong expectedEntity)
{
var pool=image+FsdPool;
if(expectedEntity==0||Read<ulong>(pool+0x68)!=0xEC0||Read<ulong>(pool+0x90)>128)throw new InvalidOperationException("Reset player pool differs");
var visited=new HashSet<nuint>();var block=Pointer(pool+0x30);Snapshot result=default;var found=0;
while(block!=0&&visited.Add(block)&&visited.Count<=128)
{
var count=Read<ulong>(block+0x38);if(count is 0 or >128)throw new InvalidOperationException("Reset player pool bound");
for(nuint i=0;i<(nuint)count;i++)
{
var fsd=block+0x80+i*0xEC0;
if(Pointer(fsd)!=image+0x5316CC8||Pointer(fsd+0x58)!=image+0x5316DF8)continue;
var owner=Pointer(fsd+0x20);var table=Pointer(owner);if(!InImage(table))continue;
var reference=Leaf(owner,Pointer(table+0x20));if(reference==0)continue;var life=Pointer(reference);
if(Read<uint>(life+0xC0)!=8||Read<ulong>(life+0xB0)!=expectedEntity)continue;
if(++found!=1)throw new InvalidOperationException("Reset player is ambiguous");
var physics=Pointer(fsd+0x2A8)-0x58;var input=Pointer(physics+0x3B0)-0x60;
result=new(){entity=expectedEntity,life=life,fsd=fsd,physics=physics,inputRoot=input};
if(!BoundFsd(result,fsd))throw new InvalidOperationException("Reset controlled actor changed");
}
block=Pointer(block+0x20);
}
if(block!=0||found!=1)throw new InvalidOperationException("Reset player is unavailable");return result;
}
internal static RecoveryResetBinding BindRecoveryReset(ulong entity,ulong world,JsonElement target,double hull,double? shield,nuint node)
{
var frame=RecoveryPlayer(entity);frame.referenceWorld=world;frame.healthValid=true;frame.hullFraction=hull;
frame.shieldKnown=shield is not null;frame.shieldFraction=shield??0;
var computer=LocalDockingComputer(frame);
if(computer==0||Pointer(node)!=image+0x512E330||Pointer(node+0x40)!=Pointer(computer+0x230)
||Pointer(node+0x78)!=Pointer(computer+0x260)||Pointer(frame.fsd+0x6F8)!=Pointer(computer+0x230))throw new InvalidOperationException("Reset node does not belong to current main ship");
return new(){baseline=frame,target=target.Clone(),node=node,source=Pointer(node+0x78),registry=Pointer(node+0x40),computer=computer,events=Pointer(node+0x68)};
}
private static bool RecoverySubscriber(RecoveryResetBinding proof)
{
var events=proof.events;var node=proof.node;
if(events<0x10000||Pointer(node+0x68)!=events||Pointer(events)!=image+0x512EC98||Pointer(Pointer(events)+0x18)!=image+0x90C170
||Pointer(node+0x20)!=image+0x512E3A0||Pointer(Pointer(node+0x20))!=image+0x8F5320)return false;
var set=events+0x9E0;var buckets=Pointer(set);var capacity=Read<ulong>(set+8);var used=Read<ulong>(set+0x18);
if(buckets<0x10000||capacity is 0 or >8192||used is 0 or >4096)return false;
var seen=new HashSet<nuint>();var matches=0;
for(nuint i=0;i<(nuint)capacity;i++)
{
var head=buckets+i*8;var item=Pointer(head);
while(item!=head)
{
if(item<0x10000||!seen.Add(item)||seen.Count>4096)return false;
if(Pointer(item+8)==node+0x20)matches++;item=Pointer(item);
}
}
return matches==1&&(ulong)seen.Count==used&&Pointer(set)==buckets&&Read<ulong>(set+8)==capacity&&Read<ulong>(set+0x18)==used;
}
private static bool RecoveryResetHealthEligible(Snapshot previous,Snapshot current)
=>previous.healthValid&¤t.healthValid&&previous.entity==current.entity&&previous.life==current.life
&&double.IsFinite(current.hullFraction)&¤t.hullFraction is >0 and <=1
&&!HealthDamageEmergency(previous,current);
private static Snapshot ReadRecoveryResetFrame(RecoveryResetBinding proof,nuint node)
{
if(node!=proof.node)throw new InvalidOperationException("Reset mapper identity differs");
var current=RecoveryPlayer(proof.baseline.entity);
if(current.life!=proof.baseline.life||current.fsd!=proof.baseline.fsd||current.physics!=proof.baseline.physics||current.inputRoot!=proof.baseline.inputRoot
||!Sample(current.physics,out var frame)||frame.entity!=proof.baseline.entity||frame.life!=current.life||frame.fsd!=current.fsd||frame.inputRoot!=current.inputRoot
||frame.referenceWorld!=proof.baseline.referenceWorld||!RecoveryResetHealthEligible(proof.baseline,frame)
||frame.rawFsdState is not(1 or 2)||!BoundFsd(frame,frame.fsd))throw new InvalidOperationException("Reset actual main ship or health changed");
if(!SampleLocalFlight(frame,out var local,out var stage))throw new InvalidOperationException("Reset original flight telemetry unavailable: "+stage);
var target=proof.target;
if(local.target.key!=target.GetProperty("key").GetInt32()||local.target.body.ToString()!=target.GetProperty("bodyAddress").GetString()
||local.target.kind!=target.GetProperty("kind").GetUInt32()||local.target.market!=target.GetProperty("marketId").GetUInt32()
||LocalIdentityName(local.target)!=target.GetProperty("name").GetString()||!local.selected||local.inSupercruise||local.distance>7500
||!local.dockingVerified||!local.dockingGranted||local.nativeDockingActive||local.nativeLaunchActive||local.cruiseAssistEngaged)
throw new InvalidOperationException("Reset actual target, ATC or native duty changed");
var computer=LocalDockingComputer(frame);var dock=LocalDocking(frame);var controller=Pointer(frame.inputRoot+0x2F8);
if(computer!=proof.computer||!LocalDockingAvailable(computer)||Pointer(computer+0x240)!=controller||Pointer(node+0x40)!=Pointer(computer+0x230)
||Pointer(node+0x40)!=Pointer(frame.fsd+0x6F8)||Pointer(node+0x78)!=proof.source||Pointer(computer+0x260)!=proof.source
||!FixtureBindingName(Pointer(node+0xB0),"ForwardReverseThrust_Set")||!FixtureBindingName(Pointer(node+0xB8),"SetSpeedZero")
||!FixtureBindingName(Pointer(node+0x90),"Bindings_Flight_Active")||dock==0||Read<uint>(dock+0x614)!=2||Read<uint>(dock+0x4C0)is not(3 or 4)||Read<byte>(dock+0x4E9)==255)
throw new InvalidOperationException("Reset original input ownership or ATC differs");
var registry=Pointer(node+0x40);
if(Pointer(registry)!=image+0x512FD90||Pointer(Pointer(registry)+0x40)!=image+0x8FEDC0
||Pointer(Pointer(node+0xB0)+0x10)!=registry+0xB8||Pointer(Pointer(node+0xB8)+0x10)!=registry+0xB8||Pointer(proof.source+0x10)!=registry+0xB8)
throw new InvalidOperationException("Reset exact registry aliases differ");
var station=Pointer(dock+0x4E0);
if(station==0||Read<uint>(station+0xC0)!=8||Read<ulong>(station+0xB0)!=local.target.market||!RecoverySubscriber(proof)
||!Platform.ReadBytes(image+0x8F5320,18).AsSpan().SequenceEqual(new byte[]{0xC6,0x81,0xC0,0,0,0,0,0xC7,0x81,0xB0,0,0,0,0,0,0,0,0xC3}))
throw new InvalidOperationException("Reset original callback or subscription differs");
return frame;
}
internal static void CallRecoveryReset(RecoveryResetBinding proof,nuint node,ulong deadline,Func<bool> stillAuthorized)
{
var frame=ReadRecoveryResetFrame(proof,node);var controller=Pointer(frame.inputRoot+0x2F8);
proof.before=Read<float>(node+0xD0);
proof.sourceBefore=Read<float>(proof.source+0x18);
var actualBefore=Read<float>(frame.inputRoot+0x70);var controllerBefore=Read<float>(controller+0x680);var checkedAt=UtcMilliseconds();
if(!float.IsFinite(proof.before)||Math.Abs(proof.before)>1.001f||!float.IsFinite(proof.sourceBefore)||Math.Abs(proof.sourceBefore)>1.001f||UtcMilliseconds()>=deadline||!stillAuthorized()
||!float.IsFinite(controllerBefore)||Math.Abs(controllerBefore)>.001f||!float.IsFinite(actualBefore)||Math.Abs(actualBefore)>.001f)
throw new InvalidOperationException($"Reset pre-call refused: accumulator={proof.before:R}, source={proof.sourceBefore:R}, actual={actualBefore:R}, controller={controllerBefore:R}, observedAt={checkedAt}, originalDeadline={deadline}");
// This original registered callback alone clears its own accumulator.
// The following original mapper invocation computes the real output.
Call(image+0x8F5320,(ulong)(node+0x20));
}
}
#endif