MassBattle Docsv1.19.20

UMassBattleBPTaskGenerateFormation

UCLASS Async Task

Source/MassBattle/Public/Tasks/MassBattleBPTaskGenerateFormation.h

概述 Overview

异步阵型生成蓝图节点(UBlueprintAsyncActionBase)。三个工厂分别生成矩形网格阵型、圆形/多边形阵型与三角形(楔形)阵型:游戏线程上先做陈旧选集自动过滤(无效/已销毁句柄、濒死、缺 FMove / 移动禁用、bStopActiveMovement 锁存者不占任何槽位),再捕获 agent 数据(位置 / 半径 / UID / 飞行状态,经 FDeterminism 解析)、纯数学生成阵型槽位、地面/障碍追踪校验后,把重型贪婪分配派发到线程池(Async(ThreadPool))。两种完成模式:MaxTicksToComplete > 0 时经 AFlowField::OnSimulationTick 逐 tick 轮询,截止期到而结果未就绪时置 bAbortStep 中止模拟步以保证确定性(模拟暂停等待);0 时完全异步,结果经游戏线程回调。完成后广播 OnCompleted(紧凑仅合格数组:ValidAgents 句柄 → Locations 位置,逐位 1:1 对齐)并销毁。网络模式下首次执行与完成广播都经 ExecuteOrDeferToLogicFrame 门控到逻辑帧(Subtick0),保证对端可见副作用落在 tick 管线的确定点上。

Async formation generation Blueprint node (UBlueprintAsyncActionBase). Three factories generate a rectangular grid formation, a circular/polygonal formation, and a triangular (wedge) formation: on the game thread it first applies the stale-selection auto-filter (invalid/destroyed handles, dying agents, missing FMove / movement-disabled, and the bStopActiveMovement latch occupy NO slot at all), then captures agent data (locations / radii / UIDs / fly state, resolved via FDeterminism), generates formation slots with pure math, validates with ground/obstacle traces, and dispatches the heavy greedy assignment to the thread pool (Async(ThreadPool)). Two completion modes: with MaxTicksToComplete > 0, it polls per tick via AFlowField::OnSimulationTick and, when the deadline hits before the result is ready, sets bAbortStep to abort the simulation step for determinism (the sim pauses to wait); with 0 it is fully async with a game-thread callback. On completion it broadcasts OnCompleted (compact valid-only arrays: ValidAgents handles → Locations, index-aligned 1:1) and destroys itself. In network mode both the first execution and the completion broadcast are gated to a logic frame (Subtick0) via ExecuteOrDeferToLogicFrame, so every peer-observable side effect lands at a deterministic point in the tick pipeline.

继承 Inheritance

UBlueprintAsyncActionBase → UMassBattleBPTaskGenerateFormation

公开方法 Public Methods

GenerateGridFormationAsync static UMassBattleBPTaskGenerateFormation*

矩形网格阵型工厂。校验世界上下文与 agent 数组(无效直接返回 nullptr),把 agent 句柄解析为 FDeterminism.UniqueID 存入缓存,记录全部参数与 FormationType = Grid,RegisterWithGameInstance 后返回。

Rectangular grid formation factory. Validates the world context and agent array (returns nullptr when invalid), resolves agent handles to FDeterminism.UniqueID into the cache, records all parameters with FormationType = Grid, calls RegisterWithGameInstance, and returns.

