UMassBattleHashGridSubsystem
Source/MassBattle/Public/Subsystems/MassBattleHashGridSubsystem.h
概述 Overview
无边界 2D/3D 哈希网格空间查询子系统,管理三类子网格:Agent(300cm 单元)、Obstacle(500cm 单元)、Loot(400cm 单元)。核心设计:块(Block)式组织 + 单元级细粒度自旋锁 + 命令缓冲回退——已存在的块允许并行线程无锁写(逐 cell 原子锁),缺失的块由并行注册方把命令压入 FParallelGatherer<FGridCommandBufferCommand>,FlushCommandBuffer 在游戏线程按确定性元组排序后串行建块并执行,保证锁步双端 Cell.Agents 追加顺序一致。网格之上还有一层粗粒度簇(Cluster)索引(仅 Agent/Obstacle),大形状 trace 用它跳过整片空区域。此外本子系统还承载 2D 压力场(影响图风格人群压力;块稀疏 FPressureBlock×FFix64 双缓冲,逐块 Jacobi 扩散,位级确定性)与整套空间索敌 API(Sphere/Box/Capsule/Sector/View/Cone 的 trace 与 sweep,支持排序、EntityQuery 剪枝与障碍遮挡射线)。全部尺寸参数在 DefaultMassBattle.ini 配置(Config = MassBattle)。
Boundless 2D/3D hash-grid spatial query subsystem managing three sub-grids: Agent (300 cm cells), Obstacle (500 cm cells), and Loot (400 cm cells). Core design: block-based organization + per-cell fine-grained spin locks + command-buffer fallback — existing blocks accept lock-free parallel writes (per-cell atomic locks); when a block is missing, the parallel writer pushes a command into FParallelGatherer<FGridCommandBufferCommand>, and FlushCommandBuffer sorts deterministically and serially creates blocks and executes commands on the game thread, so Cell.Agents append order is identical across lockstep peers. A coarse cluster layer above the blocks (Agent/Obstacle only) lets large traces skip entire empty regions. The subsystem also hosts a 2D pressure field (influence-map style crowd pressure; block-sparse FPressureBlock FFix64 double buffers with per-block Jacobi diffusion, bit-exact determinism) and the full spatial tracing API (Sphere/Box/Capsule/Sector/View/Cone traces and sweeps with sorting, EntityQuery pruning, and obstacle occlusion rays). All size parameters are configured in DefaultMassBattle.ini (Config = MassBattle).
继承 Inheritance
枚举 Enums
网格修改命令的类型,FGridCommandBufferCommand.CommandType 用它区分注册目标,FlushCommandBuffer 排序的次键与 ExecuteRegistrationCommand 分派都依赖它。
Grid modification command type; FGridCommandBufferCommand.CommandType uses it to identify the registration target, and both the FlushCommandBuffer sort key and ExecuteRegistrationCommand dispatch depend on it.
| 值 Value | 说明 Description |
|---|---|
RegisterAgent | 注册 agent 网格数据(载荷在 AgentGridData,可带 AgentComposition)。Register agent grid data (payload in AgentGridData, optionally with AgentComposition). |
RegisterCapsuleObstacle | 注册胶囊障碍(载荷在 CapsuleObstGridData)。Register capsule obstacle (payload in CapsuleObstGridData). |
RegisterSegmentObstacle | 注册样条段障碍(载荷在 SegmentObstGridData,按 GroupID + Index 排序)。Register spline segment obstacle (payload in SegmentObstGridData; sorted by GroupID + Index). |
RegisterBoxObstacle | 注册盒障碍(载荷在 BoxObstGridData)。Register box obstacle (payload in BoxObstGridData). |
RegisterLoot | 注册战利品(载荷在 LootGridData)。Register loot (payload in LootGridData). |
网格类型,TraceForCells_Internal 系列用它选择单元尺寸、块维度与坐标转换器。
Grid type; the TraceForCells_Internal family uses it to pick cell size, block dimensions, and coordinate converters.
| 值 Value | 说明 Description |
|---|---|
Agent | Agent 网格。Agent grid. |
Obstacle | 障碍网格。Obstacle grid. |
Loot | 战利品网格。Loot grid. |
结构体 Structs
命令缓冲中的单条网格修改命令,携带执行注册所需的全部数据。块缺失时由 RegisterCell_Internal 构造并压入 CommandBuffer,ExecuteRegistrationCommand 消费。
A single grid-modification command in the command buffer, carrying all data needed to perform a registration. Built by RegisterCell_Internal when the block is missing and pushed into CommandBuffer; consumed by ExecuteRegistrationCommand.
成员变量 Members
| 名称 Name | 类型 Type | 默认值 | 说明 Description |
|---|---|---|---|
CommandType | EGridCommandType | — | 命令类型,决定分派目标与排序 tiebreak。Command type; decides the dispatch target and the sort tiebreak. |
Coord | FIntVector | — | 目标全局网格坐标。Target global grid coordinate. |
AgentGridData | FAgentGridData | — | agent 载荷(RegisterAgent 时有效)。Agent payload (valid for RegisterAgent). |
CapsuleObstGridData | FCapsuleObstGridData | — | 胶囊障碍载荷。Capsule obstacle payload. |
SegmentObstGridData | FSegmentObstGridData | — | 样条段障碍载荷。Spline segment obstacle payload. |
BoxObstGridData | FBoxObstGridData | — | 盒障碍载荷。Box obstacle payload. |
LootGridData | FLootGridData | — | 战利品载荷。Loot payload. |
AgentComposition | TOptional<FMassArchetypeCompositionDescriptor> | — | agent 的 archetype composition(仅 RegisterAgent 设置),执行时用于维护 cell/block 级并集与交集剪枝。The agent's archetype composition (set only for RegisterAgent), used at execution to maintain cell/block-level union and intersection pruning. |
Agent 网格的单个单元。自带 std::atomic 自旋锁(Lock/Unlock,acquire/release 语义),当块已存在时允许多线程并发写入同一单元——这是"细粒度锁"设计的核心。维护单元级 composition 并集(Composition,All/Any 剪枝)与交集(IntersectionComposition,None 剪枝,由 bEnableIntersectionComposition 开关)。
A single cell of the agent grid. Carries its own std::atomic spin lock (Lock/Unlock, acquire/release semantics) so multiple threads can write the same cell concurrently when its block exists — the core of the "fine-grained locking" design. Maintains the cell-level composition union (Composition, All/Any pruning) and intersection (IntersectionComposition, None pruning, gated by bEnableIntersectionComposition).
成员变量 Members
| 名称 Name | 类型 Type | 默认值 | 说明 Description |
|---|---|---|---|
LockFlag | std::atomic<bool> (private) | false | 自旋锁标志;通过 Lock()(exchange-acquire 循环)与 Unlock()(store-release)访问。Spin-lock flag; accessed via Lock() (exchange-acquire loop) and Unlock() (store-release). |
CellLocation | FVector | FVector::ZeroVector | 单元中心世界坐标(AgentCoordToLocation 结果),注册时写入。Cell center world position (AgentCoordToLocation), written at registration. |
Composition | FMassArchetypeCompositionDescriptor | — | 成员 composition 并集——All/Any 聚合剪枝;首 agent 直接赋值,之后 HasAll 检查通过则跳过写入(位集 Append 昂贵)。Union of member compositions — All/Any aggregate pruning; first agent assigns directly, later appends are skipped when HasAll passes (bit-set Append is expensive). |
IntersectionComposition | FMassArchetypeCompositionDescriptor | — | 成员 composition 交集——None 聚合剪枝;仅 bEnableIntersectionComposition 时维护。Intersection of member compositions — None aggregate pruning; maintained only when bEnableIntersectionComposition is on. |
Agents | TArray<FAgentGridData, TInlineAllocator<16>> | — | 本单元内的 agent 网格数据。内联容量 16 = 实测常态每格负载(4-9 个单位,2026-10-05)的 2 倍;16×64B = 1024B 使记录块保持 2 的幂对齐;挤压密度混战(10+)一次性溢出到堆并驻留(每帧 Reset 保留容量)。追加顺序由注册路径决定(串行 flush 保证确定性)。Agent grid data in this cell. Inline capacity 16 = 2× the observed normal per-cell load (4-9 units, 2026-10-05); 16×64B = 1024B keeps the record block power-of-two aligned; crush-density scrums (10+) spill to the heap once and stay (per-frame Reset retains capacity). Append order is decided by the registration path (serial flush guarantees determinism). |
Reset() 保留容量清空(单元数据 + composition),Empty() 释放容量;二者均不重置 CellLocation。
Reset() clears contents while keeping capacity (agent data + compositions); Empty() frees capacity; neither resets CellLocation.
障碍网格的单个单元。动态与静态障碍分数组存放(静态的由 GridData.bStatic 决定),占用位也在 FObstGridBlock 里分 OccupiedCells / StaticOccupiedCells 两套——每帧 ResetOccupiedObstacleCells 只清动态侧,静态障碍跨帧存活。六个数组各按 TInlineAllocator<2> 精简内联:一个 cell 通常只持一种障碍类型(墙边格只有 segments),而六数组的内联存储由每个 cell 无条件支付,精简容量即把障碍 block 内存减半;各类型典型负载 0-2 条,溢出(林地胶囊、墙体线段 3-5 条/格)对静态体只注册一次(一次性分配,无逐帧 churn),动态容量由 Reset 保留。
A single cell of the obstacle grid. Dynamic and static obstacles live in separate arrays (chosen by GridData.bStatic), and occupancy bits are likewise split between OccupiedCells / StaticOccupiedCells in FObstGridBlock — the per-frame ResetOccupiedObstacleCells clears only the dynamic side, so static obstacles survive across frames. The six arrays each use a lean TInlineAllocator<2> inline capacity: a cell usually holds ONE obstacle type (a wall cell has segments only), but all six arrays' inline storage is paid by EVERY cell unconditionally, so lean capacity halves obst-block memory. Typical per-type load is 0-2; overflow (forest capsules, wall segments 3-5/cell) registers once for statics — a one-time alloc with no per-frame churn; dynamic capacity is Reset-retained.
成员变量 Members
| 名称 Name | 类型 Type | 默认值 | 说明 Description |
|---|---|---|---|
LockFlag | std::atomic<bool> (private) | false | 自旋锁标志。Spin-lock flag. |
CellLocation | FVector | FVector::ZeroVector | 单元中心世界坐标。Cell center world position. |
CapsuleObstacles / StaticCapsuleObstacles | TArray<FCapsuleObstGridData, TInlineAllocator<2>> | — | 动态 / 静态胶囊障碍数据。Dynamic / static capsule obstacle data. |
SegmentObstacles / StaticSegmentObstacles | TArray<FSegmentObstGridData, TInlineAllocator<2>> | — | 动态 / 静态样条段障碍数据。Dynamic / static spline segment obstacle data. |
BoxObstacles / StaticBoxObstacles | TArray<FBoxObstGridData, TInlineAllocator<2>> | — | 动态 / 静态盒障碍数据。Dynamic / static box obstacle data. |
Reset() / Empty() 只清三个动态数组;ResetAll() / EmptyAll() 清全部六个(动态 + 静态);StaticReset() 仅清静态半区——resync 拆除用:重建的静态障碍以新生语义重注册(恢复实体的 bRegistered 按设计为 false)。
Reset() / Empty() clear only the three dynamic arrays; ResetAll() / EmptyAll() clear all six (dynamic + static); StaticReset() clears the static half only — for resync teardown: rebuilt statics re-register fresh (restored entities carry bRegistered=false by design).
战利品网格的单个单元,结构最简单——只存 Loots 数组与自旋锁。
A single cell of the loot grid — the simplest cell, holding only the Loots array and a spin lock.
成员变量 Members
| 名称 Name | 类型 Type | 默认值 | 说明 Description |
|---|---|---|---|
LockFlag | std::atomic<bool> (private) | false | 自旋锁标志。Spin-lock flag. |
CellLocation | FVector | FVector::ZeroVector | 单元中心世界坐标。Cell center world position. |
Loots | TArray<FLootGridData, TInlineAllocator<4>> | — | 本单元内的战利品网格数据。内联 4:4 米格内典型掉落 0-3 条;击杀点聚簇(10+)超出任何合理内联预算,驻留堆上(Reset 保留容量,一次性溢出)。Loot grid data in this cell. Inline 4: typical drops per 4 m cell are 0-3; kill-site clusters (10+) exceed any sane inline budget and stay heap-resident (Reset retains capacity, one-time spill). |
单元的占用位数组包装,带自旋锁——锁粒度是"整个位数组"而非单 bit。占用位在注册时置 true,ResetOccupied* 时清 false;TConstSetBitIterator 用它跳过空单元。
Occupancy bit-array wrapper with a spin lock — the lock granularity is the whole bit array, not single bits. Bits are set at registration, cleared by ResetOccupied*; TConstSetBitIterator uses it to skip empty cells.
成员变量 Members
| 名称 Name | 类型 Type | 默认值 | 说明 Description |
|---|---|---|---|
LockFlag | std::atomic<bool> (private) | false | 自旋锁标志。Spin-lock flag. |
OccupiedCellBitArray | TBitArray<> | — | 单元占用位数组,长度 = 块内单元数。Per-cell occupancy bits; length equals the block's cell count. |
预分配单元数组的 agent 块,尺寸动态(构造时传入 InBlockSize)。AgentGrid 以块坐标(全局坐标除以块维度向下取整)为键。块级也维护 composition 并集/交集,供 ExecuteCellTrace 在遍历单元前整块剪枝。
An agent block of pre-allocated cells with dynamic dimensions (passed as InBlockSize at construction). AgentGrid keys on block coords (global coord floor-divided by block dimensions). The block also maintains composition union/intersection so ExecuteCellTrace can prune whole blocks before iterating cells.
成员变量 Members
| 名称 Name | 类型 Type | 默认值 | 说明 Description |
|---|---|---|---|
Cells | TArray<FHashGridAgentCell> | — | 块内单元数组(SetNum(InBlockSize) 预分配)。Cell array inside the block (pre-allocated via SetNum(InBlockSize)). |
OccupiedCells | FOccupiedCellBitArray | — | 单元占用位(Init(false, InBlockSize))。Per-cell occupancy bits (Init(false, InBlockSize)). |
Composition | FMassArchetypeCompositionDescriptor | — | 块级并集——All/Any 聚合剪枝;空 ⟺ 块内尚无 agent。Block-level union — All/Any aggregate pruning; empty ⟺ no agent in the block yet. |
IntersectionComposition | FMassArchetypeCompositionDescriptor | — | 块级交集——None 聚合剪枝(受全局开关控制)。Block-level intersection — None aggregate pruning (gated by the global switch). |
障碍块,与 FAgentGridBlock 同构,但占用位分动态/静态两套。
Obstacle block, structurally like FAgentGridBlock, but with separate dynamic/static occupancy bit arrays.
成员变量 Members
| 名称 Name | 类型 Type | 默认值 | 说明 Description |
|---|---|---|---|
Cells | TArray<FHashGridObstCell> | — | 块内障碍单元数组。Obstacle cell array. |
OccupiedCells | FOccupiedCellBitArray | — | 动态障碍占用位。Dynamic obstacle occupancy bits. |
StaticOccupiedCells | FOccupiedCellBitArray | — | 静态障碍占用位。Static obstacle occupancy bits. |
战利品块,无静态侧、无 composition、无 cluster 层。
Loot block — no static side, no compositions, no cluster layer.
成员变量 Members
| 名称 Name | 类型 Type | 默认值 | 说明 Description |
|---|---|---|---|
Cells | TArray<FHashGridLootCell> | — | 块内战利品单元数组。Loot cell array. |
OccupiedCells | FOccupiedCellBitArray | — | 单元占用位。Per-cell occupancy bits. |
一块大型压力瓦片:完整的 PressureGridDimensions × PressureCellSize 双缓冲 FFix64 场(默认 256×256 格 = 512m)。块铺在以 PressureGridOrigin 锚定的绝对格网上,block (0,0) 与旧固定网格完全重合——默认原点居中战场逐位不变。无位域:两个成员都是可平凡清零数组(零内存即 FFix64(0))。
One large pressure tile: a full double-buffered FFix64 field sized PressureGridDimensions × PressureCellSize (default 256×256 cells = 512 m). Blocks tile the world on an absolute lattice anchored at PressureGridOrigin, so block (0,0) coincides exactly with the legacy fixed grid — the default origin-centered battle behaves bit-identically. No bitfields: both members are trivially-zeroable arrays (zeroed memory IS FFix64(0)).
成员变量 Members
| 名称 Name | 类型 Type | 默认值 | 说明 Description |
|---|---|---|---|
Front | TArray<FFix64> | — | 当前帧场缓冲;构造时 SetNumZeroed(InCellCount)。Current-frame field buffer; SetNumZeroed(InCellCount) at construction. |
Back | TArray<FFix64> | — | Jacobi 扩散轮换缓冲;同样零初始化。Jacobi diffusion rotation buffer; likewise zero-initialized. |
公开方法 Public Methods
USubsystem 生命周期入口,负责把配置值落成缓存:三套网格的逆单元尺寸(*InvCellSizeCache)、块维度(*BlockDimensionsCache)(每个维度 Max(1, 配置),单元尺寸下限 0.001cm)与块大小乘积(checkf 校验 int32 溢出);簇维度强制 Z=1(checkf 断言)。随后 RandomStream.Initialize(12345)、InitPressureField()、ClearAllCells()。
USubsystem lifecycle entry; bakes config values into caches: inverse cell sizes (*InvCellSizeCache) for the three grids, block dimensions (*BlockDimensionsCache) (each axis Max(1, config), cell size floor 0.001 cm), and the block size product (checkf for int32 overflow); cluster dimensions are forced to Z=1 (checkf). Then RandomStream.Initialize(12345), InitPressureField(), and ClearAllCells().
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
Collection | FSubsystemCollectionBase& | 子系统集合,由引擎传入。Subsystem collection provided by the engine. |
Output
无返回值。副作用:写入全部尺寸缓存、随机流固定种子 12345、重算压力场格网缓存(存储惰性,此处不分配)、清空三个网格。
No return value. Side effects: fills all dimension caches, seeds the random stream with 12345, recomputes the pressure lattice caches (storage is lazy — nothing allocated here), empties the three grids.
USubsystem 生命周期出口:先 ClearAllCells() 释放三套网格与簇索引,再调用父类实现。
USubsystem lifecycle exit: calls ClearAllCells() to release the three grids and cluster indices, then the parent implementation.
Input
无参数。
No parameters.
Output
无返回值。副作用:释放全部网格块与簇索引内存。
No return value. Side effect: frees all grid block and cluster memory.
每帧 tick 入口,当前仅做一件事:FlushCommandBuffer() 排空本帧并行注册压入的命令(排序 + 串行执行 + 建块)。由 UMassBattleSubsystem 的模拟 tick 调用。
Per-frame tick entry; currently does exactly one thing: FlushCommandBuffer() drains this frame's parallel registrations (sort + serial execution + block creation). Called from UMassBattleSubsystem's simulation tick.
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
DeltaTime | float | 帧时间步长(秒),本实现未使用。Frame delta time in seconds; unused by this implementation. |
Output
无返回值。副作用:执行全部积压的网格注册命令。
No return value. Side effect: executes all backlogged grid registration commands.
静态访问器:经 GEngine->GetWorldFromContextObject(LogAndReturnNull 模式)解析世界再取子系统;解析失败返回 nullptr。
Static accessor: resolves the world via GEngine->GetWorldFromContextObject (LogAndReturnNull mode) and returns its subsystem; nullptr on resolution failure.
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
WorldContext | const UObject* | 任意 UObject 世界上下文。Any UObject world context. |
Output
返回子系统指针;世界上下文无效时为 nullptr。
Returns the subsystem pointer, or nullptr when the world context is invalid.
静态访问器的引用版本:失败即 checkf 断言("Failed to get UMassBattleHashGridSubsystem from world context.")——用于子系统必须存在的路径。
Reference version of the static accessor: fails via checkf ("Failed to get UMassBattleHashGridSubsystem from world context.") — for paths where the subsystem must exist.
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
WorldContext | const UObject* | 任意 UObject 世界上下文。Any UObject world context. |
Output
返回子系统引用;取不到时触发 checkf 断言。
Returns a subsystem reference; triggers a checkf assertion when unavailable.
惰性访问并缓存 UMassAPISubsystem:命中缓存直接返回;否则从当前世界取子系统并写入 CurrentWorld / MassAPISubsystem 缓存。
Lazily accesses and caches UMassAPISubsystem: returns the cache on hit; otherwise fetches it from the current world and fills the CurrentWorld / MassAPISubsystem caches.
Input
无参数。
No parameters.
Output
返回 UMassAPISubsystem 指针(世界不存在时可能为 nullptr)。副作用:写入两个缓存成员。
Returns the UMassAPISubsystem pointer (may be nullptr if the world is missing). Side effect: fills the two cache members.
惰性访问并缓存 UMassBattleSubsystem,行为与 GetMassAPISubsystem 对称。
Lazily accesses and caches UMassBattleSubsystem; symmetric to GetMassAPISubsystem.
Input
无参数。
No parameters.
Output
返回 UMassBattleSubsystem 指针。副作用:写入 CurrentWorld / MassBattleSubsystem 缓存。
Returns the UMassBattleSubsystem pointer. Side effect: fills the CurrentWorld / MassBattleSubsystem caches.
命令缓冲的确定性排空(由 ExecuteTick 与 MassBattleGridUpdateProcessor 调用)。流程:① CommandBuffer.Merge() 合并各线程槽;② 空则返回;③ bDeterministic 开启时按 (Coord X→Y→Z → CommandType → UniqueID;Segment 用 GroupID → Index) 排序;④ 收集缺失块,按固定顺序单线程建块(MakeShared),Agent/Obstacle 同时把簇坐标幂等加入 *OccupiedClusters;⑤ 串行(禁用 MBParallelFor)逐条 ExecuteRegistrationCommand——并行调度会抵消排序,导致 Cell.Agents 追加顺序逐运行变化;⑥ Reset() 清空收集器。
Deterministic drain of the command buffer (called by ExecuteTick and MassBattleGridUpdateProcessor). Flow: ① CommandBuffer.Merge() merges per-thread slots; ② returns when empty; ③ when bDeterministic is on, sorts by (Coord X→Y→Z → CommandType → UniqueID; Segments by GroupID → Index); ④ collects missing blocks and creates them single-threaded in fixed order (MakeShared), idempotently adding cluster coords to *OccupiedClusters for Agent/Obstacle; ⑤ executes commands serially (no MBParallelFor) via ExecuteRegistrationCommand — parallel dispatch would negate the sort and make Cell.Agents append order vary per run; ⑥ Reset() clears the gatherer.
Input
无参数(命令来自成员 gatherer)。
No parameters (commands come from the member gatherer).
Output
无返回值。副作用:建缺失块、执行全部注册、更新簇索引、清空 gatherer。
No return value. Side effects: creates missing blocks, executes all registrations, updates cluster indices, resets the gatherer.
单条命令的串行执行(仅 FlushCommandBuffer 调用)。按 CommandType 分派到三套网格:设置占用位、维护块级 composition(锁内 HasAll 检查消除 TOCTOU;首 agent 赋值交集,非首走写前检查 + AND)、写 CellLocation、锁内维护单元级 composition 并追加数据。RegisterAgent 分支额外用 CAS 原子最大值维护 MaxAgentNeighborExtent(max(AvoidRadiusX, ColliderHeight*0.5 + ColliderRadius*ColliderMult),ColliderMult 只放大半径)。
Serial execution of a single command (called only by FlushCommandBuffer). Dispatches on CommandType into the three grids: sets the occupancy bit, maintains block-level composition (HasAll checked inside the lock to close the TOCTOU race; first agent assigns the intersection, later ones write-before-check + AND), writes CellLocation, and appends the payload under the cell lock with cell-level composition maintenance. The RegisterAgent branch additionally maintains MaxAgentNeighborExtent via CAS atomic-max (max(AvoidRadiusX, ColliderHeight*0.5 + ColliderRadius*ColliderMult); ColliderMult inflates the radius only).
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
Command | const FGridCommandBufferCommand& | 要执行的注册命令。The registration command to execute. |
Output
无返回值。副作用:写入单元数据、占用位、composition 与 MaxAgentNeighborExtent。
No return value. Side effects: writes cell data, occupancy bits, compositions, and MaxAgentNeighborExtent.
agent 注册的公开入口:转发到 RegisterCell_Internal(AgentGrid, RegisterAgent, ...)。并行段(如 MassBattleGridUpdateProcessor 的 MBForEachEntityChunk)直接调用,块存在时走加锁快路径,块缺失时压命令缓冲。
Public entry for agent registration: forwards to RegisterCell_Internal(AgentGrid, RegisterAgent, ...). Called directly from parallel sections (e.g. MassBattleGridUpdateProcessor's MBForEachEntityChunk); takes the locked fast path when the block exists, else queues a command.
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
Coord | const FIntVector& | 目标全局网格坐标(单元索引空间)。Target global grid coordinate (cell index space). |
GridData | const FAgentGridData& | agent 网格数据(相对位置、碰撞体、UID 等)。Agent grid data (relative location, collider, UID, etc.). |
Composition | const FMassArchetypeCompositionDescriptor& | 该 agent 的 archetype composition,用于 cell/block 级 All/Any/None 聚合剪枝。The agent's archetype composition, used for cell/block-level All/Any/None aggregate pruning. |
Output
无返回值。副作用:写入单元占用位、composition 与 Agents 数组;块缺失时向命令缓冲压一条命令。
No return value. Side effects: writes the occupancy bit, compositions, and the Agents array; queues a command when the block is missing.
障碍注册的公开入口,Capsule / Segment / Box 各一个重载,分别转发到对应 RegisterCell_Internal(ObstacleGrid, ...)。行为与 RegisterAgentCell 相同(快路径 / 命令回退),静态障碍(GridData.bStatic)走 StaticOccupiedCells 位与 Static* 数组。
Public entries for obstacle registration, one overload per Capsule / Segment / Box, each forwarding to the matching RegisterCell_Internal(ObstacleGrid, ...). Behavior matches RegisterAgentCell (fast path / command fallback); static obstacles (GridData.bStatic) use the StaticOccupiedCells bits and Static* arrays.
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
Coord | const FIntVector& | 目标全局网格坐标。Target global grid coordinate. |
GridData | const FCapsuleObstGridData& / FSegmentObstGridData& / FBoxObstGridData& | 对应类型的障碍网格数据(bStatic 决定动态/静态侧)。Obstacle grid data of the matching type (bStatic decides the dynamic/static side). |
Output
无返回值。副作用:写入单元占用位与对应障碍数组;块缺失时压命令缓冲。
No return value. Side effects: writes the occupancy bit and matching obstacle array; queues a command when the block is missing.
战利品注册的公开入口:转发到 RegisterCell_Internal(LootGrid, RegisterLoot, ...)。
Public entry for loot registration: forwards to RegisterCell_Internal(LootGrid, RegisterLoot, ...).
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
Coord | const FIntVector& | 目标全局网格坐标。Target global grid coordinate. |
GridData | const FLootGridData& | 战利品网格数据。Loot grid data. |
Output
无返回值。副作用:写入占用位与 Loots 数组;块缺失时压命令缓冲。
No return value. Side effects: writes the occupancy bit and the Loots array; queues a command when the block is missing.
agent 注册的核心实现。块存在时:占用位 Lock→置位→Unlock(已置位跳过);块级 composition 锁内 HasAll 检查 + 追加,首 agent(Composition.IsEmpty() 判断)直接赋值交集;单元级同样锁内维护并写 CellLocation + Agents.Add。块缺失时:构造 FGridCommandBufferCommand(携带 AgentComposition)压入 CommandBuffer.GetThreadBuffer()。
Core implementation of agent registration. When the block exists: occupancy bit is Lock→set→Unlock (skipped when already set); block-level composition is HasAll-checked inside the lock before append, first agent (detected via Composition.IsEmpty()) assigns the intersection directly; cell-level composition is maintained under the cell lock together with CellLocation write and Agents.Add. When the block is missing: builds an FGridCommandBufferCommand (carrying AgentComposition) into CommandBuffer.GetThreadBuffer().
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
Grid | TMap<FIntVector, TSharedPtr<FAgentGridBlock>>& | 目标网格(实际总是 AgentGrid)。Target grid (always AgentGrid in practice). |
CommandType | EGridCommandType | 命令类型(RegisterAgent)。Command type (RegisterAgent). |
Coord | const FIntVector& | 全局网格坐标。Global grid coordinate. |
GridData | const FAgentGridData& | agent 网格数据。Agent grid data. |
Composition | const FMassArchetypeCompositionDescriptor* | composition 指针,命令回退分支会无条件解引用。Composition pointer; dereferenced unconditionally in the command-fallback branch. |
Output
无返回值。副作用见上方描述。
No return value. Side effects as described above.
障碍与战利品注册的核心实现,结构同 agent 版:块存在时置位(障碍按 bStatic 选动态/静态位数组)并在单元锁内追加到对应数组;块缺失时构造对应载荷的命令压入缓冲。
Core implementations for obstacle and loot registration, structurally identical to the agent version: when the block exists, set the bit (obstacles pick the dynamic/static bit array by bStatic) and append to the matching array under the cell lock; when the block is missing, queue a command carrying the matching payload.
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
Grid | TMap<FIntVector, TSharedPtr<FObstGridBlock>>& / <FLootGridBlock>& | 目标网格。Target grid. |
CommandType | EGridCommandType | 对应命令类型。Matching command type. |
Coord | const FIntVector& | 全局网格坐标。Global grid coordinate. |
GridData | const FCapsuleObstGridData& / FSegmentObstGridData& / FBoxObstGridData& / FLootGridData& | 对应载荷。Matching payload. |
Output
无返回值。副作用:写入单元与占用位;块缺失时压命令。
No return value. Side effects: writes the cell and occupancy bit; queues a command when the block is missing.
三套网格的占用单元全量复位(并行,每块一个任务):遍历占用位逐单元 Reset()、占用位数组 Init(false)、块级 composition 复位。最后把 MaxAgentNeighborExtent 清零,使 gather 的剪枝截止值只由本帧注册重建。
Full occupancy reset for all three grids (parallel, one task per block): iterates the occupancy bits, Reset()s each cell, Init(false)s the bit array, resets block compositions. Finally zeroes MaxAgentNeighborExtent so the gather's prune cutoff is rebuilt from this frame's registrations only.
Input
无参数。
No parameters.
Output
无返回值。副作用:清空三套网格全部单元内容与占用位。
No return value. Side effect: clears all cell contents and occupancy bits of the three grids.
仅 agent 网格的占用复位(每帧由 MassBattleGridUpdateProcessor 在重新注册所有 agent 前调用;resync 路径由 MassBattleNetworkSubsystem 调用)。同时清零 MaxAgentNeighborExtent——注释标明这是清理 gather 剪枝运行最大值"正确的钩子"。
Occupancy reset for the agent grid only (called every frame by MassBattleGridUpdateProcessor before re-registering all agents; the resync path in MassBattleNetworkSubsystem also calls it). Also zeroes MaxAgentNeighborExtent — the comment marks this as the right hook for clearing the gather's running-max prune.
Input
无参数。
No parameters.
Output
无返回值。副作用:清空 agent 单元与块 composition、占用位,清零 MaxAgentNeighborExtent。
No return value. Side effects: clears agent cells, block compositions, occupancy bits, and MaxAgentNeighborExtent.
障碍网格的动态占用复位。注意:只清动态侧——StaticOccupiedCells 位数组与单元静态数组原样保留,静态障碍跨帧存活。
Dynamic occupancy reset for the obstacle grid. Note: only the dynamic side is cleared — the StaticOccupiedCells bits and the static arrays survive untouched, so static obstacles persist across frames.
Input
无参数。
No parameters.
Output
无返回值。副作用:清空动态障碍单元与动态占用位,静态侧不变。
No return value. Side effect: clears dynamic obstacle cells and occupancy bits; static side unchanged.
清空障碍网格静态半区(resync 拆除用;并行,每块一个任务):对静态占用位置位的单元调用 StaticReset(),再把 StaticOccupiedCells 整体 Init(false)。逐帧重置从不清静态半区——resync 经 DestroyQuery 直接销毁实体(不走 Obstacle.Destroy),不清则孤儿静态条目与重建实体(bRegistered=false,新生语义)同格重复注册同 UID → [RVO_DESYNC] 排序去重报错;静态内容全部可由实体重建,清空即自愈。双半区皆空的块由随后的 ShrinkObstacleGrid 收割。由 MassBattleNetworkSubsystem 的 resync 恢复路径调用(:2114)。
Wipes the obstacle grid's STATIC half (resync teardown; parallel, one task per block): calls StaticReset() on cells with a static occupancy bit set, then re-Init(false)s the whole StaticOccupiedCells array. The per-frame reset never touches the static half — resync destroys networked entities directly (DestroyQuery, no Obstacle.Destroy), so without this wipe the orphaned static entries would meet the rebuilt entities' fresh registration (bRegistered=false by design) as duplicate UIDs in the same cell → [RVO_DESYNC] duplicate-sort errors; everything static is rebuildable from entities, so wiping is self-healing. Blocks left empty on both halves are reaped by the subsequent ShrinkObstacleGrid. Called from the resync restore path of MassBattleNetworkSubsystem (:2114).
Input
无参数。
No parameters.
Output
无返回值。副作用:清空全部静态障碍单元内容与静态占用位;动态侧不变。
No return value. Side effect: clears all static obstacle cell contents and static occupancy bits; dynamic side unchanged.
战利品网格的占用复位,行为与 agent 版一致(无 composition 部分)。
Occupancy reset for the loot grid, same behavior as the agent version (minus the composition part).
Input
无参数。
No parameters.
Output
无返回值。副作用:清空战利品单元与占用位。
No return value. Side effect: clears loot cells and occupancy bits.
按 UID 从全部块的静态胶囊/静态盒数组中移除障碍(注意:不处理静态样条段,那是 RemoveStaticSegmentObstacleByGroupID 的职责)。单元三个静态数组全空时把对应 StaticOccupiedCells 位清 false。由 MassBattleGridUpdateProcessor 在静态盒停用时调用。
Removes an obstacle by UID from every block's static capsule/box arrays (note: static spline segments are not touched — that is RemoveStaticSegmentObstacleByGroupID's job). When a cell's three static arrays are all empty, its StaticOccupiedCells bit is cleared. Called by MassBattleGridUpdateProcessor when a static box is deactivated.
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
UniqueID | int32 | 要移除的静态障碍 UID。UID of the static obstacle to remove. |
Output
无返回值。副作用:从静态数组移除数据、必要时清占用位。
No return value. Side effects: removes data from static arrays, clears occupancy bits when needed.
按 GroupID 从全部块的静态样条段数组中移除段障碍;单元静态数组全空时清占用位。
Removes segment obstacles by GroupID from every block's static segment array; clears the occupancy bit when the cell's static arrays are all empty.
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
GroupID | uint32 | 要移除的样条组 ID。Spline group ID to remove. |
Output
无返回值。副作用:从静态段数组移除数据、必要时清占用位。
No return value. Side effects: removes data from static segment arrays, clears occupancy bits when needed.
完全清空三套网格(AgentGrid / ObstacleGrid / LootGrid 的 Empty())与两个簇索引集合(AgentOccupiedClusters / ObstacleOccupiedClusters)。Initialize 与 Deinitialize 各调用一次。
Fully empties the three grids (AgentGrid / ObstacleGrid / LootGrid Empty()) and the two cluster sets (AgentOccupiedClusters / ObstacleOccupiedClusters). Called once each from Initialize and Deinitialize.
Input
无参数。
No parameters.
Output
无返回值。副作用:释放全部网格块与簇索引内存。
No return value. Side effect: releases all grid block and cluster memory.
[临时诊断·resync 循环猎杀,排查完成后移除] 转储障碍网格盒障碍条目清单外加折叠清单哈希:遍历 ObstacleGrid 全部块,对动/静态占用单元各收集 {块坐标, 格索引, 动静, UID, 半尺寸} 条目,按 (UID, CellIdx, bStatic) 排序后逐字段 CityHash64WithSeed 折叠为顺序无关的 invHash——网格相同 ⇒ 哈希相同,双端对比即可检验恢复/FF 后网格内容是否分歧(网格状态不在锁步 hash 内);差异可经逐条目日志定位。摘要行 [OBST_GRID_INV](total/dyn/static/invHash)恒打;仅 bObstacleGridInvFullDump 开启时才逐条打(一次全量 3k+ 行 Error)。仅 game thread。双端调用方:MassBattleNetworkGameModeBase(:919,tag SRV)与 MassBattleNetworkGameStateBase(:360,tag CLI)。
[TEMP-DIAG resync-loop hunt, remove when the hunt is done] Dumps the obstacle grid's box-obstacle entry inventory plus a folded inventory hash: walks every block of ObstacleGrid, collects {block coord, cell index, dynamic/static, UID, half extents} entries from the occupied cells on each half, sorts them by (UID, CellIdx, bStatic) and folds field-by-field with CityHash64WithSeed into an order-independent invHash — identical grids ⇒ identical hash, so diffing across peers tests whether the grid CONTENT diverges after restore/FF (grid state is not part of the lockstep hash); a diff localizes the lost/extra entry via the per-entry lines. The summary line [OBST_GRID_INV] (total/dyn/static/invHash) always prints; full per-entry enumeration only when bObstacleGridInvFullDump is on (one full dump is 3k+ Error lines). Game thread only. Called on both peers by MassBattleNetworkGameModeBase (:919, tag SRV) and MassBattleNetworkGameStateBase (:360, tag CLI).
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
Tag | const TCHAR* | 日志标签(如 SRV/CLI),便于双端对照。Log tag (e.g. SRV/CLI) for peer-side correlation. |
Output
无返回值。副作用:输出 [OBST_GRID_INV] Error 日志(摘要恒打,全量受 bObstacleGridInvFullDump 门控)。
No return value. Side effect: emits [OBST_GRID_INV] Error logs (summary always, full dump gated by bObstacleGridInvFullDump).
枚举全部障碍条目(动/静 × 胶囊/线段/盒三种几何)每(格注册)一次:遍历 ObstacleGrid 全部块的动/静态占用单元,经静态助手 VisitObstCell 把六数组逐条回调 Visitor(Type 编码 0=胶囊、1=线段、2=盒)。O(K + 块数),串行、只读——供只需要小障碍群体的每帧建池方,绝不该走逐 agent 引用遍历。多格注册的障碍每格出现一次,上游按 Data 指针去重。(1.19.20 源码树暂无调用方——头文件注明为每帧建池方预留。)
Enumerates EVERY obstacle entry (dynamic/static × capsule/segment/box) exactly once per (cell-registration): walks all blocks' dynamic and static occupied cells and, via the static helper VisitObstCell, hands each of the six arrays' entries to Visitor (Type encoded 0=capsule, 1=segment, 2=box). O(K + blocks), serial, read-only — for per-frame pool builders that only need the small obstacle population, never the per-agent ref walk. Multi-cell-registered obstacles appear once per registered cell; dedup upstream by Data pointer. (No callers in the 1.19.20 tree yet — the header reserves it for per-frame pool builders.)
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
Visitor | const TFunctionRef<void(uint8 Type, const void* Data, const FVector& CellLocation)>& | 逐条目回调;Data 指向具体几何结构体(FCapsuleObstGridData / FSegmentObstGridData / FBoxObstGridData),可作去重键。Per-entry callback; Data points at the concrete geometry struct (FCapsuleObstGridData / FSegmentObstGridData / FBoxObstGridData) and can serve as the dedup key. |
Output
无返回值。副作用:回调的副作用(本函数只读)。
No return value. Side effects: those of the callback (this function is read-only).
回收空块:移除所有无占用单元的块,并同步收掉簇索引(Agent/Obstacle 版先收集候选簇,再检查簇覆盖范围内是否还有块,无则从 *OccupiedClusters 移除;Loot 无簇层)。三个公开包装器 ShrinkAgentGrid / ShrinkObstacleGrid / ShrinkLootGrid 各调用对应的 ShrinkGrid_Internal 重载,ShrinkGrids 依序调用全部三个。
Reaps empty blocks: removes all blocks without occupied cells and prunes cluster indices accordingly (the Agent/Obstacle versions collect candidate clusters first, then check whether any block remains inside the cluster's footprint and remove the cluster coord from *OccupiedClusters if not; Loot has no cluster layer). The three public wrappers ShrinkAgentGrid / ShrinkObstacleGrid / ShrinkLootGrid each call the matching ShrinkGrid_Internal overload; ShrinkGrids calls all three in order.
Input
无参数。
No parameters.
Output
无返回值。副作用:从三套网格移除空块,从簇索引移除空簇。
No return value. Side effects: removes empty blocks from the three grids and empty clusters from the cluster indices.
把每个 agent 单元内的 Agents 按 UID 升序排序(并行,每单元一个任务)。先收集全部块坐标并按 X→Y→Z 排序保证确定性遍历,再收集占用单元。头文件注明:确定性排序对 None 与 Randomize 模式的确定性查询仍是必需的(它们按收集序输出/洗牌),NearToFar/FarToNear 因候选排序自带 UID tiebreak 而自足。由 MassBattleGridUpdateProcessor 在 bDeterministic 时每帧调用,作为命令排序之外的快速路径安全网。
Sorts Agents within each cell by UID ascending (parallel, one task per cell). Block coords are first collected and sorted by X→Y→Z for deterministic traversal, then occupied cells are gathered. The header notes that sorted order is still required for deterministic None/Randomize-mode queries (they emit/shuffle candidates in collection order), while NearToFar/FarToNear are self-sufficient (candidate sort with UID tie-break). Called every frame by MassBattleGridUpdateProcessor when bDeterministic, as a safety net on top of the command sort.
Input
无参数。
No parameters.
Output
无返回值。副作用:重排所有占用 agent 单元内的 Agents 顺序。
No return value. Side effect: reorders Agents inside all occupied agent cells.
障碍单元排序:胶囊/盒按 UID,样条段按 GroupID 再 Index;动态与静态六组数组各自排序;动态/静态占用位任一置位即视为占用单元。并行处理。
Obstacle cell sorting: capsules/boxes by UID, segments by GroupID then Index; all six dynamic/static arrays sorted independently; a cell is occupied when either the dynamic or static bit is set. Processed in parallel.
Input
无参数。
No parameters.
Output
无返回值。副作用:重排全部占用障碍单元内的数据顺序。
No return value. Side effect: reorders data inside all occupied obstacle cells.
战利品单元排序:每单元内按 UID 升序,并行处理。保证并行注册时(命令排序之外的快速路径)的确定性收集序。
Loot cell sorting: each cell's Loots sorted by UID ascending, in parallel. Guarantees deterministic collection order for parallel registrations (the fast path outside the command sort).
Input
无参数。
No parameters.
Output
无返回值。副作用:重排全部占用战利品单元内的 Loots 顺序。
No return value. Side effect: reorders Loots inside all occupied loot cells.
压力场格网缓存重算(Initialize 调用):格宽下限 0.001 后缓存逆格宽 PressureInvCellSizeCache;每块格数 W×H(各轴下限 1,checkf 校验乘积 int32 溢出)推导逐轴块世界尺寸 PressureBlockWorldSizeCache(默认 256×200cm = 每边 51200uu)及其逆缓存。存储惰性——块每帧由 ResetPressureField 从沉积推导创建,此处不分配任何数组。
Recomputes the pressure lattice caches (called from Initialize): floors the cell size at 0.001 and caches its inverse (PressureInvCellSizeCache); derives the per-axis block world size (PressureBlockWorldSizeCache, default 256×200 cm = 51200 uu per side) and its inverse from the per-block cell count W×H (each axis floored at 1, checkf for int32 overflow on the product). Storage is lazy — blocks are created per frame by ResetPressureField from deposits; no arrays are allocated here.
Input
无参数。
No parameters.
Output
无返回值。副作用:写 PressureInvCellSizeCache / PressureBlockWorldSizeCache / PressureInvBlockWorldSizeCache,不分配存储。
No return value. Side effects: writes PressureInvCellSizeCache / PressureBlockWorldSizeCache / PressureInvBlockWorldSizeCache; allocates no storage.
每帧 game-thread 重置:从沉积推导本帧活跃块列表(纯函数——列表是沉积块坐标的去重集合,内容与顺序无关,双端一致)。空列表即清场(PressureBlocks.Empty(),采样读 0)——本帧无沉积方时不再保留上一帧扩散值推着 agent 跑。非空时:① 销毁列表外的全部块(内存跟随战场;刻意不做 Num() 门——活跃集"平移但不减员"时幽灵块会持上一帧扩散值渗入邻块、泄漏各端私有历史,resync 后致命,场不入快照且无其他重置点);② 保留块 Memzero Front(FFix64 是可平凡清零的 Q31.32 聚合,零内存即 FFix64(0));③ 缺失块零初始化创建。块创建/销毁仅此一处 game-thread 入口,并行段只读冻结 TMap;块创建序不影响任何结果(所有消费方构造上序无关)。由 MassBattleGridUpdateProcessor 每帧调用(:195 有沉积传活跃列表,:208 无沉积传空列表)。
Per-frame game-thread reset: derives this frame's active block list from deposits (a pure function — the deduped set of deposit block coords, content- and order-independent, identical on both peers). An empty list wipes the field (PressureBlocks.Empty(), samplers read 0) — with no depositors this frame, last frame's diffused values no longer push agents around. Non-empty: ① destroys every block outside the list (memory follows the battle; deliberately no Num() gate — an active set that shifts without shrinking would leave ghost blocks holding last frame's diffused values, diffusing into neighbours and leaking peer-specific history, fatal after resync since the field is snapshot-exempt with no other reset point); ② memzeroes retained Fronts (FFix64 is a trivially-zeroable Q31.32 aggregate — zeroed memory IS FFix64(0)); ③ creates missing blocks zeroed. This is the only game-thread entry point for block create/destroy; parallel passes read the frozen TMap, and block creation order cannot influence any result (every consumer is order-insensitive by construction). Called every frame by MassBattleGridUpdateProcessor (:195 with the active list when there are deposits, :208 with an empty list otherwise).
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
ActiveBlocks | const TArray<FIntPoint>& | 本帧活跃块坐标列表(去重;顺序任意)。This frame's active block coords (deduped; order irrelevant). |
Output
无返回值。副作用:销毁列表外块、清零保留块 Front、零初始化创建缺失块;空列表清空 PressureBlocks。
No return value. Side effects: destroys blocks outside the list, zeroes retained Fronts, creates missing blocks zeroed; an empty list empties PressureBlocks.
把压力沉积并行原子散射进各块 Front:MBParallelFor 逐条把 FFix64::FromFloat(D.Amount) 的原始 int64 经 FPlatformAtomics::InterlockedAdd 加到 (BlockX, BlockY) 块的 Front[LocalIdx]。FFix64 精确整数加可交换——任意应用(交错)顺序结果逐位相同,无需预排序(bDeterministic 在内也无例外),这是 gather→排序→串行 flush 模式的一个可证明确定性例外。块必须已由 ResetPressureField 预建,本遍只读冻结 TMap;LocalIdx 越界或块缺失的条目被跳过。线程本地"上块"缓存(同一个体的脚印沉积在合并缓冲中连续且同块,常见情况一次整数比较替代一次 TMap 哈希),代数计数器为进程级(单进程 PIE 的监听服务器 + 客户端世界共用 worker 池,按实例计数会跨世界别名、把沉积写进另一个世界的块)。由 MassBattleGridUpdateProcessor 在 ResetPressureField 后调用(:198)。
Parallel atomic scatter of pressure deposits into block Fronts: MBParallelFor adds the raw int64 of FFix64::FromFloat(D.Amount) to Front[LocalIdx] of the (BlockX, BlockY) block via FPlatformAtomics::InterlockedAdd. FFix64 exact integer adds commute — the result is bit-identical under any application (interleaving) order, so no pre-sort is needed (bDeterministic included); this is a provably-deterministic exception to the gather→sort→serial-flush pattern. Blocks must already exist (created by ResetPressureField) and the pass only reads the frozen TMap; entries with an out-of-range LocalIdx or a missing block are skipped. A thread-local last-block cache trades a TMap hash for one integer compare in the common case (one agent's footprint deposits are consecutive and share a block), guarded by a process-wide generation counter (single-process PIE runs the listen-server + client worlds over one worker pool; a per-instance counter would alias across worlds and deposit into the other world's blocks). Called by MassBattleGridUpdateProcessor after ResetPressureField (:198).
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
Deposits | const TArray<FPressureDeposit>& | (未排序的)沉积数组;FPressureDeposit 携带块坐标 BlockX/BlockY、块内线性索引 LocalIdx、量 Amount 与诊断归因 AgentUniqueID(不再是排序键)。(Unsorted) deposit array; FPressureDeposit carries block coords BlockX/BlockY, in-block linear index LocalIdx, amount Amount, and the diagnostic attribution AgentUniqueID (no longer a sort key). |
Output
无返回值。副作用:原子累加各活跃块的 Front(FFix64)。
No return value. Side effect: atomically accumulates into each active block's Front (FFix64).
Jacobi 扩散:对每个活跃块的 Front<->Back 执行 PressureDiffusionIterations 次 5 点 Laplace 模板 FFix64 迭代。先一次性快照活跃块并预解析每块 4 个侧邻(并行任务完全不碰 TMap);每迭代 ParallelFor 以(块,行)展平任务写互斥 Dst 行、只读 Front(含经预解析指针读邻块接缝行/列);迭代后先全部 Swap(Front, Back)、再统一重解析接缝指针——顺序无关性只在这两个独立循环下成立(块序随合并沉积序走,resync 后双端合法地不同)。缺失侧邻读 0(活动区边缘 zero-Dirichlet,与旧全局边界同规则)。PressureDiffusionAlpha 转为 FFix64 后夹到 [0, 0.25](5 点 Laplace 稳定性要求),迭代数为 0 或 Alpha ≤ 0 时直接返回。由 MassBattleGridUpdateProcessor 每帧在沉积后调用(:200)。
Jacobi diffusion: runs PressureDiffusionIterations passes of the 5-point Laplace stencil in FFix64 over each active block's Front<->Back. Active blocks are snapshotted once and each block's 4 side-neighbours pre-resolved (parallel tasks never touch the TMap); each pass runs a ParallelFor over flattened (block, row) tasks that write a disjoint Dst row and read Front only (neighbour-block seam rows/cols through the pre-resolved pointers); after each pass ALL blocks Swap(Front, Back) first, THEN all seam pointers are re-resolved — order-independence holds only with these two separate loops (block order follows merged-deposit order, which legitimately differs between peers after resync). Missing side-neighbours read as zero (zero-Dirichlet at the active-region frontier, the same rule the legacy global boundary applied). PressureDiffusionAlpha converts to FFix64 and clamps to [0, 0.25] (5-point Laplace stability); returns early when iterations are 0 or Alpha ≤ 0. Called every frame by MassBattleGridUpdateProcessor after deposition (:200).
Input
无参数(迭代次数与强度来自配置成员)。
No parameters (iteration count and strength come from the config members).
Output
无返回值。副作用:各活跃块 Front/Back 轮换;最终扩散结果在各块 Front。
No return value. Side effects: Front/Back swap per active block; the final diffused result lives in each block's Front.
在世界 XY 处双线性采样压力——FFix 核心(SamplePressureFx)的 float 边界转换(直接转发后 ToFloat),供物理漂移/可视化消费方。活跃块外(含 PressureBlocks 为空)读 0。
Bilinear pressure sample at world XY — the float boundary conversion of the FFix core (SamplePressureFx; forwards directly then ToFloat), for physics-drift / viz consumers. Reads 0 outside active blocks (including when PressureBlocks is empty).
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
WorldPos2D | const FVector2f& | 世界 XY 坐标(cm)。World XY position (cm). |
Output
返回采样压力值(float);活跃块外为 0。
Returns the sampled pressure (float); 0 outside active blocks.
压力梯度(∂P/∂X, ∂P/∂Y):直接转发 SamplePressureGradientFx 后逐分量 ToFloat。中心差分在单元空间、缩放为每 cm 单位;活跃块外(含空场)返回零向量。由 MassBattleAgentMoveProcessor(:4243/:5981)与 MassBattleAgentMoveProcessorFP(:5960)在移动热循环中调用(FP 的确定性压力主路径走 FFix 版 SamplePressureGradientFx,:4223)。
Pressure gradient (∂P/∂X, ∂P/∂Y): forwards directly to SamplePressureGradientFx and converts per-component with ToFloat. Central differences in cell space, scaled to per-cm units; returns the zero vector outside active blocks (empty field included). Called from the move hot loop of MassBattleAgentMoveProcessor (:4243/:5981) and MassBattleAgentMoveProcessorFP (:5960); the FP variant's deterministic pressure main path goes through the FFix version SamplePressureGradientFx (:4223).
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
WorldPos2D | const FVector2f& | 世界 XY 坐标(cm)。World XY position (cm). |
Output
返回梯度向量(per-cm 单位);活跃块外返回零向量。
Returns the gradient vector (per-cm units); zero vector outside active blocks.
FFix 主采样器:在世界 XY 处以 FFix64 双线性采样压力。坐标经 FromFloat 一次性转换后全程定点(逆格宽、0.5 偏移到单元中心、Floor、Lerp);单块快路径——一次解析 (X0,Y0) 所在块,4 个采样点都在块内时直接索引,仅罕见的跨缝由 PressureTap 退回 TMap 查找;界外角点读 0。需要位级一致性的消费方(锁步移动)走本函数——上面的 float 对是本核心的边界转换,两者结构上不可能分叉。由 MassBattleAgentMoveProcessorFP 在移动热循环中调用(:4223)。
FFix primary sampler: bilinear FFix64 pressure sample at world XY. Coordinates convert via FromFloat once and stay fixed-point throughout (inverse cell size, 0.5 shift to cell centers, Floor, Lerp); single-block fast path — the (X0,Y0) block is resolved once, the 4 taps direct-index while they stay inside it, and only the rare seam straddle falls back to a TMap Find in PressureTap; out-of-bounds corners read 0. Consumers that need bit-exactness (lockstep movement) go through this function — the float pair above are boundary conversions of this core, so the two can never diverge structurally. Called from the move hot loop of MassBattleAgentMoveProcessorFP (:4223).
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
WorldPos2D | const FFixVector2& | 世界 XY 定点坐标。World XY fixed-point position. |
Output
返回 FFix64 采样值;活跃块外(含空场)返回 FFix64::Zero()。
Returns the FFix64 sample; FFix64::Zero() outside active blocks (empty field included).
FFix 主梯度采样器:(∂P/∂X, ∂P/∂Y) 中心差分——X/Y 各在 ±1 格处执行一次与 SamplePressureFx 完全相同的 FFix 双线性序列,差分除以 2×格宽得到每 cm 单位的 FFix64 梯度(结果与旧单网格核心逐位一致)。一次种子解析中心采样点所在块,±1 格采样绝大多数同块(跨缝时 PressureTap 退回 Find)。由 MassBattleAgentMoveProcessorFP 在移动热循环中调用(:4223)。
FFix primary gradient sampler: (∂P/∂X, ∂P/∂Y) via central differences — each axis runs the exact SamplePressureFx FFix bilinear sequence at ±1 cell, and the difference divided by 2×cell size yields the per-cm FFix64 gradient (results stay bit-identical to the legacy single-grid core). One seed resolves the centre tap's block; the ±1-cell taps hit the same block in the overwhelming majority of samples (PressureTap falls back to a Find on the rare straddle). Called from the move hot loop of MassBattleAgentMoveProcessorFP (:4223).
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
WorldPos2D | const FFixVector2& | 世界 XY 定点坐标。World XY fixed-point position. |
Output
返回 FFixVector2 梯度(per-cm 单位);空场返回零向量。
Returns the FFixVector2 gradient (per-cm units); zero vector when the field is empty.
单元占用查询(内联):转发到对应网格的 IsCellOccupied_Internal——块存在时读占用位(障碍为动态 | 静态),块缺失返回 false。
Cell occupancy queries (inline): forward to the matching grid's IsCellOccupied_Internal — reads the occupancy bit when the block exists (dynamic OR static for obstacles), false when the block is missing.
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
Coord | const FIntVector& | 全局网格坐标。Global grid coordinate. |
Output
返回该单元是否有注册数据;块缺失时 false。
Returns whether the cell holds registered data; false when the block is missing.
块感知的占用单元范围迭代模板:保持与朴素逐单元循环一致的全局 Z→Y→X 迭代顺序,但缓存当前块指针与块原点,把 TMap 查找从 2×N 个单元降到约 N 次块切换。障碍版同时检查动态与静态占用位。命中单元调用 Callback(Cell)。
Block-aware occupied-cell range iteration templates: preserve the same global Z→Y→X iteration order as a naive per-cell loop while caching the current block pointer and origin, reducing TMap lookups from 2×N cells to ~N block transitions. The obstacle version checks both dynamic and static occupancy bits. Callback(Cell) is invoked per occupied cell.
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
MinCoord / MaxCoord | const FIntVector& | 全局坐标范围(含端点)。Global coordinate range (inclusive). |
Callback | Func&& | 对每个占用单元调用的回调(接收 const FHashGrid*Cell&)。Callback invoked per occupied cell (receives const FHashGrid*Cell&). |
Output
无返回值。副作用:回调的副作用(本函数只读)。
No return value. Side effects: those of the callback (this function is read-only).
Agent / Obstacle / Loot 三套同构的坐标转换器(单位:位置 cm,坐标 = 单元索引空间,向下取整)。统一模式:*LocationToCoord = floor((Location - GridOrigin) * InvCellSize);*CoordToLocation = Coord * CellSize + CellSize*0.5 + GridOrigin(单元中心);*GlobalToBlockCoord = floor(Global / BlockDim);*GlobalToLocalCoord = 正模运算;*LocalCoordToIndex = (Z*DimY + Y)*DimX + X;*IndexToLocalCoord 逆运算。块→簇映射(*BlockToClusterCoord)以世界原点为 cluster (0,0) 中心:floor((Block + Dim/2) / Dim),Z 直通。
Three isomorphic converter sets for Agent / Obstacle / Loot (units: position cm, coords = cell index space, floored). Uniform pattern: *LocationToCoord = floor((Location - GridOrigin) * InvCellSize); *CoordToLocation = Coord * CellSize + CellSize*0.5 + GridOrigin (cell center); *GlobalToBlockCoord = floor(Global / BlockDim); *GlobalToLocalCoord (positive modulo); *LocalCoordToIndex = (Z*DimY + Y)*DimX + X; *IndexToLocalCoord is the inverse. The block→cluster mapping (*BlockToClusterCoord) centers the world origin at cluster (0,0): floor((Block + Dim/2) / Dim), Z passes through.
Input
| 函数 Function | 输入 Input | 输出 Output |
|---|---|---|
AgentCoordToLocation / ObstCoordToLocation / LootCoordToLocation | Coord(单元索引)Coord (cell index) | 单元中心世界坐标。Cell center world position. |
AgentLocationToCoord / ObstLocationToCoord / LootLocationToCoord | Location(世界位置,cm)Location (world pos, cm) | 所在单元索引(向下取整)。Containing cell index (floored). |
*GlobalToBlockCoord | GlobalCoordGlobalCoord | 块坐标(网格键)。Block coord (the grid key). |
*GlobalToLocalCoord | GlobalCoordGlobalCoord | 块内单元坐标(正模)。In-block cell coord (positive modulo). |
*LocalCoordToIndex | LocalCoordLocalCoord | 扁平单元索引。Flat cell index. |
AgentIndexToLocalCoord / ObstIndexToLocalCoord / LootIndexToLocalCoord | Index(扁平索引)Index (flat index) | 块内单元坐标。In-block cell coord. |
AgentBlockToClusterCoord / ObstBlockToClusterCoord | BlockCoordBlockCoord | 簇坐标(原点居中约定)。Cluster coord (origin-centered convention). |
Output
全部为纯计算,无副作用。
All pure computation, no side effects.
单元访问器(内联):坐标版转发 GetCellAt_Internal(块缺失返回静态空单元引用 Empty*Cell),位置版先经 *LocationToCoord 转换再查。
Cell accessors (inline): the coord versions forward to GetCellAt_Internal (missing block returns the static empty-cell reference Empty*Cell); the location versions convert via *LocationToCoord first.
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
Coord | const FIntVector& | 全局网格坐标。Global grid coordinate. |
Location | const FVector& | 世界位置(位置版重载)。World position (location overload). |
Output
返回单元常量引用;块缺失返回 EmptyAgentCell / EmptyObstCell / EmptyLootCell(静态空单元,安全读)。
Returns a const cell reference; EmptyAgentCell / EmptyObstCell / EmptyLootCell (static empty cells, safe to read) when the block is missing.
球体索敌的单元收集核心:Radius < 0 返回空;取中心 ± 半径的 AABB 盒算出坐标范围;经 ExecuteCellTrace 遍历候选单元,几何测试为"中心到单元 AABB 最近点距离 ≤ 半径"。支持全部三类网格。家族包装器:8 个公开函数(SphereTraceForAgentCells ×2(带/不带 Query)、SphereTraceForObstacleCells、SphereTraceForLootCells 及各自的 Sorted 变体)全部一行转发,默认 SortMode = None、SortFrom = 零向量;Sorted 变体透传排序参数。
Core cell collection for sphere traces: returns empty when Radius < 0; derives the coordinate range from the center ± radius AABB; iterates candidate cells via ExecuteCellTrace; the geometry test is "distance from center to closest point in the cell AABB ≤ radius". Supports all three grid types. Family wrappers: 8 public functions (SphereTraceForAgentCells ×2 (with/without Query), SphereTraceForObstacleCells, SphereTraceForLootCells, plus their Sorted variants) are one-line forwards with default SortMode = None and SortFrom = zero vector; Sorted variants pass the sort parameters through.
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
Center | const FVector& | 球心(cm)。Sphere center (cm). |
Radius | float | 半径(cm);负数返回空。Radius (cm); negative returns empty. |
SortMode / SortFrom | ESortMode / const FVector& | 结果排序模式与排序参考点(Sorted 变体)。Result sort mode and sort reference point (Sorted variants). |
GridType | EGridType | 目标网格。Target grid. |
bOnlyOccupied | bool | true 只返回占用单元,false 遍历范围内全部坐标。true returns only occupied cells; false iterates all coords in range. |
Query | const FEntityQuery* | 可选实体查询,用于 block 级 composition 剪枝(可为 nullptr)。Optional entity query for block-level composition pruning (may be nullptr). |
Output
返回命中单元的全局坐标数组(排序方式决定顺序:None/Randomize/NearToFar/FarToNear);非法半径返回空数组。无副作用。
Returns the global coords of hit cells (order depends on the sort mode: None/Randomize/NearToFar/FarToNear); empty array for an invalid radius. No side effects.
球体扫掠的单元收集核心:Start == End(KINDA_SMALL_NUMBER 容差)退化为 SphereTraceForCells_Internal;取两端 ± 半径的 AABB 并集为范围;几何测试为"线段最近点到单元中心 ≤ TotalRadius",其中 TotalRadius = Radius + CellHalfSize.GetMax()(保守放大)。支持全部三类网格;7 个包装器一行转发。
Core cell collection for sphere sweeps: Start == End (within KINDA_SMALL_NUMBER) degenerates to SphereTraceForCells_Internal; the range is the AABB union of both endpoints ± radius; the geometry test is "closest point on the segment to the cell center ≤ TotalRadius" with TotalRadius = Radius + CellHalfSize.GetMax() (conservatively inflated). Supports all three grid types; 7 wrappers forward in one line.
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
Start / End | const FVector& | 扫掠起止点(cm)。Sweep start/end (cm). |
Radius | float | 球半径(cm);负数返回空。Sphere radius (cm); negative returns empty. |
| 其余 | — | 与 Sphere 家族相同。Same as the Sphere family. |
Output
返回命中单元坐标数组;退化/非法输入返回空数组。无副作用。
Returns hit cell coords; empty for degenerate/invalid input. No side effects.
OBB 盒索敌的单元收集核心:先把旋转盒的轴对齐半边长投影到世界轴(|Axis| * Range 之和)得世界 AABB;几何测试:朝向为单位四元数时退化为 AABB-vs-AABB 快速比较,否则逐单元 Intersects_AABB_OBB(15 轴 SAT)。支持全部三类网格;8 个包装器一行转发。
Core cell collection for OBB box traces: first projects the rotated box's axis-aligned half extents onto the world axes (|Axis| * Range summed) to get the world AABB; geometry test: identity orientation degenerates to a fast AABB-vs-AABB compare, otherwise per-cell Intersects_AABB_OBB (15-axis SAT). Supports all three grid types; 8 wrappers forward in one line.
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
Center | const FVector& | 盒中心(cm)。Box center (cm). |
Range3D | const FVector& | 三个轴的半边长(cm)。Per-axis half extents (cm). |
Orientation | const FQuat& | 盒朝向;单位四元数走 AABB 快速路径。Box orientation; identity takes the AABB fast path. |
| 其余 | — | 与 Sphere 家族相同。Same as the Sphere family. |
Output
返回与盒相交的单元坐标数组。无副作用。
Returns cell coords intersecting the box. No side effects.
OBB 盒扫掠的单元收集核心:Start == End 退化为 BoxTraceForCells_Internal;单元先按扫掠向量做闵可夫斯基膨胀(中心减半向量、半边长加半向量的绝对值),再与起点处的静态盒做 SAT 测试。仅支持 Agent/Obstacle(三元表达式把非 Agent 一律当 Obstacle,无 Loot 分支);7 个包装器一行转发。
Core cell collection for OBB box sweeps: Start == End degenerates to BoxTraceForCells_Internal; each cell is Minkowski-inflated by the sweep vector (center minus half the vector, half extents plus half the absolute vector) and tested against the static box at the start via SAT. Agent/Obstacle only (the ternary treats any non-Agent grid as Obstacle; no Loot branch); 7 wrappers forward in one line.
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
Start / End | const FVector& | 扫掠起止点(cm)。Sweep start/end (cm). |
| 其余 | — | 与 Box 家族相同。Same as the Box family. |
Output
返回与扫掠盒相交的单元坐标数组。无副作用。
Returns cell coords intersecting the swept box. No side effects.
胶囊索敌的单元收集核心(1.19.20 新增):Radius 或 HalfHeight 为负返回空。查询轴段 = Center ± Orientation·Up × HalfHeight;粗筛包围盒为轴段 AABB 膨胀 Radius;几何测试为"轴段与膨胀 Radius 后的单元 AABB 相交"(SegmentIntersectsAABB,精确)。支持全部三类网格;8 个包装器(Agent ×2 带/不带 Query、Obstacle、Loot 及各自 Sorted 变体)一行转发,默认 SortMode = None。
Core cell collection for capsule traces (new in 1.19.20): returns empty when Radius or HalfHeight is negative. The query axis segment is Center ± Orientation·Up × HalfHeight; the broad-phase bounds are the axis segment's AABB inflated by Radius; the geometry test is "axis segment intersects the cell AABB inflated by Radius" (SegmentIntersectsAABB, exact). Supports all three grid types; 8 wrappers (Agent ×2 with/without Query, Obstacle, Loot, plus their Sorted variants) forward in one line with default SortMode = None.
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
Center | const FVector& | 胶囊中心(cm)。Capsule center (cm). |
Radius / HalfHeight | float | 胶囊半径与轴杆半高(cm);任一为负返回空。Capsule radius and shaft half-height (cm); either negative returns empty. |
Orientation | const FQuat& | 胶囊朝向(其 up 即胶囊轴)。Capsule orientation (its up is the capsule axis). |
| 其余 | — | 与 Sphere 家族相同。Same as the Sphere family. |
Output
返回与胶囊相交的单元坐标数组;非法参数返回空数组。无副作用。
Returns cell coords intersecting the capsule; empty for invalid parameters. No side effects.
胶囊扫掠的单元收集核心(1.19.20 新增):扫掠体积 = 胶囊轴线段与扫掠向量 [0, End-Start] 的闵可夫斯基和再膨胀 Radius(平行四边形 ⊕ 球)。精确单元测试:胶囊轴线段与"单元 AABB 膨胀 Radius、平移 -SweepVector/2、半边长 +|SweepVector|/2"相交(闵可夫斯基结合律把扫掠化为静态 AABB 测试);查询轴段取扫掠起点处(Start ± Up×HalfHeight),粗筛为平行四边形 4 角 AABB 膨胀 Radius。_Internal 按 GridType 分派支持全部三类网格;6 个包装器(Agent ×2 带/不带 Query、Obstacle 及各自 Sorted 变体)一行转发,无 Loot 包装器。
Core cell collection for capsule sweeps (new in 1.19.20): the swept volume is the Minkowski sum of the capsule axis segment and the sweep VECTOR [0, End-Start], inflated by Radius (parallelogram ⊕ sphere). Exact cell test: the capsule axis segment intersects the cell AABB inflated by Radius, translated by -SweepVector/2, with half extents +|SweepVector|/2 (Minkowski associativity turns the sweep into a static AABB test); the query axis segment sits at the sweep start (Start ± Up×HalfHeight), and the broad-phase is the AABB of the parallelogram's 4 corners inflated by Radius. The _Internal dispatches on GridType and supports all three grids; 6 wrappers (Agent ×2 with/without Query, Obstacle, plus their Sorted variants) forward in one line — no Loot wrapper.
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
Start / End | const FVector& | 扫掠起止点(cm)。Sweep start/end (cm). |
Radius / HalfHeight / Orientation | — | 与 Capsule 家族相同。Same as the Capsule family. |
| 其余 | — | 与 Sphere 家族相同。Same as the Sphere family. |
Output
返回与扫掠胶囊相交的单元坐标数组;非法参数返回空数组。无副作用。
Returns cell coords intersecting the swept capsule; empty for invalid parameters. No side effects.
扇形索敌的单元收集核心:Radius/Height < 0 或 AngleDegrees ≤ 0 返回空。方向先压平到 XY 平面(GetSafeNormal),两条边界法线绕 UpVector 旋转 ±(90° + 角/2)得到;几何测试为 2D 半径(中心到单元 AABB 最近 XY 点)+ Z 高度(单元 Z 范围与中心 ± 半高重叠)+ 半平面测试(单元 AABB 相对法线的投影半径;AngleDegrees < 360 才做角度测试)。仅支持 Agent/Obstacle;7 个包装器一行转发。
Core cell collection for sector traces: empty when Radius/Height < 0 or AngleDegrees ≤ 0. The direction is flattened to the XY plane (GetSafeNormal); two boundary normals rotate around UpVector by ±(90° + angle/2). The geometry test is: 2D radius (center to closest XY point in the cell AABB) + Z height (cell Z range overlapping center ± half height) + half-plane tests (projected radius of the cell AABB onto each normal; the angle test only runs when AngleDegrees < 360). Agent/Obstacle only; 7 wrappers forward in one line.
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
Center | const FVector& | 扇形中心(cm)。Sector center (cm). |
Radius | float | 扇形半径(cm)。Sector radius (cm). |
Height | float | Z 向高度(cm),中心上下各一半。Height along Z (cm), half above and below the center. |
Direction | const FVector& | 朝向(XY 分量被使用,压平后归一化)。Facing direction (XY components used, flattened and normalized). |
AngleDegrees | float | 张角(度);360 表示全向(跳过角度测试)。Aperture in degrees; 360 means omnidirectional (angle test skipped). |
| 其余 | — | 与 Sphere 家族相同。Same as the Sphere family. |
Output
返回扇形内的单元坐标数组;非法参数返回空数组。无副作用。
Returns cell coords inside the sector; empty for invalid parameters. No side effects.
视锥索敌的单元收集核心:SelectionPoints 必须恰好 4 个,否则 UE_LOG 警告并返回空。由视点 + 4 个选择点构造 4 个视锥平面(点序环绕);粗筛包围盒(视点 + 选择点,按最大单元尺寸外扩)确定坐标范围;几何测试为逐平面"中心到平面距离 ≥ -投影半径"(单元 AABB 在平面法线上的投影半径)。仅支持 Agent/Obstacle;7 个包装器一行转发。
Core cell collection for view-frustum traces: SelectionPoints must be exactly 4, otherwise a UE_LOG warning fires and an empty array is returned. Four frustum planes are built from the view point and the 4 selection points (wrapped order); the broad-phase bounding box (view point + selection points, expanded by the max cell size) defines the coord range; the geometry test per plane is "center-to-plane distance ≥ -projected radius" (cell AABB projected onto the plane normal). Agent/Obstacle only; 7 wrappers forward in one line.
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
ViewPoint | const FVector& | 视点(cm)。View point (cm). |
SelectionPoints | const TArray<FVector>& | 4 个视锥角点,顺序环绕。4 frustum corner points, in wrapped order. |
| 其余 | — | 与 Sphere 家族相同。Same as the Sphere family. |
Output
返回视锥内的单元坐标数组;选择点数量不是 4 时返回空数组并输出警告日志。无副作用。
Returns cell coords inside the frustum; empty array plus a warning log when the selection point count is not 4. No side effects.
圆锥索敌的单元收集核心:Length ≤ 0 或 AngleDegrees ≤ 0 返回空。粗筛包围盒从原点延伸到基底中心(半径 = 长度 × tan(角));几何测试:单元盒包含原点则直接命中,否则按单元中心算"轴向投影在 [-半长, 长度+半长] 内且垂直距离 ≤ (该投影处的圆锥半径 + 半长)"。
Core cell collection for cone traces: empty when Length ≤ 0 or AngleDegrees ≤ 0. The broad-phase AABB spans from the origin to the base center (radius = length × tan(angle)); geometry test: a cell box containing the origin hits directly, otherwise the cell center's axial projection must lie within [-half-extent, length + half-extent] and its perpendicular distance must be ≤ (cone radius at that projection + half-extent).
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
Origin | const FVector& | 圆锥顶点(cm)。Cone apex (cm). |
Direction | const FVector& | 锥轴方向(归一化后使用)。Cone axis direction (normalized for use). |
Length | float | 锥长(cm)。Cone length (cm). |
AngleDegrees | float | 半张角(度)。Half aperture (degrees). |
| 其余 | — | 与 Sphere 家族相同。Same as the Sphere family. |
Output
返回圆锥内的单元坐标数组;非法参数返回空数组。无副作用。
Returns cell coords inside the cone; empty for invalid parameters. No side effects.
基于分离轴定理(SAT)的 AABB 与 OBB 相交测试:测试 AABB 3 轴 + OBB 3 轴 + 9 个叉积轴(近零叉积跳过),共最多 15 轴;任一轴上投影分离即返回 false。供 BoxTraceForCells_Internal 与 BoxSweepForCells_Internal 的几何测试使用。
AABB vs OBB intersection test based on the Separating Axis Theorem (SAT): tests the 3 AABB axes + 3 OBB axes + 9 cross-product axes (near-zero cross products skipped), up to 15 axes total; projection separation on any axis returns false. Used by the geometry tests of BoxTraceForCells_Internal and BoxSweepForCells_Internal.
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
AABB_Center / AABB_HalfExtents | const FVector& | AABB 中心与半边长。AABB center and half extents. |
OBB_Center / OBB_HalfExtents / OBB_Quat | const FVector& / const FVector& / const FQuat& | OBB 中心、半边长与朝向。OBB center, half extents, and orientation. |
Output
返回两盒是否相交(相交 true,存在分离轴 false)。无副作用。
Returns whether the boxes intersect (true) or a separating axis exists (false). No side effects.
静态视线检查:从 Origin 到目标表面(终点 = 目标位置 - 方向 × 目标半径,与扇形索敌的障碍过滤约定一致——贴墙目标从 agent 一侧仍算可见)做 object-type trace。障碍列表为空或世界解析失败时视为可见返回 true;CheckRadius ≤ 0 用 LineTraceSingleByObjectType,否则用 SweepSingleByObjectType(球形)。返回 true 表示视线未被遮挡。抽出来供 Trace 处理器的 skip-trace 预检、玩家目标路径与 BP 代码共享。
Static line-of-sight check: an object-type trace from Origin to the target's surface (endpoint = target location - direction × TargetRadius, matching the sector trace's obstacle-filter convention — a target against a wall still counts as visible from the agent's side). An empty obstacle list or failed world resolution counts as visible (returns true); CheckRadius ≤ 0 uses LineTraceSingleByObjectType, otherwise SweepSingleByObjectType (spherical). Returns true when the line is unblocked. Extracted so the Trace processor's skip-trace pre-check, the player-target path, and BP code share one implementation.
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
WorldContext | UObject* | 世界上下文;解析失败视为可见。World context; resolution failure counts as visible. |
Origin / TargetLocation | const FVector& | 射线起终点(cm)。Ray start/end (cm). |
TargetRadius / CheckRadius | const float | 目标半径(终点收缩量)与检查球半径(cm;≤0 用线 trace)。Target radius (endpoint shrink) and check sphere radius (cm; ≤0 uses a line trace). |
ObstacleList | const TArray<TEnumAsByte<EObjectTypeQuery>>& | 遮挡 object type 列表;为空视为可见。Occluding object-type list; empty counts as visible. |
Output
返回视线是否未被遮挡;障碍列表为空或世界解析失败时返回 true。无副作用。
Returns whether the line of sight is unblocked; true when the obstacle list is empty or the world cannot be resolved. No side effects.
已废弃的 BP 节点(DeprecatedFunction,提示改用 MassBattleFuncLib 对应函数)。实体级球体索敌:重置输出,KeepCount == 0 或子系统缺失时提前返回;构造 FTraceContext(IgnoreSet 忽略集、SeenHashes 按 UID 去重多格 agent、缓存的 EntityQuery、方向桶剪枝状态);几何检查用"球心到胶囊轴线最近点 ≤ 半径 + ColliderRadius";经 ExecuteTraceWithPriority 按优先级分层执行;最后 RewriteEntityLocationsFromLocating 把结果位置改写为权威 FLocating::Location,Hit = !Results.IsEmpty();编辑器下按 DrawDebugConfig 绘制调试形状。
Deprecated BP node (DeprecatedFunction; the message points to the corresponding MassBattleFuncLib function). Entity-level sphere trace: resets outputs, early-returns when KeepCount == 0 or a subsystem is missing; builds the FTraceContext (IgnoreSet, SeenHashes UID dedup for multi-cell agents, cached EntityQuery, direction-bucket prune state); the geometry check is "closest point on the capsule axis to the sphere center ≤ radius + ColliderRadius"; executes per priority level via ExecuteTraceWithPriority; finally RewriteEntityLocationsFromLocating rewrites result positions to the authoritative FLocating::Location and Hit = !Results.IsEmpty(); in-editor debug shapes follow DrawDebugConfig.
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
Hit / Results | bool& / TArray<FTraceResult>& | 输出:是否有命中与结果数组(先被重置)。Outputs: any hit and the result array (reset first). |
KeepCount | int32 | 保留数量上限;-1 = 不限(默认)。Result cap; -1 = unlimited (default). |
Origin / Radius | const FVector& / const float | 球心与半径(cm,默认 300)。Sphere center and radius (cm, default 300). |
bCheckObstacle / CheckOrigin / CheckRadius | bool / FVector / float | 障碍遮挡检查开关、检查原点与检查球半径。Obstacle occlusion toggle, check origin, and check sphere radius. |
SortMode / SortOrigin | ESortMode / FVector | 排序模式与参考点。Sort mode and reference point. |
IgnoreEntities / Query / DrawDebugConfig | FEntityArray / FMassBattleQuery / FTraceDrawDebugConfig | 忽略实体集、查询与调试绘制配置。Ignore set, query, and debug draw config. |
Output
返回 void,结果经 Hit / Results 输出。副作用:编辑器下向 UMassBattleSubsystem 的 Debug 队列写入调试形状。
Returns void; results come out via Hit / Results. Side effect: in-editor debug shapes pushed into UMassBattleSubsystem's debug queues.
已废弃的实体级球体扫掠节点。几何检查:胶囊轴与扫掠线段的 SegmentDistToSegmentSafe 距离 ≤ 半径 + ColliderRadius;点状实体退化为线段最近点测试。其余流程与 SphereTraceForAgents 相同。
Deprecated entity-level sphere sweep node. Geometry check: SegmentDistToSegmentSafe distance between the capsule axis and the sweep segment ≤ radius + ColliderRadius; point entities degenerate to a closest-point-on-segment test. Otherwise identical flow to SphereTraceForAgents.
Input
与 SphereTraceForAgents 相同,另加 Start / End 扫掠起止点。
Same as SphereTraceForAgents plus Start / End sweep endpoints.
Output
返回 void;结果经 Hit / Results 输出。副作用同前。
Returns void; results via Hit / Results. Same side effects.
已废弃的实体级扇形索敌节点。几何检查:2D 半径(Radius + ColliderRadius)、角度(Angle < 360 时方向点积 ≥ cos(角/2),方向压平到 XY)、Z 高度(半高 + 胶囊半长)。其余流程同前。
Deprecated entity-level sector trace node. Geometry check: 2D radius (Radius + ColliderRadius), angle (direction dot product ≥ cos(angle/2) when Angle < 360; direction flattened to XY), and Z height (half height + capsule half length). Otherwise identical flow.
Input
与 SphereTraceForAgents 相同,另加 Height(默认 300)、Direction(默认 ForwardVector)、Angle(默认 360)。
Same as SphereTraceForAgents plus Height (default 300), Direction (default ForwardVector), Angle (default 360).
Output
返回 void;结果经 Hit / Results 输出。副作用同前。
Returns void; results via Hit / Results. Same side effects.
已废弃的实体级 OBB 盒索敌节点。几何检查:实体位置旋转进盒局部空间后,与盒的 AABB 钳制最近点距离 ≤ 胶囊包围球半径(有轴时取半径与半高的平方和开方)。
Deprecated entity-level OBB box trace node. Geometry check: the entity position is unrotated into box-local space, and the distance to the clamped box AABB must be ≤ the capsule's bounding-sphere radius (sqrt of radius² + half-height² when the capsule has a shaft).
Input
与 SphereTraceForAgents 相同,另加 Range3D(半边长)与 Orientation(Rotator)。
Same as SphereTraceForAgents plus Range3D (half extents) and Orientation (rotator).
Output
返回 void;结果经 Hit / Results 输出。副作用同前。
Returns void; results via Hit / Results. Same side effects.
已废弃的实体级 OBB 盒扫掠节点。Start == End 直接转发 BoxTraceForAgents;否则取实体到扫掠线最近点,在该点做与 BoxTraceForAgents 相同的局部空间盒测试。
Deprecated entity-level OBB box sweep node. Start == End forwards to BoxTraceForAgents; otherwise the closest point on the sweep line is found and the same local-space box test as BoxTraceForAgents runs there.
Input
与 BoxTraceForAgents 相同,另加 Start / End。
Same as BoxTraceForAgents plus Start / End.
Output
返回 void;结果经 Hit / Results 输出。副作用同前。
Returns void; results via Hit / Results. Same side effects.
静态胶囊索敌(1.19.20 新增,非废弃;BP 经 MassBattleFuncLib::CapsuleTraceForAgents 暴露):以 Origin 为中心、轴向沿 Orientation 的 up、轴杆半高 HalfHeight、半径 Radius 的胶囊——用于竖立光柱、站桩 AoE 体积与竖向光束检测。流程与其它实体级 trace 一致:重置输出,KeepCount == 0 或子系统缺失时提前返回;构造 FTraceContext(IgnoreSet、SeenHashes 按 UID 去重、缓存的 EntityQuery、方向桶剪枝状态);FetchCells 用 CapsuleTraceForAgentCells(/Sorted);几何检查为精确的胶囊 vs 胶囊——查询轴段与 agent 碰撞体轴段的 SegmentDistToSegmentSafe 距离 ≤ Radius + ColliderRadius(ColliderHeight > 0 时 agent 轴段为 ±Up×半高,否则退化为点);经 ExecuteTraceWithPriority 分层执行,RewriteEntityLocationsFromLocating 改写结果位置,Hit = !Results.IsEmpty();编辑器下绘制调试胶囊(高 = HalfHeight×2 + Radius×2)。
Static capsule trace for agent entities (new in 1.19.20, not deprecated; exposed to Blueprint via MassBattleFuncLib::CapsuleTraceForAgents): a capsule centered at Origin, axis along Orientation's up, shaft half-height HalfHeight, radius Radius — for upright light pillars, standing AoE volumes and vertical beam checks. Same flow as the other entity-level traces: resets outputs, early-returns when KeepCount == 0 or a subsystem is missing; builds the FTraceContext (IgnoreSet, SeenHashes UID dedup, cached EntityQuery, direction-bucket prune state); FetchCells uses CapsuleTraceForAgentCells (/Sorted); the geometry check is an exact capsule-vs-capsule test — SegmentDistToSegmentSafe distance between the query axis segment and the agent collider axis segment ≤ Radius + ColliderRadius (the agent axis segment is ±Up×half-height when ColliderHeight > 0, otherwise it degenerates to a point); executes per priority level via ExecuteTraceWithPriority, rewrites result positions with RewriteEntityLocationsFromLocating, Hit = !Results.IsEmpty(); in-editor draws a debug capsule (height = HalfHeight×2 + Radius×2).
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
Hit / Results / KeepCount / Origin / Radius | — | 与 SphereTraceForAgents 相同(Radius 默认 300,另加 agent 碰撞体半径)。Same as SphereTraceForAgents (Radius defaults to 300; the agent collider radius is added). |
HalfHeight | const float | 胶囊轴杆半高(cm,默认 150),沿 Orientation 朝向上的轴杆。Capsule shaft half-height (cm, default 150) along Orientation's up. |
Orientation | const FRotator& | 胶囊轴向(up 即胶囊轴)。Capsule axis orientation (up = capsule axis). |
| 其余 | — | 与 SphereTraceForAgents 相同。Same as SphereTraceForAgents. |
Output
返回 void,结果经 Hit / Results 输出。副作用:编辑器下向 UMassBattleSubsystem 的 Debug 队列写入调试胶囊。
Returns void; results come out via Hit / Results. Side effect: in-editor debug capsules pushed into UMassBattleSubsystem's debug queues.
胶囊扫掠索敌(1.19.20 新增,非废弃;BP 经 MassBattleFuncLib::CapsuleSweepForAgents 暴露):Start == End(KINDA_SMALL_NUMBER 容差)零长度扫掠直接转发 CapsuleTraceForAgents。否则查询轴段取扫掠起点处(Start ± Up×HalfHeight);几何检查为精确的 agent 碰撞体胶囊 vs 扫掠体积——agent 轴段须进入查询轴与扫掠向量 [0, End-Start] 张成的平行四边形的 (Radius + ColliderRadius) 邻域(SegmentWithinDistanceOfParallelogram,即胶囊轴与扫掠段的精确闵可夫斯基和再膨胀 agent 碰撞体半径);输出位置取扫掠段上的最近接近点(与盒扫约定一致)。其余流程与 CapsuleTraceForAgents 相同;编辑器下绘制两端点胶囊(盒扫画两端盒)。
Swept-capsule trace for agent entities (new in 1.19.20, not deprecated; exposed to Blueprint via MassBattleFuncLib::CapsuleSweepForAgents): a zero-length sweep (Start == End within KINDA_SMALL_NUMBER) forwards directly to CapsuleTraceForAgents. Otherwise the query axis segment sits at the sweep start (Start ± Up×HalfHeight); the geometry check is an exact agent-collider-capsule vs swept-volume test — the agent axis segment must come within (Radius + ColliderRadius) of the parallelogram spanned by the query axis and the sweep vector [0, End-Start] (SegmentWithinDistanceOfParallelogram, i.e. the exact Minkowski sum of the capsule axis and the sweep segment inflated by the agent's collider radius); output locations use the closest approach on the sweep segment (same convention as the box sweep). Otherwise identical flow to CapsuleTraceForAgents; in-editor draws the two endpoint capsules (the box sweep draws the two endpoint boxes).
Input
与 CapsuleTraceForAgents 相同,另加 Start / End 扫掠起止点。
Same as CapsuleTraceForAgents plus Start / End sweep endpoints.
Output
返回 void;结果经 Hit / Results 输出。副作用:编辑器下绘制两端点调试胶囊。
Returns void; results via Hit / Results. Side effect: in-editor debug capsules drawn at both sweep endpoints.
已废弃的实体级视锥索敌节点。SelectionPoints.Num() < 4 直接返回;由视点与 4 点构造 4 个视锥平面,几何检查为逐平面"平面距离 ≥ -测试半径"(测试半径 = 胶囊包围球半径)。
Deprecated entity-level view-frustum trace node. Returns immediately when SelectionPoints.Num() < 4; builds 4 frustum planes from the view point and the 4 points; the geometry check is per-plane "plane distance ≥ -test radius" (test radius = capsule bounding-sphere radius).
Input
与 SphereTraceForAgents 相同,另加 TracePoints(FViewTracePoints:视点 + 选择点)。
Same as SphereTraceForAgents plus TracePoints (FViewTracePoints: view point + selection points).
Output
返回 void;结果经 Hit / Results 输出。副作用同前。
Returns void; results via Hit / Results. Same side effects.
已废弃的实体级圆锥索敌节点。几何检查:轴向投影在 [-测试半径, 长度 + 测试半径] 内,且到轴线的垂直距离 ≤ 该投影处圆锥半径 + 测试半径。
Deprecated entity-level cone trace node. Geometry check: the axial projection must lie within [-test radius, length + test radius], and the perpendicular distance to the axis must be ≤ cone radius at that projection + test radius.
Input
与 SphereTraceForAgents 相同,另加 Length(默认 1000)、Angle(默认 45)。
Same as SphereTraceForAgents plus Length (default 1000), Angle (default 45).
Output
返回 void;结果经 Hit / Results 输出。副作用同前。
Returns void; results via Hit / Results. Same side effects.
已废弃的实体数组排序节点。空数组或 SortMode == None 直接返回;Randomize:确定性模式用 RandomStream 初始种子 ^ hash(SortOrigin) 派生局部流做 Fisher-Yates 洗牌,否则 Algo::RandomShuffle;NearToFar / FarToNear:逐实体读 FLocating::Location 算距离(无效实体距离 FLT_MAX)、FDeterminism::UniqueID 作 tiebreak,排序后原地写回。
Deprecated entity array sort node. Empty array or SortMode == None returns immediately; Randomize: deterministic mode derives a local stream from RandomStream initial seed ^ hash(SortOrigin) and Fisher-Yates shuffles, otherwise Algo::RandomShuffle; NearToFar / FarToNear: per-entity distance from FLocating::Location (invalid entities get FLT_MAX) with FDeterminism::UniqueID tiebreak, sorted and written back in place.
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
Entities | TArray<FEntityHandle>& (UPARAM(ref)) | 待排序的实体句柄数组,原地改写。Entity handle array to sort; modified in place. |
SortMode | ESortMode | 排序模式(默认 NearToFar)。Sort mode (default NearToFar). |
SortOrigin | const FVector& | 距离参考点。Distance reference point. |
Output
返回 void。副作用:原地重排 Entities。
Returns void. Side effect: reorders Entities in place.
CAS 原子最大值更新 MaxAgentNeighborExtent(relaxed 语义)。供 ExecuteRegistrationCommand 的 RegisterAgent 分支调用。
CAS atomic-max update of MaxAgentNeighborExtent (relaxed semantics). Called from the RegisterAgent branch of ExecuteRegistrationCommand.
Input
| 参数 Param | 类型 Type | 说明 Description |
|---|---|---|
NewValue | float | 候选新值;仅当大于当前值时写入。Candidate new value; written only when greater than the current value. |
Output
无返回值。副作用:可能抬高 MaxAgentNeighborExtent。
No return value. Side effect: may raise MaxAgentNeighborExtent.
成员变量 Members
网格世界原点,DefaultMassBattle.ini 可配;所有 *LocationToCoord 都相对它换算。
World-space origin of the grid, configurable in DefaultMassBattle.ini; every *LocationToCoord converts relative to it.
agent 网格单元尺寸(cm);初始化时按 0.001 下限取逆缓存。
Agent grid cell size (cm); the inverse cache is built with a 0.001 floor at Initialize.
agent 块维度(每轴 Max(1, 配置));乘积校验 int32 溢出。
Agent block dimensions (per-axis Max(1, config)); the product is checked for int32 overflow.
簇 = M×N 个 block(XY 平铺,类似 UE World Partition);Z 必须为 1(初始化 checkf 断言),XY 建议偶数以保证世界原点居中。
Cluster = M×N blocks (XY-tiled like UE World Partition); Z must be 1 (checkf at Initialize) and even XY is recommended for symmetric centering on the world origin.
trace 的 block-AABB 体积阈值:达到该值走 cluster 加速路径,否则走原 block 三重循环。
Trace block-AABB volume threshold: at/above it the trace dispatches through the cluster layer; below it the plain block triple-loop runs.
障碍网格单元尺寸(cm)。
Obstacle grid cell size (cm).
障碍块维度。
Obstacle block dimensions.
障碍簇维度,同 agent 约定(Z=1,XY 偶数)。
Obstacle cluster dimensions, same convention as agent (Z=1, even XY).
障碍网格的 cluster 分派阈值。
Cluster dispatch threshold for the obstacle grid.
trace 遮挡射线单调剪枝的方向桶数量。桶越多角度精度越高(墙上窄缝更不易被多挡),代价是每次 trace 的桶数组更大。
Direction-bucket count for the trace's obstacle-ray monotonic pruning. More buckets = finer angular precision (narrow gaps in walls less likely to over-block) at the cost of a larger per-trace bucket array.
是否维护交集 composition(None 聚合剪枝)。默认关——每 agent 注册约 +20%(10 万 agent 约 0.6-1ms);仅 None 查询占主导时开启。运行时 BP 开关双向安全:关 = 立即停剪枝;中途开 = 仅对之后(重)建过交集的格子生效(空交集不剪枝,老格子退化为逐实体检查)。关 = 纯并集基线。
Enable intersection-composition maintenance for None aggregate pruning. Off by default — costs ~20% extra per-agent registration (0.6-1ms per 100k agents); enable only when None queries dominate. Runtime BP toggle is safe both ways: turning off stops pruning immediately; turning on mid-run prunes only cells whose ∩ was (re)built since (an empty ∩ never prunes; old cells fall back to per-entity checks). Off = exact union-only baseline.
战利品网格单元尺寸(cm)。
Loot grid cell size (cm).
[临时诊断·resync 循环猎杀] 清单转储(DumpObstacleGridInventory)的逐条枚举开关。摘要行(total/dyn/static/invHash)恒打——折叠哈希承载内容对照;仅在哈希不一致、需要逐条比对时开启(一次全量 3k+ 行 Error)。
[TEMP-DIAG resync-loop hunt] Full per-entry enumeration toggle for DumpObstacleGridInventory. The summary line (total/dyn/static/invHash) always prints — the folded invHash carries the content comparison; flip true only when a hash mismatch needs the entry-level diff (one full dump is 3k+ Error lines).
战利品块维度。
Loot block dimensions.
压力格宽(cm)。越大越平滑但更滞后。五个压力参数均由 ini(DefaultMassBattle.ini)驱动——锁步双端必须同值,格网数学参与确定性求解。
Pressure cell size (cm). Bigger = smoother gradient plus more lag. All five pressure knobs are ini-driven (DefaultMassBattle.ini) — lockstep peers MUST run identical values; the lattice math feeds the deterministic solve.
块格网的世界 XY 锚点——block (0,0) 的最小角。默认 (-25600,-25600) 下 block (0,0) 与旧 512m 固定网格完全重合。
World XY anchor of the block lattice — block (0,0)'s min corner. With the default (-25600,-25600), block (0,0) coincides exactly with the legacy 512 m fixed grid.
每块 XY 方向格数(各轴下限 1);块世界尺寸 = Dimensions × CellSize(默认 256×200cm = 512m),块无界平铺世界。
Cell count along X/Y of EACH block (each axis floored at 1); block world size = Dimensions × CellSize (default 256×200 cm = 512 m), and blocks tile the world without bound.
每帧 Jacobi 扩散次数。
Number of Jacobi diffusion passes per frame.
单次扩散强度;5 点 Laplace 稳定性要求 [0, 0.25],运行时(FFix64)再夹一次。
Diffusion strength per pass; 5-point Laplace stability requires [0, 0.25], clamped again at runtime (as FFix64).
三个惰性缓存:世界与两个子系统的指针,由对应 getter 首次命中时写入。
Three lazy caches: the world and the two subsystem pointers, filled on the first getter hit.
静态空单元哨兵,GetCellAt_Internal 在块缺失时返回其引用(默认构造,可安全读)。
Static empty-cell sentinels returned by reference from GetCellAt_Internal when the block is missing (default-constructed, safe to read).
初始化时从配置烘焙的缓存:三套网格的逆单元尺寸、块维度、块大小乘积、簇维度与簇分派阈值(后两项仅 Agent/Obstacle),热路径直接用。
Config caches baked at Initialize: per-grid inverse cell sizes, block dimensions, block size products, cluster dimensions and cluster dispatch thresholds (the latter two Agent/Obstacle only) for the hot paths.
当前全部已注册 agent 的邻居合并检测半径(max(AvoidRadiusX, ColliderHeight*0.5 + ColliderRadius))的运行最大值。每帧 ResetOccupiedAgentCells 清零、注册时 CAS 更新;gather 热循环的单元 AABB 角点距离剪枝用它保守上界。注意:曾经的伴生 MaxSingleCellNeighborExtent(推导式全场盒 max,喂 PBD 搜索盒)已于 2026-09 退役——它让一个高/大单格单位撑大所有搜索者的盒子(约 20% 的 5 万 move pass 开销);单格盒扩展改为按碰撞体声明(FCollider::ExtraExtent),MoveProcessor 直接读自身片段。
Running max of each registered agent's neighbor-combined detection radius — max(AvoidRadiusX, ColliderHeight*0.5 + ColliderRadius). Zeroed per frame by ResetOccupiedAgentCells, CAS-updated at registration; the gather hot loop's per-cell AABB-corner prune uses it as a conservative upper bound. NOTE: the former companion MaxSingleCellNeighborExtent (a derived scene-wide box max feeding the PBD gather box) was retired in 2026-09 — it let ONE tall/large single-cell unit inflate EVERY searcher's box (~20% of the 50k move pass); the single-cell box extension is now per-collider declared state (FCollider::ExtraExtent), read by the MoveProcessors from their own fragment.
网格修改命令的并行收集器(thread-local 槽位,无锁);并行注册把缺失块的命令压入,FlushCommandBuffer 排序后串行 flush 保证确定性。
Parallel gatherer for grid modification commands (thread-local slots, lock-free); parallel registrations push commands for missing blocks, FlushCommandBuffer sorts and serially flushes them for determinism.
全局确定性随机流:初始化固定种子 12345,BP 可重设;Randomize 排序/洗牌在确定性模式下以 初始种子 ^ hash(SortOrigin) 派生局部流。
Global deterministic random stream: fixed seed 12345 at Initialize, BP can reseed; deterministic Randomize sorts/shuffles derive a local stream from initial seed ^ hash(SortOrigin).
三套网格的块字典,键 = 块坐标。块按需创建(FlushCommandBuffer 单线程)与回收(ShrinkGrids)。
Block dictionaries of the three grids keyed by block coord. Blocks are created on demand (FlushCommandBuffer, single-threaded) and reaped (ShrinkGrids).
压力场存储——块稀疏:以 PressureGridOrigin 锚定的绝对格网上每片大瓦片一个 FPressureBlock(FFix64 双缓冲)。FFix64 保证各端从相同的同步位置算出位级一致的场——场会喂给交通转向,派生全局状态里的浮点舍入差是放大器的种子;块创建/销毁仅在 game thread(ResetPressureField),并行段(沉积散射、扩散、采样)对冻结 TMap 只读,沉积量在唯一累加点经 FFix64::FromFloat 转换。缓存:逆格宽与逐轴块世界尺寸(默认每边 51200uu)及其逆。
Pressure field storage — block-sparse: one FPressureBlock (FFix64 double-buffered) per large tile on the absolute lattice anchored at PressureGridOrigin. FFix64 guarantees every client computes a bit-identical field from identical synced positions — the field feeds traffic steering, and float rounding differences in derived global state are an amplification seed; block create/destroy is game-thread-only (ResetPressureField), parallel passes (deposit scatter, diffusion, sampling) read the frozen TMap, and deposit amounts convert via FFix64::FromFloat at the single accumulation point. Caches: the inverse cell size and the per-axis block world extents (default 51200 uu per side) with their inverses.
簇索引层:纯存在性信号,无负载。仅串行建块(FlushCommandBuffer)时填充、ShrinkGrids 时修剪;trace 大形状时用 Contains() 跳过整片 M×N 空块区域。
Coarse cluster index layer — pure existence signal, no payload. Populated only on serial block creation (FlushCommandBuffer) and pruned on ShrinkGrids; large traces use Contains() to skip whole M×N empty block regions.
管线角色 Pipeline Role
在 MassBattle 管线中的位置(调用关系均经 grep 验证):
① 模拟 tick 由 UMassBattleSubsystem 驱动(MassBattleSubsystem.cpp:1567 调用 HashGridSub->ExecuteTick),即每帧排空命令缓冲。
② MassBattleGridUpdateProcessor 是主要写入方:每帧先 ResetOccupiedAgentCells(:110)→ 并行 RegisterAgentCell(:229/:245,块存在时零锁争用快路径)→ FlushCommandBuffer(:255)→ bDeterministic 时 SortAgentCellsByUniqueID(:257);随后压力 flush:PressureGatherer.Merge()(:163)→ 从沉积去重推导活跃块列表(:179-194)→ ResetPressureField(活跃列表)(:195;本帧无沉积时传空列表清场,:208)→ ApplyPressureDeposits(:198,无预排序的并行原子散射)→ DiffusePressureField(:200);障碍侧 ResetOccupiedObstacleCells(:289)→ 并行 RegisterObstacleCell(:379/:537/:626,盒障碍先用 BoxTraceForObstacleCells(:373)求覆盖单元,静态盒停用走 RemoveStaticObstacleByUniqueID(:329))→ FlushCommandBuffer(:633)→ SortObstacleCellsByUniqueID(:635);战利品 RegisterLootCell(:687)→ FlushCommandBuffer(:691)。
③ 压力消费方:MassBattleAgentMoveProcessor(:4243/:5981)与 MassBattleAgentMoveProcessorFP(:5960)在移动热循环读 float 版 SamplePressureGradient;FP 的确定性压力主路径走 FFix 版 SamplePressureGradientFx(:4223)。
④ 索敌消费方:MassBattleAgentTraceProcessor(:447)调用静态 CheckLineOfSight;实体级 trace 经 MassBattleFuncLib 或本子系统的(已废弃)BP 节点进入 ExecuteTrace 家族。
⑤ resync 路径:MassBattleNetworkSubsystem 在快照恢复后调用 ResetOccupiedAgentCells(:2108)重建 agent 网格,并调用 ClearStaticObstacleCells(:2114)清空障碍网格静态半区(防止孤儿静态条目与重建实体同格重复注册);诊断路径上 DumpObstacleGridInventory 由 MassBattleNetworkGameModeBase(:919)与 MassBattleNetworkGameStateBase(:360)双端调用。
Position in the MassBattle pipeline (all call relations grep-verified):
① the simulation tick is driven by UMassBattleSubsystem (MassBattleSubsystem.cpp:1567 calls HashGridSub->ExecuteTick) — i.e. the command buffer is drained every frame.
② MassBattleGridUpdateProcessor is the main writer: each frame it calls ResetOccupiedAgentCells (:110) → parallel RegisterAgentCell (:229/:245, lock-free fast path when blocks exist) → FlushCommandBuffer (:255) → SortAgentCellsByUniqueID when bDeterministic (:257); then the pressure flush: PressureGatherer.Merge() (:163) → active block list deduced from deposits (:179-194) → ResetPressureField (active list) (:195; an empty list wipes the field when there are no depositors, :208) → ApplyPressureDeposits (:198, unsorted parallel atomic scatter) → DiffusePressureField (:200); on the obstacle side ResetOccupiedObstacleCells (:289) → parallel RegisterObstacleCell (:379/:537/:626, boxes first compute covered cells via BoxTraceForObstacleCells (:373), deactivated statics go through RemoveStaticObstacleByUniqueID (:329)) → FlushCommandBuffer (:633) → SortObstacleCellsByUniqueID (:635); loot: RegisterLootCell (:687) → FlushCommandBuffer (:691).
③ pressure consumers: MassBattleAgentMoveProcessor (:4243/:5981) and MassBattleAgentMoveProcessorFP (:5960) read the float SamplePressureGradient in the move hot loop; the FP variant's deterministic pressure main path goes through the FFix version SamplePressureGradientFx (:4223).
④ trace consumers: MassBattleAgentTraceProcessor (:447) calls the static CheckLineOfSight; entity-level traces enter the ExecuteTrace family via MassBattleFuncLib or this subsystem's (deprecated) BP nodes.
⑤ resync path: MassBattleNetworkSubsystem calls ResetOccupiedAgentCells (:2108) after snapshot restore to rebuild the agent grid, and ClearStaticObstacleCells (:2114) to wipe the obstacle grid's static half (preventing orphaned static entries from double-registering against rebuilt entities); on the diagnostic path, DumpObstacleGridInventory is called on both peers by MassBattleNetworkGameModeBase (:919) and MassBattleNetworkGameStateBase (:360).
补充说明 Notes
孤立注释:头文件第 959 行有一条注释"Maximum trace sphere/sweep/box radius (cm)。Guards against unbounded cluster/block iteration."但其后没有对应成员,代码中也未发现半径上限实现——各 TraceForCells_Internal 只做负数校验。
Loot 网格差异:无簇层(FlushCommandBuffer 建块时不为 Loot 加簇)、ExecuteCellTrace 的 cluster 快路径仅 Agent/Obstacle;Sphere/Capsule Sweep 的 _Internal 按 GridType 显式分派(含 Loot 分支,但 Sweep 家族无 Loot 公开包装器);Sector/View/Cone 的 _Internal 用三元表达式选网格,非 Agent 一律按 Obstacle 处理,不支持 Loot。
簇坐标约定:*BlockToClusterCoord 以世界原点为 cluster (0,0) 中心(floor((Block + Dim/2) / Dim)),因此簇坐标到块范围的换算需要反推原点平移(ClusterCoord * Dim - Dim/2),ShrinkGrid_Internal 与 cluster 路径均如此处理。
Orphaned comment: line 959 of the header carries a comment "Maximum trace sphere/sweep/box radius (cm). Guards against unbounded cluster/block iteration." with no member after it, and no radius cap exists in the code — the TraceForCells_Internal functions only validate against negatives.
Loot grid differences: no cluster layer (block creation in FlushCommandBuffer adds no cluster for Loot), and ExecuteCellTrace's cluster fast path is Agent/Obstacle only; the Sphere/Capsule sweep _Internal functions dispatch on GridType explicitly (including a Loot branch, though the sweep families expose no Loot wrappers); the Sector/View/Cone _Internal functions select grids via ternaries that treat any non-Agent grid as Obstacle — Loot unsupported there.
Cluster coord convention: *BlockToClusterCoord centers the world origin at cluster (0,0) (floor((Block + Dim/2) / Dim)), so converting cluster coords back to block ranges requires inverting the centering shift (ClusterCoord * Dim - Dim/2) — both ShrinkGrid_Internal and the cluster fast path do this.