XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
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();
    }
}