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

namespace AutoMiningScript.Tests
{
    public class DepartureMassTests
    {
        sealed class Rig
        {
            public readonly P Program;
            public readonly P.ShipHardware Hardware;
            public readonly P.Resources Resources;
            public readonly P.FlightController Flight;
            public readonly Stub<IMyCubeGrid> Grid;
            public readonly Stub<IMyShipConnector> Connector;
            public readonly Stub<IMyGridProgramRuntimeInfo> Runtime;
            public readonly Stub<IMyGridProgramWorldInfo> World;
            public readonly Stub<IMySlimBlock> Body, Armour;
            public readonly Stub<IMyInventory> Cargo, Drill;
            public int Cells, PhysicsReads;
            public Rig(string departure = "0")
            {
                Program = TestRig.Program("[Flight]\nDepartureMass=" + departure);
                Grid = new Stub<IMyCubeGrid>().Set("EntityId", 10L).Set("Min", Vector3I.Zero).Set("Max", new Vector3I(2, 0, 0));
                TestRig.SetBase(Program, "Me", new Stub<IMyProgrammableBlock>().Set("CubeGrid", Grid.Value).Value);
                Runtime = new Stub<IMyGridProgramRuntimeInfo>().Set("MaxInstructionCount", 50000).Set("CurrentInstructionCount", 0);
                TestRig.SetBase(Program, "Runtime", Runtime.Value);
                World = new Stub<IMyGridProgramWorldInfo>().Set("InventoryMultiplier", 1f);
                TestRig.SetBase(Program, "World", World.Value);
                Body = new Stub<IMySlimBlock>().Set("CubeGrid", Grid.Value).Set("Position", Vector3I.Zero).Set("Mass", 1000f);
                Armour = new Stub<IMySlimBlock>().Set("CubeGrid", Grid.Value).Set("Position", new Vector3I(2, 0, 0)).Set("Mass", 200f);
                Grid.Method("GetCubeBlock", args => { Cells++; return ((Vector3I)args[0]).X == 2 ? Armour.Value : Body.Value; });
                Hardware = new P.ShipHardware(Program);
                Connector = TestRig.Connector(Program, true);
                Hardware.Connector = Connector.Value;
                ((List<IMyShipConnector>)typeof(P.ShipHardware).GetField("connectors", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(Hardware)).Add(Connector.Value);
                Hardware.Controller = new Stub<IMyShipController>().Set("CubeGrid", Grid.Value).Set("WorldMatrix", MatrixD.Identity)
                    .Method("CalculateShipMass", args => { PhysicsReads++; return new MyShipMass(3000, 9000000, 9000000); }).Value;
                foreach (Vector3D direction in new[] { Vector3D.Right, Vector3D.Left, Vector3D.Up, Vector3D.Down, Vector3D.Forward, Vector3D.Backward })
                {
                    var basis = MatrixD.CreateWorld(Vector3D.Zero, -direction, Math.Abs(direction.Y) > .9 ? Vector3D.Forward : Vector3D.Up);
                    Hardware.Thrusters.Add(new Stub<IMyThrust>().Set("CubeGrid", Grid.Value).Set("Enabled", true).Set("IsFunctional", true)
                        .Set("MaxEffectiveThrust", 10000000f).Set("WorldMatrix", basis).Value);
                }
                Cargo = Inventory(100); Drill = Inventory(200);
                AddInventory(Cargo, Grid.Value); AddInventory(Drill, Grid.Value);
                Resources = new P.Resources(Program, Hardware); Flight = new P.FlightController(Program, Hardware);
            }
            public static Stub<IMyInventory> Inventory(double mass)
            { return new Stub<IMyInventory>().Set("CurrentMass", (MyFixedPoint)mass).Set("MaxVolume", (MyFixedPoint)100); }
            public void AddInventory(Stub<IMyInventory> inventory, IMyCubeGrid grid)
            {
                Hardware.InventoryBlocks.Add(new Stub<IMyTerminalBlock>().Set("CubeGrid", grid).Set("HasInventory", true).Set("InventoryCount", 1)
                    .Method("GetInventory", args => inventory.Value).Value);
            }
            public void InventoryScan() { Resources.Update(.5, P.FlightState.Servicing, 0, 0); }
            public void Measure() { InventoryScan(); Hardware.UpdateDepartureMass(); }
            public bool Supports() { return Flight.CanSupport(Vector3D.Forward, Vector3D.Up, .3); }
            public double ControlMass { get { return (double)typeof(P.FlightController).GetField("mass", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(Flight); } }
        }

        [Fact] public void DockedMeasurementIncludesArmourCountsMulticellBlocksOnceAndExcludesMother()
        {
            var r = new Rig(); r.AddInventory(Rig.Inventory(9000000), new Stub<IMyCubeGrid>().Value);
            r.Measure(); Assert.Equal(1500, r.Hardware.AutoDepartureMass); Assert.True(r.Supports());
            Assert.Equal(1500, r.ControlMass); Assert.Equal(0, r.PhysicsReads);
            Assert.Equal(MyShipConnectorStatus.Connected, r.Connector.Value.Status);
        }
        [Fact] public void EachCompleteInventorySnapshotChangesMeasuredMassWithoutUsingOldFlightMass()
        {
            var r = new Rig(); r.Flight.LastFlightMass = 9000000; r.Measure();
            r.Cargo.Set("CurrentMass", (MyFixedPoint)700); r.Program.Now = .5; r.InventoryScan();
            Assert.Equal(2100, r.Hardware.AutoDepartureMass); Assert.True(r.Supports()); Assert.Equal(2100, r.ControlMass);
            r.Drill.Set("CurrentMass", (MyFixedPoint)0); r.Cargo.Set("CurrentMass", (MyFixedPoint)0); r.InventoryScan();
            Assert.Equal(1200, r.Hardware.AutoDepartureMass);
        }
        [Fact] public void WorldInventoryMultiplierConvertsCargoToPhysicalMass()
        {
            var r = new Rig(); r.World.Set("InventoryMultiplier", 10f); r.Measure();
            Assert.Equal(1230, r.Hardware.AutoDepartureMass); Assert.True(r.Supports()); Assert.Equal(1230, r.ControlMass);
        }
        [Fact] public void PositiveSettingRemainsAnExplicitDepartureOverride()
        {
            var r = new Rig("5000"); r.Body.Set("Mass", float.NaN); r.Measure();
            Assert.True(r.Supports()); Assert.Equal(5000, r.ControlMass); Assert.Equal(0, r.Cells); Assert.Equal(0, r.PhysicsReads);
        }
        [Theory]
        [InlineData("NaN")][InlineData("Infinity")][InlineData("-1")][InlineData("10000000001")]
        public void InvalidConfiguredMassIsRejected(string value)
        { var r = new Rig(value); Assert.Throws<ArgumentException>(() => r.Hardware.UpdateDepartureMass()); }
        [Fact] public void GridMeasurementIsBoundedAndNeverExposesPartialMass()
        {
            var r = new Rig(); r.Grid.Set("Max", new Vector3I(256, 0, 0)); r.Measure();
            Assert.Equal(128, r.Cells); Assert.Equal(0, r.Hardware.AutoDepartureMass); Assert.False(r.Supports());
            r.Hardware.UpdateDepartureMass(); Assert.Equal(256, r.Cells); Assert.Equal(0, r.Hardware.AutoDepartureMass);
            r.Hardware.UpdateDepartureMass(); Assert.Equal(257, r.Cells); Assert.Equal(1500, r.Hardware.AutoDepartureMass);
        }
        [Fact] public void HighInstructionUseDefersMassScanUntilTheNextInvocation()
        {
            var r = new Rig(); r.Runtime.Set("CurrentInstructionCount", 23000); r.Measure();
            Assert.Equal(0, r.Cells); Assert.False(r.Supports());
            r.Runtime.Set("CurrentInstructionCount", 0); r.Hardware.UpdateDepartureMass();
            Assert.Equal(1500, r.Hardware.AutoDepartureMass); Assert.True(r.Supports());
        }
        [Fact] public void StaleOrInvalidInventorySnapshotCannotAuthorizeDeparture()
        {
            var r = new Rig(); r.Measure(); r.Program.Now = 1;
            Assert.Equal(0, r.Hardware.AutoDepartureMass); Assert.False(r.Supports());
            Assert.Equal(P.L.MinerAutoMassInventoryPending, r.Flight.Problem);
            r.InventoryScan(); Assert.True(r.Supports());
            r.Cargo.Set("CurrentMass", (MyFixedPoint)(-1)); r.InventoryScan(); Assert.False(r.Supports());
        }
        [Theory][InlineData(float.NaN)][InlineData(float.PositiveInfinity)][InlineData(-1f)]
        public void InvalidBlockMassStaysDocked(float value)
        {
            var r = new Rig(); r.Body.Set("Mass", value); r.Measure();
            Assert.False(r.Supports()); Assert.Equal(P.L.MinerAutoMassInvalid, r.Flight.Problem);
            Assert.Equal(MyShipConnectorStatus.Connected, r.Connector.Value.Status);
        }
        [Theory][InlineData(float.NaN)][InlineData(0f)][InlineData(-1f)]
        public void InvalidWorldMultiplierCannotYieldAValidMeasurement(float value)
        { var r = new Rig(); r.World.Set("InventoryMultiplier", value); r.Measure(); Assert.False(r.Supports()); }
        [Fact] public void OversizedGridIsRejectedWithoutAnUnboundedScan()
        {
            var r = new Rig(); r.Grid.Set("Max", new Vector3I(1000000, 0, 0)); r.Measure();
            Assert.Equal(0, r.Cells); Assert.False(r.Supports()); Assert.Equal(P.L.MinerAutoMassGridTooLarge, r.Flight.Problem);
        }
        [Fact] public void RescanAndRedockingRequireFreshGeometry()
        {
            var r = new Rig(); r.Measure(); r.Hardware.InvalidateDepartureMass(); Assert.Equal(0, r.Hardware.AutoDepartureMass);
            r.Body.Set("Mass", 2000f); r.Hardware.UpdateDepartureMass(); Assert.Equal(2500, r.Hardware.AutoDepartureMass);
            r.Connector.Set("Status", MyShipConnectorStatus.Unconnected); r.Hardware.UpdateDepartureMass(); Assert.Equal(0, r.Hardware.AutoDepartureMass);
            r.Connector.Set("Status", MyShipConnectorStatus.Connected); r.Body.Set("Mass", 3000f); r.Hardware.UpdateDepartureMass();
            Assert.Equal(3500, r.Hardware.AutoDepartureMass);
        }
        [Fact] public void GeometryIsRecheckedAfterFiveSecondsEvenWhenBoundsAreUnchanged()
        {
            var r = new Rig(); r.Measure(); r.Program.Now = 6; r.Body.Set("Mass", 2000f); r.Measure();
            Assert.Equal(2500, r.Hardware.AutoDepartureMass); Assert.Equal(6, r.Cells);
        }
        [Fact] public void FreeFlightUsesLivePhysicsInsteadOfTheDepartureOverride()
        {
            var r = new Rig("5000"); r.Measure(); r.Connector.Set("Status", MyShipConnectorStatus.Unconnected);
            Assert.True(r.Supports()); Assert.Equal(9000000, r.ControlMass); Assert.Equal(1, r.PhysicsReads);
        }
        static MyInventoryItem Ore(double amount)
        {
            object item = default(MyInventoryItem);
            typeof(MyInventoryItem).GetField("Type").SetValue(item, MyItemType.MakeOre("Iron"));
            typeof(MyInventoryItem).GetField("Amount").SetValue(item, (MyFixedPoint)amount);
            return (MyInventoryItem)item;
        }
        [Fact] public void InventoryLimitPreservesLastCompleteSampleAndClearsDeparturePermission()
        {
            var r = new Rig(); double amount = 10;
            r.Cargo.Method("GetItems", args => { ((List<MyInventoryItem>)args[0]).Add(Ore(amount)); return null; });
            r.Measure(); Assert.Equal(10, r.Resources.Ores["Iron"]); r.Resources.Empty = true;
            amount = 999; r.Drill.Set("ItemCount", 513);
            r.InventoryScan();
            Assert.Equal(P.L.MinerInventoryScanLimit, r.Resources.ScanProblem); Assert.Equal(10, r.Resources.Ores["Iron"]);
            Assert.Equal(10, r.Resources.OreAmount); Assert.False(r.Resources.Empty); Assert.False(r.Resources.SamplingValid);
            Assert.Equal(0, r.Hardware.AutoDepartureMass); Assert.False(r.Supports());
        }
        [Fact] public void InventoryCountLimitCannotRetainAnEmptyPermit()
        {
            var r = new Rig(); r.Measure(); r.InventoryScan(); Assert.True(r.Resources.Empty);
            for (int i = 0; i < 127; i++) r.AddInventory(Rig.Inventory(0), r.Grid.Value);
            r.InventoryScan(); Assert.Equal(P.L.MinerInventoryScanLimit, r.Resources.ScanProblem); Assert.False(r.Resources.Empty);
            Assert.False(r.Supports());
        }
        [Fact] public void OverflowLatchedUntilRescanDoesNotKeepThrowingOrDisableReturnChecks()
        {
            var r = new Rig(); r.Measure(); r.Drill.Set("ItemCount", 513); r.InventoryScan();
            string reason; Assert.True(r.Resources.MustReturn(out reason)); Assert.Equal(P.L.MinerInventoryScanLimit, reason);
            Assert.False(r.Resources.ReadyForSortie(0, 0, out reason));
            r.Drill.Set("ItemCount", 0); r.InventoryScan(); Assert.Equal(P.L.MinerInventoryScanLimit, r.Resources.ScanProblem);
            r.Resources.ResetInventoryScan(); r.InventoryScan(); Assert.Equal("", r.Resources.ScanProblem); Assert.False(r.Resources.Empty);
            r.InventoryScan(); Assert.True(r.Resources.Empty); Assert.Equal(1500, r.Hardware.AutoDepartureMass);
        }
    }
}