MassBattle Docsv1.19.20

MassBattleSnapshotRegistry.h

Source/MassBattle/Public/Network/MassBattleSnapshotRegistry.h

概述 Overview

宏注册表头文件(无 .cpp):以 MB_FOR_EACH_* 系列宏集中声明哪些 fragment、哪些字段、哪些 tag 参与 NetworkSnapshot(快照捕获/恢复)与逐实体 hash(失步检测)。GetOrBuildSnapshotLayout、GetFragmentPtrByName、tag delta 捕获/应用、GetOrBuildHashLayout 等消费点统一展开这些宏——单一来源:新增快照字段/快照 fragment/快照 tag/hash 字段只需在对应 SYNC(...) 行添加,所有消费点自动同步。宏无运行时成本(全部在编译期展开为代码)。文件末尾的 MassBattleFieldAudit 命名空间把全部注册表展开为运行时映射(FRegistryMaps),供编辑器字段注册审计使用(见下方「字段注册审计」)。

A macro-registry header (no .cpp): the MB_FOR_EACH_* family of macros centrally declares which fragments, fields, and tags participate in NetworkSnapshot (capture/restore) and the per-entity hash (desync detection). Consumers such as GetOrBuildSnapshotLayout, GetFragmentPtrByName, tag-delta capture/apply, and GetOrBuildHashLayout expand these macros — a single source: adding a snapshot field/fragment/tag or hash field means editing one SYNC(...) line and every consumer stays in sync. The macros cost nothing at runtime (they expand to code at compile time). The MassBattleFieldAudit namespace at the end of the file expands every registry into runtime maps (FRegistryMaps) for the editor field-registration audit (see "Field-Registration Audit" below).

快照注册表 Snapshot Registry

每个 SYNC 行 = 一个 fragment + 其快照字段。字段顺序即快照布局顺序(注册表驱动,双端同一代码)。Query 字段(FMassBattleQuery/FEntityQuery)走 QueryStruct 策略:仅序列化 UPROPERTY 配置数组(All/Any/None/Priority/Flags/Obstacle),私有 lazy 缓存不同步,恢复端 MarkCacheDirty() 按需重建。

Each SYNC line = one fragment plus its snapshot fields. Field order IS the snapshot layout order (registry-driven, identical code on both peers). Query fields (FMassBattleQuery/FEntityQuery) follow the QueryStruct policy: only the UPROPERTY config arrays (All/Any/None/Priority/Flags/Obstacle) are serialized; private lazy caches are not synced and the restore side calls MarkCacheDirty() to rebuild on demand.

MB_FOR_EACH_SNAPSHOT_AGENT_FRAGMENT

Agent fragment 注册表——驱动 agent 网络查询与捕获。不变量:每个 agent fragment 必须存在于所有 agent archetype——统一网络查询将其注册为 Optional,Agent 分支对其无守卫索引;缺失会 fail-loud(空视图越界),而非静默掉出网络同步。每个 SYNC 行须 ≥1 字段(MB_SNAP_LAYOUT 对零字段 checkf 失败)。2026-08-24 起各 agent 配置 fragment 的 bEnable 功能开关(及 FPatrol.Origin / FReinforce.CommandCenter / FTrace.Query / FGather.LootQuery)入册——运行时(玩法/指令)切换的模拟状态须在快照重建后存活(FReturn.bEnable 先例);FAvoidance.bUseTrafficRules 为交通层全局总闸,关闭时所有规则被旁路,同理须随恢复存活。FNavigation.FlowFieldToUse 为配置片段上运行时指派的流场软引用(恢复侧重解析读取,先例 FLootParamsRT.FlowFieldSoftPtr)。

Agent fragment registry — drives the agent network query and capture. Invariant: every agent fragment MUST exist on all agent archetypes — the unified network query registers them Optional and the Agent branch indexes unguarded; a missing fragment fails loud (empty-view indexing) instead of silently dropping entities out of network sync. Every SYNC line needs ≥1 field (MB_SNAP_LAYOUT checkf-fails on a zero-field fragment). Since 2026-08-24 the agent config fragments' bEnable switches (plus FPatrol.Origin / FReinforce.CommandCenter / FTrace.Query / FGather.LootQuery) are registered — runtime (gameplay/command) toggles must survive snapshot rebuild (FReturn.bEnable precedent); FAvoidance.bUseTrafficRules is the traffic-layer global gate (when false EVERY rule is bypassed) and must survive restore for the same reason. FNavigation.FlowFieldToUse is the runtime-assigned flow-field soft ref on the config fragment (the restore-side re-resolve reads it; soft-path precedent FLootParamsRT.FlowFieldSoftPtr).

Fragment快照字段 Snapshot fields
FSubTypeIndex, PreviousIndex
FTeamindex, PreviousIndex
FDeterminismUniqueID, RandomStream
FAgentControllerControlMode, OwningPlayerSlot, LockstepNetID
FAgentControllingPreviousControlMode
FHealthCurrent, Maximum, bLockHealth
FHealthBarTargetRatio, CurrentRatio, Opacity
FStatisticsbEnable, CreditToEntity, TotalDamage, TotalKills, TotalScore, TotalTime, SelfScore, PlayerID, PlayerName
FLocatingLocation, PreLocation, InitialLocation
FRotatingRotation, Direction, RotationQuat, DesiredRotationQuat
FScalingScale, JiggleMultiplier
FTracingTraceResult, LockedTarget, TimeLeft, bInitDelayApplied, bLostTargetRetraceTriggered, bChaseAttackInterruptible, ActiveChaseAttackTaskID, LastKnownTargetLocation
FAnimatingLevel1State, Level2State, Level3State, AnimBlendResult, AnimState, PreviousAnimState, CurrentAnimBlendLevel, SelectedIdleAnimIndex, SelectedMoveAnimIndex, SelectedFallAnimIndex, SelectedAppearAnimIndex, SelectedAttackAnimIndex, SelectedHitAnimIndex, SelectedDeathAnimIndex, SelectedMontageAnimIndex, MontagePlayRate, bMontageLooping, HitGlow, Dissolve, IceFx, FireFx, PoisonFx, IceFxInterped, FireFxInterped, PoisonFxInterped, IdleRandomStartFrame, MoveRandomStartFrame
FMovingCurrentVelocity, DesiredVelocity, PendingInputVector, LastInputVector, CurrentAngularVelocity, SteeringAngle, Goal, MoveState, ActiveMoveToTaskID, LaunchVelSum, PushBackSpeedOverride, FlyingHeight, MoveSpeedMult, TurnSpeedMult, CurrentTilt, CachedGroundNormal, CachedGroundZ, LaunchingTimeLeft, FallingTimer, SceneSweepTimer, AverageSpeed, bMovingToGoal, bPreviouslyInAcceptanceRadius, bCachedHitGround, bHasRecentSceneHit, bCachedSupportedByCollision, bCachedTouchingObst, bCachedIsAvoidingObst, bCachedLocalDisturbance, bCachedSideStepObligation, bAlignReverseActive, bMoveToLocked, bMoveToSuspended, bMoveInputIgnored, bComponentDrivenPosition, bStopActiveMovement, bCachedCollidedAgent, RotationalResistance
FAvoidingCurrentVelocity, DesiredVelocity, AvoidingVelocity, MaxSpeed, AvoidRadius, bCanAvoid
FNavigatingPathPoints, TimeLeft, CurrentPathIndex, LastFlowFieldDirection, ChangeDirectionTimeLeft, PathReactionTimeLeft, PreviousNavMode, RequestedNavMode, bIsPathPatched, LastSampledCellsHash, FlowFieldLayerHandle
FNavigationFlowFieldToUse
FBehavingActiveBehavior, RequestedBehavior, bHasSwitchRequest
FMovebEnable
FChasebEnable
FAttackbEnable
FAppearbEnable
FDeathbEnable
FDefencebEnable
FSleepbEnable
FPatrolbEnable, Origin
FReinforcebEnable, CommandCenter
FReturnbEnable
FTracebEnable, Query
FGatherbEnable, LootQuery
FAvoidancebEnable, bUseTrafficRules
FSelectbEnable
FDebuffbEnable
FAgentEventbEnable
FPatrollingMoveTimeLeft, WaitTimeLeft
FReinforcingCurrentReinforceTarget, bHasEverHadTarget, TargetEntries, StuckTimer, LastDistToTarget, LastPathIndex, LastDistToPathPointSq
FReturningElapsedTime, bJustFinished, SpaceGateCooldown, bGoalBlocked, bGoalCoveredByGather, OscillationWindowLeft, CarriedGateTime, bPendingFailReset, RolledInitDelay
FAttackingAimTime, ATKTime, CoolTime, State, bAimFailed
FAppearingbInitialized, bStarted, Time, AnimTime, DissolveTime
FBeingHitGlowTime, JiggleTime, AnimTime, HealthBarTimer, GlowCooldownTimer, AnimCooldownTimer
FDyingbInitialized, bIsSuicide, Duration, Time, DeathDissolveTime, DeathAnimTime, Instigator, HitDirection, DisableCollisionWithAgentTimer
FGatheringCurrentTargets, DetectionCooldownTimeLeft
FDamageDamage, Query
FDebuffingTemporalDmgCausers, SlowCausers, CombinedSlowMult
MB_FOR_EACH_SNAPSHOT_DEBUFF_FRAGMENT

