@aeonsparx/pi-unreal 0.0.0-stage → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +89 -0
- package/LICENSE +21 -0
- package/README.md +199 -2
- package/docs/internals.md +245 -0
- package/extensions/unreal/index.ts +696 -0
- package/extensions/unreal/lib/cache.ts +190 -0
- package/extensions/unreal/lib/compiledb.ts +491 -0
- package/extensions/unreal/lib/descriptors.ts +631 -0
- package/extensions/unreal/lib/engine-resolver.ts +443 -0
- package/extensions/unreal/lib/pi-tools.ts +452 -0
- package/extensions/unreal/lib/plugin-resolver.ts +305 -0
- package/extensions/unreal/lib/query.ts +272 -0
- package/extensions/unreal/lib/registry.ts +208 -0
- package/extensions/unreal/lib/scan.ts +510 -0
- package/extensions/unreal/lib/store.ts +1490 -0
- package/extensions/unreal/lib/tools.ts +1074 -0
- package/extensions/unreal/lib/ubt.ts +380 -0
- package/extensions/unreal/lib/util.ts +210 -0
- package/package.json +60 -4
- package/prompts/unreal-context.md +36 -0
- package/skills/ue-engine-resolution/SKILL.md +129 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Version numbers follow
|
|
4
|
+
[Semantic Versioning](https://semver.org/spec/v2.0.0.html). Every version bump in `package.json`
|
|
5
|
+
adds an entry here; release notes stay auto-generated from commits.
|
|
6
|
+
|
|
7
|
+
Rule for bump class (repo policy): new tools, new parameters and new answer types are **minor**;
|
|
8
|
+
**patch** is fixes with the same surface; **major** is a breaking surface change — a removed tool,
|
|
9
|
+
a renamed parameter, or answer text an existing consumer parses.
|
|
10
|
+
|
|
11
|
+
## [Unreleased]
|
|
12
|
+
|
|
13
|
+
## [1.1.0] - 2026-10-28
|
|
14
|
+
|
|
15
|
+
Closes the field findings in `docs/field-findings-2026-10-27.md` (measured on a UE 5.8.3 installed
|
|
16
|
+
engine against a project with 25 enabled plugin references).
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- `unreal_index` `action: "headers"` — a path-only header index answering "does this header exist in
|
|
21
|
+
this engine version?": exact path, owning module, owning plugin, `EnabledByDefault`, and whether
|
|
22
|
+
the `.uproject` references it. Invented names come back as *not a file path* plus the closest real
|
|
23
|
+
file names, labelled as files and never as types. Never built implicitly; keyed by its own root set
|
|
24
|
+
(`lib/store.ts` `buildHeaderIndex`, `lookupHeaderPaths`, `suggestHeaderPaths`; `lib/tools.ts`
|
|
25
|
+
`headerReport`, `headerLookup`).
|
|
26
|
+
- Engine-scope indexes include the project's enabled plugin roots, and `engineAreas` accepts engine
|
|
27
|
+
plugin dials: `["Plugins"]` (every `Engine/Plugins` source tree, ~2.8x the `Runtime` scan) or
|
|
28
|
+
`["Plugins/Animation/PhysicsControl"]` (one plugin).
|
|
29
|
+
- Every answer states what it scanned. A 0-row symbol answer names the index keys, the root kinds
|
|
30
|
+
(`279 engine-source root(s), 62 engine-plugin root(s)`), the plugins the project does not reference
|
|
31
|
+
whose names match the query, and the exact next call (`lib/tools.ts` `zeroResultNotes`,
|
|
32
|
+
`indexCoverageNote`, `rootKindsNote`). `unreal_index` `action: "status"` reports the same per index,
|
|
33
|
+
plus the header indexes.
|
|
34
|
+
- `unreal_context` `module: "X"` reports per-target availability: whether the target's module graph
|
|
35
|
+
contains it, its module directory, the declared module `Type`, its owning plugin with
|
|
36
|
+
`EnabledByDefault`, and the `.uproject` reference status as separate facts
|
|
37
|
+
(`lib/tools.ts` `moduleAvailability`).
|
|
38
|
+
- `unreal_symbol` exposes `substring: true` (the substring pass already existed in `lookupSymbol`;
|
|
39
|
+
it was unreachable from the tool).
|
|
40
|
+
- `unreal_project_inspect` / `unreal_plugin_inspect` name the modules a resolved plugin reference
|
|
41
|
+
buys — `Mover: resolved ← Engine · modules Mover(Runtime), MoverCVDData(Runtime),
|
|
42
|
+
MoverEditor(UncookedOnly)` — and list engine plugins available with **no** `.uproject` reference
|
|
43
|
+
(`EnabledByDefault: true`), separated from the references.
|
|
44
|
+
|
|
45
|
+
### Changed
|
|
46
|
+
|
|
47
|
+
- Index format v6 (`INDEX_VERSION = 6`): `meta.rootKinds` + `meta.areas`. Engine-scope index keys
|
|
48
|
+
change because engine roots now include enabled plugin roots, so v5 engine indexes are not reused
|
|
49
|
+
(one rebuild per machine; project indexes are unaffected).
|
|
50
|
+
- Definitions-mode module attribution names modules after their `*.Build.cs` file, not the directory
|
|
51
|
+
leaf: `Engine/Plugins/Animation/PoseSearch/Source/Runtime` is module `PoseSearch`, not `Runtime`.
|
|
52
|
+
Multi-`Build.cs` directories are disambiguated by the `.uplugin` module names
|
|
53
|
+
(`store.ts` `moduleFromBuildCs`, `buildCsNames`, `pickModuleName`; `assembleRoots` root modules).
|
|
54
|
+
This is what makes `unreal_symbol module: "PoseSearch"` answer in `definitions` mode.
|
|
55
|
+
- Index writes and whole-file passes are streamed: `buildIndex` sorts definition rows per 40 000-row
|
|
56
|
+
shard and k-way merges them into `defs.tsv`, and the linear passes (substring lookup,
|
|
57
|
+
symbols-in-file, module-scope recovery) read the TSV in 4 MB chunks. The whole-Plugins engine scope
|
|
58
|
+
is 1.24 M rows / ~250 MB and previously died in the allocator at 1.91 GB
|
|
59
|
+
(`ReachJSValueFormalMemoryCommit Allocation failed: out of memory`).
|
|
60
|
+
- `unreal_context` `file:` derives scope from path shape (`Engine/Plugins/...` is engine scope), and
|
|
61
|
+
a miss falls back to the header index: "this file exists, in plugin X, `EnabledByDefault` false,
|
|
62
|
+
not referenced by your `.uproject`, here is the call that indexes it" — instead of "not in index".
|
|
63
|
+
- `unreal_index` `action: "compiledb"` with `scope: "project+engine"` now includes `Engine/Plugins`
|
|
64
|
+
sources, where plugin `.cpp` bodies live.
|
|
65
|
+
|
|
66
|
+
### Fixed
|
|
67
|
+
|
|
68
|
+
- `engineAreas` schema wording: `["Runtime"]` is the engine's own gameplay code, not every gameplay
|
|
69
|
+
type — plugin-shipped types were unreachable and a 0 read as "the engine has no such type".
|
|
70
|
+
- `test/live-check.ts` no longer defaults to a machine-local `.uproject` path (it resolved to
|
|
71
|
+
nothing on CI) and prints a usage line instead.
|
|
72
|
+
|
|
73
|
+
### Documentation
|
|
74
|
+
|
|
75
|
+
- `README.md` and `docs/internals.md`: engine/plugin coverage and its measured cost, the header index
|
|
76
|
+
and the path-vs-symbol distinction, "an empty clangd answer is evidence", and the asset boundary —
|
|
77
|
+
pi-unreal answers C++ declaration/module/include/dependency facts and does not answer UENUM index
|
|
78
|
+
order, UStruct field types, UCLASS/CDO values or Blueprint graphs (that needs the `unreal-engine`
|
|
79
|
+
editor MCP with the editor running).
|
|
80
|
+
|
|
81
|
+
## [1.0.0]
|
|
82
|
+
|
|
83
|
+
- Initial release: `unreal_resolve_engine`, `unreal_project_inspect`, `unreal_plugin_inspect`,
|
|
84
|
+
`unreal_symbol`, `unreal_symbol_list`, `unreal_context`, `unreal_index` (compiler-free symbol
|
|
85
|
+
index, UnrealBuildTool Query facts, clangd compile-database enrichment).
|
|
86
|
+
|
|
87
|
+
[Unreleased]: https://github.com/Aeonsparx-Interactive/pi-unreal/commits/main
|
|
88
|
+
[1.1.0]: https://github.com/Aeonsparx-Interactive/pi-unreal/releases/tag/v1.1.0
|
|
89
|
+
[1.0.0]: https://github.com/Aeonsparx-Interactive/pi-unreal/releases/tag/v1.0.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Aeonsparx Interactive
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,200 @@
|
|
|
1
|
-
#
|
|
1
|
+
# pi-unreal
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Unreal Engine awareness for the Pi coding agent.**
|
|
4
|
+
|
|
5
|
+
Open a UE project in a `pi` session and the agent stops guessing. It knows which engine
|
|
6
|
+
installation that `.uproject` really resolves to, what the `.uproject` / `.uplugin` files actually
|
|
7
|
+
say, which plugins exist on disk, and where a C++ symbol is declared — with the file, the line and
|
|
8
|
+
the owning module. No compiler, no Visual Studio, no Rider, no clangd required.
|
|
9
|
+
|
|
10
|
+
It is **read-only**: it never writes to your project, never touches the Windows registry, never
|
|
11
|
+
launches the editor, and blocks three kinds of edit that damage Unreal work.
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
### Requirements
|
|
16
|
+
|
|
17
|
+
- **Windows**, with **PowerShell 7** (`pwsh`) for registry-based engine discovery. Without it the
|
|
18
|
+
extension still works: resolution falls back to `UNREAL_ENGINE` / `UE_ROOT` /
|
|
19
|
+
`PI_UNREAL_ENGINE_ROOT`, the Launcher's install list, and a scan of
|
|
20
|
+
`C:/Program Files/Epic Games`.
|
|
21
|
+
- An Unreal Engine installation the project can resolve to (Launcher install or source build).
|
|
22
|
+
Descriptor field handling is transcribed from UE 5.8.
|
|
23
|
+
- Nothing else. No compiler, no IDE language service. clangd is optional enrichment for
|
|
24
|
+
`compiledb` and the `clangd --check` acceptance step.
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
### Installation
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pi install npm:@aeonsparx/pi-unreal # optionally pin to a specific version, reproducible
|
|
31
|
+
pi install git:github.com/Aeonsparx-Interactive/pi-unreal@v1.1 # follows patch releases on the v1.1 line
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The `npm:` route installs from the registry and pins an exact version. The `git:` route clones the
|
|
35
|
+
repository and checks out the ref: a line alias (`@v1.1`) is a moving tag that patch releases
|
|
36
|
+
force-move, so `pi` picks up patches on update; pin `@v1.1.0` for a fixed snapshot. Loading straight
|
|
37
|
+
from a clone still works and needs no install: `pi -e ./extensions/unreal/index.ts`.
|
|
38
|
+
|
|
39
|
+
## What you get in a session
|
|
40
|
+
|
|
41
|
+
**Context is detected for you.** When the session starts in a directory that contains a
|
|
42
|
+
`.uproject` — the working directory itself, or any of up to 3 parent directories — one note is
|
|
43
|
+
shown before the first answer: the resolved engine root and version, installed vs source build,
|
|
44
|
+
the project's modules, the number of declared plugin references, and the conventions below. Ask
|
|
45
|
+
for a re-check any time with `/unreal`.
|
|
46
|
+
|
|
47
|
+
**Ask in plain English.** "Which engine is this project on?", "Is MassGameplay available to this
|
|
48
|
+
project?", "Where is `FLpMovementDirectionThresholds` defined?", "What do I need to link to use
|
|
49
|
+
`UAnimInstance`?" The agent picks the matching tool:
|
|
50
|
+
|
|
51
|
+
| Tool | Question it answers |
|
|
52
|
+
| --- | --- |
|
|
53
|
+
| `unreal_resolve_engine` | "Which engine does this `.uproject` use — and how do you know?" |
|
|
54
|
+
| `unreal_project_inspect` | Modules, target platforms, and every plugin reference resolved against the plugins that exist on disk |
|
|
55
|
+
| `unreal_plugin_inspect` | One `.uplugin` as the engine parses it: modules, loading phases, version fields, plugin dependencies |
|
|
56
|
+
| `unreal_symbol` | "Where is this class / struct / function / `UPROPERTY` / delegate declared?" One line per hit: kind, file:line, module |
|
|
57
|
+
| `unreal_symbol_list` | "What does this project define?" Names by prefix — `ULp`, `ANiMy`, `UAnim` |
|
|
58
|
+
| `unreal_context` | "What does this file/module include, define, and depend on?" Include paths, dependency lists, the real `WITH_*` defines; for a module, also whether the target's module graph contains it and how the `.uproject` treats its plugin |
|
|
59
|
+
| `unreal_index` | Builds and reports the source index, the path-only **header index** ("does this header exist in this engine version?"), and the clangd compile database on request |
|
|
60
|
+
|
|
61
|
+
**Slash commands you can type yourself:**
|
|
62
|
+
|
|
63
|
+
| Command | Result |
|
|
64
|
+
| --- | --- |
|
|
65
|
+
| `/unreal [project]` | Engine, modules and plugin-reference report for this directory |
|
|
66
|
+
| `/unreal-engines` | Every engine installation this machine can prove, and how each was found |
|
|
67
|
+
| `/unreal-symbol <symbol>` | Definition lookup, project + plugins, then engine if an engine index exists |
|
|
68
|
+
| `/unreal-module <Module>` | Module directory, public/private dependency lists, defines file, C++ standard, SDK |
|
|
69
|
+
| `/unreal-cache stats\|clear` | Inspect or clear the cached indexes |
|
|
70
|
+
|
|
71
|
+
Example — `/unreal`:
|
|
72
|
+
|
|
73
|
+
```text
|
|
74
|
+
project C:/Work/Lp/Lp.uproject
|
|
75
|
+
engine: C:/Program Files/Epic Games/UE_5.8
|
|
76
|
+
version 5.8.3 | installed build | association "5.8" (version) via dir-scan
|
|
77
|
+
Build.version: C:/Program Files/Epic Games/UE_5.8/Engine/Build/Build.version
|
|
78
|
+
modules: Lp (Runtime), LpEditor (Editor)
|
|
79
|
+
plugins declared: 25
|
|
80
|
+
plugin index: 897 .uplugin (cache hit)
|
|
81
|
+
plugin references:
|
|
82
|
+
Mover: resolved ← Engine · modules Mover(Runtime), MoverCVDData(Runtime), MoverEditor(UncookedOnly)
|
|
83
|
+
MassGameplay: resolved ← Engine · modules MassEntity(Runtime), MassCore(Runtime), MassSimulation(Runtime), …
|
|
84
|
+
SomeLocalPlugin: resolved ← Project · modules SomeLocalPlugin(Runtime)
|
|
85
|
+
RetiredPlugin: missing
|
|
86
|
+
totals: 22 resolved, 3 missing of 25 references
|
|
87
|
+
engine plugins available with NO .uproject reference (EnabledByDefault true): GameplayCameras, IKRig
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Example — `unreal_symbol` for an engine type (engine index already built):
|
|
91
|
+
|
|
92
|
+
```text
|
|
93
|
+
unreal_symbol 'AActor' scope=engine: 1 definition(s)
|
|
94
|
+
class AActor C:/Program Files/Epic Games/UE_5.8/Engine/Source/Runtime/Engine/Classes/GameFramework/Actor.h:282 [Engine · engine]
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
That is a definition line, not a grep dump: grepping a hot engine class name returns ~176 files of
|
|
98
|
+
noise, which is exactly what burns a session's context.
|
|
99
|
+
|
|
100
|
+
Example — `unreal_index` `action: "headers"`, the question a symbol index cannot answer:
|
|
101
|
+
|
|
102
|
+
```text
|
|
103
|
+
unreal_index headers → hdr-UE_5.8-1a40c1c3d516
|
|
104
|
+
37,788 header paths from 1,934 roots (1,655 engine-plugin root(s), 279 engine-source root(s))
|
|
105
|
+
'MoverState.h': does NOT exist as a file path in this engine version
|
|
106
|
+
closest real file names (files, not types):
|
|
107
|
+
Engine/Plugins/Experimental/Mover/Source/Mover/Public/MoverTypes.h [Mover]
|
|
108
|
+
Engine/Plugins/Experimental/Mover/Source/Mover/Public/MoverSimulationTypes.h [Mover]
|
|
109
|
+
Engine/Plugins/Experimental/Mover/Source/Mover/Public/MovementMode.h [Mover]
|
|
110
|
+
Engine/Plugins/Experimental/Mover/Source/Mover/Public/MovementModeStateMachine.h [Mover]
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
`MoverState.h` is the kind of name an agent invents. The answer says it is not a file, lists real
|
|
114
|
+
files, and never presents a file name as a type. The same call on
|
|
115
|
+
`PhysicsControlComponent.h` returns the path plus `plugin PhysicsControl [Engine] · EnabledByDefault
|
|
116
|
+
false · .uproject reference NO` — the file exists, the project does not reference the plugin, and
|
|
117
|
+
those are different facts.
|
|
118
|
+
|
|
119
|
+
Example — the coverage lines a 0-row answer prints (nothing here says "the engine has no such type"):
|
|
120
|
+
|
|
121
|
+
```text
|
|
122
|
+
unreal_symbol 'PhysicsControlComponent' scope=engine: 0 definition(s)
|
|
123
|
+
· no definitions matched 'PhysicsControlComponent' in scope 'engine'
|
|
124
|
+
· scanned engine index idx-engine-defs-b8d82464af4a: 279 engine-source root(s), 62 engine-plugin root(s)
|
|
125
|
+
· engine plugins on disk: 897, referenced by this .uproject: 25; the engine index scans referenced plugins only
|
|
126
|
+
· a plugin the project does not reference is not in any index root: pass engineAreas ["Plugins"] (…2.8× the Runtime scan) or ["Plugins/Animation/PhysicsControl"]
|
|
127
|
+
· next: unreal_symbol query 'PhysicsControlComponent' scope "all" prefix true, or unreal_index action "headers" name "PhysicsControlComponent.h"
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Guardrails (automatic, nothing to enable)
|
|
131
|
+
|
|
132
|
+
| Situation | What happens |
|
|
133
|
+
| --- | --- |
|
|
134
|
+
| An edit targeting `*.uasset` / `*.umap` | **Blocked** — those are cooked binary assets; author them in the running editor |
|
|
135
|
+
| A C++ edit while `UnrealEditor` is running | **Warning** — freshly compiled C++ will not load into a running editor; close it, then build |
|
|
136
|
+
| `clang-format` aimed at a `*.cs` file | **Blocked** — clang-format applies the C# rule and can empty the file |
|
|
137
|
+
|
|
138
|
+
## Costs: what is fast, and what is opt-in
|
|
139
|
+
|
|
140
|
+
| Operation | Time |
|
|
141
|
+
| --- | --- |
|
|
142
|
+
| Cached lookup (symbol, project facts) | ~0.3 s |
|
|
143
|
+
| First project/plugin index (≈2,400 files) | seconds |
|
|
144
|
+
| Engine `Runtime` index — cold | ~1 minute |
|
|
145
|
+
| Engine `Runtime` index — warm | ~6 s |
|
|
146
|
+
| UnrealBuildTool Query facts | ~7 s, then cached |
|
|
147
|
+
| clangd compile database (`unreal_index` → `compiledb`) | minutes, ~1 GB for the engine scope |
|
|
148
|
+
|
|
149
|
+
Because of that model:
|
|
150
|
+
|
|
151
|
+
- Symbol lookups never stall. If a question needs engine sources and no engine index exists, the
|
|
152
|
+
agent reports the cost and how to pay it, and asks you. Say **yes** once per machine —
|
|
153
|
+
`/unreal-cache stats` shows what you have. Engine scans default to `engineAreas: ["Runtime"]`,
|
|
154
|
+
which is the engine's **own** gameplay code (`AActor`, `UAnimInstance`, `USceneComponent`);
|
|
155
|
+
`Editor` and `Developer` are opt-in and roughly triple the scan. An engine-scope index always
|
|
156
|
+
includes the plugin roots your `.uproject` enables, so `UMoverComponent` and the PoseSearch types
|
|
157
|
+
are in it. Types shipped by plugins you do **not** reference (`PhysicsControl`, `BlendStack`,
|
|
158
|
+
`StateTree`, `GameplayAbilities`) need `engineAreas: ["Plugins"]` — every `Engine/Plugins`
|
|
159
|
+
source tree, ~2.8× the `Runtime` scan — or `engineAreas: ["Plugins/Animation/PhysicsControl"]`
|
|
160
|
+
for one plugin.
|
|
161
|
+
- "Does this header exist in this engine version?" is a path question, not a symbol question:
|
|
162
|
+
`unreal_index` with `action: "headers"` (and `name: "MoverState.h"`) answers it in seconds from a
|
|
163
|
+
path walk, and says which plugin owns a header it finds, whether that plugin is
|
|
164
|
+
`EnabledByDefault`, and whether your `.uproject` references it. Invented names come back as
|
|
165
|
+
*not a file path* plus the closest real **file** names — never as types.
|
|
166
|
+
- Ask for `unreal_index` with `action: "build"`, `scope: "engine"` when you want engine-wide
|
|
167
|
+
navigation, and `action: "compiledb"` when you want clangd's references/call hierarchy.
|
|
168
|
+
- After a branch switch, a rebase, adding a plugin, or an engine version change, say "rebuild the
|
|
169
|
+
Unreal index" (that is `refresh: true`).
|
|
170
|
+
- Everything lives in `~/.pi/agent/unreal-cache` (override with `$PI_UNREAL_CACHE_DIR`) — never
|
|
171
|
+
inside your project tree or your engine installation. The compile database encodes this
|
|
172
|
+
machine's absolute paths, so it is machine-local by design.
|
|
173
|
+
|
|
174
|
+
## Troubleshooting
|
|
175
|
+
|
|
176
|
+
| Report | What to do |
|
|
177
|
+
| --- | --- |
|
|
178
|
+
| `engine: AMBIGUOUS — more than one valid installation matches` | Two roots match the association. Pass the one you want as `engineRootHint` (e.g. `engineRootHint: "C:/Program Files/Epic Games/UE_5.8"`). |
|
|
179
|
+
| `engine: UNRESOLVED` with rejected candidates | Read the reasons — a stale registry key, a missing `Build.version`, a version mismatch. The report lists remediation steps; the extension never writes registry keys for you. |
|
|
180
|
+
| `no .uproject within 4 levels above …` | The search walks up from the working directory. Pass the project explicitly: `project: "C:/Work/Lp/Lp.uproject"` (a directory containing one works too). |
|
|
181
|
+
| `unreal_symbol` finds nothing in scope `engine` | Read the coverage lines the answer prints: they name the root kinds that were scanned. A plugin your `.uproject` does not reference is in no index root — `engineAreas: ["Plugins"]` (or one plugin subtree), then rebuild. |
|
|
182
|
+
| `unreal_symbol` finds nothing and you are not sure the name exists | `unreal_index` → `action: "headers"`, `name: "ThatName.h"`: a seconds-long path answer with the closest real file names. |
|
|
183
|
+
| Results look stale after a rebase or engine update | Re-run with `refresh: true`, or `/unreal-cache clear`. |
|
|
184
|
+
| `no plugin named "X" in the index` | That reference is genuinely not on disk. `/unreal` shows which roots were scanned. |
|
|
185
|
+
|
|
186
|
+
### What it deliberately does not do
|
|
187
|
+
|
|
188
|
+
- It does not install, register, migrate, or "fix" an engine, and never writes registry keys.
|
|
189
|
+
- It does not build, cook, package, launch the editor, or edit `.ini` files.
|
|
190
|
+
- It does not hand-edit assets, and blocks attempts to.
|
|
191
|
+
- Symbol lookup reports **declarations**. Type resolution, overloads, call sites, inheritance and
|
|
192
|
+
diagnostics are clangd's job when clangd is installed. An empty clangd answer is evidence: on an
|
|
193
|
+
installed engine the compile database has no engine translation units, so "clangd found nothing"
|
|
194
|
+
in engine code is a property of the setup, not a bug this package fixes.
|
|
195
|
+
- A 0-row answer is a statement about **the roots that were scanned**, never about the engine. The
|
|
196
|
+
answer names its index keys and root kinds; `unreal_index` → `action: "status"` prints the same.
|
|
197
|
+
- pi-unreal answers C++ **declaration, module, include-path and dependency** facts. It does not
|
|
198
|
+
answer asset questions — UENUM index order, UStruct field types, UCLASS/CDO instance values,
|
|
199
|
+
Blueprint graphs. Those need the `unreal-engine` editor MCP with the editor running.
|
|
200
|
+
- `.ini` provenance, live-coding state, and asset metadata are out of scope for v1.
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
# pi-unreal internals
|
|
2
|
+
|
|
3
|
+
Design and implementation notes: how the tools derive their answers, and the measured numbers behind
|
|
4
|
+
the cost model. Read the README for day-to-day usage; this file is the engine-facing detail that
|
|
5
|
+
the README deliberately leaves out.
|
|
6
|
+
|
|
7
|
+
## Symbol index (no compiler, no IDE)
|
|
8
|
+
|
|
9
|
+
`unreal_symbol`, `unreal_context`, and `unreal_index` answer navigation questions from two
|
|
10
|
+
compiler-free sources:
|
|
11
|
+
|
|
12
|
+
1. **UnrealBuildTool Query** (`-Mode=Query`: `TargetDetails`, `TargetModuleReferences`) — the
|
|
13
|
+
engine's own record of targets, modules, module dependencies, include paths, and forced
|
|
14
|
+
includes. Measured on UE 5.8: 6.0 s for 1,079 modules, 2.1 s for the dependency graph, and it
|
|
15
|
+
needs no compiler. That is why MSVC-only machines (Visual Studio, Rider) are first class here:
|
|
16
|
+
Visual Studio's `Browse.VC.db` is encrypted with no public API, Rider's resolver is in-process
|
|
17
|
+
through RiderLink, and both derive their context from the same UBT rules this layer reads.
|
|
18
|
+
2. **A regex definition scanner** over the project, its enabled plugins, and the engine areas its
|
|
19
|
+
modules actually depend on — `class`/`struct`/`enum`/`union`, `UFUNCTION`, `UPROPERTY`,
|
|
20
|
+
delegates, aliases, with `Owner:Member` qualified names and forward declarations marked. In an
|
|
21
|
+
installed engine "engine areas" is not where the gameplay types are: `Engine/Source/Runtime` is the
|
|
22
|
+
engine's own code, and plugin-shipped types live under `Engine/Plugins/<Category>/<Plugin>/Source/`,
|
|
23
|
+
so an engine-scope index takes its plugin roots from the `.uproject` (plus an explicit
|
|
24
|
+
`engineAreas: ["Plugins"]` dial for the rest).
|
|
25
|
+
|
|
26
|
+
Artifacts live in `$PI_UNREAL_CACHE_DIR/indexes/<key>/` (`meta.json`, `defs.tsv`, `files.tsv`,
|
|
27
|
+
plus `includes.tsv` in `full` mode): plain TSV — greppable, inspectable, shared across sessions
|
|
28
|
+
and projects — and never inside the project tree or the engine installation.
|
|
29
|
+
|
|
30
|
+
Writes and whole-file passes are **streamed**, because the whole-Plugins engine index is 1.24 M rows
|
|
31
|
+
(~250 MB of TSV): `buildIndex` sorts rows per 40 000-row shard and k-way merges them into `defs.tsv`
|
|
32
|
+
(peak memory is one shard, output is identical to a single sorted pass), and the linear passes
|
|
33
|
+
(substring lookup, symbols-in-file, module scope recovery) read the TSV in 4 MB chunks and stop when
|
|
34
|
+
the answer is full. An earlier build accumulated every row in an array and died in the allocator at
|
|
35
|
+
1.91 GB (`ReachJSValueFormalMemoryCommit Allocation failed: out of memory`) — which is the failure
|
|
36
|
+
mode of "just load the index" at engine scale.
|
|
37
|
+
|
|
38
|
+
Measured on this box (UE 5.8.3 installed engine; Lp project with 25 enabled plugins):
|
|
39
|
+
|
|
40
|
+
| Scope | Files | Definitions | Cold build |
|
|
41
|
+
| --- | --- | --- | --- |
|
|
42
|
+
| Project + plugins | 2,405 | 38,901 | 6.7 s |
|
|
43
|
+
| Engine `Runtime` (shipped default: 279 module roots) | 18,566 | 436,729 | 57.6 s cold, 5.7 s warm |
|
|
44
|
+
| Engine `Runtime` + 62 enabled plugin roots | 20,966 | 476,327 | 122 s cold, 0.4 s warm |
|
|
45
|
+
| Engine `Runtime` + every `Engine/Plugins` source | 71,004 | 1,240,246 | ~2 min cold (1,996 roots: 279 engine-source + 1,717 engine-plugin) |
|
|
46
|
+
| Engine `Runtime/Core` + `Runtime/CoreUObject` | 3,094 | 70,548 | 16 s |
|
|
47
|
+
| Header index (paths only, engine `Runtime` + all `Engine/Plugins`) | 37,788 headers | — | 4.5 s cold, 0.5 s warm |
|
|
48
|
+
| Cached lookup | — | — | ~0.3 s |
|
|
49
|
+
|
|
50
|
+
Cost discipline is the design. A lookup builds the project index (seconds) and uses an engine
|
|
51
|
+
index only if one exists; `scope: "engine"` on a cold machine returns
|
|
52
|
+
`engine index not built — build it with unreal_index (action: "build", scope: "engine")` instead of
|
|
53
|
+
spending minutes on a scan nobody asked for. `unreal_index` is the explicit, paid path.
|
|
54
|
+
|
|
55
|
+
Ranking inside `unreal_symbol`: exact (0) → qualified member (1) → prefix (2) → substring (3).
|
|
56
|
+
Forward declarations rank last, so `unreal_symbol AActor` returns
|
|
57
|
+
`Engine/Source/Runtime/Engine/Classes/GameFramework/Actor.h:282` (the `UCLASS` declaration), not
|
|
58
|
+
the `class AActor;` line in `PhysicsCollision.h`.
|
|
59
|
+
`unreal_symbol LpGameModeBase` finds `ALpGameModeBase` (the UE prefix is added for you); `unreal_symbol FLpMovementDirectionThresholds:F` finds a single-letter `UPROPERTY` field; `unreal_context LpCharacterTypes.h` resolves a bare file name through the index. Engine areas are derived from module
|
|
60
|
+
dependencies (`.uproject` modules → recursive `PublicDependencyModuleNames` → plugin-supplied
|
|
61
|
+
modules → recursive `PublicDependencyModuleNames` → plugin-supplied
|
|
62
|
+
modules → `Engine/Source/<area>/*`), so the index contains what this project can compile against,
|
|
63
|
+
not the whole engine. An **engine-scope** index is `Engine/Source/<area>` roots *plus the plugin
|
|
64
|
+
roots the `.uproject` enables* — in UE 5.8 most gameplay types ship as plugins (`Mover`,
|
|
65
|
+
`PoseSearch`, `SmartObjects`, `BlendStack`, `StateTree`, `GameplayAbilities`), and an index of
|
|
66
|
+
`Engine/Source/Runtime` alone reports 0 rows for `UMoverComponent` while the project index already
|
|
67
|
+
contains it. Engine plugins the project does **not** reference are in no root: `engineAreas:
|
|
68
|
+
["Plugins"]` adds every `Engine/Plugins` source tree (~2.8× the `Runtime` scan),
|
|
69
|
+
`["Plugins/Animation/PhysicsControl"]` adds one.
|
|
70
|
+
|
|
71
|
+
Every answer states what it scanned: index key, root kinds (`279 engine-source root(s),
|
|
72
|
+
62 engine-plugin root(s)`), and the `engineAreas` it was built with. A 0-row answer is a statement
|
|
73
|
+
about those roots, never about the engine, and it prints the exact next call.
|
|
74
|
+
|
|
75
|
+
## Header index (`unreal_index` action `headers`)
|
|
76
|
+
|
|
77
|
+
"Does this header exist in this engine version?" is a path question that a definitions index cannot
|
|
78
|
+
answer: absence of a symbol row is not absence of a file, and the index roots exclude every plugin
|
|
79
|
+
the project does not enable. `buildHeaderIndex` walks file **paths** only — no content read — over
|
|
80
|
+
the same root assembly (`Engine/Source/<area>`, `Engine/Plugins/...`, project sources), writes
|
|
81
|
+
`headers.tsv` (`file \t module \t kind`) beside the symbol indexes, and answers exists / exact path
|
|
82
|
+
/ owning module / owning plugin / `EnabledByDefault` / referenced-in-`.uproject`. Measured: 37,788
|
|
83
|
+
header paths in 4.5 s on a UE 5.8 install (`Runtime` + all of `Engine/Plugins`).
|
|
84
|
+
|
|
85
|
+
It is never built implicitly (a path answer must not cost a scan nobody asked for), its key encodes
|
|
86
|
+
its own root set, and when the name does not exist the answer lists the closest real **file** names
|
|
87
|
+
labelled as files. That is the discipline behind it: an invented name like `MoverState.h` must not
|
|
88
|
+
become a confident type suggestion — the old workflow produced `Mover/Public/InputContainerStruct.h`
|
|
89
|
+
(a real file, a bogus answer) for `FCharacterDefaultInputs`, and the types
|
|
90
|
+
`FPoseSearchBlendPose(History)` do not exist in 5.8 at all.
|
|
91
|
+
|
|
92
|
+
One engine fact worth knowing: UBT Query reports `"defines": []` for every module. The effective
|
|
93
|
+
preprocessor set lives in a forced include —
|
|
94
|
+
`Intermediate/Build/<Platform>/<Config>/<Target>/Development/<Module>/Definitions.<Module>.h` —
|
|
95
|
+
and `unreal_context` reads that file instead of guessing `WITH_*` values. Query is also never
|
|
96
|
+
run with `-NoIntellisense`: that flag produces a syntactically valid skeleton with an empty
|
|
97
|
+
`moduleToCompileSettings`, and `payloadOk()` rejects it.
|
|
98
|
+
|
|
99
|
+
## clangd enrichment (`unreal_index` action `compiledb`)
|
|
100
|
+
|
|
101
|
+
The definition index is the compiler-free path. When you want clangd's semantic power (references,
|
|
102
|
+
call hierarchy, diagnostics), the database it needs comes from the engine: `UnrealBuildTool
|
|
103
|
+
-Modes=GenerateClangDatabase`, normalized in the pi-unreal cache.
|
|
104
|
+
|
|
105
|
+
The UnrealBuildTool invocation is the part nobody documents, so it is encoded in one place
|
|
106
|
+
(`lib/compiledb.ts`):
|
|
107
|
+
|
|
108
|
+
- The target is **three positional tokens** — `Win64 Development LpEditor`. `TargetDescriptor` only
|
|
109
|
+
inspects arguments that do not start with `-`, and its `+` split requires every token to be the
|
|
110
|
+
same kind, so `-Target=LpEditor` fails with `No platforms specified for target` and
|
|
111
|
+
`Win64+Development+LpEditor` fails with `The platform name Development is not a valid platform
|
|
112
|
+
name`. `-Platform=`/`-Configuration=` set `BuildConfiguration` only and produce a duplicate
|
|
113
|
+
platform error next to the positional tokens.
|
|
114
|
+
- `-OutputDir=` must already exist (UnrealBuildTool throws
|
|
115
|
+
`DirectoryNotFoundException: Could not find a part of the path ...\compile_commands.json`), and
|
|
116
|
+
the mode's own `-NoPCH -NoVFS -Compiler=Clang` additions mean the emitted driver is
|
|
117
|
+
`clang-cl.exe`, not `cl.exe`.
|
|
118
|
+
- `-Include=` rules match nothing useful (measured: `Source/Lp`, `*/Source/Lp/*`,
|
|
119
|
+
`C:/Users/.../Source/Lp/**` all yield an empty database), so scoping happens after generation.
|
|
120
|
+
|
|
121
|
+
Normalization is Epic's `stripPostPch.py` recipe, ported: expand the per-module `@file.rsp`
|
|
122
|
+
response files, drop `/Yu* /Fm* /Fe* /Fp*` and everything after `/link`, drop PCH translation
|
|
123
|
+
units (`SharedPCH.*.h.cpp`, `PCH.*.h.cpp`) and header entries, then keep the requested scope. The
|
|
124
|
+
database is written to `$PI_UNREAL_CACHE_DIR/compiledb/<target>.<platform>.<config>/` — it encodes
|
|
125
|
+
this machine's absolute paths and toolchain version, so it is a machine artifact, never a repo one.
|
|
126
|
+
|
|
127
|
+
`check: "<file>"` runs `clangd --check` against the result, which is the acceptance test. Measured
|
|
128
|
+
on Lp (UE 5.8.3, installed engine, VS 18 LLVM clangd): UnrealBuildTool 1.5-1.7 s, 4 entries,
|
|
129
|
+
4 response files expanded, 0 switches dropped; `clangd --check` built a 62 MB preamble and
|
|
130
|
+
reported **`All checks completed, 0 errors`** in ~2.6 s.
|
|
131
|
+
|
|
132
|
+
The honest limits of that 4-entry number: an installed (precompiled) engine contributes no compile
|
|
133
|
+
actions, so the database covers the project's own translation units, not `Engine/Source`. Engine
|
|
134
|
+
files still work under clangd because the project's `.clangd` supplies the include paths — exactly
|
|
135
|
+
what Epic's Unreal-clangd VS Code extension does (its generated `Lp.0.rsp` contains only `/FI`
|
|
136
|
+
plus 523 `/I` lines, and `compile_commands.json` there has 6 project entries and no engine entry).
|
|
137
|
+
Re-run with `refresh: true` after changing `Build.cs` files, adding modules, or switching engine
|
|
138
|
+
version.
|
|
139
|
+
|
|
140
|
+
## How engine resolution works
|
|
141
|
+
|
|
142
|
+
Mirrors `FDesktopPlatformWindows::GetAvailableEngineDescriptions`
|
|
143
|
+
(`Engine/Source/Developer/DesktopPlatform/Private/DesktopPlatformBase.cpp:459-511`) and
|
|
144
|
+
`VerifyEngineGuid` (`DesktopPlatformWindows.cpp:615-664`):
|
|
145
|
+
|
|
146
|
+
| `.uproject` association | Source of truth |
|
|
147
|
+
| --- | --- |
|
|
148
|
+
| engine-root path | used directly, validated |
|
|
149
|
+
| `5.8` (Launcher install) | `HKLM:\SOFTWARE\EpicGames\Unreal Engine\<ver>` → `InstalledDirectory`, then `<installDirDefault>\UE_<ver>` |
|
|
150
|
+
| `{GUID}` (source build) | `HKCU:\SOFTWARE\Epic Games\Unreal Engine\Builds` |
|
|
151
|
+
| empty | walk up 12 levels looking for `Engine/Config/BaseEngine.ini` |
|
|
152
|
+
|
|
153
|
+
Below the association: `LauncherInstalled.dat`, `HKLM` versions, `UNREAL_ENGINE` / `UE_ROOT` /
|
|
154
|
+
`PI_UNREAL_ENGINE_ROOT`, and a scan of `C:/Program Files/Epic Games` for `UE_*`. Explicit
|
|
155
|
+
`engineRootHint` outranks every registry source.
|
|
156
|
+
|
|
157
|
+
Every candidate is validated before use — `Engine/Binaries` + `Engine/Build`
|
|
158
|
+
(`DesktopPlatformBase.cpp:401-421`) **and** `Engine/Build/Build.version` matching the
|
|
159
|
+
association. Stale registry keys and env pointers are reported as rejected candidates with the
|
|
160
|
+
reason, never silently dropped. One survivor → `resolved`; several → `ambiguous`; none →
|
|
161
|
+
`unresolved` + remediation. Nothing is ever written back to the registry.
|
|
162
|
+
|
|
163
|
+
Registry reads run through one memoized `pwsh -NoProfile` snapshot (8 s timeout). If `pwsh` is
|
|
164
|
+
missing the snapshot degrades to `available: false` and the resolver continues with
|
|
165
|
+
file-based sources — the extension never fails at import time.
|
|
166
|
+
|
|
167
|
+
## Plugin discovery
|
|
168
|
+
|
|
169
|
+
Mirrors `UnrealBuildTool.System.ReadAvailablePlugins` (`System/Plugins.cs:322`):
|
|
170
|
+
Engine `Engine/Plugins` → Project `Plugins/` → Mod `Mods/` → `AdditionalPluginDirectories`,
|
|
171
|
+
with later scans shadowing earlier ones on name collision. `Binaries/`, `Intermediate/`,
|
|
172
|
+
`Saved/`, `.git/`, `ThirdParty/` are skipped. Reference semantics mirror `PluginManager`:
|
|
173
|
+
`Enabled` / `Optional` / `Activate` (`PluginReferenceDescriptor.cpp:132-172`); an engine-version
|
|
174
|
+
mismatch is a warning, not an error (`PluginManager.cpp:2690-2712`).
|
|
175
|
+
|
|
176
|
+
Indexes are cached on disk keyed by the mtime of every scanned directory plus the engine
|
|
177
|
+
changelist, with a 10-minute backstop (`MAX_AGE_MS`) because content-only `.uplugin` edits do
|
|
178
|
+
not move the parent directory's mtime.
|
|
179
|
+
|
|
180
|
+
## Descriptor fidelity
|
|
181
|
+
|
|
182
|
+
Field names, host types, and loading phases are transcribed from the engine's serializers
|
|
183
|
+
(UE 5.8): `ProjectDescriptor.cpp:100-225`, `PluginDescriptor.cpp:263-409`,
|
|
184
|
+
`ModuleDescriptor.cpp`, `PluginReferenceDescriptor.cpp:130-180`, cross-checked against 897
|
|
185
|
+
`.uplugin` files in UE 5.8 `Engine/Plugins`. Consequences:
|
|
186
|
+
|
|
187
|
+
- `.uproject` / `.uplugin` are parsed as JSONC (comments and trailing commas are legal in the
|
|
188
|
+
engine's reader).
|
|
189
|
+
- `Modules` is an array of objects keyed by `Name`; `Type` is required
|
|
190
|
+
(`Found Module entry 'X' with a missing 'Type' field`), `LoadingPhase` defaults to `Default`.
|
|
191
|
+
- A plugin reference without `"Enabled"` is rejected by UE 5.8 — reported, not guessed.
|
|
192
|
+
- Unknown keys are reported as `… is not serialized by FPluginDescriptor`, and the known-key
|
|
193
|
+
set is wide enough (including legacy `Whitelist*`/`Blacklist*` and pre-5.x keys) that genuine
|
|
194
|
+
engine files produce no noise.
|
|
195
|
+
- `.uplugin` has no `Enabled` key; enablement is `EnabledByDefault` + the project reference.
|
|
196
|
+
- `IsBetaVersion` is metadata in UE 5.8 (no engine/UBT beta gate exists).
|
|
197
|
+
|
|
198
|
+
## Known limits
|
|
199
|
+
|
|
200
|
+
- Registry access needs `pwsh` (PowerShell 7). Without it, registry sources are unavailable and
|
|
201
|
+
resolution relies on env, directory scans, and inline associations.
|
|
202
|
+
- `unreal_resolve_engine` reports what the machine can prove. It does not install, register, or
|
|
203
|
+
migrate engines, and never writes registry keys (the engine's `RegisterEngineInstallation`
|
|
204
|
+
does; this package deliberately does not).
|
|
205
|
+
- v1 is inspection only. `.ini` provenance is out of scope.
|
|
206
|
+
- The definition index is a scanner, not a parser: it finds declarations (`class`, `struct`,
|
|
207
|
+
`enum`, `union`, `UFUNCTION`/`UPROPERTY`/`UCLASS`-marked members, delegates, aliases) and
|
|
208
|
+
records `Owner:Member` qualified names. It does not resolve types, overloads, call sites, or
|
|
209
|
+
inheritance — that is what clangd is for when it is installed. Macro-heavy code can still be
|
|
210
|
+
misread: the scanner is regex-based, so a definition hidden inside an unusual macro spelling may
|
|
211
|
+
be missed, and `#if` branches are all recorded (a symbol declared in a disabled branch is a
|
|
212
|
+
candidate, not a guarantee).
|
|
213
|
+
- `moduleRefs` and `includePaths` come from UnrealBuildTool Query, which needs a buildable
|
|
214
|
+
target for the project; when Query fails the index still builds and says so.
|
|
215
|
+
- The engine index is never built implicitly: scans are opt-in through `unreal_index`. The header
|
|
216
|
+
index is never built implicitly either, for the same reason: a path answer must not cost a scan.
|
|
217
|
+
- `action: "compiledb"` needs UnrealBuildTool (so an engine installation) and, for the
|
|
218
|
+
`clangd --check` acceptance step, a clangd binary — `CLANGD_PATH`, the Visual Studio LLVM
|
|
219
|
+
toolset, the WinGet LLVM package, or `C:/Program Files/LLVM/bin`. Without clangd the database is
|
|
220
|
+
still produced and reported; only the check is skipped.
|
|
221
|
+
- On an installed engine the compile database covers the project's translation units (engine
|
|
222
|
+
modules are precompiled and contribute no compile actions). The engine-wide scope of
|
|
223
|
+
`project+engine` is the source-built case, and there it is a ~1 GB artifact taking minutes.
|
|
224
|
+
`project+engine` now includes `Engine/Plugins` sources as well as `Engine/Source` — that is where
|
|
225
|
+
plugin `.cpp` bodies live, and a database without them silently drops every plugin implementation
|
|
226
|
+
file from clangd.
|
|
227
|
+
- An empty clangd answer is **evidence, not a bug to route around**. On an installed engine the
|
|
228
|
+
database has no engine translation units, so "clangd found no references in
|
|
229
|
+
`MoverComponent.cpp`" describes the setup, not a defect pi-unreal fixes: it answers declaration,
|
|
230
|
+
module, include-path and dependency facts by a compiler-free route, and says what it scanned.
|
|
231
|
+
- Engine area selection is a cost dial, not a completeness claim. `DEFAULT_ENGINE_AREAS =
|
|
232
|
+
["Runtime"]` covers the engine's **own** gameplay code (`AActor`, `UAnimInstance`,
|
|
233
|
+
`USceneComponent`, 18,566 files) — in an installed engine that is not every gameplay type, because
|
|
234
|
+
the ones shipped by plugins (`Mover`, `PoseSearch`, `PhysicsControl`, `BlendStack`, `SmartObjects`,
|
|
235
|
+
`StateTree`, `GameplayAbilities`) live under `Engine/Plugins/<Category>/<Plugin>/Source/<module>`.
|
|
236
|
+
Engine-scope indexes add the plugin roots the `.uproject` enables; the rest are opt-in via
|
|
237
|
+
`engineAreas: ["Plugins"]` (~2.8× the `Runtime` scan) or `["Plugins/Animation/PhysicsControl"]`
|
|
238
|
+
for one plugin. `Editor` and `Developer` are opt-in and roughly triple the scan.
|
|
239
|
+
- pi-unreal answers C++ **declaration, module, include-path and dependency** facts. It does not
|
|
240
|
+
answer asset questions: UENUM index order (Blueprint enumerators are stored in index order, so
|
|
241
|
+
`4 = OnGround` is an asset fact), UStruct field types, UCLASS/CDO instance values, component
|
|
242
|
+
lists, parent chains, Blueprint graphs. Those need the `unreal-engine` editor MCP with the editor
|
|
243
|
+
running; a C++ scan cannot see them and must not pretend to.
|
|
244
|
+
- Index reuse requires the *same root set*: an index built over two modules is never used to answer
|
|
245
|
+
a `Runtime`-wide query. Partial coverage reported as an answer is worse than a rebuild.
|