[{"id":"WL3","fact":"`nav_status`'s `tiles` is ARecastNavMesh::GetNavMeshTilesCount(), which returns Detour's `getMaxTiles()` - the size of the navmesh's tile POOL, above zero as soon as a navmesh exists, whether or not any tile was generated. So `tiles` > 0, `ready` and the absence of the zero-tile warning prove nothing was built; U15 measured a volume that covered nothing while `nav_status` reported a non-zero tile count. The count of generated content is `tilesWithPolygons` / `polygons` (from 2026-09-26). 5.8 adds GetNumActiveTiles, documented beside it as the count of populated tiles 'rather than pool capacity'.","source":"5.3 `Runtime/NavigationSystem/Public/NavMesh/PImplRecastNavMesh.h:80`, 5.3 `Runtime/NavigationSystem/Private/NavMesh/RecastNavMesh.cpp:1364-1369`, 5.8 `Runtime/NavigationSystem/Public/NavMesh/PImplRecastNavMesh.h:77`, 5.8 `Runtime/NavigationSystem/Private/NavMesh/RecastNavMesh.cpp:1803-1808`, 5.8 `Runtime/NavigationSystem/Public/NavMesh/RecastNavMesh.h:1168-1170`","engine":"5.3-5.8","ue":["5.3","5.4","5.5","5.6","5.7","5.8"],"bl":[],"section":"UE navigation, placed volumes and packed level actors - the World Settings flag, the navmesh tile pool, how a brush builder moves a volume, a volume's collision, round collision under non-uniform scale, and the name a packed Blueprint is given"},{"id":"WL4","fact":"UEditorBrushBuilder::EndBrush snaps the brush's actor to the grid - FSnappingUtils::SnapToBSPVertex on its location, then SetActorLocation - so a volume given a box brush through a UCubeBuilder (UActorFactory::CreateBrushForVolumeActor, the placement path's brush) moves off the location it was spawned at. Measured on 5.8.2 before the fix: `add_nav_volume` fitted to a center at z 104.5 read back through `get_actor_bounds` at z 100 (x -300 and y 0, already on the grid, stayed). MifBridge's one `BuildVolumeBoxBrush` puts the actor back after the build; test_nav_coverage NC102 and NC111 (an explicit volume at (123456.5, -98765.25, 5004.5)) read the requested centers back on 5.8.2.","source":"5.3 `Editor/UnrealEd/Private/EditorBrushBuilder.cpp:50`, 5.3 `Editor/UnrealEd/Private/EditorBrushBuilder.cpp:87-88`, 5.8 `Editor/UnrealEd/Private/EditorBrushBuilder.cpp:52`, 5.8 `Editor/UnrealEd/Private/EditorBrushBuilder.cpp:92-93`; measured with `get_actor_bounds` on a scratch project (port 8871), 2026-09-26","engine":"5.3-5.8","ue":["5.3","5.4","5.5","5.6","5.7","5.8"],"bl":[],"section":"UE navigation, placed volumes and packed level actors - the World Settings flag, the navmesh tile pool, how a brush builder moves a volume, a volume's collision, round collision under non-uniform scale, and the name a packed Blueprint is given"},{"id":"WL5","fact":"A placed volume's collision comes from its class's constructor, not from the placement: ABlockingVolume sets its brush component to the `InvisibleWall` profile (and marks it as affecting navigation), APostProcessVolume to `NoCollision` with `bAlwaysCreatePhysicsState` set, because it still needs physics data for traces. BaseEngine.ini defines InvisibleWall as QueryAndPhysics, object type WorldStatic, with only Visibility ignored, so a blocking wall stops pawns and the camera but not a Visibility line trace; a ProfileRedirects entry maps the old profile name `BlockingVolume` to it. test_add_volume AV101 reads each class's collision back on 5.8.2 and 5.3.2: BlockingVolume InvisibleWall, QueryAndPhysics, Pawn Block, Visibility Ignore, Camera Block; TriggerVolume Trigger, QueryOnly; PhysicsVolume, KillZVolume and PainCausingVolume OverlapAllDynamic, QueryOnly; PostProcessVolume, LightmassImportanceVolume and AudioVolume NoCollision; CameraBlockingVolume QueryOnly with Camera Block and Pawn Overlap (its per-channel responses rename the profile to Custom).","source":"5.3 `Runtime/Engine/Private/BlockingVolume.cpp:10`, 5.3 `Runtime/Engine/Private/BlockingVolume.cpp:12-17`, 5.3 `Runtime/Engine/Private/PostProcessVolume.cpp:12-17`, 5.8 `Runtime/Engine/Private/BlockingVolume.cpp:10`, 5.8 `Runtime/Engine/Private/BlockingVolume.cpp:12-17`, 5.8 `Runtime/Engine/Private/PostProcessVolume.cpp:13-18`; the InvisibleWall profile and its redirect in Engine/Config/BaseEngine.ini (5.3 lines 2713 and 2726, 5.8 lines 3115 and 3129); measured by tools/test_add_volume.py AV101 on a scratch project (5.8.2, port 8871) and a scratch project (5.3.2, port 8872), 2026-09-26","engine":"5.3-5.8","ue":["5.3","5.4","5.5","5.6","5.7","5.8"],"bl":[],"section":"UE navigation, placed volumes and packed level actors - the World Settings flag, the navmesh tile pool, how a brush builder moves a volume, a volume's collision, round collision under non-uniform scale, and the name a packed Blueprint is given"},{"id":"WL6","fact":"Simple collision is scaled shape by shape, and round shapes stay round. A sphere's radius is multiplied by the SMALLEST absolute axis of the body's scale (SetupNonUniformHelper, which also turns a nearly zero scale into 0.1) and its center by the scale. A capsule's half length is max((Length + 2 x Radius) x abs(Sz) / 2, 0.1), its radius Radius x max(abs(Sx), abs(Sy)) clamped to [0.1, half length], and its cylinder length max(0.1, 2 x (half length - radius)) - with X, Y and Z the MESH's axes, not the capsule's, so a capsule lying along X takes its length from the Z scale; squashed along Z, its radius is clamped to the half length and it is in effect a sphere. Chaos builds a plain sphere and a plain capsule from those numbers. A box's extents are multiplied by abs(Sx), abs(Sy) and abs(Sz) in its own frame; convex hulls and the triangle mesh are wrapped in TImplicitObjectScaled with the full non-uniform scale. So a sphere-collision prop scaled (1, 1, 3.5) keeps a radius-50 sphere while its mesh is 3.5 times taller: test_collision_report C107 traces the round shapes' tops on 5.8.2 and 5.3.2.","source":"5.3 `Runtime/PhysicsCore/Public/PhysicsInterfaceTypesCore.h:92`, 5.3 `Runtime/Engine/Private/PhysicsEngine/BodySetup.cpp:1866`, 5.3 `Runtime/Engine/Private/PhysicsEngine/BodySetup.cpp:1908`, 5.3 `Runtime/Engine/Private/PhysicsEngine/BodySetup.cpp:2004`, 5.3 `Runtime/Engine/Private/PhysicsEngine/BodySetup.cpp:2027`, 5.3 `Runtime/Engine/Private/PhysicsEngine/BodySetup.cpp:2039`, 5.3 `Runtime/Engine/Private/PhysicsEngine/Experimental/ChaosInterfaceUtils.cpp:120-122`, 5.3 `Runtime/Engine/Private/PhysicsEngine/Experimental/ChaosInterfaceUtils.cpp:157-170`, 5.3 `Runtime/Engine/Private/PhysicsEngine/Experimental/ChaosInterfaceUtils.cpp:262`, 5.3 `Runtime/Engine/Private/PhysicsEngine/Experimental/ChaosInterfaceUtils.cpp:293`, 5.8 `Runtime/PhysicsCore/Public/PhysicsInterfaceTypesCore.h:109`, 5.8 `Runtime/Engine/Private/PhysicsEngine/BodySetup.cpp:2006`, 5.8 `Runtime/Engine/Private/PhysicsEngine/BodySetup.cpp:2048`, 5.8 `Runtime/Engine/Private/PhysicsEngine/BodySetup.cpp:2144`, 5.8 `Runtime/Engine/Private/PhysicsEngine/BodySetup.cpp:2167`, 5.8 `Runtime/Engine/Private/PhysicsEngine/BodySetup.cpp:2179`, 5.8 `Runtime/Engine/Private/PhysicsEngine/Experimental/ChaosInterfaceUtils.cpp:139-141`, 5.8 `Runtime/Engine/Private/PhysicsEngine/Experimental/ChaosInterfaceUtils.cpp:176-189`, 5.8 `Runtime/Engine/Private/PhysicsEngine/Experimental/ChaosInterfaceUtils.cpp:281`, 5.8 `Runtime/Engine/Private/PhysicsEngine/Experimental/ChaosInterfaceUtils.cpp:316`; measured by tools/test_collision_report.py C107 (traces) on a scratch project (5.8.2) and a scratch project (5.3.2), 2026-09-26","engine":"5.3-5.8","ue":["5.3","5.4","5.5","5.6","5.7","5.8"],"bl":[],"section":"UE navigation, placed volumes and packed level actors - the World Settings flag, the navmesh tile pool, how a brush builder moves a volume, a volume's collision, round collision under non-uniform scale, and the name a packed Blueprint is given"},{"id":"M5c5478","fact":"FAIMoveRequest holds exactly ONE goal — a single TWeakObjectPtr<AActor> GoalActor and a single FVector GoalLocation, set by SetGoalActor/SetGoalLocation — so there is no engine-side route chaining and multi-waypoint walking must be sequenced by the caller.","source":"Engine/Source/Runtime/AIModule/Classes/AITypes.h:546-547 (setters) with the single GoalActor/GoalLocation members immediately below at :553-559. NOTE: the candidate's implementation recipe (FTSTicker leg queue, gate on DidMoveReachGoal()) is a design proposal, not sourced — dropped","engine":"5.3.2","ue":["5.3"],"bl":[],"section":"UE AI / navigation","value":"`AIMODULE_API void SetGoalLocation(const FVector& InGoalLocation);`"},{"id":"M77738a","fact":"LineTraceMultiByChannel generates only the single closest BLOCKING result and performs no tests beyond it, so a multi-trace hit list is truncated at the first blocker; touch-response shapes nearer than the blocker DO still appear, so the list is only \"functionally a single trace\" for objects that block.","source":"Engine/Source/Runtime/Engine/Classes/Engine/World.h:1956 (contract sentence), :1965 (signature). Nuance recorded in MifBridge docs/audit/work/Q_gap_rootcauses.md:276","engine":"5.3.2","ue":["5.3"],"bl":[],"section":"UE collision / tracing","value":"`Only the single closest blocking result will be generated, no tests will be done after that`"},{"id":"M862b25","fact":"FCollisionResponseParams defaults every channel to ECR_Block (which is why an unparameterised multi-trace truncates); passing FCollisionResponseParams(ECR_Overlap) makes every interaction Touch, so no hit terminates the ray, OutHits is sorted first-to-last hit, and every entry carries bBlockingHit=false.","source":"`FCollisionResponseParams(ECollisionResponse DefaultResponse = ECR_Block) { CollisionResponse.SetAllChannels(DefaultResponse); }`","engine":"Engine/Source/Runtime/Engine/Public/CollisionQueryParams.h:243 (doc), :247 (ctor default), :257 (DefaultResponseParam ENGINE_API). Sort at Runtime/Engine/Private/Collision/CollisionConversions.cpp:452-453 (`OutHits.Sort(FCompareFHitResultTime())`); bBlockingHit at :505-506 (`= (HitType == ECollisionQueryHitTyp | 5.3.2","ue":["5.3"],"bl":[],"section":"UE collision / tracing"},{"id":"M99116c","fact":"A trace hit's type is the minimum of the querier's response and the shape's response — the mechanism that turns Block into Touch when the query passes ECR_Overlap.","source":"Engine/Source/Runtime/Engine/Private/PhysicsEngine/CollisionQueryFilterCallback.cpp:75-76, inside CalcQueryHitType (:11-80)","engine":"5.3.2","ue":["5.3"],"bl":[],"section":"UE collision / tracing","value":"`// return minimum agreed-upon interaction\\n return FMath::Min(QuerierHitType, ShapeHitType);`"},{"id":"Mf4879c","fact":"Landscape heightfield collision uses the BlockAll profile, so landscape can only ever be the single terminal blocking hit of a default-response trace — never an intermediate entry — which is why intervening road/floor meshes hide it entirely from a ground-snap scan.","source":"Engine/Source/Runtime/Landscape/Private/LandscapeCollision.cpp:2964 (in the ULandscapeHeightfieldCollisionComponent ctor at :2961); profile definition ObjectTypeName=\"WorldStatic\", CustomResponses empty, at Engine/Config/BaseEngine.ini:2702","engine":"5.3.2","ue":["5.3"],"bl":[],"section":"UE landscape / collision","value":"`SetCollisionProfileName(UCollisionProfile::BlockAll_ProfileName);`"},{"id":"U16","fact":"**The level's builder brush is not necessarily 200 units.** `MifBridgeNavigation.cpp`'s `H_add_nav_volume` computes `scale = size / 200` from a comment asserting a 200-unit default cube; the builder brush in this project measures **256** units per side. `tools/nav.py` measures the copied volume with `get_actor_bounds` and derives the scale from the measurement instead.","source":"`get_actor_bounds` on a fresh `BRUSH ADDVOLUME` copy: extent 128/128/128, size 256/256/256.","engine":"5.8","ue":["5.8"],"bl":[],"section":"UE + Blender asset pipeline and navigation"},{"id":"U17","fact":"**`import_asset` on an FBX leaves the StaticMesh on `CTF_UseDefault` with an auto-generated CONVEX HULL.** For a tower that is one solid shell — no walking under it, up its stair or onto its deck, and navigation sees a block. Static level geometry wants `CTF_UseComplexAsSimple`.","source":"`get_property` on `BodySetup.CollisionTraceFlag` (→ `CTF_UseDefault`) and `BodySetup.AggGeom.ConvexElems` (→ a populated hull) immediately after import; set and re-read on all seven meshes by `tools/import_meshes.py`.","engine":"5.8","ue":["5.8"],"bl":[],"section":"UE + Blender asset pipeline and navigation"},{"id":"U19","fact":"**Recast erodes the agent radius off BOTH sides of a walkable strip, and handrails count as walls.** A 0.90 m stair flight with a handrail on each edge has 0.84 m clear; at `AgentRadius` 35 that leaves 0.14 m and **no navmesh is generated anywhere on the flight**. Reducing `CellSize`/`CellHeight` from 19/19 to 8/8 does not recover it.","source":"scan of `nav_project_point` across the flight at 10 cm steps, UE x −2030..−1880 at z 160: 0 hits out of 16, before and after the cell-size change. Defaults read from `RecastNavMesh-Default`: AgentRadius 35, AgentHeight 144, AgentMaxStepHeight 35, AgentMaxSlope 44, CellSize 19, CellHeight 10.","engine":"5.8","ue":["5.8"],"bl":[],"section":"UE + Blender asset pipeline and navigation"},{"id":"U22","fact":"**A struct read through `get_property` returns `typed` with UPPERCASE component keys** — `{'X':..,'Y':..,'Z':..}` — while a vector passed INTO `set_property` is lowercase `{x,y,z}`. Reading the lowercase names off a struct silently yields 0.0 for every component.","source":"measured 2026-09-17 on a `NavLinkProxy`: `get_property {propertyPath:\"PointLinks[0].Right\"}` returned `typed={'X': -62, 'Y': -38, 'Z': 590}` and `value='(X=-62.000000,Y=-38.000000,Z=590.000000)'`, after being SET with `{\"x\":-62,\"y\":-38,\"z\":590}`.","engine":"5.8","ue":["5.8"],"bl":[],"section":"UE + Blender asset pipeline and navigation"},{"id":"U23","fact":"**`load_level` takes `path`, not `level`.** `describe_endpoint` lists `level` by name as a common mistake: *\"level is the sublevel selector on the streaming endpoints; load_level opens a whole map\"*. Passing `level` is rejected and the editor world does not change.","source":"measured 2026-09-17 — `tools/open_level.py` shipped with `level` and the editor stayed on the previous map; only the script's own post-condition check (compare `pie_status.editorWorld` against the requested map) surfaced it.","engine":"5.8","ue":["5.8"],"bl":[],"section":"UE + Blender asset pipeline and navigation"},{"id":"GR9","fact":"**`gameplay_recipe`'s perception recipe works as built: 63 steps, the controller and the pawn compiling with no error, warning or note and linting clean, ai_setup_report reading one controller with three senses and the pawn's two reports perceived; in PIE an AI pawn possessed by the controller sees the pawn 600 in front and not the ones 800 behind or 6000 away, hears a noise from behind but not one from 6000 away, and feels damage reported against its pawn but not against another.**","source":"measured: tools/test_gameplay_recipes_live.py G300-G306, 155/155 on 5.8.2; tools/test_gameplay_recipes_offline.py 130/130","engine":"5.8","ue":["5.8"],"bl":[],"section":"Gameplay recipes - whole systems built from verified calls"},{"id":"U379","fact":"**`UBehaviorTreeGraph::UpdateAsset` rebuilds the runtime tree from the editor graph: `CreateBTFromGraph` sets RootNode to null and builds it again from the root graph node, and each output pin's links are sorted by `FCompareNodeXLocation` first - so siblings run in the order of their graph x position.** `add_bt_node` runs it after every node, and `describe_behavior_tree` reads the runtime tree in that order.","source":"5.3 `Editor/BehaviorTreeEditor/Private/BehaviorTreeGraph.cpp:898`, `:903`, `:547`, `:1185`; 5.8 the same file :902, :907, :551, :1189; measured: `tools/test_behavior_tree_authoring.py` BA103 (the Wait at x -400 runs before the Sequence at 0)","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE Behavior Trees - the editor graph, key filters and what a save does"},{"id":"U380","fact":"**A new Behavior Tree root node takes the AI config's DefaultBlackboard, else the FIRST BlackboardData loaded in memory - whichever that is.** `create_behavior_tree` sets the blackboard asked for instead and says so in blackboardNote when the engine had picked another.","source":"5.3 `Editor/BehaviorTreeEditor/Private/BehaviorTreeGraphNode_Root.cpp:23-49` (PostPlacedNewNode), 5.8 `:26-52`","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE Behavior Trees - the editor graph, key filters and what a save does"},{"id":"U381","fact":"**Opening a tree in the Behavior Tree editor rebuilds its runtime tree from the graph: `RestoreBehaviorTree` runs OnLoaded, Initialize and `UpdateAsset(KeepRebuildCounter)` on a tree that has a graph. A tree with NO graph is not emptied: the editor makes one, and its OnCreated spawns graph nodes from the runtime tree (`SpawnMissingNodes`).** `add_bt_node` refuses a tree with no graph rather than rebuild one, because that spawn path drops task services and root decorators (read, not run).","source":"5.3 `Editor/BehaviorTreeEditor/Private/BehaviorTreeEditor.cpp:339-391`, 5.8 `:342-394`; `BehaviorTreeGraph.cpp` OnCreated 5.3 :185-189, 5.8 :189-193, SpawnMissingNodes 5.3 :985-1009, 5.8 :989-1013; measured on 5.8.2: a planted Sequence over a Wait with no graph read the same after open_asset_editor, and BTGraph was set","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE Behavior Trees - the editor graph, key filters and what a save does"},{"id":"U382","fact":"**The Behavior Tree editor's Save runs the graph's OnSave - `SpawnMissingNodesForParallel`, which only touches Simple Parallel nodes, then `UpdateAsset` - before the package save. `save_package` runs neither.** No live command list maps AssetEditor.SaveAsset for `invoke_editor_command` (measured on 5.8.2), so a test runs its parts: open the editor, save the package, reload it.","source":"5.3 `Editor/BehaviorTreeEditor/Private/BehaviorTreeEditor.cpp:1393-1405` (SaveAsset_Execute), 5.8 `:1391-1403`; `BehaviorTreeGraph.cpp` OnSave 5.3 :204, 5.8 :208","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE Behavior Trees - the editor graph, key filters and what a save does"},{"id":"U383","fact":"**From 5.6 every save drops a Behavior Tree node's blackboard key that fails the node's key filter: `UBTNode::PreSave` runs `FBlackboardKeySelector::PreSave` on each key selector (and `FValueOrBlackboardKeyBase::PreSave` on each value-or-key), which clears the key - or, when the selector allows None, picks the first key that fits - with a LogBehaviorTree warning and no error. The warning's text has the two outcomes the wrong way round. 5.3, 5.4 and 5.5 have no `UBTNode::PreSave`.** `add_bt_node` refuses such a key before the node exists.","source":"5.6, 5.7 and 5.8 `Runtime/AIModule/Private/BehaviorTree/BTNode.cpp:231-255`, `BehaviorTreeTypes.cpp:681-726`; `ValueOrBBKey.cpp:580` on 5.6, `:582` on 5.7 and 5.8; measured on 5.8.2: a Move To and a Default Focus bound to an Object key of base class Object read TargetActor, then None after one save_package, each save logging a warning that said \"Setting the key to first matching key\" (9 across the measurement runs); in PIE the reloaded Default Focus focused the pawn itself","engine":"5.3-5.8","ue":["5.3","5.4","5.5","5.6","5.7","5.8"],"bl":[],"section":"UE Behavior Trees - the editor graph, key filters and what a save does"},{"id":"U384","fact":"**Move To and Default Focus take an Object key whose base class is Actor or a Vector key (their constructors' AddObjectFilter and AddVectorFilter); an Object key's base class defaults to Object, and an Object key passes a filter only when its base class is the filter's or derives from it - so an Object key made with no base class fits neither.** `add_blackboard_key` takes `baseClass` for Object and Class keys.","source":"5.3 and 5.8 `Runtime/AIModule/Private/BehaviorTree/Tasks/BTTask_MoveTo.cpp:35-36`, `Services/BTService_DefaultFocus.cpp:23-24`, `Blackboard/BlackboardKeyType_Object.cpp:14` (BaseClass = UObject) and `:58` (IsAllowedByFilter)","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE Behavior Trees - the editor graph, key filters and what a save does"},{"id":"U385","fact":"**The Behavior Tree editor's graph-node classes for the base node, tasks, subtree tasks, decorators and services are `UCLASS()` with no API macro on 5.3, so their StaticClass does not link from another module; the composite and root graph nodes are exported. 5.8 marks all seven `UCLASS(MinimalAPI)`.** `add_bt_node` finds them by name (/Script/BehaviorTreeEditor.<Class>) on every engine.","source":"5.3 `Editor/BehaviorTreeEditor/Classes/BehaviorTreeGraphNode.h:24`, `_Task.h:17`, `_SubtreeTask.h:17`, `_Decorator.h:18`, `_Service.h:17` (UCLASS() on the line before), `_Composite.h:17` and `_Root.h:20` (BEHAVIORTREEEDITOR_API); 5.8 the same headers, UCLASS(MinimalAPI)","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE Behavior Trees - the editor graph, key filters and what a save does"},{"id":"U386","fact":"**The value-or-key structs (`FValueOrBlackboardKeyBase`, BehaviorTree/ValueOrBBKey.h) arrive in 5.5; 5.3 and 5.4 have no such header. `UBTTask_Wait::WaitTime` is a float on 5.3 and an `FValueOrBBKey_Float` on 5.8.** `add_bt_node` judges a value-or-key's key by its own IsCompatibleType on 5.5+.","source":"the header's presence in 5.3.2, 5.4.4, 5.5.4, 5.6.1, 5.7.4 and 5.8.2 `Runtime/AIModule/Classes/BehaviorTree/`; 5.3 `Tasks/BTTask_Wait.h:24`, 5.8 `:25`","engine":"5.3-5.8","ue":["5.3","5.4","5.5","5.6","5.7","5.8"],"bl":[],"section":"UE Behavior Trees - the editor graph, key filters and what a save does"},{"id":"A108","fact":"**`create_behavior_tree` makes a Behavior Tree with its editor graph, root node and the blackboard asked for; `add_bt_node` joins a Selector to the root, a Sequence and two Waits to it and Move To to the Sequence, hangs a Blackboard decorator on the Sequence and a Default Focus service on the Selector, and reads each back from the runtime tree the engine rebuilt, with its execution index. `describe_behavior_tree` reads the same tree: children in x order, the service and decorator where they were hung, TargetActor used by the task, the decorator and the service.**","source":"measured: `tools/test_behavior_tree_authoring.py` BA100-BA103, 31/31 on 5.3.2, 5.4.4, 5.5.4, 5.6.1, 5.7.4 and 5.8.2","engine":"5.3-5.8","ue":["5.3","5.4","5.5","5.6","5.7","5.8"],"bl":[],"section":"UE Behavior Trees - the editor graph, key filters and what a save does"},{"id":"A109","fact":"**`add_bt_node` refuses, adding nothing: a task on the root, a second root composite, a child under a task, a decorator on the root, an unknown class, a class that is not a tree node, Simple Parallel, a property that does not resolve, an Object key of base class Object on Move To (naming its type, the types Move To takes and the keys that fit), a key the blackboard does not have, a tree that does not exist and a new tree's blackboard that does not exist - neither leaving anything at its path.**","source":"measured: `tools/test_behavior_tree_authoring.py` BA104, 31/31 on 5.3.2, 5.4.4, 5.5.4, 5.6.1, 5.7.4 and 5.8.2","engine":"5.3-5.8","ue":["5.3","5.4","5.5","5.6","5.7","5.8"],"bl":[],"section":"UE Behavior Trees - the editor graph, key filters and what a save does"},{"id":"A110","fact":"**A tree made by `create_behavior_tree` and `add_bt_node` survives serialization, its editor, and a save and reload: duplicate_asset's copy reads the same; the Behavior Tree editor opens it and rebuilds the same tree; after save_package and reload_packages it reads the same, keys included; the editor opens the reloaded copy and rebuilds it the same.**","source":"measured: `tools/test_behavior_tree_authoring.py` BA105-BA106, 31/31 on 5.3.2, 5.4.4, 5.5.4, 5.6.1, 5.7.4 and 5.8.2; 0 LogBehaviorTree warnings in the 5.8.2 log for the run","engine":"5.3-5.8","ue":["5.3","5.4","5.5","5.6","5.7","5.8"],"bl":[],"section":"UE Behavior Trees - the editor graph, key filters and what a save does"},{"id":"A111","fact":"**The tree runs: in PIE a pawn the default AI controller possesses runs it through RunBehaviorTree (true, the brain running), and setting TargetActor on its blackboard turns the controller's focus from none to that actor through the Default Focus service - after the tree was saved and reloaded.**","source":"measured: `tools/test_behavior_tree_authoring.py` BA107, 31/31 on 5.3.2, 5.4.4, 5.5.4, 5.6.1, 5.7.4 and 5.8.2","engine":"5.3-5.8","ue":["5.3","5.4","5.5","5.6","5.7","5.8"],"bl":[],"section":"UE Behavior Trees - the editor graph, key filters and what a save does"},{"id":"A112","fact":"**`add_blackboard_key` takes `baseClass` for Object and Class keys and reads it back on every Object and Class key (/Script/Engine.Actor as asked, /Script/CoreUObject.Object by default, /Script/Engine.Pawn on a Class key); baseClass on a Float key, or naming no class, is refused and adds no key.**","source":"measured: `tools/test_behavior_tree_authoring.py` BA098-BA099, 31/31 on 5.3.2, 5.4.4, 5.5.4, 5.6.1, 5.7.4 and 5.8.2","engine":"5.3-5.8","ue":["5.3","5.4","5.5","5.6","5.7","5.8"],"bl":[],"section":"UE Behavior Trees - the editor graph, key filters and what a save does"},{"id":"A113","fact":"**`describe_behavior_tree` and `ai_setup_report` judge each key a node names by that node's own filter: a use carries fitsFilter and the property that names it, and a Move To whose BlackboardKey was set with set_property to an Object key of base class Object is listed in keysRefusedByFilter (keyType \"Object (base class Object)\", takes \"Object (base class Actor) or Vector keys\") and counted by ai_setup_report, while every use on a tree made by add_bt_node fits.**","source":"measured: `tools/test_behavior_tree_authoring.py` BA108, 36/36 on 5.5.4, 5.6.1, 5.7.4 and 5.8.2 and 34/34 on 5.3.2 and 5.4.4","engine":"5.3-5.8","ue":["5.3","5.4","5.5","5.6","5.7","5.8"],"bl":[],"section":"UE Behavior Trees - the editor graph, key filters and what a save does"},{"id":"A114","fact":"**From 5.5 a Wait's WaitTime takes a blackboard key: `add_bt_node {properties: {WaitTime: {Key: \"WaitSeconds\"}}}` binds it, `describe_behavior_tree` shows WaitSeconds used by the Wait through WaitTime, and a WaitTime bound to an Object key is refused, naming ValueOrBBKey_Float.**","source":"measured: `tools/test_behavior_tree_authoring.py` BA109 on 5.5.4, 5.6.1, 5.7.4 and 5.8.2; not run on 5.3.2 and 5.4.4, where WaitTime is a float","engine":"5.5-5.8","ue":["5.5","5.6","5.7","5.8"],"bl":[],"section":"UE Behavior Trees - the editor graph, key filters and what a save does"},{"id":"U387","fact":"**A Vector blackboard key with no value reads FLT_MAX in every component, not zero: its InvalidValue is FAISystem::InvalidLocation, FVector(FLT_MAX).** A reader of GetValueAsVector must test for it (`gameplay_recipe` enemy_ai's LastKnownLocation is unset exactly so).","source":"5.3 `Runtime/AIModule/Classes/AITypes.h:25`, 5.8 `:23`; 5.3 and 5.8 `Private/BehaviorTree/Blackboard/BlackboardKeyType_Vector.cpp:8`; measured on 5.8.2: GetValueAsVector of an unset LastKnownLocation read 3.4028e38 in X, Y and Z","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE gameplay recipes - an enemy AI on the perception build, sprint, crouch and stamina, a settings menu, footsteps, readables, inspect, a weapon, a sliding door and a flickering light"},{"id":"U388","fact":"**A child Blueprint's component-bound event for a component it inherits is bound beside the parent's own: both run on the delegate.** Measured: a controller derived from `gameplay_recipe` perception's, with its own OnTargetPerceptionUpdated for the inherited Perception component, set TargetActor while the parent's handler set LastSeen, for the same sighting.","source":"measured: `tools/test_gameplay_recipes_live.py` G325 on 5.8.2 and 5.3.2","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE gameplay recipes - an enemy AI on the perception build, sprint, crouch and stamina, a settings menu, footsteps, readables, inspect, a weapon, a sliding door and a flickering light"},{"id":"A115","fact":"**`gameplay_recipe {recipe: \"enemy_ai\"}` builds with every step - 177 with its own perception build - six Blueprints compiling with no error, warning or note, the tree as planned with all 10 key uses fitting their nodes, lint clean, and ai_setup_report reading two controllers, one tree run from one call and two Blueprint tasks.**","source":"measured: `tools/test_gameplay_recipes_live.py` G320-G321, 17/17 on 5.8.2 and 5.3.2; `tools/test_gameplay_recipes_offline.py` G115","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE gameplay recipes - an enemy AI on the perception build, sprint, crouch and stamina, a settings menu, footsteps, readables, inspect, a weapon, a sliding door and a flickering light"},{"id":"A116","fact":"**`gameplay_recipe`'s enemy AI works in PIE on a navmesh: placed with two route points it walks to the first, waits, takes the second; a noise behind it sets LastKnownLocation to the noise; turning, it sees the pawn and TargetActor is the pawn; the pawn gone mid-chase clears TargetActor, leaves LastKnownLocation where it was last seen, and the enemy walks about 1000 units there; after its wait LastKnownLocation clears and it walks its route again.**","source":"measured: `tools/test_gameplay_recipes_live.py` G322-G327, 17/17 on 5.8.2 and 5.3.2","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE gameplay recipes - an enemy AI on the perception build, sprint, crouch and stamina, a settings menu, footsteps, readables, inspect, a weapon, a sliding door and a flickering light"},{"id":"U394","fact":"**A Character's movement component is reached in Blueprint as its CharacterMovement PROPERTY (a variable get, BlueprintReadOnly), not a function: GetCharacterMovement is a plain inline C++ accessor with no UFUNCTION, so add_function_call refuses it.** `gameplay_recipe` movement reads the property to set MaxWalkSpeed.","source":"5.3 `Runtime/Engine/Classes/GameFramework/Character.h:249-250` (UPROPERTY BlueprintReadOnly) and `:392` (the accessor); 5.8 `:355-356` and `:498`; measured on 5.8.2: add_function_call Character.GetCharacterMovement answered \"function not found\"","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE gameplay recipes - an enemy AI on the perception build, sprint, crouch and stamina, a settings menu, footsteps, readables, inspect, a weapon, a sliding door and a flickering light"},{"id":"A117","fact":"**`gameplay_recipe {recipe: \"movement\"}` builds with every step (141): the component and an example Character, both compiling with no error, warning or note, lint clean, the defaults reading back and the example allowed to crouch (CharMoveComp NavAgentProps.bCanCrouch).**","source":"measured: `tools/test_gameplay_recipes_live.py` G330-G331, 12/12 on 5.8.2 and 5.3.2; `tools/test_gameplay_recipes_offline.py` G116","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE gameplay recipes - an enemy AI on the perception build, sprint, crouch and stamina, a settings menu, footsteps, readables, inspect, a weapon, a sliding door and a flickering light"},{"id":"A118","fact":"**`gameplay_recipe`'s movement works in PIE: walking at 600 with stamina full; StartSprint - MaxWalkSpeed 900, moving at it, stamina draining at the rate set (50 a second, measured 40-60); at 0 exhausted, walking with the sprint still held; every reading while exhausted under RecoverAt 30, the exhaustion ending about 1.1 s after it began and the held sprint resuming by itself; StopSprint back to 600 with stamina climbing; crouched at the crouched walk speed with no sprint taken, and standing again.**","source":"measured: `tools/test_gameplay_recipes_live.py` G332-G337, 12/12 on 5.8.2 and 5.3.2","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE gameplay recipes - an enemy AI on the perception build, sprint, crouch and stamina, a settings menu, footsteps, readables, inspect, a weapon, a sliding door and a flickering light"},{"id":"U396","fact":"**DoesSaveGameExist and GetGameUserSettings are BlueprintCallable - impure - though each reads like a getter: a node of either wired only by its return value is pruned by the compiler, with a warning, and its value reads as the default.** Measured on 5.8.2: `gameplay_recipe` settings' first build had DoesSaveGameExist off the exec chain, the compile warned it was pruned, and Load always made new settings.","source":"5.3 `Runtime/Engine/Classes/Kismet/GameplayStatics.h:1153-1154`, 5.8 `:1174-1175`; 5.3 `Runtime/Engine/Classes/GameFramework/GameUserSettings.h:330-331`, 5.8 `:374-375`","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE gameplay recipes - an enemy AI on the perception build, sprint, crouch and stamina, a settings menu, footsteps, readables, inspect, a weapon, a sliding door and a flickering light"},{"id":"U397","fact":"**CreateSaveGameObject's output takes the type of the class given to it (DeterminesOutputType=SaveGameClass) only when the Blueprint compiles: before that, wiring it into a variable of the save class is refused as a plain SaveGame, and after it a cast earns the compiler's \"you don't need\" note.** `gameplay_recipe` settings sets the class, compiles, then wires.","source":"5.3 `Runtime/Engine/Classes/Kismet/GameplayStatics.h:1102-1103`, 5.8 `:1123-1124`; measured on 5.8.2: apply_graph_patch preflight \"Save Game Object Reference is not compatible with SG Settings Object Reference\"","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE gameplay recipes - an enemy AI on the perception build, sprint, crouch and stamina, a settings menu, footsteps, readables, inspect, a weapon, a sliding door and a flickering light"},{"id":"A119","fact":"**`gameplay_recipe {recipe: \"settings\"}` builds with every step (272): three sound classes (Music and Effects under Master), a mix, the save object, the component and the menu, the three Blueprints compiling with no error, warning or note, lint clean.**","source":"measured: `tools/test_gameplay_recipes_live.py` G340-G341, 14/14 on 5.8.2 and 5.3.2; `tools/test_gameplay_recipes_offline.py` G117","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE gameplay recipes - an enemy AI on the perception build, sprint, crouch and stamina, a settings menu, footsteps, readables, inspect, a weapon, a sliding door and a flickering light"},{"id":"A120","fact":"**`gameplay_recipe`'s settings work in PIE: the defaults load with no slot; SetVolumes and SetMouseSensitivity store clamped values (2, -1, 0.5 as 1, 0, 0.5); SetQuality with ApplyQuality sets the engine's overall scalability level; resolution and window mode (0, 1, 2 as fullscreen, windowed fullscreen, windowed) reach GameUserSettings; a save survives every value changed and a load; the menu bound to the component shows every value and ReadControls writes moved controls back.** Not measured: resolution and window mode applied, and the audible level of a volume.","source":"measured: `tools/test_gameplay_recipes_live.py` G342-G348, 14/14 on 5.8.2 and 5.3.2","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE gameplay recipes - an enemy AI on the perception build, sprint, crouch and stamina, a settings menu, footsteps, readables, inspect, a weapon, a sliding door and a flickering light"},{"id":"U398","fact":"**Every Blueprint trace (LineTraceSingle and its kin) asks for the physical material - ConfigureCollisionParams sets bReturnPhysicalMaterial - so a hit result's PhysMat is filled from the hit body, a mesh's PhysMaterialOverride included.** `gameplay_recipe` footsteps keys its sounds by that Physical Material.","source":"5.3 and 5.8 `Runtime/Engine/Private/KismetTraceUtils.cpp:14-17`; measured on 5.8.2 and 5.3.2: floors with SetPhysMaterialOverride gave their own materials to the trace","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE gameplay recipes - an enemy AI on the perception build, sprint, crouch and stamina, a settings menu, footsteps, readables, inspect, a weapon, a sliding door and a flickering light"},{"id":"A121","fact":"**`gameplay_recipe {recipe: \"footsteps\"}` builds with every step (47): the surfaces class, its data asset and the notify - Received_Notify overridden as a function through implement_interface_function - both Blueprints compiling with no error, warning or note, lint clean.**","source":"measured: `tools/test_gameplay_recipes_live.py` G350-G351, 11/11 on 5.8.2 and 5.3.2; `tools/test_gameplay_recipes_offline.py` G118","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE gameplay recipes - an enemy AI on the perception build, sprint, crouch and stamina, a settings menu, footsteps, readables, inspect, a weapon, a sliding door and a flickering light"},{"id":"A122","fact":"**`gameplay_recipe`'s footsteps work in PIE: SoundFor over a floor with one physical material answers that floor's sound and the floor's top as the landing point, over a second floor its own, over an unmapped floor the default, over nothing none; Received_Notify plays and answers true.**","source":"measured: `tools/test_gameplay_recipes_live.py` G352-G356, 11/11 on 5.8.2 and 5.3.2","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE gameplay recipes - an enemy AI on the perception build, sprint, crouch and stamina, a settings menu, footsteps, readables, inspect, a weapon, a sliding door and a flickering light"},{"id":"U399","fact":"**A Blueprint made on a const parent class (AnimNotify, AnimNotifyState) is BPTYPE_Const and has no event graph; the editor overrides there with a function graph, events included, and a const Blueprint's every function compiles const.** Overrides on it go through `implement_interface_function`.","source":"5.8 `Editor/UnrealEd/Private/Kismet2/Kismet2.cpp:442-446` (BPTYPE_Const), `Editor/UnrealEd/Private/Kismet2/BlueprintEditorUtils.cpp:3493-3497` (DoesSupportEventGraphs), `Editor/Kismet/Private/SMyBlueprint.cpp:2881` (5.3 :2780), `Editor/KismetCompiler/Private/KismetCompiler.cpp:4633`; measured on 5.8.2 and 5.3.2: list_graphs of a new AnimNotify Blueprint is empty","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE gameplay recipes - an enemy AI on the perception build, sprint, crouch and stamina, a settings menu, footsteps, readables, inspect, a weapon, a sliding door and a flickering light"},{"id":"U400","fact":"**The compiler's pass for an event overriding a const function covers only the placement error; an event for a const function that returns a value still fails the compile, on the signature.** `add_override_event` places a const function only without an output.","source":"5.8 `Editor/KismetCompiler/Private/KismetCompiler.cpp:3979`; measured on 5.8.2: Character's CanJumpInternal as an event - \"Cannot order parameters ReturnValue in function CanJumpInternal\", \"Cannot override 'Character::CanJumpInternal' ... with a different signature\"; a Blueprint's own const Ping with no output compiled with one note","engine":"5.8","ue":["5.8"],"bl":[],"section":"UE gameplay recipes - an enemy AI on the perception build, sprint, crouch and stamina, a settings menu, footsteps, readables, inspect, a weapon, a sliding door and a flickering light"},{"id":"U401","fact":"**A function graph cannot be made in a macro library: CreateFunctionGraphTerminators - every function graph's entry and result, a dispatcher's signature, an interface's graphs - checks the Blueprint is not one, and the check ends the editor.** The editor offers none there.","source":"5.3 `Editor/BlueprintGraph/Private/EdGraphSchema_K2.cpp:3368`, 5.8 :3325; 5.8 `Editor/UnrealEd/Private/Kismet2/BlueprintEditorUtils.cpp:3480-3485, 3500-3506`, `Editor/Kismet/Private/BlueprintEditor.cpp:9864-9871`; read, not run","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE gameplay recipes - an enemy AI on the perception build, sprint, crouch and stamina, a settings menu, footsteps, readables, inspect, a weapon, a sliding door and a flickering light"},{"id":"A123","fact":"**`implement_interface_function` overrides a parent class's function as well as an interface's - an AnimNotify's Received_Notify and GetNotifyName, a parent Blueprint's hook, a Character's CanJumpInternal, whose override then answers CanJump - reporting the declaring class and fromInterface; it refuses a function that is not a Blueprint event, an event-style one, and one an event already overrides.**","source":"measured: `tools/test_override_routes.py` OV103-OV122, 39/39 on all six engines, 5.3.2 to 5.8.2","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE gameplay recipes - an enemy AI on the perception build, sprint, crouch and stamina, a settings menu, footsteps, readables, inspect, a weapon, a sliding door and a flickering light"},{"id":"A124","fact":"**`add_override_event` refuses, naming `implement_interface_function`, a function that returns a value (const included) and any override on a Blueprint without an event graph, saying why; a name that is not there is 'not found' first.**","source":"measured: `tools/test_override_routes.py` OV101-OV102, OV105, OV110, 39/39 on all six engines, 5.3.2 to 5.8.2","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE gameplay recipes - an enemy AI on the perception build, sprint, crouch and stamina, a settings menu, footsteps, readables, inspect, a weapon, a sliding door and a flickering light"},{"id":"A125","fact":"**Six calls that make a function graph refuse a macro library before changing anything, and the editor keeps running:** create_function, recipe_add_debug_print, implement_interface_function, add_event_dispatcher, add_interface, set_variable_flags' RepNotify.","source":"measured: `tools/test_override_routes.py` OV130-OV138, 39/39 on all six engines, 5.3.2 to 5.8.2","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE gameplay recipes - an enemy AI on the perception build, sprint, crouch and stamina, a settings menu, footsteps, readables, inspect, a weapon, a sliding door and a flickering light"},{"id":"U402","fact":"**A canvas panel and a user widget are both made SelfHitTestInvisible by their constructors: their children take the pointer, they do not.** `gameplay_recipe`'s inspect screen sets its canvas Visible so a drag anywhere reaches OnMouseMove.","source":"5.3 and 5.8 `Runtime/UMG/Private/Components/CanvasPanel.cpp:18`; `Runtime/UMG/Private/UserWidget.cpp` 5.3 :85, 5.8 :100","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE gameplay recipes - an enemy AI on the perception build, sprint, crouch and stamina, a settings menu, footsteps, readables, inspect, a weapon, a sliding door and a flickering light"},{"id":"U403","fact":"**`AActor::AddComponentByClass` is BlueprintInternalUseOnly - the Add Component by Class node's internals - so a graph cannot call it; a component that shows something at runtime spawns an actor instead.**","source":"`Runtime/Engine/Classes/GameFramework/Actor.h` 5.3 :1761, 5.8 :1974","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE gameplay recipes - an enemy AI on the perception build, sprint, crouch and stamina, a settings menu, footsteps, readables, inspect, a weapon, a sliding door and a flickering light"},{"id":"A128","fact":"**`gameplay_recipe {recipe: \"inspect\"}` builds with every step (211, its own stack included): four Blueprints clean, lint clean; OnMouseMove is a function graph and the canvas takes the pointer; the holder's mesh has no collision.**","source":"measured: `tools/test_gameplay_recipes_live.py` G370-G371, 14/14 on 5.8.2 and 5.3.2; `tools/test_gameplay_recipes_offline.py` G120","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE gameplay recipes - an enemy AI on the perception build, sprint, crouch and stamina, a settings menu, footsteps, readables, inspect, a weapon, a sliding door and a flickering light"},{"id":"A129","fact":"**`gameplay_recipe`'s inspect works in PIE: BeginInspect holds the mesh 60 in front of the pawn's eyes, where they look, with the screen up and the game paused; Turn(20, 0) turns it 8 degrees of yaw; EndInspect hides it and brings gameplay's state back; a second BeginInspect shows the same holder; one with no mesh answers false.**","source":"measured: `tools/test_gameplay_recipes_live.py` G372-G376, 14/14 on 5.8.2 and 5.3.2","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE gameplay recipes - an enemy AI on the perception build, sprint, crouch and stamina, a settings menu, footsteps, readables, inspect, a weapon, a sliding door and a flickering light"},{"id":"U404","fact":"**`K2_SetTimer` (by function name) refuses a function whose ParmsSize is above 0 - a return value counts - with only a log warning; the timer's function must take nothing and return nothing.** `gameplay_recipe`'s weapon loops a parameterless AutoFire.","source":"`Runtime/Engine/Private/KismetSystemLibrary.cpp` 5.3 :599-604, 5.8 :698-703","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE gameplay recipes - an enemy AI on the perception build, sprint, crouch and stamina, a settings menu, footsteps, readables, inspect, a weapon, a sliding door and a flickering light"},{"id":"A130","fact":"**`gameplay_recipe {recipe: \"weapon\"}` builds with every step (161): the weapon component and the ammo counter, both with no error, warning or note, lint clean - OnAmmoChanged heard by the counter; defaults 8 shots a second, a clip of 30, 90 in reserve, a 1.5 s reload, 20 damage over 5000.**","source":"measured: `tools/test_gameplay_recipes_live.py` G380-G381, 13/13 on 5.8.2 and 5.3.2; `tools/test_gameplay_recipes_offline.py` G121","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE gameplay recipes - an enemy AI on the perception build, sprint, crouch and stamina, a settings menu, footsteps, readables, inspect, a weapon, a sliding door and a flickering light"},{"id":"A131","fact":"**`gameplay_recipe`'s weapon works in PIE: a shot spends a round and a health build's cube 600 in front takes 20 through ApplyPointDamage, the counter reading 29 / 90; at 2 a second a shot straight after another is refused and one half a second on fires; a shot at nothing spends a round and damages nothing; Reload blocks firing while it runs and then moves 4 from 90 into the clip (30 and 86); StartFire fires 3-7 rounds in half a second at 8 a second and none after StopFire; an empty clip and an empty reserve refuse, and AddAmmo refills.**","source":"measured: `tools/test_gameplay_recipes_live.py` G382-G387, 13/13 on 5.8.2 and 5.3.2","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE gameplay recipes - an enemy AI on the perception build, sprint, crouch and stamina, a settings menu, footsteps, readables, inspect, a weapon, a sliding door and a flickering light"},{"id":"U405","fact":"**A Details-panel write to a PIE actor's component reruns the actor's construction script and replaces the component: the new one keeps the old one's property values, but its dispatchers are empty, and every reference other objects held still points at the old object, renamed TRASH_*.**","source":"measured on 5.8.2 and 5.3.2 (`tools/test_gameplay_recipes_live.py` G388): OnAmmoChanged from a widget's handler to \"()\", the widget's Weapon variable on TRASH_BPC_Weapon_C_0, Clip kept; the rerun is ConsolidatedPostEditChange's (`Runtime/Engine/Private/Components/ActorComponent.cpp`)","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE gameplay recipes - an enemy AI on the perception build, sprint, crouch and stamina, a settings menu, footsteps, readables, inspect, a weapon, a sliding door and a flickering light"},{"id":"A132","fact":"**`set_property` on a component whose owner's construction script reruns answers reconstructed:true and warns that the dispatcher bindings and held references stay with the old, TRASH_* object.**","source":"measured: `tools/test_gameplay_recipes_live.py` G388, on 5.8.2 and 5.3.2","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE gameplay recipes - an enemy AI on the perception build, sprint, crouch and stamina, a settings menu, footsteps, readables, inspect, a weapon, a sliding door and a flickering light"},{"id":"A133","fact":"**`gameplay_recipe`'s door slides when its variant says so: with the drawer variant (bSlide, SlideOffset 40 along X) it opens the hinge 40 out without turning it and closes it back to 0.**","source":"measured: `tools/test_gameplay_recipes_live.py` G269, in the full suite, 267/267 on 5.8.2 and 5.3.2; `tools/test_gameplay_recipes_offline.py` G123","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE gameplay recipes - an enemy AI on the perception build, sprint, crouch and stamina, a settings menu, footsteps, readables, inspect, a weapon, a sliding door and a flickering light"},{"id":"A134","fact":"**`gameplay_recipe {recipe: \"light\"}` builds with every step (46), clean and lint clean; in PIE the light flickers from BeginPlay between 40% and all of its own intensity - the template's - holds its own after StopFlicker and flickers again after StartFlicker.**","source":"measured: `tools/test_gameplay_recipes_live.py` G390-G394, in the full suite, 267/267 on 5.8.2 and 5.3.2; `tools/test_gameplay_recipes_offline.py` G122","engine":"5.3, 5.8","ue":["5.3","5.8"],"bl":[],"section":"UE gameplay recipes - an enemy AI on the perception build, sprint, crouch and stamina, a settings menu, footsteps, readables, inspect, a weapon, a sliding door and a flickering light"},{"id":"U557","fact":"**A walking Character pushes only bodies that are simulating physics, with a force that does not grow with the body's mass, and a placed Pawn is possessed by an AI controller at play start by default.** UCharacterMovementComponent::ApplyImpactPhysicsForces sets bCanBePushed only when the hit body's IsInstanceSimulatingPhysics() (or a simulating geometry collection), and multiplies by mass only with bPushForceScaledToMass. APawn's constructor sets AutoPossessAI = PlacedInWorld, so a placed pawn's ReceivePossessed runs at BeginPlay with an AIController. To make a parked vehicle immovable on foot: leave its physics off while no one drives it, and set Auto Possess AI to Disabled if possession turns physics on.","source":"5.8: Runtime/Engine/Private/Components/CharacterMovementComponent.cpp:7814-7842 and :7880-7882; Runtime/Engine/Private/Pawn.cpp:53 (read in the stock install 2026-10-16); measured 2026-10-16 on 5.8.3: a simulating 13 t wheeled vehicle in park mode was moved about 2.3 m by a walking character; with physics off and AutoPossessAI Disabled it read no controller, physics off, and its placed transform in PIE","engine":"5.8","ue":["5.8"],"bl":[],"section":"UE generic routes settled live - create_asset, set_property, edit_container, call_function, evaluate_sequence (UE 5.8.2 scratch editor, 2026-10-04)"},{"id":"U646","fact":"**In UE 5.8 `UCharacterMovementComponent::bUseAccelerationForPaths` is no longer a member of the movement component (C++ error C2039): it lives on `FNavMovementProperties` (`NavigationTypes.h:432`, `bool bUseAccelerationForPaths = false`), reached as `Move->GetNavMovementProperties()->bUseAccelerationForPaths`; `NavMovementComponent.h:42` carries `UE_DEPRECATED(5.5, \"...use NavMovementProperties.bUseAccelerationForPaths instead.\")`. With it false, AI path following (MoveTo) leaves CurrentAcceleration at zero, so an anim Blueprint that gates walking on acceleration (the third-person template's ABP_Unarmed) plays idle while the pawn slides.**","source":"Engine source UE_5.8 Engine/Source/Runtime/Engine/Classes/AI/Navigation/NavigationTypes.h:432 and GameFramework/NavMovementComponent.h:42,56,139; compile error seen and the fix built 2026-10-20 (UBT_20261020b/c logs). The idle-while-sliding effect: observed in PIE by the user; the acceleration gate is the template ABP's documented behaviour, not re-traced here.","engine":"5.8","ue":["5.8"],"bl":[],"section":"UE generic routes settled live - create_asset, set_property, edit_container, call_function, evaluate_sequence (UE 5.8.2 scratch editor, 2026-10-04)"},{"id":"U662","fact":"**A NavMeshBoundsVolume added to a level whose RecastNavMesh has RuntimeGeneration = Dynamic gets no nav tiles, in the editor world or in a fresh PIE session, until `RebuildNavigation` runs in the editor (and the map is saved for PIE).**","source":"Live 2026-10-25, stock 5.8.3, one-file-per-level map: after duplicating a bounds volume to a new area and saving, `NavigationSystemV1.project_point_to_navigation(world, p, None, None, (100,100,300))` returned None for 4 points inside it, in the editor world and 40 s into PIE, while a point in an older volume projected; after `run_console RebuildNavigation` (world editor) all 4 projected.","engine":"5.8","ue":["5.8"],"bl":[],"section":"UE generic routes settled live - create_asset, set_property, edit_container, call_function, evaluate_sequence (UE 5.8.2 scratch editor, 2026-10-04)"}]