using System.Diagnostics;
using System.Globalization;
using System.Text.Json;
using XFEEDToolBox.Core.Data;
using XFEEDToolBox.Core.Models;
using XFEEDToolBox.Core.Native;
using XFEEDToolBox.Core.Navigation;
internal static class LocalTargetSelection
{
public static async Task RunAsync(int pid,string exactName,string reportPath)
{
if(File.Exists(reportPath))throw new IOException("Use a new report path.");
using var timeout=new CancellationTokenSource(TimeSpan.FromSeconds(15));var token=timeout.Token;
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 pipe=new NavigationPipeClient(pid);var hello=await pipe.CallAsync(new{op="describe"},token);var owner=Guid.NewGuid().ToString("N");
using var source=new NativeCurrentSystemSource(pid,hello.GetProperty("gameSha256").GetString()!,()=>journal.State);
var before=await source.ReadLocationsAsync(token);var target=before.Locations.Single(x=>x.Name.Equals(exactName,StringComparison.Ordinal));
JsonElement selection=JsonSerializer.SerializeToElement<object?>(null),telemetry=selection;CurrentSystemSnapshot? after=null;var selected=false;string? failure=null;
try
{
selection=await pipe.CallAsync(new{op="local.select",owner,key=target.Key,bodyAddress=target.WorldAddress.ToString(CultureInfo.InvariantCulture),kind=target.NativeKind,
marketId=target.MarketId??uint.MaxValue,name=target.Name},token);
var generation=selection.GetProperty("generation").GetInt64();var wait=Stopwatch.StartNew();
while(!selection.GetProperty("selected").GetBoolean())
{
if(!selection.GetProperty("pending").GetBoolean()||wait.Elapsed>TimeSpan.FromSeconds(2))throw new InvalidOperationException("Original local target selection did not confirm.");
await Task.Delay(30,token);selection=await pipe.CallAsync(new{op="local.status",owner,generation},token);
}
await Task.Delay(100,token);telemetry=await pipe.CallAsync(new{op="local.read"},token);after=await source.ReadLocationsAsync(token);
var row=after.Locations.Single(x=>x.Selected);
selected=row.Identity==target.Identity&&telemetry.GetProperty("target").GetProperty("name").GetString()==target.Name
&&telemetry.GetProperty("target").GetProperty("bodyAddress").GetString()==target.WorldAddress.ToString(CultureInfo.InvariantCulture)
&&telemetry.GetProperty("target").GetProperty("key").GetInt32()==target.Key
&&row.DistanceMetres is {} distance&&Math.Abs(telemetry.GetProperty("distanceMetres").GetDouble()-distance)<Math.Max(10,distance*.0001);
if(!selected)throw new InvalidDataException("Selected target or independently read distance differs.");
}
catch(Exception error){failure=error.ToString();}
finally{await pipe.CallAsync(new{op="release",owner},CancellationToken.None);}
await File.WriteAllTextAsync(reportPath,JsonSerializer.Serialize(new{pid,target,selection,telemetry,independentSelection=after?.Locations.FirstOrDefault(x=>x.Selected),selected,failure,flightInputsSent=0},ToolboxSettings.JsonOptions));
Console.WriteLine(JsonSerializer.Serialize(new{selected,target.Name,target.DistanceMetres,failure,reportPath,flightInputsSent=0}));
if(!selected)throw new InvalidOperationException("Local target acceptance failed; inspect report.");
}
}
using System.Diagnostics;
using System.Globalization;
using System.Text.Json;
using XFEEDToolBox.Core.Data;
using XFEEDToolBox.Core.Models;
using XFEEDToolBox.Core.Native;
using XFEEDToolBox.Core.Navigation;
internal static class LocalTargetSelection
{
public static async Task RunAsync(int pid,string exactName,string reportPath)
{
if(File.Exists(reportPath))throw new IOException("Use a new report path.");
using var timeout=new CancellationTokenSource(TimeSpan.FromSeconds(15));var token=timeout.Token;
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 pipe=new NavigationPipeClient(pid);var hello=await pipe.CallAsync(new{op="describe"},token);var owner=Guid.NewGuid().ToString("N");
using var source=new NativeCurrentSystemSource(pid,hello.GetProperty("gameSha256").GetString()!,()=>journal.State);
var before=await source.ReadLocationsAsync(token);var target=before.Locations.Single(x=>x.Name.Equals(exactName,StringComparison.Ordinal));
JsonElement selection=JsonSerializer.SerializeToElement<object?>(null),telemetry=selection;CurrentSystemSnapshot? after=null;var selected=false;string? failure=null;
try
{
selection=await pipe.CallAsync(new{op="local.select",owner,key=target.Key,bodyAddress=target.WorldAddress.ToString(CultureInfo.InvariantCulture),kind=target.NativeKind,
marketId=target.MarketId??uint.MaxValue,name=target.Name},token);
var generation=selection.GetProperty("generation").GetInt64();var wait=Stopwatch.StartNew();
while(!selection.GetProperty("selected").GetBoolean())
{
if(!selection.GetProperty("pending").GetBoolean()||wait.Elapsed>TimeSpan.FromSeconds(2))throw new InvalidOperationException("Original local target selection did not confirm.");
await Task.Delay(30,token);selection=await pipe.CallAsync(new{op="local.status",owner,generation},token);
}
await Task.Delay(100,token);telemetry=await pipe.CallAsync(new{op="local.read"},token);after=await source.ReadLocationsAsync(token);
var row=after.Locations.Single(x=>x.Selected);
selected=row.Identity==target.Identity&&telemetry.GetProperty("target").GetProperty("name").GetString()==target.Name
&&telemetry.GetProperty("target").GetProperty("bodyAddress").GetString()==target.WorldAddress.ToString(CultureInfo.InvariantCulture)
&&telemetry.GetProperty("target").GetProperty("key").GetInt32()==target.Key
&&row.DistanceMetres is {} distance&&Math.Abs(telemetry.GetProperty("distanceMetres").GetDouble()-distance)<Math.Max(10,distance*.0001);
if(!selected)throw new InvalidDataException("Selected target or independently read distance differs.");
}
catch(Exception error){failure=error.ToString();}
finally{await pipe.CallAsync(new{op="release",owner},CancellationToken.None);}
await File.WriteAllTextAsync(reportPath,JsonSerializer.Serialize(new{pid,target,selection,telemetry,independentSelection=after?.Locations.FirstOrDefault(x=>x.Selected),selected,failure,flightInputsSent=0},ToolboxSettings.JsonOptions));
Console.WriteLine(JsonSerializer.Serialize(new{selected,target.Name,target.DistanceMetres,failure,reportPath,flightInputsSent=0}));
if(!selected)throw new InvalidOperationException("Local target acceptance failed; inspect report.");
}
}