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

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
using XFEEDToolBox.Core.Models;
using XFEEDToolBox.Core.Session;

namespace XFEEDToolBox.Core.Notifications;

public sealed record SessionReadyNotification(string Id,string Title,string Detail,NavigationArrival Scene);

/// <summary>A new process alone is not completion: wait for a fresh playable session.</summary>
public sealed class SessionReadyNotificationObserver
{
    private readonly object gate=new();
    private sealed record Pending(SessionReentryEvent Entry,string Commander,DateTimeOffset? PreviousSession,bool ProcessReady);
    private Pending? pending;
    public GameSessionTarget? ExpectedTarget{get{lock(gate)return pending is {ProcessReady:true} p?p.Entry.Target:null;}}
    public void OnReentry(SessionReentryEvent entry,PlayerState player)
    {
        lock(gate)
        {
            if(entry.Stage==SessionReentryStage.Requested)
                pending=new(entry,player.CommanderId,player.LoadGameAt,false);
            else if(pending is {} p&&p.Entry.Id==entry.Id)
                pending=entry.Stage==SessionReentryStage.Aborted?null:p with{Entry=entry,ProcessReady=true};
        }
    }
    public SessionReadyNotification? Observe(PlayerState player,GameSessionTarget running,DateTimeOffset now)
    {
        lock(gate)
        {
            if(pending is not {ProcessReady:true} p)return null;
            if(p.Commander.Length>0&&player.CommanderId.Length>0&&p.Commander!=player.CommanderId){pending=null;return null;}
            var expected=p.Entry.Target;
            if(running.ProcessId!=expected.ProcessId||running.StartedUtcTicks!=expected.StartedUtcTicks
                ||!string.Equals(running.Executable,expected.Executable,StringComparison.OrdinalIgnoreCase))return null;
            if(!player.InGame||player.CommanderId.Length==0||player.LoadGameAt is not {} loaded
                ||p.PreviousSession is {} previous&&loaded<=previous||loaded<p.Entry.RequestedAt.AddSeconds(-1)
                ||loaded>now.AddSeconds(1)||player.LocationAt is not {} location||location<loaded
                ||player.StatusAt is not {} statusAt||statusAt<loaded||player.StatusReadAt is not {} readAt||readAt<loaded||readAt<now.AddSeconds(-5)
                ||player.Navigation.CurrentSystemAddress is not >0||player.SystemName.Length==0||player.Navigation.JumpInProgress
                ||player.Status is not {} status||((status.Flags&((1L<<24)|(1L<<25)|(1L<<26)))==0&&(status.Flags2&1)==0))return null;
            pending=null;
            var id=p.Entry.Id.ToString("N");
            var action=p.Entry.Protection?"飞船保护大退":p.Entry.Operation switch
                {SessionOperation.Relog=>"一键重进",SessionOperation.Restart=>"一键大退",_=>"启动游戏"};
            var scene=new NavigationArrival(id,player.Navigation.CurrentSystemAddress.Value,player.SystemName,player.SystemName,
                player.Docked,false,player.CommanderId,loaded,now);
            return new(id,p.Entry.Operation==SessionOperation.Start?"游戏已准备就绪":"已重新进入游戏",$"{action}已完成 · {player.SystemName}",scene);
        }
    }
}