140 lines
4.6 KiB
C#
140 lines
4.6 KiB
C#
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using Cysharp.Threading.Tasks;
|
||
|
||
namespace SLSUtilities.General
|
||
{
|
||
/// <summary>命令组的执行模式。</summary>
|
||
public enum ExecutionMode
|
||
{
|
||
/// <summary>子命令逐条顺序执行。</summary>
|
||
Sequential,
|
||
/// <summary>子命令同时并行执行。</summary>
|
||
Parallel
|
||
}
|
||
|
||
/// <summary>
|
||
/// 命令组,将多条 <see cref="CommandBase"/> 按 Sequential 或 Parallel 模式执行。
|
||
/// 自身也是 <see cref="CommandBase"/>,可嵌套组合。
|
||
/// </summary>
|
||
public class CommandGroup : CommandBase
|
||
{
|
||
/// <summary>子命令列表。</summary>
|
||
public readonly List<CommandBase> commands = new List<CommandBase>();
|
||
|
||
/// <summary>本组的执行模式。</summary>
|
||
public readonly ExecutionMode mode;
|
||
|
||
/// <summary>
|
||
/// 组级别上下文,执行过程中会合并每条子命令的 outerContext 与 selfContext。
|
||
/// 可在组执行完成后读取聚合数据(如 DrawnCards)。
|
||
/// </summary>
|
||
public readonly CommandContext groupContext;
|
||
|
||
public CommandGroup(ExecutionMode mode = ExecutionMode.Sequential)
|
||
{
|
||
this.mode = mode;
|
||
groupContext = new CommandContext();
|
||
}
|
||
|
||
public CommandGroup(ExecutionMode mode, params CommandBase[] commands)
|
||
{
|
||
this.mode = mode;
|
||
groupContext = new CommandContext();
|
||
this.commands.AddRange(commands);
|
||
}
|
||
|
||
public CommandGroup(params CommandBase[] commands)
|
||
{
|
||
mode = ExecutionMode.Sequential;
|
||
groupContext = new CommandContext();
|
||
this.commands.AddRange(commands);
|
||
}
|
||
|
||
/// <summary>添加一条子命令,返回自身支持链式调用。</summary>
|
||
public CommandGroup AddCommand(CommandBase command)
|
||
{
|
||
commands.Add(command);
|
||
return this;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取所有子命令。设 <paramref name="alsoIncludeGroups"/> 为 true 时,
|
||
/// 返回结果中也包含 <see cref="CommandGroup"/> 自身节点。
|
||
/// </summary>
|
||
public List<CommandBase> GetAllCommands(bool alsoIncludeGroups = false)
|
||
{
|
||
//CommandBase可能也是CommandGroup,需要递归获取
|
||
var allCommands = new List<CommandBase>();
|
||
|
||
if (alsoIncludeGroups)
|
||
{
|
||
allCommands.Add(this);
|
||
}
|
||
|
||
foreach (CommandBase cmd in commands)
|
||
{
|
||
if (cmd is CommandGroup group)
|
||
{
|
||
if (alsoIncludeGroups)
|
||
{
|
||
allCommands.Add(group);
|
||
}
|
||
|
||
allCommands.AddRange(group.GetAllCommands(alsoIncludeGroups));
|
||
}
|
||
else
|
||
{
|
||
allCommands.Add(cmd);
|
||
}
|
||
}
|
||
|
||
return allCommands;
|
||
}
|
||
|
||
/// <summary>获取所有指定类型的子命令(递归,包含组节点)。</summary>
|
||
public List<T> GetAllCommands<T>() where T : CommandBase
|
||
{
|
||
return GetAllCommands(true).OfType<T>().ToList();
|
||
}
|
||
|
||
/// <summary>深拷贝整个命令组及其子命令。</summary>
|
||
public override CommandBase Clone()
|
||
{
|
||
var cloned = new CommandGroup(mode);
|
||
foreach (var cmd in commands)
|
||
cloned.AddCommand(cmd.Clone());
|
||
return cloned;
|
||
}
|
||
|
||
protected override async UniTask ExecuteAsync(CommandContext outerContext)
|
||
{
|
||
if (mode == ExecutionMode.Sequential)
|
||
{
|
||
foreach (var cmd in commands)
|
||
{
|
||
await cmd.RunAsync(outerContext);
|
||
MergeContexts(cmd, outerContext);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
await UniTask.WhenAll(commands.Select(cmd =>
|
||
ExecuteAndMergeAsync(cmd, outerContext)));
|
||
}
|
||
}
|
||
|
||
/// <summary>执行单条子命令并将上下文合并到 groupContext。</summary>
|
||
private async UniTask ExecuteAndMergeAsync(CommandBase cmd, CommandContext outerContext)
|
||
{
|
||
await cmd.RunAsync(outerContext);
|
||
MergeContexts(cmd, outerContext);
|
||
}
|
||
|
||
private void MergeContexts(CommandBase cmd, CommandContext outerContext)
|
||
{
|
||
groupContext.Merge(outerContext);
|
||
groupContext.Merge(cmd.selfContext);
|
||
}
|
||
}
|
||
} |