Debuff fragment 注册表。debuff 实体是独立 archetype——切勿加入 agent 注册表:Agent 分支生成的视图/捕获会在 agent 上索引这些 fragment(debuff fragment 在 agent 上不存在 → 空视图 fail-loud)。Debuff 分支经自己的视图读取。

Debuff fragment registry. Debuff entities are separate archetypes — never add these to the agent registry: the Agent branch's generated views/capture would index them on agents (where they don't exist → empty-view fail-loud). The Debuff branch reads them through its own views.

Fragment快照字段 Snapshot fields
FSlowDebuffSlowTarget, SlowTimeout, SlowStrength, DmgType, bJustSpawned, UniqueID
FTemporalDmgDebuffTemporalDmgInstigator, TemporalDmgTarget, TotalTemporalDmg, RemainingTemporalDmg, CurrentSegment, TemporalDmgSegment, TemporalDmgTimeout, TemporalDmgInterval, DmgType, bJustSpawned, UniqueID
MB_FOR_EACH_SNAPSHOT_FX_FRAGMENT

FX 宿主/FX 实体 fragment 注册表,仅经下方并集供 layout/恢复消费——捕获按 FX 查询手写(同 debuff)。FLocating/FRotating/FScaling/FSubType/FDeterminism 已在 agent 注册表(布局共用)。排除(渲染/音频运行时状态,不入快照):NiagaraAsset/CascadeAsset 硬指针(SoftPath 恢复)、组件指针/数组、位域/渲染态。池状态(bIsPooled/PoolCountdown)进注册表——池是锁步确定性状态,池分歧=bug 必须被检测。

FX host / FX entity fragment registry, consumed via the UNION below by layout/restore only — capture is hand-written per FX query (like debuff). FLocating/FRotating/FScaling/FSubType/FDeterminism already live in the agent registry (shared layouts). Excluded (per-instance render/audio state, never in snapshot): NiagaraAsset/CascadeAsset hard pointers (SoftPath restores them), component pointers/arrays, bitfields/render state. Pool state (bIsPooled/PoolCountdown) IS in the registry — pools are lockstep-deterministic state; a pool divergence is a bug and must be detected.

Fragment快照字段 Snapshot fields
FFxConfig_FinalbEnable, SubType_Index, StyleType_Index, SoftNiagaraAsset, SoftCascadeAsset, Transform, bAttached, SpawnOrigin, Delay, LifeSpan, BindToAnimIndex, bDespawnWhenNoParent, SpawnProbability, AgentBehaviorState, InterpMode, bLockstepNetworked, RandomStream, OwnerEntity, AttachToEntity, SpawnTransform, InitialRelativeTransform, bInitialized, bSpawned, LaunchSpeed, bShouldDestroy, PairedFxEntity, bIsPooled, PoolCountdown, SpawnEventParentTransform, SpawnEventWorldTransform
FHostHierarchyAttachmentEntity, ParentHost, FirstChildHost, NextSiblingHost, PrevSiblingHost, AttachmentSource, ResolvedWorldTransform, ResolvedLinearVelocity, ResolvedAngularVelocity, ResolvedInterpParams, ResolvedWorldScale
FFxVisualizingUniqueID, ParentEntity, RelativeTransform, FxScale, ParentGTLoc, ParentGTRot, ParentVel, ParentAngularVelocity, ParentInterpParams, ParentGTScale, CachedWorldLocation, CachedWorldRotation, CachedWorldScale, bCpuInterpMode, EventParentLoc, EventParentRot, EventWorldLoc, EventWorldRot, bHasEventAnchor
FStyleTypeIndex
MB_FOR_EACH_SNAPSHOT_PROJECTILE_FRAGMENT

Projectile 实体(非 host)+ ProjectileHost fragment 注册表。捕获按移动变种子查询手写(Static/Interped/Ballistic/Tracking 四子查询,互斥);伤害/减益变种不进查询(同样互斥),捕获走 per-chunk DoesArchetypeHaveFragment + 逐实体 GetFragmentPtr。Query 字段经 QueryStruct 策略序列化。排除:事件/渲染/硬缓存/模板。池状态进注册表。注意:FProjectileVisualizing.CachedVelocity/AngularVelocity 为 sim 写(ProjectileMonoProcessor)/宿主解析读(HostMonoProcessor)——非纯渲染,恢复保证宿主 hier 一致;不入 hash(渲染目标字段不进折叠)。

Projectile entity (non-host) + ProjectileHost fragment registry. Capture is hand-written per moving-variant query (4 sub-queries: Static/Interped/Ballistic/Tracking — mutually exclusive); damage/debuff variants stay out of the queries (also mutually exclusive) and are captured via per-chunk DoesArchetypeHaveFragment + per-entity GetFragmentPtr. Query fields serialize via the QueryStruct policy. Excluded: events/render/hard caches/templates. Pool state is in the registry. Note: FProjectileVisualizing.CachedVelocity/AngularVelocity are SIM-written (ProjectileMonoProcessor) and SIM-read by the host hierarchy resolve (HostMonoProcessor) — not render-only; restored for host-hier parity; not in the hash (render-target fields stay out of the fold).

