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

AutoMiningScript

【SpaceEngineer】全自动挖矿脚本

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

namespace AutoMiningScript.Tests
{
    public class RuntimeBudgetTests
    {
        sealed class Rig
        {
            public readonly P Program = TestRig.Program();
            public readonly Stub<IMyGridProgramRuntimeInfo> Runtime = new Stub<IMyGridProgramRuntimeInfo>();
            public readonly Queue<MyIGCMessage> Incoming = new Queue<MyIGCMessage>();
            public readonly List<P.Packet> Sent = new List<P.Packet>();
            public Rig()
            {
                Runtime.Set("MaxInstructionCount", 50000).Set("CurrentInstructionCount", 0).Set("TimeSinceLastRun", TimeSpan.FromSeconds(1.0 / 60));
                TestRig.SetBase(Program, "Runtime", Runtime.Value);
                var broadcast = new Stub<IMyBroadcastListener>();
                var unicast = new Stub<IMyUnicastListener>().Method("get_HasPendingMessage", a => Incoming.Count > 0)
                    .Method("AcceptMessage", a => Incoming.Dequeue());
                var igc = new Stub<IMyIntergridCommunicationSystem>().Set("UnicastListener", unicast.Value)
                    .Method("RegisterBroadcastListener", a => broadcast.Value)
                    .Method("SendBroadcastMessage", a => Capture(a[1] as string))
                    .Method("SendUnicastMessage", a => { Capture(a[2] as string); return true; });
                TestRig.SetBase(Program, "IGC", igc.Value); Program.Bus = new P.Wire(Program);
            }
            object Capture(string value) { P.Packet packet; Assert.True(P.Packet.TryDecode(value, "mining", out packet)); Sent.Add(packet); return null; }
            public void Add(string session, long seq, string kind = "TELEMETRY",string peer="peer",long address=123)
            {
                var packet = new P.Packet { From = peer, Session = session, Seq = seq, Kind = kind, Id = session + seq, Body = new MyIni() };
                Incoming.Enqueue(new MyIGCMessage(packet.Encode("mining"), "AMS2/mining", address));
            }
        }
        sealed class BusyRole : P.RoleLogic
        {
            readonly Rig rig;
            public bool Busy = true;
            public int Ticks, Received;
            public readonly List<P.Job> Jobs = new List<P.Job> { new P.Job { Id = "active", Owner = "miner-1", Progress = 12 } };
            public BusyRole(Rig r) : base(r.Program) { rig = r; }
            public override void Tick(double dt) { Ticks++; if (Busy) rig.Runtime.Set("CurrentInstructionCount", 34000); }
            public override void Receive(P.Packet packet) { Received++; }
            public override List<P.Job> GetJobs() { return Jobs; }
        }
        static void Set(P p, string name, object value) { typeof(P).GetField(name, BindingFlags.Instance | BindingFlags.NonPublic).SetValue(p, value); }

        [Fact]
        public void BusyFrameDefersBackgroundWithoutErasingActiveProgressAndNextFrameContinues()
        {
            var rig = new Rig(); var role = new BusyRole(rig);
            Set(rig.Program, "role", role); Set(rig.Program, "dashboard", new P.Dashboard(rig.Program));
            Set(rig.Program, "nextDraw", double.MaxValue); Set(rig.Program, "nextSave", double.MaxValue);
            rig.Add("session", 1); rig.Program.Main("", UpdateType.Update1);
            Assert.Equal(1, role.Ticks); Assert.Equal(0, role.Received); Assert.Single(rig.Incoming);
            Assert.Equal(1, rig.Program.BudgetDeferrals); Assert.Equal(12, role.Jobs[0].Progress); Assert.Equal("miner-1", role.Jobs[0].Owner);
            role.Busy = false; rig.Runtime.Set("CurrentInstructionCount", 0);
            rig.Program.Main("", UpdateType.Update1);
            Assert.Equal(2, role.Ticks); Assert.Equal(1, role.Received); Assert.Empty(rig.Incoming);
        }

        [Fact]
        public void IncomingBurstIsBoundedAndUnprocessedPacketsStayQueued()
        {
            var rig = new Rig(); for (int n = 1; n <= 10; n++) rig.Add("session", n);
            int received = 0; rig.Program.Bus.Drain(p => received++);
            Assert.Equal(4, received); Assert.Equal(6, rig.Incoming.Count);
            rig.Runtime.Set("CurrentInstructionCount", 28000); rig.Program.Bus.Drain(p => received++);
            Assert.Equal(4, received); Assert.Equal(6, rig.Incoming.Count);
            rig.Runtime.Set("CurrentInstructionCount", 0); rig.Program.Bus.Drain(p => received++); rig.Program.Bus.Drain(p => received++);
            Assert.Equal(10, received); Assert.Empty(rig.Incoming);
        }

