125 lines
4.3 KiB
C#
125 lines
4.3 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using UniRx;
|
||
using UnityEngine;
|
||
|
||
namespace SLSFramework.General
|
||
{
|
||
public enum ExecutionMode { Sequential, Parallel }
|
||
|
||
public class CommandGroup : CommandBase
|
||
{
|
||
public readonly List<CommandBase> commands = new List<CommandBase>();
|
||
public readonly ExecutionMode mode;
|
||
|
||
/// <summary>
|
||
/// 包含了指令组执行过程中产生的所有上下文信息。不论是内部还是外部的上下文皆可获取。
|
||
/// </summary>
|
||
public readonly CommandContext groupContext;
|
||
|
||
public CommandGroup(ExecutionMode mode, params CommandBase[] commands)
|
||
{
|
||
this.mode = mode;
|
||
this.groupContext = new CommandContext();
|
||
this.commands.AddRange(commands);
|
||
}
|
||
|
||
public CommandGroup(ExecutionMode mode, CommandContext groupContext, params CommandBase[] commands)
|
||
{
|
||
this.mode = mode;
|
||
this.groupContext = groupContext;
|
||
this.commands.AddRange(commands);
|
||
}
|
||
|
||
public override CommandBase Clone()
|
||
{
|
||
CommandGroup newGroup = new CommandGroup(mode);
|
||
foreach (var cmd in commands)
|
||
{
|
||
newGroup.AddCommand(cmd.Clone());
|
||
}
|
||
return newGroup;
|
||
}
|
||
|
||
public CommandGroup AddCommand(CommandBase command)
|
||
{
|
||
commands.Add(command);
|
||
return this;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取所有子指令,包含嵌套的指令组中的指令。
|
||
/// </summary>
|
||
/// <param name="alsoIncludeGroups">是否也包含CommandGroup,false则不会将CommandGroup返回</param>
|
||
/// <returns></returns>
|
||
public List<CommandBase> GetAllCommands(bool alsoIncludeGroups = false)
|
||
{
|
||
//CommandBase可能也是CommandGroup,需要递归获取
|
||
List<CommandBase> 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;
|
||
}
|
||
|
||
public List<T> GetAllCommands<T>() where T : CommandBase
|
||
{
|
||
return GetAllCommands(true).OfType<T>().ToList();
|
||
}
|
||
|
||
protected override IObservable<Unit> OnExecute(CommandContext outerContext)
|
||
{
|
||
// --- 核心修正 ---
|
||
// 我们不再直接调用 cmd.Execute(context)。
|
||
// 而是创建一个“延迟执行”的 Observable 序列。
|
||
// Defer 会将对 Execute 的调用推迟到 Concat/WhenAll 真正订阅它的时候。
|
||
var lazyCommandObservables = commands.Select(cmd =>
|
||
Observable.Defer(() =>
|
||
{
|
||
IObservable<Unit> result = cmd.Execute(outerContext);
|
||
groupContext.Merge(outerContext);
|
||
groupContext.Merge(cmd.selfContext);
|
||
return result;
|
||
})
|
||
);
|
||
|
||
IObservable<Unit> executionFlow;
|
||
if (mode == ExecutionMode.Sequential)
|
||
{
|
||
// Concat 现在会按顺序地、一个一个地订阅 lazyCommandObservables 中的 Defer 对象。
|
||
// 每订阅一个,对应的 cmd.Execute() 才会被真正调用。
|
||
executionFlow = lazyCommandObservables.Concat();
|
||
}
|
||
else
|
||
{
|
||
// WhenAll 同样能很好地处理延迟的 Observable 序列。
|
||
executionFlow = Observable.WhenAll(lazyCommandObservables).AsUnitObservable();
|
||
}
|
||
|
||
|
||
return executionFlow;
|
||
// 注意:基类中的 TakeUntil(forceCompleteSubject) 会自动应用到这里返回的流上,所以无需重复添加。
|
||
}
|
||
}
|
||
} |