Input
参数 Param类型 Type说明 Description
WorldContextUObject*世界上下文,用于 ECS 子系统查找。World context for ECS subsystem lookup.
Agentsconst TArray<FEntityHandle>&要分配阵型槽位的 agent 句柄(读 FLocating/FStatistics/FMove)。计算任何槽位前自动过滤:无效/已销毁句柄、濒死(死亡动画窗口)、缺 FMove 或移动被禁用(Move.bEnable 关——静态道具/建筑/炮塔)、运行时 bStopActiveMovement 锁存者。被剔除者不占槽位:OnCompleted 的 Locations/ValidAgents 为紧凑的仅合格数组,逐位 1:1 对齐。Agent handles to assign formation slots (reads FLocating/FStatistics/FMove). AUTO-FILTERED before any slot is computed: invalid/destroyed handles, dying agents (death-animation window), agents without FMove or with movement disabled (Move.bEnable off — static props/buildings/turrets), and agents with the runtime bStopActiveMovement latch. Filtered agents occupy NO slot: OnCompleted's Locations/ValidAgents are compact valid-only arrays, 1:1 index-aligned.
CenterLocationFVector网格的世界空间中心。World-space center of the grid.
ShapeDataconst FAgentSpawnRectangleShapeData&矩形形状参数:Region(XY 范围)、Spacing(XY 间距)、ShapeDirection、Offset、地面/障碍追踪配置。Rectangle shape params: Region (XY extents), Spacing (XY), ShapeDirection, Offset, ground/obstacle trace config.
AssignmentModeEFormationAssignmentModeKeepFormation:保持 agent 相对排列;ReformTheLine:就近分配槽位。KeepFormation: preserve relative arrangement; ReformTheLine: nearest-slot assignment.
MaxTicksToCompleteint32>0 时强制在该 MassBattle tick 数内完成(确定性,必要时中止模拟步);0 = 完全异步。>0 forces completion within that many MassBattle ticks (deterministic, aborting the sim step if needed); 0 = fully async.
AgentBoundModeEAgentBoundMode每 agent 半径来源:FromCollider(胶囊边界圆)或 FromAvoidance(避障椭圆长轴)。Per-agent radius source: FromCollider (capsule bounding circle) or FromAvoidance (avoidance ellipse long axis).
SizeMultiplierfloat应用于每个采样半径的倍数。Multiplier applied to each sampled radius.
VisualizationConfigFFormationVisualizationConfig调试可视化配置(ULineBatchComponent 绘制,Shipping 可见)。Debug visualization config (drawn via ULineBatchComponent, visible in Shipping).
Output

返回任务实例;世界或 agent 无效时返回 nullptr。副作用:缓存输入,注册进 GameInstance。

Returns the task instance, or nullptr when the world or agents are invalid. Side effects: caches inputs, registers with the GameInstance.

GenerateCircularFormationAsync static UMassBattleBPTaskGenerateFormation*

圆形/多边形阵型工厂。流程与网格工厂相同,仅 ShapeData 为 FAgentSpawnPolygonShapeData(OuterRadius / InnerRadius / Spacing(弧/环) / Segments(>=3 多边形,否则圆) / SectorAngle / PolygonRotation)且 FormationType = Circular。

Circular/polygonal formation factory. Same flow as the grid factory, except ShapeData is FAgentSpawnPolygonShapeData (OuterRadius / InnerRadius / Spacing (arc/ring) / Segments (>=3 polygon, else circle) / SectorAngle / PolygonRotation) and FormationType = Circular.

Input
参数 Param类型 Type说明 Description
WorldContext 等 9 参数同网格工厂参数与网格工厂一致(含 Agents 自动过滤),仅形状数据为多边形类型。Same parameters as the grid factory (including the Agents auto-filter), with polygon shape data.
Output

返回任务实例;无效时返回 nullptr。

Returns the task instance, or nullptr when invalid.

GenerateTriangleFormationAsync static UMassBattleBPTaskGenerateFormation*

三角形(楔形)阵型工厂(BP 显示名 "Generate Triangle Formation (Async)")。行从沿 ShapeDirection 的单槽顶点递增到底边:第 j 行 j+1 个槽位,行内间距 Spacing.X,行距 Spacing.Y,行数受 Region 限制。重型贪婪分配运行在线程池中,OnCompleted 在游戏线程触发。大 Agent 的槽位排除使用正六边形脚印(一条顶点朝前)。其余参数语义与网格/圆形工厂相同(含 Agents 自动过滤与紧凑 1:1 输出契约),FormationType = Triangle。

Triangular (wedge) formation factory (BP display name "Generate Triangle Formation (Async)"). Rows grow from a 1-slot apex pointing along ShapeDirection to the base row: row j holds j+1 slots spaced Spacing.X, rows pitch Spacing.Y, row count capped by Region. The heavy greedy-assign runs on a thread pool and OnCompleted fires on the game thread. Large-agent slot exclusion uses a regular-hexagon footprint (one vertex forward). The remaining parameter semantics match the grid/circular factories (including the Agents auto-filter and the compact 1:1 output contract), with FormationType = Triangle.

Input
参数 Param类型 Type说明 Description
WorldContext 等 9 参数同网格工厂参数与网格工厂一致(含 Agents 自动过滤),仅形状数据为 FAgentSpawnTriangleShapeData。Same parameters as the grid factory (including the Agents auto-filter), with FAgentSpawnTriangleShapeData as the shape data.
Output

