using XFEEDToolBox.Core.Navigation;
using XFEEDToolBox.Core.Notifications;
using XFEEDToolBox.Core.Session;
namespace XFEEDToolBox.ViewModels;
public partial class ToolboxViewModel
{
private event Action<SessionReentryEvent>? ProtectionReentry;
internal IDisposable ObserveArrivals(Action<NavigationArrival,int> arrived,Action<NavigationArrival,int> captureStar,
Action<SessionReadyNotification,int> sessionReady)
{
var observer=new NavigationArrivalObserver();
var reentryObserver=new SessionReadyNotificationObserver();
int ProcessId()=>(runtime.FlightDriver as NativeFlightControlDriver)?.ProcessId??gameEnvironment?.ProcessId??0;
void Interstellar(NavigationProgress progress)
{
if(OfflinePreview||DemoMode)return;
if(observer.Observe(progress,runtime.Player,DateTimeOffset.UtcNow) is {} arrival)arrived(arrival,ProcessId());
}
void Local(SystemNavigationProgress progress)
{
if(OfflinePreview||DemoMode)return;
if(observer.Observe(progress,runtime.Player,DateTimeOffset.UtcNow) is {} arrival)arrived(arrival,ProcessId());
}
void Jump(Core.Data.ObservedJournalEvent observation,Core.Models.PlayerState player)
{
if(OfflinePreview||DemoMode||runtime.Navigator.State!=NavigationRunState.Running
||!observation.Data.TryGetProperty("event",out var kind)||kind.GetString()!="FSDJump"
||!player.InGame||player.Navigation.CurrentSystemAddress is not >0)return;
captureStar(new(Guid.NewGuid().ToString("N"),player.Navigation.CurrentSystemAddress.Value,player.SystemName,player.SystemName,false,false,
player.CommanderId,player.LoadGameAt,DateTimeOffset.UtcNow),ProcessId());
}
void SessionState(Core.Services.RuntimeChange change)
{
if(OfflinePreview||DemoMode||reentryObserver.ExpectedTarget is not {} expected)return;
try
{
using var process=System.Diagnostics.Process.GetProcessById(expected.ProcessId);
if(process.HasExited||!process.ProcessName.Equals("EliteDangerous64",StringComparison.OrdinalIgnoreCase))return;
var running=expected with{StartedUtcTicks=process.StartTime.ToUniversalTime().Ticks,Executable=process.MainModule?.FileName??""};
if(reentryObserver.Observe(runtime.Player,running,DateTimeOffset.UtcNow) is {} notice)sessionReady(notice,running.ProcessId);
}
catch(Exception error)when(error is ArgumentException or InvalidOperationException or System.ComponentModel.Win32Exception){}
}
void Reentry(SessionReentryEvent entry)
{
if(OfflinePreview||DemoMode)return;
reentryObserver.OnReentry(entry,runtime.Player);SessionState(Core.Services.RuntimeChange.Player);
}
runtime.Navigator.Progress+=Interstellar;systemNavigator.Progress+=Local;
runtime.LiveJournalEvent+=Jump;
sessions.Reentry+=Reentry;ProtectionReentry+=Reentry;runtime.DataChanged+=SessionState;
return new ArrivalSubscription(()=>
{
runtime.Navigator.Progress-=Interstellar;systemNavigator.Progress-=Local;runtime.LiveJournalEvent-=Jump;
sessions.Reentry-=Reentry;ProtectionReentry-=Reentry;runtime.DataChanged-=SessionState;
});
}
private sealed class ArrivalSubscription(Action release):IDisposable
{
private Action? cleanup=release;
public void Dispose()=>Interlocked.Exchange(ref cleanup,null)?.Invoke();
}
}
using XFEEDToolBox.Core.Navigation;
using XFEEDToolBox.Core.Notifications;
using XFEEDToolBox.Core.Session;
namespace XFEEDToolBox.ViewModels;
public partial class ToolboxViewModel
{
private event Action<SessionReentryEvent>? ProtectionReentry;
internal IDisposable ObserveArrivals(Action<NavigationArrival,int> arrived,Action<NavigationArrival,int> captureStar,
Action<SessionReadyNotification,int> sessionReady)
{
var observer=new NavigationArrivalObserver();
var reentryObserver=new SessionReadyNotificationObserver();
int ProcessId()=>(runtime.FlightDriver as NativeFlightControlDriver)?.ProcessId??gameEnvironment?.ProcessId??0;
void Interstellar(NavigationProgress progress)
{
if(OfflinePreview||DemoMode)return;
if(observer.Observe(progress,runtime.Player,DateTimeOffset.UtcNow) is {} arrival)arrived(arrival,ProcessId());
}
void Local(SystemNavigationProgress progress)
{
if(OfflinePreview||DemoMode)return;
if(observer.Observe(progress,runtime.Player,DateTimeOffset.UtcNow) is {} arrival)arrived(arrival,ProcessId());
}
void Jump(Core.Data.ObservedJournalEvent observation,Core.Models.PlayerState player)
{
if(OfflinePreview||DemoMode||runtime.Navigator.State!=NavigationRunState.Running
||!observation.Data.TryGetProperty("event",out var kind)||kind.GetString()!="FSDJump"
||!player.InGame||player.Navigation.CurrentSystemAddress is not >0)return;
captureStar(new(Guid.NewGuid().ToString("N"),player.Navigation.CurrentSystemAddress.Value,player.SystemName,player.SystemName,false,false,
player.CommanderId,player.LoadGameAt,DateTimeOffset.UtcNow),ProcessId());
}
void SessionState(Core.Services.RuntimeChange change)
{
if(OfflinePreview||DemoMode||reentryObserver.ExpectedTarget is not {} expected)return;
try
{
using var process=System.Diagnostics.Process.GetProcessById(expected.ProcessId);
if(process.HasExited||!process.ProcessName.Equals("EliteDangerous64",StringComparison.OrdinalIgnoreCase))return;
var running=expected with{StartedUtcTicks=process.StartTime.ToUniversalTime().Ticks,Executable=process.MainModule?.FileName??""};
if(reentryObserver.Observe(runtime.Player,running,DateTimeOffset.UtcNow) is {} notice)sessionReady(notice,running.ProcessId);
}
catch(Exception error)when(error is ArgumentException or InvalidOperationException or System.ComponentModel.Win32Exception){}
}
void Reentry(SessionReentryEvent entry)
{
if(OfflinePreview||DemoMode)return;
reentryObserver.OnReentry(entry,runtime.Player);SessionState(Core.Services.RuntimeChange.Player);
}
runtime.Navigator.Progress+=Interstellar;systemNavigator.Progress+=Local;
runtime.LiveJournalEvent+=Jump;
sessions.Reentry+=Reentry;ProtectionReentry+=Reentry;runtime.DataChanged+=SessionState;
return new ArrivalSubscription(()=>
{
runtime.Navigator.Progress-=Interstellar;systemNavigator.Progress-=Local;runtime.LiveJournalEvent-=Jump;
sessions.Reentry-=Reentry;ProtectionReentry-=Reentry;runtime.DataChanged-=SessionState;
});
}
private sealed class ArrivalSubscription(Action release):IDisposable
{
private Action? cleanup=release;
public void Dispose()=>Interlocked.Exchange(ref cleanup,null)?.Invoke();
}
}