using System.Text.Json;
using XFEEDToolBox.Core.Data;
using XFEEDToolBox.Core.Models;
using XFEEDToolBox.Core.Native;
using XFEEDToolBox.Core.Navigation;
internal static class LocalLaunchCancellationAcceptance
{
public static async Task RunAsync(int pid,string stationName,string reportPath)
{
if(File.Exists(reportPath))throw new IOException("Use a new evidence 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==stationName);
if(!initial.InGame||!initial.Docked||initial.MarketId!=row.MarketId||!NavigationAssists.From(initial).AdvancedDocking)throw new InvalidOperationException("Exact docked ship and original advanced docking required.");
await using var protection=await FlightTestProtectionScope.ArmAsync(pid);using var stop=new CancellationTokenSource(TimeSpan.FromSeconds(35));
var target=new SystemNavigationTarget(catalogue.SystemAddress,row.WorldAddress,row.Name,SystemTargetKind.Station,row.MarketId){NativeKey=row.Key,NativeKind=row.NativeKind,NativeIdentity=row.Identity};
var driver=new NativeSystemFlightControlDriver(pid,hash,()=>journal.State);var started=DateTimeOffset.UtcNow;string? failure=null;JsonElement? requested=null,after=null;var released=false;var samples=0;
try
{
await driver.SelectAsync(target,stop.Token);await driver.RequestLaunchAsync(stop.Token);
var requestDeadline=DateTimeOffset.UtcNow.AddSeconds(2);
do
{
requested=await pipe.CallAsync(new{op="local.read"},stop.Token);
if(NativeSystemFlightObservation.LaunchNeedsCancellation(requested.Value.GetProperty("docking")))break;
await Task.Delay(20,stop.Token);
}while(DateTimeOffset.UtcNow<requestDeadline);
if(!NativeSystemFlightObservation.LaunchNeedsCancellation(requested.Value.GetProperty("docking")))throw new InvalidOperationException("Original launch was neither queued nor engaged before cancellation.");
await driver.ReleaseSystemFlightAsync();released=true;
// Renew only observation of the same station. No flight input is
// sent during this five-second check for resumed launch/throttle.
await driver.SelectAsync(target,stop.Token);var deadline=DateTimeOffset.UtcNow.AddSeconds(5);
while(DateTimeOffset.UtcNow<deadline)
{
var frame=await driver.ReadSystemFlightAsync(stop.Token);after=driver.LastTelemetry;
if(after is null||NativeSystemFlightObservation.LaunchNeedsCancellation(after.Value.GetProperty("docking"))||frame.Throttle>.001||frame.PlayerOverride||frame.ExternalThreat)
throw new InvalidOperationException("Original launch or throttle resumed after cancellation.");
if(journal.State.CurrentShipId!=initial.CurrentShipId||journal.State.LoadGameAt!=initial.LoadGameAt||journal.State.CargoCount!=initial.CargoCount)throw new InvalidOperationException("Cancellation session or reserved cargo changed.");
samples++;await Task.Delay(100,stop.Token);
}
}
catch(Exception error){failure=error.ToString();}
finally{try{await driver.ReleaseSystemFlightAsync();released=true;}catch(Exception error){failure=(failure??"")+error;}}
var passed=failure is null&&released&&samples>=20;
await File.WriteAllTextAsync(reportPath,JsonSerializer.Serialize(new{pid,started,finished=DateTimeOffset.UtcNow,passed,released,samples,requested,after,finalDocked=journal.State.Docked,failure,flightAxesSent=0,screenUse=false},ToolboxSettings.JsonOptions));
Console.WriteLine(JsonSerializer.Serialize(new{passed,released,samples,finalDocked=journal.State.Docked,failure}));
if(!passed)throw new InvalidOperationException("Original launch cancellation acceptance failed.");
}
}
using System.Text.Json;
using XFEEDToolBox.Core.Data;
using XFEEDToolBox.Core.Models;
using XFEEDToolBox.Core.Native;
using XFEEDToolBox.Core.Navigation;
internal static class LocalLaunchCancellationAcceptance
{
public static async Task RunAsync(int pid,string stationName,string reportPath)
{
if(File.Exists(reportPath))throw new IOException("Use a new evidence 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==stationName);
if(!initial.InGame||!initial.Docked||initial.MarketId!=row.MarketId||!NavigationAssists.From(initial).AdvancedDocking)throw new InvalidOperationException("Exact docked ship and original advanced docking required.");
await using var protection=await FlightTestProtectionScope.ArmAsync(pid);using var stop=new CancellationTokenSource(TimeSpan.FromSeconds(35));
var target=new SystemNavigationTarget(catalogue.SystemAddress,row.WorldAddress,row.Name,SystemTargetKind.Station,row.MarketId){NativeKey=row.Key,NativeKind=row.NativeKind,NativeIdentity=row.Identity};
var driver=new NativeSystemFlightControlDriver(pid,hash,()=>journal.State);var started=DateTimeOffset.UtcNow;string? failure=null;JsonElement? requested=null,after=null;var released=false;var samples=0;
try
{
await driver.SelectAsync(target,stop.Token);await driver.RequestLaunchAsync(stop.Token);
var requestDeadline=DateTimeOffset.UtcNow.AddSeconds(2);
do
{
requested=await pipe.CallAsync(new{op="local.read"},stop.Token);
if(NativeSystemFlightObservation.LaunchNeedsCancellation(requested.Value.GetProperty("docking")))break;
await Task.Delay(20,stop.Token);
}while(DateTimeOffset.UtcNow<requestDeadline);
if(!NativeSystemFlightObservation.LaunchNeedsCancellation(requested.Value.GetProperty("docking")))throw new InvalidOperationException("Original launch was neither queued nor engaged before cancellation.");
await driver.ReleaseSystemFlightAsync();released=true;
// Renew only observation of the same station. No flight input is
// sent during this five-second check for resumed launch/throttle.
await driver.SelectAsync(target,stop.Token);var deadline=DateTimeOffset.UtcNow.AddSeconds(5);
while(DateTimeOffset.UtcNow<deadline)
{
var frame=await driver.ReadSystemFlightAsync(stop.Token);after=driver.LastTelemetry;
if(after is null||NativeSystemFlightObservation.LaunchNeedsCancellation(after.Value.GetProperty("docking"))||frame.Throttle>.001||frame.PlayerOverride||frame.ExternalThreat)
throw new InvalidOperationException("Original launch or throttle resumed after cancellation.");
if(journal.State.CurrentShipId!=initial.CurrentShipId||journal.State.LoadGameAt!=initial.LoadGameAt||journal.State.CargoCount!=initial.CargoCount)throw new InvalidOperationException("Cancellation session or reserved cargo changed.");
samples++;await Task.Delay(100,stop.Token);
}
}
catch(Exception error){failure=error.ToString();}
finally{try{await driver.ReleaseSystemFlightAsync();released=true;}catch(Exception error){failure=(failure??"")+error;}}
var passed=failure is null&&released&&samples>=20;
await File.WriteAllTextAsync(reportPath,JsonSerializer.Serialize(new{pid,started,finished=DateTimeOffset.UtcNow,passed,released,samples,requested,after,finalDocked=journal.State.Docked,failure,flightAxesSent=0,screenUse=false},ToolboxSettings.JsonOptions));
Console.WriteLine(JsonSerializer.Serialize(new{passed,released,samples,finalDocked=journal.State.Docked,failure}));
if(!passed)throw new InvalidOperationException("Original launch cancellation acceptance failed.");
}
}