MassBattle Docsv1.19.20

AMassBattleNetworkGameModeBase

UCLASS

Source/MassBattle/Public/Network/MassBattleNetworkGameModeBase.h

概述 Overview

内置确定性锁步网络同步的 GameMode 基类,服务器侧网络中枢。职责:① K-buffer 调度——所有命令以 ExecuteTick = 基准 + K + ExtraDeferTicks 排程,按 (ExecuteTick, ServerExecSequence) 确定性排序后多播;② 逐 tick 广播 MulticastSyncTick(服务端 tick 进度 + 时间膨胀)与失步检测 hash;③ resync 与 late-join 快照派发(TCP 侧通道,后台线程序列化/压缩);④ 组件驱动的锁步生成冲刷(AgentComponent 在服务器端 BeginPlay 自注册,GameMode 在 tick 边界冲刷 Agent.Spawn 指令);⑤ 玩家槽位分配、ack 追踪、步调超时踢人;⑥ 客户端命令准入闸门——默认拒绝,ClientAllowedCommandTags 放行游戏输入 tag,服务器权威 tag(生成/销毁/流场重建等)恒拒;⑦ 流场基底锁步同步(SendLockstepCommandToClients_RebuildFlowField,全量/差分/自动择优,含动态 navmesh 自动重导出)。UE 生成并 Possess 一个携带 UMassBattleAgentComponent 的 ACharacter;锁步会话下服务器端组件自驱生成指令,客户端被动等待。

GameMode base class with built-in deterministic lockstep network sync — the server-side network hub. Responsibilities: ① K-buffer scheduling — all commands are scheduled with ExecuteTick = base + K + ExtraDeferTicks, sorted deterministically by (ExecuteTick, ServerExecSequence), then multicast; ② per-tick MulticastSyncTick broadcast (server tick progress + time dilation) and desync-check hash broadcast; ③ resync and late-join snapshot dispatch (TCP side-channel, background-thread serialize/compress); ④ component-driven lockstep spawn flushing (the server-side AgentComponent self-registers on BeginPlay; the GameMode flushes Agent.Spawn commands at tick boundaries); ⑤ player slot allocation, ack tracking, and pacing-timeout kicks; ⑥ the client command admission gate — default-deny, with game input tags allow-listed via ClientAllowedCommandTags and server-authority tags (spawn/despawn/flow-field rebuild etc.) always rejected; ⑦ flow-field substrate lockstep sync (SendLockstepCommandToClients_RebuildFlowField, full/delta/auto wire-form, including dynamic-navmesh auto re-export). UE spawns and possesses an ACharacter carrying UMassBattleAgentComponent; in lockstep sessions the server-side AgentComponent self-drives the spawn command while clients wait passively.

继承 Inheritance

AGameMode → AMassBattleNetworkGameModeBase

EMassBattleClientCommandGateMode UENUM

客户端命令闸门模式,由 ClientCommandGateMode 使用。闸门在 ReceivePlayerCommand 这唯一收口点执法——服务器自驱命令(经 SendLockstepCommandToClients / OnSimTickCompleted / Logout 入队)不经此处。

Client command gate mode, used by ClientCommandGateMode. The gate is enforced at the single choke point ReceivePlayerCommand — server-originated commands (enqueued via SendLockstepCommandToClients / OnSimTickCompleted / Logout) never pass through it.

值 Value说明 Description
Enforce拒绝 ClientAllowedCommandTags 之外的一切客户端来源命令(服务器权威 tag 恒拒,deny 优先于 allow)。默认值。Rejects every client-originated command outside ClientAllowedCommandTags (server-authority tags always rejected; deny wins over allow). Default.
LogOnly仅记录本应拒绝的命令但放行——存量游戏切换到 Enforce 前的迁移观察期。Logs would-reject but allows through — a migration observation period before switching to Enforce.
Disabled闸门关闭。Gate off.

方法 Methods

AMassBattleNetworkGameModeBase 构造函数

设置 bReplicates=true 并把 GameStateClass 指到 AMassBattleNetworkGameStateBase。DefaultPawnClass 有意不在此设置——在 BP GameMode 中配置为携带 UMassBattleAgentComponent 的 ACharacter 派生 Pawn。

Sets bReplicates=true and points GameStateClass at AMassBattleNetworkGameStateBase. DefaultPawnClass is intentionally unset here — configure it in the BP GameMode to an ACharacter-based pawn carrying UMassBattleAgentComponent.

Input

无参数。

No parameters.

Output

无返回值。副作用:配置复制标志与 GameStateClass。

No return value. Side effects: replication flag and GameStateClass configuration.

InitGame virtual void (const FString&, const FString&, FString&) (protected)

先调用父类,随后当 bEnableNetworkSync 开启时提前置 MB->bNetworkedMode=true。InitGame 先于一切 Actor BeginPlay 执行——关卡摆放 Actor 的 BeginPlay(组件按会话标志路由 + 模板工厂按 bNetworkedMode 盖 FNetworkTag)不再与 BeginPlay 时的置位竞态;BeginPlay 中的置位保留(幂等)。

Calls the parent first, then — when bEnableNetworkSync is on — flips MB->bNetworkedMode=true early. InitGame runs BEFORE any actor BeginPlay, so level-placed actors' BeginPlay (component routing on the session flag + template-factory FNetworkTag stamping off bNetworkedMode) never races the flag; the BeginPlay-time set is kept idempotent.

Input
参数 Param类型 Type说明 Description
MapName / Optionsconst FString&引擎传入的地图名与启动选项(透传给父类)。Engine-provided map name and options (forwarded to the parent).
ErrorMessageFString&输出:传给父类的错误信息。Output: error message forwarded to the parent.
Output

无返回值。副作用:开启网络同步时提前置位 bNetworkedMode。

No return value. Side effect: sets bNetworkedMode early when network sync is enabled.

BeginPlay virtual void (protected)

初始化:先把插件自有的模糊测试 tag MB.FuzzTask 注册进客户端命令 allow 集(服务器来源但走标准准入归一化);把 DefaultPawnClass 同步到 GameState 的 PlayerCharacterClass(供客户端/快照访问角色类);当 bEnableNetworkSync 开启时——置 MB->bNetworkedMode=true(幂等)、确保 TCP 传输(EnsureSnapshotTcpTransport)、绑定 OnTickCompleted → OnSimTickCompleted、创建 UMassBattleNetworkRelay 并按 GetNetMode() 初始化为 DedicatedServer 或 ListenServer 模式;随后输出命令闸门自检日志([CMD_WHITELIST]:生效模式与 allow 集内容;Enforce 且 allow 集为空时输出 Warning——所有客户端命令都将被拒绝)。关闭时无网络初始化。

Initialization: first allow-lists the plugin's own fuzz tag MB.FuzzTask (server-originated but flowing through standard admission normalization); syncs DefaultPawnClass into the GameState's PlayerCharacterClass (for clients/snapshot); when bEnableNetworkSync is on — sets MB->bNetworkedMode=true (idempotent), ensures the TCP transport (EnsureSnapshotTcpTransport), binds OnTickCompleted → OnSimTickCompleted, and creates UMassBattleNetworkRelay initialized to DedicatedServer or ListenServer mode per GetNetMode(); then dumps the client command gate self-check ([CMD_WHITELIST]: effective mode and allow-set contents; Enforce with an empty allow set logs a Warning — every client command will be rejected). No network init when disabled.

Input

无参数。

No parameters.

Output

无返回值。副作用:设置 bNetworkedMode、创建 relay、绑定 tick 回调。

No return value. Side effects: sets bNetworkedMode, creates the relay, binds the tick callback.

PostLogin virtual void (APlayerController* NewPlayer) (protected)

玩家登录处理:分配确定性 PlayerSlot(AllocatePlayerSlot),初始化 ack 追踪(ClientAckedTicks 置当前 tick,ClientMaxObservedLag 置 0)。远程后加入者(非 ListenServer 本地控制器)标记 bForceSnapshotNextTick=true 并加入 PendingLateJoinClients,在确定性 post-command 边界做快照优先接入;监听服务器主机共享服务端模拟,从不后加入。

Player login handling: allocates a deterministic PlayerSlot (AllocatePlayerSlot) and initializes ack tracking (ClientAckedTicks to the current tick, ClientMaxObservedLag to 0). Remote late-joiners (not the listen-server local controller) get bForceSnapshotNextTick=true and join PendingLateJoinClients for snapshot-first onboarding at the deterministic post-command boundary; the listen-server host shares the server sim and never late-joins.

Input
参数 Param类型 Type说明 Description
NewPlayerAPlayerController*新登录的玩家控制器。The newly logged-in player controller.
Output

无返回值。副作用:分配槽位、初始化追踪、可能排队 late-join。

No return value. Side effects: slot allocation, tracking init, possible late-join queueing.

Logout virtual void (AController* Exiting) (protected)

玩家登出:经 possess 链捕获退出 pawn 拥有的每个 agent UID(1:N),按 UID 广播 Player.Leave 锁步指令(所有端确定性销毁各 agent);清理每玩家追踪(CleanupPlayerState);调用引擎登出后释放确定性槽位(FreePlayerSlot)。

Player logout: captures every agent UID owned by the exiting pawn (1:N) via the possess chain, broadcasts one Player.Leave lockstep command per UID (all peers destroy each agent deterministically); clears per-player tracking (CleanupPlayerState); after the engine logout, frees the deterministic slot (FreePlayerSlot).

Input
参数 Param类型 Type说明 Description
ExitingAController*登出的控制器。The exiting controller.
Output

无返回值。副作用:入队 Player.Leave 指令、清理追踪、释放槽位。

No return value. Side effects: enqueues Player.Leave commands, clears tracking, frees the slot.

SendLockstepCommandToClients void (BlueprintCallable)

