init
This commit is contained in:
43
Plugins/CharacterControl/FCommandMeta.md
Normal file
43
Plugins/CharacterControl/FCommandMeta.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# FCommandMeta
|
||||
|
||||
## 基本信息
|
||||
- **类型**: USTRUCT(BlueprintType)
|
||||
- **父类**: (none)
|
||||
- **源文件**: Plugins/CharacterControl/Source/CharacterControl/Public/CommandEndpoint.h
|
||||
- **模块**: CharacterControl
|
||||
|
||||
## 功能概述
|
||||
Metadata header for every command packet. Carries CommandID (int32, from UInputAction), HopLimit (uint8, mutable, decremented per router hop), bIsContinuous (bool, routing strategy selector), bIsUpward (bool, upward propagation flag).
|
||||
|
||||
## 设计用意
|
||||
Routing envelope - decouples "what the command is" (payload) from "how it travels" (hop limit, direction). HopLimit prevents broadcast storms in router graphs. Upward flag supports parent-child router topologies.
|
||||
|
||||
## 职责范围
|
||||
Carries routing metadata for one command packet. Embedded in FCommandPacket::Meta. Decremented at each router hop.
|
||||
|
||||
## 项目内依赖
|
||||
| 依赖项 | 关系 | 源文件 |
|
||||
|--------|------|--------|
|
||||
| (none) | | |
|
||||
|
||||
## 对外接口
|
||||
FCommandMeta 是嵌入在 FCommandPacket::Meta 中的数据容器,所有字段通过 UPROPERTY(BlueprintReadOnly) 暴露给蓝图。调用者不直接构造 FCommandMeta,而是由 UCommandInputComponent::BuildPacket 在输入事件触发时自动填充。路由过程中 UCommandRouter::ReceiveCommand 会递减 HopLimit。
|
||||
|
||||
- **CommandID** (int32, BlueprintReadOnly): 由 BuildPacket 从 UInputAction::GetUniqueID() 填充,标识命令来源
|
||||
- **HopLimit** (uint8, mutable, BlueprintReadOnly): 每经过一层路由递减 1,耗尽则丢包。BuildPacket 对连续命令设为 3、离散命令设为 5
|
||||
- **bIsContinuous** (bool, BlueprintReadOnly): 决定路由分发策略(连续走 RouteContinuousCommand,离散走 RouteDiscreteCommand)
|
||||
- **bIsUpward** (bool, BlueprintReadOnly): 上行传播标志,在上级路由器中决定是否同时投递本地和向上转发
|
||||
|
||||
## 使用方法
|
||||
FCommandMeta 作为 FCommandPacket 的成员由 BuildPacket 构建,在 CommandRouter 中消费:
|
||||
|
||||
- **构建**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandInputComponent.cpp:70-72` -- BuildPacket 设置 CommandID、bIsContinuous、HopLimit(连续 3、离散 5)
|
||||
- **跳数递减**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouter.cpp:16-21` -- ReceiveCommand 检查 HopLimit 并在 >0 时递减
|
||||
- **上行传播跳数递减**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouter.cpp:155` -- 上行命令在路由器层面再递减一次
|
||||
- **路由策略选择**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouter.cpp:23-30` -- 根据 bIsContinuous 选择 RouteContinuousCommand 或 RouteDiscreteCommand
|
||||
|
||||
## 用例
|
||||
- **BuildPacket 构建**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandInputComponent.cpp:70-72` -- 输入触发时根据 FInputCommand::bIsContinuous 设置 Meta 各字段,连续命令 HopLimit=3,离散命令 HopLimit=5
|
||||
- **HopLimit 防护**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouter.cpp:16-18` -- ReceiveCommand 入口处首先检查 HopLimit,<=0 直接丢包,防止广播风暴
|
||||
- **逐跳递减**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouter.cpp:21` -- 每经过一个路由器,mutable 的 HopLimit 减 1,确保命令不会无限传播
|
||||
- **上行转发**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouter.cpp:148-155` -- 当 bIsUpward 为 true 时,先投递本地(清除上行标志),再向上级路由器转发
|
||||
47
Plugins/CharacterControl/FCommandPacket.md
Normal file
47
Plugins/CharacterControl/FCommandPacket.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# FCommandPacket
|
||||
|
||||
## 基本信息
|
||||
- **类型**: USTRUCT(BlueprintType)
|
||||
- **父类**: (none)
|
||||
- **源文件**: Plugins/CharacterControl/Source/CharacterControl/Public/CommandEndpoint.h
|
||||
- **模块**: CharacterControl
|
||||
|
||||
## 功能概述
|
||||
Complete unified command message flowing through routing system. Composed of Meta (FCommandMeta), ContinuousPayload (for continuous commands), DiscretePayload (TInstancedStruct<FDiscreteMeta>, for discrete commands).
|
||||
|
||||
## 设计用意
|
||||
Unified message envelope. All routers and endpoints share single ReceiveCommand(const FCommandPacket&) interface. TInstancedStruct for discrete payload enables future extensibility without changing packet layout.
|
||||
|
||||
## 职责范围
|
||||
Carries ONE command through the routing system. Either continuous or discrete payload is valid (determined by Meta.bIsContinuous).
|
||||
|
||||
## 项目内依赖
|
||||
| 依赖项 | 关系 | 源文件 |
|
||||
|--------|------|--------|
|
||||
| FCommandMeta | 包含 (成员) | Plugins/CharacterControl/Source/CharacterControl/Public/CommandEndpoint.h |
|
||||
| FContinuousPayload | 包含 (成员) | Plugins/CharacterControl/Source/CharacterControl/Public/CommandEndpoint.h |
|
||||
| FDiscreteMeta | 包含 (TInstancedStruct) | Plugins/CharacterControl/Source/CharacterControl/Public/CommandEndpoint.h |
|
||||
|
||||
## 对外接口
|
||||
FCommandPacket 是贯穿整个路由系统的统一命令消息。所有路由器、端点组件、输入组件的 ReceiveCommand 接口都接收 `const FCommandPacket&`。三个 UPROPERTY(BlueprintReadWrite) 成员字段:
|
||||
|
||||
- **Meta** (FCommandMeta): 携带路由元数据(CommandID、HopLimit、bIsContinuous、bIsUpward)
|
||||
- **ContinuousPayload** (FContinuousPayload): 连续命令的有效载荷,当 Meta.bIsContinuous 为 true 时有效
|
||||
- **DiscretePayload** (TInstancedStruct<FDiscreteMeta>): 离散命令的有效载荷,当 Meta.bIsContinuous 为 false 时有效。使用 TInstancedStruct 支持未来扩展
|
||||
|
||||
命令包在 UCommandInputComponent::BuildPacket 中构建,通过 FOnCommandOutput 委托广播,最终到达所有匹配端点的 ReceiveCommand。路由过程中 Meta.HopLimit 被递减,但载荷内容保持不变。
|
||||
|
||||
## 使用方法
|
||||
FCommandPacket 的生命周期:BuildPacket 构建 -> 委托广播 -> Router 接收分发 -> Endpoint 接收:
|
||||
|
||||
- **构建**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandInputComponent.cpp:41-80` -- BuildPacket 根据 FInputCommand 和 FInputActionInstance 构造完整的 FCommandPacket
|
||||
- **广播**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandInputComponent.cpp:108-110` -- 在 BindAllCommands 的 lambda 中构建后通过 OnCommandOutput.ExecuteIfBound 广播
|
||||
- **路由消费**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouter.cpp:13-31` -- ReceiveCommand 检查 HopLimit 后分发到 RouteContinuousCommand 或 RouteDiscreteCommand
|
||||
- **端点消费**: `Plugins/CharacterControl/Source/CharacterControl/Private/EndpointComponent.cpp:16-19` -- ReceiveCommand 转调 OnCommandReceived 蓝图事件
|
||||
- **蓝图桥接**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandEndpoint.cpp:23-26` -- ICommandEndpoint 默认实现通过 Execute_ReceiveCommand_BP 转发到蓝图
|
||||
|
||||
## 用例
|
||||
- **BuildPacket 构造**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandInputComponent.cpp:41-80` -- 输入触发时,BuildPacket 从 FInputCommand 配置和 FInputActionInstance 运行时值构造完整的 FCommandPacket
|
||||
- **BindAllCommands 中广播**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandInputComponent.cpp:106-111` -- 每次输入事件触发 lambda,BuildPacket 构造包,OnPacketBuilt 钩子执行后通过 OnCommandOutput 广播
|
||||
- **路由器入口分发**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouter.cpp:13-31` -- ReceiveCommand 根据 bIsContinuous 分发到不同的路由路径
|
||||
- **上行传播本地拷贝**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouter.cpp:151-153` -- 上行命令先做本地拷贝(清除 bIsUpward),投递本地端点后再向上转发原始命令
|
||||
41
Plugins/CharacterControl/FContinuousPayload.md
Normal file
41
Plugins/CharacterControl/FContinuousPayload.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# FContinuousPayload
|
||||
|
||||
## 基本信息
|
||||
- **类型**: USTRUCT(BlueprintType)
|
||||
- **父类**: (none)
|
||||
- **源文件**: Plugins/CharacterControl/Source/CharacterControl/Public/CommandEndpoint.h
|
||||
- **模块**: CharacterControl
|
||||
|
||||
## 功能概述
|
||||
Payload for continuous (analog) commands. Contains CommandTag (FGameplayTag, semantic ID) and ContinuousValue (FVector3f, analog value from input).
|
||||
|
||||
## 设计用意
|
||||
Separates continuous payload from discrete. FVector3f supports Boolean (0 or 1), Axis1D, Axis2D, Axis3D input types. Tag-based identification means endpoints subscribe by semantics, not input action IDs.
|
||||
|
||||
## 职责范围
|
||||
Data container for continuous input values. Used when FCommandMeta::bIsContinuous is true.
|
||||
|
||||
## 项目内依赖
|
||||
| 依赖项 | 关系 | 源文件 |
|
||||
|--------|------|--------|
|
||||
| (none) | | |
|
||||
|
||||
## 对外接口
|
||||
FContinuousPayload 是连续(模拟量)命令的数据载荷,作为 FCommandPacket::ContinuousPayload 成员存在。所有字段为 BlueprintReadWrite,可在蓝图/C++ 中读写。
|
||||
|
||||
- **CommandTag** (FGameplayTag, BlueprintReadWrite): 命令的语义标签,端点通过匹配此标签来订阅连续命令
|
||||
- **ContinuousValue** (FVector3f, BlueprintReadWrite): 从 Enhanced Input 转换来的模拟量值。Boolean 输入转为 OneVector/ZeroVector,Axis1D 存入 X 分量,Axis2D 存入 XY,Axis3D 存入 XYZ
|
||||
|
||||
调用者不直接创建 FContinuousPayload,而是通过 UCommandInputComponent::BuildPacket 在连续输入事件触发时自动构建。路由匹配时 UCommandRouter::IsEndpointMatched 读取 CommandTag 与端点 InterestedTags 进行比对。
|
||||
|
||||
## 使用方法
|
||||
FContinuousPayload 由 BuildPacket 根据输入值类型自动构造:
|
||||
|
||||
- **构建**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandInputComponent.cpp:73-75` -- 使用聚合初始化构造,`FContinuousPayload{ Command.ContinousCommandTag, ContinuousValue }`;非连续命令则构造为空 `FContinuousPayload{}`
|
||||
- **值转换**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandInputComponent.cpp:46-67` -- 根据 EInputActionValueType 将 Boolean/Axis1D/Axis2D/Axis3D 统一转换为 FVector3f
|
||||
- **匹配使用**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouter.cpp:277` -- IsEndpointMatched 检查端点 InterestedTags 是否包含 CommandTag
|
||||
|
||||
## 用例
|
||||
- **连续输入构建**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandInputComponent.cpp:73-74` -- bIsContinuous 为 true 时,BuildPacket 将 FInputCommand::ContinousCommandTag 和转换后的 ContinuousValue 打包进 FContinuousPayload
|
||||
- **空载荷构建**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandInputComponent.cpp:75` -- 离散命令时 ContinuousPayload 为空
|
||||
- **连续命令匹配**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouter.cpp:277` -- 连续命令路由时,端点必须声明 bIsContinuousFriendly 且 InterestedTags 包含 CommandTag 才能收到命令
|
||||
43
Plugins/CharacterControl/FDiscreteMeta.md
Normal file
43
Plugins/CharacterControl/FDiscreteMeta.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# FDiscreteMeta
|
||||
|
||||
## 基本信息
|
||||
- **类型**: USTRUCT(BlueprintType)
|
||||
- **父类**: (none)
|
||||
- **源文件**: Plugins/CharacterControl/Source/CharacterControl/Public/CommandEndpoint.h
|
||||
- **模块**: CharacterControl
|
||||
|
||||
## 功能概述
|
||||
Routing metadata for discrete (one-shot) commands. Contains CommandTags (FGameplayTagContainer, semantic IDs for endpoint matching) and bIsAll (bool, match mode: ALL tags must match vs ANY tag).
|
||||
|
||||
## 设计用意
|
||||
Bridges raw input events to tag-based subscription model. Defines matching semantics. TInstancedStruct in FCommandPacket allows this to be subclassed for specialized routing logic.
|
||||
|
||||
## 职责范围
|
||||
Defines subscription matching rules for one discrete command. Used by UCommandRouter::IsEndpointMatched for endpoint filtering.
|
||||
|
||||
## 项目内依赖
|
||||
| 依赖项 | 关系 | 源文件 |
|
||||
|--------|------|--------|
|
||||
| (none) | | |
|
||||
|
||||
## 对外接口
|
||||
FDiscreteMeta 定义离散命令的订阅匹配规则。作为 TInstancedStruct<FDiscreteMeta> 嵌入在 FCommandPacket::DiscretePayload 和 FInputCommand::DiscreteCommandMeta 中。所有字段为 BlueprintReadWrite。
|
||||
|
||||
- **CommandTags** (FGameplayTagContainer, BlueprintReadWrite): 离散命令携带的语义标签集合,路由时与端点 InterestedTags 进行匹配
|
||||
- **bIsAll** (bool, BlueprintReadWrite): 匹配模式开关。true = ALL 模式(端点必须包含所有 CommandTags),false = ANY 模式(端点包含任意一个即可)
|
||||
|
||||
调用者在 UInputCommandData 资产中配置每个 FInputCommand 的 DiscreteCommandMeta。运行时由 UCommandRouter::IsEndpointMatched 读取并执行匹配逻辑。因为有 TInstancedStruct 支持,可子类化 FDiscreteMeta 添加自定义路由字段。
|
||||
|
||||
## 使用方法
|
||||
FDiscreteMeta 在 InputCommandData 资产中配置,运行时由路由器使用:
|
||||
|
||||
- **配置定义**: `Plugins/CharacterControl/Source/CharacterControl/Public/InputCommandData.h:24` -- FInputCommand::DiscreteCommandMeta 字段类型为 `TInstancedStruct<FDiscreteMeta>`
|
||||
- **包构建**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandInputComponent.cpp:76-78` -- 离散命令时 DiscretePayload 直接取用 Command.DiscreteCommandMeta
|
||||
- **提取验证**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouter.cpp:221-249` -- ExtractDiscreteMeta 验证 bIsContinuous、有效性、类型兼容性后提取
|
||||
- **匹配判断**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouter.cpp:301-327` -- IsEndpointMatched 根据 bIsAll 使用 HasAll 或 HasAny 匹配
|
||||
|
||||
## 用例
|
||||
- **ALL 模式匹配**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouter.cpp:308-318` -- 当 bIsAll 为 true 时,端点必须用 HasAll 完全包含命令的所有 CommandTags 才会被投递
|
||||
- **ANY 模式匹配**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouter.cpp:322-323` -- 当 bIsAll 为 false 时,端点 InterestedTags 中包含任意一个 CommandTags 即命中
|
||||
- **类型兼容性检查**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouter.cpp:240-245` -- ExtractDiscreteMeta 运行时检查 DiscretePayload 的 ScriptStruct 是否为 FDiscreteMeta 的子类,确保 TInstancedStruct 扩展安全
|
||||
- **空命令防护**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouter.cpp:311-315` -- CommandTags 为空时不匹配任何端点,避免无标签命令广播给所有端点
|
||||
47
Plugins/CharacterControl/FEndpointState.md
Normal file
47
Plugins/CharacterControl/FEndpointState.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# FEndpointState
|
||||
|
||||
## 基本信息
|
||||
- **类型**: USTRUCT(BlueprintType) with TStructOpsTypeTraits specialization
|
||||
- **父类**: (none)
|
||||
- **源文件**: Plugins/CharacterControl/Source/CharacterControl/Public/CommandEndpoint.h
|
||||
- **模块**: CharacterControl
|
||||
|
||||
## 功能概述
|
||||
Full state and identity of a command endpoint. Contains EndpointGuid (FGuid, unique identity), InterestedTags (FGameplayTagContainer, subscription list), bIsActive, bIsContinuousFriendly, bIsAsynchronous flags. Custom operator= preserves GUID on copy while updating config fields. TStructOpsTypeTraits with WithCopy=true forces UE to use C++ copy path instead of memcpy.
|
||||
|
||||
## 设计用意
|
||||
Solves endpoint identity problem in dynamic routing graph. Custom copy operator prevents CDO/Blueprint default overwriting of runtime-assigned GUID. Tag subscription model enables declarative routing (no hard references between producers/consumers).
|
||||
|
||||
## 职责范围
|
||||
Identity and configuration for one endpoint in the routing graph. GUID serves as registry key in UCommandRouter. Tags determine which commands the endpoint receives.
|
||||
|
||||
## 项目内依赖
|
||||
| 依赖项 | 关系 | 源文件 |
|
||||
|--------|------|--------|
|
||||
| (none) | | |
|
||||
|
||||
## 对外接口
|
||||
FEndpointState 定义命令端点的完整身份和配置。在 UCommandRouter::EndpointState、UEndpointComponent::EndpointState、UEndpointDispatcher::CurrentState 中作为成员使用。
|
||||
|
||||
- **EndpointGuid** (FGuid, VisibleAnywhere, BlueprintReadOnly): 端点的唯一标识符,自动初始化为 NewGuid(),路由注册表以此为 Key。自定义 operator= 在目标已有身份时保留 GUID,防止 CDO/蓝图赋值覆盖运行时身份
|
||||
- **InterestedTags** (FGameplayTagContainer, EditDefaultsOnly, BlueprintReadOnly): 端点订阅的命令标签集合,决定端点接收哪些命令
|
||||
- **bIsActive** (bool, EditDefaultsOnly, BlueprintReadOnly): 端点活跃开关,false 时 IsEndpointMatched 直接返回 false,端点不接收任何命令
|
||||
- **bIsContinuousFriendly** (bool, EditDefaultsOnly, BlueprintReadOnly): 是否接收连续命令,false 的端点不会被投递连续命令
|
||||
- **bIsAsynchronous** (bool, EditDefaultsOnly, BlueprintReadOnly): 异步端点标志,端点应在自身 ReceiveCommand 中自行调度异步执行以保证线程安全
|
||||
|
||||
FEndpointState 有 TStructOpsTypeTraits<WithCopy=true> 特化,强制 UE 使用 C++ 拷贝路径(而非 memcpy),确保自定义 operator= 被正确调用。
|
||||
|
||||
## 使用方法
|
||||
FEndpointState 在不同位置设定和使用:
|
||||
|
||||
- **端点配置**: `Plugins/CharacterControl/Source/CharacterControl/Private/EndpointComponent.cpp:13` -- UEndpointComponent 构造函数中设置 `EndpointState.bIsActive = true`
|
||||
- **路由器配置**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouter.cpp:8-11` -- UCommandRouter 构造函数中设置 `bIsActive=true, bIsContinuousFriendly=true, bIsAsynchronous=false`
|
||||
- **注册时读取**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouter.cpp:52-53` -- RegisterEndpoint 读取 EndpointGuid 验证有效性和唯一性
|
||||
- **匹配时读取**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouter.cpp:266-298` -- IsEndpointMatched 读取 bIsActive 和 bIsContinuousFriendly 决定匹配结果
|
||||
- **状态变更**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouter.cpp:33-42` -- SetRouterState 只更新配置字段,保留 Guid 并广播 StateChangedDelegate
|
||||
|
||||
## 用例
|
||||
- **GUID 保护机制**: `Plugins/CharacterControl/Source/CharacterControl/Public/CommandEndpoint.h:88-105` -- 自定义 operator= 通过 bGuidAssigned 标志判断:未分配时拷贝 GUID,已分配时保留现有 GUID。防止蓝图 CDO 属性灌装覆盖运行时赋予的唯一 ID
|
||||
- **端点注册验证**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouter.cpp:53-58` -- RegisterEndpoint 检查 EndpointGuid 有效性,无效时拒绝注册并输出警告
|
||||
- **自注册防护**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouter.cpp:65-69` -- 检查端点 GUID 是否等于路由器自身 GUID,防止拓扑环路
|
||||
- **匹配判断入口**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouter.cpp:268-271` -- bIsActive 为 false 时直接返回 false,快速短路所有匹配逻辑
|
||||
44
Plugins/CharacterControl/FInputCommand.md
Normal file
44
Plugins/CharacterControl/FInputCommand.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# FInputCommand
|
||||
|
||||
## 基本信息
|
||||
- **类型**: USTRUCT(BlueprintType)
|
||||
- **父类**: (none)
|
||||
- **源文件**: Plugins/CharacterControl/Source/CharacterControl/Public/InputCommandData.h
|
||||
- **模块**: CharacterControl
|
||||
|
||||
## 功能概述
|
||||
Data row mapping a UInputAction to command routing parameters. Contains InputAction reference, bIsContinuous flag, ContinousCommandTag (FGameplayTag for continuous), DiscreteCommandMeta (TInstancedStruct<FDiscreteMeta> for discrete).
|
||||
|
||||
## 设计用意
|
||||
Designer configuration unit. Answers "When this input fires, what command packet should be generated?" Separates continuous and discrete metadata into distinct fields reflecting different routing semantics.
|
||||
|
||||
## 职责范围
|
||||
Configuration data for one input-to-command mapping. Used by UCommandInputComponent::BuildPacket. Stored in UInputCommandData::InputCommands array.
|
||||
|
||||
## 项目内依赖
|
||||
| 依赖项 | 关系 | 源文件 |
|
||||
|--------|------|--------|
|
||||
| CommandEndpoint.h | #include (for FDiscreteMeta, etc.) | Plugins/CharacterControl/Source/CharacterControl/Public/CommandEndpoint.h |
|
||||
|
||||
## 对外接口
|
||||
FInputCommand 是一个纯数据配置结构体,定义"某个 Enhanced Input 动作触发时生成什么命令"的映射规则。在 UInputCommandData 资产编辑器中通过详情面板配置。所有字段为 BlueprintReadWrite。
|
||||
|
||||
- **InputAction** (TObjectPtr<UInputAction>, BlueprintReadWrite): 引用的 Enhanced Input Action 资产,用于绑定输入事件
|
||||
- **bIsContinuous** (bool, BlueprintReadWrite): 命令类型开关。true = 连续命令(使用 Triggered 事件,每帧触发),false = 离散命令(使用 Started 事件,一次性)
|
||||
- **ContinousCommandTag** (FGameplayTag, BlueprintReadWrite): 连续命令的语义标签,BuildPacket 时写入 FContinuousPayload::CommandTag
|
||||
- **DiscreteCommandMeta** (TInstancedStruct<FDiscreteMeta>, BlueprintReadWrite): 离散命令的路由元数据,包含 CommandTags 和 bIsAll 匹配模式。BuildPacket 时直接拷贝到 FCommandPacket::DiscretePayload
|
||||
|
||||
调用者通过 UInputCommandData 资产配置 FInputCommand 数组,运行时由 UCommandInputComponent::BuildPacket 逐字段读取构建命令包。
|
||||
|
||||
## 使用方法
|
||||
FInputCommand 在 UInputCommandData::InputCommands 数组中配置,运行时由 UCommandInputComponent 读取:
|
||||
|
||||
- **配置定义**: `Plugins/CharacterControl/Source/CharacterControl/Public/InputCommandData.h:39` -- UInputCommandData::InputCommands 类型为 `TArray<FInputCommand>`
|
||||
- **BuildPacket 消费**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandInputComponent.cpp:41-80` -- BuildPacket 从 FInputCommand 读取 InputAction(获取 CommandID)、bIsContinuous(决定处理路径)、ContinousCommandTag(连续载荷标签)、DiscreteCommandMeta(离散载荷)
|
||||
- **绑定循环**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandInputComponent.cpp:96` -- BindAllCommands 遍历 `CommandData->InputCommands` 数组
|
||||
- **事件类型选择**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandInputComponent.cpp:99-101` -- 根据 bIsContinuous 选择 ETriggerEvent::Triggered 或 Started
|
||||
|
||||
## 用例
|
||||
- **连续命令配置**: 策划在 UInputCommandData 资产中将某个 FInputCommand 的 bIsContinuous 设为 true,设置 ContinousCommandTag(如 "Input.Move"),BuildPacket 将摇杆移动量转为 FVector3f,生成每帧触发的连续命令包
|
||||
- **离散命令配置**: 策划将 bIsContinuous 设为 false,配置 DiscreteCommandMeta.CommandTags(如 "Action.Jump")和 bIsAll 匹配模式,BuildPacket 在按键按下时生成一次性命令包
|
||||
- **BuidPacket 字段读取**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandInputComponent.cpp:70-78` -- BuildPacket 逐一读取 Command.InputAction(CommandID)、Command.bIsContinuous(Meta+载荷选择)、Command.ContinousCommandTag(连续载荷)、Command.DiscreteCommandMeta(离散载荷),组装完整的 FCommandPacket
|
||||
56
Plugins/CharacterControl/ICommandEndpoint.md
Normal file
56
Plugins/CharacterControl/ICommandEndpoint.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# ICommandEndpoint
|
||||
|
||||
## 基本信息
|
||||
- **类型**: UINTERFACE + C++ interface
|
||||
- **父类**: UInterface
|
||||
- **源文件**: Plugins/CharacterControl/Source/CharacterControl/Public/CommandEndpoint.h
|
||||
- **模块**: CharacterControl
|
||||
|
||||
## 功能概述
|
||||
Central abstraction for all nodes in command routing graph. Pure virtual methods: GetEndpointState, GetStateChangedDelegate, GetCommandOutputDelegate, ReceiveCommand. BlueprintNativeEvents: ReceiveCommand_BP, GetEndpointDispatcher_BP. Default C++ implementations route through dispatcher for Blueprint subclasses, while C++ subclasses override directly.
|
||||
|
||||
## 设计用意
|
||||
Uniform interface enabling heterogeneous routing graph. Routers manage collections of ICommandEndpoint without knowing concrete types. Dispatcher pattern solves UE limitation that BlueprintNativeEvent can't return delegate references directly.
|
||||
|
||||
## 职责范围
|
||||
Defines contract for command routing participants. All routers, endpoint components, and input components implement this. Single ReceiveCommand entry point for all command types.
|
||||
|
||||
## 项目内依赖
|
||||
| 依赖项 | 关系 | 源文件 |
|
||||
|--------|------|--------|
|
||||
| FEndpointState | 返回类型 (GetEndpointState) | Plugins/CharacterControl/Source/CharacterControl/Public/CommandEndpoint.h |
|
||||
| FCommandPacket | 参数类型 (ReceiveCommand) | Plugins/CharacterControl/Source/CharacterControl/Public/CommandEndpoint.h |
|
||||
| UEndpointDispatcher | 返回类型 (GetEndpointDispatcher_BP) | Plugins/CharacterControl/Source/CharacterControl/Public/CommandEndpoint.h |
|
||||
|
||||
## 对外接口
|
||||
ICommandEndpoint 是命令路由图中所有参与者的统一抽象接口。任何希望接收或产出命令的对象都需要实现此接口。接口包含四个 C++ 纯虚方法和两个 BlueprintNativeEvent。
|
||||
|
||||
**C++ 纯虚方法**(C++ 子类直接重写):
|
||||
|
||||
- **GetEndpointState()** -> const FEndpointState&: 返回端点的身份和配置状态。UCommandRouter::RegisterEndpoint 以此获取 GUID 和 InterestedTags
|
||||
- **GetStateChangedDelegate()** -> FOnEndpointStateChanged&: 返回状态变更委托引用。Router 通过 BindDynamic 订阅,当端点状态变化时触发标签聚合更新
|
||||
- **GetCommandOutputDelegate()** -> FOnCommandOutput&: 返回命令输出委托引用。Router 订阅以接收端点产出的命令,转发给其他端点
|
||||
- **ReceiveCommand(const FCommandPacket&)**: 接收命令的统一入口。Router 调用此方法向匹配的端点投递命令
|
||||
|
||||
**BlueprintNativeEvent**(蓝图子类重写):
|
||||
|
||||
- **ReceiveCommand_BP(const FCommandPacket&)**: 蓝图端点的命令接收入口。C++ 默认实现通过调度器桥接调用此事件
|
||||
- **GetEndpointDispatcher_BP()** -> UEndpointDispatcher*: 蓝图端点返回调度器实例。C++ 默认实现通过此方法获取委托引用
|
||||
|
||||
**默认实现策略**:C++ 默认实现(CommandEndpoint.cpp:8-26)全部通过 Execute_GetEndpointDispatcher_BP 获取 UEndpointDispatcher,然后委托执行。这意味着蓝图类(如 UEndpointComponent_BP 子类)必须重写 GetEndpointDispatcher_BP 并返回有效调度器。C++ 类(UCommandRouter、UCommandRouterComponent、UEndpointComponent)则直接重写纯虚函数,不使用调度器。
|
||||
|
||||
## 使用方法
|
||||
ICommandEndpoint 是接口而非具体类,通过 TScriptInterface<ICommandEndpoint> 在多处使用:
|
||||
|
||||
- **路由器注册**: `Plugins/CharacterControl/Source/CharacterControl/Public/CommandRouter.h:37` -- RegisterEndpoint 接受 `TScriptInterface<ICommandEndpoint>`,从接口获取端点状态、委托并完成注册
|
||||
- **路由器实现**: `Plugins/CharacterControl/Source/CharacterControl/Public/CommandRouter.h:14` -- UCommandRouter 实现此接口,作为端点参与上级路由器的路由
|
||||
- **组件实现**: `Plugins/CharacterControl/Source/CharacterControl/Public/CommandRouterComponent.h:14` -- UCommandRouterComponent 实现此接口,委托给 InternalRouter
|
||||
- **端点组件实现**: `Plugins/CharacterControl/Source/CharacterControl/Public/EndpointComponent.h:13` -- UEndpointComponent 实现此接口,作为蓝图端点的基类
|
||||
- **默认 C++ 实现**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandEndpoint.cpp:8-26` -- 所有纯虚函数的默认实现,通过调度器桥接蓝图
|
||||
|
||||
## 用例
|
||||
- **Router 实现端点的 ReceiveCommand**: `Plugins/CharacterControl/Source/CharacterControl/Public/CommandRouter.h:22-25` -- UCommandRouter 直接重写 ReceiveCommand、GetEndpointState、GetStateChangedDelegate、GetCommandOutputDelegate,不使用调度器桥接
|
||||
- **EndpointComponent 实现端点的 ReceiveCommand**: `Plugins/CharacterControl/Source/CharacterControl/Public/EndpointComponent.h:30-33` -- UEndpointComponent 直接重写纯虚方法,ReceiveCommand 转调 BlueprintImplementableEvent OnCommandReceived
|
||||
- **端点注册入口**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouter.cpp:45-84` -- RegisterEndpoint 通过 TScriptInterface 获取端点的 EndpointGuid、委托,绑定状态变更和命令输出回调,执行标签聚合
|
||||
- **自动发现注册**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouterComponent.cpp:37-41` -- AutoRegisterEndpoints 遍历 Actor 组件,通过 `Implements<UCommandEndpoint>()` 检查并注册所有实现接口的兄弟组件
|
||||
- **蓝图桥接**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandEndpoint.cpp:23-26` -- 蓝图类没有重写 ReceiveCommand 时,C++ 默认实现调用 Execute_ReceiveCommand_BP,由蓝图元数据系统查找蓝图重写
|
||||
56
Plugins/CharacterControl/UCommandInputComponent.md
Normal file
56
Plugins/CharacterControl/UCommandInputComponent.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# UCommandInputComponent
|
||||
|
||||
## 基本信息
|
||||
- **类型**: UCLASS(BlueprintSpawnableComponent, Blueprintable)
|
||||
- **父类**: UEndpointComponent
|
||||
- **源文件**: Plugins/CharacterControl/Source/CharacterControl/Public/CommandInputComponent.h
|
||||
- **模块**: CharacterControl
|
||||
|
||||
## 功能概述
|
||||
Translates Enhanced Input actions into FCommandPacket commands. BeginPlay adds InputMappingContext to local player subsystem, then binds all InputActions from CommandData. BuildPacket converts Boolean/Axis1D/Axis2D/Axis3D values to FVector3f. Continuous commands use Triggered (every frame), discrete use Started. OnPacketBuilt virtual hook for inspection/modification. Default hop limits: 3 continuous, 5 discrete.
|
||||
|
||||
## 设计用意
|
||||
Bridge between UE Enhanced Input and tag-based routing. Decouples gameplay logic from input bindings - systems subscribe to tags instead. Same input can trigger different responses based on state. Hop limit differentiation reflects frequency differences.
|
||||
|
||||
## 职责范围
|
||||
Input-to-command translation. Binds Enhanced Input actions, converts values to command packets, outputs via delegate. Does NOT route commands.
|
||||
|
||||
## 项目内依赖
|
||||
| 依赖项 | 关系 | 源文件 |
|
||||
|--------|------|--------|
|
||||
| EndpointComponent.h | #include (parent) | Plugins/CharacterControl/Source/CharacterControl/Public/EndpointComponent.h |
|
||||
| UInputCommandData | forward-declare (header) | Plugins/CharacterControl/Source/CharacterControl/Public/CommandInputComponent.h |
|
||||
| FInputCommand | forward-declare (header) | Plugins/CharacterControl/Source/CharacterControl/Public/CommandInputComponent.h |
|
||||
| InputCommandData.h | #include (in .cpp) | Plugins/CharacterControl/Source/CharacterControl/Public/InputCommandData.h |
|
||||
|
||||
## 对外接口
|
||||
UCommandInputComponent 继承 UEndpointComponent,是 Enhanced Input 到命令路由系统的翻译器。挂载到 APlayerController 上,自动加载 InputMappingContext 并将输入动作绑定为命令。
|
||||
|
||||
**配置属性**:
|
||||
|
||||
- **CommandData** (TObjectPtr<UInputCommandData>, EditAnywhere, BlueprintReadOnly): 指向 UInputCommandData 资产,包含要加载的 InputMappingContext 和 FInputCommand 映射列表
|
||||
|
||||
**可重写方法**:
|
||||
|
||||
- **BuildPacket(const FInputCommand&, const FInputActionInstance&) -> FCommandPacket** (virtual): 根据配置和运行时输入值构建命令包。默认实现:Boolean -> ZeroVector/OneVector, Axis1D -> X, Axis2D -> XY, Axis3D -> XYZ。连续命令 HopLimit=3,离散命令 HopLimit=5。C++ 子类可重写自定义构造逻辑
|
||||
- **OnPacketBuilt(const FInputCommand&, FCommandPacket&)** (virtual): 钩子函数,在包构建完成、广播之前调用。子类可在此检查、修改或拦截命令包。默认实现为空
|
||||
|
||||
**继承自 UEndpointComponent 的接口**:
|
||||
|
||||
- OnCommandReceived、OnEndpointStateChanged、OnCommandOutput、EndpointState 等全部可用。同时自动注册到兄弟 UCommandRouterComponent
|
||||
|
||||
## 使用方法
|
||||
将 UCommandInputComponent 添加到 PlayerController,配置 CommandData 资产即可:
|
||||
|
||||
- **BeginPlay 初始化**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandInputComponent.cpp:16-32` -- 获取 PlayerController,通过 UEnhancedInputLocalPlayerSubsystem 添加 InputMappingContext,调用 BindAllCommands
|
||||
- **EndPlay 清理**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandInputComponent.cpp:34-39` -- 调用 UnbindAllCommands 移除所有输入绑定,再调用 Super::EndPlay
|
||||
- **BuildPacket**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandInputComponent.cpp:41-80` -- 根据动作值类型转换输入值,设置 Meta 和载荷字段
|
||||
- **BindAllCommands**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandInputComponent.cpp:82-116` -- 遍历 CommandData->InputCommands,使用 BindActionInstanceLambda 绑定。连续命令用 ETriggerEvent::Triggered,离散命令用 Started
|
||||
- **UnbindAllCommands**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandInputComponent.cpp:118-133` -- 遍历 BindingHandles 逐一 RemoveBindingByHandle 后清空数组
|
||||
|
||||
## 用例
|
||||
- **完整输入翻译**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandInputComponent.cpp:96-114` -- BindAllCommands 对每个 FInputCommand 绑定 lambda:BuildPacket 构建包 -> OnPacketBuilt 钩子修改 -> OnCommandOutput.ExecuteIfBound 广播。一条输入动作的完整流水线
|
||||
- **连续命令(Triggered)**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandInputComponent.cpp:99-100` -- bIsContinuous 为 true 时绑定 ETriggerEvent::Triggered,每帧触发,用于移动、瞄准等模拟量操作
|
||||
- **离散命令(Started)**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandInputComponent.cpp:101` -- bIsContinuous 为 false 时绑定 ETriggerEvent::Started,按一次触发一次,用于跳跃、射击等一次性动作
|
||||
- **输入值类型转换**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandInputComponent.cpp:49-67` -- 根据 GetValueType() 将 Boolean/Axis1D/Axis2D/Axis3D 统一转为 FVector3f,实现多类型输入的标准化输出
|
||||
- **InputMappingContext 加载**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandInputComponent.cpp:20-29` -- BeginPlay 中通过 UEnhancedInputLocalPlayerSubsystem::AddMappingContext 加载映射上下文
|
||||
63
Plugins/CharacterControl/UCommandRouter.md
Normal file
63
Plugins/CharacterControl/UCommandRouter.md
Normal file
@@ -0,0 +1,63 @@
|
||||
# UCommandRouter
|
||||
|
||||
## 基本信息
|
||||
- **类型**: UCLASS(BlueprintType, EditInlineNew, DefaultToInstanced)
|
||||
- **父类**: UObject, implements ICommandEndpoint
|
||||
- **源文件**: Plugins/CharacterControl/Source/CharacterControl/Public/CommandRouter.h
|
||||
- **模块**: CharacterControl
|
||||
|
||||
## 功能概述
|
||||
Core command routing engine. Manages child endpoint registry (TMap<FGuid, FEndpointEntry>). Implements tag-based matching with two modes: continuous (tag + ContinuousFriendly check) and discrete (tag ALL/ANY matching). Tag aggregation system merges child tags upward with ref-counting. Hop-limit guarded dispatch. Upward propagation for child output commands. Self-identity protection prevents circular registration.
|
||||
|
||||
## 设计用意
|
||||
Heart of the plugin. Tag-based publish-subscribe bus replacing hard references. Hierarchical tree topology support (routers inside routers). Hop-limit prevents infinite loops. Tag aggregation enables efficient parent-level filtering. EditInlineNew/DefaultToInstanced for embedding in components.
|
||||
|
||||
## 职责范围
|
||||
Command routing and endpoint management. Registers/unregisters endpoints. Matches and dispatches commands. Aggregates and manages tag subscriptions. Does NOT generate commands (input components do that).
|
||||
|
||||
## 项目内依赖
|
||||
| 依赖项 | 关系 | 源文件 |
|
||||
|--------|------|--------|
|
||||
| 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,防止路由器将自己注册为子端点造成环路
|
||||
45
Plugins/CharacterControl/UCommandRouterComponent.md
Normal file
45
Plugins/CharacterControl/UCommandRouterComponent.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# UCommandRouterComponent
|
||||
|
||||
## 基本信息
|
||||
- **类型**: UCLASS(BlueprintSpawnableComponent, Blueprintable)
|
||||
- **父类**: UActorComponent, implements ICommandEndpoint
|
||||
- **源文件**: Plugins/CharacterControl/Source/CharacterControl/Public/CommandRouterComponent.h
|
||||
- **模块**: CharacterControl
|
||||
|
||||
## 功能概述
|
||||
ActorComponent wrapper around UCommandRouter. Creates InternalRouter as default subobject. Implements ICommandEndpoint by delegating all methods to InternalRouter. BeginPlay calls AutoRegisterEndpoints which discovers ICommandEndpoint siblings and registers them, skipping self and already-registered endpoints.
|
||||
|
||||
## 设计用意
|
||||
Bridge putting a command router on an Actor without C++. Auto-registration implements "local bus" pattern: all endpoint components on same actor auto-wire through this router. Designer adds component -> automatic local command bus.
|
||||
|
||||
## 职责范围
|
||||
Actor-attached router host. Owns and delegates to UCommandRouter. Auto-discovers and registers sibling endpoints. Does NOT implement routing logic (delegated to InternalRouter).
|
||||
|
||||
## 项目内依赖
|
||||
| 依赖项 | 关系 | 源文件 |
|
||||
|--------|------|--------|
|
||||
| CommandEndpoint.h | #include | Plugins/CharacterControl/Source/CharacterControl/Public/CommandEndpoint.h |
|
||||
| CommandRouter.h | #include | Plugins/CharacterControl/Source/CharacterControl/Public/CommandRouter.h |
|
||||
|
||||
## 对外接口
|
||||
UCommandRouterComponent 是将 UCommandRouter 挂载到 Actor 上的组件包装器。实现 ICommandEndpoint 接口(全部委托给 InternalRouter),使得挂载此组件的 Actor 本身可作为端点参与上级路由。
|
||||
|
||||
- **InternalRouter** (TObjectPtr<UCommandRouter>, EditAnywhere, BlueprintReadOnly, Instanced): 暴露给蓝图的设计时属性,可在组件详情面板中查看/配置路由器的端点状态。作为默认子对象通过 CreateDefaultSubobject 创建
|
||||
- **实现 ICommandEndpoint**: GetEndpointState、GetStateChangedDelegate、GetCommandOutputDelegate、ReceiveCommand 全部直接委托给 InternalRouter 的同名方法。这意味着对 UCommandRouterComponent 调用 ReceiveCommand 等价于向 InternalRouter 注入命令
|
||||
|
||||
UCommandRouterComponent 的核心价值在于 BeginPlay 自动调用 AutoRegisterEndpoints()。不需要手动注册端点 -- 只需将 UEndpointComponent 或 UCommandInputComponent 作为兄弟组件添加到同一 Actor 上,BeginPlay 时自动发现并注册。
|
||||
|
||||
## 使用方法
|
||||
UCommandRouterComponent 是"即插即用"的本地命令总线:
|
||||
|
||||
- **创建默认子对象**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouterComponent.cpp:15` -- 构造函数中 `CreateDefaultSubobject<UCommandRouter>("InternalCommandRouter")`
|
||||
- **BeginPlay 自动注册**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouterComponent.cpp:20-24` -- BeginPlay 调用 Super::BeginPlay 后立即执行 AutoRegisterEndpoints
|
||||
- **自动发现**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouterComponent.cpp:27-43` -- 遍历 Owner 的所有 UActorComponent,通过 `Implements<UCommandEndpoint>()` 检查,跳过自身和已注册(委托已绑定)的端点,其余全部注册
|
||||
- **端点自注册**: `Plugins/CharacterControl/Source/CharacterControl/Private/EndpointComponent.cpp:22-42` -- UEndpointComponent::BeginPlay 也会主动查找兄弟 UCommandRouterComponent 并注册
|
||||
- **端点间通信**: 注册后的端点通过路由器互相收发命令。端点 A 调用 OutputCommand -> Router 接收 -> 匹配 -> 投递到端点 B 的 ReceiveCommand
|
||||
|
||||
## 用例
|
||||
- **Actor 本地命令总线**: 在 Character 蓝图上添加 UCommandRouterComponent + UCommandInputComponent + UEndpointComponent(蓝图子类),BeginPlay 时自动完成连线,输入组件产出的命令自动匹配到端点组件
|
||||
- **自动注册兄弟端点**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouterComponent.cpp:31-42` -- AutoRegisterEndpoints 遍历所有兄弟组件,调用 Implements<UCommandEndpoint>() 检查接口实现,将未注册的端点通过 InternalRouter->RegisterEndpoint 注册
|
||||
- **跳过已注册端点**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandRouterComponent.cpp:40` -- 通过 `GetCommandOutputDelegate().IsBound()` 判断端点是否已注册(委托已绑 = 已注册),避免重复注册
|
||||
- **以路由器作为端点参与上级路由**: 由于 UCommandRouterComponent 实现 ICommandEndpoint 且全部委托给 InternalRouter,其他 Actor 上的上级路由器可以通过 TScriptInterface<ICommandEndpoint> 将此组件注册为端点
|
||||
53
Plugins/CharacterControl/UEndpointComponent.md
Normal file
53
Plugins/CharacterControl/UEndpointComponent.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# UEndpointComponent
|
||||
|
||||
## 基本信息
|
||||
- **类型**: UCLASS(BlueprintSpawnableComponent, Blueprintable)
|
||||
- **父类**: UActorComponent, implements ICommandEndpoint
|
||||
- **源文件**: Plugins/CharacterControl/Source/CharacterControl/Public/EndpointComponent.h
|
||||
- **模块**: CharacterControl
|
||||
|
||||
## 功能概述
|
||||
Base ActorComponent for Blueprint-authored endpoints. Holds own FEndpointState, delegates. ReceiveCommand calls OnCommandReceived (BlueprintImplementableEvent). BeginPlay auto-registers with sibling UCommandRouterComponent.
|
||||
|
||||
## 设计用意
|
||||
Primary base class for Blueprint endpoints. Subclass in Blueprint, override OnCommandReceived. Auto-wiring with UCommandRouterComponent for default setup. Blueprintable meta explicitly encourages Blueprint subclassing.
|
||||
|
||||
## 职责范围
|
||||
Blueprint-friendly endpoint base. Handles state, delegates, and auto-registration. OnCommandReceived event is the Blueprint extension point.
|
||||
|
||||
## 项目内依赖
|
||||
| 依赖项 | 关系 | 源文件 |
|
||||
|--------|------|--------|
|
||||
| CommandEndpoint.h | #include | Plugins/CharacterControl/Source/CharacterControl/Public/CommandEndpoint.h |
|
||||
|
||||
## 对外接口
|
||||
UEndpointComponent 是蓝图端点的主要基类。BlueprintSpawnableComponent + Blueprintable 允许直接在蓝图中创建子类并重写事件。
|
||||
|
||||
**蓝图可重写事件**:
|
||||
|
||||
- **OnCommandReceived(const FCommandPacket&)** (BlueprintImplementableEvent): 蓝图的主要扩展点。当路由器投递命令到此端点时调用。蓝图子类重写此事件实现具体逻辑(移动、技能、UI 等)。C++ 侧 ReceiveCommand 直接调用此事件
|
||||
|
||||
**委托(C++ 访问)**:
|
||||
|
||||
- **OnEndpointStateChanged** (FOnEndpointStateChanged, BlueprintReadOnly): 状态变更委托。被路由器订阅以触发标签聚合更新
|
||||
- **OnCommandOutput** (FOnCommandOutput, BlueprintReadOnly): 命令输出委托。端点产出命令时通过此委托广播,由路由器接收并转发
|
||||
|
||||
**配置**:
|
||||
|
||||
- **EndpointState** (FEndpointState, EditAnywhere): 端点的身份和配置。在组件详情面板中设置 InterestedTags、bIsActive、bIsContinuousFriendly、bIsAsynchronous。EndpointGuid 自动生成
|
||||
|
||||
**自动注册**:BeginPlay 时 UEndpointComponent 主动查找兄弟 UCommandRouterComponent 并通过其 InternalRouter->RegisterEndpoint(this) 注册。只需将端点组件添加到有 UCommandRouterComponent 的 Actor 上即可自动接入本地命令总线。
|
||||
|
||||
## 使用方法
|
||||
蓝图子类化 UEndpointComponent 并配置 EndpointState 是最常见的端点创建方式:
|
||||
|
||||
- **构造函数初始化**: `Plugins/CharacterControl/Source/CharacterControl/Private/EndpointComponent.cpp:8-14` -- 构造函数中设置 bIsActive=true,禁用 Tick
|
||||
- **ReceiveCommand 桥接**: `Plugins/CharacterControl/Source/CharacterControl/Private/EndpointComponent.cpp:16-19` -- ReceiveCommand 直接调用 OnCommandReceived(Command),将 C++ 接口调用桥接到蓝图事件
|
||||
- **BeginPlay 自动注册**: `Plugins/CharacterControl/Source/CharacterControl/Private/EndpointComponent.cpp:22-42` -- 查找 Owner 上的 UCommandRouterComponent,通过 `OnCommandOutput.IsBound()` 判断是否已注册,未注册则调用 `Router->InternalRouter->RegisterEndpoint(this)`
|
||||
- **注册到第一个路由器**: `Plugins/CharacterControl/Source/CharacterControl/Private/EndpointComponent.cpp:39` -- `break` 语句确保只注册到第一个找到的 UCommandRouterComponent
|
||||
|
||||
## 用例
|
||||
- **蓝图端点实现**: 创建 Blueprint 类继承 UEndpointComponent,在 EndpointState 中配置 InterestedTags(如 "Input.Move", "Action.Jump"),在 Event Graph 中重写 OnCommandReceived 实现具体逻辑
|
||||
- **自动连线**: `Plugins/CharacterControl/Source/CharacterControl/Private/EndpointComponent.cpp:22-42` -- BeginPlay 自动找到兄弟 UCommandRouterComponent 并注册。策划只需将组件拖入 Actor 即可,无需手动连线
|
||||
- **重复注册防护**: `Plugins/CharacterControl/Source/CharacterControl/Private/EndpointComponent.cpp:34-37` -- 通过检查 OnCommandOutput.IsBound() 判断是否已注册,避免重复注册导致标签聚合错误
|
||||
- **只注册到一个路由器**: `Plugins/CharacterControl/Source/CharacterControl/Private/EndpointComponent.cpp:39` -- break 退出循环,一个端点只注册到一个路由器
|
||||
47
Plugins/CharacterControl/UEndpointDispatcher.md
Normal file
47
Plugins/CharacterControl/UEndpointDispatcher.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# UEndpointDispatcher
|
||||
|
||||
## 基本信息
|
||||
- **类型**: UCLASS(BlueprintType)
|
||||
- **父类**: UObject
|
||||
- **源文件**: Plugins/CharacterControl/Source/CharacterControl/Public/CommandEndpoint.h
|
||||
- **模块**: CharacterControl
|
||||
|
||||
## 功能概述
|
||||
Bridge object exposing endpoint delegates to Blueprint. Holds OnStateChanged and OnCommandOutput delegates, plus CurrentState. Provides NotifyStateChanged/OutputCommand wrapper UFUNCTIONs for Blueprint callers.
|
||||
|
||||
## 设计用意
|
||||
Glue between C++ delegates and Blueprint VM. Blueprint endpoint implementations return this via GetEndpointDispatcher_BP. The ICommandEndpoint default C++ implementations all route through this dispatcher.
|
||||
|
||||
## 职责范围
|
||||
Delegate bridge for Blueprint endpoints. Broadcasts state changes and command output to C++ observers. Does NOT implement endpoint logic.
|
||||
|
||||
## 项目内依赖
|
||||
| 依赖项 | 关系 | 源文件 |
|
||||
|--------|------|--------|
|
||||
| (none) | | |
|
||||
|
||||
## 对外接口
|
||||
UEndpointDispatcher 是蓝图端点与 C++ 委托系统之间的桥接对象。它暴露委托引用供 C++ 直接访问,同时提供 UFUNCTION 包装供蓝图调用。
|
||||
|
||||
- **OnStateChanged** (FOnEndpointStateChanged, public field): C++ 直接访问的委托。当端点状态变更时广播。被 UCommandRouter 通过 BindDynamic 订阅以触发聚合更新
|
||||
- **OnCommandOutput** (FOnCommandOutput, public field): C++ 直接访问的委托。当端点输出命令时广播。被 UCommandRouter 订阅以转发端点产出的命令
|
||||
- **CurrentState** (FEndpointState, EditAnywhere, BlueprintReadWrite): 端点当前状态的副本,ICommandEndpoint::GetEndpointState 默认实现返回此字段
|
||||
- **NotifyStateChanged** (UFUNCTION, BlueprintCallable): 蓝图广播入口,调用后执行 OnStateChanged.ExecuteIfBound(NewState),C++ 订阅者收到通知
|
||||
- **OutputCommand** (UFUNCTION, BlueprintCallable): 蓝图广播入口,调用后执行 OnCommandOutput.ExecuteIfBound(Command),将命令推送到路由系统
|
||||
|
||||
蓝图端点实现 ICommandEndpoint 时,需重写 GetEndpointDispatcher_BP 返回调度器实例。ICommandEndpoint 的 C++ 默认实现全部通过此调度器工作。
|
||||
|
||||
## 使用方法
|
||||
UEndpointDispatcher 是 ICommandEndpoint 蓝图实现的内部机制:
|
||||
|
||||
- **C++ 默认桥接**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandEndpoint.cpp:8-26` -- ICommandEndpoint 的四个纯虚函数默认实现全部通过 GetEndpointDispatcher_BP 获取调度器后委托执行
|
||||
- **GetEndpointState 默认实现**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandEndpoint.cpp:10` -- 返回 `Execute_GetEndpointDispatcher_BP(...)->CurrentState`
|
||||
- **ReceiveCommand 默认实现**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandEndpoint.cpp:25` -- 调用 `Execute_ReceiveCommand_BP(..., Command)`
|
||||
- **GetStateChangedDelegate 默认实现**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandEndpoint.cpp:15` -- 返回调度器的 OnStateChanged 引用
|
||||
- **NotifyStateChanged 内联**: `Plugins/CharacterControl/Source/CharacterControl/Public/CommandEndpoint.h:140-143` -- 函数体内直接 ExecuteIfBound
|
||||
- **OutputCommand 内联**: `Plugins/CharacterControl/Source/CharacterControl/Public/CommandEndpoint.h:146-149` -- 函数体内直接 ExecuteIfBound
|
||||
|
||||
## 用例
|
||||
- **蓝图端点状态通知**: 蓝图端点实现类调用 NotifyStateChanged,调度器转发给所有绑定的 C++ 订阅者(如 UCommandRouter::OnRegisteredEndpointStateChanged),触发标签聚合更新
|
||||
- **蓝图端点命令输出**: 蓝图端点调用 OutputCommand 将命令包推入路由系统,调度器广播 OnCommandOutput,由 UCommandRouter::OnRegisteredEndpointOutputCommand 接收处理
|
||||
- **C++ 端点绕过调度器**: `Plugins/CharacterControl/Source/CharacterControl/Public/CommandRouter.h:22-25` -- UCommandRouter 作为 C++ 端点直接重写 GetEndpointState/ReceiveCommand 等方法,不使用调度器;`Plugins/CharacterControl/Source/CharacterControl/Public/EndpointComponent.h:30-33` -- UEndpointComponent 同样直接重写
|
||||
45
Plugins/CharacterControl/UInputCommandData.md
Normal file
45
Plugins/CharacterControl/UInputCommandData.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# UInputCommandData
|
||||
|
||||
## 基本信息
|
||||
- **类型**: UCLASS(BlueprintType)
|
||||
- **父类**: UDataAsset
|
||||
- **源文件**: Plugins/CharacterControl/Source/CharacterControl/Public/InputCommandData.h
|
||||
- **模块**: CharacterControl
|
||||
|
||||
## 功能概述
|
||||
UDataAsset container for input configuration. Holds InputMappingContext (Enhanced Input mapping context to load) and InputCommands (TArray<FInputCommand>, the action-to-command mappings). Pure data container with no runtime logic.
|
||||
|
||||
## 设计用意
|
||||
Standard UE data asset pattern for designer-friendly configuration. Designer creates asset, fills in mappings, assigns to UCommandInputComponent::CommandData. Decouples configuration from code.
|
||||
|
||||
## 职责范围
|
||||
Configuration data container. Holds mapping context reference and command array. No runtime logic (empty .cpp file).
|
||||
|
||||
## 项目内依赖
|
||||
| 依赖项 | 关系 | 源文件 |
|
||||
|--------|------|--------|
|
||||
| FInputCommand | 包含 (TArray成员) | Plugins/CharacterControl/Source/CharacterControl/Public/InputCommandData.h |
|
||||
| CommandEndpoint.h | #include (for FDiscreteMeta) | Plugins/CharacterControl/Source/CharacterControl/Public/CommandEndpoint.h |
|
||||
|
||||
## 对外接口
|
||||
UInputCommandData 是 UDataAsset 子类,纯数据容器,无运行时逻辑。在 Content Browser 中创建资产,通过资产编辑器配置输入映射。所有属性为 EditAnywhere BlueprintReadOnly,设计师可在编辑器中填写。
|
||||
|
||||
- **InputMappingContext** (TObjectPtr<UInputMappingContext>, EditAnywhere, BlueprintReadOnly): 指向 Enhanced Input 的 InputMappingContext 资产。UCommandInputComponent::BeginPlay 将此上下文加载到 EnhancedInputLocalPlayerSubsystem
|
||||
- **InputCommands** (TArray<FInputCommand>, EditAnywhere, BlueprintReadOnly): FInputCommand 数组,每个条目定义一条 InputAction 到命令的映射。包含:InputAction 引用、bIsContinuous 开关、ContinousCommandTag(连续标签)、DiscreteCommandMeta(离散元数据)
|
||||
|
||||
创建资产后将其赋值给 UCommandInputComponent::CommandData 属性即可激活。多个 UCommandInputComponent 可共享同一个 UInputCommandData 资产。
|
||||
|
||||
## 使用方法
|
||||
UInputCommandData 是设计时配置资产,运行时由 UCommandInputComponent 消费:
|
||||
|
||||
- **定义**: `Plugins/CharacterControl/Source/CharacterControl/Public/InputCommandData.h:31-40` -- UCLASS(BlueprintType) UDataAsset 子类,两个 UPROPERTY
|
||||
- **读取 InputMappingContext**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandInputComponent.cpp:26-29` -- CommandData->InputMappingContext 传给 Subsystem->AddMappingContext
|
||||
- **读取 InputCommands**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandInputComponent.cpp:96` -- 遍历 `CommandData->InputCommands` 数组
|
||||
- **消费 FInputCommand 字段**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandInputComponent.cpp:41-80` -- BuildPacket 读取每个 FInputCommand 的各字段构建 FCommandPacket
|
||||
- **空实现**: `Plugins/CharacterControl/Source/CharacterControl/Private/InputCommandData.cpp` -- .cpp 文件只包含 include,无任何实现,确认为纯数据资产
|
||||
|
||||
## 用例
|
||||
- **设计师配置流程**: 在 Content Browser 中右键创建 UInputCommandData 资产,配置 InputMappingContext 指向已有的 Enhanced Input 映射上下文。在 InputCommands 数组中添加条目:选择 InputAction,设置 bIsContinuous,填入 GameplayTag,配置 DiscreteCommandMeta 的匹配规则。最后将资产赋值给 PlayerController 上的 UCommandInputComponent::CommandData
|
||||
- **InputMappingContext 加载**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandInputComponent.cpp:26-29` -- BeginPlay 从 CommandData 读取 InputMappingContext 并通过 Subsystem->AddMappingContext 加载
|
||||
- **InputCommands 数组遍历**: `Plugins/CharacterControl/Source/CharacterControl/Private/CommandInputComponent.cpp:96-114` -- BindAllCommands 遍历 CommandData->InputCommands,对每条 FInputCommand 执行输入绑定
|
||||
- **多组件共享资产**: 同一 UInputCommandData 资产可被多个 UCommandInputComponent 引用,实现配置复用
|
||||
32
Plugins/CharacterControl/_relationships.md
Normal file
32
Plugins/CharacterControl/_relationships.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# CharacterControl 插件依赖关系
|
||||
|
||||
## 文件间引用关系
|
||||
|
||||
| 源文件 | 引用方式 | 目标文件 | 目标单位 |
|
||||
|--------|---------|---------|---------|
|
||||
| CommandEndpoint.h | 定义(自包含) | GameplayTagContainer.h | FGameplayTagContainer |
|
||||
| CommandEndpoint.h | 定义(自包含) | InstancedStruct.h | FInstancedStruct |
|
||||
| CommandEndpoint.h | 定义(自包含) | —(自身) | FCommandMeta, FContinuousPayload, FCommandPacket, FDiscreteMeta, FEndpointState, UEndpointDispatcher, ICommandEndpoint, UCommandEndpoint |
|
||||
| CommandRouter.h | #include | CommandEndpoint.h | ICommandEndpoint, FCommandPacket, FEndpointState |
|
||||
| CommandRouterComponent.h | #include | CommandEndpoint.h | ICommandEndpoint, FCommandPacket, FEndpointState |
|
||||
| CommandRouterComponent.h | #include | CommandRouter.h | UCommandRouter |
|
||||
| CommandRouterComponent.cpp | #include | CommandRouterComponent.h | UCommandRouterComponent |
|
||||
| EndpointComponent.h | #include | CommandEndpoint.h | ICommandEndpoint, UCommandEndpoint, FEndpointState, FCommandPacket, UEndpointDispatcher |
|
||||
| CommandInputComponent.h | #include | EndpointComponent.h | UEndpointComponent |
|
||||
| CommandInputComponent.h | 前向声明 | — | UInputCommandData, UEnhancedInputComponent, FInputCommand |
|
||||
| CommandInputComponent.cpp | #include | InputCommandData.h | UInputCommandData, FInputCommand |
|
||||
| CommandInputComponent.cpp | #include | EnhancedInputComponent.h | UEnhancedInputComponent |
|
||||
| CommandInputComponent.cpp | #include | EnhancedInputSubsystems.h | UEnhancedInputLocalPlayerSubsystem |
|
||||
| CommandInputComponent.cpp | #include | InputAction.h | UInputAction |
|
||||
| InputCommandData.h | #include | CommandEndpoint.h | FCommandMeta, FContinuousPayload, FDiscreteMeta |
|
||||
| InputCommandData.h | 前向声明 | — | UInputAction |
|
||||
|
||||
## 关键依赖链
|
||||
|
||||
1. Input to Command: Enhanced Input → UCommandInputComponent::BuildPacket → FInputCommand (from UInputCommandData) → FCommandPacket → OnCommandOutput delegate
|
||||
2. Command Routing: FCommandPacket → UCommandRouter::ReceiveCommand (hop check) → RouteDiscreteCommand/RouteContinuousCommand → IsEndpointMatched → child ICommandEndpoint::ReceiveCommand
|
||||
3. Upward Propagation: child endpoint outputs → UCommandRouter::OnRegisteredEndpointOutputCommand → if bIsUpward → re-inject locally + forward upward
|
||||
4. State Change Propagation: child endpoint state changes → UCommandRouter::OnRegisteredEndpointStateChanged → tag aggregation update → CommitTagsToInterest
|
||||
5. Auto-Wiring: UCommandRouterComponent::BeginPlay → AutoRegisterEndpoints → discovers sibling ICommandEndpoint on owner Actor → RegisterEndpoint
|
||||
6. Endpoint Auto-Registration: UEndpointComponent::BeginPlay → finds sibling UCommandRouterComponent → self-registers with InternalRouter
|
||||
7. Blueprint Endpoint Pattern: ICommandEndpoint (BP implementation) → GetEndpointDispatcher_BP → UEndpointDispatcher → delegates broadcast to C++ observers
|
||||
Reference in New Issue
Block a user