Async Message · 项目消息与排查

查阅 Starry 已接入的消息标签、载荷和触发点,区分本地通知、状态复制与 RPC 转发,并沿真实链路排查。

本页内容4 节

当前有哪些消息入口

下表依据当前 C++ 调用整理。它确认发送路径与载荷,不表示每个标签都已有完整 UI 消费者,也不把未检查的蓝图资产当作已验证接入。项目当前使用默认 World Endpoint,先按当前 World 接收,再筛选对应玩家、组件或目标。

消息 Id载荷发送位置与时机
Ability.UserFacingSimpleActivateFail.MessageFStarryAbilitySimpleFailureMessageGameplayAbility 处理激活失败,存在匹配的提示文本时发送
Ability.PlayMontageOnActivateFail.MessageFStarryAbilityMontageFailureMessageGameplayAbility 处理激活失败,存在匹配的失败 Montage 时发送
Starry.Damage.MessageFStarryVerbMessageHealthSet 的伤害处理路径,填入本次数值和来源/目标
Starry.Elimination.MessageFStarryVerbMessageHealthComponent 的死亡处理路径,发布淘汰通知
GameplayEvent.ResetFStarryPlayerResetMessageReset 能力执行重置流程时发布通知,不是请求重置的入口
Starry.Inventory.Message.StackChangedFStarryInventoryChangeMessage背包 Fast Array 的新增、变化和移除复制回调
Starry.QuickBar.Message.SlotsChangedFStarryQuickBarSlotsChangedMessage快捷栏的 OnRep_Slots,相关服务器修改路径也显式调用该通知函数
Starry.QuickBar.Message.ActiveIndexChangedFStarryQuickBarActiveIndexChangedMessage快捷栏的 OnRep_ActiveSlotIndex,服务器切换时也调用该通知函数

能力失败消息中的 PlayerController 用于选择接收提示的玩家,简单失败消息提供 FailureTags 和 UserFacingReason;Montage 失败消息另有 AvatarActor 与 FailureMontage。

伤害与淘汰共用的 FStarryVerbMessage 包含 Verb、Instigator、Target、双方标签、环境标签和 Magnitude。伤害路径把 Magnitude 设为本次伤害;淘汰路径没有给它写入伤害数值,保留结构体默认值,不能把所有 Verb Message 的 Magnitude 都当作伤害。两条路径的 Target 也不同:伤害使用 Avatar,淘汰使用从 Avatar 解析的 PlayerState。

背包消息中的 InventoryOwner 是组件,另有物品 Instance、变化后的 NewCount 与正负 Delta。快捷栏内容消息带 Actor Owner 和整个 Slots 快照;选中消息带 Owner 和 ActiveIndex,-1 表示没有活跃插槽。监听默认范围时必须筛选这些字段,否则同一 World 内其他对象的变化也会更新自己的界面。

消息总线与网络分别负责哪一段

消息系统只在本地 World 内派发。背包和快捷栏先通过各自的状态复制到达客户端,再由客户端复制回调发布本地消息;这是状态复制带来的通知,不是消息总线自动联网。

复制状态之后,再发客户端本地通知时序
正在整理图表…
复制状态之后,再发客户端本地通知
查看图表源码
sequenceDiagram
  participant Server as 服务器领域状态
  participant Net as UE 状态复制
  participant Client as 客户端复制回调
  participant Bus as 客户端 World 消息系统
  participant UI as 客户端监听者
  Server->>Net: 修改背包或快捷栏状态
  Net->>Client: Fast Array 回调 / OnRep
  Client->>Bus: Queue 本地变化消息
  Bus->>UI: 对应 Tick Group 派发
  UI->>UI: 筛选自己的 Owner 后更新

项目还提供显式的 FStarryVerbMessage 网络转发入口:

接口真实行为
AStarryGameState::MulticastMessageToClients不可靠 NetMulticast,在接收端 NM_Client 世界重新入队
AStarryGameState::MulticastReliableMessageToClients可靠 NetMulticast,复用上述接收实现
AStarryPlayerState::ClientBroadcastMessage不可靠 Client RPC,面向该玩家的接收连接,在 NM_Client 重新入队

