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

AutoMiningScript

【SpaceEngineer】全自动挖矿脚本

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

namespace AutoMiningScript.Tests
{
    public class ProtocolTests
    {
        static P.Packet Message()
        {
            var body = new MyIni();
            body.Set("job", "Id", "base-hole-1");
            body.Set("job", "Entry", "0,0,0");
            body.Set("job", "Note", "第一行\n[not an outer section]\nkey=value; retained");
            return new P.Packet { Kind = "JOB", From = "base", Target = "miner-01", Id = "session-5", Session = "session", Seq = 5, Reliable = true, Source = 123, Body = body };
        }

        [Fact]
        public void WaitingSlotRoundTripsAndLegacyTelemetryRequestsAnUnassignedSlot()
        {
            var body=new P.Telemetry {WaitingSlot=23}.ToIni();Assert.Equal(23,P.Telemetry.FromIni(body).WaitingSlot);
            body.Delete("telemetry","WaitingSlot");Assert.Equal(-1,P.Telemetry.FromIni(body).WaitingSlot);
            body.Set("telemetry","WaitingSlot",1000001);Assert.Throws<ArgumentException>(()=>P.Telemetry.FromIni(body));
        }

        [Fact]
        public void CancellationWatermarkRoundTripsWithoutAcknowledgingLegacyTelemetry()
        {
            var telemetry=new P.Telemetry {CancelledThrough=100};var body=telemetry.ToIni();
            Assert.Equal(100,P.Telemetry.FromIni(body).CancelledThrough);
            body.Delete("telemetry","CancelledThrough");Assert.Equal(-1,P.Telemetry.FromIni(body).CancelledThrough);
            body.Set("telemetry","CancelledThrough",-2);Assert.Throws<ArgumentException>(()=>P.Telemetry.FromIni(body));
        }

        [Fact]
        public void PacketRoundTripKeepsAtomicMultilinePayloadAndRouting()
        {
            var input = Message(); P.Packet output;
            Assert.True(P.Packet.TryDecode(input.Encode("mine-a"), "mine-a", out output));
            Assert.Equal(input.Kind, output.Kind); Assert.Equal(input.From, output.From);
            Assert.Equal(input.Target, output.Target); Assert.Equal(input.Id, output.Id);
            Assert.Equal(input.Session, output.Session); Assert.Equal(5, output.Seq);
            Assert.True(output.Reliable);
            Assert.Equal(input.Body.Get("job", "Note").ToString(), output.Body.Get("job", "Note").ToString());
            Assert.Equal("0,0,0", output.Body.Get("job", "Entry").ToString());
            // Transport identity comes from IGC, never from a sender-supplied payload.
            Assert.Equal(0, output.Source);
        }

        [Fact]
        public void PacketRejectsOtherFleetAndOtherProtocolVersion()
        {
            P.Packet parsed; string encoded = Message().Encode("mine-a");
            Assert.False(P.Packet.TryDecode(encoded, "mine-b", out parsed));
            var ini = new MyIni(); Assert.True(ini.TryParse(encoded)); ini.Set("wire", "Version", 1);
            Assert.False(P.Packet.TryDecode(ini.ToString(), "mine-a", out parsed));
        }

        [Theory]
        [InlineData("From", "")]
        [InlineData("Kind", "")]
        [InlineData("Session", "")]
        [InlineData("Seq", "0")]
        [InlineData("Seq", "-1")]
        [InlineData("Seq", "NaN")]
        [InlineData("Version", "Infinity")]
        [InlineData("Payload", "[broken")]
        public void PacketRejectsInvalidEnvelope(string field, string value)
        {
            var ini = new MyIni(); Assert.True(ini.TryParse(Message().Encode("mine-a")));
            ini.Set("wire", field, value); P.Packet parsed;
            Assert.False(P.Packet.TryDecode(ini.ToString(), "mine-a", out parsed));
            Assert.Null(parsed);
        }

        [Fact]
        public void PacketRejectsOversizeMalformedAndOverlongIdentities()
        {
            P.Packet parsed;
            Assert.False(P.Packet.TryDecode(null, "mine-a", out parsed));
            Assert.False(P.Packet.TryDecode(new string('x', 24001), "mine-a", out parsed));
            Assert.False(P.Packet.TryDecode("[broken", "mine-a", out parsed));
            var input = Message(); input.From = new string('a', 65);
            Assert.False(P.Packet.TryDecode(input.Encode("mine-a"), "mine-a", out parsed));
            input = Message(); input.Kind = new string('x', 33);
            Assert.False(P.Packet.TryDecode(input.Encode("mine-a"), "mine-a", out parsed));
            input = Message(); input.Id = new string('x', 161);
            Assert.False(P.Packet.TryDecode(input.Encode("mine-a"), "mine-a", out parsed));
        }

