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.Navigation;
using XFEEDToolBox.Core.Session;

namespace XFEEDToolBox.Services;

/// <summary>Bounded recovery before the station's departure deadline, shared by station journeys and trade.</summary>
internal static class WindowsFlightRecovery
{
    public static async Task RecoverAsync(int pid,string hash,Func<PlayerState> player,string executable,string package,
        Func<Task> releaseProtection,Action<string> progress,CancellationToken token)
    {
        var expected=player();var lifecycle=new WindowsGameSessionDriver(player,()=>executable);
        var target=await lifecycle.FindTargetAsync(token);
        if(target.ProcessId!=pid||hash!=NativeRelogChannel.SupportedGameSha256||expected.CommanderId.Length==0||expected.CurrentShipId is null
            ||!expected.CargoReliable||NavigationSafety.UnhealthyHull(expected)||!NativeRelogWorkflow.SupportsMode(expected.GameMode))
            throw new InvalidOperationException("离场恢复的实例、身份、货舱或健康状态未确认。");
        await lifecycle.ValidateLaunchAsync(target,token);
        var began=System.Diagnostics.Stopwatch.StartNew();var totalTimeout=TimeSpan.FromMinutes(8);
        var channel=new NativeSessionRecoveryChannel(pid,hash,Path.Combine(package,"DockingControl"));
        var workflow=new NativeRelogWorkflow(channel,player){Timeout=totalTimeout,MenuExitTimeout=TimeSpan.FromSeconds(45),OnReachedMainMenu=releaseProtection};
        async Task<NativeSessionFrame> ObserveActualMenuAsync()
        {
            using var read=CancellationTokenSource.CreateLinkedTokenSource(token);read.CancelAfter(TimeSpan.FromSeconds(1));
            return await channel.ReadOriginalMenuStateAsync(read.Token).ConfigureAwait(false);
        }
        async Task RetainAndFinishEntryAsync(NativeSessionFrame actual)
        {
            progress("已确认游戏处于原始菜单或载入阶段,保留客户端并等待原模式完成载入。");
            if(actual.State=="MainMenu"&&actual.Stable)
            {
                await releaseProtection();token.ThrowIfCancellationRequested();
                var remaining=totalTimeout-began.Elapsed;
                if(remaining<=TimeSpan.Zero)throw new TimeoutException("原模式载入总期限已到,当前客户端已保留。");
                var entry=new NativeSessionEntryWorkflow(new NativeRelogChannel(pid,hash,entryOnly:true),player,expected.GameMode,expected.CommanderId){Timeout=remaining};
                entry.Progress+=progress;await entry.RunAsync(token).ConfigureAwait(false);return;
            }
            while(began.Elapsed<totalTimeout)
            {
                token.ThrowIfCancellationRequested();var current=player();
                if(current.InGame&&current.LoadGameAt>expected.LoadGameAt)return;
                await Task.Delay(100,token).ConfigureAwait(false);
            }
            throw new TimeoutException("原模式载入总期限已到,当前客户端已保留。");
        }
        try
        {
            workflow.Progress+=progress;
            progress("离场超时,正在空间站期限前通过原始菜单恢复原航程。");
            await workflow.RunAsync(token);
        }
        catch(Exception error)when(!workflow.ReachedMainMenu&&NativeMenuExitSafety.CanFallback(error,token))
        {
            var current=player();
            if(current.CommanderId!=expected.CommanderId||current.CurrentShipId!=expected.CurrentShipId||current.CargoCount!=expected.CargoCount
                ||!current.CargoReliable||current.GameMode!=expected.GameMode||NavigationSafety.UnhealthyHull(current)||NavigationSafety.HasExternalThreat(current))throw;
            // The original Begin can reach a safe menu at the deadline edge.
            // Its independently verified current state outranks an outer timeout.
            var actual=await ObserveActualMenuAsync().ConfigureAwait(false);
            if(!NativeMenuExitSafety.Fresh(actual,DateTimeOffset.UtcNow))throw;
            if(NativeMenuExitSafety.MenuOrLoading(actual.State)||NativeMenuExitSafety.MenuOrLoading(actual.NextState)
                ||current.InGame&&current.LoadGameAt>expected.LoadGameAt)
                await RetainAndFinishEntryAsync(actual).ConfigureAwait(false);
            else
            {
            if(!NativeMenuExitSafety.CanExitClient(expected,current,actual,DateTimeOffset.UtcNow))throw;
            NativeFlightTestProtection.CheckBeforeInput(pid);
            // No further flight or trade request is outstanding. Do not leave
            // an unattended ship inside the five-minute station exclusion zone.
            progress("原始菜单退出未完成,正在保护退出客户端并保留原订单。");
            await releaseProtection();token.ThrowIfCancellationRequested();
            actual=await ObserveActualMenuAsync().ConfigureAwait(false);current=player();
            if(!NativeMenuExitSafety.Fresh(actual,DateTimeOffset.UtcNow))throw;
            if(NativeMenuExitSafety.MenuOrLoading(actual.State)||NativeMenuExitSafety.MenuOrLoading(actual.NextState)
                ||current.InGame&&current.LoadGameAt>expected.LoadGameAt)
                await RetainAndFinishEntryAsync(actual).ConfigureAwait(false);
            else
            {
            if(!NativeMenuExitSafety.CanExitClient(expected,current,actual,DateTimeOffset.UtcNow))throw;
            await lifecycle.TerminateAsync(target,token);
            var until=DateTimeOffset.UtcNow.AddSeconds(15);
            while(!await lifecycle.HasExitedAsync(target,token))
            {if(DateTimeOffset.UtcNow>=until)throw new TimeoutException("保护退出未确认,未重复启动。");await Task.Delay(100,token);}
            var bootstrap=new WindowsTradingBootstrap(player,executable,package){ResumeExistingCargo=true};
            bootstrap.Progress+=progress;await bootstrap.UpgradeAndEnterAsync(token);
            }
            }
        }
        var restored=player();
        if(restored.CommanderId!=expected.CommanderId||restored.CurrentShipId!=expected.CurrentShipId||restored.CargoCount!=expected.CargoCount
            ||!restored.CargoReliable||restored.GameMode!=expected.GameMode||NavigationSafety.UnhealthyHull(restored))
            throw new InvalidDataException("离场恢复后的身份、货物或健康状态不一致。");
    }
}