服务器向全体客户端广播一条锁步指令。自动分流:序列化负载 ≥ MassBattle.AutoFloodSwitchBytes(默认 16KB)时,把负载打包压缩为 TCP 数据块(BroadcastLockstepDataBlock)并广播轻量 UDP 引用命令(载荷只含 DataBlockId/DataBlockCrc),绕过 64KB RPC bunch 上限;否则走现有可靠多播 RPC。两种路径都经 NextServerExecSequence 分配执行序号并写入服务端自身命令队列(EnqueueNetCommand),ExecuteTick = 当前 tick + K + ExtraDeferTicks。命令标签如 AgentComponent.Spawn/Obstacle.Spawn 等由 ExecuteNetCommand 解释。

Broadcasts one lockstep command from the server to all clients. Auto-flood: when the serialized payload ≥ MassBattle.AutoFloodSwitchBytes (default 16KB), the payload is packed/compressed into a TCP data block (BroadcastLockstepDataBlock) plus a lightweight UDP reference command (payload carries only DataBlockId/DataBlockCrc), bypassing the 64KB RPC bunch limit; otherwise the existing reliable multicast RPC is used. Both paths assign an execution sequence via NextServerExecSequence and enqueue into the server's own command queue (EnqueueNetCommand), with ExecuteTick = current tick + K + ExtraDeferTicks. Command tags such as AgentComponent.Spawn/Obstacle.Spawn are interpreted by ExecuteNetCommand.

Input
参数 Param类型 Type说明 Description
CommandTagFName命令标签(如 AgentComponent.Spawn)。Command tag (e.g. AgentComponent.Spawn).
NamePayloadconst TArray<FName>&名称载荷(如 DataAsset 路径)。Name payload (e.g. DataAsset paths).
IntPayloadconst TArray<int32>&整数载荷(如 UID、槽位)。Integer payload (e.g. UIDs, slots).
FloatPayloadconst TArray<float>&浮点载荷(如变换分量)。Float payload (e.g. transform components).
ExtraDeferTicksint32K-buffer 之外额外推迟执行的 tick 数(默认 0);可用于自动分流大块传输余量。Extra ticks to defer beyond the K-buffer (default 0); handy for auto-flood large-block transit headroom.
Output

无返回值。副作用:分配 ServerExecSequence、广播 RPC(或 TCP 块 + 引用命令)、写入服务端自身命令队列、消耗一个 DataBlockId(自动分流路径)。

No return value. Side effects: assigns ServerExecSequence, broadcasts the RPC (or TCP block + reference command), enqueues into the server's own queue, consumes a DataBlockId on the auto-flood path.

SendLockstepCommandToClient void (BlueprintCallable)

定向单播:按 PlayerIndex 找到目标 AMassBattleNetworkPlayerControllerBase 并调用 ClientReceiveLockstepCommand 只发给该客户端。ExecuteTick = 当前 tick + K,同样分配执行序号并写入服务端自身队列。

Targeted unicast: locates the AMassBattleNetworkPlayerControllerBase by PlayerIndex and delivers via ClientReceiveLockstepCommand to that client only. ExecuteTick = current tick + K, with sequence assignment and server self-enqueue as well.

Input
参数 Param类型 Type说明 Description
TargetPlayerIndexint32目标玩家索引(PlayerState 的 PlayerId)。Target player index (PlayerState PlayerId).
CommandTagFName命令标签。Command tag.
NamePayloadconst TArray<FName>&名称载荷。Name payload.
IntPayloadconst TArray<int32>&整数载荷。Integer payload.
FloatPayloadconst TArray<float>&浮点载荷。Float payload.
Output

无返回值。副作用:分配序号、向目标客户端发单播 RPC、写入服务端自身队列。目标未找到时仅服务端自身入队。

No return value. Side effects: sequence assignment, unicast RPC to the target, server self-enqueue. If the target is not found, only the server self-enqueue happens.

SendLockstepCommandToClients_RebuildFlowField bool (AFlowField*, int32 ExtraDeferTicks = 120, EFFSubstrateSyncMode SyncMode = Auto) (BlueprintCallable)

导出流场基底(场自身的数据结构——Grid 格子 / NavMesh 图,由 FlowFieldCanvas 紧凑量化)并锁步广播到全端,使各端本地计算路径、引擎 navmesh 查询链彻底退出锁步路径(NavMesh-A* 失步修复)。导出后服务器自导入同一份字节(KI-011:服务器与客户端必须进入同一同步基底态,否则两套 A* 回答同一查询即失步);首次基底发送时订阅 navmesh 重建委托(动态 navmesh 自动重导出)。差分同步:SyncMode 选择线上形态——Full = 每次整份基底;Incremental = 优先对缓存基准发差分(变更格子/tile + 目标集),无基准或差分不可构造时自动回退全量;Auto(默认)= 服务器择小发送(差分达到 MassBattle.FF.DeltaToFullRatio × 全量即弃用,默认 0.75)。缓存永远持有最新全量导出——同时充当差分基准与晚加入补发源;真无变动时整次跳过(无 TCP 块、无命令)。命令标签为 FF.RebuildFlowField;重发幂等(内容哈希跳过)。

Exports a flow field's substrate (the field's own data structure — Grid cells / NavMesh graph, compactly quantized by FlowFieldCanvas) and lockstep-broadcasts it to every peer so all peers compute paths locally and the engine navmesh query chain leaves the lockstep path entirely (the NavMesh-A* desync fix). After export the server self-imports the same bytes (KI-011: server and clients must enter the same synced-substrate state, otherwise two different A* implementations answer the same query and desync); the first substrate send subscribes to the navmesh rebuild delegate (dynamic-navmesh auto re-export). Delta sync: SyncMode selects the wire form — Full = entire substrate every time; Incremental = prefer a delta (changed cells/tiles + goal set) against the cached base, auto-falling back to full when no base exists or the delta can't be built; Auto (default) = the server sends whichever is smaller (a delta at or above MassBattle.FF.DeltaToFullRatio × full is rejected, default 0.75). The cache always holds the latest FULL export — it doubles as the delta base AND the late-join re-delivery source; a true no-change dispatch skips entirely (no TCP block, no command). The command tag is FF.RebuildFlowField; re-delivery is idempotent (content-hash skip).

Input
参数 Param类型 Type说明 Description
FieldAFlowField*要导出并同步的流场(服务器已构建)。场无效或非权威端时直接失败。The flow field to export & sync (server-built). Fails outright on an invalid field or without authority.
ExtraDeferTicksint32MB 级 TCP 块的额外传输余量(默认 120)。Extra transit headroom for the MB-size TCP block (default 120).
SyncModeEFFSubstrateSyncMode全量/增量/自动择优选择器(默认 Auto)。Full / Incremental / Auto wire-form selector (default Auto).
Output

已导出并派发时返回 true(真无变动跳过也返回 true);导出失败或无权限返回 false。副作用:服务器自导入基底、刷新/写入网络子系统的基底缓存、经 SendLockstepDataCommandToClients 广播 TCP 块 + FF.RebuildFlowField 引用命令(差分时 NamePayload 为 {FieldKey, "Delta"})。

Returns true when exported and dispatched (a true no-change skip also returns true); false on export failure or no authority. Side effects: server self-import, substrate cache refresh/write in the network subsystem, and a TCP block + FF.RebuildFlowField reference command broadcast via SendLockstepDataCommandToClients (delta dispatches carry {FieldKey, "Delta"} in NamePayload).

SendLockstepDataCommandToClients bool (FName, const TArray<FName>&, const TArray<int32>&, const TArray<float>&, const TArray<uint8>&, int32)

字节感知的锁步广播核心——恒走 auto-flood TCP 块路径(字节负载为基底级体量),镜像 SendLockstepCommandToClients 的自动分流分支:Pack→压缩→分配 ServerBlockId 自存并广播块,再多播轻量 UDP 引用命令(载荷只含 DataBlockId/DataBlockCrc),ExecuteTick = 当前 tick + K + ExtraDeferTicks。上面的公开便捷函数不带字节;本核带字节。

Byte-aware lockstep broadcast core — always rides the auto-flood TCP block path (byte payloads are substrate-sized), mirroring the auto-flood branch of SendLockstepCommandToClients: Pack → compress → allocate a ServerBlockId, self-store and broadcast the block, then multicast a lightweight UDP reference command (payload carries only DataBlockId/DataBlockCrc), with ExecuteTick = current tick + K + ExtraDeferTicks. The public helpers above pass no bytes; this is the byte-capable core.

Input
参数 Param类型 Type说明 Description
CommandTag … FloatPayload同 SendLockstepCommandToClients命令标签与三类标量载荷。Command tag and the three scalar payloads.
BytePayloadconst TArray<uint8>&字节负载(基底导出/差分字节),随块下发。Byte payload (substrate export/delta bytes), delivered via the block.
ExtraDeferTicksint32额外推迟执行的 tick 数(负值钳为 0)。Extra deferral ticks (negatives clamped to 0).
Output

派发成功返回 true;子系统/GameState 缺失或 TCP 传输未激活返回 false。副作用:消耗一个 ServerBlockId、广播块与引用命令、写入服务端自身命令队列。

Returns true on dispatch; false when the subsystem/GameState is missing or the TCP transport is inactive. Side effects: consumes a ServerBlockId, broadcasts the block and the reference command, enqueues into the server's own queue.

HandleFlowFieldFullResyncRequest void (int32 PlayerIndex, FName FieldKey)

差分修复入口:已应用基底版本脱节的端(跳过差分的晚加入端、分叉链)请求该场的显式全量重发——ServerRequestFlowFieldFullResync 的服务器侧对应(由 PlayerController RPC 与 GameStateBase 的拒收链调用)。按场墙钟节流(2 秒窗口,异常端的修复风暴收敛为每窗口一次全量重发)。非锁步命令:基底修复本身带版本且幂等,无需定序。

Delta-repair entry: a peer whose applied substrate version missed a delta's base (skipped-delta late joiner, forked chain) asks for an explicit FULL re-send of that field — the server-side counterpart of ServerRequestFlowFieldFullResync (called from the PlayerController RPC and the GameStateBase rejection chain). Wall-clock throttled per field (2s window; repair storms from misbehaving peers collapse to one full re-send per window). Not a lockstep command: substrate repair is versioned + idempotent and needs no ordering.

