#if PLUGIN_SESSION_RECOVERY
namespace XFEEDToolBox.Plugin;
internal static unsafe partial class Navigation
{
private readonly record struct RecoveryDockingStartGate(ulong now,ulong deadline,bool authorized,bool module,bool profile,bool blocked,
float actual,float controller,float source,float accumulator);
private static bool RecoveryDockingStartAllowed(in RecoveryDockingStartGate value)
=>value.authorized&&value.module&&value.profile&&!value.blocked&&value.now<value.deadline&&value.deadline-value.now<=250
&&float.IsFinite(value.actual)&&Math.Abs(value.actual)<=.001f&&float.IsFinite(value.controller)&&Math.Abs(value.controller)<=.001f
&&float.IsFinite(value.source)&&Math.Abs(value.source)<=.001f&&float.IsFinite(value.accumulator)&&Math.Abs(value.accumulator)<=.001f;
private static bool RecoveryDockingBlocked(nuint consumer)
{
// Exact E9A160 predicate. The original getter owns the temporary weak
// reference; the original contains function neither consumes it nor
// changes the set. Both temporary references are released once.
var subject=Pointer(consumer+0xA8);var blockers=Pointer(consumer+0x1C8);
if(subject<0x10000||Pointer(subject)!=image+0x515E020||Pointer(Pointer(subject)+0x30)!=image+0xEBDA20||blockers<0x10000)
throw new InvalidOperationException("Original docking blocker interfaces differ");
var set=blockers+0x90;var capacity=Read<ulong>(set+8);var used=Read<ulong>(set+0x18);
if(used>4096||capacity>8192||used!=0&&(capacity==0||Pointer(set)<0x10000))throw new InvalidOperationException("Original docking blocker set exceeds its bound");
nuint reference=0,copy=0;
try
{
Call(image+0xEBDA20,(ulong)subject,(ulong)(nuint)(&reference));
if((byte)Call(image+0x64ADF0,(ulong)(nuint)(&reference))==0)return false;
Call(image+0x62D0A0,(ulong)(nuint)(©),(ulong)(nuint)(&reference));
return (byte)Call(image+0x8C2710,(ulong)set,(ulong)(nuint)(©))!=0;
}
finally
{
if(copy!=0)Call(image+0x62F3A0,(ulong)(nuint)(©));
if(reference!=0)Call(image+0x62F3A0,(ulong)(nuint)(&reference));
}
}
internal static void CallRecoveryDockingStart(RecoveryResetBinding proof,nuint node,ulong deadline,Func<bool> stillAuthorized,Action dispatching)
{
var frame=ReadRecoveryResetFrame(proof,node);var consumer=proof.computer-0x58;
var activity=Pointer(consumer+0xF0);var atc=Pointer(consumer+0x1B0);var dock=LocalDocking(frame);
var profile=Pointer(consumer+0x298);var controller=Pointer(frame.inputRoot+0x2F8);var station=Pointer(dock+0x4E0);
if(activity==0||Pointer(activity)!=image+0x5165E08||Pointer(Pointer(activity)+0x40)!=image+0xEE9F30
||atc==0||Pointer(atc)!=image+0x5317960||Pointer(Pointer(atc)+0xF0)!=image+0x2C65D40
||profile==0||Pointer(profile)!=image+0x52A0930||Pointer(Pointer(profile)+0x90)!=image+0x25FF830
||Read<byte>(consumer+0x3CA)!=0||Read<byte>(consumer+0x3CD)!=0||Read<byte>(consumer+0x3CF)==0
||Pointer(consumer+0x2B8)!=proof.source||station==0||Read<uint>(station+0xC0)!=8||Read<ulong>(station+0xB0)!=proof.target.GetProperty("marketId").GetUInt32())
throw new InvalidOperationException("Original docking activity, module, profile or ATC owner differs");
// A present automatic target must match. With no retained automatic
// target, the explicit SDK request uses the verified original ATC
// station reference, just as the original activity command accepts.
var automaticTarget=Pointer(consumer+0x2B0);
if(automaticTarget!=0&&automaticTarget!=station)throw new InvalidOperationException("Original automatic docking target differs from its current ATC grant");
var enabled=(byte)Call(image+0x25FF830,(ulong)profile)!=0;
var blocked=RecoveryDockingBlocked(consumer);
var check=new RecoveryDockingStartGate(UtcMilliseconds(),deadline,stillAuthorized(),LocalDockingAvailable(proof.computer),enabled,blocked,
Read<float>(frame.inputRoot+0x70),Read<float>(controller+0x680),Read<float>(proof.source+0x18),Read<float>(node+0xD0));
if(!RecoveryDockingStartAllowed(check))throw new InvalidOperationException("Original docking start requires a live intent, real four-place zero, available module and enabled unblocked policy");
if(!Platform.ReadBytes(image+0xEE9F30,8).AsSpan().SequenceEqual(new byte[]{0x4C,0x8B,0xDC,0x57,0x48,0x83,0xEC,0x50})
||!Platform.ReadBytes(image+0xB8BF30,10).AsSpan().SequenceEqual(new byte[]{0x48,0x89,0x5C,0x24,0x08,0x48,0x89,0x74,0x24,0x10})
||Read<ulong>(image+0x4E328D0)!=0x4000000040000000UL||Read<ulong>(image+0x4E328D8)!=0x4000000040000000UL)
throw new InvalidOperationException("Original docking command signature or original parameters differ");
ushort identifier=0;nuint stationCopy=0;var transferred=false;
try
{
Call(image+0x62D0A0,(ulong)(nuint)(&stationCopy),(ulong)(nuint)(&station));
Call(image+0xB8BF30,(ulong)(nuint)(&identifier));
if(identifier==0||stationCopy!=station)throw new InvalidOperationException("Original docking request identity or station reference is unavailable");
frame=ReadRecoveryResetFrame(proof,node);controller=Pointer(frame.inputRoot+0x2F8);
check=check with{now=UtcMilliseconds(),authorized=stillAuthorized(),actual=Read<float>(frame.inputRoot+0x70),
controller=Read<float>(controller+0x680),source=Read<float>(proof.source+0x18),accumulator=Read<float>(node+0xD0)};
if(!RecoveryDockingStartAllowed(check)||Pointer(LocalDocking(frame)+0x4E0)!=station||Pointer(consumer+0xF0)!=activity||Pointer(consumer+0x1B0)!=atc)
throw new InvalidOperationException("Original docking request changed before dispatch");
dispatching();transferred=true;
// Original E9A160 uses this exact command, original parameter
// vector and fifth argument. EE9F30 retains its own E781C0
// eligibility predicate, creates the native state-1 activity and
// consumes the token/reference. No SDK write to AI or its timer.
Call(image+0xEE9F30,(ulong)activity,(ulong)(nuint)(&identifier),(ulong)(nuint)(&stationCopy),(ulong)(image+0x4E328D0),0);
Call(image+0x2C65D40,(ulong)atc);
}
finally
{
// An uncertain native return may already have consumed both
// arguments. Never free or replay such an intent a second time.
if(!transferred)
{
if(identifier!=0)Call(image+0x551D80,(ulong)Pointer(image+0x5EFF5E0),identifier);
if(stationCopy!=0)Call(image+0x62F3A0,(ulong)(nuint)(&stationCopy));
}
}
}
internal static uint RecoveryDockingStartSelfTest()
{
var good=new RecoveryDockingStartGate(1000,1250,true,true,true,false,0,0,0,0);uint result=0;
if(RecoveryDockingStartAllowed(good))result|=1;
if(!RecoveryDockingStartAllowed(good with{source=.05f})&&!RecoveryDockingStartAllowed(good with{accumulator=.75f}))result|=2;
if(!RecoveryDockingStartAllowed(good with{actual=.05f})&&!RecoveryDockingStartAllowed(good with{controller=.75f}))result|=4;
if(!RecoveryDockingStartAllowed(good with{actual=float.NaN})&&!RecoveryDockingStartAllowed(good with{source=float.PositiveInfinity}))result|=8;
if(!RecoveryDockingStartAllowed(good with{now=1250})&&!RecoveryDockingStartAllowed(good with{deadline=1251}))result|=16;
if(!RecoveryDockingStartAllowed(good with{authorized=false}))result|=32;
if(!RecoveryDockingStartAllowed(good with{profile=false})&&!RecoveryDockingStartAllowed(good with{module=false}))result|=64;
var stable=new Snapshot{healthValid=true,entity=7,life=0x123400,hullFraction=.4,shieldKnown=true,shieldFraction=1};var changed=stable;
var historical=RecoveryResetHealthEligible(stable,changed);changed.hullFraction=.39;var damageRejected=!RecoveryResetHealthEligible(stable,changed);
changed=stable;changed.shieldFraction=0;var shieldsRejected=!RecoveryResetHealthEligible(stable,changed);
changed=stable;changed.hullFraction=double.NaN;var invalidRejected=!RecoveryResetHealthEligible(stable,changed);
changed=stable;changed.hullFraction=0;var deadRejected=!RecoveryResetHealthEligible(stable,changed);
changed=stable;changed.entity=8;var identityRejected=!RecoveryResetHealthEligible(stable,changed);
if(!RecoveryDockingStartAllowed(good with{blocked=true})&&historical&&damageRejected&&shieldsRejected&&invalidRejected&&deadRejected&&identityRejected)result|=128;
return result;
}
}
#endif
#if PLUGIN_SESSION_RECOVERY
namespace XFEEDToolBox.Plugin;
internal static unsafe partial class Navigation
{
private readonly record struct RecoveryDockingStartGate(ulong now,ulong deadline,bool authorized,bool module,bool profile,bool blocked,
float actual,float controller,float source,float accumulator);
private static bool RecoveryDockingStartAllowed(in RecoveryDockingStartGate value)
=>value.authorized&&value.module&&value.profile&&!value.blocked&&value.now<value.deadline&&value.deadline-value.now<=250
&&float.IsFinite(value.actual)&&Math.Abs(value.actual)<=.001f&&float.IsFinite(value.controller)&&Math.Abs(value.controller)<=.001f
&&float.IsFinite(value.source)&&Math.Abs(value.source)<=.001f&&float.IsFinite(value.accumulator)&&Math.Abs(value.accumulator)<=.001f;
private static bool RecoveryDockingBlocked(nuint consumer)
{
// Exact E9A160 predicate. The original getter owns the temporary weak
// reference; the original contains function neither consumes it nor
// changes the set. Both temporary references are released once.
var subject=Pointer(consumer+0xA8);var blockers=Pointer(consumer+0x1C8);
if(subject<0x10000||Pointer(subject)!=image+0x515E020||Pointer(Pointer(subject)+0x30)!=image+0xEBDA20||blockers<0x10000)
throw new InvalidOperationException("Original docking blocker interfaces differ");
var set=blockers+0x90;var capacity=Read<ulong>(set+8);var used=Read<ulong>(set+0x18);
if(used>4096||capacity>8192||used!=0&&(capacity==0||Pointer(set)<0x10000))throw new InvalidOperationException("Original docking blocker set exceeds its bound");
nuint reference=0,copy=0;
try
{
Call(image+0xEBDA20,(ulong)subject,(ulong)(nuint)(&reference));
if((byte)Call(image+0x64ADF0,(ulong)(nuint)(&reference))==0)return false;
Call(image+0x62D0A0,(ulong)(nuint)(©),(ulong)(nuint)(&reference));
return (byte)Call(image+0x8C2710,(ulong)set,(ulong)(nuint)(©))!=0;
}
finally
{
if(copy!=0)Call(image+0x62F3A0,(ulong)(nuint)(©));
if(reference!=0)Call(image+0x62F3A0,(ulong)(nuint)(&reference));
}
}
internal static void CallRecoveryDockingStart(RecoveryResetBinding proof,nuint node,ulong deadline,Func<bool> stillAuthorized,Action dispatching)
{
var frame=ReadRecoveryResetFrame(proof,node);var consumer=proof.computer-0x58;
var activity=Pointer(consumer+0xF0);var atc=Pointer(consumer+0x1B0);var dock=LocalDocking(frame);
var profile=Pointer(consumer+0x298);var controller=Pointer(frame.inputRoot+0x2F8);var station=Pointer(dock+0x4E0);
if(activity==0||Pointer(activity)!=image+0x5165E08||Pointer(Pointer(activity)+0x40)!=image+0xEE9F30
||atc==0||Pointer(atc)!=image+0x5317960||Pointer(Pointer(atc)+0xF0)!=image+0x2C65D40
||profile==0||Pointer(profile)!=image+0x52A0930||Pointer(Pointer(profile)+0x90)!=image+0x25FF830
||Read<byte>(consumer+0x3CA)!=0||Read<byte>(consumer+0x3CD)!=0||Read<byte>(consumer+0x3CF)==0
||Pointer(consumer+0x2B8)!=proof.source||station==0||Read<uint>(station+0xC0)!=8||Read<ulong>(station+0xB0)!=proof.target.GetProperty("marketId").GetUInt32())
throw new InvalidOperationException("Original docking activity, module, profile or ATC owner differs");
// A present automatic target must match. With no retained automatic
// target, the explicit SDK request uses the verified original ATC
// station reference, just as the original activity command accepts.
var automaticTarget=Pointer(consumer+0x2B0);
if(automaticTarget!=0&&automaticTarget!=station)throw new InvalidOperationException("Original automatic docking target differs from its current ATC grant");
var enabled=(byte)Call(image+0x25FF830,(ulong)profile)!=0;
var blocked=RecoveryDockingBlocked(consumer);
var check=new RecoveryDockingStartGate(UtcMilliseconds(),deadline,stillAuthorized(),LocalDockingAvailable(proof.computer),enabled,blocked,
Read<float>(frame.inputRoot+0x70),Read<float>(controller+0x680),Read<float>(proof.source+0x18),Read<float>(node+0xD0));
if(!RecoveryDockingStartAllowed(check))throw new InvalidOperationException("Original docking start requires a live intent, real four-place zero, available module and enabled unblocked policy");
if(!Platform.ReadBytes(image+0xEE9F30,8).AsSpan().SequenceEqual(new byte[]{0x4C,0x8B,0xDC,0x57,0x48,0x83,0xEC,0x50})
||!Platform.ReadBytes(image+0xB8BF30,10).AsSpan().SequenceEqual(new byte[]{0x48,0x89,0x5C,0x24,0x08,0x48,0x89,0x74,0x24,0x10})
||Read<ulong>(image+0x4E328D0)!=0x4000000040000000UL||Read<ulong>(image+0x4E328D8)!=0x4000000040000000UL)
throw new InvalidOperationException("Original docking command signature or original parameters differ");
ushort identifier=0;nuint stationCopy=0;var transferred=false;
try
{
Call(image+0x62D0A0,(ulong)(nuint)(&stationCopy),(ulong)(nuint)(&station));
Call(image+0xB8BF30,(ulong)(nuint)(&identifier));
if(identifier==0||stationCopy!=station)throw new InvalidOperationException("Original docking request identity or station reference is unavailable");
frame=ReadRecoveryResetFrame(proof,node);controller=Pointer(frame.inputRoot+0x2F8);
check=check with{now=UtcMilliseconds(),authorized=stillAuthorized(),actual=Read<float>(frame.inputRoot+0x70),
controller=Read<float>(controller+0x680),source=Read<float>(proof.source+0x18),accumulator=Read<float>(node+0xD0)};
if(!RecoveryDockingStartAllowed(check)||Pointer(LocalDocking(frame)+0x4E0)!=station||Pointer(consumer+0xF0)!=activity||Pointer(consumer+0x1B0)!=atc)
throw new InvalidOperationException("Original docking request changed before dispatch");
dispatching();transferred=true;
// Original E9A160 uses this exact command, original parameter
// vector and fifth argument. EE9F30 retains its own E781C0
// eligibility predicate, creates the native state-1 activity and
// consumes the token/reference. No SDK write to AI or its timer.
Call(image+0xEE9F30,(ulong)activity,(ulong)(nuint)(&identifier),(ulong)(nuint)(&stationCopy),(ulong)(image+0x4E328D0),0);
Call(image+0x2C65D40,(ulong)atc);
}
finally
{
// An uncertain native return may already have consumed both
// arguments. Never free or replay such an intent a second time.
if(!transferred)
{
if(identifier!=0)Call(image+0x551D80,(ulong)Pointer(image+0x5EFF5E0),identifier);
if(stationCopy!=0)Call(image+0x62F3A0,(ulong)(nuint)(&stationCopy));
}
}
}
internal static uint RecoveryDockingStartSelfTest()
{
var good=new RecoveryDockingStartGate(1000,1250,true,true,true,false,0,0,0,0);uint result=0;
if(RecoveryDockingStartAllowed(good))result|=1;
if(!RecoveryDockingStartAllowed(good with{source=.05f})&&!RecoveryDockingStartAllowed(good with{accumulator=.75f}))result|=2;
if(!RecoveryDockingStartAllowed(good with{actual=.05f})&&!RecoveryDockingStartAllowed(good with{controller=.75f}))result|=4;
if(!RecoveryDockingStartAllowed(good with{actual=float.NaN})&&!RecoveryDockingStartAllowed(good with{source=float.PositiveInfinity}))result|=8;
if(!RecoveryDockingStartAllowed(good with{now=1250})&&!RecoveryDockingStartAllowed(good with{deadline=1251}))result|=16;
if(!RecoveryDockingStartAllowed(good with{authorized=false}))result|=32;
if(!RecoveryDockingStartAllowed(good with{profile=false})&&!RecoveryDockingStartAllowed(good with{module=false}))result|=64;
var stable=new Snapshot{healthValid=true,entity=7,life=0x123400,hullFraction=.4,shieldKnown=true,shieldFraction=1};var changed=stable;
var historical=RecoveryResetHealthEligible(stable,changed);changed.hullFraction=.39;var damageRejected=!RecoveryResetHealthEligible(stable,changed);
changed=stable;changed.shieldFraction=0;var shieldsRejected=!RecoveryResetHealthEligible(stable,changed);
changed=stable;changed.hullFraction=double.NaN;var invalidRejected=!RecoveryResetHealthEligible(stable,changed);
changed=stable;changed.hullFraction=0;var deadRejected=!RecoveryResetHealthEligible(stable,changed);
changed=stable;changed.entity=8;var identityRejected=!RecoveryResetHealthEligible(stable,changed);
if(!RecoveryDockingStartAllowed(good with{blocked=true})&&historical&&damageRejected&&shieldsRejected&&invalidRejected&&deadRejected&&identityRejected)result|=128;
return result;
}
}
#endif