主题
指令便利 API(Command API)
指令便利 API 是对 指令系统 的高级封装,提供类型安全的流式接口,简化技能释放、移动、攻击等常见操作。
调用成功与实际完成的区别,以及排队、施法、取消和动画表现的完整流程,见指令与技能生命周期指南。
定义位置:TriggerEncapsulation.Commands
三层 API
| 层级 | 适用场景 | 示例 |
|---|---|---|
扩展方法 CommandExtensions | 简单操作,一行完成 | unit.CastAbility(abilityLink, target) |
构建器 CommandBuilder | 需要自定义 Flag/Target/Player | CommandBuilder.Create().WithAbility(...).AsUser().Execute(unit) |
上下文 CommandContext | 批量操作,复用 Player/Flag | context.CastAbility(...).Execute(unit) |
扩展方法
Entity 扩展
csharp
// 技能
unit.CastAbility(abilityLink, target);
unit.ToggleAbility(abilityLink);
unit.TurnOnAbility(abilityLink);
unit.TurnOffAbility(abilityLink);
// 移动
unit.MoveInDirection(45f); // 按角度
unit.MoveInDirection(new Angle(90f)); // 用 Angle 结构
unit.MoveTo(scenePoint); // 移动到位置
unit.StopMovement(); // 停止方向移动
// 攻击 / 停止
unit.AttackTarget(enemyUnit);
unit.Stop(); // 清空指令队列
// 物品(需要 InventoryManager 组件)
unit.PickUpItem(pickUpItem);
unit.UseItem(item);
unit.DropItem(itemPickable);所有 Entity 扩展方法共享参数 bool asUser = true, Player? player = null:
asUser: true(默认):设置CommandFlag.IsUser,player默认为Player.LocalPlayerasUser: false:不设置 IsUser/IsAI 标志,用于系统指令
Player 扩展
操作玩家的 MainUnit:
csharp
player.CastAbilityWithMainUnit(abilityLink, target);
player.MoveMainUnitInDirection(angle);
player.MoveMainUnitTo(scenePoint);
player.StopMainUnit();完整签名参考
csharp
// Entity 技能扩展
static CmdResult CastAbility(this Entity unit, IGameLink<GameDataAbility> abilityLink,
ICommandTarget? target = null, bool asUser = true, Player? player = null);
static CmdResult ToggleAbility(this Entity unit, IGameLink<GameDataAbility> abilityLink,
bool asUser = true, Player? player = null);
static CmdResult TurnOnAbility(this Entity unit, IGameLink<GameDataAbility> abilityLink,
bool asUser = true, Player? player = null);
static CmdResult TurnOffAbility(this Entity unit, IGameLink<GameDataAbility> abilityLink,
bool asUser = true, Player? player = null);
// Entity 移动扩展
static CmdResult MoveInDirection(this Entity unit, float degrees,
bool asUser = true, Player? player = null);
static CmdResult MoveInDirection(this Entity unit, Angle angle,
bool asUser = true, Player? player = null);
static CmdResult MoveTo(this Entity unit, ScenePoint position,
bool asUser = true, Player? player = null);
static CmdResult StopMovement(this Entity unit,
bool asUser = true, Player? player = null);
// Entity 攻击/停止
static CmdResult AttackTarget(this Entity unit, Unit target,
bool asUser = true, Player? player = null);
static CmdResult Stop(this Entity unit,
bool asUser = true, Player? player = null);
// Entity 物品
static CmdResult PickUpItem(this Entity unit, IPickUpItem item,
bool asUser = true, Player? player = null);
static CmdResult DropItem(this Entity unit, ItemPickable item,
bool asUser = true, Player? player = null);
static CmdResult UseItem(this Entity unit, Item item,
bool asUser = true, Player? player = null);CommandBuilder
流式构建器,适合需要精细控制的场景。
csharp
var result = CommandBuilder.Create()
.WithIndex(CommandIndex.Execute)
.WithType(ComponentTagEx.AbilityManager)
.WithAbility(abilityLink)
.ToUnit(enemyUnit)
.AsUser()
.Execute(playerUnit);构建器方法
csharp
static CommandBuilder Create();
// 核心配置
CommandBuilder WithIndex(CommandIndex index);
CommandBuilder WithType(ComponentTag type);
CommandBuilder WithFlag(CommandFlag flag);
CommandBuilder WithPlayer(Player? player);
CommandBuilder WithTarget(ICommandTarget? target);
CommandBuilder WithAbility(IGameLink<GameDataAbility>? abilityLink);
CommandBuilder WithItem(Item? item);
// Toggle 技能
CommandBuilder WithToggle(IGameLink<GameDataAbility> abilityLink);
CommandBuilder WithTurnOn(IGameLink<GameDataAbility> abilityLink);
CommandBuilder WithTurnOff(IGameLink<GameDataAbility> abilityLink);
// 物品
CommandBuilder WithPickUp(IPickUpItem item);
CommandBuilder WithDrop(ItemPickable item);
CommandBuilder WithUse(Item item);
// 目标快捷方法
CommandBuilder ToUnit(Unit unit);
CommandBuilder ToPosition(ScenePoint position);
CommandBuilder ToAngle(Angle angle);
CommandBuilder ToAngle(float degrees);
// 上下文快捷方法
CommandBuilder AsUser(Player? player = null); // 设置 IsUser + Player
CommandBuilder AsAI(Player player); // 设置 IsAI + Player
CommandBuilder AsSystem(); // 无标志,Player = null
// 执行
Command Build();
CmdResult Execute(Entity unit, bool testOnly = false);
CmdResult<T> Execute<T>(Entity unit, bool testOnly = false) where T : class;
(bool IsValid, string? ErrorMessage) Validate();
// 隐式转换
static implicit operator Command(CommandBuilder builder);条件构建
csharp
var builder = CommandBuilder.Create()
.WithIndex(CommandIndex.Execute)
.WithType(ComponentTagEx.AbilityManager)
.WithAbility(abilityLink);
if (hasTarget)
builder.ToUnit(target);
else if (hasPosition)
builder.ToPosition(fallbackPosition);
else
builder.ToAngle(facing);
var result = builder.AsUser().Execute(unit);CommandContext
复用 Player 和 Flag 设置,适合批量操作。
创建上下文
csharp
var userCtx = CommandContext.ForUser(player); // 用户操作
var aiCtx = CommandContext.ForAI(aiPlayer); // AI 操作
var systemCtx = CommandContext.ForSystem(); // 系统操作(绕过权限)上下文方法
返回 CommandBuilder,调用 .Execute(unit) 执行:
csharp
CommandBuilder CastAbility(IGameLink<GameDataAbility> abilityLink, ICommandTarget? target = null);
CommandBuilder MoveInDirection(Angle angle);
CommandBuilder MoveInDirection(float degrees);
CommandBuilder MoveTo(ScenePoint position);
CommandBuilder AttackTarget(Unit target);
CommandBuilder StopMovement();
CommandBuilder Stop();BoundCommandContext
绑定到特定 Entity,免去每次传递参数:
csharp
var bound = unit.AsUser(); // 绑定用户上下文
bound.CastAbility(abilityLink, target); // 直接执行,返回 CmdResult
bound.MoveInDirection(45f);
bound.AttackTarget(enemy);
var boundAI = unit.AsAI(aiPlayer); // 绑定 AI 上下文
boundAI.MoveTo(patrolPoint);通过 CommandContextExtensions 扩展创建:
csharp
static BoundCommandContext AsUser(this Entity entity, Player? player = null);
static BoundCommandContext AsAI(this Entity entity, Player? player = null);
static BoundCommandContext AsSystem(this Entity entity);批量操作
csharp
var aiCtx = CommandContext.ForAI(aiPlayer);
var targetPosition = GetPatrolPoint();
foreach (var unit in aiUnits)
{
aiCtx.MoveTo(targetPosition).Execute(unit);
}错误处理
所有命令返回 CmdResult(或服务端 CmdResult<Order>)。
csharp
var result = unit.CastAbility(abilityLink, target);
if (!result.IsSuccess)
{
Game.Logger.LogWarning("命令失败: {Error}", result.Error);
}测试模式
不实际执行,仅检查是否可行:
csharp
var testResult = unit.CastAbility(abilityLink, target, testOnly: true);
if (testResult.IsSuccess)
{
unit.CastAbility(abilityLink, target);
}服务端 Ability 实例重载
服务端可直接使用 Ability 实例,跳过 GameLink 查找:
csharp
#if SERVER
// 扩展方法 — Ability 实例重载
unit.CastAbility(ability, target);
unit.ToggleAbility(ability);
unit.TurnOnAbility(ability);
unit.TurnOffAbility(ability);
// CommandBuilder — Ability 实例重载
CommandBuilder.Create().WithAbility(ability);
CommandBuilder.Create().WithToggle(ability);
CommandBuilder.Create().WithTurnOn(ability);
CommandBuilder.Create().WithTurnOff(ability);
// Player 扩展
player.CastAbilityWithMainUnit(ability, target);
#endif底层类型
CommandIndex
可扩展枚举,标识命令类型:
| 值 | 说明 |
|---|---|
Execute | 执行(技能等) |
TurnOn | 开启 |
TurnOff | 关闭 |
Toggle | 切换 |
Attack | 攻击 |
Move | 移动到位置 |
VectorMove | 方向移动 |
VectorMoveAdjust | 调整方向(不中断) |
VectorMoveStop | 停止方向移动 |
Stop | 完全停止 |
物品相关(CommandIndexInventory):PickUp、Use、Swap、Give、Drop
CommandFlag
| 值 | 说明 |
|---|---|
None | 无标志(系统操作) |
IsUser | 用户操作 |
IsAI | AI 操作 |
Queued | 加入队列 |
Preempt | 抢占 |
IsRequest | 请求类型(IsUser 或 IsAI) |
ICommandTarget
命令目标接口,实现类型:Unit、ScenePoint、Angle、ItemPickable
客户端 vs 服务端
- 客户端:
IssueOrder发送ProtoClientCommand到服务端,不本地创建 Order - 服务端:
IssueOrder创建Order并加入OrderQueue执行