Input
参数 Param类型 Type说明 Description
PlayerIndexint32请求全量重发的玩家。Player requesting the full re-send.
FieldKeyFName要修复的场名;None 或本端查无此场时直接返回。Field to repair; returns immediately when None or the field is not found on this peer.
Output

无返回值。副作用:节流通过后按 Full 模式重发该场基底(ExtraDeferTicks=120)。

No return value. Side effect: once past the throttle, re-sends that field's substrate in Full mode (ExtraDeferTicks=120).

OnNavDataGenerationFinished UFUNCTION() void (ANavigationData* NavData)

动态 navmesh 自动重导出:服务器 navmesh(RuntimeGeneration Dynamic / Dynamic-ModifiersOnly)重建完成时,把全部已同步 NavMesh 模式场的基底从活体重导出并重播——全端(含服务器)在命令 ExecuteTick 原子换版,零发散窗口(同步图换版前保持旧基底在线)。墙钟节流(2 秒):中间重建收敛为最新导出。Grid 模式场不参与——其基底源自场景探测而非 navmesh,重建/重导出保持显式(BP)。委托在首次基底发送时绑定。

Dynamic-navmesh auto re-export: when the server navmesh (RuntimeGeneration Dynamic / Dynamic-ModifiersOnly) finishes a rebuild, every synced NavMesh-mode field's substrate is re-exported from the live mesh and re-broadcast — all peers (server included) swap atomically at the command's ExecuteTick, zero divergence window (the synced graph stays on the old substrate until the swap). Wall-clock throttled (2s): intermediate rebuilds collapse to the latest export. Grid-mode fields are excluded — their substrate derives from scene traces, not the navmesh; their rebuild/re-export stays explicit (BP). The delegate is bound on the first substrate send.

Input
参数 Param类型 Type说明 Description
NavDataANavigationData*完成重建的导航数据(当前实现未直接使用其内容)。The navigation data that finished rebuilding (its contents are not directly used by the current implementation).
Output

无返回值。副作用:可能对每个 NavMesh 模式缓存场触发一次全量/差分基底重发。

No return value. Side effect: may trigger a full/delta substrate re-send for every cached NavMesh-mode field.

IsServerAuthorityCommandTag static bool (FName Tag)

判断 Tag 是否为服务器权威命令 tag——从 MB_FOR_EACH_SERVER_AUTHORITY_TAG 注册表展开(静态集合,可安全供 CheatManager/诊断复用)。客户端来源命令携带这些 tag 恒被拒绝:AgentComponent.Spawn / SetAgentTransform / Despawn、ProjectileComponent.Spawn / Despawn、LootComponent.Spawn / Despawn、Obstacle.Spawn / SyncTransform / Destroy、FF.RebuildFlowField、Game.Pause / Resume、Player.Leave。特权意图必须走服务器 API(SendLockstepCommandToClients)。

Whether Tag is a server-authority command tag — expanded from the MB_FOR_EACH_SERVER_AUTHORITY_TAG registry (a static set, safe for CheatManager/diagnostics reuse). Client-originated commands carrying these tags are always rejected: AgentComponent.Spawn / SetAgentTransform / Despawn, ProjectileComponent.Spawn / Despawn, LootComponent.Spawn / Despawn, Obstacle.Spawn / SyncTransform / Destroy, FF.RebuildFlowField, Game.Pause / Resume, Player.Leave. Privileged intents must go through the server API (SendLockstepCommandToClients).

Input
参数 Param类型 Type说明 Description
TagFName待检查的命令 tag。Command tag to check.
Output

属于注册表返回 true。

Returns true when the tag is in the registry.

RegisterClientAllowedCommandTag void (FName Tag) (BlueprintCallable)

运行时把游戏侧客户端命令 tag 注册进 allow 集(仅服务器,留审计日志)。拒绝服务器权威 tag——其永不允许客户端发起,注册会打 Error 并跳过(放行一个就重新打开本闸门要封的洞)。优先在 BP GameMode 默认值填写 ClientAllowedCommandTags;动态 tag 用本函数。重复注册幂等。

Runtime-registers a game-side client-issued command tag into the allow set (server only, logged). Refuses server-authority tags — they can never be client-issued; registering one logs an Error and is skipped (allowing one would reopen the exact hole this gate closes). Prefer filling ClientAllowedCommandTags in BP GameMode defaults; use this for dynamic tags. Re-registration is idempotent.

Input
参数 Param类型 Type说明 Description
TagFName要放行的命令 tag(None 直接忽略)。Command tag to allow (None is ignored).
Output

无返回值。副作用:非权威 tag 追加进 ClientAllowedCommandTags 并留日志。

No return value. Side effect: non-authority tags are appended to ClientAllowedCommandTags with a log.

RemoveClientAllowedCommandTag void (FName Tag) (BlueprintCallable)

运行时从 allow 集移除 tag(仅服务器,留审计日志)。已调度的在途命令不受影响。

Runtime-removes a tag from the allow set (server only, logged). In-flight commands already scheduled are unaffected.

Input
参数 Param类型 Type说明 Description
TagFName要撤销的命令 tag。Command tag to revoke.
Output

无返回值。副作用:命中时从 ClientAllowedCommandTags 移除并留日志。

No return value. Side effect: removed from ClientAllowedCommandTags with a log on hit.

EnqueueAuthorityCommandForFuzz void (const FMassBattleNetCommand& Cmd)

服务器权威直通入队(自动失步取证模糊器专用,由 MassBattleDesyncAutoDebugger 调用):按 ExecuteTick 盖 ServerExecSequence 后直接进入 PendingCommands——与内置服务器命令同款路径,绕过客户端准入闸门(模糊器是服务器来源)。

Server-authority direct enqueue (for the auto-forensics desync fuzzer, called by MassBattleDesyncAutoDebugger): stamps a ServerExecSequence for the command's ExecuteTick and enters PendingCommands — the same path as the built-in server commands, bypassing the client admission gate (the fuzzer is server-originated).

Input
参数 Param类型 Type说明 Description
Cmdconst FMassBattleNetCommand&要入队的命令(ExecuteTick 由调用方填好;非权威端直接忽略)。The command to enqueue (ExecuteTick pre-filled by the caller; ignored without authority).
Output

无返回值。副作用:分配序号并入队,打一条 [DESYNC_FUZZER] Warning 日志。

No return value. Side effects: sequence assignment + enqueue, plus a [DESYNC_FUZZER] Warning log.

ReceivePlayerCommand void (const FMassBattleNetCommand& Cmd)

客户端上行命令的服务器入口(Server_SendNetCommand 的落地,也是客户端命令闸门的唯一执法点)。准入顺序:① 客户端命令闸门——非 Disabled 模式时,服务器权威 tag 或不在 ClientAllowedCommandTags 的命令记拒绝日志(有界诊断)并广播 CommandRejectedByWhitelist 网络事件,Enforce 模式直接丢弃;② 隔离中的客户端(ClientsRejectedUntilResync)丢弃并打 Warning;③ 每玩家每 tick 准入配额(MaxClientCommandsPerTick,超限丢弃——洪泛客户端在入口即被丢弃,不被 N 倍放大给所有端);④ 待广播队列硬上限(MaxPendingCommands,聚合尖峰保护);⑤ 客户端可控调度输入钳制——ExtraDeferTicks 钳到 [0, MaxExtraDeferTicks]、IssuedTick 钳到服务器 tick 周围窗口([LastKnownServerTick-1024, +256])。之后 K-buffer 调度:ExecuteTick = max(LastKnownServerTick, Cmd.IssuedTick, 最快已 ack 客户端 tick 与 LastKnownServerTick+K 的较小者) + K + ExtraDeferTicks,再分配 ServerExecSequence。带 DataBlockId 的命令走 ConvergeUplinkBlock 汇聚。

Server entry for client-uplink commands (the landing site of Server_SendNetCommand, and the single enforcement point of the client command gate). Admission order: ① client command gate — when not Disabled, commands with a server-authority tag or absent from ClientAllowedCommandTags get a bounded rejection log plus a CommandRejectedByWhitelist network event broadcast, and are dropped outright in Enforce mode; ② quarantined clients (ClientsRejectedUntilResync) are dropped with a Warning; ③ per-player per-tick admission quota (MaxClientCommandsPerTick, overflow dropped — a flooding client is dropped at entry instead of being amplified N-fold to every peer); ④ pending-broadcast queue hard cap (MaxPendingCommands, aggregate spike protection); ⑤ client-controlled schedule inputs are clamped — ExtraDeferTicks to [0, MaxExtraDeferTicks] and IssuedTick to a window around the server tick ([LastKnownServerTick-1024, +256]). Then K-buffer scheduling: ExecuteTick = max(LastKnownServerTick, Cmd.IssuedTick, min(fastest acked client tick, LastKnownServerTick+K)) + K + ExtraDeferTicks, then a ServerExecSequence is assigned. Commands carrying a DataBlockId route through ConvergeUplinkBlock.

Input
参数 Param类型 Type说明 Description
Cmdconst FMassBattleNetCommand&上行命令(PlayerIndex 已在 PC 侧盖章)。Uplink command (PlayerIndex already stamped on the PC side).
Output

无返回值。副作用:入队 PendingCommands(下个网络 flush tick 广播)或触发块汇聚;闸门/配额/上限/隔离任一命中时丢弃并可能广播拒绝事件。

No return value. Side effects: enqueues into PendingCommands (broadcast at the next network flush tick) or triggers block convergence; dropped (possibly with a rejection event broadcast) when the gate/quota/cap/quarantine hits.

ConvergeUplinkBlock void (const FMassBattleNetCommand& Cmd)

汇聚上行命令的 TCP 块:从 Net 的已上传块缓存按 (PlayerIndex, LocalBlockId) 取块;块未到则把命令暂存(StagePendingBlockCommand),块到达回调(OnLockstepDataBlockUploaded)时再汇聚(竞态修复)。块已到时:重新计算 CRC、压缩、分配权威 ServerBlockId(AllocServerBlockId)自存并向所有客户端广播块,命令的 DataBlockId 重映射为 ServerBlockId,消费上行块后入队 PendingCommands。

