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 System.Runtime.Remoting;
using Sandbox.ModAPI.Ingame;
using VRage.Game.ModAPI.Ingame;
using VRageMath;
using Xunit;
using P = AutoMiningScript.Program;

namespace AutoMiningScript.Tests
{
    public class InstantBerthTests
    {
        static void Returning(FleetStateTests.Rig rig, int index = 0, double distance = 100)
        {
            var miner = rig.Miners[index];
            miner.State = P.FlightState.Returning;
            miner.Connected = false;
            miner.Position += Vector3D.Forward * distance;
        }

        static P.DockFrame Grant(FleetStateTests.Rig rig, string miner)
        {
            var packet = Assert.Single(rig.Sent, p => p.Kind == "DOCK_GRANT" && p.Target == miner);
            var pose = P.DockFrame.FromIni(packet.Body);
            Assert.Equal(miner, pose.Owner);
            Assert.Equal("base", pose.BaseId);
            Assert.NotEmpty(pose.Token);
            Assert.Equal("", pose.Problem);
            return pose;
        }

        static void Near(Vector3D expected, Vector3D actual)
        { Assert.True(Vector3D.Distance(expected, actual) < .000001, expected + " vs " + actual); }

        [Theory]
        [InlineData(false, false)]
        [InlineData(true, false)]
        [InlineData(false, true)]
        [InlineData(true, true)]
        public void ReturningRequestReceivesItsBerthBeforeAnyTickWhetherRegisteredOrBasePaused(bool registered, bool paused)
        {
            var rig = new FleetStateTests.Rig(1, false, "[Dock]\nStableSeconds=30\n");
            Returning(rig);
            if (registered) rig.RegisterAll();
            if (paused) { rig.Fleet.Command("start"); rig.Fleet.Command("pause"); }
            rig.Sent.Clear();

            rig.Receive("DOCK_REQUEST", rig.Miners[0]);

            Assert.Equal(0, rig.Program.Now);
            var pose = Grant(rig, rig.Miners[0].Id);
            Assert.Equal(100, pose.ConnectorId);
            Assert.Equal(30, pose.ApproachDistance);
            Assert.Equal(5000, Assert.Single(rig.Fleet.GetTelemetry()).Address);
            // The first motion sample remains unqualified for an actual docking
            // maneuver. That must not prevent choosing the free connector.
            pose.ReceivedAt = rig.Program.Now;
            Assert.False(pose.IsWindow(rig.Program.Config, rig.Program.Now));
        }

        [Fact]
        public void SeveralFirstRequestsReceiveDifferentAvailableBerthsWithoutAdvancingTheSchedulerClock()
        {
            var rig = new FleetStateTests.Rig(3, false);
            for (int i = 0; i < rig.Miners.Count; i++)
            {
                Returning(rig, i);
                rig.Receive("DOCK_REQUEST", rig.Miners[i]);
                Assert.Equal(i + 1, rig.Sent.Count(p => p.Kind == "DOCK_GRANT"));
            }
            var grants = rig.Miners.Select(t => Grant(rig, t.Id)).ToList();
            Assert.Equal(0, rig.Program.Now);
            Assert.Equal(3, grants.Select(p => p.ConnectorId).Distinct().Count());
            Assert.Equal(new[] { 30d, 40d, 50d }, grants.Select(p => p.ApproachDistance).OrderBy(d => d));
        }

