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

AutoMiningScript

【SpaceEngineer】全自动挖矿脚本

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

namespace AutoMiningScript.Tests
{
    public class ReturnStateTests
    {
        static readonly BindingFlags Private = BindingFlags.Instance | BindingFlags.NonPublic;
        static T Read<T>(object instance, string name) { return (T)instance.GetType().GetField(name, Private).GetValue(instance); }
        static void Write(object instance, string name, object value) { instance.GetType().GetField(name, Private).SetValue(instance, value); }
        static void Call(object instance, string name, params object[] args) { instance.GetType().GetMethod(name, Private).Invoke(instance, args); }
        static P.DockFrame Waiting(MinerStateTests.MinerRig r,bool granted=false)
        {
            r.PrepareDeparture("valid-lease"); r.Connector.Set("Status", MyShipConnectorStatus.Unconnected);
            Write(r.Miner, "laneKind", "dock"); if(!granted)Write(r.Miner,"lane",""); Write(r.Miner, "stableSince", -1d); r.State(P.FlightState.Holding);
            var dock = Read<P.DockFrame>(r.Miner, "dock"); dock.WaitingLocal = new Vector3D(0, 0, -80); return dock;
        }
        static void Step(MinerStateTests.MinerRig r, P.DockFrame dock, double seconds = .1)
        { r.Program.Now += seconds; dock.ReceivedAt = r.Program.Now; Call(r.Miner, "Waiting", seconds); }
        static MatrixD Desired(MinerStateTests.MinerRig r)
        { return Read<MatrixD>(Read<P.FlightController>(r.Miner, "flight"), "previousDesired"); }

        [Fact]
        public void WaitingKeepsTravelAndHoldingControlUntilTheGrantAllowsDirectApproach()
        {
            var r = new MinerStateTests.MinerRig(); var dock = Waiting(r);
            r.Position = new Vector3D(100, 0, -80);
            MatrixD orientation = MatrixD.Identity; Vector3D velocity = Vector3D.Zero;
            r.Controller.Method("get_WorldMatrix", a => orientation).Method("GetShipVelocities", a => new MyShipVelocities(velocity, Vector3D.Zero));
            Step(r, dock);
            Assert.True(Vector3D.Dot(Desired(r).Forward, Vector3D.Left) > .999);
            Assert.False(Read<bool>(r.Miner, "waitingAligning")); Assert.Equal(P.FlightState.Holding, r.StateNow);

            r.Position = dock.WaitingLocal + Vector3D.Right;
            orientation = MatrixD.CreateWorld(Vector3D.Zero, Vector3D.Left, Vector3D.Up);
            velocity = Vector3D.Left * .4;
            Step(r, dock); Assert.False(Read<bool>(r.Miner, "waitingAligning"));

            velocity = Vector3D.Zero;
            Step(r, dock); Assert.True(Read<bool>(r.Miner, "waitingAligning"));
            Assert.True(Vector3D.Dot(Desired(r).Forward, Vector3D.Forward) > .999);
            Assert.Equal(-1d, Read<double>(r.Miner, "stableSince")); Assert.Equal(P.FlightState.Holding, r.StateNow);

            orientation = MatrixD.Identity;
            Step(r, dock); Assert.Equal(P.FlightState.Holding,r.StateNow);
            Assert.Contains(P.L.MinerDockGrantMissing,Read<string>(r.Miner,"reason"));
            Write(r.Miner,"lane","valid-lease");Step(r,dock);
            Assert.Equal(P.FlightState.DockAlign, r.StateNow);
            Assert.Equal("valid-lease", Read<string>(r.Miner, "lane"));
        }

        [Fact]
        public void WaitingAlignmentLatchAvoidsAlternatingAttitudesButResetsAfterFourMetresDrift()
        {
            var r = new MinerStateTests.MinerRig(); var dock = Waiting(r); r.Position = dock.WaitingLocal;
            Step(r, dock); Assert.True(Read<bool>(r.Miner, "waitingAligning"));
            r.Position += Vector3D.Right * 3;
            Step(r, dock); Assert.True(Read<bool>(r.Miner, "waitingAligning"));
            Assert.True(Vector3D.Dot(Desired(r).Forward, Vector3D.Forward) > .999);
            r.Position += Vector3D.Right * 2;
            Step(r, dock); Assert.False(Read<bool>(r.Miner, "waitingAligning"));
            Assert.True(Vector3D.Dot(Desired(r).Forward, Vector3D.Left) > .999);
            Assert.Equal(-1d, Read<double>(r.Miner, "stableSince"));
        }

