XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

AutoMiningScript

【SpaceEngineer】全自动挖矿脚本

公开
关注 0 Fork 0 Star 0
UTF-8
using System;
using System.Linq;
using System.Reflection;
using Sandbox.ModAPI.Ingame;
using VRage.Game.ModAPI.Ingame.Utilities;
using VRageMath;
using Xunit;
using P=AutoMiningScript.Program;

namespace AutoMiningScript.Tests
{
    public class FleetTrafficTests
    {
        static FleetStateTests.Rig Arrivals(int count)
        {
            var r=new FleetStateTests.Rig(count,false);
            foreach(var t in r.Miners){t.State=P.FlightState.Holding;t.Position+=Vector3D.Forward*100;}
            r.RegisterAll();r.Tick(30);return r;
        }
        static void FreshTicks(FleetStateTests.Rig r,int count)
        {for(int n=0;n<count;n++){if(n%5==0)foreach(var t in r.Miners)r.Receive("TELEMETRY",t);r.Tick(1);}}
        [Theory]
        [InlineData(4)]
        [InlineData(16)]
        public void IndependentParallelBerthsCanRemainGrantedAtTheSameTime(int count)
        {
            var r=Arrivals(count);foreach(var t in r.Miners)r.Receive("DOCK_REQUEST",t);FreshTicks(r,count*12);
            var grants=r.Sent.Where(p=>p.Kind=="DOCK_GRANT").Select(p=>P.DockFrame.FromIni(p.Body)).ToList();
            Assert.Equal(count,grants.Count);Assert.Equal(count,grants.Select(g=>g.ConnectorId).Distinct().Count());
            Assert.Equal(count,grants.Select(g=>g.Token).Distinct().Count());Assert.Equal(count,P.Data.ReadLong(r.Save(),"fleet","LaneCount"));
        }
        [Fact]
        public void OverlappingPortCorridorsSerializeAndDoNotExpireAnUnknownShip()
        {
            var r=Arrivals(2);r.SetPort(1,Vector3D.Right*4,Vector3D.Forward);r.Miners[1].Position=new Vector3D(4,0,-130);
            FreshTicks(r,30);foreach(var t in r.Miners)r.Receive("DOCK_REQUEST",t);FreshTicks(r,30);
            var first=Assert.Single(r.Sent,p=>p.Kind=="DOCK_GRANT");r.Sent.Clear();r.Tick(1000);
            int other=first.Target==r.Miners[0].Id?1:0;r.Receive("DOCK_REQUEST",r.Miners[other]);r.Tick(20);
            Assert.DoesNotContain(r.Sent,p=>p.Kind=="DOCK_GRANT");Assert.Equal(1,P.Data.ReadLong(r.Save(),"fleet","LaneCount"));
        }
        [Fact]
        public void ArrivalAndDepartureOnSeparateCorridorsRunTogether()
        {
            var r=new FleetStateTests.Rig(2,true);r.SetConnected(1,false);r.Miners[1].Position=new Vector3D(40,0,-100);r.Miners[1].State=P.FlightState.Holding;
            r.RegisterAll();r.Fleet.Command("mark 6 6 20 GPS:entry:0:0:-200: GPS:inward:0:0:-201:");r.Fleet.Command("start");FreshTicks(r,30);
            r.Miners[0].JobId=r.Fleet.GetJobs().Single().Id;r.Receive("DEPART_REQUEST",r.Miners[0]);r.Receive("DOCK_REQUEST",r.Miners[1]);FreshTicks(r,30);
            Assert.Single(r.Sent,p=>p.Kind=="DOCK_GRANT");Assert.Single(r.Sent,p=>p.Kind=="DEPART_GRANT");Assert.Equal(2,P.Data.ReadLong(r.Save(),"fleet","LaneCount"));
        }
        [Fact]
        public void StoppedFaultAwayFromThePortReleasesItsLaneAndItsRemoteTask()
        {
            var r=Arrivals(2);r.Receive("DOCK_REQUEST",r.Miners[0]);FreshTicks(r,15);
            r.Fleet.Command("mark 6 6 20 GPS:entry:0:0:-300: GPS:inward:0:0:-301:");var job=r.Fleet.GetJobs().Single();r.Planner.SetOwner(job,r.Miners[0].Id);
            r.Miners[0].State=P.FlightState.Fault;r.Miners[0].Position=new Vector3D(-50,0,-100);r.Receive("TELEMETRY",r.Miners[0]);
            r.Receive("DOCK_REQUEST",r.Miners[1]);FreshTicks(r,20);
            Assert.Equal("",job.Owner);Assert.Equal(1,P.Data.ReadLong(r.Save(),"fleet","LaneCount"));
            Assert.Equal(r.Miners[1].Id,P.Data.Text(r.Save(),"fleet","LaneOwner"));Assert.Contains(r.Sent,p=>p.Kind=="DOCK_GRANT" && p.Target==r.Miners[1].Id);
        }
        [Theory]
        [InlineData(true)]
        [InlineData(false)]
        public void FaultAtAContactOnlyBlocksTheAffectedCorridor(bool stale)
        {
            var r=Arrivals(2);r.Receive("DOCK_REQUEST",r.Miners[0]);FreshTicks(r,15);
            r.Miners[0].State=P.FlightState.Fault;r.Miners[0].Position=Vector3D.Forward*20;r.Receive("TELEMETRY",r.Miners[0]);
            if(stale)r.Program.Now+=10;else r.Tick(12);
            r.Receive("DOCK_REQUEST",r.Miners[1]);r.Tick(12);
            var second=Assert.Single(r.Sent,p=>p.Kind=="DOCK_GRANT" && p.Target==r.Miners[1].Id);
            Assert.Equal(101,P.DockFrame.FromIni(second.Body).ConnectorId);
            Assert.Equal(stale?2:1,P.Data.ReadLong(r.Save(),"fleet","LaneCount"));
        }
        [Fact]
        public void DockRetreatReleaseAcceptsAStoppedShipBeforeTheFarWaitingPoint()
        {
            var r=Arrivals(1);r.Receive("DOCK_REQUEST",r.Miners[0]);FreshTicks(r,15);var grant=P.DockFrame.FromIni(r.Sent.First(p=>p.Kind=="DOCK_GRANT").Body);
            r.Miners[0].Position=Vector3D.Forward*35;r.Miners[0].State=P.FlightState.DockRetreat;r.Receive("TELEMETRY",r.Miners[0]);
            var body=new MyIni();body.Set("lease","Token",grant.Token);r.Fleet.Receive(new P.Packet {Kind="LANE_RELEASE",From=r.Miners[0].Id,Source=5000,Body=body});
            Assert.Equal(0,P.Data.ReadLong(r.Save(),"fleet","LaneCount"));
        }
        [Fact]
        public void MultipleUnknownLanesSurviveSaveRemovalAndReloadWithTokensRevoked()
        {
            var r=Arrivals(2);r.Checkpoint();foreach(var t in r.Miners)r.Receive("DOCK_REQUEST",t);FreshTicks(r,30);Assert.Equal(2,P.Data.ReadLong(r.Save(),"fleet","LaneCount"));
            r.Program.Now+=10;r.Fleet.Command("clear-offline");var after=new FleetStateTests.Rig(2,false);after.Restore(r.Program.Storage);
            Assert.Empty(after.Fleet.GetTelemetry());var saved=after.Save();Assert.Equal(2,P.Data.ReadLong(saved,"fleet","LaneCount"));
            Assert.Empty(P.Data.Text(saved,"fleet","LaneToken"));Assert.Empty(P.Data.Text(saved,"fleetLane1","LaneToken"));
            Assert.Equal(2,P.Data.ReadLong(saved,"fleet","ProtectedOwnerCount"));
        }
        static P.Packet Traffic(FleetStateTests.Rig r,int index)
        {
            typeof(P.FleetController).GetMethod("SendTraffic",BindingFlags.NonPublic|BindingFlags.Instance).Invoke(r.Fleet,new object[]{r.Fleet.GetTelemetry().Single(t=>t.Id==r.Miners[index].Id)});
            return r.Sent.Last(p=>p.Kind=="TRAFFIC" && p.Target==r.Miners[index].Id);
        }
        [Fact]
        public void CrossingCruisePathsHaveDeterministicYieldPriority()
        {
            var r=Arrivals(2);var a=r.Miners[0];var b=r.Miners[1];a.State=b.State=P.FlightState.Transit;a.HasRoute=b.HasRoute=true;
            a.Position=Vector3D.Left*20;a.RouteTarget=Vector3D.Right*20;a.Velocity=Vector3D.Right*3;
            b.Position=Vector3D.Forward*20;b.RouteTarget=Vector3D.Backward*20;b.Velocity=Vector3D.Backward*3;
            a.ThrustMargin=b.ThrustMargin=2;r.Receive("TELEMETRY",a);r.Receive("TELEMETRY",b);
            Assert.False(P.Data.Flag(Traffic(r,0).Body,"traffic","Wait"));Assert.True(P.Data.Flag(Traffic(r,1).Body,"traffic","Wait"));
        }
        [Fact]
        public void StationaryFaultOnTheCruiseLineCreatesACameraCheckedDetour()
        {
            var r=Arrivals(2);var a=r.Miners[0];var b=r.Miners[1];a.State=P.FlightState.Transit;a.HasRoute=true;
            a.Position=Vector3D.Forward*100;a.RouteTarget=Vector3D.Zero;a.ThrustMargin=2;b.Position=Vector3D.Forward*80;b.State=P.FlightState.Fault;
            r.Receive("TELEMETRY",a);r.Receive("TELEMETRY",b);var body=Traffic(r,0).Body;
            Assert.True(P.Data.Flag(body,"traffic","Avoid"));Assert.False(P.Data.Flag(body,"traffic","Wait"));
            var point=P.Data.ReadVector(body,"traffic","Point",Vector3D.Zero);Assert.True(Vector3D.Distance(point,b.Position)>a.Radius+b.Radius+4);
        }
        [Fact]
        public void StaleFaultPositionCannotAuthorizeAnUnverifiedDetour()
        {
            var r=Arrivals(2);var a=r.Miners[0];var b=r.Miners[1];a.State=P.FlightState.Transit;a.HasRoute=true;
            a.Position=Vector3D.Forward*100;a.RouteTarget=Vector3D.Zero;b.Position=Vector3D.Forward*80;b.State=P.FlightState.Fault;r.Receive("TELEMETRY",b);
            r.Program.Now+=5;r.Receive("TELEMETRY",a);var body=Traffic(r,0).Body;Assert.True(P.Data.Flag(body,"traffic","Wait"));Assert.False(P.Data.Flag(body,"traffic","Avoid"));
        }
        [Fact]
        public void AStoppedFaultStillProtectsItsPointAfterOfflineRegistryRemoval()
        {
            var r=Arrivals(2);r.Checkpoint();r.Miners[0].State=P.FlightState.Fault;r.Miners[0].Position=Vector3D.Forward*20;
            r.Receive("TELEMETRY",r.Miners[0]);r.Tick(12);r.Program.Now+=10;r.Receive("TELEMETRY",r.Miners[1]);r.Fleet.Command("clear-offline");
            var after=new FleetStateTests.Rig(2,false);after.Restore(r.Program.Storage);
            Assert.Equal(1,P.Data.ReadLong(after.Save(),"fleet","ClearanceCount"));Assert.Equal(1,P.Data.ReadLong(after.Save(),"fleet","ProtectedOwnerCount"));
        }
        [Fact]
        public void FrontShipDoesNotYieldToItsFollower()
        {
            var r=Arrivals(2);var rear=r.Miners[0];var front=r.Miners[1];rear.HasRoute=front.HasRoute=true;rear.State=front.State=P.FlightState.Transit;
            rear.Position=Vector3D.Forward*80;front.Position=Vector3D.Forward*60;rear.RouteTarget=front.RouteTarget=Vector3D.Zero;
            rear.Velocity=front.Velocity=Vector3D.Backward*3;r.Receive("TELEMETRY",rear);r.Receive("TELEMETRY",front);
            Assert.False(P.Data.Flag(Traffic(r,1).Body,"traffic","Wait"));
        }
        sealed class MovingShip
        {
            public readonly ReturnNavigationTests.Rig R=new ReturnNavigationTests.Rig();
            public Vector3D Position,Velocity,Target;
            public bool Arrived;
            public MovingShip(Vector3D start,Vector3D target)
            {
                Position=start;Target=target;R.Orientation=MatrixD.CreateWorld(start,Vector3D.Normalize(target-start),Vector3D.Up);
                R.Controller.Method("GetPosition",a=>Position).Method("GetShipVelocities",a=>new MyShipVelocities(Velocity,Vector3D.Zero));
                R.Camera.Method("GetPosition",a=>Position).Method("CanScan",a=>true);
            }
            public void Step(double now)
            {
                R.Program.Now=now;Arrived=R.Flight.Move(Target,Vector3D.Zero,Vector3D.Normalize(Target-Position),Vector3D.Up,5,.5,true,.05,true);
                Vector3D force=Vector3D.Zero;foreach(var thrust in R.Ship.Thrusters)force+=thrust.WorldMatrix.Backward*thrust.ThrustOverridePercentage*thrust.MaxEffectiveThrust;
                Velocity+=force/1000*.05;Position+=Velocity*.05;
                var desired=(MatrixD)typeof(P.FlightController).GetField("previousDesired",BindingFlags.NonPublic|BindingFlags.Instance).GetValue(R.Flight);
                R.Orientation=MatrixD.CreateWorld(Position,desired.Forward,desired.Up);
            }
        }
        [Fact]
        public void CrossingShipsBothReachTheirGoalsWithPhysicalSeparationInTheControlModel()
        {
            var r=Arrivals(2);var ships=new[]{new MovingShip(Vector3D.Left*40,Vector3D.Right*40),new MovingShip(Vector3D.Forward*40,Vector3D.Backward*40)};
            double separation=double.MaxValue;bool yielded=false;
            for(int n=0;n<2000 && ships.Any(s=>!s.Arrived);n++)
            {
                r.Program.Now+=.05;
                if(n%10==0)
                {
                    for(int i=0;i<2;i++)
                    {
                        var t=r.Miners[i];var s=ships[i];t.State=P.FlightState.Transit;t.Position=s.Position;t.Velocity=s.Velocity;t.Radius=2;t.ThrustMargin=100;
                        t.HasRoute=!s.Arrived;t.RouteTarget=s.R.Flight.HasRoute?s.R.Flight.RouteTarget:s.Target;r.Receive("TELEMETRY",t);
                    }
                    for(int i=0;i<2;i++)if(!ships[i].Arrived)
                    {
                        var body=Traffic(r,i).Body;var f=ships[i].R.Flight;f.TrafficWait=P.Data.Flag(body,"traffic","Wait");f.TrafficAvoid=P.Data.Flag(body,"traffic","Avoid");
                        f.TrafficPoint=P.Data.ReadVector(body,"traffic","Point",Vector3D.Zero);f.TrafficAt=r.Program.Now;yielded|=f.TrafficWait;
                    }
                }
                foreach(var s in ships)s.Step(r.Program.Now);
                separation=Math.Min(separation,Vector3D.Distance(ships[0].Position,ships[1].Position));
            }
            Assert.True(yielded);Assert.True(ships.All(s=>s.Arrived));Assert.True(separation>=5,"Minimum separation: "+separation);
        }
        [Fact]
        public void FinalDockingDoesNotUseAnOldTrafficWaitOrDetour()
        {
            var r=new ReturnNavigationTests.Rig();r.Flight.TrafficWait=r.Flight.TrafficAvoid=true;r.Flight.TrafficPoint=Vector3D.Right*100;r.Flight.TrafficAt=0;
            r.Flight.Move(Vector3D.Forward*3,Vector3D.Zero,Vector3D.Forward,Vector3D.Up,.2,.03,false,.05,false,false);
            Assert.True(r.Flight.CommandSpeed>0);Assert.Equal(0,r.Rays);Assert.Equal(Vector3D.Forward*3,r.Flight.RouteTarget);
        }
    }
}