        [Fact]
        public void ReceiverCostStopsFurtherProcessingInTheSameFrame()
        {
            var rig = new Rig(); rig.Add("s", 1); rig.Add("s", 2);
            int received = 0; rig.Program.Bus.Drain(p => { received++; rig.Runtime.Set("CurrentInstructionCount", 28000); });
            Assert.Equal(1, received); Assert.Single(rig.Incoming);
        }

        [Fact]
        public void RetriesAreLimitedPerFrameWithoutDroppingPendingMessages()
        {
            var rig = new Rig(); for (int n = 0; n < 8; n++) rig.Program.Bus.Send("JOB", "peer", new MyIni(), true, 123);
            rig.Sent.Clear(); rig.Program.Now = 2;
            rig.Program.Bus.Tick(); Assert.Equal(2, rig.Sent.Count); Assert.Equal(8, rig.Program.Bus.PendingCount);
            rig.Program.Bus.Tick(); rig.Program.Bus.Tick(); rig.Program.Bus.Tick();
            Assert.Equal(8, rig.Sent.Count); Assert.Equal(8, rig.Program.Bus.PendingCount);
        }

        [Fact]
        public void ForgettingPeerStopsRetriesAndDuplicatesButPermitsFreshReconnection()
        {
            var rig=new Rig();int received=0;rig.Add("old",1,"HELLO");rig.Program.Bus.Drain(p=>received++);
            rig.Program.Bus.Send("JOB","peer",new MyIni(),true);rig.Program.Bus.Send("COMMAND","peer",new MyIni(),true);
            rig.Program.Bus.ForgetPeer("peer");Assert.Equal(0,rig.Program.Bus.PendingCount);
            var peers=(IDictionary)typeof(P.Wire).GetField("peers",BindingFlags.Instance|BindingFlags.NonPublic).GetValue(rig.Program.Bus);
            Assert.Empty(peers);rig.Add("old",1,"HELLO");rig.Program.Bus.Drain(p=>received++);Assert.Equal(1,received);Assert.Empty(peers);
            rig.Add("old",2,"HELLO");rig.Program.Bus.Drain(p=>received++);Assert.Equal(2,received);Assert.Single(peers);
            rig.Program.Bus.ForgetPeer("peer");rig.Add("replacement",1,"HELLO","peer",456);rig.Program.Bus.Drain(p=>received++);Assert.Equal(3,received);
            Assert.Equal(456L,peers["peer"]);
        }

        [Fact]
        public void DelayedAckCannotRecreateAForgottenAddressBinding()
        {
            var rig=new Rig();int received=0;rig.Add("original",1,"HELLO");rig.Program.Bus.Drain(p=>received++);
            rig.Program.Bus.ForgetPeer("peer");rig.Add("original",2,"ACK");rig.Program.Bus.Drain(p=>received++);
            var peers=(IDictionary)typeof(P.Wire).GetField("peers",BindingFlags.Instance|BindingFlags.NonPublic).GetValue(rig.Program.Bus);
            Assert.Empty(peers);rig.Add("replacement",1,"HELLO","peer",456);rig.Program.Bus.Drain(p=>received++);Assert.Equal(2,received);
        }

        [Fact]
        public void AckRequiresTheExpectedAddressAndDoesNotRegisterAPeer()
        {
            var rig=new Rig();rig.Program.Bus.Send("COMMAND","peer",new MyIni(),true,123);P.Packet sent=rig.Sent[0];
            var body=new MyIni();body.Set("ack","Id",sent.Id);var ack=new P.Packet {From="peer",Session="s",Seq=1,Kind="ACK",Body=body};
            rig.Incoming.Enqueue(new MyIGCMessage(ack.Encode("mining"),"AMS2/mining",456));rig.Program.Bus.Drain(p=>{});Assert.Equal(1,rig.Program.Bus.PendingCount);
            rig.Incoming.Enqueue(new MyIGCMessage(ack.Encode("mining"),"AMS2/mining",123));rig.Program.Bus.Drain(p=>{});Assert.Equal(0,rig.Program.Bus.PendingCount);
            var peers=(IDictionary)typeof(P.Wire).GetField("peers",BindingFlags.Instance|BindingFlags.NonPublic).GetValue(rig.Program.Bus);
            Assert.Empty(peers);
        }

        [Fact]
        public void RepeatedCleanupReleasesPeerLimitAndBoundsRetainedReplayStreams()
        {
            var rig=new Rig();int received=0;
            for(int n=0;n<300;n++)
            {
                string name="renamed-"+n;rig.Add("session",1,"HELLO",name);rig.Program.Bus.Drain(p=>received++);rig.Program.Bus.ForgetPeer(name);
            }
            Assert.Equal(300,received);
            var peers=(IDictionary)typeof(P.Wire).GetField("peers",BindingFlags.Instance|BindingFlags.NonPublic).GetValue(rig.Program.Bus);
            var streams=(IDictionary)typeof(P.Wire).GetField("streams",BindingFlags.Instance|BindingFlags.NonPublic).GetValue(rig.Program.Bus);
            Assert.Empty(peers);Assert.InRange(streams.Count,1,128);
        }