Fragment快照字段 Snapshot fields
FProjectileConfig_FinalbEnable, ProjectileConfigDataAsset, Multipliers, Transform, bAttached, SpawnOrigin, Delay, BindToAnimIndex, InheritFromInstigator, bDespawnWhenNoParent, SpawnProbability, AgentBehaviorState, RandomStream, OwnerEntity, AttachToEntity, TargetEntity, SpawnTransform, InitialRelativeTransform, FromPoint, ToPoint, TargetVelocity, bInitialized, bSpawned, bShouldDestroy, SpawnedProjectile, bIsPooled, PoolCountdown
FProjectileParamsLifeSpan, Health, Query
FProjectileParamsRTInstigator, IgnoreEntities, DmgCoolDownTimeLeft, PoolDataAsset, bBornFired, PoolCountdown
FProjectileVisualizingCachedVelocity, AngularVelocity
FProjectileMoving_InterpedFromPoint, ToPoint, Target, TargetOffset, BirthTime, XOffsetMult, YOffsetMult, ZOffsetMult
FProjectileMoving_BallisticFromPoint, ToPoint, InitialVelocity, BirthTime
FProjectileMoving_TrackingFromPoint, ToPoint, Target, TargetOffset, FlightDirection, CurrentSpeed, bHasValidTarget
FDamage_PointDmgType, Damage, PercentDmg, CritDmgMult, CritProbability, Query
FDamage_RadialDmgType, Damage, PercentDmg, CritDmgMult, CritProbability, DmgRadius, bUseFalloff, bCheckObstacle, Query
FDamage_BeamDmgType, Damage, PercentDmg, CritDmgMult, CritProbability, DmgRadius, BeamLength, BeamRelativeLocation, BeamRelativeRotation, bRotationFollowProjectile, bUseFalloff, bCheckObstacle, Query
FDebuff_PointbEnable, LaunchParams, TemporalDmgParams, SlowParams
FDebuff_RadialbEnable, bUseFalloff, LaunchParams, TemporalDmgParams, SlowParams
FDebuff_BeambEnable, bUseFalloff, LaunchParams, TemporalDmgParams, SlowParams
MB_FOR_EACH_SNAPSHOT_LOOT_FRAGMENT

Loot 实体(非 host)+ LootHost fragment 注册表。捕获按移动变种子查询手写(Ballistic/InterpedSpawn 两子查询,互斥;FLootMoving_Interped_Gather 恒在 → 属公共折叠)。FLootGridData 为每 tick 全量重建的派生数据——绝不注册。config/事件/渲染/生成内容由模板提供。FLootVisualizing 与弹丸同款 sim 读取修复(恢复保证宿主 hier 一致)。

Loot entity (non-host) + LootHost fragment registry. Capture is hand-written per moving-variant query (2 sub-queries: Ballistic/InterpedSpawn — mutually exclusive; FLootMoving_Interped_Gather is ALWAYS present → part of the common fold). FLootGridData is derived data rebuilt fully every tick — never registered. Config/event/render/spawn content is provided by the template. FLootVisualizing mirrors the projectile fix (restored for host-hier parity).

Fragment快照字段 Snapshot fields
FLootParamsLifeSpan, ScoreValue
FLootParamsRTSpawner, Collector, State, CollectDelayTimeLeft, FlowFieldSoftPtr, PoolDataAsset, bBornFired, PoolCountdown
FLootVisualizingCachedVelocity, AngularVelocity
FLootMoving_BallisticVelocity, BirthTime, bHasSettled
FLootMoving_Interped_SpawnFromPoint, ToPoint, Target, StartTime, OffsetMultipliers, InitialDistance, LerpProgress
FLootMoving_Interped_GatherFromPoint, ToPoint, Target, StartTime, OffsetMultipliers, InitialDistance, LerpProgress
FLootConfig_FinalbEnable, LootConfigDataAsset, Multipliers, Transform, InitialRelativeTransform, SpawnOrigin, bAttached, bDespawnWhenNoParent, Delay, SpawnProbability, AgentBehaviorState, InheritFromSpawner, RandomStream, OwnerEntity, AttachToEntity, SpawnTransform, FromPoint, FlowFieldSoftPtr, bInitialized, bSpawned, bShouldDestroy, SpawnedLoot, bIsPooled, PoolCountdown
MB_FOR_EACH_SNAPSHOT_INDEPENDENTHOST_FRAGMENT

ActorHost / SoundHost / AgentHost——无配对实体的独立宿主。UObject(AActor / UAudioComponent)绝不进快照——经 bNeedsSpawnRefresh(重发生成 op)恢复;软引用(SoftPath)+ 硬缓存(RuntimeObjectByPath)都进——op 预检在 miss 时重新加载硬缓存。排除:UObject 指针/瞬态。池状态进注册表。

ActorHost / SoundHost / AgentHost — standalone hosts with no paired entity. UObjects (AActor / UAudioComponent) never enter the snapshot — restored via bNeedsSpawnRefresh (re-issue the spawn op); soft refs (SoftPath) plus hard caches (RuntimeObjectByPath) are both in — the op pre-scan reloads the hard cache on miss. Excluded: UObject pointers / transient. Pool state is in the registry.

Fragment快照字段 Snapshot fields
FActorSpawnConfig_FinalbEnable, SoftActorClass, ActorClass, Transform, bAttached, SpawnOrigin, Delay, LifeSpan, BindToAnimIndex, bDespawnWhenNoParent, SpawnProbability, AgentBehaviorState, bLockstepNetworked, RandomStream, OwnerEntity, HostEntity, AttachToEntity, SpawnTransform, InitialRelativeTransform, bInitialized, bSpawned, bShouldDestroy, bIsPooled, PoolCountdown
FSoundConfig_FinalbEnable, SoftSound, Sound, Transform, bAttached, SpawnOrigin, Delay, Volume, LifeSpan, RadiusThreshold, BindToAnimIndex, bDespawnWhenNoParent, SpawnProbability, AgentBehaviorState, Concurrency, bLockstepNetworked, ConcurrencyStartTime, RandomStream, OwnerEntity, AttachToEntity, SpawnTransform, InitialRelativeTransform, bInitialized, bSpawned, bShouldDestroy, bIsPooled, PoolCountdown
FAgentHostConfig_FinalbEnable, Transform, bAttached, bDespawnWhenNoParent, OwnerEntity, HostEntity, AttachToEntity, AgentToAttach, SpawnTransform, InitialRelativeTransform, bInitialized, bSpawned, bShouldDestroy, bIsPooled, PoolCountdown
MB_FOR_EACH_SNAPSHOT_OBSTACLE_COMMON / _BOX / _CAPSULE / _SPLINE_FRAGMENT

快照障碍物 fragment 注册表(四个宏)。命令路由障碍物复刻 agent 模式:FNetworkTag + FNetworking.Key + 合成模板键(如 ObstacleTemplates/Box.CmdRouted,仅定原型——几何在片段里)——捕获进快照 blob,经非 agent 分支恢复,由 RebindAllCommandRoutedObstacles 重绑(FObstacleNetBinding 联结)。三类障碍物为互斥原型——三个按类型组;ObstacleBlock 按 chunk 的网格数据片段子分派。FObstacleNetBinding/FLocating/FRotating/FDeterminism 沿用 agent 行的共享布局——ObstacleBlock 手写捕获(FX 先例),不在本组重复列出。排除:FBoxObstacle/FCapsuleObstacle(BoundComponent 指针不可序列化;bStatic/bRegistered 由合成模板默认值提供)、RelativeLocation(每格派生,实体上恒默认)、EntityHandle(经 FDeterminism.UniqueID 重注册恢复)。

Snapshot OBSTACLE fragment registries (four macros). Command-routed obstacles replicate the agent pattern: FNetworkTag + FNetworking.Key + synthetic template keys (e.g. ObstacleTemplates/Box.CmdRouted, archetype-only — geometry lives in fragments) — captured into the snapshot blob, restored via the non-agent branch, re-bound by RebindAllCommandRoutedObstacles (the FObstacleNetBinding join). The three obstacle types are disjoint archetypes — three per-type groups; ObstacleBlock sub-branches per chunk by its grid-data fragment. FObstacleNetBinding/FLocating/FRotating/FDeterminism reuse the AGENT rows' shared layouts — hand-captured in ObstacleBlock (FX precedent), NOT re-listed here. Excluded: FBoxObstacle/FCapsuleObstacle (BoundComponent pointer non-serializable; bStatic/bRegistered provided by synthetic template defaults), RelativeLocation (per-cell derived, always default on the entity), EntityHandle (restored via FDeterminism.UniqueID re-registration).