这些入口需要由有权限的调用方显式调用。当前源码没有查到它们与每条伤害/淘汰消息自动连接的通用转发器,不能把“存在接口”写成“所有消息都已跨端广播”。它们目前只接收 FStarryVerbMessage,不能直接传背包或技能失败的其他载荷。

接收实现均检查 GetNetMode() == NM_Client,不会为 Standalone、服务器世界或 Listen Server 的主机本地表现额外入队;这些场景应由所属领域明确安排本地通知。不要为了让 UI 出现就同时在发送和接收两端无条件重复发布。

FStarryVerbMessageReplication 另有 Fast Array 回调后重新入队的实现,但本轮源码搜索没有查到实际持有并复制该容器的项目成员,暂按可用实现位置记录,不视作当前已装配的通用同步通道。

重置请求仍通过 GAS 的 GameplayEvent.RequestReset 触发服务器 Reset 能力;后续 GameplayEvent.Reset 消息只是通知。消息总线、GAS Gameplay Event 与 Gameplay Cue 的用途和调用入口不同,不能只因标签名称相似就互换。

按现象排查

现象先核对什么
Success = false是否在当前 World 先登记了此标签或父级监听,Id 是否已注册,子系统是否存在且未关闭
Success = true 但没有显示是否同一个有效 Endpoint,是否等到了接收阶段,任务是否已停止,解包是否进入 Not Valid,Owner/Target 筛选是否正确
进编辑器就找不到子系统纯 Editor World 默认不开启该子系统;在实际 PIE/Game World 验证,并核对 World Context
同一事件收到多次是否每次 Construct/激活都新建任务却没停止旧任务,是否同时监听父级和叶标签,是否有重复本地发布或显式网络转发
开界面后没有当前内容消息不是状态存储,不能等过去的消息重播;登记监听后读取领域当前状态,再接后续变化
收到其他玩家的数据默认 Endpoint 是当前 World 的公共范围,按实际载荷里的 PlayerController、Owner、InventoryOwner 或 Target 筛选
父标签解包失败父级可能接收多个不同结构体的子消息,先看 MessageSourceId,再选正确类型
服务器能收到、客户端没有本地入队不复制;逐段检查领域状态复制或显式 RPC、接收端 World 的重新入队与监听
Listen Server 主机缺提示现有消息 RPC 接收体只处理 NM_Client;确认主机本地领域通知,而不是假定广播会再执行一份本地入队

蓝图核心接线见蓝图收发与解绑,原生代码见 C++ 收发与解绑,线程、路由和载荷寿命见标签、时机与生命周期。必要时用 HaloDebug 的日志与工具入口观察项目状态,消息本身的调试设置仍在本模块说明。

追查消息从哪里发出

输出日志类别为 LogAsyncMessageSystem。插件的 Project Settings 对应 AsyncMessageDeveloperSettings,可按具体 Id 开启入队调试、打印蓝图调用栈,或记录消息入队时的调用栈;尽量选少量目标消息,避免全量堆栈记录干扰性能。

Get Message Native Queue Callstack 和 Get Message Blueprint Script Callstack 可在接收端查看入队来源,前提是已启用 bShouldRecordQueueCallstackOnMessages 且当前构建开启 ENABLE_ASYNC_MESSAGES_DEBUG。默认编辑器和非 Shipping 构建启用该宏,普通 Shipping 不提供同样信息;不要把缺少堆栈直接判断为没有发生消息。

本机已有 Starry.Framework.AsyncMessages 专项,代码覆盖双 World 隔离、父标签保留原来源、延迟回调、入队值副本和派发前解绑。本轮只核对其实现与插件源码,没有重新运行这项 UE 自动化,网页检查结果也不代表联网或运行期验收。

实现入口:项目 Framework/AbilitySystem/Abilities/StarryGameplayAbility、StarryGameplayAbility_Reset、Framework/AbilitySystem/Attributes/StarryHealthSet、Framework/Character/StarryHealthComponent、Framework/Inventory/StarryInventoryManagerComponent、Framework/Equipment/StarryQuickBarComponent、Framework/GameModes/StarryGameState、Framework/Player/StarryPlayerState 与 Framework/Messages。

