using XFEEDToolBox.Core.Native;
using XFEEDToolBox.Core.Navigation;
using XFEExtension.NetCore.XUnit.Attributes;
namespace XFEEDToolBox.Test;
[TestFixture]
public class NativeSystemOrbitReaderTests
{
private const ulong Resource=0x20000,Body=0x30000,Parent=0x40000,Transforms=0x50000;
private const ulong ChildAddress=(2UL<<55)|7,ParentAddress=(1UL<<55)|7;
private static readonly DateTimeOffset At=DateTimeOffset.Parse("2026-10-25T10:00:00Z");
private sealed class Memory:IReadOnlyGameMemory
{
public ulong ImageBase=>0x100000000;public ulong ImageSize=>0x7000000;
private readonly Dictionary<ulong,byte> bytes=[];public Action<ulong>? BeforeRead;
public byte[] Read(ulong at,int length){BeforeRead?.Invoke(at);return Enumerable.Range(0,length).Select(i=>bytes.GetValueOrDefault(at+(ulong)i)).ToArray();}
public void Put(ulong at,byte[] data){for(var i=0;i<data.Length;i++)bytes[at+(ulong)i]=data[i];}
public void Q(ulong at,ulong value)=>Put(at,BitConverter.GetBytes(value));
public void U(ulong at,uint value)=>Put(at,BitConverter.GetBytes(value));
public void D(ulong at,double value)=>Put(at,BitConverter.GetBytes(value));
public void V(ulong at,Vector3d value){D(at,value.X);D(at+8,value.Y);D(at+16,value.Z);}
public void Frame(ulong at,Vector3d x,Vector3d y,Vector3d z,Vector3d position)
{V(at,x);V(at+0x20,y);V(at+0x40,z);V(at+0x60,position);}
}
private static Memory Scene()
{
var m=new Memory();
// Original instructions independently copied from the pinned PE proof.
m.Put(m.ImageBase+0x29EB59A,Convert.FromHexString("410f108f300100000f540dd7f43f02660f2f0dafac730276754d8d4770450fb6ce488d542468498bcde828190000"));
m.Put(m.ImageBase+0x3D00FA0,Convert.FromHexString("48895c2408574883ec30488bd90f297424204883c170498bf90f28f1e8ff936bfe"));
m.Put(m.ImageBase+0x23BA7A7,Convert.FromHexString("4c8d87800100000f28050b6fa202488d542440"));
m.Put(m.ImageBase+0x3D0180D,Convert.FromHexString("49039e88030000488bd3e824ffbbfc"));
m.Q(Body,m.ImageBase+0x553F860);m.Q(m.ImageBase+0x553F880,m.ImageBase+0x3D00FA0);
m.Q(Body+0x18,ChildAddress);m.U(Body+0x20,2);m.Q(Body+0x378,Resource);m.Q(Body+0x350,Parent);
m.D(Body+0x70,.3);m.D(Body+0x90,.4);m.D(Body+0xB0,.5);m.D(Body+0x130,86400);m.D(Body+0x150,.2);m.D(Body+0x170,1000);
m.Frame(Body+0x1F0,new(1,0,0),new(0,1,0),new(0,0,1),Vector3d.Zero);
m.Q(Parent+0x18,ParentAddress);m.Q(Parent+0x378,Resource);m.U(Parent+0x384,1);m.Q(Resource+0x380,2);m.Q(Resource+0x388,Transforms);
// Parent orbit frame rotates90degrees; independent spin (+80) is a
// different rotation that the orbit reader must not accidentally add.
m.Frame(Transforms+0x180+0x100,new(0,1,0),new(-1,0,0),new(0,0,1),new(10000,20000,30000));
m.Frame(Transforms+0x180+0x80,new(0,0,-1),new(0,1,0),new(1,0,0),Vector3d.Zero);
return m;
}
private static SystemLocation Child=>new(1,ChildAddress,"Fixture planet","",3,SystemLocationCategory.Planet,null,
new(10000,19800,30000+1000*Math.Sqrt(.96)),null,false,"child-identity");
private static SystemLocation ParentLocation=>new(2,ParentAddress,"Fixture star","",1,SystemLocationCategory.Star,null,
new(10000,20000,30000),null,false,"parent-identity");
private static SystemOrbit Read(Memory memory,IReadOnlyList<SystemLocation>? locations=null)
=>NativeSystemOrbitReader.Read(memory,Resource,7,At,locations??[Child],id=>id==ChildAddress?Body:id==ParentAddress?Parent:0).First();
[Test]public void OriginalOrbitAxesComposeWithParentOrbitFrameWithoutTheIndependentSpin()
{
var orbit=Read(Scene(),[Child,ParentLocation]);Check.That(orbit.Renderable);Check.Equal(SystemOrbitQuality.NativeVerified,orbit.Quality);
Check.Equal(new Vector3d(0,1,0),orbit.PeriapsisDirection);Check.Equal(new Vector3d(0,0,1),orbit.TransverseDirection);
Check.Equal(ParentLocation.Position,orbit.ParentPosition);Check.Equal("parent-identity",orbit.ParentIdentity);
Check.Equal(1000d,orbit.SemiMajorAxisMetres);Check.Equal(.2,orbit.Eccentricity);Check.Equal(86400d,orbit.PeriodSeconds);
Check.That(Math.Abs(orbit.OrbitalInclinationDegrees!.Value-.3*180/Math.PI)<1e-10);
}
[Test]public void ARealParentFrameWithoutACatalogueRowSuppliesAFocusWithoutInventingASelectableBody()
{
var orbit=Read(Scene());Check.That(orbit.Renderable);Check.Equal(ParentAddress,orbit.ParentWorldAddress);
Check.Equal("native-body:7:"+ParentAddress,orbit.ParentIdentity);Check.That(orbit.ParentPosition is {Finite:true});
Check.That(!orbit.ParentIsBarycentre);Check.Equal("原生父焦点",orbit.ParentName);
}
[Test]public void CarriersAndPoisSharingAParentsReferenceWorldAreNotItsCelestialIdentity()
{
var carrier=ParentLocation with{Category=SystemLocationCategory.Carrier,Name="Carrier",Identity="carrier",Position=new(11000,21000,31000)};
var signal=carrier with{Category=SystemLocationCategory.Signal,Identity="signal"};
var orbit=Read(Scene(),[Child,carrier,ParentLocation,signal]);
Check.That(orbit.Renderable);Check.Equal("parent-identity",orbit.ParentIdentity);Check.Equal(ParentLocation.Position,orbit.ParentPosition);
}
[Test]public void UnknownLayoutAndWrongBodyKindsCannotAuthorizeOrbitGeometry()
{
var m=Scene();m.Put(m.ImageBase+0x23BA7A7,[0]);
Check.Equal(0,NativeSystemOrbitReader.Read(m,Resource,7,At,[Child],_=>Body).Count);
m=Scene();m.U(Body+0x20,7);Check.That(!Read(m).Renderable);
m=Scene();m.Q(Body,m.ImageBase+0x553F908);Check.That(!Read(m).Renderable);
}
[Test]public void AFiniteEllipseInTheWrongFrameOrWithConflictingParentIdentityIsRejected()
{
var m=Scene();m.Frame(Body+0x1F0,new(0,1,0),new(-1,0,0),new(0,0,1),Vector3d.Zero);
Check.That(!Read(m).Renderable);
Check.That(!Read(Scene(),[Child,ParentLocation with{Position=new(10002,20000,30000)}]).Renderable);
Check.That(!Read(Scene(),[Child,ParentLocation,ParentLocation with{Identity="duplicate"}]).Renderable);
Check.That(!Read(Scene(),[Child with{Position=Child.Position!.Value+new Vector3d(2000,0,0)}]).Renderable);
}
[Test]public void ChangedResourceOrElementsDuringReadCannotPublishVerifiedOrbit()
{
var m=Scene();var reads=0;m.BeforeRead=at=>{if(at==Body+0x70&&++reads==2)m.D(Body+0x170,2000);};
Check.That(!Read(m).Renderable);
m=Scene();m.Q(Parent+0x378,Resource+8);Check.That(!Read(m).Renderable);
m=Scene();m.D(Body+0x150,1);Check.That(!Read(m).Renderable);
m=Scene();m.D(Body+0x170,double.NaN);Check.That(!Read(m).Renderable);
}
}
using XFEEDToolBox.Core.Native;
using XFEEDToolBox.Core.Navigation;
using XFEExtension.NetCore.XUnit.Attributes;
namespace XFEEDToolBox.Test;
[TestFixture]
public class NativeSystemOrbitReaderTests
{
private const ulong Resource=0x20000,Body=0x30000,Parent=0x40000,Transforms=0x50000;
private const ulong ChildAddress=(2UL<<55)|7,ParentAddress=(1UL<<55)|7;
private static readonly DateTimeOffset At=DateTimeOffset.Parse("2026-10-25T10:00:00Z");
private sealed class Memory:IReadOnlyGameMemory
{
public ulong ImageBase=>0x100000000;public ulong ImageSize=>0x7000000;
private readonly Dictionary<ulong,byte> bytes=[];public Action<ulong>? BeforeRead;
public byte[] Read(ulong at,int length){BeforeRead?.Invoke(at);return Enumerable.Range(0,length).Select(i=>bytes.GetValueOrDefault(at+(ulong)i)).ToArray();}
public void Put(ulong at,byte[] data){for(var i=0;i<data.Length;i++)bytes[at+(ulong)i]=data[i];}
public void Q(ulong at,ulong value)=>Put(at,BitConverter.GetBytes(value));
public void U(ulong at,uint value)=>Put(at,BitConverter.GetBytes(value));
public void D(ulong at,double value)=>Put(at,BitConverter.GetBytes(value));
public void V(ulong at,Vector3d value){D(at,value.X);D(at+8,value.Y);D(at+16,value.Z);}
public void Frame(ulong at,Vector3d x,Vector3d y,Vector3d z,Vector3d position)
{V(at,x);V(at+0x20,y);V(at+0x40,z);V(at+0x60,position);}
}
private static Memory Scene()
{
var m=new Memory();
// Original instructions independently copied from the pinned PE proof.
m.Put(m.ImageBase+0x29EB59A,Convert.FromHexString("410f108f300100000f540dd7f43f02660f2f0dafac730276754d8d4770450fb6ce488d542468498bcde828190000"));
m.Put(m.ImageBase+0x3D00FA0,Convert.FromHexString("48895c2408574883ec30488bd90f297424204883c170498bf90f28f1e8ff936bfe"));
m.Put(m.ImageBase+0x23BA7A7,Convert.FromHexString("4c8d87800100000f28050b6fa202488d542440"));
m.Put(m.ImageBase+0x3D0180D,Convert.FromHexString("49039e88030000488bd3e824ffbbfc"));
m.Q(Body,m.ImageBase+0x553F860);m.Q(m.ImageBase+0x553F880,m.ImageBase+0x3D00FA0);
m.Q(Body+0x18,ChildAddress);m.U(Body+0x20,2);m.Q(Body+0x378,Resource);m.Q(Body+0x350,Parent);
m.D(Body+0x70,.3);m.D(Body+0x90,.4);m.D(Body+0xB0,.5);m.D(Body+0x130,86400);m.D(Body+0x150,.2);m.D(Body+0x170,1000);
m.Frame(Body+0x1F0,new(1,0,0),new(0,1,0),new(0,0,1),Vector3d.Zero);
m.Q(Parent+0x18,ParentAddress);m.Q(Parent+0x378,Resource);m.U(Parent+0x384,1);m.Q(Resource+0x380,2);m.Q(Resource+0x388,Transforms);
// Parent orbit frame rotates90degrees; independent spin (+80) is a
// different rotation that the orbit reader must not accidentally add.
m.Frame(Transforms+0x180+0x100,new(0,1,0),new(-1,0,0),new(0,0,1),new(10000,20000,30000));
m.Frame(Transforms+0x180+0x80,new(0,0,-1),new(0,1,0),new(1,0,0),Vector3d.Zero);
return m;
}
private static SystemLocation Child=>new(1,ChildAddress,"Fixture planet","",3,SystemLocationCategory.Planet,null,
new(10000,19800,30000+1000*Math.Sqrt(.96)),null,false,"child-identity");
private static SystemLocation ParentLocation=>new(2,ParentAddress,"Fixture star","",1,SystemLocationCategory.Star,null,
new(10000,20000,30000),null,false,"parent-identity");
private static SystemOrbit Read(Memory memory,IReadOnlyList<SystemLocation>? locations=null)
=>NativeSystemOrbitReader.Read(memory,Resource,7,At,locations??[Child],id=>id==ChildAddress?Body:id==ParentAddress?Parent:0).First();
[Test]public void OriginalOrbitAxesComposeWithParentOrbitFrameWithoutTheIndependentSpin()
{
var orbit=Read(Scene(),[Child,ParentLocation]);Check.That(orbit.Renderable);Check.Equal(SystemOrbitQuality.NativeVerified,orbit.Quality);
Check.Equal(new Vector3d(0,1,0),orbit.PeriapsisDirection);Check.Equal(new Vector3d(0,0,1),orbit.TransverseDirection);
Check.Equal(ParentLocation.Position,orbit.ParentPosition);Check.Equal("parent-identity",orbit.ParentIdentity);
Check.Equal(1000d,orbit.SemiMajorAxisMetres);Check.Equal(.2,orbit.Eccentricity);Check.Equal(86400d,orbit.PeriodSeconds);
Check.That(Math.Abs(orbit.OrbitalInclinationDegrees!.Value-.3*180/Math.PI)<1e-10);
}
[Test]public void ARealParentFrameWithoutACatalogueRowSuppliesAFocusWithoutInventingASelectableBody()
{
var orbit=Read(Scene());Check.That(orbit.Renderable);Check.Equal(ParentAddress,orbit.ParentWorldAddress);
Check.Equal("native-body:7:"+ParentAddress,orbit.ParentIdentity);Check.That(orbit.ParentPosition is {Finite:true});
Check.That(!orbit.ParentIsBarycentre);Check.Equal("原生父焦点",orbit.ParentName);
}
[Test]public void CarriersAndPoisSharingAParentsReferenceWorldAreNotItsCelestialIdentity()
{
var carrier=ParentLocation with{Category=SystemLocationCategory.Carrier,Name="Carrier",Identity="carrier",Position=new(11000,21000,31000)};
var signal=carrier with{Category=SystemLocationCategory.Signal,Identity="signal"};
var orbit=Read(Scene(),[Child,carrier,ParentLocation,signal]);
Check.That(orbit.Renderable);Check.Equal("parent-identity",orbit.ParentIdentity);Check.Equal(ParentLocation.Position,orbit.ParentPosition);
}
[Test]public void UnknownLayoutAndWrongBodyKindsCannotAuthorizeOrbitGeometry()
{
var m=Scene();m.Put(m.ImageBase+0x23BA7A7,[0]);
Check.Equal(0,NativeSystemOrbitReader.Read(m,Resource,7,At,[Child],_=>Body).Count);
m=Scene();m.U(Body+0x20,7);Check.That(!Read(m).Renderable);
m=Scene();m.Q(Body,m.ImageBase+0x553F908);Check.That(!Read(m).Renderable);
}
[Test]public void AFiniteEllipseInTheWrongFrameOrWithConflictingParentIdentityIsRejected()
{
var m=Scene();m.Frame(Body+0x1F0,new(0,1,0),new(-1,0,0),new(0,0,1),Vector3d.Zero);
Check.That(!Read(m).Renderable);
Check.That(!Read(Scene(),[Child,ParentLocation with{Position=new(10002,20000,30000)}]).Renderable);
Check.That(!Read(Scene(),[Child,ParentLocation,ParentLocation with{Identity="duplicate"}]).Renderable);
Check.That(!Read(Scene(),[Child with{Position=Child.Position!.Value+new Vector3d(2000,0,0)}]).Renderable);
}
[Test]public void ChangedResourceOrElementsDuringReadCannotPublishVerifiedOrbit()
{
var m=Scene();var reads=0;m.BeforeRead=at=>{if(at==Body+0x70&&++reads==2)m.D(Body+0x170,2000);};
Check.That(!Read(m).Renderable);
m=Scene();m.Q(Parent+0x378,Resource+8);Check.That(!Read(m).Renderable);
m=Scene();m.D(Body+0x150,1);Check.That(!Read(m).Renderable);
m=Scene();m.D(Body+0x170,double.NaN);Check.That(!Read(m).Renderable);
}
}