        [Theory]
        [InlineData("NaN")]
        [InlineData("Infinity")]
        [InlineData("-Infinity")]
        [InlineData("1e309")]
        public void SettingsAndVectorsRejectNonFiniteNumbers(string value)
        {
            var config = new P.Settings("[Flight]\nCruiseSpeed=" + value, "miner", "miner-1");
            var exception = Assert.Throws<ArgumentException>(() => config.Number("Flight", "CruiseSpeed", 15, .5, 95));
            Assert.Contains(P.Settings.SectionName("Flight")+"."+P.Settings.ParameterName("CruiseSpeed"), exception.Message);
            Vector3D vector; Assert.False(P.Data.TryVector("1," + value + ",3", out vector));
        }

        [Fact]
        public void ZeroWorldCoordinatesAndGpsAreValid()
        {
            Vector3D vector;
            Assert.True(P.Data.TryVector("0,0,0", out vector)); Assert.Equal(Vector3D.Zero, vector);
            Assert.True(P.Data.TryGps("GPS:origin:0:0:0:", out vector)); Assert.Equal(Vector3D.Zero, vector);
            Assert.False(P.Data.TryGps("GPS:bad:0:NaN:0:", out vector));
            Assert.False(P.Data.TryVector("0,0", out vector));
        }

        [Fact]
        public void SerializationIsInvariantUnderCommaDecimalCulture()
        {
            var previous = Thread.CurrentThread.CurrentCulture;
            try
            {
                Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("fr-FR");
                Assert.Equal("1.25,-2.5,0", P.Data.Vector(new Vector3D(1.25, -2.5, 0)));
                Vector3D parsed; Assert.True(P.Data.TryVector("1.25,-2.5,0", out parsed));
                Assert.Equal(1.25, parsed.X, 12); Assert.Equal(-2.5, parsed.Y, 12);
                var job = new P.Job { Id = "job-1", Entry = parsed, Direction = Vector3D.Forward, Up = Vector3D.Up, Depth = 12.75, Progress = 2.5 };
                var restored = P.Job.FromIni(job.ToIni());
                Assert.Equal(job.Entry, restored.Entry); Assert.Equal(12.75, restored.Depth, 12);
                var config = new P.Settings("[Flight]\nCruiseSpeed=1.25", "miner", "miner-1");
                Assert.Equal(1.25, config.Number("Flight", "CruiseSpeed", 15, .5, 95), 12);
            }
            finally { Thread.CurrentThread.CurrentCulture = previous; }
        }

        [Fact]
        public void SettingsReportTheExactInvalidFieldAndPreserveInput()
        {
            string source = "[Flight]\nCruiseSpeed=96\n[Watchdog]\nEnabled=yes\n[Fleet]\nMaxMiners=17";
            var config = new P.Settings(source, "miner", "miner-1");
            Assert.Contains(P.Settings.SectionName("Flight")+"."+P.Settings.ParameterName("CruiseSpeed"), Assert.Throws<ArgumentException>(() => config.Number("Flight", "CruiseSpeed", 15, .5, 95)).Message);
            Assert.Contains(P.Settings.SectionName("Watchdog")+"."+P.Settings.ParameterName("Enabled"), Assert.Throws<ArgumentException>(() => config.Flag("Watchdog", "Enabled", false)).Message);
            Assert.Contains(P.Settings.SectionName("Fleet")+"."+P.Settings.ParameterName("MaxMiners"), Assert.Throws<ArgumentException>(() => config.Integer("Fleet", "MaxMiners", 16, 1, 16)).Message);
            Assert.Equal("96", config.Text("Flight", "CruiseSpeed", "fallback"));
            Assert.Equal(15, config.Number("Missing", "Speed", 15, 1, 95));
            Assert.False(config.Flag("Missing", "Enabled", false));
        }

        [Fact]
        public void SettingsIgnoreLegacyRoleButRejectMalformedIniAndInvalidIdentity()
        {
            Assert.Equal("miner", new P.Settings("[System]\nRole=fleet", "miner", "miner-1").Role);
            Assert.Throws<ArgumentException>(() => new P.Settings("[broken", "miner", "miner-1"));
            Assert.Throws<ArgumentException>(() => new P.Settings("[System]\nId=", "miner", "miner-1"));
            Assert.Throws<ArgumentException>(() => new P.Settings("[System]\nFleetId=" + new string('a', 65), "miner", "miner-1"));
        }

