using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using XFEEDToolBox.Core.Galaxy;
using XFEEDToolBox.Core.Navigation;
namespace XFEEDToolBox.ViewModels;
public partial class ToolboxViewModel
{
[ObservableProperty] public partial IReadOnlyList<GalaxyThargoidCountDisplay> GalaxyThargoidCounts { get;set; }=[];
[ObservableProperty] public partial IReadOnlyList<GalaxyThargoidTarget> GalaxyThargoidSignals { get;set; }=[];
[ObservableProperty] public partial IReadOnlyList<GalaxyThargoidTarget> GalaxyThargoidRecommendations { get;set; }=[];
[ObservableProperty] public partial string GalaxyThargoidStatus { get;set; }="原游戏 Thargoid 缓存尚未连接;状态计数未知。";
private DateTimeOffset galaxyThargoidReadAt;
private string galaxyThargoidContext="";
private IReadOnlyDictionary<long,int?> galaxyThargoidObservedStates=new Dictionary<long,int?>();
private string ThargoidContext()=>CurrentPlayer.InGame&&runtime.FlightDriver is NativeFlightControlDriver driver
?$"{driver.ProcessId}|{CurrentPlayer.CommanderId}|{CurrentPlayer.LoadGameAt:O}":"";
private void ClearGalaxyThargoid(string status)
{
if(GalaxyThargoidCounts.Count>0)GalaxyThargoidCounts=[];
if(GalaxyThargoidSignals.Count>0)GalaxyThargoidSignals=[];
if(GalaxyThargoidRecommendations.Count>0)GalaxyThargoidRecommendations=[];
galaxyThargoidContext="";GalaxyThargoidStatus=status;
if(galaxyThargoidObservedStates.Count>0){galaxyThargoidObservedStates=new Dictionary<long,int?>();galaxyNativeFactsVersion++;}
}
private async Task ReadGalaxyThargoidAsync(CancellationToken token)
{
var context=ThargoidContext();
if(galaxyThargoidContext.Length>0&&galaxyThargoidContext!=context)
{ClearGalaxyThargoid("游戏会话已变化;旧 Thargoid 缓存已清除。原计数未知。");galaxyThargoidReadAt=default;}
if(DateTimeOffset.UtcNow-galaxyThargoidReadAt<TimeSpan.FromSeconds(2))return;
galaxyThargoidReadAt=DateTimeOffset.UtcNow;
if(context.Length==0||runtime.FlightDriver is not NativeFlightControlDriver{SupportsGalaxyThargoid:true} driver)
{ClearGalaxyThargoid("原游戏 Thargoid 缓存尚未连接;状态计数未知。");return;}
bool Latest()=>context==ThargoidContext();
try
{
var snapshot=await new NativeGalaxyAccountCatalog(driver.ProcessId).ReadThargoidAsync(token);
token.ThrowIfCancellationRequested();if(!Latest())return;
if(!snapshot.Available){ClearGalaxyThargoid("原游戏 Thargoid 服务尚未就绪;状态计数未知。");return;}
var addresses=snapshot.Signals.Select(s=>s.SystemAddress).Concat(snapshot.Recommended.Select(s=>s.SystemAddress)).ToHashSet();
var names=galaxyCache.Values.Where(s=>s.SystemAddress is {} address&&addresses.Contains(address)&&s.Position.IsValid).GroupBy(s=>s.SystemAddress!.Value).ToDictionary(g=>g.Key,g=>g.First().Name);
GalaxyThargoidTarget Name(GalaxyThargoidTarget item)=>names.TryGetValue(item.SystemAddress,out var name)?item with{SystemName=name}:item;
var counts=GalaxyThargoidPresentation.Counts(snapshot);var signals=GalaxyThargoidPresentation.Signals(snapshot).Select(Name).ToArray();var recommendations=GalaxyThargoidPresentation.Recommendations(snapshot).Select(Name).ToArray();
var observed=GalaxyThargoidPresentation.ObservedStates(snapshot);if(observed.Count!=galaxyThargoidObservedStates.Count||observed.Any(x=>!galaxyThargoidObservedStates.TryGetValue(x.Key,out var state)||state!=x.Value)){galaxyThargoidObservedStates=observed;galaxyNativeFactsVersion++;}
if(!GalaxyThargoidCounts.SequenceEqual(counts))GalaxyThargoidCounts=counts;
if(!GalaxyThargoidSignals.SequenceEqual(signals))GalaxyThargoidSignals=signals;
if(!GalaxyThargoidRecommendations.SequenceEqual(recommendations))GalaxyThargoidRecommendations=recommendations;
galaxyThargoidContext=context;
GalaxyThargoidStatus=$"原缓存 · {signals.Length:N0} 个信号 · {recommendations.Length:N0} 个推荐"+(snapshot.Ready?";计数来自现有缓存,全球完整性未确认。":";源尚未就绪,保留已有条目,状态计数未知。");
}
catch(OperationCanceledException)when(!token.IsCancellationRequested)
{if(Latest())ClearGalaxyThargoid("原游戏 Thargoid 缓存读取超时;计数保持未知。");}
catch(Exception error)when(error is IOException or TimeoutException or InvalidDataException or InvalidOperationException or System.Text.Json.JsonException or KeyNotFoundException or FormatException)
{if(Latest())ClearGalaxyThargoid("原游戏 Thargoid 缓存尚未确认:"+error.Message);}
}
[RelayCommand] private async Task SelectGalaxyThargoidTargetAsync(GalaxyThargoidTarget? target)
{
if(target is null||galaxyThargoidContext.Length==0||galaxyThargoidContext!=ThargoidContext())return;
var context=galaxyThargoidContext;var request=++galaxyMapTargetSelectionVersion;
bool Listed()=>GalaxyThargoidSignals.Concat(GalaxyThargoidRecommendations).Any(t=>t.Kind==target.Kind&&t.Id==target.Id&&t.SystemAddress==target.SystemAddress);
bool Latest()=>request==galaxyMapTargetSelectionVersion&&context==ThargoidContext()&&context==galaxyThargoidContext&&Listed();
if(!Listed())return;
try
{
var system=galaxyCache.Values.FirstOrDefault(s=>s.SystemAddress==target.SystemAddress&&s.Position.IsValid&&!string.IsNullOrWhiteSpace(s.Name));
if(system is null)
{
if(runtime.FlightDriver is not NativeFlightControlDriver{SupportsGalaxyResolveAddress:true}||NativeGalaxy() is not {} catalog)
{GalaxyThargoidStatus="已知原信号地址,尚未连接精确地址解析;没有坐标时不能定位。";return;}
GalaxyThargoidStatus="正在读取原目标的实际坐标…";
system=await catalog.ResolveAddressAsync(target.SystemAddress,lifetime.Token);
}
if(!Latest())return;
if(system.SystemAddress!=target.SystemAddress||!system.Position.IsValid)throw new InvalidDataException("目标地址与实际目录记录不一致。");
system=RememberGalaxy(system);GalaxySelection=system;GalaxyCentre=system.Position;PublishGalaxy();
GalaxyThargoidStatus=target.Label+" · 已按原星系地址定位 "+system.Name;
}
catch(OperationCanceledException){ }
catch(Exception error)when(error is IOException or TimeoutException or InvalidDataException or InvalidOperationException or KeyNotFoundException or System.Text.Json.JsonException)
{if(Latest())GalaxyThargoidStatus="原目标定位尚未完成:"+error.Message;}
}
}
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using XFEEDToolBox.Core.Galaxy;
using XFEEDToolBox.Core.Navigation;
namespace XFEEDToolBox.ViewModels;
public partial class ToolboxViewModel
{
[ObservableProperty] public partial IReadOnlyList<GalaxyThargoidCountDisplay> GalaxyThargoidCounts { get;set; }=[];
[ObservableProperty] public partial IReadOnlyList<GalaxyThargoidTarget> GalaxyThargoidSignals { get;set; }=[];
[ObservableProperty] public partial IReadOnlyList<GalaxyThargoidTarget> GalaxyThargoidRecommendations { get;set; }=[];
[ObservableProperty] public partial string GalaxyThargoidStatus { get;set; }="原游戏 Thargoid 缓存尚未连接;状态计数未知。";
private DateTimeOffset galaxyThargoidReadAt;
private string galaxyThargoidContext="";
private IReadOnlyDictionary<long,int?> galaxyThargoidObservedStates=new Dictionary<long,int?>();
private string ThargoidContext()=>CurrentPlayer.InGame&&runtime.FlightDriver is NativeFlightControlDriver driver
?$"{driver.ProcessId}|{CurrentPlayer.CommanderId}|{CurrentPlayer.LoadGameAt:O}":"";
private void ClearGalaxyThargoid(string status)
{
if(GalaxyThargoidCounts.Count>0)GalaxyThargoidCounts=[];
if(GalaxyThargoidSignals.Count>0)GalaxyThargoidSignals=[];
if(GalaxyThargoidRecommendations.Count>0)GalaxyThargoidRecommendations=[];
galaxyThargoidContext="";GalaxyThargoidStatus=status;
if(galaxyThargoidObservedStates.Count>0){galaxyThargoidObservedStates=new Dictionary<long,int?>();galaxyNativeFactsVersion++;}
}
private async Task ReadGalaxyThargoidAsync(CancellationToken token)
{
var context=ThargoidContext();
if(galaxyThargoidContext.Length>0&&galaxyThargoidContext!=context)
{ClearGalaxyThargoid("游戏会话已变化;旧 Thargoid 缓存已清除。原计数未知。");galaxyThargoidReadAt=default;}
if(DateTimeOffset.UtcNow-galaxyThargoidReadAt<TimeSpan.FromSeconds(2))return;
galaxyThargoidReadAt=DateTimeOffset.UtcNow;
if(context.Length==0||runtime.FlightDriver is not NativeFlightControlDriver{SupportsGalaxyThargoid:true} driver)
{ClearGalaxyThargoid("原游戏 Thargoid 缓存尚未连接;状态计数未知。");return;}
bool Latest()=>context==ThargoidContext();
try
{
var snapshot=await new NativeGalaxyAccountCatalog(driver.ProcessId).ReadThargoidAsync(token);
token.ThrowIfCancellationRequested();if(!Latest())return;
if(!snapshot.Available){ClearGalaxyThargoid("原游戏 Thargoid 服务尚未就绪;状态计数未知。");return;}
var addresses=snapshot.Signals.Select(s=>s.SystemAddress).Concat(snapshot.Recommended.Select(s=>s.SystemAddress)).ToHashSet();
var names=galaxyCache.Values.Where(s=>s.SystemAddress is {} address&&addresses.Contains(address)&&s.Position.IsValid).GroupBy(s=>s.SystemAddress!.Value).ToDictionary(g=>g.Key,g=>g.First().Name);
GalaxyThargoidTarget Name(GalaxyThargoidTarget item)=>names.TryGetValue(item.SystemAddress,out var name)?item with{SystemName=name}:item;
var counts=GalaxyThargoidPresentation.Counts(snapshot);var signals=GalaxyThargoidPresentation.Signals(snapshot).Select(Name).ToArray();var recommendations=GalaxyThargoidPresentation.Recommendations(snapshot).Select(Name).ToArray();
var observed=GalaxyThargoidPresentation.ObservedStates(snapshot);if(observed.Count!=galaxyThargoidObservedStates.Count||observed.Any(x=>!galaxyThargoidObservedStates.TryGetValue(x.Key,out var state)||state!=x.Value)){galaxyThargoidObservedStates=observed;galaxyNativeFactsVersion++;}
if(!GalaxyThargoidCounts.SequenceEqual(counts))GalaxyThargoidCounts=counts;
if(!GalaxyThargoidSignals.SequenceEqual(signals))GalaxyThargoidSignals=signals;
if(!GalaxyThargoidRecommendations.SequenceEqual(recommendations))GalaxyThargoidRecommendations=recommendations;
galaxyThargoidContext=context;
GalaxyThargoidStatus=$"原缓存 · {signals.Length:N0} 个信号 · {recommendations.Length:N0} 个推荐"+(snapshot.Ready?";计数来自现有缓存,全球完整性未确认。":";源尚未就绪,保留已有条目,状态计数未知。");
}
catch(OperationCanceledException)when(!token.IsCancellationRequested)
{if(Latest())ClearGalaxyThargoid("原游戏 Thargoid 缓存读取超时;计数保持未知。");}
catch(Exception error)when(error is IOException or TimeoutException or InvalidDataException or InvalidOperationException or System.Text.Json.JsonException or KeyNotFoundException or FormatException)
{if(Latest())ClearGalaxyThargoid("原游戏 Thargoid 缓存尚未确认:"+error.Message);}
}
[RelayCommand] private async Task SelectGalaxyThargoidTargetAsync(GalaxyThargoidTarget? target)
{
if(target is null||galaxyThargoidContext.Length==0||galaxyThargoidContext!=ThargoidContext())return;
var context=galaxyThargoidContext;var request=++galaxyMapTargetSelectionVersion;
bool Listed()=>GalaxyThargoidSignals.Concat(GalaxyThargoidRecommendations).Any(t=>t.Kind==target.Kind&&t.Id==target.Id&&t.SystemAddress==target.SystemAddress);
bool Latest()=>request==galaxyMapTargetSelectionVersion&&context==ThargoidContext()&&context==galaxyThargoidContext&&Listed();
if(!Listed())return;
try
{
var system=galaxyCache.Values.FirstOrDefault(s=>s.SystemAddress==target.SystemAddress&&s.Position.IsValid&&!string.IsNullOrWhiteSpace(s.Name));
if(system is null)
{
if(runtime.FlightDriver is not NativeFlightControlDriver{SupportsGalaxyResolveAddress:true}||NativeGalaxy() is not {} catalog)
{GalaxyThargoidStatus="已知原信号地址,尚未连接精确地址解析;没有坐标时不能定位。";return;}
GalaxyThargoidStatus="正在读取原目标的实际坐标…";
system=await catalog.ResolveAddressAsync(target.SystemAddress,lifetime.Token);
}
if(!Latest())return;
if(system.SystemAddress!=target.SystemAddress||!system.Position.IsValid)throw new InvalidDataException("目标地址与实际目录记录不一致。");
system=RememberGalaxy(system);GalaxySelection=system;GalaxyCentre=system.Position;PublishGalaxy();
GalaxyThargoidStatus=target.Label+" · 已按原星系地址定位 "+system.Name;
}
catch(OperationCanceledException){ }
catch(Exception error)when(error is IOException or TimeoutException or InvalidDataException or InvalidOperationException or KeyNotFoundException or System.Text.Json.JsonException)
{if(Latest())GalaxyThargoidStatus="原目标定位尚未完成:"+error.Message;}
}
}