返回任务实例;无效时返回 nullptr。

Returns the task instance, or nullptr when invalid.

Activate virtual void

游戏线程激活入口,网络模式下经 UMassBattleSubsystem::ExecuteOrDeferToLogicFrame 门控——渲染帧 Activate 会在随发起端帧落地时机而变的帧中途时刻读 ECS 片段(资格/半径/位置),门控把执行体排队到下一个 Subtick0;单机立即执行;随后进入 ActivateInternal:⓪ 陈旧选集过滤(IsFormationSlotEligible:无效句柄 / 濒死 / 缺 FMove / 移动禁用 / bStopActiveMovement 锁存者剔除,幽灵不得占槽或扭曲晶格尺寸);① UID → 句柄解析(resync 后仍有效);② 并行/串行计算每 agent 半径(ComputeAgentFormationRadius,无效实体回退 34×SizeMultiplier,≥256 用 MBParallelFor);③ 捕获位置/UID/可飞/Z 冻结状态(质心串行归约);KeepFormation 模式在此直接算纯平移目标(goal_i = 中心 +(当前位_i − 群质心),逐点贴地,绝不增删——整个排列作为刚体平移,不生成晶格);④ 纯数学生成阵型位置——网格:按 Region/Spacing 铺满矩形;圆形:环形 + 扇形扫描(多边形按角度钳制外半径、apothem 比);三角形:顶点到底边的递增行;⑤ 地面/障碍追踪校验(ValidateAndOffsetPositions,必须游戏线程);⑥ RunAssignment() 派发。

Game-thread activation entry; in network mode it is gated through UMassBattleSubsystem::ExecuteOrDeferToLogicFrame — a render-frame Activate would read ECS fragments (eligibility/radii/locations) at a mid-frame moment that depends on when the issuing peer's frame landed, so the gate queues the body to the next Subtick0; standalone runs it now. It then enters ActivateInternal: ⓪ stale-selection filter (IsFormationSlotEligible: drops invalid handles / dying / missing FMove / movement-disabled / bStopActiveMovement-latched agents — ghosts must not reserve slots or skew the lattice sizing); ① UID → handle resolution (still valid after resync); ② parallel/serial per-agent radius computation (ComputeAgentFormationRadius, invalid entities fall back to 34×SizeMultiplier; ≥256 uses MBParallelFor); ③ capture locations/UIDs/fly/Z-frozen state (serial centroid reduce); KeepFormation computes the pure translation goals right here (goal_i = Center + (Loc_i − GroupCentroid), ground-snapped per point, NEVER resized — the whole arrangement moves as one rigid body; no lattice is generated); ④ pure-math formation slot generation — grid: fill the rectangle by Region/Spacing; circular: rings + sector sweep (polygons clamp the outer radius by angle, apothem ratio); triangle: apex-to-base growing rows; ⑤ ground/obstacle trace validation (ValidateAndOffsetPositions, game thread required); ⑥ dispatch via RunAssignment().

Input

无参数。

No parameters.

Output

无返回值。副作用:填充捕获数组、启动异步分配、注册 OnSimulationTick(tick 限定模式)。

No return value. Side effects: fills capture arrays, starts the async assignment, registers OnSimulationTick (tick-limited mode).

RunAssignment void (private)

派发贪婪分配:AssignPositionsFromData(纯函数,含网格矩形环宽高比)在线程池执行。KeepFormation 模式已有纯平移目标(CachedTranslatedGoals 非空),直接返回并跳过分配核心;ReformTheLine 走晶格流水线。tick 限定模式(MaxTicksToComplete > 0)把 future 存 AssignFuture 并注册 OnMassBattleTick;完全异步模式在后台线程完成后经 AsyncTask(GameThread) 回调。两条路径的收尾都汇入 FinalizeAndBroadcast(经 ExecuteOrDeferToLogicFrame 门控:可视化 → 紧凑 1:1 广播 → SetReadyToDestroy;网络模式下渲染帧到达等待下一个 Subtick0,tick 限路径已在逻辑帧内直通)。

