Files
loneseDocument/Plugins/CharacterControl/UCommandRouter.md

64 lines
5.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# UCommandRouter
## 基本信息
- **类型**: UCLASS(BlueprintType, EditInlineNew, DefaultToInstanced)
- **父类**: UObject, implements ICommandEndpoint
- **源文件**: Plugins/CharacterControl/Source/CharacterControl/Public/CommandRouter.h
- **模块**: CharacterControl
## 功能概述
核心命令路由引擎。管理子端点注册表TMap<FGuid, FEndpointEntry>)。实现基于标签的匹配,包含两种模式:连续模式(标签 + ContinuousFriendly 检查)和离散模式(标签 ALL/ANY 匹配)。标签聚合系统通过引用计数将子标签向上合并。受跳数限制保护的调度。子端点输出命令的向上传播。自身身份保护防止循环注册。
## 设计用意
插件的核心。基于标签的发布-订阅总线替代硬引用。支持层级树拓扑路由器嵌套路由器。跳数限制防止无限循环。标签聚合实现高效的父级过滤。EditInlineNew/DefaultToInstanced 用于嵌入组件中。
## 职责范围
命令路由与端点管理。注册/注销端点。匹配并调度命令。聚合并管理标签订阅。不生成命令(由输入组件负责)。
## 项目内依赖
| 依赖项 | 关系 | 源文件 |
|--------|------|--------|
| CommandEndpoint.h | #include | Plugins/CharacterControl/Source/CharacterControl/Public/CommandEndpoint.h |
## 对外接口
UCommandRouter 是命令路由系统的核心引擎。作为 UObject(EditInlineNew, DefaultToInstanced) 且实现 ICommandEndpoint它既可以嵌入组件又可以参与上级路由。蓝图和 C++ 均可调用以下 UFUNCTION
**端点管理BlueprintCallable**
- **RegisterEndpoint(TScriptInterface<ICommandEndpoint>) -> bool**: 注册一个端点。检查 GUID 有效性、重复注册、自注册防护。注册成功后绑定端点的两个委托并执行标签聚合。返回 false 表示注册失败
- **UnregisterEndpoint(const FGuid&) -> bool**: 按 GUID 注销端点。解绑委托、移除标签聚合、从注册表删除
- **UnregisterEndpointByInterface(TScriptInterface<ICommandEndpoint>) -> bool**: 按接口指针注销端点,内部提取 GUID 后转调 UnregisterEndpoint
- **ClearAllEndpoints()**: 批量注销所有已注册端点。遍历收集所有端点后逐个调用 UnregisterEndpointByInterface
- **GetEndpointCount() -> int32**: 返回当前已注册端点数量
**路由器自身配置BlueprintCallable**
- **SetRouterState(const FEndpointState&)**: 设置路由器作为端点时的配置。只更新 InterestedTags/bIsActive/bIsContinuousFriendly/bIsAsynchronous 字段,保留 EndpointGuid。更新后广播 StateChangedDelegate
- **GetRouterState() -> FEndpointState**: 返回当前路由器的端点状态
**命令输入BlueprintCallable**
- **InputCommand(const FCommandPacket&)**: 向路由器注入命令,直接调用 ReceiveCommand 触发路由逻辑。可用于外部系统或上级路由器向本路由器投递命令
**委托public field**
- **StateChangedDelegate** (FOnEndpointStateChanged): 路由器自身状态变更时广播
- **CommandOutputDelegate** (FOnCommandOutput): 路由器作为端点向上级输出的命令通过此委托广播
## 使用方法
UCommandRouter 通常不直接使用,而是通过 UCommandRouterComponent 包裹后挂载到 Actor
- **组件嵌入选框**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouterComponent.cpp:15` -- UCommandRouterComponent 通过 CreateDefaultSubobject 创建 InternalRouter
- **端点注册入口**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouter.cpp:45-84` -- RegisterEndpoint 的完整注册流程
- **命令分发**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouter.cpp:13-31` -- ReceiveCommand 入口HopLimit 检查 -> 递减 -> 按类型分发
- **离散路由**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouter.cpp:164-197` -- RouteDiscreteCommand 遍历注册表,提取离散元数据,对每个匹配端点投递
- **连续路由**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouter.cpp:199-218` -- RouteContinuousCommand 遍历注册表,对每个 bIsContinuousFriendly 且 Tag 匹配端点投递
- **端点注册**: `Plugins/CharacterControl/Source/CharacterControl/Private/EndpointComponent.cpp:38` -- UEndpointComponent::BeginPlay 找到兄弟 UCommandRouterComponent 后调用 `Router->InternalRouter->RegisterEndpoint(this)`
## 用例
- **命令注入**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouter.cpp:145-162` -- OnRegisteredEndpointOutputCommand 接收子端点产出的命令:上行命令先投递本地再转发上级,非上行命令直接投递本地端点
- **端点注册完整流程**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouter.cpp:45-84` -- 验证 -> 注册 -> 委托绑定BindDynamic -> 标签聚合AddEndpointToAggregation全在 RegisterEndpoint 中完成
- **上行传播**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouter.cpp:148-155` -- bIsUpward 命令处理:拷贝命令清除上行标志后本地投递,同时对原始命令做额外 HopLimit 递减后通过 CommandOutputDelegate 向上转发
- **标签聚合更新**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouter.cpp:137-143` -- OnRegisteredEndpointStateChanged 收到端点状态变更后调用 UpdateEndpointInAggregation 做差分更新
- **自注册防护**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouter.cpp:65-69` -- RegisterEndpoint 检查端点 GUID 是否等于自身 GUID防止路由器将自己注册为子端点造成环路