fix: 修复命令行启动时自动更新阻塞导致 StartGameTask 跳过等待主界面的问题 (#2902)

Co-authored-by: ShadowLemoon <119576779+ShadowLemoon@users.noreply.github.com>
This commit is contained in:
Shadow-Lemon
2026-03-11 09:56:01 +08:00
committed by GitHub
parent bb1f6d7281
commit 5dcbd9b577
7 changed files with 158 additions and 57 deletions

View File

@@ -56,6 +56,12 @@ public class ScriptRepoUpdater : Singleton<ScriptRepoUpdater>
/// </summary>
public event EventHandler? AutoUpdateStateChanged;
/// <summary>
/// 命令行启动时并行执行的自动更新 Task。
/// StartGameTask 结束后会 await 此 Task确保更新完成后再执行任务。
/// </summary>
public Task? CommandLineAutoUpdateTask { get; set; }
// 仓储位置
public static readonly string ReposPath = Global.Absolute("Repos");

View File

@@ -0,0 +1,96 @@
using System;
using System.Linq;
namespace BetterGenshinImpact.Helpers;
/// <summary>
/// 命令行参数统一解析,启动时解析一次,各处查询解析结果。
/// </summary>
public class CommandLineOptions
{
private static CommandLineOptions? _instance;
public static CommandLineOptions Instance => _instance ??= Parse(Environment.GetCommandLineArgs());
public CommandLineAction Action { get; }
/// <summary>
/// startOneDragon 时可选的配置名称(第 3 个参数)
/// </summary>
public string? OneDragonConfigName { get; }
/// <summary>
/// --startGroups / --TaskProgress 时传入的组名列表(第 3 个参数起)
/// </summary>
public string[] GroupNames { get; } = [];
/// <summary>
/// 是否有命令行任务参数startOneDragon / --startGroups / --TaskProgress / start
/// </summary>
public bool HasTaskArgs => Action != CommandLineAction.None;
/// <summary>
/// 是否是需要 StartGameTask 自行处理游戏启动的命令
/// (一条龙、配置组、任务进度由各自流程中的 StartGameTask 启动游戏)
/// </summary>
public bool ShouldDeferGameStart => Action is CommandLineAction.StartOneDragon
or CommandLineAction.StartGroups
or CommandLineAction.TaskProgress;
private CommandLineOptions(CommandLineAction action, string? oneDragonConfigName = null, string[]? groupNames = null)
{
Action = action;
OneDragonConfigName = oneDragonConfigName;
GroupNames = groupNames ?? [];
}
internal static CommandLineOptions Parse(string[] args)
{
if (args.Length <= 1)
return new CommandLineOptions(CommandLineAction.None);
var arg1 = args[1].Trim();
var extra = args.Skip(2).Select(x => x.Trim()).ToArray();
if (arg1.Contains("startOneDragon", StringComparison.OrdinalIgnoreCase))
{
return new CommandLineOptions(CommandLineAction.StartOneDragon,
oneDragonConfigName: extra.Length > 0 ? extra[0] : null);
}
if (arg1.Equals("--startGroups", StringComparison.OrdinalIgnoreCase))
{
return new CommandLineOptions(CommandLineAction.StartGroups, groupNames: extra);
}
if (arg1.Equals("--TaskProgress", StringComparison.OrdinalIgnoreCase))
{
return new CommandLineOptions(CommandLineAction.TaskProgress, groupNames: extra);
}
if (arg1.Contains("start", StringComparison.OrdinalIgnoreCase))
{
return new CommandLineOptions(CommandLineAction.Start);
}
return new CommandLineOptions(CommandLineAction.None);
}
}
public enum CommandLineAction
{
/// <summary>双击启动,无命令行参数</summary>
None,
/// <summary>纯 "start" — 仅启动截图器</summary>
Start,
/// <summary>startOneDragon — 启动一条龙</summary>
StartOneDragon,
/// <summary>--startGroups — 启动调度组</summary>
StartGroups,
/// <summary>--TaskProgress — 启动任务进度</summary>
TaskProgress,
}

View File

@@ -9,8 +9,7 @@ using System.Threading.Tasks;
using System.Windows;
using BetterGenshinImpact.Core.Script;
using BetterGenshinImpact.GameTask;
using BetterGenshinImpact.GameTask.Common;
using Microsoft.Extensions.Logging;
using BetterGenshinImpact.Helpers;
using Wpf.Ui;
namespace BetterGenshinImpact.Service;
@@ -49,66 +48,56 @@ public class ApplicationHostService(IServiceProvider serviceProvider) : IHostedS
{
_navigationWindow = (serviceProvider.GetService(typeof(INavigationWindow)) as INavigationWindow)!;
_navigationWindow!.ShowWindow();
//
var args = Environment.GetCommandLineArgs();
if (args.Length > 1)
var cmdOptions = CommandLineOptions.Instance;
if (cmdOptions.HasTaskArgs)
{
//无论如何,先跳到主页,否则在通过参数的任务在执行完之前,不会加载快捷键
_ = _navigationWindow.Navigate(typeof(HomePage));
// 命令行启动时,先等待自动更新订阅脚本完成,再运行配置组/一条龙
// (正常双击启动在 MainWindowViewModel.OnLoaded 中以 fire-and-forget 方式调用)
// 命令行启动时,并行更新订阅脚本(不阻塞游戏启动和导航)
// StartGameTask 会在游戏进入主界面后等待此 Task 完成,再开始执行任务
var scriptConfig = TaskContext.Instance().Config.ScriptConfig;
if (scriptConfig.AutoUpdateBeforeCommandLineRun)
{
await Task.Run(() => ScriptRepoUpdater.Instance.AutoUpdateSubscribedScripts());
ScriptRepoUpdater.Instance.CommandLineAutoUpdateTask =
Task.Run(() => ScriptRepoUpdater.Instance.AutoUpdateSubscribedScripts());
}
if (args[1].Contains("startOneDragon", StringComparison.InvariantCultureIgnoreCase))
switch (cmdOptions.Action)
{
case CommandLineAction.StartOneDragon:
// 通过命令行参数启动「一条龙」 => 跳转到一条龙配置页。
_ = _navigationWindow.Navigate(typeof(OneDragonFlowPage));
// 后续代码在 OneDragonFlowViewModel / OnLoaded 中。
break;
// 通过命令行参数启动「一条龙」 => 跳转到一条龙配置页。
_ = _navigationWindow.Navigate(typeof(OneDragonFlowPage));
// 后续代码在 OneDragonFlowViewModel / OnLoaded 中。
}
else if (args[1].Trim().Equals("--startGroups", StringComparison.InvariantCultureIgnoreCase))
{
// 通过命令行参数启动「调度组」 => 跳转到调度器配置页。
_ = _navigationWindow.Navigate(typeof(ScriptControlPage));
if (args.Length > 2)
{
// 获取调度组
var names = args.Skip(2).ToArray().Select(x => x.Trim()).ToArray();
// 启动调度器
var scheduler = App.GetService<ScriptControlViewModel>();
scheduler?.OnStartMultiScriptGroupWithNamesAsync(names);
}
}else if (args[1].Trim().Equals("--TaskProgress", StringComparison.InvariantCultureIgnoreCase))
{
case CommandLineAction.StartGroups:
// 通过命令行参数启动「调度组」 => 跳转到调度器配置页。
_ = _navigationWindow.Navigate(typeof(ScriptControlPage));
if (cmdOptions.GroupNames.Length > 0)
{
var scheduler = App.GetService<ScriptControlViewModel>();
scheduler?.OnStartMultiScriptGroupWithNamesAsync(cmdOptions.GroupNames);
}
break;
// 通过命令行参数启动「调度组」 => 跳转到调度器配置页。
_ = _navigationWindow.Navigate(typeof(ScriptControlPage));
if (args.Length > 1)
{
// 获取调度组
var names = args.Skip(2).ToArray().Select(x => x.Trim()).ToArray();
// 启动调度器
var scheduler = App.GetService<ScriptControlViewModel>();
scheduler?.OnStartMultiScriptTaskProgressAsync(names);
}
}
else if (args[1].Contains("start"))
{
// 通过命令行参数打开「启动页开关」 => 跳转到主页
_ = _navigationWindow.Navigate(typeof(HomePage));
// 后续代码在 HomePageViewModel / OnLoaded 中。
}
else
{
// 其它命令行参数 => 跳转到主页。
_ = _navigationWindow.Navigate(typeof(HomePage));
case CommandLineAction.TaskProgress:
// 通过命令行参数启动「任务进度」 => 跳转到调度器配置页。
_ = _navigationWindow.Navigate(typeof(ScriptControlPage));
if (cmdOptions.GroupNames.Length > 0)
{
var scheduler = App.GetService<ScriptControlViewModel>();
scheduler?.OnStartMultiScriptTaskProgressAsync(cmdOptions.GroupNames);
}
break;
case CommandLineAction.Start:
// 通过命令行参数打开「启动页开关」 => 跳转到主页。
_ = _navigationWindow.Navigate(typeof(HomePage));
// 后续代码在 HomePageViewModel / OnLoaded 中
break;
}
}
else

View File

@@ -621,5 +621,13 @@ public partial class ScriptService : IScriptService
});
}
}
// 等待命令行启动时并行执行的自动更新完成(如果有)
var pendingUpdate = ScriptRepoUpdater.Instance.CommandLineAutoUpdateTask;
if (pendingUpdate != null)
{
await pendingUpdate;
ScriptRepoUpdater.Instance.CommandLineAutoUpdateTask = null;
}
}
}

