using System.Collections.Generic;
using System.Linq;
using Cysharp.Threading.Tasks;
namespace SLSUtilities.General
{
/// 命令组的执行模式。
public enum ExecutionMode
{
/// 子命令逐条顺序执行。
Sequential,
/// 子命令同时并行执行。
Parallel
}
///
/// 命令组,将多条 按 Sequential 或 Parallel 模式执行。
/// 自身也是 ,可嵌套组合。
///
public class CommandGroup : CommandBase
{
/// 子命令列表。
public readonly List commands = new List();
/// 本组的执行模式。
public readonly ExecutionMode mode;
///
/// 组级别上下文,执行过程中会合并每条子命令的 outerContext 与 selfContext。
/// 可在组执行完成后读取聚合数据(如 DrawnCards)。
///
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);
}
/// 添加一条子命令,返回自身支持链式调用。
public CommandGroup AddCommand(CommandBase command)
{
commands.Add(command);
return this;
}
///
/// 获取所有子命令。设 为 true 时,
/// 返回结果中也包含 自身节点。
///
public List GetAllCommands(bool alsoIncludeGroups = false)
{
//CommandBase可能也是CommandGroup,需要递归获取
var allCommands = new List();
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;
}
/// 获取所有指定类型的子命令(递归,包含组节点)。
public List GetAllCommands() where T : CommandBase
{
return GetAllCommands(true).OfType().ToList();
}
/// 深拷贝整个命令组及其子命令。
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)));
}
}
/// 执行单条子命令并将上下文合并到 groupContext。
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);
}
}
}