Converges an uplink command's TCP block: fetches the block from Net's uploaded-block cache by (PlayerIndex, LocalBlockId); if the block is missing, the command is staged (StagePendingBlockCommand) and converged when the block arrives (via OnLockstepDataBlockUploaded) — a race fix. When the block is present: recomputes CRC, compresses, allocates the authoritative ServerBlockId (AllocServerBlockId), self-stores and broadcasts the block to all clients, remaps the command's DataBlockId to ServerBlockId, consumes the uplink block, and enqueues into PendingCommands.

Input
参数 Param类型 Type说明 Description
Cmdconst FMassBattleNetCommand&带 LocalBlockId 的引用命令。Reference command carrying a LocalBlockId.
Output

无返回值。副作用:可能暂存命令;成功时分配 ServerBlockId、广播块、入队命令、消费上行块。

No return value. Side effects: possible command staging; on success, allocates a ServerBlockId, broadcasts the block, enqueues the command, consumes the uplink block.

ExecuteNetCommand BlueprintNativeEvent void (const FMassBattleNetCommand& Cmd)

锁步命令执行钩子。_Implementation 默认空实现——游戏特定命令在 BP 或派生 C++ 中覆写。网络会话中,单位任务(AgentsMoveTo、AgentsChaseAttack 等)必须在此钩子内创建,使各端确定性地构建——本地创建的任务只写入本端可见的 fragment,会导致失步。内置命令标签(AgentComponent.Spawn 等)由 AMassBattleNetworkGameStateBase::ExecuteNetCommand 统一执行,不经此钩子。

Lockstep command execution hook. The _Implementation is empty by default — game-specific commands override it in BP or derived C++. In networked sessions, agent tasks (AgentsMoveTo, AgentsChaseAttack, ...) must be created inside this hook so every peer builds them deterministically — creating them locally writes fragments only this peer can see and causes a desync. Built-in command tags (AgentComponent.Spawn etc.) are executed centrally by AMassBattleNetworkGameStateBase::ExecuteNetCommand, not through this hook.

Input
参数 Param类型 Type说明 Description
Cmdconst FMassBattleNetCommand&待执行命令。The command to execute.
Output

无返回值,默认无副作用。

No return value; no side effects by default.

OnClientResynced BlueprintNativeEvent void (int32 PlayerIndex, int32 PayloadTick, bool bSuccess)

重同步结果钩子。插件在 _Implementation 提供默认状态处理:失败时把客户端移入 ClientsRejectedUntilResync(隔离);成功时无额外动作(延迟 Agent.Spawn 已由 OnClientResyncComplete → FlushDeferredLockstepSpawnsForOwner 冲刷,快照优先保证)。BP 覆写以接入游戏特定生成状态机。

Resync outcome hook. The plugin's _Implementation provides default state handling: on failure the client is moved into ClientsRejectedUntilResync (quarantine); on success nothing extra is done (deferred Agent.Spawn is already flushed by OnClientResyncComplete → FlushDeferredLockstepSpawnsForOwner — the snapshot-first guarantee). Override in BP for game-specific spawn state machines.

Input
参数 Param类型 Type说明 Description
PlayerIndexint32玩家索引。Player index.
PayloadTickint32快照捕获 tick。Snapshot capture tick.
bSuccessbool重同步是否成功。Whether the resync succeeded.
Output

无返回值。副作用:失败时隔离客户端,成功时清理 resync 守卫。

No return value. Side effects: quarantines the client on failure; clears the resync guard on success.

CheckSpawnTimeouts BlueprintImplementableEvent void ()

游戏特定生成超时检查,在 CheckPacingTimeouts 末尾被调用。BP 实现;默认空操作。

Game-specific spawn-timeout check, called at the end of CheckPacingTimeouts. Implement in BP; no-op by default.

Input

无参数。

No parameters.

Output

无返回值(事件)。

No return value (event).

IsSpawnInProgress BlueprintImplementableEvent bool ()

是否有生成正阻塞重同步。BP 实现;默认 false。被 ProcessPendingResyncs / HandleClientResyncRequest 用于在生成进行中推迟 resync。

Whether a spawn is currently blocking resync. Implement in BP; default false. Used by ProcessPendingResyncs / HandleClientResyncRequest to defer resync while spawning.

Input

无参数。

No parameters.

Output

返回是否有生成正在进行。

Returns whether a spawn is in progress.

IsClientAwaitingResync bool (int32 PlayerId) const

查询玩家是否处于待 resync 状态:PendingLateJoinClients 或 ClientsWithPendingResync 含该玩家即返回 true。被 ProcessPendingLockstepSpawns 用于延迟待 resync 玩家的 Agent.Spawn(快照优先保证)。

Queries whether a player is awaiting resync: true when the player is in PendingLateJoinClients or ClientsWithPendingResync. Used by ProcessPendingLockstepSpawns to defer a resync-pending player's Agent.Spawn (snapshot-first guarantee).

Input
参数 Param类型 Type说明 Description
PlayerIdint32玩家索引。Player index.
Output

返回是否待 resync。

Returns whether the player awaits resync.

RegisterPendingLockstepSpawn void (UMassBattleAgentComponent* Comp)

服务器端 AgentComponent 在 BeginPlay 自注册(AddUnique)到 PendingComponentSpawns。ProcessPendingLockstepSpawns 在确定性 tick 边界冲刷:属主就绪(IsLockstepOwnerReady)且不在 resync 中时调用 RequestLockstepSpawn。

Server-side AgentComponent self-registers (AddUnique) into PendingComponentSpawns on BeginPlay. ProcessPendingLockstepSpawns flushes at the deterministic tick boundary: RequestLockstepSpawn fires when the owner is ready (IsLockstepOwnerReady) and not awaiting resync.

Input
参数 Param类型 Type说明 Description
CompUMassBattleAgentComponent*待冲刷的 Agent 组件。Agent component to flush.
Output

无返回值。副作用:加入冲刷队列。

No return value. Side effect: joins the flush queue.

RegisterPendingLockstepProjectileSpawn void (UMassBattleProjectileComponent* Comp)

ProjectileComponent 驱动的锁步生成注册(仅服务器)。无玩家门控(投射物无属主槽位),在同一 tick 边界通道冲刷。

Registers a ProjectileComponent-driven lockstep spawn (server only). No player gating (projectiles have no owner slot); flushed in the same tick-boundary pass.

Input
参数 Param类型 Type说明 Description
CompUMassBattleProjectileComponent*待冲刷的投射物组件。Projectile component to flush.
Output

无返回值。副作用:加入冲刷队列。

No return value. Side effect: joins the flush queue.

RegisterPendingLockstepLootSpawn void (UMassBattleLootComponent* Comp)

LootComponent 驱动的锁步生成注册(仅服务器)。无玩家门控,同一 tick 边界通道冲刷。

Registers a LootComponent-driven lockstep spawn (server only). No player gating; flushed in the same tick-boundary pass.

Input
参数 Param类型 Type说明 Description
CompUMassBattleLootComponent*待冲刷的 loot 组件。Loot component to flush.
Output

无返回值。副作用:加入冲刷队列。

No return value. Side effect: joins the flush queue.

FlushDeferredLockstepSpawnsForOwner void (int32 OwnerId)

为指定玩家立即冲刷其延迟的 Agent.Spawn:遍历 PendingComponentSpawns,属主匹配的组件直接 RequestLockstepSpawn,其余保留。由 OnClientResyncComplete 调用——快照优先保证:客户端拥有世界状态后才触发其生成。

Immediately flushes one player's deferred Agent.Spawn: iterates PendingComponentSpawns, firing RequestLockstepSpawn for matching owners and keeping the rest. Called from OnClientResyncComplete — the snapshot-first guarantee: a client's spawn fires only after it holds the world state.

Input
参数 Param类型 Type说明 Description
OwnerIdint32玩家索引。Player index.
Output

无返回值。副作用:触发匹配组件的 RequestLockstepSpawn。

No return value. Side effect: fires RequestLockstepSpawn on matching components.

AllocatePlayerSlot int32 (int32 PlayerIndex)

为玩家分配确定性槽位:优先复用 FreeSlots,否则取 NextPlayerSlot++;写入双向映射,并清除 TCP transport 的 freed 守卫(ReusePlayerSlot)使该槽位重新成为合法认证目标。

Assigns a deterministic slot: reuses FreeSlots first, else NextPlayerSlot++; fills both direction maps and clears the TCP transport's freed guard (ReusePlayerSlot) so the slot is a legitimate auth target again.

Input
参数 Param类型 Type说明 Description
PlayerIndexint32玩家索引。Player index.
Output

返回分配的槽位号。副作用:更新两个映射、复用 transport 槽位。

Returns the allocated slot. Side effects: updates both maps, reuses the transport slot.

FreePlayerSlot void (int32 PlayerSlot)

释放玩家槽位:清除双向映射、槽位入 FreeSlots 复用池,并调用 transport 的 ReleasePlayerSlot 释放该槽位全部 TCP 资源(socket、认证注册、挂起快照)——防止死 socket 跨玩家登出残留污染下一次重连。

Frees a player slot: clears both maps, returns the slot to the FreeSlots pool, and calls the transport's ReleasePlayerSlot to release all TCP resources (socket, auth registration, pending snapshot) — so a dead socket cannot survive a player's logout and poison the slot's next reconnect.

Input
参数 Param类型 Type说明 Description
PlayerSlotint32要释放的槽位。The slot to release.
Output

无返回值。副作用:更新映射、回收槽位、释放 transport 资源。

No return value. Side effects: map updates, slot recycling, transport resource release.

ReportClientDesync void (int32 PlayerIndex, int32 TickCount, int64 LocalHash)

客户端主动报告的失步(ServerReportDesync 落地):查服务器该 tick 的 hash,不一致则 RecordDesync 并把客户端移入 ClientsRejectedUntilResync(拒绝其输入直到 resync 完成)。

Client-reported desync (landing of ServerReportDesync): looks up the server hash for that tick; on mismatch, records the desync and quarantines the client in ClientsRejectedUntilResync (input rejected until resync completes).