Fragment快照字段 Snapshot fields
FObstacleNetBinding (common)LockstepNetID, ComponentPath
FBoxObstGridData (box)HalfExtents, Orientation, Center2D, Velocity, UniqueID, bStatic, bActivated, bOverrideSpeedLimit, bInsideOut, bForceHybridFF
FCapsuleObstGridData (capsule)UpVector, Velocity, UniqueID, Radius, HalfHeight, bCanAvoid, bStatic, bActivated, bOverrideSpeedLimit, bIsCylinder, bForceHybridFF
FCollider (capsule)Radius, Height
FSegmentObstGridData (spline)GroupID, Velocity, center, point, nextPoint, unitDir, nextUnitDir, pointZ, height, isConvex_, bStatic, bActivated, bOverrideSpeedLimit, bForceHybridFF, Index
FSplineObstacle (spline)LocalSamplePoints, WorldBaseLoc, WorldBaseRot, bFlipDirection
MB_FOR_EACH_SNAPSHOT_FRAGMENT_A / _B / 全量并集

并集拆分:_A = agent + debuff;_B = FX + projectile + loot + independent host + obstacle(四个障碍物组);MB_FOR_EACH_SNAPSHOT_FRAGMENT = 两者之和,供 GetFragmentPtrByName / GetOrBuildSnapshotLayout / PreBuildSnapshotLayoutCache 消费。_A/_B 拆半仅用于把 GetOrBuildSnapshotLayout 的分发函数体拆到 MSVC C4883(函数过大)限制以内——完整并集仍是其它所有消费点的单一来源。

Union split: _A = agent + debuff; _B = FX + projectile + loot + independent host + obstacle (the four obstacle groups); MB_FOR_EACH_SNAPSHOT_FRAGMENT = both, consumed by GetFragmentPtrByName / GetOrBuildSnapshotLayout / PreBuildSnapshotLayoutCache. The _A/_B halves exist ONLY to split GetOrBuildSnapshotLayout's dispatch body under MSVC's C4883 (function-too-large) limit — the full UNION stays the single source for every other consumer.

MB_FOR_EACH_SNAPSHOT_SHARED_FRAGMENT

Shared fragment 注册表(初始为空):shared fragment 为 per-chunk;按实体捕获到 RuntimeOverlay.SharedFragmentBlobs,在 BuildEntity 前经 SetSharedFragment 恢复到模板(写时复制 + 按值去重)。字段策略由 GetSnapshotFieldPolicy 自动判定;注意 FTracingShared 含 per-client 玩家上下文,不可跨端同步。需要覆盖时在此添加 SYNC 行。

Shared fragment registry (starts EMPTY): shared fragments are per-chunk; captured per-entity into RuntimeOverlay.SharedFragmentBlobs, restored into the template BEFORE BuildEntity via SetSharedFragment (copy-on-write + value dedup). Field policies are auto-detected by GetSnapshotFieldPolicy; CAUTION: FTracingShared holds per-client player context — never snapshot it across peers. Add SYNC lines here when a shared fragment needs snapshot coverage.

MB_FOR_EACH_SNAPSHOT_TAG

快照 tag 注册表:所有快照 tag 列在单行 SYNC(...) 中,位索引按位置自动分配(0,1,2,...)。当前:FAppearingTag, FDyingTag, FDestroyingTag——对应 FEntitySnapshotRecord.TagDelta 的 bit0/bit1/bit2。

Snapshot tag registry: all snapshot tags live in a single SYNC(...) line; bit indices are auto-assigned by position (0,1,2,...). Currently: FAppearingTag, FDyingTag, FDestroyingTag — mapping to bit0/bit1/bit2 of FEntitySnapshotRecord.TagDelta.

Hash 注册表 Hash Registry

每个 SYNC 行 = 折叠进逐实体 hash 的一个 fragment + 字段。字段增减改变所有 hash 值——双端必须跑同一代码(锁步)。支持类型由 GetHashFieldPolicy 自动判定:数值标量、float/double 结构(递归)、FRandomStream(经 GetCurrentSeed)、FEntityHandle(→ 目标 UniqueID);字符串/数组/对象暂不支持 → dev checkf。字段顺序即折叠顺序(注册表驱动,双站点一致)。任何 float/double 字段(标量或结构叶)都经共享规范化折叠:-0.0 → 0.0 且反规格化数(|V| < FLT_MIN/DBL_MIN)→ 0.0——穿零积分器(倾摆/EMA/摩擦)会途经反规格化数区,每进程 FP 环境(FTZ/DAZ)可能一端写 -0.0、另一端保留反规格化数;禁止添加绕过此规则的折叠路径。

Each SYNC line = one fragment plus the fields folded into the per-entity hash. Adding/removing a field changes every hash value — both peers must run identical code (lockstep). Supported types are auto-classified by GetHashFieldPolicy: numeric scalars, float/double structs (recursion ok), FRandomStream (hashed via GetCurrentSeed), FEntityHandle (→ target UniqueID); strings/arrays/objects are not yet supported → dev checkf. Field order IS the fold order (registry-driven, both sites identical). EVERY float/double field — scalar or struct-leaf — folds through the shared canonicalization: -0.0 → 0.0 AND subnormals (|V| < FLT_MIN/DBL_MIN) → 0.0 — integrators that converge THROUGH zero (tilt/EMA/friction) pass through subnormal land where the per-process FP environment (FTZ/DAZ) may write -0.0 on one peer and a denormal on the other; do NOT add a fold path that bypasses this rule.

MB_FOR_EACH_HASH_AGENT_FRAGMENT