        [Fact]
        public void RepeatedSessionChangesAndCleanupKeepRetiredSessionsBounded()
        {
            var rig=new Rig();int received=0;
            for(int n=0;n<1300;n++) {rig.Add("s"+n,1);rig.Program.Bus.Drain(p=>received++);rig.Program.Bus.ForgetPeer("peer");}
            Assert.Equal(1300,received);
            var retired=(ICollection<string>)typeof(P.Wire).GetField("retired",BindingFlags.Instance|BindingFlags.NonPublic).GetValue(rig.Program.Bus);
            Assert.InRange(retired.Count,1,1024);
            rig.Add("s1298",2);rig.Program.Bus.Drain(p=>received++);Assert.Equal(1300,received);
        }

        [Fact]
        public void ProtectedOccupantRejectsReusedIdBeforeRetiringItsRealSession()
        {
            var rig=new Rig();int received=0;rig.Add("original",1);rig.Program.Bus.Drain(p=>received++);
            rig.Program.Bus.ProtectPeer("peer",123);rig.Program.Bus.ForgetPeer("peer");
            rig.Add("replacement",1,"TELEMETRY","peer",456);rig.Program.Bus.Drain(p=>received++);Assert.Equal(1,received);
            rig.Add("original",2);rig.Program.Bus.Drain(p=>received++);Assert.Equal(2,received);
            rig.Program.Bus.ProtectPeer("peer",0);rig.Program.Bus.ForgetPeer("peer");rig.Add("replacement",2,"TELEMETRY","peer",456);rig.Program.Bus.Drain(p=>received++);Assert.Equal(3,received);
        }

        [Fact]
        public void SessionCacheAutomaticallyReplacesOldStreamsButRejectsRetiredSessionReplay()
        {
            var rig = new Rig(); int received = 0;
            for (int session = 0; session < 80; session++)
            {
                for (int kind = 0; kind < 32; kind++)
                {
                    rig.Add("s" + session, kind + 1, "K" + kind);
                    rig.Program.Bus.Drain(p => received++);
                }
            }
            Assert.Equal(2560, received);
            var streams = (IDictionary)typeof(P.Wire).GetField("streams", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(rig.Program.Bus);
            Assert.Single(streams); Assert.Equal(32, ((IDictionary)streams["peer"]).Count);
            rig.Add("s0", 1000, "K0"); rig.Program.Bus.Drain(p => received++); Assert.Equal(2560, received);
            rig.Add("s79", 32, "K31"); rig.Program.Bus.Drain(p => received++); Assert.Equal(2560, received);
            rig.Add("s80", 1, "K0"); rig.Program.Bus.Drain(p => received++); Assert.Equal(2561, received);
        }

        [Fact]
        public void ClearingAndReplacingTasksDropsAnUnfinishedMapAndPublishedTotals()
        {
            var rig=new Rig();var role=new BusyRole(rig);role.Jobs.Clear();
            for(int n=0;n<128;n++)role.Jobs.Add(new P.Job {Id="old"+n,RegionId="old-region",Outcome="Complete"});
            var dashboard=new P.Dashboard(rig.Program);dashboard.Update(role);
            role.Jobs.Clear();role.Jobs.Add(new P.Job {Id="new",RegionId="new-region",Outcome="Complete"});dashboard.Update(role);
            var count=typeof(P.Dashboard).GetField("completedJobs",BindingFlags.Instance|BindingFlags.NonPublic);
            Assert.Equal(1,(int)count.GetValue(dashboard));
            role.Jobs.Clear();dashboard.Update(role);Assert.Equal(0,(int)count.GetValue(dashboard));
        }

        [Fact]
        public void DisplayBuildsLargeMapAcrossFramesAndKeepsJobsUntouched()
        {
            var rig = new Rig(); var role = new BusyRole(rig); role.Jobs.Clear();
            for (int n = 0; n < 2048; n++) role.Jobs.Add(new P.Job { Id = "job" + n, RegionId = "r", Outcome = "Complete" });
            var dashboard = new P.Dashboard(rig.Program);
            var count = typeof(P.Dashboard).GetField("completedJobs", BindingFlags.Instance | BindingFlags.NonPublic);
            dashboard.Update(role); Assert.Equal(0, (int)count.GetValue(dashboard));
            for (int n = 0; n < 31; n++) dashboard.Update(role);
            Assert.Equal(2048, (int)count.GetValue(dashboard)); Assert.Equal(2048, role.Jobs.Count);
            rig.Runtime.Set("CurrentInstructionCount", 30000); dashboard.ClearTransientCache(); dashboard.Update(role);
            Assert.Equal(2048, (int)count.GetValue(dashboard));
        }
    }
}