Input
参数 Param类型 Type说明 Description
PlayerIndexint32玩家索引。Player index.
TickCountint32失步 tick。The diverging tick.
LocalHashint64客户端本地 hash。Client local hash.
Output

无返回值。副作用:hash 不一致时记录失步并隔离客户端。

No return value. Side effects: records the desync and quarantines the client on hash mismatch.

AckClientTick void (int32 PlayerIndex, int32 AckedTick, int64 LocalHash)

处理客户端 ack(ServerAckTick 落地):先做 ack 钳制——超过服务器当前 tick 的 ack(伪造值,合法客户端只能 ack 已广播过的 tick)钳到当前 tick,每玩家首次伪造打一条 [ACK_CLAMP] Warning(作弊信号),其后静默钳制(不给日志洪水向量);推进 ClientAckedTicks、更新最大滞后;若服务器在该 tick 有 hash 且与客户端不一致——计入 ClientConsecutiveHashMismatches 连击,连续 DesyncConfirmTicks 次(阈值见 UMassBattleNetworkSubsystem)才记录失步并隔离客户端(瞬态自愈型 1-2 tick 毛刺到不了阈值);任一匹配 ack 清零连击(与客户端 ConsecutiveDesyncMismatchTicks 镜像)。监听服务器本地玩家每 tick 自 ack(共享服务端模拟故恒匹配)。

Handles a client ack (landing of ServerAckTick): first the ack clamp — an ack beyond the server's current tick (a fabricated value; a legit client can only ack ticks the server has broadcast) is clamped to the current tick, with one [ACK_CLAMP] Warning per player on first fabrication (cheat signal) and silent clamping afterwards (no log-flood vector); advances ClientAckedTicks, updates the max observed lag; when the server has a hash for that tick and it mismatches the client — the streak counter ClientConsecutiveHashMismatches increments, and the desync is recorded + the client quarantined only after DesyncConfirmTicks consecutive mismatches (threshold on UMassBattleNetworkSubsystem; a transient self-healing 1-2 tick blip never reaches it); any matching ack resets the streak (mirrors the client-side ConsecutiveDesyncMismatchTicks). The listen-server local player self-acks every tick (shares the server sim, so it always matches).

Input
参数 Param类型 Type说明 Description
PlayerIndexint32玩家索引(负值忽略)。Player index (negative ignored).
AckedTickint32客户端已确认执行的 tick。Tick the client has acked as executed.
LocalHashint64客户端该 tick 的本地 hash(未校验阶段为服务端期望值)。Client local hash for that tick (server expected value while unvalidated).
Output

无返回值。副作用:更新 ack/滞后追踪;hash 不一致时记录失步并隔离。

No return value. Side effects: updates ack/lag tracking; records desync and quarantines on hash mismatch.

CheckPacingTimeouts void ()

服务端心跳监控(内部 bPacedMode 门控):最后 ack 早于 PacingTimeoutTicks 的客户端判死,踢出前广播 ClientKickedPacingTimeout 网络事件。单阈值——ack 年龄即停滞。网络恢复中的客户端经 MulticastDesyncCheck 持续 ack,天然豁免。末尾委托 CheckSpawnTimeouts。由 OnSimTickCompleted 每 tick 调用。

Server-side heartbeat monitor (gated by bPacedMode internally): clients whose last ack is older than PacingTimeoutTicks are judged dead; a ClientKickedPacingTimeout network event is broadcast before kicking. Single threshold — the ack age IS the stall. Clients in network recovery keep acking via MulticastDesyncCheck and are naturally exempt. Delegates to CheckSpawnTimeouts at the end. Called every tick from OnSimTickCompleted.

Input

无参数。

No parameters.

Output

无返回值。副作用:广播事件、经 GameSession->KickPlayer 踢出超时客户端。

No return value. Side effects: broadcasts the event, kicks timed-out clients via GameSession->KickPlayer.

HandleClientResyncRequest void (int32 PlayerIndex, int32 ClientTickCount, APlayerController* PC)

处理客户端 resync 请求(ServerRequestResync 落地):已在派发中(ClientsWithPendingResync)则忽略重复;非 post-command 边界或生成进行中则延迟入 PendingResyncClients。到达边界后:取最新缓存快照,从命令历史填充半开区间 [PayloadTick, CurrentTick+1] 的 gap 命令(客户端 FF 期间重放,不得依赖在途投递),派发 TCP 快照(DispatchSnapshotViaTcp_Async,后台序列化/压缩),派发前加入 in-flight 守卫。

Handles a client resync request (landing of ServerRequestResync): duplicates are ignored while a dispatch is in flight (ClientsWithPendingResync); requests are deferred into PendingResyncClients outside the post-command boundary or while spawning. At the boundary: takes the latest cached snapshot, fills gap commands over the half-open range [PayloadTick, CurrentTick+1] from command history (the client replays them during FF and must not depend on in-flight delivery), dispatches via TCP (DispatchSnapshotViaTcp_Async, background serialize/compress), and adds the in-flight guard before dispatch.

Input
参数 Param类型 Type说明 Description
PlayerIndexint32玩家索引。Player index.
ClientTickCountint32客户端当前 tick(当前实现未使用,以服务器当前 tick 为目标)。Client's current tick (currently unused; the server's current tick is the target).
PCAPlayerController*请求客户端控制器(当前经 GameState->PlayerArray 重查)。Requesting client controller (currently re-looked-up via GameState->PlayerArray).
Output

无返回值。副作用:可能延迟排队、设置 in-flight 守卫、异步派发快照(失败时 OnClientResyncResult(false) 清理守卫)。

No return value. Side effects: possible deferral, in-flight guard set, async snapshot dispatch (failure funnels to OnClientResyncResult(false) which clears the guard).

ProcessPendingResyncs void ()

在确定性 post-command 边界逐个处理延迟的 resync 请求:取队列头玩家,调 HandleClientResyncRequest。生成进行中(IsSpawnInProgress)则整批推迟。

Processes deferred resync requests one by one at the deterministic post-command boundary: takes the head player and calls HandleClientResyncRequest. Deferred wholesale while a spawn is in progress (IsSpawnInProgress).

Input

无参数。

No parameters.

Output

无返回值。副作用:出队一个 resync 请求并处理。

No return value. Side effect: dequeues and handles one resync request.

ProcessPendingLateJoinSnapshots void ()

在确定性 post-command 边界处理 late-join 客户端:队列清空后逐个解析控制器与槽位;无缓存快照则标记强制捕获并重新入队;有快照则填充 [PayloadTick, 当前 tick) 的 gap 命令,加入 LateJoinSnapshotsInFlight 后异步派发——派发失败移除 in-flight 并重新入队(下一边界重试),防止失败快照从重试中永久消失。

Handles late-join clients at the deterministic post-command boundary: after clearing the queue, resolves each controller and slot; without a cached snapshot it forces a capture and re-queues; with one, fills gap commands over [PayloadTick, current tick), adds the client to LateJoinSnapshotsInFlight, and dispatches asynchronously — on dispatch failure the in-flight marker is removed and the client re-queued (retried next boundary), so a failed late-join snapshot never vanishes from retry forever.

Input

无参数。

No parameters.

Output

无返回值。副作用:可能标记强制捕获、异步派发快照、重排队列。

No return value. Side effects: possible forced capture flag, async snapshot dispatch, queue re-queueing.

OnClientResyncComplete void (int32 PlayerIndex)

客户端 resync 完成的清理(ServerResyncComplete / ServerReportResyncResult 落地):ack 置当前 tick、解除隔离、移除 in-flight 守卫,并冲刷该玩家的延迟 Agent.Spawn(快照优先保证)。

Post-resync cleanup (landing of ServerResyncComplete / ServerReportResyncResult): ack to the current tick, un-quarantine, remove the in-flight guard, and flush the player's deferred Agent.Spawn (snapshot-first guarantee).

Input
参数 Param类型 Type说明 Description
PlayerIndexint32玩家索引。Player index.
Output

无返回值。副作用:更新追踪、冲刷延迟生成。

No return value. Side effects: tracking updates, deferred spawn flush.

OnClientResyncResult void (int32 PlayerIndex, int32 PayloadTick, bool bSuccess, int32 SnapshotId = -1, bool bServerInitiated = false)

resync 结果统一收敛点(TCP 异步派发失败、ServerReportTcpSnapshotResult、ServerReportResyncResult 都汇聚于此):失败且属于 late-join in-flight 时重新入队(服务端主动重试,不依赖客户端 300-tick pacing 自救);随后经 H2 派发匹配闸——客户端上报的结果必须匹配一条在途派发记录(双方都有 SnapshotId 时还需匹配;服务器内部失败作为可信方直接通过),无效上报保持隔离但释放 ClientsWithPendingResync 传输守卫(否则错配上报会让该客户端下一次真实 resync 请求被去重死锁);通过后 OnClientResyncComplete + OnClientResynced 钩子。

Unified resync-outcome funnel (async TCP dispatch failure, ServerReportTcpSnapshotResult, and ServerReportResyncResult all converge here): on failure of a late-join in-flight dispatch the client is re-queued (the server retries proactively instead of relying on the client's 300-tick pacing self-recovery); then the H2 dispatch-match gate — a client-reported result must match an outstanding dispatch record (SnapshotId too when both sides have one; server-internal failures pass as trusted), and an invalid report holds the quarantine but releases the ClientsWithPendingResync transport guard (otherwise a mismatched report would deadlock the client's next genuine resync request in the dedup); on pass, OnClientResyncComplete + the OnClientResynced hook run.

Input
参数 Param类型 Type说明 Description
PlayerIndexint32玩家索引。Player index.
PayloadTickint32快照捕获 tick(透传给钩子)。Snapshot capture tick (forwarded to the hook).
bSuccessbool是否成功。Whether it succeeded.
SnapshotIdint32上报的快照 ID(默认 -1 = 不可得,仅双方都有时参与匹配)。Reported snapshot ID (default -1 = unavailable; participates in matching only when both sides have one).
bServerInitiatedbooltrue = 服务器内部完成路径(可信,直接消费记录);false = 客户端上报(须匹配在途派发)。true = server-internal completion path (trusted, consumes the record directly); false = client report (must match an outstanding dispatch).
Output

