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 bytes=[];public Action? 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;iPut(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? 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); } }