View File

@@ -250,7 +250,7 @@ public partial class MainWindowViewModel : ObservableObject, IViewModel
// 预热OCR
await OcrPreheating();
if (Environment.GetCommandLineArgs().Length > 1)
if (CommandLineOptions.Instance.HasTaskArgs)
{
return;
}

View File

@@ -133,8 +133,9 @@ public partial class HomePageViewModel : ViewModel
_autoRun = false;
var args = Environment.GetCommandLineArgs();
if (args.Length > 1 && args[1].Contains("start"))
// 只对纯 "start" 参数自动启动截图器
// startOneDragon、--startGroups 等由各自流程中的 StartGameTask 处理
if (CommandLineOptions.Instance.Action == CommandLineAction.Start)
{
_ = OnStartTriggerAsync();
}

View File

@@ -545,15 +545,16 @@ public partial class OneDragonFlowViewModel : ViewModel
}
_autoRun = false;
//
var args = Environment.GetCommandLineArgs();
if (args.Length > 1 && args[1].Contains("startOneDragon"))
var cmdOptions = CommandLineOptions.Instance;
if (cmdOptions.Action == CommandLineAction.StartOneDragon)
{
// 通过命令行参数启动一条龙。
if (args.Length > 2)
if (cmdOptions.OneDragonConfigName != null)
{
// 从命令行参数中提取一条龙配置名称。
_logger.LogInformation($"参数指定的一条龙配置:{args[2]}");
var argsOneDragonConfig = ConfigList.FirstOrDefault(x => x.Name == args[2], null);
_logger.LogInformation($"参数指定的一条龙配置:{cmdOptions.OneDragonConfigName}");
var argsOneDragonConfig = ConfigList.FirstOrDefault(x =>
string.Equals(x.Name, cmdOptions.OneDragonConfigName, StringComparison.Ordinal));
if (argsOneDragonConfig != null)
{
// 设定配置,配置下拉框会选定。