无返回值。副作用:late-join 失败重排队、消费/拒绝对应 H2 派发记录、触发完成清理与 BP 钩子。

No return value. Side effects: late-join failure re-queue, H2 dispatch-record consume/reject, completion cleanup, BP hook.

TryConsumePendingDispatch / RecordPendingDispatchSnapshotId / ValidateAndCompleteResync bool / void / void

H2 派发匹配验证三件套(由 PlayerController RPC 与静态异步派发助手调用):TryConsumePendingDispatch 是验证核心——服务器内部完成(bServerInitiated)作为可信方直接消费 PendingSnapshotDispatches 记录;客户端上报必须有在途记录,且双方 SnapshotId 都有效时须一致;RecordPendingDispatchSnapshotId 在异步派发拿到 SnapshotId 后回填记录;ValidateAndCompleteResync 是 ServerResyncComplete 的带验证入口——TCP 派发的快照会产生两份完成上报(传输层 ack 与追帧完成 RPC),后到者查无记录:未隔离玩家按幂等重复上报放行(仅清理语义),隔离中的玩家保持审计拒绝(但释放传输守卫)。

The H2 dispatch-match validation trio (called by PlayerController RPCs and the static async dispatch helper): TryConsumePendingDispatch is the validation core — server-internal completions (bServerInitiated) consume the PendingSnapshotDispatches record as trusted; client reports require an outstanding record, with SnapshotIds matching when both are valid; RecordPendingDispatchSnapshotId backfills the record once the async dispatch obtains a SnapshotId; ValidateAndCompleteResync is the validated entry of ServerResyncComplete — a TCP-dispatched snapshot produces TWO completion reports (transport ack + FF-completion RPC), and whichever lands second finds no record: an unquarantined reporter passes as an idempotent duplicate (cleanup semantics only), a quarantined one is still audit-rejected (but the transport guard is released).

Input

PlayerIndex(+ 可选 SnapshotId / bServerInitiated)标识待验证的玩家派发。

PlayerIndex (+ optional SnapshotId / bServerInitiated) identifying the player dispatch to validate.

Output

TryConsumePendingDispatch 返回是否匹配并消费;其余无返回值。副作用:增删 PendingSnapshotDispatches 记录,决定隔离是否解除。

TryConsumePendingDispatch returns whether it matched (and consumed); the others return nothing. Side effects: PendingSnapshotDispatches record bookkeeping; decides whether the quarantine lifts.

ReportClientHash void (int32 PlayerIndex, int32 TickCount, uint64 Hash)

专用服务器路径:接收客户端模拟 hash(ServerReportHash 落地)并转发给 NetworkRelay->ReportClientHash 参与投票。

DedicatedServer path: receives a client simulation hash (landing of ServerReportHash) and forwards it to NetworkRelay->ReportClientHash for voting.

Input
参数 Param类型 Type说明 Description
PlayerIndexint32玩家索引。Player index.
TickCountint32hash 对应 tick。Tick of the hash.
Hashuint64客户端模拟 hash。Client simulation hash.
Output

无返回值。副作用:转发给 relay 聚合。

No return value. Side effect: forwards to the relay for aggregation.

ReceiveSnapshotUpload void (int32 PlayerIndex, int32 TickCount, const TArray<uint8>& CompressedSnapshot)

专用服务器路径:接收压缩快照上传(ServerUploadSnapshot 落地)用于灾备。入口验证:大小须在 (0, 64MB] 且 tick 在 [LastKnownServerTick-1024, LastKnownServerTick+256] 窗口内——未来 tick 视为恶意标记直接拒绝(防 relay 的 SnapshotHistory 无界增长,ListenServer 模式 relay 自身 CurrentTick 从不推进);另加每玩家上传冷却(5 秒,审计 H6 带宽向量——relay 字节预算限制内存,冷却限制 CPU/带宽:反复的 64MB 上传消耗真实的序列化/压缩时间);通过后转发 NetworkRelay->UploadSnapshot 存储。

DedicatedServer path: receives a compressed snapshot upload (landing of ServerUploadSnapshot) for disaster recovery. Entry validation: size in (0, 64MB] and tick inside [LastKnownServerTick-1024, LastKnownServerTick+256] — a future tick is treated as a hostile marker and rejected (prevents unbounded SnapshotHistory growth, since the relay's own CurrentTick never advances in ListenServer mode); plus a per-player upload cooldown (5s, audit H6 bandwidth vector — the relay's byte budget bounds memory while the cooldown bounds CPU/bandwidth: repeated 64MB uploads cost real serialization/compression time); valid uploads forward to NetworkRelay->UploadSnapshot.

Input
参数 Param类型 Type说明 Description
PlayerIndexint32上传玩家(冷却按玩家计)。Uploading player (the cooldown is per player).
TickCountint32快照对应 tick。Tick of the snapshot.
CompressedSnapshotconst TArray<uint8>&压缩快照字节。Compressed snapshot bytes.
Output

无返回值。副作用:验证/冷却失败时 Error 或 Warning 日志并拒绝;通过时写入 relay 快照历史并刷新该玩家的冷却时间戳。

No return value. Side effects: Error/Warning log + rejection on validation/cooldown failure; relay snapshot history write and cooldown-timestamp refresh on success.

GetDynamicInputBufferMs float ()

计算动态 K(毫秒)。当前实现返回静态 MinInputBufferMs——LAN 环境无需动态抖动/RTT 测量;广域网请在配置中增大 MinInputBufferMs。每次 tick 由 OnSimTickCompleted 读取并随 MulticastSyncTick 下发。

Computes the dynamic K (ms). The current implementation returns the static MinInputBufferMs — LAN play needs no dynamic jitter/RTT measurement; for WAN, raise MinInputBufferMs in config. Read each tick by OnSimTickCompleted and broadcast with MulticastSyncTick.

Input

无参数。

No parameters.

Output

返回当前输入缓冲毫秒数(默认 = MinInputBufferMs,150ms)。

Returns the current input buffer in ms (defaults to MinInputBufferMs, 150ms).

OnSimTickCompleted UFUNCTION() void (int32 TickCount, int64 TickHash) (private bridge)

服务端每 tick 网络中枢(私有,由 UMassBattleNetworkSubsystem::OnTickCompleted 触发,仅权威端执行)。流程:① 网络 flush tick(按 NetworkFlushIntervalTicks 节拍)为每个带 Component→Entity 轴的组件采样变换、K-buffer 预测外推、网格编码生成 AgentComponent.SetAgentTransform 指令;② 排序并多播 PendingCommands((ExecuteTick, ServerExecSequence) 序);③ 每 tick 计算服务端 tick 间隔 EWMA 与时间膨胀并 MulticastSyncTick;④ flush tick 且开启失步检测时 MulticastDesyncCheck;⑤ post-command 边界处理 late-join 与 resync;⑥ 冲刷组件驱动锁步生成;⑦ 监听服务器本地自 ack、步调超时检查、强制 flush 连接降低调速延迟。

Per-tick server network hub (private, fired by UMassBattleNetworkSubsystem::OnTickCompleted, authority only). Flow: ① on network flush ticks (paced by NetworkFlushIntervalTicks), samples every component with a Component→Entity axis, extrapolates by K-buffer prediction, grid-encodes, and produces AgentComponent.SetAgentTransform commands; ② sorts and multicasts PendingCommands (by (ExecuteTick, ServerExecSequence)); ③ every tick computes the server tick-interval EWMA and time dilation and calls MulticastSyncTick; ④ on flush ticks with desync check enabled, MulticastDesyncCheck; ⑤ handles late-join and resync at the post-command boundary; ⑥ flushes component-driven lockstep spawns; ⑦ listen-server local self-ack, pacing timeout checks, and forced connection flush to lower pace-sync latency.

Input
参数 Param类型 Type说明 Description
TickCountint32刚完成的模拟 tick。The just-completed simulation tick.
TickHashint64该 tick 的服务端确定性 hash。Server deterministic hash for that tick.
Output

无返回值。副作用:更新 LastTickHash/LastKnownServerTick,广播命令/sync/desync RPC,派发 resync 快照,冲刷生成队列。

No return value. Side effects: updates LastTickHash/LastKnownServerTick, broadcasts command/sync/desync RPCs, dispatches resync snapshots, flushes spawn queues.

成员变量 Members

NetworkRelay TObjectPtr<UMassBattleNetworkRelay> (UPROPERTY)

网络中继层实例,BeginPlay 时创建,按 GetNetMode() 初始化为 ListenServer 或 DedicatedServer 模式。ListenServer 下为被动(时钟由 Subsystem 驱动);DedicatedServer 下提供 hash 投票与快照存储。

Network relay instance, created in BeginPlay and initialized to ListenServer or DedicatedServer mode per GetNetMode(). Passive under ListenServer (clock driven by the Subsystem); provides hash voting and snapshot storage under DedicatedServer.

bEnableNetworkSync bool (EditAnywhere, BlueprintReadWrite)

网络锁步总开关,默认 true。关闭后游戏以单机模式运行,无网络同步。

Master switch for deterministic lockstep networking, default true. When off, the game runs as standalone with no network synchronization.

bEnableDesyncCheck bool (EditAnywhere, BlueprintReadWrite)

逐 tick hash 广播开关,默认 true。客户端本地 hash 与服务器期望值不一致时触发失步恢复。

Per-tick hash broadcast switch, default true. Client-side desync recovery triggers when the local hash mismatches the server expected hash.

bPacedMode bool (EditAnywhere, BlueprintReadWrite)

服务端心跳监控开关,默认 true。开启后追踪每客户端 ack tick,未 ack 达 PacingTimeoutTicks 的客户端被踢出。大多数情况由客户端 LagResyncThresholdTicks 自恢复处理;此机制捕获真正掉线/网络丢失的客户端。

Server heartbeat monitor switch, default true. Tracks per-client ack ticks and kicks clients silent for PacingTimeoutTicks. Most cases are handled by client-side LagResyncThresholdTicks self-recovery; this catches truly dead/network-lost clients.