        [Theory]
        [InlineData(false)]
        [InlineData(true)]
        public void RequestSamplesCurrentRotatingBerthEvenBeforeTheNextFrameUpdate(bool hadEarlierFrame)
        {
            var rig = new FleetStateTests.Rig(1, false);
            Returning(rig);
            if (hadEarlierFrame) rig.Tick(1);
            var now = rig.Program.Now;
            var position = new Vector3D(7, -3, 11);
            var forward = Vector3D.Normalize(new Vector3D(1, 2, -1));
            var center = new Vector3D(-12, 4, 6);
            var velocity = new Vector3D(2, 1, -3);
            var angular = new Vector3D(0, .04, 0);
            rig.SetPort(0, position, forward);
            var controller = (IMyShipController)typeof(P.FleetController).GetField("controller", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(rig.Fleet);
            var stub = (Stub<IMyShipController>)RemotingServices.GetRealProxy(controller);
            stub.Set("CenterOfMass", center).Method("GetShipVelocities", a => new MyShipVelocities(velocity, angular));

            rig.Receive("DOCK_REQUEST", rig.Miners[0]);

            var pose = Grant(rig, rig.Miners[0].Id);
            Assert.Equal(now, rig.Program.Now);
            Near(position, pose.Position); Near(forward, pose.Forward);
            Near(center, pose.Center); Near(velocity, pose.Velocity); Near(angular, pose.AngularVelocity);
            Near(position + forward * pose.ApproachDistance, pose.Position + pose.Forward * pose.ApproachDistance);
            pose.ReceivedAt = now;
            Assert.False(pose.IsWindow(rig.Program.Config, now));
        }

        [Theory]
        [InlineData(15)]
        [InlineData(100)]
        public void RestoredInboundOwnerReceivesANewGrantOnItsFreshRequestWithoutAStabilityWait(double distance)
        {
            var before = new FleetStateTests.Rig(1, false);
            Returning(before, distance: distance);
            before.Receive("DOCK_REQUEST", before.Miners[0]);
            var original = Grant(before, before.Miners[0].Id);
            var saved = before.Checkpoint();
            var after = new FleetStateTests.Rig(1, false, "[Dock]\nStableSeconds=30\n");
            after.Restore(saved);
            Returning(after, distance: distance);
            after.RegisterAll();
            Assert.DoesNotContain(after.Sent, p => p.Kind == "DOCK_GRANT");

            after.Receive("DOCK_REQUEST", after.Miners[0]);

            var renewed = Grant(after, after.Miners[0].Id);
            Assert.Equal(0, after.Program.Now);
            Assert.NotEqual(original.Token, renewed.Token);
            Assert.Equal(original.ConnectorId, renewed.ConnectorId);
            Assert.Equal(original.ApproachDistance, renewed.ApproachDistance);
        }

        [Fact]
        public void FirstRequestCannotClaimAConnectorThatIsPhysicallyOccupied()
        {
            var rig = new FleetStateTests.Rig(1, true);
            Returning(rig);
            rig.Miners[0].ConnectorId = 9999;
            rig.Receive("DOCK_REQUEST", rig.Miners[0]);
            Assert.Single(rig.Fleet.GetTelemetry());
            Assert.DoesNotContain(rig.Sent, p => p.Kind == "DOCK_GRANT");
            Assert.Equal(0, P.Data.ReadLong(rig.Save(), "fleet", "LaneCount"));
        }

        static void CloseCachedBerth(FleetStateTests.Rig rig,long connector)
        {
            var ports=(System.Collections.Generic.List<IMyShipConnector>)typeof(P.FleetController).GetField("docks",BindingFlags.NonPublic|BindingFlags.Instance).GetValue(rig.Fleet);
            var port=ports.Single(p=>p.EntityId==connector);
            ((Stub<IMyShipConnector>)RemotingServices.GetRealProxy(port)).Set("Closed",true).Set("IsFunctional",true);
            Assert.True(port.Closed);Assert.True(port.IsFunctional);
        }

        [Theory]
        [InlineData(false)]
        [InlineData(true)]
        public void RemovedCachedBerthCannotBlockTheRemainingFreeBerthBeforeHardwareRescan(bool restoredAssignment)
        {
            var rig=new FleetStateTests.Rig(2,false);Returning(rig);
            if(restoredAssignment)
            {
                rig.Receive("DOCK_REQUEST",rig.Miners[0]);Assert.Equal(100,Grant(rig,rig.Miners[0].Id).ConnectorId);
                var saved=rig.Checkpoint();rig=new FleetStateTests.Rig(2,false);rig.Restore(saved);Returning(rig);
            }
            CloseCachedBerth(rig,100);rig.Sent.Clear();

            rig.Receive("DOCK_REQUEST",rig.Miners[0]);

            Assert.Equal(0,rig.Program.Now);Assert.Equal(101,Grant(rig,rig.Miners[0].Id).ConnectorId);
            Assert.Equal(1,P.Data.ReadLong(rig.Save(),"fleet","LaneCount"));
        }

        [Fact]
        public void ARemovedBerthCannotRenewAStillNearbyRestoredAssignment()
        {
            var before=new FleetStateTests.Rig(2,false);Returning(before,distance:15);before.Receive("DOCK_REQUEST",before.Miners[0]);
            Assert.Equal(100,Grant(before,before.Miners[0].Id).ConnectorId);
            var after=new FleetStateTests.Rig(2,false);after.Restore(before.Checkpoint());Returning(after,distance:15);
            CloseCachedBerth(after,100);after.Receive("DOCK_REQUEST",after.Miners[0]);
            Assert.DoesNotContain(after.Sent,p=>p.Kind=="DOCK_GRANT");
            Assert.Empty(P.Data.Text(after.Save(),"fleet","LaneToken"));
            Assert.Equal(100,P.Data.ReadLong(after.Save(),"fleet","LaneDock"));
        }

        [Fact]
        public void AFirstRequestOverTheWireRegistersAndReceivesTheGrantInTheSameDrain()
        {
            var rig = new FleetStateTests.Rig(1, false);
            Returning(rig);
            var incoming = new System.Collections.Generic.Queue<MyIGCMessage>();
            var listener = (Stub<IMyUnicastListener>)RemotingServices.GetRealProxy(rig.Program.IGC.UnicastListener);
            listener.Method("get_HasPendingMessage", a => incoming.Count > 0).Method("AcceptMessage", a => incoming.Dequeue());
            var packet = new P.Packet { From = rig.Miners[0].Id, Target = "base", Kind = "DOCK_REQUEST", Session = "fresh-miner", Id = "fresh-miner-1", Seq = 1, Reliable = true, Body = rig.Miners[0].ToIni() };
            incoming.Enqueue(new MyIGCMessage(packet.Encode("mining"), "AMS2/mining", 5000));

            rig.Program.Bus.Drain(rig.Fleet.Receive);

            Assert.Empty(incoming);
            Assert.Equal(0, rig.Program.Now);
            Grant(rig, rig.Miners[0].Id);
            Assert.Equal(5000, Assert.Single(rig.Fleet.GetTelemetry()).Address);
        }

        [Fact]
        public void FirstRequestStillHonorsTheRegistryCapacityLimit()
        {
            var rig = new FleetStateTests.Rig(2, false, "[Fleet]\nMaxMiners=1\n");
            Returning(rig, 0); Returning(rig, 1);
            rig.Receive("DOCK_REQUEST", rig.Miners[0]);
            Grant(rig, rig.Miners[0].Id);
            rig.Receive("DOCK_REQUEST", rig.Miners[1]);
            Assert.Equal(rig.Miners[0].Id, Assert.Single(rig.Fleet.GetTelemetry()).Id);
            Assert.DoesNotContain(rig.Sent, p => p.Kind == "DOCK_GRANT" && p.Target == rig.Miners[1].Id);
            Assert.Equal(1, P.Data.ReadLong(rig.Save(), "fleet", "LaneCount"));
        }
    }
}