        [Fact]
        public void NearPortReturnPreservesCalibratedAttitudeInsteadOfTurningBesideMother()
        {
            var r = new MinerStateTests.MinerRig(); var dock = Waiting(r);
            r.Position = Vector3D.Right * 10; Step(r, dock);
            Assert.False(Read<bool>(r.Miner, "waitingAligning"));
            Assert.True(Vector3D.Dot(Desired(r).Forward, Vector3D.Forward) > .999);
            Assert.Equal(P.FlightState.Holding, r.StateNow);
        }

        [Theory]
        [InlineData(P.FlightState.Returning)]
        [InlineData(P.FlightState.Holding)]
        [InlineData(P.FlightState.DockAlign)]
        [InlineData(P.FlightState.DockApproach)]
        [InlineData(P.FlightState.DockRetreat)]
        public void RepeatedReturnKeepsNavigationProgressScanAndExistingLane(P.FlightState state)
        {
            var r = new MinerStateTests.MinerRig(); Waiting(r,true); r.State(state);
            Read<List<Vector3D>>(r.Miner, "breadcrumbs").AddRange(new[] { Vector3D.Zero, Vector3D.Right * 20, Vector3D.Right * 40 });
            Write(r.Miner, "returnIndex", 1); Write(r.Miner, "waitingAligning", true); Write(r.Miner, "stableSince", 2d);
            var flight = Read<P.FlightController>(r.Miner, "flight"); Write(flight, "scanIndex", 7); Write(flight, "scanning", true);
            double since = Read<double>(r.Miner, "stateSince");
            for (int n = 0; n < 3; n++) { r.Program.Now++; r.Miner.Command("return"); }
            Assert.Equal(state, r.StateNow); Assert.Equal(1, Read<int>(r.Miner, "returnIndex"));
            Assert.Equal(7, Read<int>(flight, "scanIndex")); Assert.True(Read<bool>(flight, "scanning"));
            Assert.True(Read<bool>(r.Miner, "waitingAligning")); Assert.Equal(2d, Read<double>(r.Miner, "stableSince"));
            Assert.Equal(since, Read<double>(r.Miner, "stateSince")); Assert.Equal("valid-lease", Read<string>(r.Miner, "lane"));
            Assert.DoesNotContain(r.Sent, p => p.Kind == "LANE_RELEASE");
        }

        [Fact]
        public void ReturnDuringDepartureFinishesStraightRetreatBeforeReleasingTheDepartureLane()
        {
            var r = new MinerStateTests.MinerRig(); r.PrepareDeparture("valid-lease");
            r.Connector.Set("Status", MyShipConnectorStatus.Unconnected); r.Position = Vector3D.Forward * 5; r.State(P.FlightState.Departing);
            var dock = Read<P.DockFrame>(r.Miner, "dock");
            r.Miner.Command("return");
            Assert.Equal(P.FlightState.DockRetreat, r.StateNow);
            Vector3D retreat = Read<Vector3D>(r.Miner, "abortPoint");
            Assert.True(Vector3D.Dot(retreat - r.Position, dock.Forward) >= 30);
            Assert.True(Vector3D.Cross(retreat - r.Position, dock.Forward).Length() < .00001);
            Assert.Equal("valid-lease", Read<string>(r.Miner, "lane"));
            r.Program.Now += .1; r.Miner.Command("return");
            Assert.Equal(retreat, Read<Vector3D>(r.Miner, "abortPoint"));
            Call(r.Miner, "DockRetreat", .1);
            Assert.True(Vector3D.Dot(Desired(r).Forward, Vector3D.Forward) > .999);
            Assert.DoesNotContain(r.Sent, p => p.Kind == "LANE_RELEASE");
            r.Position = retreat; Call(r.Miner, "DockRetreat", .1);
            Assert.Equal(P.FlightState.Holding, r.StateNow); Assert.Equal("", Read<string>(r.Miner, "lane"));
            Assert.Single(r.Sent, p => p.Kind == "LANE_RELEASE");
        }
    }
}