Starry手册导览从模块进入子模块与具体功能,查阅功能用途、配置步骤、技术架构和扩展方法。工程分层与系统协作了解 Framework、Gameplay 与通用插件的依赖方向,以及配置装配和运行状态的边界。模块总览与接入从行为系统、执行系统与机会调度了解 AstraAI,再为角色配置第一套组合决策。组合与覆盖正确区分优先级、行为分数与 Stack 顺序,按完整路径组织可撤销的配置。评分与抢占沿着条件、优先级、分数、持续有效性与冷却,解释一个行为为何开始或退出。Logic 与生命周期把动作接入 Start、Cancel、Cleanup,正确处理共享模板、蓝图实例与过期异步回调。BT、StateTree 与 HTN复用控制器上的树组件,正确传入数据、报告整树结果并等待安全退出。Objective 与机会生成把领域事实整理成当前机会,让评分只读数据,让生成器独立管理订阅。命令发布与领取发布一条命令后,经机会评估、Take、执行与 EndUse 完成一次受控使用。行为区域用可挂载的 Zone 组件分配行为层,并把回区机会与实际导航分开。调试与排查从初始化到候选、机会、应用层与后端,沿真实运行路径定位 AI 没有行动的原因。模块总览与使用了解通用调试工具的操作、远程连接与窗口扩展,再由各模块的排查说明定位具体问题。netImgui 远程面板在独立桌面程序查看调试窗口,区分远程 UI、游戏视口绘制与玩法网络权限。窗口扩展与属性绘制复用窗口生命周期、反射 Inspector 和场景绘制,避免为每个调试页重做基础设施。模块总览与接入从配置绑定、动作处理、通道缓存与玩家改键了解 Input,再接入角色的输入配置。绑定与配置生命周期理解跨 IMC 的共享绑定、配置所有权、延迟初始化,以及切换角色时的清理。Handler 与能力分派选择正确的输入阶段,把输入交给移动、GAS、GameplayEvent 或 UI,保持共享 Handler 无玩家状态。修饰器与双击选择输入值变换所在层,理解玩家设置修饰器与 Double Tap 的时序规则。通道输入缓存按 GameplayTag 通道开窗,保留首批或末批输入,正常关闭执行,中断取消丢弃。改键与玩家设置通过 GameSettings 统一编辑与应用,区分 SharedSettings 偏好和 Enhanced Input 键映射数据。调试与排查使用 Gamepad 与 Actions 观察和模拟输入,沿设备、映射、绑定、缓存与能力定位问题。模块总览与接入使用 UE 5.8 原生 Async Message System,把事件通知与接收方解耦,查阅消息收发、路由和 Starry 的实际接入。蓝图收发与解绑通过消息 Id、监听、载荷封装与解包的核心连线,掌握蓝图收发和任务解绑。C++ 收发与解绑按取得系统、登记监听、读取载荷、发送与解绑的顺序,查阅原生 C++ 接口用法。标签、时机与生命周期理解消息的标签层级、World 和 Endpoint 路由、游戏线程派发、载荷快照与 C++ 监听清理。项目消息与排查查阅 Starry 已接入的消息标签、载荷和触发点,区分本地通知、状态复制与 RPC 转发,并沿真实链路排查。模块总览与项目接入管理软引用加载、有序回调与任务作用域,了解指示器画布的实际接入,以及加载完成后的资源和宿主生命周期。软引用加载与 C++ 用法用组件加载软对象和控件类,保存加载结果,理解路径数组、同步回调、失败结果,以及重载与退出时的取消清理。主资产与资源驻留按主资产 ID 和 Bundle 预加载资源,理解句柄保留、取消与 GC 引用的关系,以及 AssetManager 和打包配置的职责。回调顺序与独立作用域理解并行加载与有序回调的区别,使用 FAsyncScope 分开取消任务,了解 AsyncEvent、开始完成通知和等待条件的当前边界。在文档中说明蓝图用法将真实蓝图节点嵌入正文,结合步骤、引脚和连线说明功能,节点文本随文章保存。维护这本手册本地文件与网页编辑共用一份 MDX,日常只改内容与关系,沿用共享版式和图表。