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.Native;
using XFEEDToolBox.Core.Navigation;

internal static class LocalAssistAcceptance
{
    public static async Task RunAsync(int pid,string exactName,string reportPath)
    {
        if(File.Exists(reportPath)||File.Exists(reportPath+".jsonl"))throw new IOException("Use a new report path.");
        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;var pipe=new NavigationPipeClient(pid);
        var hash=(await pipe.CallAsync(new{op="describe"})).GetProperty("gameSha256").GetString()!;
        using var source=new NativeCurrentSystemSource(pid,hash,()=>journal.State);var catalogue=await source.ReadLocationsAsync();var row=catalogue.Locations.Single(x=>x.Name==exactName);
        var target=new SystemNavigationTarget(catalogue.SystemAddress,row.WorldAddress,row.Name,SystemTargetKind.Station,row.MarketId){NativeKey=row.Key,NativeKind=row.NativeKind,NativeIdentity=row.Identity};
        await using var protection=await FlightTestProtectionScope.ArmAsync(pid);
        var driver=new NativeSystemFlightControlDriver(pid,hash,()=>journal.State);var start=DateTimeOffset.UtcNow;var engaged=false;var cancelled=false;var released=false;
        DateTimeOffset? engagedAt=null;var requests=0;var inputs=0;string? failure=null;double maxHeat=0,maxSpeed=0;
        await using var log=new StreamWriter(new FileStream(reportPath+".jsonl",FileMode.CreateNew,FileAccess.Write,FileShare.Read));
        try
        {
            using var stop=new CancellationTokenSource(TimeSpan.FromSeconds(55));await driver.SelectAsync(target,stop.Token);
            while(true)
            {
                var state=journal.State;if(state.CurrentShipId!=initial.CurrentShipId||state.CommanderId!=initial.CommanderId||state.LoadGameAt!=initial.LoadGameAt||!NavigationAssists.From(state).Supercruise)
                    throw new InvalidOperationException("Assist acceptance ship/session or fitted module changed.");
                var frame=await driver.ReadSystemFlightAsync(stop.Token);maxHeat=Math.Max(maxHeat,frame.HeatPercent??100);maxSpeed=Math.Max(maxSpeed,frame.Speed);
                if(frame.Mode!=LocalFlightMode.Supercruise||frame.PlayerOverride||frame.ExternalThreat||maxHeat>=65)throw new InvalidOperationException("Assist acceptance no longer has safe SC conditions.");
                if(frame.SupercruiseAssist==NativeAssistState.Engaged){engaged=true;engagedAt??=DateTimeOffset.UtcNow;}
                var direction=(frame.TargetPosition-frame.Position).Unit();var aligned=Vector3d.AngleDegrees(frame.Forward,direction)<=3;
                SystemFlightDecision decision;
                if(engagedAt is {} observed&&DateTimeOffset.UtcNow-observed>TimeSpan.FromSeconds(1))
                {
                    decision=new(SystemNavigationPhase.Waiting,"验证取消原生辅助",null,0,SystemNavigationAction.CancelOwnedAssists);
                    if(driver.LastTelemetry is {} local&&!local.GetProperty("supercruiseAssist").GetProperty("enabled").GetBoolean()&&frame.SupercruiseAssist!=NativeAssistState.Engaged&&frame.Speed<=100000)
                    {cancelled=true;break;}
                }
                else if(engaged)decision=new(SystemNavigationPhase.Supercruise,"验证原生辅助接管",null,null,SystemNavigationAction.ReleaseFlightAxes);
                else
                {
                    if(DateTimeOffset.UtcNow-start>TimeSpan.FromSeconds(30))throw new TimeoutException("Original fitted assist did not engage.");
                    var enable=aligned&&requests==0;decision=new(SystemNavigationPhase.Aligning,"验证原生超巡辅助",direction,aligned?.75:0,enable?SystemNavigationAction.EnableSupercruiseAssist:SystemNavigationAction.None);
                    if(enable)requests++;
                }
                await driver.ApplySystemFlightAsync(decision,frame,target,frame.ObservedAt.AddMilliseconds(250),stop.Token);inputs++;
                await log.WriteLineAsync(JsonSerializer.Serialize(new{at=DateTimeOffset.UtcNow,engaged,cancelled,requests,inputs,frame,driver.LastTelemetry}));await log.FlushAsync();
                await Task.Delay(50,stop.Token);
            }
        }
        catch(Exception error){failure=error.ToString();}
        finally
        {
            try
            {
                var frame=await driver.ReadSystemFlightAsync(CancellationToken.None);
                await driver.ApplySystemFlightAsync(new(SystemNavigationPhase.Waiting,"结束辅助验证并减速",null,0,SystemNavigationAction.CancelOwnedAssists),frame,target,frame.ObservedAt.AddMilliseconds(250),CancellationToken.None);
            }
            catch(Exception error){failure=(failure??"")+" Cleanup: "+error.Message;}
            try{await driver.ReleaseSystemFlightAsync();released=true;}catch(Exception error){failure=(failure??"")+" Release: "+error.Message;}
        }
        var passed=engaged&&cancelled&&released&&failure is null;
        await File.WriteAllTextAsync(reportPath,JsonSerializer.Serialize(new{pid,start,finished=DateTimeOffset.UtcNow,passed,engaged,cancelled,released,requests,inputs,maxHeat,maxSpeed,failure,tradeOrdersSent=0,dockingRequestsSent=0},ToolboxSettings.JsonOptions));
        Console.WriteLine(JsonSerializer.Serialize(new{passed,engaged,cancelled,released,requests,inputs,maxHeat,maxSpeed,failure}));
        if(!passed)throw new InvalidOperationException("Native SC assist acceptance failed.");
    }
}