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

AutoMiningScript

【SpaceEngineer】全自动挖矿脚本

公开
关注 0 Fork 0 Star 0
返回提交历史

SpaceEngineersModDev/AutoMiningScript

修复不可达探索入口的持续绕行并记录实机调试

c5f2d22
XFE工作室室长 <mail@xfegzs.com>
提交于

代码差异

5 个文件 +103 -2
Modified AutoMiningScript.Tests/SurveyNavigationTests.cs +86 -0
@@ -158,6 +158,92 @@ namespace AutoMiningScript.Tests
158 158 Assert.DoesNotContain(r.R.Sent,p=>p.Kind=="RESULT");Assert.Equal(P.L.MinerWaitSurveyScan,Read<string>(r.R.Miner,"reason"));
159 159 r.Ready=true;Assert.Equal("SurveyEmpty",r.Finish().Outcome);
160 160 }
161
162 [Fact]
163 public void SurveyEntryLoopReportsBlockedEvenWhileLocalFlightKeepsMoving()
164 {
165 var r=new SurveyRig();r.Job.Entry=Vector3D.Zero;
166 r.R.Camera.Method("CanScan",a=>true);
167 // Like the live trace, repeatedly fly useful-looking local legs while
168 // never getting meaningfully closer than the best approach to the entry.
169 for(int n=0;n<1300 && !r.R.Sent.Any(p=>p.Kind=="RESULT");n++)
170 {
171 double angle=n*.05;
172 r.R.Position=new Vector3D(Math.Cos(angle)*12,0,Math.Sin(angle)*12);
173 r.Velocity=new Vector3D(-Math.Sin(angle)*3,0,Math.Cos(angle)*3);
174 r.Tick(false);
175 Assert.False(r.Flight.Blocked);
176 }
177 var report=P.JobReport.FromIni(Assert.Single(r.R.Sent,p=>p.Kind=="RESULT").Body);
178 Assert.Equal("Blocked",report.Outcome);Assert.Equal(r.Job.Id,report.JobId);
179 Assert.Null(report.Scan);Assert.Equal(0,r.SurveyRays);
180 Assert.InRange(r.R.Program.Now,45,46);
181 Assert.Null(Read<P.Job>(r.R.Miner,"job"));
182 Assert.Equal(P.FlightState.Survey,r.R.StateNow);
183 Assert.True(Read<bool>(r.R.Miner,"continuing"));
184 }
185
186 [Fact]
187 public void SurveyTransitKeepsItsBudgetWhileMakingSlowCumulativeProgress()
188 {
189 var r=new SurveyRig();r.Job.Entry=Vector3D.Zero;r.R.Camera.Method("CanScan",a=>true);
190 for(int n=0;n<1800;n++)
191 {
192 r.R.Position=Vector3D.Backward*(100-n*.005);r.Velocity=Vector3D.Forward*.1;
193 r.Tick(false);
194 }
195 Assert.True(r.R.Program.Now>89);Assert.Equal(P.FlightState.Transit,r.R.StateNow);
196 Assert.DoesNotContain(r.R.Sent,p=>p.Kind=="RESULT");
197 }
198
199 [Fact]
200 public void SurveyBlockageBudgetUsesRecentProgressInsteadOfTotalTransitAge()
201 {
202 var r=new SurveyRig();r.R.Camera.Method("CanScan",a=>true);
203 r.R.Position=Vector3D.Backward*100;r.Tick(false);
204 r.R.Program.Now=50;r.R.Position=Vector3D.Backward*20;
205 foreach(var thrust in r.R.Hardware.Thrusters)thrust.Enabled=false;
206 r.Tick(false);
207 Assert.True(r.Flight.Blocked);Assert.Equal(P.FlightState.Transit,r.R.StateNow);
208 Assert.DoesNotContain(r.R.Sent,p=>p.Kind=="RESULT");
209 }
210
211 [Fact]
212 public void SurveyCanTemporarilyDetourAwayThenResumeApproachingTheEntry()
213 {
214 var r=new SurveyRig();r.Job.Entry=Vector3D.Zero;r.R.Camera.Method("CanScan",a=>true);
215 for(int n=0;n<700;n++)
216 {
217 r.R.Position=Vector3D.Backward*(n<500?20+n*.01:25-(n-500)*.05);
218 r.Tick(false);
219 }
220 Assert.Equal(P.FlightState.Transit,r.R.StateNow);Assert.DoesNotContain(r.R.Sent,p=>p.Kind=="RESULT");
221 r.R.Position=Vector3D.Zero;r.Velocity=Vector3D.Zero;
222 for(int n=0;n<50 && !r.R.Sent.Any(p=>p.Kind=="RESULT");n++)r.Tick();
223 Assert.Equal("SurveyEmpty",P.JobReport.FromIni(Assert.Single(r.R.Sent,p=>p.Kind=="RESULT").Body).Outcome);
224 }
225
226 [Fact]
227 public void AsteroidObservedAtTheProgressDeadlineStillBecomesASurfaceReport()
228 {
229 var r=new SurveyRig();r.R.Position=Vector3D.Backward*20;r.R.Camera.Method("CanScan",a=>true);
230 r.Tick(false);r.R.Program.Now=50;r.Flight.ResetRoute();
231 var surface=new Vector3D(0,0,-100);
232 r.R.Camera.Method("Raycast",a=>new MyDetectedEntityInfo(42,"Asteroid",MyDetectedEntityType.Asteroid,surface,
233 MatrixD.Identity,Vector3.Zero,VRage.Game.MyRelationsBetweenPlayerAndBlock.NoOwnership,
234 new BoundingBoxD(surface-Vector3D.One,surface+Vector3D.One),1));
235 r.Tick(false);
236 Assert.Equal("SurveyHit",P.JobReport.FromIni(Assert.Single(r.R.Sent,p=>p.Kind=="RESULT").Body).Outcome);
237 }
238
239 [Fact]
240 public void ResumingSurveyTransitStartsANewProgressWindow()
241 {
242 var r=new SurveyRig();r.R.Position=Vector3D.Backward*20;r.R.Camera.Method("CanScan",a=>true);
243 r.Tick(false);r.R.Program.Now=100;
244 r.R.Miner.Command("pause");r.R.Miner.Command("resume");r.Tick(false);
245 Assert.Equal(P.FlightState.Transit,r.R.StateNow);Assert.DoesNotContain(r.R.Sent,p=>p.Kind=="RESULT");
246 }
161 247 [Fact]
162 248 public void ProbeTransitReachesTheAlignmentToleranceBeforeTurningToTheBore()
163 249 {
Modified AutoMiningScript/MinerController.cs +7 -2
@@ -68,7 +68,7 @@ namespace AutoMiningScript
68 68 bool ReturningToDock => state==FlightState.Returning || state==FlightState.Holding || state==FlightState.DockAlign || state==FlightState.DockApproach || state==FlightState.DockRetreat;
69 69 void Set(FlightState next,string text,bool keepRoute=false)
70 70 {
71 if(state!=next) {P.Log(L.State(next)+": "+text);state=next;stateSince=P.Now;progressAt=P.Now;lastProgress=0;waitingAligning=false;if(!keepRoute)flight.ResetRoute();if(next==FlightState.Align) {entryProbe=0;entryNearest=double.MaxValue;entryFarthest=double.MinValue;}if(next==FlightState.DockAlign || next==FlightState.DockApproach) {lastProgress=double.MaxValue;stableSince=-1;}}
71 if(state!=next) {P.Log(L.State(next)+": "+text);state=next;stateSince=P.Now;progressAt=P.Now;lastProgress=next==FlightState.Transit?double.MaxValue:0;waitingAligning=false;if(!keepRoute)flight.ResetRoute();if(next==FlightState.Align) {entryProbe=0;entryNearest=double.MaxValue;entryFarthest=double.MinValue;}if(next==FlightState.DockAlign || next==FlightState.DockApproach) {lastProgress=double.MaxValue;stableSince=-1;}}
72 72 reason=text;
73 73 }
74 74 public override void Tick(double dt)
@@ -231,6 +231,9 @@ namespace AutoMiningScript
231 231 var travel=Data.Unit(target-Position,f);
232 232 var cruiseUp=Data.LengthSquared(gravity)>0.001?Data.Unit(-gravity,u):u;
233 233 var distance=Data.Distance(Position,target);
234 // Local detour motion is not progress toward an observation entry.
235 // Keep the window alive only after gaining two metres on its best approach.
236 if(surveying && distance<lastProgress-2) {lastProgress=distance;progressAt=P.Now;}
234 237 var face=surveying || distance>ship.Radius*3?travel:f;
235 238 if(!surveying && !flight.CanSupport(face,Data.Perpendicular(face,cruiseUp),0.3)) {BeginReturn(L.MinerTargetAttitudeThrustLow);return;}
236 239 // Observation rays may point sideways from the arrival path. Keep the
@@ -243,7 +246,9 @@ namespace AutoMiningScript
243 246 reason=L.F(L.MinerDockNavigationProgress,L.MinerTravelTaskEntry,distance,Data.Length(ship.Controller.GetShipVelocities().LinearVelocity),flight.AttitudeError*180/Math.PI);
244 247 if(flight.Problem.Length>0)reason=flight.Problem+" / "+reason;
245 248 RecordBreadcrumb();
246 if(flight.Blocked && P.Now-stateSince>45) {FinishBlocked(L.MinerRouteBlocked+" / "+flight.Problem);return;}
249 if(surveying && !arrived && P.Now-progressAt>45)
250 {flight.Hold(dt);FinishBlocked(L.MinerSurveyEntryStalled);return;}
251 if(!surveying && flight.Blocked && P.Now-stateSince>45) {FinishBlocked(L.MinerRouteBlocked+" / "+flight.Problem);return;}
247 252 if(arrived)Set(surveying?FlightState.Survey:FlightState.Align,L.MinerTaskEntryReached);
248 253 }
249 254 void Align(double dt)
Modified Localization/miner.en-US.json +1 -0
@@ -1,5 +1,6 @@
1 1 {
2 2 "MinerFindingRoute": "Scanning a route around the obstacle",
3 "MinerSurveyEntryStalled": "No progress toward survey entry; reported blocked for reassignment",
3 4 "MinerAutomaticReturn": "Initialized; returning to dock",
4 5 "MinerWaitNextTask": "Awaiting next regional task; probes first",
5 6 "MinerSearchCompleteReturn": "No pending regional work; returning",
Modified Localization/miner.zh-CN.json +1 -0
@@ -1,5 +1,6 @@
1 1 {
2 2 "MinerFindingRoute": "正在扫描可行绕路",
3 "MinerSurveyEntryStalled": "探索入口持续无法接近,已报告受阻并等待续派",
3 4 "MinerAutomaticReturn": "矿机初始化完成,自动返航接港",
4 5 "MinerWaitNextTask": "本项作业完成,等待本矿区续派(优先试钻)",
5 6 "MinerSearchCompleteReturn": "本矿区暂无待执行任务,返航待命",
Modified docs/VALIDATION.md +8 -0
@@ -4,6 +4,14 @@
4 4
5 5 ## 开发机检查
6 6
7 2026-09-14 不可达探索入口退出:在原仓库 `f6b7d8f` 的独立工作树中修复,不改动原工作树已有的主控修改。AgentBridge 对授权单机副本的实机采样显示,7号在同一探索任务346上多次停车、换绕行点再回头;从脚本时间204秒持续到503秒仍未进入扫描。导航能进行局部绕行,不能用单帧 `Blocked` 代表任务入口可达。现有命中点距目标约1.54米,矿机半径约4.63米,因此这条采样路径不足以安全抵达原入口。原始证据为 AgentBridge 项目的 `artifacts/seven-survey-navigation.jsonl` 和 `artifacts/seven-current.json`。
8
9 探索入口按累计接近至少2米刷新进展窗口;45秒没有有效接近时当次制动,沿现有可靠结果协议报告 `Blocked` 并在空中等待续派。当帧真实小行星命中仍优先报告 `SurveyHit`,合法绕行和缓慢累计接近保留。没有把任意绕行点冒充原扫描入口,以免错误完成覆盖任务;非探索任务保留原受阻处理。
10
11 六项回归覆盖不停移动的循环、慢速累计接近、长途后短暂阻挡、先远离再接近、截止时发现小行星,以及暂停恢复后的新窗口。循环回归在原逻辑下失败、修复后通过。完整 `./build.ps1` 成功,中英文各810/810项测试、428对语言资源及8项生成器检查通过;八份实际导出均通过编译和角色校验,0警告、0错误,均小于100000字符。日志为 `obj/agent-debug-build.log`,导出校验见 `dist/manifest.json`;中文矿机95590字符,SHA-256为 `b191430cf9ab7fe2b21569344ebcdc927bfa52847b84632440bdc68f3e5abc73`。本段记录的是修复前实机证据和修复后的自动化结果,修复后的实机续派仍待验证。
12
13 通过 AgentBridge 将上述中文导出部署到授权副本的7号,游戏返回已部署、已编译、有运行实例、无编译错误,并保留了源码备份。更新后的43个实机样本均在返航对齐/避让2号阶段,未重新进入探索入口,因此没有把这段运行计为45秒受阻续派验收。副本最终保存并正常退出;原存档25个文件摘要一致、无新增删除。
14
7 15 2026-09-14 停靠断推、发现优先派钻与六向摄像机绕障:只读核对14:36、14:41及15:01存档,7号处于Survey状态,28个镜头覆盖六向、16个推进器覆盖六轴。连续存档显示它更换了探索任务但只移动约3米;原导航遇障后反复受阻,不能据此认定为任务派发互锁。按85个方块的定义尺寸和安装姿态复算,远控相对船体范围为(-2.25,-1.75,-2.25)至(2.25,1.25,2.25),实际推力余量约5.24m/s²。原游戏存档未修改,证据见 `obj/miner7-save-audit.json` 和 `obj/miner7-body-audit.json`。
8 16
9 17 物理连接后清零并关闭本机同网格全部推进器,包括硬件组外的推进器;正常离港先恢复推进器再核算推力,连接锁定当次也执行关闭。新小行星的发现结果与完成遥测齐备后优先安排试钻,消息颠倒或重复不会重置调度,资源不足可交给其他可用矿机,其他正在执行的探索及钻孔不被抢占。