        [Fact]
        public void DockPointVelocityIncludesRotationAroundCenterOfMass()
        {
            var dock = new P.DockFrame { Center = new Vector3D(10, 20, 30), Position = new Vector3D(12, 20, 30), Velocity = new Vector3D(1, 2, 3), AngularVelocity = new Vector3D(0, 0, .5) };
            Assert.Equal(new Vector3D(1, 3, 3), dock.PointVelocity(dock.Position));
            Assert.Equal(dock.Velocity, dock.PointVelocity(dock.Center));
        }

        [Fact]
        public void DockWindowRejectsStaleFastRotatingAndAcceleratingBases()
        {
            var config = new P.Settings("", "miner", "miner-1");
            var dock = new P.DockFrame { ReceivedAt = 10, Forward = Vector3D.Forward, Up = Vector3D.Up };
            Assert.True(dock.IsWindow(config, 10.5)); Assert.False(dock.IsWindow(config, 10.5001));
            dock.Velocity = new Vector3D(5.01, 0, 0); Assert.False(dock.IsWindow(config, 10));
            dock.Velocity = Vector3D.Zero; dock.AngularVelocity = new Vector3D(0, .21 * Math.PI / 180, 0); Assert.False(dock.IsWindow(config, 10));
            dock.AngularVelocity = Vector3D.Zero; dock.Acceleration = new Vector3D(.1001, 0, 0); Assert.False(dock.IsWindow(config, 10));
        }

        [Fact]
        public void DockWindowUsesConnectorSpeedInsteadOfCenterSpeed()
        {
            var config = new P.Settings("", "miner", "miner-1");
            var dock = new P.DockFrame { ReceivedAt = 10, Position = new Vector3D(2000, 0, 0), AngularVelocity = new Vector3D(0, 0, .003) };
            Assert.True(dock.AngularVelocity.Length() < .2 * Math.PI / 180);
            Assert.Equal(6, dock.PointVelocity(dock.Position).Length(), 10);
            Assert.False(dock.IsWindow(config, 10));
        }

        [Fact]
        public void DockPredictionClampsHorizonAndRotatesTheConnectorOffset()
        {
            var dock = new P.DockFrame { Center = new Vector3D(100, 200, 300), Position = new Vector3D(110, 200, 300), Velocity = new Vector3D(2, 0, 0), AngularVelocity = new Vector3D(0, 0, 1), ReceivedAt = 10 };
            Assert.Equal(dock.Position, dock.Predicted(9).Translation);
            var expected = dock.Center + new Vector3D(1, 0, 0) + new Vector3D(10 * Math.Cos(.5), 10 * Math.Sin(.5), 0);
            Assert.True(Vector3D.Distance(expected, dock.Predicted(1000).Translation) < 1e-9);
            Assert.Equal(dock.Predicted(10.5).Translation, dock.Predicted(1000).Translation);
            var frame = dock.Predicted(10.25);
            Assert.Equal(1, frame.Forward.Length(), 10); Assert.Equal(1, frame.Up.Length(), 10);
            Assert.True(Math.Abs(Vector3D.Dot(frame.Forward, frame.Up)) < 1e-10);
            Assert.True(Vector3D.Distance(frame.Translation + frame.Forward * 30, dock.GetPoint(30, 10.25)) < 1e-9);
        }

        [Fact]
        public void DockRoundTripPreservesGeometryButDoesNotTrustArrivalTimeOrSource()
        {
            var original = new P.DockFrame { BaseId = "base", Token = "lease-1", Owner = "miner-1", ConnectorId = 42, GridId = 7, Position = new Vector3D(1, 2, 3), Center = Vector3D.Zero, Velocity = new Vector3D(3, 2, 1), AngularVelocity = new Vector3D(0, .1, 0), ReceivedAt = 1234, Source = 9876, Connected = true };
            var restored = P.DockFrame.FromIni(original.ToIni());
            Assert.Equal(original.Position, restored.Position); Assert.Equal(original.Velocity, restored.Velocity);
            Assert.Equal(original.GridId, restored.GridId); Assert.Equal(original.ConnectorId, restored.ConnectorId);
            Assert.Equal(original.Owner, restored.Owner); Assert.Equal(original.Token, restored.Token); Assert.True(restored.Connected);
            Assert.Equal(0, restored.ReceivedAt); Assert.Equal(0, restored.Source);
        }
    }
}