Agent hash 注册表。不变量:每个 fragment 必须同时在 agent 快照注册表中(需有 V_##T 视图;不在 agent 查询中的 fragment → MB_HASH_ONE 编译错,fail loud)。2026-09-11 行为层哈希扩展:FMoving 从 (CurrentVelocity, Goal) 两字段扩到全生命周期集——MoveState/挂起/锁/任务所有权/均速/地面缓存的分叉此前要等泄漏进速度才可见;字段镜像快照表(纯标量+位域)。FNavigating 行整体入册,PathFingerprint 经写位维护(重算/补丁/清除写位 + 恢复钩子重算)重新纳入哈希,逐 tick 共识刷新仍禁用(成本);快照行不变。FTracing 增补 LastKnownTargetLocation(追击目标位置缓存——仅 TraceResult 对该缓存是盲区)。行为层 FBehaving/FAttacking/FReturning/FAnimating 此前仅快照——攻击层已被实验证明是失步的必要成分。

Agent hash registry. Invariant: every fragment must also be in the agent snapshot registry (needs a V_##T view; a fragment not in the agent query → MB_HASH_ONE compile error, fail loud). 2026-09-11 behavior-layer hash extension: FMoving grew from (CurrentVelocity, Goal) to the full lifecycle set — forks in MoveState/suspend/lock flags/task ownership/AverageSpeed/cached ground state were hash-invisible until they leaked into velocity; fields mirror the snapshot list (scalars + bitfields only). The FNavigating row joins as a whole, with PathFingerprint re-admitted via write-site maintenance (recalc/patch/clear sites + restore-hook recompute) while the per-tick consensus refresh stays disabled (cost); the snapshot row is unchanged. FTracing gains LastKnownTargetLocation (the chase-goal position cache — TraceResult alone left it fork-blind). The behavior stratum FBehaving/FAttacking/FReturning/FAnimating was previously snapshot-only — the attack layer was proven a necessary ingredient of the divergence.

FragmentHash 字段 Hash fields
FScalingScale
FLocatingLocation
FRotatingRotationQuat
FMovingCurrentVelocity, DesiredVelocity, PendingInputVector, LastInputVector, CurrentAngularVelocity, SteeringAngle, Goal, MoveState, ActiveMoveToTaskID, LaunchVelSum, PushBackSpeedOverride, FlyingHeight, MoveSpeedMult, TurnSpeedMult, CurrentTilt, CachedGroundZ, LaunchingTimeLeft, FallingTimer, SceneSweepTimer, AverageSpeed, bMovingToGoal, bPreviouslyInAcceptanceRadius, bCachedHitGround, bHasRecentSceneHit, bCachedSupportedByCollision, bCachedTouchingObst, bCachedIsAvoidingObst, bCachedLocalDisturbance, bCachedSideStepObligation, bAlignReverseActive, bMoveToLocked, bMoveToSuspended, bMoveInputIgnored, bComponentDrivenPosition, bStopActiveMovement, bCachedCollidedAgent, RotationalResistance
FNavigatingCurrentPathIndex, TimeLeft, ChangeDirectionTimeLeft, PathReactionTimeLeft, LastFlowFieldDirection, LastSampledCellsHash, PreviousNavMode, RequestedNavMode, FlowFieldLayerHandle, bIsPathPatched, PathFingerprint
FTracingTraceResult, LastKnownTargetLocation
FDeterminismUniqueID, RandomStream
FBehavingActiveBehavior, RequestedBehavior, bHasSwitchRequest
FAttackingAimTime, ATKTime, CoolTime, State, bAimFailed
FReturningElapsedTime, bJustFinished, SpaceGateCooldown, bGoalBlocked, bGoalCoveredByGather, OscillationWindowLeft, CarriedGateTime, bPendingFailReset, RolledInitDelay
FAnimatingSelectedAttackAnimIndex, SelectedHitAnimIndex, SelectedMontageAnimIndex, MontagePlayRate, bMontageLooping
MB_FOR_EACH_HASH_DEBUFF_FRAGMENT

Debuff hash 注册表。由 MB_HASH_DEBUFF_ONE(捕获)/ MB_HASH_DEBUFF_PTR(恢复校验)消费——对 _DebuffFrag 做 if constexpr 类型过滤,两个 debuff 查询各折叠自己的变种。fragment 必须同时在 debuff 快照注册表中。

Debuff hash registry. Consumed by MB_HASH_DEBUFF_ONE (capture) / MB_HASH_DEBUFF_PTR (restore-validate) — if-constexpr type-filtered on _DebuffFrag, so each of the two debuff queries folds only its own variant. Fragments must also be in the debuff snapshot registry.

FragmentHash 字段 Hash fields
FSlowDebuffSlowStrength, SlowTimeout, DmgType
FTemporalDmgDebuffRemainingTemporalDmg, TotalTemporalDmg, CurrentSegment, TemporalDmgSegment, TemporalDmgInterval, TemporalDmgTimeout, DmgType
MB_FOR_EACH_HASH_FXHOST_FRAGMENT / MB_FOR_EACH_HASH_FXENTITY_FRAGMENT

FxHost(FFxConfig_Final + FHostHierarchy + FDeterminism)与 FxEntity(FFxVisualizing + 变换/subtype fragment + FDeterminism)hash 注册表。FDeterminism 行必须与 agent hash 行逐字一致(HashLayoutCache 按 fragment 名缓存,先建先得)。FxHost 受 UMassBattleNetworkSubsystem::bEnableFxHash 门控(双端必须一致)。FxEntity 硬规则:渲染层写入永不进 hash——TickCpuInterp 每引擎帧以帧率相关 DeltaTime 写入的 Cached*/Parent* 系列与变换不入折叠(配对 FxHost 回收后 FxEntity 休眠,再捕获会折叠最后一次插值值——双端帧率不同即分歧)。渲染局部字段(InstanceId/RenderBatchId 等)不在快照注册表 → 重建后缺失 → 严禁折叠。

FxHost (FFxConfig_Final + FHostHierarchy + FDeterminism) and FxEntity (FFxVisualizing + transform/subtype fragments + FDeterminism) hash registries. The FDeterminism rows must stay VERBATIM-identical to the agent hash row (HashLayoutCache is keyed by fragment name, first build wins). FxHost is gated by UMassBattleNetworkSubsystem::bEnableFxHash (all peers must agree). FxEntity hard rule: render-layer writes never enter the hash — the Cached*/Parent* series and transforms written by TickCpuInterp with the frame-rate-dependent engine DeltaTime stay out of the fold (once the paired FxHost recycles, the FxEntity goes dormant and the next capture would fold the last interp value — differing per peer frame rate → interp-driven desync). Render-local fields (InstanceId/RenderBatchId etc.) are absent after rebuild → must NOT be folded.

FragmentHash 字段 Hash fields
FFxConfig_Final (host)bSpawned, bShouldDestroy, bIsPooled, PoolCountdown, SpawnTransform
FHostHierarchy (host)AttachmentEntity, ParentHost, FirstChildHost, AttachmentSource
FFxVisualizing (entity)RelativeTransform, FxScale
FDeterminism (both)UniqueID, RandomStream
MB_FOR_EACH_HASH_PROJECTILE_FRAGMENT / _VARIANT / _PROJECTILEHOST

Projectile 实体公共折叠(4 个移动变种查询 + 恢复共用);移动变种 fragment 在独立 VARIANT 组——仅布局构建消费(GetOrBuildHashLayout/PreBuildHashLayoutCache),折叠调用仍在折叠顺序末位手写(捕获块 + 恢复 if-else 链,见 NetworkProcessor),绝不被 MB_HASH_ONE/MB_HASH_PTR 消费(变种视图在其它 chunk 为空,且 MB_HASH_ONE 无空守卫)。BirthTime(SimulationTime 时间戳)有意不进 hash——运动计算只用差值(CurrentTime - BirthTime),时间戳本身不带分歧信号。IgnoreEntities(数组)/PoolDataAsset(对象)不可 hash → 排除。ProjectileHost 镜像 FXHOST 结构。

Projectile entity common fold (shared by all 4 moving-variant queries + restore); the moving-variant fragments live in the SEPARATE VARIANT group — layout-builder consumption only (GetOrBuildHashLayout/PreBuildHashLayoutCache); the fold CALLS stay hand-written LAST in the fold order (capture block + restore if-else chain — see NetworkProcessor), never consumed by MB_HASH_ONE/MB_HASH_PTR (variant views are empty on other chunks and MB_HASH_ONE has no null guard). BirthTime (SimulationTime stamp) is intentionally NOT hashed — movement math consumes only delta (CurrentTime - BirthTime), so the stamp itself carries no divergence signal. IgnoreEntities (array) / PoolDataAsset (object) are not hashable → excluded. ProjectileHost mirrors the FXHOST structure.

FragmentHash 字段 Hash fields
FProjectileParamsHealth
FProjectileParamsRTDmgCoolDownTimeLeft, PoolCountdown
FProjectileMoving_Interped (variant)FromPoint, ToPoint, Target, TargetOffset, XOffsetMult, YOffsetMult, ZOffsetMult
FProjectileMoving_Ballistic (variant)FromPoint, ToPoint, InitialVelocity
FProjectileMoving_Tracking (variant)FromPoint, ToPoint, Target, TargetOffset, FlightDirection, CurrentSpeed, bHasValidTarget
FProjectileConfig_Final (host)bSpawned, bShouldDestroy, bIsPooled, PoolCountdown, SpawnTransform
FHostHierarchy (host)AttachmentEntity, ParentHost, FirstChildHost, AttachmentSource
FDeterminism (common rows)UniqueID, RandomStream
MB_FOR_EACH_HASH_LOOT_FRAGMENT / _VARIANT / _LOOTHOST

Loot 实体公共折叠。FLootMoving_Interped_Gather 恒在 → 公共行;FLootMoving_Ballistic 与 _Interped_Spawn 互斥变种在独立 VARIANT 组(镜像 projectile 变种组)。StartTime/BirthTime 时间戳字段有意不进 hash——网络模式下 SimulationTime 乘法重算(TickCount × StepTime)、跨端位级一致,时间戳双端同值,不带分歧信号。LootHost 镜像 FXHOST 结构。

Loot entity common fold. FLootMoving_Interped_Gather is ALWAYS present → common row; FLootMoving_Ballistic vs _Interped_Spawn are mutually exclusive variants in the separate VARIANT group (mirrors the projectile variant group). StartTime/BirthTime timestamp fields are intentionally NOT hashed — in networked mode SimulationTime is multiply-rebased (TickCount × StepTime) and bit-identical across peers, so the stamps agree and carry no divergence signal. LootHost mirrors the FXHOST structure.

FragmentHash 字段 Hash fields
FLootParamsRTCollector, State, CollectDelayTimeLeft, PoolCountdown
FLootMoving_Interped_GatherFromPoint, ToPoint, Target, OffsetMultipliers, InitialDistance, LerpProgress
FLootMoving_Ballistic (variant)Velocity, bHasSettled
FLootMoving_Interped_Spawn (variant)FromPoint, ToPoint, Target, OffsetMultipliers, InitialDistance, LerpProgress
FLootConfig_Final (host)bSpawned, bShouldDestroy, bIsPooled, PoolCountdown, SpawnTransform
FHostHierarchy (host)AttachmentEntity, ParentHost, FirstChildHost, AttachmentSource
FDeterminism (common rows)UniqueID, RandomStream
MB_FOR_EACH_HASH_ACTORHOST / SOUNDHOST / AGENTHOST_FRAGMENT

独立宿主(ActorHost/SoundHost/AgentHost)hash 注册表,镜像 FXHOST 结构。资产引用排除(GetHashFieldPolicy → Unsupported);FHostHierarchy/FDeterminism 行逐字复制自 FXHOST(缓存按 fragment 名,先建先得)。

Independent host (ActorHost/SoundHost/AgentHost) hash registries, mirroring the FXHOST structure. Asset refs are excluded (GetHashFieldPolicy → Unsupported); FHostHierarchy/FDeterminism rows are VERBATIM-copied from FXHOST (cache keyed by fragment name, first build wins).

FragmentHash 字段 Hash fields
FActorSpawnConfig_Final / FSoundConfig_Final / FAgentHostConfig_FinalbSpawned, bShouldDestroy, bIsPooled, PoolCountdown, SpawnTransform
FHostHierarchyAttachmentEntity, ParentHost, FirstChildHost, AttachmentSource
FDeterminismUniqueID, RandomStream
MB_FOR_EACH_HASH_OBSTACLE_BOX / _CAPSULE / _SPLINE_FRAGMENT

Hash 障碍物注册表(三个宏)。命令路由障碍物纳入逐 tick 共识 hash——0 vs N 障碍集合分叉在生成当 tick 即报失步(而非等首次 agent 接触)。三个按类型组镜像快照组的互斥原型;共享行(FLocating/FRotating/FDeterminism)与 agent 行逐字一致(HashLayoutCache 按 fragment 名缓存,先建先得)。与其它非 agent 类别同受 bEnableFxHash 门控(捕获/恢复读同一标志)。位域标志字段按所在字节整字节 RawBytes 折叠——pad 位保持确定性零(位域初始化纪律)。

Hash OBSTACLE registries (three macros). Command-routed obstacles fold into the per-tick consensus hash — a 0-vs-N obstacle-set fork fails loud at the spawn tick (not at first agent contact). The three per-type groups mirror the snapshot groups' disjoint archetypes; shared rows (FLocating/FRotating/FDeterminism) are VERBATIM-identical to the agent rows (HashLayoutCache keyed by fragment name, first build wins). Gated by bEnableFxHash like the other non-agent categories (capture + restore read the same flag). Bitfield flag fields hash as RawBytes over the containing byte — pad bits stay deterministically zero (bitfield-init discipline).

FragmentHash 字段 Hash fields
FBoxObstGridDataHalfExtents, Center2D, bActivated, bInsideOut
FCapsuleObstGridDataRadius, HalfHeight, bActivated, bIsCylinder
FCollider (capsule)Radius, Height
FSegmentObstGridDatacenter, pointZ, height, bActivated
FSplineObstacleWorldBaseLoc, WorldBaseRot
FLocating / FRotating / FObstacleNetBinding / FDeterminism(各组公共行)FLocating / FRotating / FObstacleNetBinding / FDeterminism (common row of each group)Location / RotationQuat / LockstepNetID / UniqueID, RandomStream
MB_FOR_EACH_HASH_TAG

Hash tag 注册表:每行一个 tag 类型,存在性(0/1)在 fragment 折叠后折入逐实体 hash。不变量:① tag 必须同时在快照 tag 注册表——恢复端 TagDelta 已应用,重建实体的 HasTag 折叠才能与捕获端一致;不在快照里的 tag 重建后缺失 → 恢复 hash 不匹配 → 拒绝应用(fail loud);② 只放影响跨端模拟状态的 tag(Appearing/Dying/Destroying 门控生命周期逻辑),纯视觉 tag 严禁加入;③ 增减 tag 改变所有 per-tick hash。

Hash tag registry: one tag type per SYNC line; presence (0/1) folds into the per-entity hash after the fragments. Invariants: ① tags MUST also be in the snapshot tag registry — restore applies TagDelta, so the restore-side HasTag fold on the rebuilt entity matches capture; a tag absent from the snapshot is missing after rebuild → restore-hash mismatch → apply refused (fail loud); ② only tags that gate cross-peer simulation state belong here (Appearing/Dying/Destroying gate lifecycle logic); pure-visual tags must NOT; ③ adding/removing a tag changes every per-tick hash.

Tag说明 Description
FAppearingTag出现阶段(门控生命周期逻辑)。Appearing phase (gates lifecycle logic).
FDyingTag死亡阶段。Dying phase.
FDestroyingTag销毁阶段。Destroying phase.

字段注册审计 Field-Registration Audit

网络实体 fragment 上的每个 UPROPERTY 都处于三态之一:① 已注册——已 SYNC 进上方快照/hash 注册表;② 显式豁免——列入下方豁免清单并注明原因(有意的本地状态);③ 未注册——审计器会报告:整片段缺失(出现在网络实体上却不在任何注册表)与未注册字段的运行时变化(静默锁步失步)。审计器对导出值做影子比较;每(片段, 字段)每会话只报一次;首跑即分拣报告——按需充实下方豁免清单。 消费点:UMassBattleNetworkProcessor::AuditFieldRegistration(MassBattleNetworkProcessor.cpp)——仅编辑器(WITH_EDITOR,打包构建整体剔除)、仅网络模式,每 chunk 取一个代表实体串行扫描统一网络查询,受 UMassBattleNetworkSubsystem 的 bDisableFieldRegistrationAudit 门控、按 FieldAuditIntervalTicks 节流;只检测、绝不写片段(锁步中立)。 局限:仅覆盖 UPROPERTY(未反射成员注册表与审计都看不见);shared fragment 暂不遍历;出生期分叉(生成时默认值不同)不在范围内。

Every UPROPERTY on a networked entity's fragment is in one of three states: ① REGISTERED — SYNC'd into the snapshot and/or hash registry above; ② EXPLICITLY EXCLUDED — listed below WITH a reason (intentional local state); ③ UNREGISTERED — the audit reports BOTH whole fragments absent from the registries AND runtime CHANGES of unregistered fields (silent lockstep divergence). The audit shadow-compares exported values; one report per (fragment, field) per session; the first run doubles as a triage report — seed the exclusion lists below as needed. Consumer: UMassBattleNetworkProcessor::AuditFieldRegistration (MassBattleNetworkProcessor.cpp) — editor-only (WITH_EDITOR; packaged builds compile it out) and networked-mode only; a serial pass over the unified network query taking one representative entity per chunk, gated by bDisableFieldRegistrationAudit and throttled by FieldAuditIntervalTicks on UMassBattleNetworkSubsystem; detects but never heals (never writes fragments, lockstep-neutral). Limits: UPROPERTY-only (non-reflected members are invisible to BOTH the registry and the audit); shared fragments are not yet walked; birth-divergence (differing spawn-time defaults) is out of scope.

MB_FOR_EACH_SNAPSHOT_EXCLUDED_FRAGMENT

整片段有意豁免清单(逐片段注明原因)。

Whole-fragment intentional exclusions (each with its reason).

Fragment豁免原因 Exclusion reason
FBoxObstacle / FCapsuleObstacleBoundComponent 指针不可序列化;网格门控读已注册的 GridData.bStatic。BoundComponent pointer non-serializable; grid gates read the registered GridData.bStatic.
FLootGridData每 tick 由 RebuildLootGrid 全量重建的派生数据——绝不注册。Per-tick derived by RebuildLootGrid (reset + full rebuild) — NEVER registered.
FAgentDebug仅编辑器/调试可视化——非模拟状态。Editor/debug visualization only — never simulation state.
FEntityFlagFragment走专用记录头路径(Record.FlagsLow/FlagsHigh)而非 blob 注册表:两个裸 int64 直接拷贝更便宜,且恢复端需按位清零端侧本地渲染 flag(SnapshotStrippedRenderFlagsMask)——原样 blob 做不到。Captured by the DEDICATED record-header path (Record.FlagsLow/FlagsHigh), NOT the blob registry: two bare int64s copy cheaper than per-property policy, AND the restore side needs the per-bit SnapshotStrippedRenderFlagsMask wash the raw-copy blob path cannot express.
FMainType / FNetworking生成时模板值,经模板恢复——运行时无合法修改(若未来运行时改写,须先移出豁免并注册)。Spawn-time template values, restored via the template — no legitimate runtime modification (if a future feature mutates them at runtime, they must first move out of this list and be registered).
FCollider / FBehavior / FHit / FVisualize / FTextPop生成时数据资产配置,经模板恢复——无运行时可开关状态(区别于注册了 bEnable 的 FMove/FChase 等配置片段)。Spawn-time DataAsset CONFIG, template-restored — no runtime-toggleable state (unlike the config fragments that register bEnable: FMove/FChase/...).
FAgentEventRT每 tick 瞬态事件——注册的姊妹片段 FAgentEvent 只带 bEnable 配置。Transient per-tick runtime events — the registered sibling FAgentEvent carries only the bEnable config.
FBeingSelect端侧本地选中状态(渲染层)——绝不同步;LocalVisualRegistry 为重放权威(与 Selected/BeingSelect flag 位同类)。Peer-local selection state (render layer) — never synced; LocalVisualRegistry is the replay authority (same class as the Selected/BeingSelect flag bits).
FVisualizingAGENT 渲染层插值缓存(区别于已注册的 FFxVisualizing FX 实体行)——逐引擎帧写入、双端帧率相关;渲染管线每帧从已注册模拟片段重算,绝非锁步状态。AGENT render-layer interp cache (distinct from the registered FFxVisualizing FX-entity row) — per-ENGINE-frame writes, frame-rate dependent per peer; the render pipeline owns it and recomputes from the registered sim fragments every frame. Never lockstep state.
FProjectileMove_Ballistic / FProjectileMove_Tracking / FProjectileSpawn投射物配置拷贝——生成时数据资产值经模板恢复(与 FCollider/FBehavior 同类;loot 孪生 FLootMove、FLootSpawn 同样不注册)。若项目在运行时改写,必须移出本清单并注册进双注册表(快照恢复保真 + 哈希分叉检测缺一不可)。Projectile CONFIG copies — spawn-time DataAsset values restored via the template (same class as FCollider/FBehavior; the loot twins FLootMove and FLootSpawn are likewise unregistered). If a project ever mutates these at runtime they MUST move out of this list into BOTH registries (snapshot restore fidelity + hash divergence detection).
FProjectileEvent事件配置(bEnable、bGenerate 系标志、EventReceiveSoftActor)——DataAsset 配置经模板恢复;接收者软引用是端侧运行时 BP 绑定。若未来需要运行时开关,bool 字段须注册进双注册表且仅软引用字段保留豁免。Event config (bEnable, bGenerate flags, EventReceiveSoftActor) — DataAsset config restored via the template; the receiver soft-actor is a peer-local BP binding. If runtime toggles are ever needed, register the bools in BOTH registries and keep only the soft-actor field excluded.
FProjectileEventRT端侧本地事件绑定(裸 actor/组件指针,恢复后本地重绑)——与 FAgentEventRT 同类。Peer-local event binding (raw actor/component pointers, re-bound locally after restore) — same class as FAgentEventRT.
MB_FOR_EACH_SNAPSHOT_EXCLUDED_FIELD

字段级有意豁免清单(逐字段注明原因)。

Field-level intentional exclusions (each with its reason).

Fragment.Field豁免原因 Exclusion reason
FProjectileConfig_Final.ProjectileConfigDataAssetPtr已注册软引用 ProjectileConfigDataAsset 的硬指针缓存——池复用(如 CannonBall→Bullet)在双端确定性地同时重写两者;恢复后由复用路径重新解析。绝非分叉信号。Raw-ptr CACHE of the registered soft ref ProjectileConfigDataAsset — pool recycle (e.g. CannonBall→Bullet reuse) rewrites BOTH deterministically on every peer; after restore the recycle path re-resolves it. Never a divergence signal.
FFxVisualizing.InstanceId / FFxVisualizing.RendererActorFX 渲染层缓存——InstanceId 是本地渲染器实例计数;RendererActor 是端侧本地 Actor 对象(每端各自生成)。池复用双端各自换。FX render-layer caches — InstanceId is the local renderer instance counter; RendererActor is a peer-local actor object (each peer spawns its own). Pool recycle swaps both locally.
FHostHierarchy.bResolvedThisTick逐 tick 瞬态解析标志——宿主解析每 tick 重算。Per-tick transient resolve flag — recomputed every tick by the host resolve.
FSplineObstacle.bStatic / FSplineObstacle.bRegistered / FSplineObstacle.BoundComponent网格门控每帧从已注册的 GridData.bStatic 盖章;单次注册哨兵(恢复=新生);UObject 指针经 FObstacleNetBinding 联结恢复。Grid gates stamp per-frame from the registered GridData.bStatic; single-shot static-registration sentinel (restored = fresh by design); UObject pointer restored via the FObstacleNetBinding join.
FBoxObstGridData.RelativeLocation / FCapsuleObstGridData.RelativeLocation / FSegmentObstGridData.RelativeLocation每格派生——实体侧恒为默认值。Per-cell derived — the entity-side value is always default.
namespace MassBattleFieldAudit

把全部注册表展开为运行时映射的辅助命名空间,供编辑器审计 pass 消费。键为运行时反射名(UScriptStruct::GetFName()——UE 剥离 F 前缀,"FMoving" → "Moving");DisplayNames 反映射回 C++ 标识符供报错显示。GetMaps() 以函数内静态局部一次性构建(展开每个 MB_AUDIT_SNAP_GROUP / MB_AUDIT_HASH_GROUP 组块与两条豁免清单),之后常量引用返回。

Helper namespace expanding every registry into runtime maps for the editor audit pass. Keys are RUNTIME reflection names (UScriptStruct::GetFName() — UE strips the F prefix, "FMoving" → "Moving"); DisplayNames maps back to the C++ identifier for fix messages. GetMaps() builds once via a function-local static (expanding every MB_AUDIT_SNAP_GROUP / MB_AUDIT_HASH_GROUP block plus both exclusion lists), then returns the constant reference.

成员 Member说明 Description
FRegistryMaps映射集:SnapshotFields / HashFields(fragment → 已注册字段)、SnapshotGroup / HashGroup(fragment → 组宏名,报错指引)、ExcludedFragments(整片段豁免)、ExcludedFields(字段级豁免)、DisplayNames(运行时键 → 带 F 的标识符)。The map set: SnapshotFields / HashFields (fragment → registered fields), SnapshotGroup / HashGroup (fragment → group macro name, for fix messages), ExcludedFragments (whole-fragment exclusions), ExcludedFields (field-level exclusions), DisplayNames (runtime key → "FMoving"-style identifier).
RuntimeKey(const TCHAR*)注册表标识符按项目约定带 F 前缀、运行时反射名不带——本函数剥掉 F 前缀生成运行时键。Registry identifiers are F-prefixed by project convention; runtime names are not — this strips the F prefix to produce the runtime key.
SplitCsvIntoSet / AddRegisteredLineCSV 字段串切分为 TSet;把一条 SYNC 行(fragment + 字段 CSV + 组宏名)登记进对应映射(快照侧或 hash 侧)。Splits a CSV field string into a TSet; registers one SYNC line (fragment + field CSV + group macro name) into the corresponding maps (snapshot or hash side).
MB_AUDIT_SNAP_LINE / MB_AUDIT_HASH_LINE / MB_AUDIT_EXCL_FRAG_LINE / MB_AUDIT_EXCL_FIELD_LINE行发射器——逐 SYNC 行展开(#__VA_ARGS__ 字符串化字段列表,按逗号切分)。Line emitters — one per SYNC line (#__VA_ARGS__ stringizes the field list, split by comma).
MB_AUDIT_SNAP_GROUP / MB_AUDIT_HASH_GROUP组块宏——TEXT(#GROUPMACRO) 字符串化宏名本身,报错信息能点名要改的宏。Group-block macros — TEXT(#GROUPMACRO) stringizes the macro NAME itself, so the fix message can name the exact macro to edit.
GetMaps()返回一次性构建的 FRegistryMaps 常量引用(函数内静态局部)。Returns a const reference to the once-built FRegistryMaps (function-local static).

修改指引 How to Extend

新增 snapshot 字段:在对应 fragment 的 SYNC(...) 行添加字段名。 新增 snapshot fragment:添加一行 SYNC(FragmentType, Field1, Field2, ...);agent fragment → MB_FOR_EACH_SNAPSHOT_AGENT_FRAGMENT(驱动 agent 网络查询 + 捕获),debuff fragment → MB_FOR_EACH_SNAPSHOT_DEBUFF_FRAGMENT(独立 archetype,独立查询);并集 MB_FOR_EACH_SNAPSHOT_FRAGMENT 供 layout/恢复消费(两组都要)。每个 SYNC 行须 ≥1 字段(MB_SNAP_LAYOUT 对零字段 checkf 失败)。 新增 snapshot tag:在单行 SYNC(...) 中添加 tag 类型,位索引按位置自动分配。 hash 侧:新增 hash 字段/行须满足各注册表注释中的不变量(如与快照注册表共存、共享行逐字一致、渲染层不入 hash)。 有意不注册的片段/字段:加入 MB_FOR_EACH_SNAPSHOT_EXCLUDED_FRAGMENT / MB_FOR_EACH_SNAPSHOT_EXCLUDED_FIELD 豁免清单并注明原因——否则字段注册审计会把它们当未注册状态报错。

Adding a snapshot field: add the field name to the fragment's SYNC(...) line. Adding a snapshot fragment: add one SYNC(FragmentType, Field1, Field2, ...) line; agent fragments → MB_FOR_EACH_SNAPSHOT_AGENT_FRAGMENT (drives the agent network query + capture), debuff fragments → MB_FOR_EACH_SNAPSHOT_DEBUFF_FRAGMENT (separate archetypes, own queries); the union MB_FOR_EACH_SNAPSHOT_FRAGMENT feeds layout/restore — both groups needed. Every SYNC line needs ≥1 field (MB_SNAP_LAYOUT checkf-fails on zero fields). Adding a snapshot tag: add the tag type to the single SYNC(...) line; bit indices are auto-assigned by position. Hash side: new hash fields/rows must satisfy the invariants in each registry's comments (e.g. coexistence with the snapshot registry, verbatim-identical shared rows, no render-layer fields). Deliberately unregistered fragments/fields: add them to the MB_FOR_EACH_SNAPSHOT_EXCLUDED_FRAGMENT / MB_FOR_EACH_SNAPSHOT_EXCLUDED_FIELD exclusion lists WITH a reason — otherwise the field-registration audit reports them as unregistered.

管线角色 Pipeline Role

快照侧消费(均展开 MB_FOR_EACH_SNAPSHOT_FRAGMENT):GetFragmentPtrByName(MassBattleNetworkSubsystem.cpp:764-768,按名取实体 fragment 指针)、GetOrBuildSnapshotLayout(:786,懒构建字段布局,经 _A/_B 拆半分发)、PreBuildSnapshotLayoutCache(:804,预构建缓存)。tag delta 捕获/应用经 MB_SNAP_TAG_DELTA_* 宏(读 MB_FOR_EACH_SNAPSHOT_TAG)写入/恢复 FEntitySnapshotRecord.TagDelta。 hash 侧消费:GetOrBuildHashLayout / PreBuildHashLayoutCache(MB_HASH_LAYOUT/MB_HASH_PREBUILD 宏,见 MassBattleMacros.h:123-161)构建折叠布局;MB_HASH_ONE/MB_HASH_PTR(agent)、MB_HASH_DEBUFF_ONE/MB_HASH_DEBUFF_PTR(debuff)在 UMassBattleNetworkProcessor 的捕获/恢复折叠中展开;变种组(VARIANT)的折叠调用在折叠序末位手写。字段策略由 GetHashFieldPolicy(MassBattleNetworkSubsystem.cpp:565 附近)判定。 快照捕获/恢复与 hash 折叠的调用时机见 MassBattleNetworkSubsystem.html 与 MassBattleNetworkProcessor.html。

Snapshot-side consumers (all expanding MB_FOR_EACH_SNAPSHOT_FRAGMENT): GetFragmentPtrByName (MassBattleNetworkSubsystem.cpp:764-768, fetches a fragment pointer by name), GetOrBuildSnapshotLayout (:786, lazy field-layout build, dispatched via the _A/_B halves), PreBuildSnapshotLayoutCache (:804, pre-build cache). Tag-delta capture/apply goes through the MB_SNAP_TAG_DELTA_* macros (reading MB_FOR_EACH_SNAPSHOT_TAG) into/from FEntitySnapshotRecord.TagDelta. Hash-side consumers: GetOrBuildHashLayout / PreBuildHashLayoutCache (MB_HASH_LAYOUT/MB_HASH_PREBUILD macros, see MassBattleMacros.h:123-161) build fold layouts; MB_HASH_ONE/MB_HASH_PTR (agent) and MB_HASH_DEBUFF_ONE/MB_HASH_DEBUFF_PTR (debuff) expand inside UMassBattleNetworkProcessor's capture/restore folds; the VARIANT groups' fold calls stay hand-written LAST in the fold order. Field policy is decided by GetHashFieldPolicy (near MassBattleNetworkSubsystem.cpp:565). Capture/restore and hash-fold timing is described in MassBattleNetworkSubsystem.html and MassBattleNetworkProcessor.html.