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

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
using System.Text.Json;
using XFEEDToolBox.Core.Data;
using XFEEDToolBox.Core.Models;
using XFEEDToolBox.Core.Navigation;

internal static class NativeStationServiceAcceptance
{
    public static async Task RunAsync(int pid,string maintenanceAddress,string reportPath)
    {
        if(File.Exists(reportPath)||File.Exists(reportPath+".submitted.json"))throw new IOException("Use a new evidence path; never resend an uncertain service order.");
        var settings=ToolboxSettings.Load(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),"XFEstudio","XFEEDToolBox","settings.json"));
        await using var journal=new JournalMonitor(settings.JournalDirectory);await journal.StartAsync();var initial=journal.State;
        if(!initial.InGame||!initial.Docked||initial.MarketId is not {} market||initial.CurrentShipId!=7||!initial.StationServicesKnown||!initial.StationServices.Contains("refuel"))
            throw new InvalidOperationException("Expected identified docked acceptance ship and a station providing refuel.");
        var limpets=initial.Inventory.Where(x=>x.Key=="drones").Sum(x=>x.Count);
        var testCargo=initial.Inventory.Where(x=>x.Key=="biowaste").Sum(x=>x.Count);
        if(!initial.CargoReliable||initial.CargoCount!=16||!(limpets==16&&testCargo==0||limpets==15&&testCargo==1))
            throw new InvalidOperationException("Expected the agreed test cargo or the restored 16-limpet baseline.");
        using var stop=new CancellationTokenSource(TimeSpan.FromSeconds(100));
        await using var protection=await FlightTestProtectionScope.ArmAsync(pid);var pipe=new NavigationPipeClient(pid);
        async Task<JsonElement> Wait(ulong generation)
        {
            while(true)
            {
                var value=await pipe.CallAsync(new{op="commerce.market.status",generation},stop.Token);
                if(value.GetProperty("state").GetInt32()>=3)return value;
                await Task.Delay(80,stop.Token);
            }
        }
        async Task<JsonElement> Prices()
        {
            var queued=await pipe.CallAsync(new{op="station.services.inspect",marketId=(uint)market,maintenanceAddress},stop.Token);
            var result=await Wait(queued.GetProperty("generation").GetUInt64());
            if(result.GetProperty("state").GetInt32()!=3)throw new InvalidOperationException("Original service quote failed.");return result;
        }
        var started=DateTimeOffset.UtcNow;var key=Guid.NewGuid().ToString("N");string? failure=null;
        JsonElement? before=null,quote=null,receipt=null,after=null,serverAfter=null;
        try
        {
            before=await pipe.CallAsync(new{op="station.services.inventory"},stop.Token);quote=await Prices();
            var cost=quote.Value.GetProperty("fuelPrices").GetProperty("costToRefuel").GetInt64();
            if(cost is <=0 or >50000)throw new InvalidOperationException("Expected a nonzero bounded original refuel quote.");
            if(!journal.State.InGame||!journal.State.Docked||journal.State.MarketId!=market||journal.State.CurrentShipId!=initial.CurrentShipId||journal.State.LoadGameAt!=initial.LoadGameAt)
                throw new InvalidOperationException("Docking or session changed before refuel.");
            await File.WriteAllTextAsync(reportPath+".submitted.json",JsonSerializer.Serialize(new{key,market,pid,started,before,quotedCost=cost,action="refuel",instruction="Do not resend; query/reconcile this original operation."},ToolboxSettings.JsonOptions));
            var queued=await pipe.CallAsync(new{op="station.services",marketId=(uint)market,maintenanceAddress,action="refuel",operationKey=key},stop.Token);
            receipt=await Wait(queued.GetProperty("generation").GetUInt64());
            if(receipt.Value.GetProperty("state").GetInt32()!=3||!receipt.Value.GetProperty("clientApplied").GetBoolean())throw new InvalidOperationException("Original refuel receipt unconfirmed; do not resend.");
            after=await pipe.CallAsync(new{op="station.services.inventory"},stop.Token);
            if(after.Value.GetProperty("credits").GetInt64()!=before.Value.GetProperty("credits").GetInt64()-cost||after.Value.GetProperty("cargoCount").GetInt32()!=before.Value.GetProperty("cargoCount").GetInt32()
                ||Math.Abs(after.Value.GetProperty("fuelLevel").GetDouble()-after.Value.GetProperty("fuelCapacity").GetDouble())>.01
                ||Math.Abs(after.Value.GetProperty("reserveLevel").GetDouble()-after.Value.GetProperty("reserveCapacity").GetDouble())>.01)
                throw new InvalidOperationException("Actual native fuel, cargo or wallet disagrees with the service receipt.");
            serverAfter=await Prices();
            if(serverAfter.Value.GetProperty("fuelPrices").GetProperty("costToRefuel").GetInt64()!=0)throw new InvalidOperationException("A second original server quote did not confirm full fuel.");
        }
        catch(Exception error){failure=error.ToString();}
        var passed=failure is null;
        await File.WriteAllTextAsync(reportPath,JsonSerializer.Serialize(new{pid,market,started,finished=DateTimeOffset.UtcNow,key,passed,before,quote,receipt,after,serverAfter,failure,screenUse=false,osInputsSent=0,journalEventsSynthesized=0},ToolboxSettings.JsonOptions));
        Console.WriteLine(JsonSerializer.Serialize(new{passed,market,failure,screenUse=false,journalEventsSynthesized=0}));
        if(!passed)throw new InvalidOperationException("Original station service acceptance did not pass.");
    }
}