using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Microsoft.UI.Dispatching;
using XFEEDToolBox.Core.Native;
using XFEEDToolBox.Core.Navigation;
using XFEEDToolBox.Core.Presentation;
using XFEEDToolBox.Core.Services;
namespace XFEEDToolBox.ViewModels;
public partial class ToolboxViewModel
{
public LiveCollection<SystemLocationLiveRow,SystemLocation,string> CurrentSystemLocations{get;}=new(x=>x.Identity,x=>new(x));
[ObservableProperty] public partial string CurrentSystemTitle{get;set;}="当前星系";
[ObservableProperty] public partial string CurrentSystemSearch{get;set;}="";
[ObservableProperty] public partial string CurrentSystemStatus{get;set;}="等待读取游戏中的导航地点。";
[ObservableProperty] public partial string SystemFlightStatus{get;set;}="选择地点后检查可用驾驶方式。";
[ObservableProperty] public partial string SystemSceneStatus{get;set;}="等待读取真实地点坐标";
[ObservableProperty] public partial string SystemControlAvailability{get;set;}="等待驾驶接口。";
[ObservableProperty] public partial bool CurrentSystemReading{get;set;}
[ObservableProperty] public partial bool SystemFlightActive{get;set;}
[ObservableProperty] public partial bool SystemFlightReady{get;set;}
[ObservableProperty,NotifyCanExecuteChangedFor(nameof(StartSystemFlightCommand))] public partial SystemLocationLiveRow? SelectedSystemLocation{get;set;}
[ObservableProperty] public partial bool ShowSystemStars{get;set;}
[ObservableProperty] public partial bool ShowSystemAsteroids{get;set;}
[ObservableProperty] public partial bool ShowSystemPlanets{get;set;}
[ObservableProperty] public partial bool ShowSystemLandablePlanets{get;set;}
[ObservableProperty] public partial bool ShowSystemSettlements{get;set;}
[ObservableProperty] public partial bool ShowSystemStations{get;set;}
[ObservableProperty] public partial bool ShowSystemCarriers{get;set;}
[ObservableProperty] public partial bool ShowSystemPoints{get;set;}
[ObservableProperty] public partial bool ShowSystemSignals{get;set;}
[ObservableProperty] public partial bool ShowSystemOther{get;set;}
private NativeCurrentSystemSource? currentSystemSource;
private CurrentSystemSnapshot? currentSystemSnapshot;
private DispatcherQueueTimer? currentSystemTimer;
private int currentSystemViewCount,currentSystemPid;
private bool currentSystemReadInProgress;
private int currentSystemReadFailures;
private string currentSystemGameHash="";
private ISystemFlightControlDriver? currentSystemCapabilityDriver;
private SystemNavigationCapabilities? currentSystemCapabilities;
private DateTimeOffset currentSystemCapabilitiesReadAt;
private readonly SystemNavigationRunner systemNavigator;
private CancellationTokenSource? systemFlightStop;
internal CurrentSystemSnapshot? CurrentSystemSceneSnapshot=>currentSystemSnapshot;
internal event Action? CurrentSystemSceneChanged;
public string SelectedSystemTitle=>SelectedSystemLocation?.Name??"选择目的地";
public string SelectedSystemKind=>SelectedSystemLocation?.Record.KindText??"在场景或地点列表中选择";
public string SelectedSystemDistance=>SelectedSystemLocation?.Distance??"—";
public string SelectedSystemPositionStatus=>SelectedSystemLocation is null?"选中地点后查看驾驶方式":SelectedSystemLocation.Record.Position is {Finite:true}?"游戏坐标已读取":"坐标待确认 · 仍保留在地点列表";
partial void OnSelectedSystemLocationChanged(SystemLocationLiveRow? value)
{
OnPropertyChanged(nameof(SelectedSystemTitle));OnPropertyChanged(nameof(SelectedSystemKind));OnPropertyChanged(nameof(SelectedSystemDistance));OnPropertyChanged(nameof(SelectedSystemPositionStatus));
UpdateSystemControlAvailability();
}
private static bool CurrentGameProcessAlive(int pid)
{
try{using var process=System.Diagnostics.Process.GetProcessById(pid);return !process.HasExited&&process.ProcessName.Equals("EliteDangerous64",StringComparison.OrdinalIgnoreCase);}
catch(Exception error)when(error is ArgumentException or InvalidOperationException or System.ComponentModel.Win32Exception){return false;}
}
partial void OnCurrentSystemSearchChanged(string value)=>FilterSystemLocations();
partial void OnShowSystemStarsChanged(bool value)=>FilterSystemLocations();
partial void OnShowSystemAsteroidsChanged(bool value)=>FilterSystemLocations();
partial void OnShowSystemPlanetsChanged(bool value)=>FilterSystemLocations();
partial void OnShowSystemLandablePlanetsChanged(bool value)=>FilterSystemLocations();
partial void OnShowSystemSettlementsChanged(bool value)=>FilterSystemLocations();
partial void OnShowSystemStationsChanged(bool value)=>FilterSystemLocations();
partial void OnShowSystemCarriersChanged(bool value)=>FilterSystemLocations();
partial void OnShowSystemPointsChanged(bool value)=>FilterSystemLocations();
partial void OnShowSystemSignalsChanged(bool value)=>FilterSystemLocations();
partial void OnShowSystemOtherChanged(bool value)=>FilterSystemLocations();
partial void OnSystemFlightReadyChanged(bool value)=>StartSystemFlightCommand.NotifyCanExecuteChanged();
private void FilterSystemLocations(bool keepOrder=false)
{
if(currentSystemSnapshot is not {} snapshot)return;
var categories=SystemLocationCategory.None;
void Add(bool show,SystemLocationCategory category){if(show)categories|=category;}
Add(ShowSystemStars,SystemLocationCategory.Star);Add(ShowSystemAsteroids,SystemLocationCategory.Asteroid);Add(ShowSystemPlanets,SystemLocationCategory.Planet);
Add(ShowSystemLandablePlanets,SystemLocationCategory.LandablePlanet);Add(ShowSystemSettlements,SystemLocationCategory.Settlement);Add(ShowSystemStations,SystemLocationCategory.Station);
Add(ShowSystemCarriers,SystemLocationCategory.Carrier);Add(ShowSystemPoints,SystemLocationCategory.PointOfInterest);Add(ShowSystemSignals,SystemLocationCategory.Signal);Add(ShowSystemOther,SystemLocationCategory.Other);
var selected=SelectedSystemLocation?.Record.Identity;
CurrentSystemLocations.ApplyLocations(new SystemLocationFilter(categories,CurrentSystemSearch).Apply(snapshot),sortExisting:!keepOrder);
SelectedSystemLocation=CurrentSystemLocations.FirstOrDefault(r=>r.Record.Identity==selected);
CurrentSystemStatus=$"{CurrentSystemLocations.Count} / {snapshot.Locations.Count} 个地点";
OnPropertyChanged(nameof(SelectedSystemDistance));OnPropertyChanged(nameof(SelectedSystemPositionStatus));
CurrentSystemSceneChanged?.Invoke();
}
internal void ShowCurrentSystem()
{
if(OfflinePreview)return;
currentSystemViewCount++;
if(currentSystemTimer is null){currentSystemTimer=dispatcher.CreateTimer();currentSystemTimer.Interval=TimeSpan.FromSeconds(3);currentSystemTimer.Tick+=async(_,_)=>await RefreshCurrentSystemAsync();}
currentSystemTimer.Start();_=RefreshCurrentSystemAsync();
}
internal void HideCurrentSystem(){currentSystemViewCount=Math.Max(0,currentSystemViewCount-1);if(currentSystemViewCount==0)currentSystemTimer?.Stop();}
[RelayCommand] private async Task RefreshCurrentSystemAsync()
{
if(OfflinePreview)return;
if(currentSystemReadInProgress)return;
currentSystemReadInProgress=true;
CurrentSystemReading=currentSystemSnapshot is null;
try
{
if(DemoMode||!runtime.Player.InGame)
{
CurrentSystemStatus="请进入游戏后查看当前星系地点。";CurrentSystemLocations.Apply([]);currentSystemSnapshot=null;SelectedSystemLocation=null;SystemFlightReady=false;
CurrentSystemSceneChanged?.Invoke();UpdateSystemControlAvailability();runtime.ReportStatus("current-system.wait","当前星系","等待进入驾驶场景。");return;
}
// The driver may still belong to a game process that has exited.
// Refresh the environment independently and bind reads to its live PID.
// Checking the PID is cheap; hashing the game image every thirty
// seconds is not. Re-discover only on process loss or read failure.
if(gameEnvironment?.ProcessId is not >0||!CurrentGameProcessAlive(gameEnvironment.ProcessId.Value))
await ReadEnvironmentAsync();
var pid=gameEnvironment?.ProcessId??0;
var hash=gameEnvironment?.ImageSha256??"";
if(pid<=0||hash.Length!=64){await ReadEnvironmentAsync();pid=gameEnvironment?.ProcessId??0;hash=gameEnvironment?.ImageSha256??"";}
if(pid<=0)throw new FlightTelemetryUnavailableException("等待当前游戏实例。");
if(currentSystemSource is null||currentSystemPid!=pid||currentSystemGameHash!=hash)
{currentSystemSource?.Dispose();currentSystemSource=new(pid,hash,()=>runtime.Player,snapshot=>runtime.Journal.SystemOrbits.Bind(snapshot));currentSystemPid=pid;currentSystemGameHash=hash;currentSystemCapabilityDriver=null;currentSystemCapabilities=null;}
var next=await currentSystemSource.ReadLocationsAsync(lifetime.Token);
if(runtime.Player.Navigation.CurrentSystemAddress!=next.SystemAddress)return;
ApplyCurrentSystemSnapshot(next);
currentSystemReadFailures=0;
await RefreshCurrentSystemControlAsync(pid,hash,lifetime.Token);
runtime.ResolveDiagnostic("current-system.read","当前星系","地点读取已恢复。");
runtime.ResolveDiagnostic("current-system.read-stalled","当前星系","地点遥测已恢复。");
runtime.ReportStatus("current-system.wait","当前星系",$"已读取 {next.Locations.Count} 个真实地点。");
}
catch(OperationCanceledException)when(lifetime.IsCancellationRequested){}
catch(Exception error)when(NavigationRecovery.CanRetry(error,lifetime.Token))
{
HandleCurrentSystemReadFailure();
runtime.ReportStatus("current-system.wait","当前星系","正在等待驾驶场景和最新地点遥测,恢复后自动刷新。");
if(currentSystemReadFailures>=10)runtime.ReportDiagnostic("current-system.read-stalled","当前星系",error,ActivitySeverity.Warning,"地点遥测持续未就绪,保留最近目录,暂不允许启动驾驶。");
}
catch(Exception error)
{
HandleCurrentSystemReadFailure();CurrentSystemStatus="地点接口暂不可用:"+error.Message;
runtime.ReportDiagnostic("current-system.read","当前星系",error,error is NotSupportedException?ActivitySeverity.Warning:ActivitySeverity.Error,"地点读取失败:"+error.Message);
}
finally{currentSystemReadInProgress=false;CurrentSystemReading=false;}
}
internal void ApplyCurrentSystemSnapshot(CurrentSystemSnapshot snapshot)
{
if(currentSystemSnapshot?.SystemAddress!=snapshot.SystemAddress)SelectedSystemLocation=null;
currentSystemSnapshot=snapshot;CurrentSystemTitle=snapshot.SystemName;FilterSystemLocations(keepOrder:true);
}
private void HandleCurrentSystemReadFailure()
{
SystemFlightReady=false;currentSystemReadFailures++;CurrentSystemStatus="正在重新读取当前星系地点…";
if(currentSystemSnapshot?.SystemAddress!=runtime.Player.Navigation.CurrentSystemAddress)
{currentSystemSnapshot=null;CurrentSystemLocations.Apply([]);SelectedSystemLocation=null;CurrentSystemSceneChanged?.Invoke();}
UpdateSystemControlAvailability();
}
private bool CanStartSystemFlight()=>SystemFlightReady&&CurrentSystemTargetIssue() is null&&!SystemFlightActive&&!NavigationActive&&!RunActive&&!SessionBusy&&!runtime.FlightAutomation.IsActive;
[RelayCommand(CanExecute=nameof(CanStartSystemFlight))] private async Task StartSystemFlightAsync()
{
if(!CanStartSystemFlight()||SelectedSystemLocation is not {} selected||currentSystemSnapshot is not {} snapshot)return;
if(currentSystemCapabilityDriver is not {} driver)return;
var row=selected.Record;
var target=SystemTarget(snapshot,row);
using var stop=CancellationTokenSource.CreateLinkedTokenSource(lifetime.Token);systemFlightStop=stop;SystemFlightActive=true;StartSystemFlightCommand.NotifyCanExecuteChanged();
try
{
shipProtection?.RequireHealthyShip();var result=await Task.Run(()=>runtime.FlightAutomation.NavigateLocalAsync(target,driver,stop.Token),stop.Token);
if(result.Failure is {} failure)
runtime.ReportDiagnostic("current-system.flight","星系内驾驶",failure,ActivitySeverity.Error,"驾驶已停止:"+failure.Message);
else if(result.State==NavigationRunState.Completed)
runtime.ResolveDiagnostic("current-system.flight","星系内驾驶","已确认到达所选目的地。");
}
catch(OperationCanceledException){SystemFlightStatus="星系内导航已停止。";}
catch(Exception error){SystemFlightStatus=error.Message;runtime.ReportDiagnostic("current-system.flight","星系内驾驶",error,ActivitySeverity.Error,"驾驶未能启动:"+error.Message);}
finally{systemFlightStop=null;SystemFlightActive=false;StartSystemFlightCommand.NotifyCanExecuteChanged();}
}
[RelayCommand] private void StopSystemFlight(){systemFlightStop?.Cancel();runtime.FlightAutomation.Stop();systemNavigator.Stop();}
private void OnSystemFlightProgress(SystemNavigationProgress progress)=>dispatcher.TryEnqueue(()=>
{
SystemFlightStatus=progress.Message;if(runtime.FlightAutomation.ActiveEntry==FlightAutomationEntry.Galaxy)NavigationStatus=progress.Message;
if(progress.Diagnostic is {} diagnostic)
runtime.ReportDiagnostic("flight.telemetry-recovery","驾驶恢复",progress.Message,diagnostic,ActivitySeverity.Status);
else if(progress.Phase!=SystemNavigationPhase.Waiting)
runtime.ResolveDiagnostic("flight.telemetry-recovery","驾驶恢复",progress.State==NavigationRunState.Stopped?"自动驾驶已停止,原始诊断已保留。":"飞行数据已恢复,继续原航程。");
});
}
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Microsoft.UI.Dispatching;
using XFEEDToolBox.Core.Native;
using XFEEDToolBox.Core.Navigation;
using XFEEDToolBox.Core.Presentation;
using XFEEDToolBox.Core.Services;
namespace XFEEDToolBox.ViewModels;
public partial class ToolboxViewModel
{
public LiveCollection<SystemLocationLiveRow,SystemLocation,string> CurrentSystemLocations{get;}=new(x=>x.Identity,x=>new(x));
[ObservableProperty] public partial string CurrentSystemTitle{get;set;}="当前星系";
[ObservableProperty] public partial string CurrentSystemSearch{get;set;}="";
[ObservableProperty] public partial string CurrentSystemStatus{get;set;}="等待读取游戏中的导航地点。";
[ObservableProperty] public partial string SystemFlightStatus{get;set;}="选择地点后检查可用驾驶方式。";
[ObservableProperty] public partial string SystemSceneStatus{get;set;}="等待读取真实地点坐标";
[ObservableProperty] public partial string SystemControlAvailability{get;set;}="等待驾驶接口。";
[ObservableProperty] public partial bool CurrentSystemReading{get;set;}
[ObservableProperty] public partial bool SystemFlightActive{get;set;}
[ObservableProperty] public partial bool SystemFlightReady{get;set;}
[ObservableProperty,NotifyCanExecuteChangedFor(nameof(StartSystemFlightCommand))] public partial SystemLocationLiveRow? SelectedSystemLocation{get;set;}
[ObservableProperty] public partial bool ShowSystemStars{get;set;}
[ObservableProperty] public partial bool ShowSystemAsteroids{get;set;}
[ObservableProperty] public partial bool ShowSystemPlanets{get;set;}
[ObservableProperty] public partial bool ShowSystemLandablePlanets{get;set;}
[ObservableProperty] public partial bool ShowSystemSettlements{get;set;}
[ObservableProperty] public partial bool ShowSystemStations{get;set;}
[ObservableProperty] public partial bool ShowSystemCarriers{get;set;}
[ObservableProperty] public partial bool ShowSystemPoints{get;set;}
[ObservableProperty] public partial bool ShowSystemSignals{get;set;}
[ObservableProperty] public partial bool ShowSystemOther{get;set;}
private NativeCurrentSystemSource? currentSystemSource;
private CurrentSystemSnapshot? currentSystemSnapshot;
private DispatcherQueueTimer? currentSystemTimer;
private int currentSystemViewCount,currentSystemPid;
private bool currentSystemReadInProgress;
private int currentSystemReadFailures;
private string currentSystemGameHash="";
private ISystemFlightControlDriver? currentSystemCapabilityDriver;
private SystemNavigationCapabilities? currentSystemCapabilities;
private DateTimeOffset currentSystemCapabilitiesReadAt;
private readonly SystemNavigationRunner systemNavigator;
private CancellationTokenSource? systemFlightStop;
internal CurrentSystemSnapshot? CurrentSystemSceneSnapshot=>currentSystemSnapshot;
internal event Action? CurrentSystemSceneChanged;
public string SelectedSystemTitle=>SelectedSystemLocation?.Name??"选择目的地";
public string SelectedSystemKind=>SelectedSystemLocation?.Record.KindText??"在场景或地点列表中选择";
public string SelectedSystemDistance=>SelectedSystemLocation?.Distance??"—";
public string SelectedSystemPositionStatus=>SelectedSystemLocation is null?"选中地点后查看驾驶方式":SelectedSystemLocation.Record.Position is {Finite:true}?"游戏坐标已读取":"坐标待确认 · 仍保留在地点列表";
partial void OnSelectedSystemLocationChanged(SystemLocationLiveRow? value)
{
OnPropertyChanged(nameof(SelectedSystemTitle));OnPropertyChanged(nameof(SelectedSystemKind));OnPropertyChanged(nameof(SelectedSystemDistance));OnPropertyChanged(nameof(SelectedSystemPositionStatus));
UpdateSystemControlAvailability();
}
private static bool CurrentGameProcessAlive(int pid)
{
try{using var process=System.Diagnostics.Process.GetProcessById(pid);return !process.HasExited&&process.ProcessName.Equals("EliteDangerous64",StringComparison.OrdinalIgnoreCase);}
catch(Exception error)when(error is ArgumentException or InvalidOperationException or System.ComponentModel.Win32Exception){return false;}
}
partial void OnCurrentSystemSearchChanged(string value)=>FilterSystemLocations();
partial void OnShowSystemStarsChanged(bool value)=>FilterSystemLocations();
partial void OnShowSystemAsteroidsChanged(bool value)=>FilterSystemLocations();
partial void OnShowSystemPlanetsChanged(bool value)=>FilterSystemLocations();
partial void OnShowSystemLandablePlanetsChanged(bool value)=>FilterSystemLocations();
partial void OnShowSystemSettlementsChanged(bool value)=>FilterSystemLocations();
partial void OnShowSystemStationsChanged(bool value)=>FilterSystemLocations();
partial void OnShowSystemCarriersChanged(bool value)=>FilterSystemLocations();
partial void OnShowSystemPointsChanged(bool value)=>FilterSystemLocations();
partial void OnShowSystemSignalsChanged(bool value)=>FilterSystemLocations();
partial void OnShowSystemOtherChanged(bool value)=>FilterSystemLocations();
partial void OnSystemFlightReadyChanged(bool value)=>StartSystemFlightCommand.NotifyCanExecuteChanged();
private void FilterSystemLocations(bool keepOrder=false)
{
if(currentSystemSnapshot is not {} snapshot)return;
var categories=SystemLocationCategory.None;
void Add(bool show,SystemLocationCategory category){if(show)categories|=category;}
Add(ShowSystemStars,SystemLocationCategory.Star);Add(ShowSystemAsteroids,SystemLocationCategory.Asteroid);Add(ShowSystemPlanets,SystemLocationCategory.Planet);
Add(ShowSystemLandablePlanets,SystemLocationCategory.LandablePlanet);Add(ShowSystemSettlements,SystemLocationCategory.Settlement);Add(ShowSystemStations,SystemLocationCategory.Station);
Add(ShowSystemCarriers,SystemLocationCategory.Carrier);Add(ShowSystemPoints,SystemLocationCategory.PointOfInterest);Add(ShowSystemSignals,SystemLocationCategory.Signal);Add(ShowSystemOther,SystemLocationCategory.Other);
var selected=SelectedSystemLocation?.Record.Identity;
CurrentSystemLocations.ApplyLocations(new SystemLocationFilter(categories,CurrentSystemSearch).Apply(snapshot),sortExisting:!keepOrder);
SelectedSystemLocation=CurrentSystemLocations.FirstOrDefault(r=>r.Record.Identity==selected);
CurrentSystemStatus=$"{CurrentSystemLocations.Count} / {snapshot.Locations.Count} 个地点";
OnPropertyChanged(nameof(SelectedSystemDistance));OnPropertyChanged(nameof(SelectedSystemPositionStatus));
CurrentSystemSceneChanged?.Invoke();
}
internal void ShowCurrentSystem()
{
if(OfflinePreview)return;
currentSystemViewCount++;
if(currentSystemTimer is null){currentSystemTimer=dispatcher.CreateTimer();currentSystemTimer.Interval=TimeSpan.FromSeconds(3);currentSystemTimer.Tick+=async(_,_)=>await RefreshCurrentSystemAsync();}
currentSystemTimer.Start();_=RefreshCurrentSystemAsync();
}
internal void HideCurrentSystem(){currentSystemViewCount=Math.Max(0,currentSystemViewCount-1);if(currentSystemViewCount==0)currentSystemTimer?.Stop();}
[RelayCommand] private async Task RefreshCurrentSystemAsync()
{
if(OfflinePreview)return;
if(currentSystemReadInProgress)return;
currentSystemReadInProgress=true;
CurrentSystemReading=currentSystemSnapshot is null;
try
{
if(DemoMode||!runtime.Player.InGame)
{
CurrentSystemStatus="请进入游戏后查看当前星系地点。";CurrentSystemLocations.Apply([]);currentSystemSnapshot=null;SelectedSystemLocation=null;SystemFlightReady=false;
CurrentSystemSceneChanged?.Invoke();UpdateSystemControlAvailability();runtime.ReportStatus("current-system.wait","当前星系","等待进入驾驶场景。");return;
}
// The driver may still belong to a game process that has exited.
// Refresh the environment independently and bind reads to its live PID.
// Checking the PID is cheap; hashing the game image every thirty
// seconds is not. Re-discover only on process loss or read failure.
if(gameEnvironment?.ProcessId is not >0||!CurrentGameProcessAlive(gameEnvironment.ProcessId.Value))
await ReadEnvironmentAsync();
var pid=gameEnvironment?.ProcessId??0;
var hash=gameEnvironment?.ImageSha256??"";
if(pid<=0||hash.Length!=64){await ReadEnvironmentAsync();pid=gameEnvironment?.ProcessId??0;hash=gameEnvironment?.ImageSha256??"";}
if(pid<=0)throw new FlightTelemetryUnavailableException("等待当前游戏实例。");
if(currentSystemSource is null||currentSystemPid!=pid||currentSystemGameHash!=hash)
{currentSystemSource?.Dispose();currentSystemSource=new(pid,hash,()=>runtime.Player,snapshot=>runtime.Journal.SystemOrbits.Bind(snapshot));currentSystemPid=pid;currentSystemGameHash=hash;currentSystemCapabilityDriver=null;currentSystemCapabilities=null;}
var next=await currentSystemSource.ReadLocationsAsync(lifetime.Token);
if(runtime.Player.Navigation.CurrentSystemAddress!=next.SystemAddress)return;
ApplyCurrentSystemSnapshot(next);
currentSystemReadFailures=0;
await RefreshCurrentSystemControlAsync(pid,hash,lifetime.Token);
runtime.ResolveDiagnostic("current-system.read","当前星系","地点读取已恢复。");
runtime.ResolveDiagnostic("current-system.read-stalled","当前星系","地点遥测已恢复。");
runtime.ReportStatus("current-system.wait","当前星系",$"已读取 {next.Locations.Count} 个真实地点。");
}
catch(OperationCanceledException)when(lifetime.IsCancellationRequested){}
catch(Exception error)when(NavigationRecovery.CanRetry(error,lifetime.Token))
{
HandleCurrentSystemReadFailure();
runtime.ReportStatus("current-system.wait","当前星系","正在等待驾驶场景和最新地点遥测,恢复后自动刷新。");
if(currentSystemReadFailures>=10)runtime.ReportDiagnostic("current-system.read-stalled","当前星系",error,ActivitySeverity.Warning,"地点遥测持续未就绪,保留最近目录,暂不允许启动驾驶。");
}
catch(Exception error)
{
HandleCurrentSystemReadFailure();CurrentSystemStatus="地点接口暂不可用:"+error.Message;
runtime.ReportDiagnostic("current-system.read","当前星系",error,error is NotSupportedException?ActivitySeverity.Warning:ActivitySeverity.Error,"地点读取失败:"+error.Message);
}
finally{currentSystemReadInProgress=false;CurrentSystemReading=false;}
}
internal void ApplyCurrentSystemSnapshot(CurrentSystemSnapshot snapshot)
{
if(currentSystemSnapshot?.SystemAddress!=snapshot.SystemAddress)SelectedSystemLocation=null;
currentSystemSnapshot=snapshot;CurrentSystemTitle=snapshot.SystemName;FilterSystemLocations(keepOrder:true);
}
private void HandleCurrentSystemReadFailure()
{
SystemFlightReady=false;currentSystemReadFailures++;CurrentSystemStatus="正在重新读取当前星系地点…";
if(currentSystemSnapshot?.SystemAddress!=runtime.Player.Navigation.CurrentSystemAddress)
{currentSystemSnapshot=null;CurrentSystemLocations.Apply([]);SelectedSystemLocation=null;CurrentSystemSceneChanged?.Invoke();}
UpdateSystemControlAvailability();
}
private bool CanStartSystemFlight()=>SystemFlightReady&&CurrentSystemTargetIssue() is null&&!SystemFlightActive&&!NavigationActive&&!RunActive&&!SessionBusy&&!runtime.FlightAutomation.IsActive;
[RelayCommand(CanExecute=nameof(CanStartSystemFlight))] private async Task StartSystemFlightAsync()
{
if(!CanStartSystemFlight()||SelectedSystemLocation is not {} selected||currentSystemSnapshot is not {} snapshot)return;
if(currentSystemCapabilityDriver is not {} driver)return;
var row=selected.Record;
var target=SystemTarget(snapshot,row);
using var stop=CancellationTokenSource.CreateLinkedTokenSource(lifetime.Token);systemFlightStop=stop;SystemFlightActive=true;StartSystemFlightCommand.NotifyCanExecuteChanged();
try
{
shipProtection?.RequireHealthyShip();var result=await Task.Run(()=>runtime.FlightAutomation.NavigateLocalAsync(target,driver,stop.Token),stop.Token);
if(result.Failure is {} failure)
runtime.ReportDiagnostic("current-system.flight","星系内驾驶",failure,ActivitySeverity.Error,"驾驶已停止:"+failure.Message);
else if(result.State==NavigationRunState.Completed)
runtime.ResolveDiagnostic("current-system.flight","星系内驾驶","已确认到达所选目的地。");
}
catch(OperationCanceledException){SystemFlightStatus="星系内导航已停止。";}
catch(Exception error){SystemFlightStatus=error.Message;runtime.ReportDiagnostic("current-system.flight","星系内驾驶",error,ActivitySeverity.Error,"驾驶未能启动:"+error.Message);}
finally{systemFlightStop=null;SystemFlightActive=false;StartSystemFlightCommand.NotifyCanExecuteChanged();}
}
[RelayCommand] private void StopSystemFlight(){systemFlightStop?.Cancel();runtime.FlightAutomation.Stop();systemNavigator.Stop();}
private void OnSystemFlightProgress(SystemNavigationProgress progress)=>dispatcher.TryEnqueue(()=>
{
SystemFlightStatus=progress.Message;if(runtime.FlightAutomation.ActiveEntry==FlightAutomationEntry.Galaxy)NavigationStatus=progress.Message;
if(progress.Diagnostic is {} diagnostic)
runtime.ReportDiagnostic("flight.telemetry-recovery","驾驶恢复",progress.Message,diagnostic,ActivitySeverity.Status);
else if(progress.Phase!=SystemNavigationPhase.Waiting)
runtime.ResolveDiagnostic("flight.telemetry-recovery","驾驶恢复",progress.State==NavigationRunState.Stopped?"自动驾驶已停止,原始诊断已保留。":"飞行数据已恢复,继续原航程。");
});
}