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

XFEEDToolBox

【WinUI】XFE精英危险工具箱

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

XFEstudio/XFEEDToolBox

Account protected empty-ship maintenance outside cargo journeys

Add a docked-only maintenance entry point for the verified CG route ship. Record confirmed original service debits in a separate ledger and require its final wallet to reconcile. It sends no trade or flight orders. Validation: isolated CLI publish and live read-only source diagnostics; actual empty-ship refuel/integrity service and wallet reconciliation passed. Continuous SCA handoff remains unresolved; recovered normal-space docking does not count as continuous arrival acceptance.

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

代码差异

3 个文件 +63 -0
Modified docs/CG-TRADING-VALIDATION.md +2 -0
@@ -27,3 +27,5 @@
27 27 `cg-cargo-journey <PID> <旅程目录>` 固定验证Corsair/5、192t、Duamta/Polyakov→AD Leonis/Homer的Uranium路线。首次采购前要求本机原1t已完成回执及CG成员证明。买价上限7,241、卖价下限57,104只是限价,执行前仍读原始价格和库存。每站维护与交易均完成才离站,保留实际重购资金;提高后的CG报价不得再乘8。
28 28
29 29 继续已有货物必须复用原目录。原始回执、钱包、会话身份及日志只存本机,不能提交到仓库。`continuousArrivalAccepted` 必须来自同一完整到站报告,不能用正常空间重试替代。未领取CG奖励不计入净利润。
30
31 空载诊断停靠可使用 `service-cg-docked <PID> <独立维护目录>`。它仅接受已核对路线站点、空舱及受保护的Corsair/5,不启动贸易或飞行;每笔原始服务费用记入独立账本,结尾必须与原始钱包核对。该路径已在恢复停靠后完成加油与完整性服务实测,诊断费用也应从总收益扣除。
Added research/NativeAcceptance/DockedMaintenance.cs +59 -0
@@ -0,0 +1,59 @@
1 using System.Text.Json;
2 using XFEEDToolBox.Core.Data;
3 using XFEEDToolBox.Core.Execution;
4 using XFEEDToolBox.Core.Models;
5 using XFEEDToolBox.Core.Navigation;
6
7 internal static class DockedMaintenance
8 {
9 internal static async Task RunAsync(int pid,string directory)
10 {
11 directory=Path.GetFullPath(directory);Directory.CreateDirectory(directory);
12 using var lease=new FileStream(Path.Combine(directory,"runner.lock"),FileMode.OpenOrCreate,FileAccess.ReadWrite,FileShare.None);
13 var settings=ToolboxSettings.Load(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),"XFEstudio","XFEEDToolBox","settings.json"));
14 await using var journal=new JournalMonitor(settings.JournalDirectory);await journal.StartAsync();var initial=journal.State;
15 if(!initial.InGame||!initial.Docked||initial.CurrentShipId!=5||initial.CargoCount!=0||initial.CargoCapacity!=192||!initial.StationServicesKnown
16 ||initial.MarketId is not (3228792064 or 4210924803)||string.IsNullOrWhiteSpace(initial.CommanderId))
17 throw new InvalidOperationException("Expected the empty, docked CG ship at its verified route station.");
18 await using var protection=await FlightTestProtectionScope.ArmAsync(pid);
19 var channel=new NativeCommerceChannel(pid);using var ledger=new TradeProfitLedger(Path.Combine(directory,"ledger"));
20 NativeWalletObservation? wallet=null;PlayerState Player()=>wallet?.Project(journal.State)??journal.State;
21 async Task Check(CancellationToken token)
22 {
23 var player=Player();token.ThrowIfCancellationRequested();
24 if(!player.InGame||!player.Docked||player.MarketId!=initial.MarketId||player.CommanderId!=initial.CommanderId||player.CurrentShipId!=initial.CurrentShipId
25 ||player.LoadGameAt!=initial.LoadGameAt||player.CargoCount!=0||protection.Stopped||NavigationSafety.HasExternalThreat(player))
26 throw new InvalidOperationException("Docked maintenance ship, cargo or protection changed.");
27 var h=(await channel.CallAsync(new{op="health.read"},token)).GetProperty("shipHealth");
28 if(!h.GetProperty("verified").GetBoolean()||h.GetProperty("hullFraction").GetDouble()<.5)throw new InvalidOperationException("Fresh original ship health required.");
29 }
30 var driver=new NativeTradeCommandDriver(channel,Player,Path.Combine(directory,"operations"),(_,_,_)=>throw new InvalidOperationException("No travel in docked maintenance."),Check);
31 driver.WalletObserved+=value=>wallet=value;driver.ServiceConfirmed+=receipt=>ledger.Record(receipt.ToCashEntry());driver.Status+=Console.WriteLine;
32 using var stop=new CancellationTokenSource(TimeSpan.FromMinutes(3));
33 using var sentinel=new Timer(_=>{if(File.Exists(Path.Combine(directory,"stop")))stop.Cancel();},null,100,100);
34 string? failure=null;long? opening=null,closing=null;
35 try
36 {
37 await driver.PreflightAsync(stop.Token);var path=Path.Combine(directory,"opening-wallet.json");
38 if(File.Exists(path)){using var saved=JsonDocument.Parse(await File.ReadAllTextAsync(path,stop.Token));opening=saved.RootElement.GetProperty("credits").GetInt64();}
39 else
40 {
41 opening=wallet!.Credits;await using var file=new FileStream(path,FileMode.CreateNew,FileAccess.Write,FileShare.Read);
42 await JsonSerializer.SerializeAsync(file,new{credits=opening},cancellationToken:stop.Token);
43 }
44 await driver.ServiceDockedAsync(new(initial.MarketId!.Value,192),Check,stop.Token);
45 await Check(stop.Token);var inventory=await channel.CallAsync(new{op="commerce.inventory"},stop.Token);closing=inventory.GetProperty("credits").GetInt64();
46 if(inventory.GetProperty("count").GetInt32()!=0||opening+ledger.Snapshot.CashChange!=closing)
47 throw new InvalidDataException("Docked maintenance wallet does not reconcile with confirmed service debits.");
48 }
49 catch(Exception error){failure=error.ToString();}
50 finally
51 {
52 await driver.ReleaseAllAsync();
53 await File.WriteAllTextAsync(Path.Combine(directory,"result.json"),JsonSerializer.Serialize(new{passed=failure is null,pid,finished=DateTimeOffset.UtcNow,
54 initial.MarketId,opening,closing,profit=ledger.Snapshot,failure,cargoCount=0,tradeOrdersSent=0,screenUse=false},ToolboxSettings.JsonOptions));
55 }
56 if(failure is not null)throw new InvalidOperationException("Docked maintenance requires reconciliation: "+failure);
57 Console.WriteLine(JsonSerializer.Serialize(new{passed=true,opening,closing,profit=ledger.Snapshot}));
58 }
59 }
Modified research/NativeAcceptance/Program.cs +2 -0
@@ -7,6 +7,8 @@ using XFEEDToolBox.Core.Galaxy;
7 7
8 8 try
9 9 {
10 if(args.Length==3&&args[0]=="service-cg-docked")
11 {await DockedMaintenance.RunAsync(int.Parse(args[1]),args[2]);return;}
10 12 if(args.Length==3&&args[0]=="inspect-docking-input-sources")
11 13 {
12 14 if(File.Exists(args[2]))throw new IOException("Use a new read-only docking input report.");