Files
loneseDocument/Plugins/CharacterControl/UCommandRouter.md

5.6 KiB
Raw Permalink Blame History

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) -> bool: 注册一个端点。检查 GUID 有效性、重复注册、自注册防护。注册成功后绑定端点的两个委托并执行标签聚合。返回 false 表示注册失败
  • UnregisterEndpoint(const FGuid&) -> bool: 按 GUID 注销端点。解绑委托、移除标签聚合、从注册表删除
  • UnregisterEndpointByInterface(TScriptInterface) -> 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防止路由器将自己注册为子端点造成环路