PacingTimeoutTicks int32 (EditAnywhere, BlueprintReadWrite)

踢人阈值(默认 600)。必须大于客户端 LagResyncThresholdTicks(300),确保客户端快照自恢复优先;仅 bPacedMode 为 true 时生效。

Kick threshold (default 600). Must be larger than the client's LagResyncThresholdTicks (300) so client snapshot self-recovery gets its chance first; only effective when bPacedMode is true.

MinInputBufferMs float (EditAnywhere, BlueprintReadWrite, Category "K-Buffer")

输入缓冲下限(毫秒),默认 150。LAN 环境 GetDynamicInputBufferMs 直接返回此值。

Minimum input buffer in ms, default 150. GetDynamicInputBufferMs returns this directly for LAN play.

MaxInputBufferMs float (EditAnywhere, BlueprintReadWrite, Category "K-Buffer")

输入缓冲上限(毫秒),默认 300。当前实现未引用(保留配置位)。

Maximum input buffer in ms, default 300. Not referenced by the current implementation (reserved configuration).

ExtraSpawnBufferMs float (EditAnywhere, BlueprintReadWrite, Category "K-Buffer")

生成指令的额外缓冲(毫秒),默认 66。当前实现未直接引用(ExtraDeferTicks 参数承担同类职责)。

Extra buffer for spawn commands in ms, default 66. Not referenced directly by the current implementation (the ExtraDeferTicks parameter covers the same duty).

ClientCommandGateMode EMassBattleClientCommandGateMode (EditAnywhere, BlueprintReadWrite)

客户端命令闸门模式(默认 Enforce):Enforce 拒绝 ClientAllowedCommandTags 之外的客户端来源锁步命令(服务器权威 tag 恒拒,deny 优先);LogOnly 仅记录本应拒绝的命令但放行——存量游戏迁移观察期;Disabled 关闭闸门。

Client command gate mode (default Enforce): Enforce rejects client-originated lockstep commands outside ClientAllowedCommandTags (server-authority tags always rejected, deny wins); LogOnly logs would-reject but allows through — a migration period for existing games; Disabled turns the gate off.

ClientAllowedCommandTags TSet<FName> (EditAnywhere, BlueprintReadWrite)

游戏侧允许通过闸门的客户端命令 tag(输入/指令/技能)。服务器权威 tag(见 MB_FOR_EACH_SERVER_AUTHORITY_TAG)永不可放行——deny 注册表优先。在 BP GameMode 子类默认值填写,或经 RegisterClientAllowedCommandTag 运行时注册。

Game-side client-issued command tags allowed through the gate (input/orders/abilities). Server-authority tags (see MB_FOR_EACH_SERVER_AUTHORITY_TAG) can NEVER be allowed — the deny registry wins. Fill in BP GameMode subclass defaults, or register at runtime via RegisterClientAllowedCommandTag.

bLogRejectedClientCommands bool (EditAnywhere, BlueprintReadWrite)

拒绝详录开关(默认 true):每 (玩家,tag) 组合首见详录 + 每 300 次拒绝输出累计摘要;无论洪泛速率多大,诊断状态均有界(最多 1024 个组合被追踪)。

Verbose rejection logging (default true): first occurrence per (player,tag) combo plus a summary every 300 rejections; diagnostics stay bounded regardless of flood rate (at most 1024 combos tracked).

MaxClientCommandsPerTick int32 (EditAnywhere, BlueprintReadWrite)

每玩家每 tick 锁步命令准入配额(默认 16,审计 H7)——洪泛 Server_SendNetCommand 的客户端在入口即被丢弃,而不是被 N 倍放大给所有端。合法输入流(每 tick 数条命令)远达不到此值。

Per-player per-tick lockstep-command admission quota (default 16, audit H7) — a client flooding Server_SendNetCommand is dropped at entry instead of being amplified N-fold to every peer. Legit input streams (a few commands per tick) never approach this.

MaxPendingCommands int32 (EditAnywhere, BlueprintReadWrite)

服务器待广播命令队列硬上限(默认 4096,审计 H7)——在每玩家配额之上的聚合尖峰保护,超限命令丢弃并打 Error。

Hard cap on the server's pending-broadcast command queue (default 4096, audit H7) — aggregate spike protection over the per-player quota; overflow commands are dropped with an Error log.

MaxExtraDeferTicks int32 (EditAnywhere, BlueprintReadWrite)

客户端提供的 ExtraDeferTicks 上限(默认 1024,审计 M6)——ReceivePlayerCommand 把客户端可控的推迟值钳到 [0, 此值],防止极值溢出 ExecuteTick 调度算术并使 NextServerExecSequence 增长大量远未来键。

Upper bound for client-supplied ExtraDeferTicks (default 1024, audit M6) — ReceivePlayerCommand clamps the client-controllable deferral to [0, this value], keeping unclamped extremes from overflowing the ExecuteTick schedule arithmetic and growing NextServerExecSequence with far-future keys.

DynamicInputBufferMs float

每 tick 由 GetDynamicInputBufferMs() 刷新的动态 K(毫秒),随 MulticastSyncTick 下发;命令排程与 K-buffer 预测均引用它。

Dynamic K (ms) refreshed per tick by GetDynamicInputBufferMs() and broadcast with MulticastSyncTick; used by command scheduling and K-buffer prediction.

PlayerSlotToPlayerId / PlayerIdToPlayerSlot TMap<int32, int32> ×2 (public)

PlayerSlot ↔ PlayerId 双向查找表,由 AllocatePlayerSlot / FreePlayerSlot 维护。槽位是网络命令与 TCP 认证中的确定性玩家标识。

Bidirectional PlayerSlot ↔ PlayerId lookup tables, maintained by AllocatePlayerSlot / FreePlayerSlot. The slot is the deterministic player identity in net commands and TCP auth.

NextPlayerSlot / FreeSlots int32 / TArray<int32> (public)

槽位分配状态:下一个新槽位序号与释放槽位复用池(AllocatePlayerSlot 优先取 FreeSlots)。

Slot allocation state: next fresh slot number and the freed-slot reuse pool (AllocatePlayerSlot pops FreeSlots first).

PendingCommands TArray<FMassBattleNetCommand> (protected)

待广播命令缓冲:本 tick 内由各入口(上行/自驱/钩子)入队,下个网络 flush tick 排序后多播并清空。

Pending broadcast buffer: commands enqueued by the various entries (uplink/self-driven/hooks) within a tick, sorted and multicast at the next network flush tick, then cleared.

NextServerExecSequence TMap<int32, int32> (protected)

按 ExecuteTick 的命令序号计数器——同 tick 内命令的确定性次序,入队时递增分配。

Per-ExecuteTick command sequence counter — deterministic order within a tick, incremented at enqueue.

ClientAckedTicks TMap<int32, int32> (protected)

PlayerIndex → 最近 ack tick。驱动 GetFastestAckedClientTick 与步调超时判定。

PlayerIndex → latest acked tick. Drives GetFastestAckedClientTick and pacing-timeout judgment.

ClientMaxObservedLag TMap<int32, int32> (protected)

PlayerIndex → 观察到的最大滞后(tick),ack 时取历史最大值。

PlayerIndex → max observed lag in ticks, kept at the historical maximum on ack.

ClientConsecutiveHashMismatches TMap<int32, int32> (protected)

失步防抖:每玩家连续失配 ack 连击——连续 DesyncConfirmTicks 次(阈值见 UMassBattleNetworkSubsystem)才 DESYNC + 隔离;任一匹配 ack 清零。与客户端 ConsecutiveDesyncMismatchTicks 镜像。

Desync debounce: per-player consecutive mismatching-ack streak — DESYNC + quarantine only after DesyncConfirmTicks consecutive mismatches (threshold on UMassBattleNetworkSubsystem); reset by any matching ack. Mirrors the client-side ConsecutiveDesyncMismatchTicks.

PendingLateJoinClients TArray<int32> (protected)

从 PostLogin 延迟到确定性边界的 late-join 客户端队列。

Late-join client queue, deferred from PostLogin to the deterministic boundary.

PendingLateJoinMinSnapshotTick TMap<int32, int32> (protected)

晚加入派发的加入 tick 下限:第一份快照必须在加入 tick 或之后捕获。陈旧缓存快照(周期捕获节奏、长会话)配大 gap,gap 里全是 auto-flood 块命令——新客户端从未收到那些块 → 暂存冻结 → 10s 超时 → 失步;此前必须第二次(新鲜)resync 才能稳定。派发完成后随玩家清理移除。

Join-tick floor for the late-join dispatch: the first snapshot MUST be captured at/after the join tick. A stale cached snapshot (periodic capture cadence, long session) pairs a large gap full of auto-flood block commands whose TCP blocks the newcomer never received → staged → 10s timeout → desync; a SECOND (fresh) resync used to be required to stabilize. Removed with the player once its dispatch is served.

LateJoinSnapshotsInFlight / LateJoinSnapshotsInFlightSince TSet<int32> / TMap<int32, int32> (protected)

等待异步结果的 late-join 快照派发集合——失败的派发把客户端重新入队,避免从重试中永久消失;伴随的 Since 映射为每个在途标记盖起始 tick 戳,滞留逾约 600 tick 视为孤儿释放(完成上报丢失的兜底)。

Late-join snapshot dispatches awaiting async results — failed dispatches re-queue the client so it never vanishes from retry; the companion Since map stamps the start tick per in-flight marker, releasing markers resident past ~600 ticks as orphans (a lost-completion backstop).

ClientsWithPendingResync TSet<int32> (protected)

正在重同步的客户端集合;同时充当去重守卫(派发中忽略重复请求)。

Clients being resynced; doubles as the dedup guard (duplicate requests ignored while dispatching).

ClientsRejectedUntilResync TSet<int32> (protected)

隔离的客户端:失步被确认后其上行输入被拒绝,直到 resync 成功。

Quarantined clients: uplink input rejected after confirmed desync until resync succeeds.

PendingResyncClients TArray<int32> (protected)

延迟的 resync 请求队列,post-command 边界逐个处理。