Dispatches the greedy assignment: AssignPositionsFromData (pure function, with the grid's rectangular-ring aspect ratio) runs on the thread pool. KeepFormation already has the pure translation goals (CachedTranslatedGoals non-empty) and returns them directly, skipping the assignment core; ReformTheLine runs the lattice pipeline. Tick-limited mode (MaxTicksToComplete > 0) stores the future in AssignFuture and registers OnMassBattleTick; fully-async mode calls back via AsyncTask(GameThread) once the background thread finishes. Both paths converge on FinalizeAndBroadcast (gated by ExecuteOrDeferToLogicFrame: visualization → compact 1:1 broadcast → SetReadyToDestroy; in network mode a render-frame arrival waits for the next Subtick0, while the tick-limited caller is already inside the logic frame and passes straight through).

Input

无参数(数据来自捕获数组)。

No parameters (data comes from the capture arrays).

Output

无返回值。副作用:启动线程池任务;tick 限定模式注册模拟 tick 回调。

No return value. Side effects: starts a thread-pool task; registers the sim tick callback in tick-limited mode.

OnMassBattleTick void (private, UFUNCTION)

tick 限定模式的逐 tick 轮询:ElapsedTicks 递增;future 就绪 → 取结果、退订 tick、可视化、广播 OnCompleted 并销毁;截止期到(ElapsedTicks ≥ MaxTicksToComplete)而结果未就绪 → 置 Context.bAbortStep = true 中止本模拟步(确定性:模拟暂停等待结果)。

Per-tick polling for tick-limited mode: increments ElapsedTicks; when the future is ready → take the result, unsubscribe the tick, visualize, broadcast OnCompleted, and destroy; when the deadline is reached (ElapsedTicks ≥ MaxTicksToComplete) before the result is ready → sets Context.bAbortStep = true to abort this simulation step (determinism: the sim pauses to wait for the result).

Input
参数 Param类型 Type说明 Description
ContextFFlowFieldTickContext&模拟 tick 上下文,含 bAbortStep 中止标志。Simulation tick context carrying the bAbortStep abort flag.
Output

无返回值。副作用:可能置 bAbortStep、广播完成、销毁任务。

No return value. Side effects: may set bAbortStep, broadcast completion, and destroy the task.

成员变量 Members

OnCompleted FOnFormationCompleted (public, UPROPERTY BlueprintAssignable)

完成委托(DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams):参数 1 为 ValidAgents(TArray<FEntityHandle>,合格 agent 句柄,在前——BP 输出 pin 顺序为句柄 → 位置),参数 2 为 Locations(TArray<FVector> 每 agent 目标位置)。两数组均为紧凑仅合格数组(合格序)且逐位 1:1 对齐:逐位配对即得锁步 payload(uid 与槽位一一对应);被剔除者不占任何槽位(旧契约会把它们填成中心点,导致"计算时被剔、执行时活着"的单位朝人堆里走)。

Completion delegate (DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams): param 1 is ValidAgents (TArray<FEntityHandle>, the eligible agents' handles, first — so the BP output pins read handles → locations); param 2 is Locations (TArray<FVector> per-agent goal locations). Both arrays are compact valid-only (ValidAgentIndices order) and index-aligned 1:1: pair them entry-for-entry to build lockstep payloads (uids match slots); excluded agents occupy NO slot at all (the old contract padded them to the formation center, so an agent excluded at compute time but alive at execution was commanded to walk INTO the crowd).

ResultValidAgents TArray<FEntityHandle> (public, UPROPERTY BlueprintReadOnly)

广播前填充的合格句柄数组:紧凑(仅合格,合格序),与广播的 Locations 逐位 1:1;被剔除 agent 不占任何槽位。与广播逐位配对即得 uid 与槽位 1:1 对应的锁步 payload——修复了此前"无过滤输出"的缺口(旧做法让 BP 拿未过滤的 uid 数组对过滤后的槽位数组下发,任何跳过/配对差异都会大规模错移目标,是 2026-09-11 恢复重放的放大器)。

Handle array filled right before the broadcast: COMPACT (valid-only, ValidAgentIndices order), 1:1 with the broadcast Locations; excluded agents occupy NO slot at all. Pairing it with the broadcast index-for-index yields lockstep payloads whose uids match slots 1:1 — fixing the previous "no filtered output" gap (BPs used to send unfiltered uid arrays against filtered slot arrays, so every skip/pairing difference mass-shifted goals — the 2026-09-11 recovery-replay amplifier).

CachedWorldContext / CachedAgentUIDs / CachedCenterLocation / CachedAssignmentMode / CachedAgentBoundMode / CachedSizeMultiplier / CachedVisualizationConfig / MaxTicksToComplete / FormationType private 缓存字段

工厂缓存输入(世界上下文、agent UID 数组、中心、分配/半径模式、倍数、可视化、tick 上限、阵型类型 EFormationType{Grid, Circular, Triangle})。

Factory-cached inputs (world context, agent UID array, center, assignment/bound modes, multiplier, visualization, tick cap, and EFormationType{Grid, Circular, Triangle}).

CachedGridShapeData / CachedCircularShapeData / CachedTriangleShapeData private 形状数据

三种形状数据,按 FormationType 只使用其一。

All three shape data records; only one is used depending on FormationType.

ValidAgentIndices / CapturedZFrozen / CachedTranslatedGoals private 过滤与平移状态

ValidAgentIndices:可竞争阵型槽的 agent 在 CachedAgentUIDs 中的下标(Activate 采集,存活且未濒死);战斗减员后 RTS 陈旧选集仍带着死亡句柄,幽灵不得占槽或扭曲晶格尺寸——所有采集数组都压缩为这些条目。CapturedZFrozen:逐有效 agent 的 Z 冻结标志(!FMove.Z.bEnable——垂直速度强制归零,地面单位硬锁出生高度);此类 agent 永远改变不了高度,其 goal 保持自身采集 Z,否则 3D 验收尺下不可达。CachedTranslatedGoals:KeepFormation 纯平移目标(非空时 goal_i = 中心 +(当前位_i − 群质心),逐点贴地,绝不增删;整个排列——长条、方块、多个分离方阵及其间隙——作为刚体整体平移,不生成晶格;RunAssignment 直接返回它们并跳过分配核心。ReformTheLine 为空——走晶格流水线)。

ValidAgentIndices: indices into CachedAgentUIDs of agents eligible to compete for formation slots (live + not dying, gathered in Activate); stale RTS selections keep dead handles after combat losses — ghosts must not reserve slots or skew the lattice sizing, so all captured arrays are compacted to these entries. CapturedZFrozen: per-VALID-agent Z-frozen flag (!FMove.Z.bEnable — vertical velocity force-zeroed, ground units hard-locked to birth Z); such agents can never change height, so their goal keeps their own captured Z, or it is unreachable under the 3D acceptance ruler. CachedTranslatedGoals: KeepFormation pure-translation goals (when non-empty, goal_i = Center + (Loc_i − GroupCentroid), ground-snapped per point, NEVER resized; the whole arrangement — strips, blocks, multiple separated squads and the gaps between them — moves as one rigid body; no lattice is generated, and RunAssignment returns these directly, skipping the assignment core. Empty for ReformTheLine — the lattice pipeline).

Captured* / AssignFuture / MassBattleTickHandle / ElapsedTicks private 运行状态

游戏线程捕获的异步派发数据(位置/半径/UID/可飞/阵型位置/质心/方向)与异步状态(future、tick 句柄、已过 tick 数)。

Game-thread-captured async dispatch data (locations/radii/UIDs/fly flags/formation positions/centroid/directions) and async state (future, tick handle, elapsed ticks).

管线角色 Pipeline Role

由蓝图调用 GenerateGridFormationAsync / GenerateCircularFormationAsync / GenerateTriangleFormationAsync 创建;计算委托给 UMassBattleFormationAlgorithms(AssignPositionsFromData 贪婪分配,线程池;IsFormationSlotEligible 资格过滤)。tick 限定模式经 AFlowField::OnSimulationTick 与 UMassBattleSubsystem 的模拟步同步——截止期未就绪时中止模拟步保证确定性;网络模式下首次执行与完成广播都经 ExecuteOrDeferToLogicFrame 落在逻辑帧(Subtick0)。分配结果只广播给 BP(本任务不写 agent fragment,移动由外部命令驱动)。

Created from Blueprint via GenerateGridFormationAsync / GenerateCircularFormationAsync / GenerateTriangleFormationAsync; the computation delegates to UMassBattleFormationAlgorithms (AssignPositionsFromData greedy assignment, thread pool; eligibility via IsFormationSlotEligible). Tick-limited mode synchronizes with the UMassBattleSubsystem simulation step via AFlowField::OnSimulationTick — aborting the step at the deadline preserves determinism; in network mode both the first execution and the completion broadcast are gated onto a logic frame (Subtick0) via ExecuteOrDeferToLogicFrame. Assignment results are only broadcast to BP (this task does not write agent fragments; movement is driven by external commands).