using System; using System.Linq; using VRage.Game.ModAPI.Ingame.Utilities; using VRageMath; using Xunit; using P=AutoMiningScript.Program; namespace AutoMiningScript.Tests { public class BulkMiningTests { static void Drain(P.TaskPlanner p) {for(int n=0;n<1024;n++)p.Advance();} static P.Job Hit(P.TaskPlanner p,double radius=100) { p.Survey(Vector3D.Zero,Vector3D.Down,Vector3D.Forward,Vector3D.Up,radius); p.Report(p.Jobs[0],new P.JobReport {Outcome="SurveyHit",Position=new Vector3D(0,-10,0),Direction=Vector3D.Down,EntityId=42}); return p.Jobs.Single(j=>j.Kind==P.JobKind.Probe); } [Theory] [InlineData(8)] [InlineData(12)] [InlineData(16)] public void SpaceExplorationUsesEveryReadyMinerAtADistinctObservation(int count) { var r=new FleetStateTests.Rig(count,true);foreach(var t in r.Miners)t.Radius=4.9;r.RegisterAll(); r.Fleet.Command("survey 2000");r.Fleet.Command("start"); for(int n=0;n<300;n++){if(n%5==0)foreach(var t in r.Miners)r.Receive("TELEMETRY",t);r.Tick(1);} var jobs=r.Planner.OwnedJobs.Values.ToList();Assert.Equal(count,jobs.Count); Assert.All(jobs,j=>Assert.Equal(P.JobKind.Survey,j.Kind));Assert.Equal(count,jobs.Select(j=>j.Entry).Distinct().Count()); for(int i=0;i=11.8); Assert.All(r.Planner.Jobs,j=>Assert.Equal(2000,Vector3D.Distance(Vector3D.Zero,j.Entry+j.Direction*j.Depth),6)); } [Theory] [InlineData(0)] [InlineData(12)] public void SpaceObservationGenerationRestoresLegacyAndFleetSizedCursors(int ships) { var p=new P.TaskPlanner(TestRig.Program());p.Survey(Vector3D.Zero,Vector3D.Zero,Vector3D.Forward,Vector3D.Up,2000,ships); var saved=new MyIni();p.Save(saved);if(ships==0)saved.Set("region0","Rows",0); var after=new P.TaskPlanner(TestRig.Program());after.Load(saved);Drain(p);Drain(after); Assert.Equal(p.Jobs.Select(j=>j.Entry),after.Jobs.Select(j=>j.Entry)); for(int n=0;nj.Entry).Distinct().Count()); } [Fact] public void TwelveMinerSearchDoesNotSleepBetweenEveryAssignmentBatch() { var r=new FleetStateTests.Rig(12,true);r.RegisterAll();r.Fleet.Command("survey 2000");r.Fleet.Command("start"); for(int n=0;n<240;n++) { if(n%60==0)foreach(var t in r.Miners)r.Receive("TELEMETRY",t); r.Program.Now+=1d/60;r.Fleet.Tick(1d/60); } Assert.Equal(504,r.Planner.Jobs.Count);Assert.Equal(12,r.Planner.OwnedJobs.Count); } [Theory] [InlineData(12)] [InlineData(16)] public void OneSurfaceHitCanEmployTheWholeReadyFleetWithoutOreConfirmation(int count) { var r=new FleetStateTests.Rig(count,true);foreach(var t in r.Miners)t.Radius=4.9;r.RegisterAll(); r.Planner.Survey(Vector3D.Zero,Vector3D.Zero,Vector3D.Forward,Vector3D.Up,2000); r.Planner.Report(r.Planner.Jobs[0],new P.JobReport {Outcome="SurveyHit",Position=Vector3D.Forward*500,Direction=Vector3D.Forward,EntityId=42});Drain(r.Planner); foreach(var j in r.Planner.Jobs.Where(j=>j.Kind==P.JobKind.Survey).ToList())r.Planner.Report(j,new P.JobReport {Outcome="SurveyEmpty"}); r.Fleet.Command("start"); for(int n=0;n<200;n++){if(n%5==0)foreach(var t in r.Miners)r.Receive("TELEMETRY",t);r.Tick(1);} var jobs=r.Planner.OwnedJobs.Values.ToList();Assert.Equal(count,jobs.Count);Assert.Equal(count,jobs.Select(j=>j.Owner).Distinct().Count()); Assert.All(jobs,j=>{Assert.Equal(P.JobKind.Probe,j.Kind);Assert.Equal(42,j.EntityId);Assert.Empty(j.ConfirmedOres);}); for(int i=0;i=11.8-1e-6); } [Fact] public void BulkGenerationResumesExactlyAfterCheckpoint() { var p=new P.TaskPlanner(TestRig.Program());Hit(p);p.Advance();p.Advance(); var saved=new MyIni();p.Save(saved);var after=new P.TaskPlanner(TestRig.Program());after.Load(saved);Drain(p);Drain(after); Assert.Equal(p.Jobs.Select(j=>j.Id),after.Jobs.Select(j=>j.Id));Assert.Equal(p.Jobs.Select(j=>j.Entry),after.Jobs.Select(j=>j.Entry)); Assert.Equal(p.Jobs.Count,p.Jobs.Select(j=>j.Id).Distinct().Count());Assert.Equal(0,after.PendingGeneration); Assert.True(after.Regions.Single(r=>r.Patch).Bulk); } [Theory] [InlineData(false)] [InlineData(true)] public void FleetRecordStorageResumesNewGridOrUpgradesLegacyRingWithoutLosingActiveWork(bool legacy) { var before=new FleetStateTests.Rig(1,true);before.RegisterAll();var seed=Hit(before.Planner); seed.Progress=12;before.Planner.SetOwner(seed,"miner-0"); if(legacy) { var patch=before.Planner.Regions.Single(r=>r.Patch);patch.Bulk=false;patch.Generation="Ring"; patch.Cursor=3;patch.Total=8;patch.Columns=patch.Rows=1; } else {before.Planner.Advance();before.Planner.Advance();} var after=new FleetStateTests.Rig(1,true);after.Restore(before.Checkpoint());Drain(after.Planner); var restored=after.Planner.Find(seed.Id);Assert.Equal(12,restored.Progress);Assert.Equal(seed.Entry,restored.Entry); Assert.Equal("miner-0",restored.Owner);Assert.Equal(restored,after.Planner.OwnedJobs["miner-0"]); Assert.True(after.Planner.Regions.Single(r=>r.Patch).Bulk);Assert.Equal(0,after.Planner.PendingGeneration); var holes=after.Planner.Jobs.Where(j=>j.Kind==P.JobKind.Probe).ToList();Assert.Equal(145,holes.Count); Assert.Equal(holes.Count,holes.Select(j=>j.Entry).Distinct().Count()); if(!legacy) { Drain(before.Planner);Assert.Equal(before.Planner.Jobs.Select(j=>j.Id),after.Planner.Jobs.Select(j=>j.Id)); Assert.Equal(before.Planner.Jobs.Select(j=>j.Entry),after.Planner.Jobs.Select(j=>j.Entry)); } } [Fact] public void ExcavationNearSearchEdgeClipsBothEntriesAndBoreEndsToTheFrozenSphere() { var p=new P.TaskPlanner(TestRig.Program());p.Survey(Vector3D.Zero,Vector3D.Zero,Vector3D.Forward,Vector3D.Up,200); p.Report(p.Jobs[0],new P.JobReport {Outcome="SurveyHit",Position=Vector3D.Forward*198,Direction=Vector3D.Forward,EntityId=42});Drain(p); var holes=p.Jobs.Where(j=>j.Kind==P.JobKind.Probe).ToList();Assert.InRange(holes.Count,2,144); Assert.All(holes,j=> { Assert.True(j.Entry.Length()<=200+1e-6);Assert.True((j.Entry+j.Direction*j.Depth).Length()<=200+1e-6); Assert.InRange(j.Depth,1,2+1e-6); }); } [Fact] public void LegacyIsolatedProbeExpandsWithoutChangingItsProgressOrOwnership() { var p=new P.TaskPlanner(TestRig.Program());p.Survey(Vector3D.Zero,Vector3D.Down,Vector3D.Forward,Vector3D.Up,100);Drain(p); string search=p.Regions[0].Id;p.Manual(new Vector3D(0,-10,0),Vector3D.Down,Vector3D.Forward,6,6,40); var seed=p.Jobs.Last();seed.Kind=P.JobKind.Probe;seed.EntityId=42;seed.RegionId=search;seed.Progress=12;p.SetOwner(seed,"old-miner"); var saved=new MyIni();p.Save(saved);var after=new P.TaskPlanner(TestRig.Program());after.Load(saved);Drain(after); var restored=after.Find(seed.Id);Assert.Equal(12,restored.Progress);Assert.Equal(40,restored.Depth);Assert.Equal("old-miner",restored.Owner); Assert.Equal(seed.Entry,restored.Entry);Assert.True(after.Regions.Single(r=>r.Patch).Bulk); Assert.True(after.Jobs.Count(j=>j.Kind==P.JobKind.Probe)>100); } [Fact] public void LegacyStoppedEmptyRingsUpgradeWithoutRepeatingExistingHoles() { var p=new P.TaskPlanner(TestRig.Program());var seed=Hit(p);p.Report(seed,new P.JobReport {Outcome="Complete",Progress=seed.Depth}); var saved=new MyIni();p.Save(saved); saved.Set("region1","Bulk",false);saved.Set("region1","Generation","");saved.Set("region1","Status","Sampling complete: two empty rings");saved.Set("region1","Ring",2);saved.Set("region1","EmptyRings",2); var after=new P.TaskPlanner(TestRig.Program());after.Load(saved);Drain(after); Assert.Equal("Complete",after.Find(seed.Id).Outcome);Assert.Equal("Pending",after.Regions.Single(r=>r.Patch).Status); var holes=after.Jobs.Where(j=>j.Kind==P.JobKind.Probe).ToList();Assert.True(holes.Count>100);Assert.Equal(holes.Count,holes.Select(j=>j.Entry).Distinct().Count()); } [Fact] public void JobBudgetProducesFinitePartialWorkAndHonestIncompleteStatus() { var p=new P.TaskPlanner(TestRig.Program("[Survey]\nMaxJobs=32\n"));Hit(p);Drain(p); Assert.InRange(p.Jobs.Count,15,32);Assert.Equal(0,p.PendingGeneration);Assert.Equal("Pending",p.Regions.Single(r=>r.Patch).Status); Assert.True(p.Jobs.Count(j=>j.Kind==P.JobKind.Probe)>1); foreach(var j in p.Jobs.Where(j=>j.Kind==P.JobKind.Probe).ToList())p.Report(j,new P.JobReport {Outcome="Complete",Progress=j.Depth});Drain(p); Assert.Contains("job budget",p.Regions.Single(r=>r.Patch).Status); } [Fact] public void NewExcavationDepthUsesMaxDepthInsteadOfLegacyProbeDepth() { var p=new P.TaskPlanner(TestRig.Program("[Survey]\nMaxDepth=80\nProbeDepth=3\n"));Hit(p);Drain(p); Assert.All(p.Jobs.Where(j=>j.Kind==P.JobKind.Probe),j=>Assert.Equal(80,j.Depth)); } [Fact] public void GrazingAsteroidDiscoveryBuildsAnInwardPatchInsteadOfFollowingTheTangentialRay() { var p=new P.TaskPlanner(TestRig.Program());p.Survey(Vector3D.Zero,Vector3D.Zero,Vector3D.Forward,Vector3D.Up,2000); var hit=new Vector3D(100,100,-700);var center=new Vector3D(200,250,-560); p.Report(p.Jobs[0],new P.JobReport {Outcome="SurveyHit",Position=hit,Direction=new Vector3D(.2,-.1,.97),EntityId=42, Scan=new P.ScanRecord {Start=Vector3D.Zero,End=hit,Center=center,Size=new Vector3D(512),Asteroid=42}});Drain(p); var direction=Vector3D.Normalize(center-hit);var holes=p.Jobs.Where(j=>j.Kind==P.JobKind.Probe).ToList();Assert.Equal(145,holes.Count); Assert.All(holes,j=>{Assert.True(Vector3D.Distance(direction,j.Direction)<1e-12);Assert.Equal(100,j.Depth);Assert.True(Vector3D.Distance(hit,j.Entry)<=43);}); } } }