Deferred resync request queue, handled one by one at the post-command boundary.

ClientRejectionCounts / TotalRejectedCommands TMap<uint64, int32> / int32 (protected)

客户端命令闸门诊断(有界):按 (玩家,tag) 组合计数,最多追踪 1024 个组合;配合 TotalRejectedCommands 每 300 次拒绝输出摘要——恶意 tag 模糊不得无界扩大日志/状态。

Client command gate diagnostics (bounded): counts per (player,tag) combo with at most 1024 combos tracked; with TotalRejectedCommands emitting a summary every 300 rejections — hostile tag fuzzing must not grow log/state unbounded.

FabricatedAckWarnedPlayers TSet<int32> (protected)

ack 钳制首警记录——每玩家一条 [ACK_CLAMP] 日志(声称 ack 超过服务器当前 tick 即伪造),其后静默钳制,不给日志洪水向量。

Ack-clamp first-warning bookkeeping — one [ACK_CLAMP] log per player (an ack beyond the server's current tick is fabricated), then silent clamping to deny a log-flood vector.

PendingSnapshotDispatches TMap<int32, FPendingSnapshotDispatch> (protected)

在途快照派发记录(内部结构 FPendingSnapshotDispatch{SnapshotId, PayloadTick})——H2 验证闸:客户端上报的恢复完成仅在存在在途派发(有记录,可得时 SnapshotId 匹配)时才解除隔离;服务器内部完成路径作为可信方消费记录。

In-flight snapshot dispatch records (inner struct FPendingSnapshotDispatch{SnapshotId, PayloadTick}) — the H2 validation gate: a client-reported resync completion only lifts quarantine against an outstanding dispatch (record present, SnapshotId matching when available); server-internal completion paths consume the record as trusted.

PlayerCommandRateByTick TMap<int32, FPlayerCommandRate> (protected)

每玩家命令准入配额状态(审计 H7,内部结构 FPlayerCommandRate{Tick, Count})——按 tick 重置计数,驱动 MaxClientCommandsPerTick 判定。

Per-player command admission quota state (audit H7, inner struct FPlayerCommandRate{Tick, Count}) — per-tick reset counter driving the MaxClientCommandsPerTick check.

LastSnapshotUploadTime TMap<int32, double> (protected)

每玩家快照上传冷却时间戳(审计 H6 带宽向量)——5 秒窗口内的重复上传直接拒绝。

Per-player snapshot-upload cooldown timestamps (audit H6 bandwidth vector) — repeated uploads within the 5s window are rejected.

bNavGenDelegateBound / LastAutoSubstrateResendTime / LastFFFullResyncRequestTimes bool / double / TMap<FName, double> (public)

流场基底同步状态:navmesh 重建委托是否已绑定(首次基底发送时绑定)、自动重导出的墙钟节流时间戳(2 秒)、按场的全量重发请求节流时间戳(修复风暴收敛为每窗口一次)。

Flow-field substrate sync state: whether the navmesh rebuild delegate is bound (on first substrate send), the wall-clock throttle timestamp for auto re-exports (2s), and per-field full-resend request throttle timestamps (repair storms collapse to one per window).

PendingComponentSpawns / PendingProjectileComponentSpawns / PendingLootComponentSpawns TArray<TWeakObjectPtr<...>> ×3 (protected)

组件驱动锁步生成的冲刷队列(仅服务器)。Agent 队列有玩家门控(resync 中延迟);Projectile/Loot 队列无门控。同一 tick 边界通道(ProcessPendingLockstepSpawns)冲刷,无效弱指针即丢弃。

Component-driven lockstep spawn flush queues (server only). The Agent queue is player-gated (deferred while resyncing); the Projectile/Loot queues are not. All flushed in the same tick-boundary pass (ProcessPendingLockstepSpawns), dropping invalid weak pointers.

LastTickHash / LastKnownServerTick int64 / int32 (protected)

最近一次 OnSimTickCompleted 的服务端 hash 与 tick,由快照上传校验等读取。

Latest server hash and tick from OnSimTickCompleted, read by snapshot-upload validation and others.

ServerTickIntervalEWMA / ServerTimeDilation double / float (protected)

实际服务端 tick 间隔的 EWMA(α=0.1,约 30 tick 平滑)与由此导出的时间膨胀(钳制 [0.2, 1.0])。服务端跟不上实时时下调膨胀,客户端降速保持对齐。

EWMA of the actual server tick interval (α=0.1, ~30-tick smoothing) and the derived time dilation (clamped to [0.2, 1.0]). When the server can't keep real-time, dilation drops and clients slow down to stay aligned.

LastTickWallTime double (protected)

tick 间隔 EWMA 的上一次墙钟采样。实例成员而非 static——static 跨世界重启残留,会使首个 EWMA 采样间隔巨大(所有客户端被压到 20% 速度)。

Last wall-clock sample for the tick-interval EWMA. Instance member, NOT static — a static survives world restarts and pollutes the first EWMA sample with a huge interval (all clients throttled to 20%).

管线角色 Pipeline Role

服务器侧锁步网络中枢,UMassBattleSubsystem 每 tick 完成后经 OnTickCompleted → OnSimTickCompleted 驱动(GameModeBase.cpp:152 绑定;实现 185-383 行)。 命令流:客户端上行 Server_SendNetCommand → ReceivePlayerCommand(客户端命令闸门 + 配额/队列上限/调度钳制 + K-buffer 排程)→ PendingCommands → flush tick 排序 → MulticastCommandToClients 广播;服务器自驱命令由组件/子系统直接调 SendLockstepCommandToClients(如 MassBattleAgentComponent.cpp:1104 的 AgentComponent.Spawn、MassBattleProjectileComponent.cpp:646、MassBattleLootComponent.cpp:745、MassBattleObstSubsystem.cpp:485 的 Obstacle.Spawn 与各 Despawn),不经闸门。下行大负载走自动分流(TCP 块 + 引用命令)。 流场基底同步:SendLockstepCommandToClients_RebuildFlowField 导出 + 服务器自导入 + 经 SendLockstepDataCommandToClients 广播 FF.RebuildFlowField TCP 块(全量或差分);动态 navmesh 重建经 OnNavDataGenerationFinished 自动重导出;版本脱节的端经 ServerRequestFlowFieldFullResync → HandleFlowFieldFullResyncRequest 请求全量自愈(MassBattleNetworkPlayerControllerBase.cpp:137、MassBattleNetworkGameStateBase.cpp:1101);失步取证模糊器经 EnqueueAuthorityCommandForFuzz 直通入队(MassBattleDesyncAutoDebugger.cpp:309)。 组件驱动生成:服务器端 AgentComponent BeginPlay 自注册(AgentComponent.cpp:133)→ ProcessPendingLockstepSpawns 每 tick 冲刷(无此步骤则无任何锁步 agent 生成 → 0 实体 → hash=0 + 空快照);resync 完成经 OnClientResyncComplete → FlushDeferredLockstepSpawnsForOwner 快照优先触发。 快照派发:resync 请求经 HandleClientResyncRequest / ProcessPendingLateJoinSnapshots 在 post-command 边界以 DispatchSnapshotViaTcp_Async(后台线程序列化+压缩,弹回游戏线程非阻塞发送)经 FMassBattleSnapshotTcpTransport::SendSnapshot 下发,成功与否经 OnClientResyncResult(H2 派发匹配闸)汇聚。 块汇聚:客户端上行 TCP 块经 transport 回调暂存(NetworkSubsystem.cpp:177),ConvergeUplinkBlock 把 LocalBlockId 重映射为 ServerBlockId 后回广播。

The server-side lockstep network hub, driven each tick by UMassBattleSubsystem via OnTickCompleted → OnSimTickCompleted (bound at GameModeBase.cpp:152; implementation lines 185-383). Command flow: client uplink Server_SendNetCommand → ReceivePlayerCommand (client command gate + quota/queue caps/schedule clamps + K-buffer scheduling) → PendingCommands → sorted at flush ticks → MulticastCommandToClients broadcast; server self-driven commands call SendLockstepCommandToClients directly (e.g. AgentComponent.Spawn at MassBattleAgentComponent.cpp:1104, MassBattleProjectileComponent.cpp:646, MassBattleLootComponent.cpp:745, Obstacle.Spawn at MassBattleObstSubsystem.cpp:485, plus the Despawn variants), never passing the gate. Large downlink payloads use the auto-flood path (TCP block + reference command). Flow-field substrate sync: SendLockstepCommandToClients_RebuildFlowField exports + server self-imports + broadcasts the FF.RebuildFlowField TCP block (full or delta) via SendLockstepDataCommandToClients; dynamic-navmesh rebuilds re-export automatically via OnNavDataGenerationFinished; a peer whose version missed a delta's base self-heals via ServerRequestFlowFieldFullResync → HandleFlowFieldFullResyncRequest (MassBattleNetworkPlayerControllerBase.cpp:137, MassBattleNetworkGameStateBase.cpp:1101); the auto-forensics fuzzer enqueues directly via EnqueueAuthorityCommandForFuzz (MassBattleDesyncAutoDebugger.cpp:309). Component-driven spawn: the server-side AgentComponent self-registers on BeginPlay (AgentComponent.cpp:133) → ProcessPendingLockstepSpawns flushes every tick (without it no lockstep agent ever spawns → 0 entities → hash=0 + empty snapshots); on resync completion, OnClientResyncComplete → FlushDeferredLockstepSpawnsForOwner fires spawns snapshot-first. Snapshot dispatch: resync requests flow through HandleClientResyncRequest / ProcessPendingLateJoinSnapshots at the post-command boundary, dispatched via DispatchSnapshotViaTcp_Async (background-thread serialize+compress, bounce back to the game thread for non-blocking send) through FMassBattleSnapshotTcpTransport::SendSnapshot; outcomes converge on OnClientResyncResult (the H2 dispatch-match gate). Block convergence: client-uplink TCP blocks are staged by the transport callback (NetworkSubsystem.cpp:177); ConvergeUplinkBlock remaps LocalBlockId → ServerBlockId and rebroadcasts.