using System.Text.Json;
using XFEEDToolBox.Core.Data;
using XFEEDToolBox.Core.Models;
using XFEEDToolBox.Core.Navigation;
internal static class NativeMarketOrderAcceptance
{
public static async Task RunAsync(int pid,string commodity,int delta,string reportPath)
{
if(File.Exists(reportPath))throw new IOException("Use a new report path.");
var id=commodity switch{"drones"=>128066403u,"biowaste"=>128049244u,"hydrogenfuel"=>128049202u,"scrap"=>128049248u,_=>throw new ArgumentException("Choose a permitted low-price test commodity.")};
if(delta is not(1 or -1))throw new ArgumentException("The acceptance order must be exactly 1t.");
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.CargoReliable||initial.CurrentShipId!=7)throw new InvalidOperationException("Expected identified docked acceptance ship and reliable reserved cargo.");
var limpets=initial.Inventory.Where(x=>x.Key=="drones"&&x.Stolen==0&&x.MissionId is null).Sum(x=>x.Count);
if(commodity=="drones"&&(delta<0?limpets!=16:limpets!=15)||commodity!="drones"&&limpets!=15)
throw new InvalidOperationException("The agreed limpet baseline is not established.");
if(delta>0&&initial.FreeCargo<1)throw new InvalidOperationException("Sell the authorized single limpet before the cheap 1t test.");
using var stop=new CancellationTokenSource(TimeSpan.FromSeconds(80));
await using var protection=await FlightTestProtectionScope.ArmAsync(pid);var pipe=new NavigationPipeClient(pid);
async Task<JsonElement> Wait(ulong generation)
{
while(true)
{
var result=await pipe.CallAsync(new{op="commerce.market.status",generation},stop.Token);
if(result.GetProperty("state").GetInt32()>=3)return result;
await Task.Delay(80,stop.Token);
}
}
async Task<JsonElement> ReadMarket()
{
var queued=await pipe.CallAsync(new{op="commerce.market.read",marketId=(uint)market},stop.Token);
var result=await Wait(queued.GetProperty("generation").GetUInt64());
if(result.GetProperty("state").GetInt32()!=3)throw new InvalidOperationException("Original current-market read failed.");return result;
}
var started=DateTimeOffset.UtcNow;JsonElement? receipt=null,after=null,serverAfter=null;var key=Guid.NewGuid().ToString("N");string? failure=null;
var before=await pipe.CallAsync(new{op="commerce.inventory"},stop.Token);
try
{
await ReadMarket();
var current=journal.State;
if(!current.InGame||!current.Docked||current.MarketId!=market||current.CommanderId!=initial.CommanderId||current.CurrentShipId!=initial.CurrentShipId||current.LoadGameAt!=initial.LoadGameAt)
throw new InvalidOperationException("Acceptance session or docking identity changed before the order.");
var queued=await pipe.CallAsync(new{op="commerce.trade",marketId=(uint)market,commodityId=id,quantityDelta=delta,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 order result is not confirmed; never resend this operation key.");
after=await pipe.CallAsync(new{op="commerce.inventory"},stop.Token);
var price=receipt.Value.GetProperty("unitPrice").GetInt64();
if(price is <=0 or >500||after.Value.GetProperty("count").GetInt32()!=before.GetProperty("count").GetInt32()+delta
||after.Value.GetProperty("credits").GetInt64()!=before.GetProperty("credits").GetInt64()-price*delta)
throw new InvalidOperationException("The original cargo or wallet does not match the confirmed server order.");
serverAfter=await ReadMarket();
var actual=serverAfter.Value.GetProperty("cargo").TryGetProperty(commodity,out var amount)?amount.GetInt32():0;
if(actual!=receipt.Value.GetProperty("after").GetInt32())throw new InvalidOperationException("A second original server read did not confirm the new inventory.");
var cargoDeadline=DateTimeOffset.UtcNow.AddSeconds(5);
while(journal.State.CargoCount!=after.Value.GetProperty("count").GetInt32())
{
if(DateTimeOffset.UtcNow>=cargoDeadline)throw new InvalidOperationException("The game's actual Cargo.json has not confirmed the new cargo count.");
await Task.Delay(100,stop.Token);
}
}
catch(Exception error){failure=error.ToString();}
var passed=failure is null;
await File.WriteAllTextAsync(reportPath,JsonSerializer.Serialize(new{pid,started,finished=DateTimeOffset.UtcNow,commodity,delta,market,key,passed,before,receipt,after,serverAfter,
journalCargoCount=journal.State.CargoCount,journalCargoAt=journal.State.CargoAt,failure,screenUse=false,osInputsSent=0,journalEventsSynthesized=0,completeTradeCycleAccepted=false},ToolboxSettings.JsonOptions));
Console.WriteLine(JsonSerializer.Serialize(new{passed,commodity,delta,market,failure,screenUse=false,journalEventsSynthesized=0}));
if(!passed)throw new InvalidOperationException("The original 1t market-order acceptance did not pass.");
}
}
using System.Text.Json;
using XFEEDToolBox.Core.Data;
using XFEEDToolBox.Core.Models;
using XFEEDToolBox.Core.Navigation;
internal static class NativeMarketOrderAcceptance
{
public static async Task RunAsync(int pid,string commodity,int delta,string reportPath)
{
if(File.Exists(reportPath))throw new IOException("Use a new report path.");
var id=commodity switch{"drones"=>128066403u,"biowaste"=>128049244u,"hydrogenfuel"=>128049202u,"scrap"=>128049248u,_=>throw new ArgumentException("Choose a permitted low-price test commodity.")};
if(delta is not(1 or -1))throw new ArgumentException("The acceptance order must be exactly 1t.");
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.CargoReliable||initial.CurrentShipId!=7)throw new InvalidOperationException("Expected identified docked acceptance ship and reliable reserved cargo.");
var limpets=initial.Inventory.Where(x=>x.Key=="drones"&&x.Stolen==0&&x.MissionId is null).Sum(x=>x.Count);
if(commodity=="drones"&&(delta<0?limpets!=16:limpets!=15)||commodity!="drones"&&limpets!=15)
throw new InvalidOperationException("The agreed limpet baseline is not established.");
if(delta>0&&initial.FreeCargo<1)throw new InvalidOperationException("Sell the authorized single limpet before the cheap 1t test.");
using var stop=new CancellationTokenSource(TimeSpan.FromSeconds(80));
await using var protection=await FlightTestProtectionScope.ArmAsync(pid);var pipe=new NavigationPipeClient(pid);
async Task<JsonElement> Wait(ulong generation)
{
while(true)
{
var result=await pipe.CallAsync(new{op="commerce.market.status",generation},stop.Token);
if(result.GetProperty("state").GetInt32()>=3)return result;
await Task.Delay(80,stop.Token);
}
}
async Task<JsonElement> ReadMarket()
{
var queued=await pipe.CallAsync(new{op="commerce.market.read",marketId=(uint)market},stop.Token);
var result=await Wait(queued.GetProperty("generation").GetUInt64());
if(result.GetProperty("state").GetInt32()!=3)throw new InvalidOperationException("Original current-market read failed.");return result;
}
var started=DateTimeOffset.UtcNow;JsonElement? receipt=null,after=null,serverAfter=null;var key=Guid.NewGuid().ToString("N");string? failure=null;
var before=await pipe.CallAsync(new{op="commerce.inventory"},stop.Token);
try
{
await ReadMarket();
var current=journal.State;
if(!current.InGame||!current.Docked||current.MarketId!=market||current.CommanderId!=initial.CommanderId||current.CurrentShipId!=initial.CurrentShipId||current.LoadGameAt!=initial.LoadGameAt)
throw new InvalidOperationException("Acceptance session or docking identity changed before the order.");
var queued=await pipe.CallAsync(new{op="commerce.trade",marketId=(uint)market,commodityId=id,quantityDelta=delta,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 order result is not confirmed; never resend this operation key.");
after=await pipe.CallAsync(new{op="commerce.inventory"},stop.Token);
var price=receipt.Value.GetProperty("unitPrice").GetInt64();
if(price is <=0 or >500||after.Value.GetProperty("count").GetInt32()!=before.GetProperty("count").GetInt32()+delta
||after.Value.GetProperty("credits").GetInt64()!=before.GetProperty("credits").GetInt64()-price*delta)
throw new InvalidOperationException("The original cargo or wallet does not match the confirmed server order.");
serverAfter=await ReadMarket();
var actual=serverAfter.Value.GetProperty("cargo").TryGetProperty(commodity,out var amount)?amount.GetInt32():0;
if(actual!=receipt.Value.GetProperty("after").GetInt32())throw new InvalidOperationException("A second original server read did not confirm the new inventory.");
var cargoDeadline=DateTimeOffset.UtcNow.AddSeconds(5);
while(journal.State.CargoCount!=after.Value.GetProperty("count").GetInt32())
{
if(DateTimeOffset.UtcNow>=cargoDeadline)throw new InvalidOperationException("The game's actual Cargo.json has not confirmed the new cargo count.");
await Task.Delay(100,stop.Token);
}
}
catch(Exception error){failure=error.ToString();}
var passed=failure is null;
await File.WriteAllTextAsync(reportPath,JsonSerializer.Serialize(new{pid,started,finished=DateTimeOffset.UtcNow,commodity,delta,market,key,passed,before,receipt,after,serverAfter,
journalCargoCount=journal.State.CargoCount,journalCargoAt=journal.State.CargoAt,failure,screenUse=false,osInputsSent=0,journalEventsSynthesized=0,completeTradeCycleAccepted=false},ToolboxSettings.JsonOptions));
Console.WriteLine(JsonSerializer.Serialize(new{passed,commodity,delta,market,failure,screenUse=false,journalEventsSynthesized=0}));
if(!passed)throw new InvalidOperationException("The original 1t market-order acceptance did not pass.");
}
}