Unreal Engine editor plugin that exports StateTree assets to deterministic, AI/human-readable Markdown every time they are saved.
StateTree アセット(バイナリ .uasset)を、保存のたびに AI が読める Markdown に自動エクスポートする UE エディタプラグインです。AI コーディングエージェント(Claude Code, Codex, Cursor など)が、エディタで組んだ StateTree の実構造を読めるようになります。
## State: Root/CounterStance
- Type: State | Selection: TrySelectChildrenInOrder | Enabled: true
- Tasks:
1. "Battle: Stance Tag While Active" (FSTT_StanceState)
- Instance: {"StanceTag":{"TagName":"Battle.Stance.Counter"}}
- Transitions:
1. OnEvent [Tag=Event.Turn.PlayerActionResolved] -> Root/Telegraph- Auto-export on save: saving any StateTree asset in the editor writes/updates a Markdown file under
<ProjectRoot>/Docs/StateTreeExport/, mirroring the Content path (/Game/Battle/ST_EnemyBrain→Docs/StateTreeExport/Battle/ST_EnemyBrain.md). StateTree.ExportAllconsole command: exports every StateTree asset under/Game. Works headless (no GUI) — see Refresh command.- Deterministic output: same asset → byte-identical file. No timestamps. Unchanged content is not rewritten (mtime preserved). Safe for version control and file watchers.
- Reflection-based: custom C++ StateTree tasks/conditions/evaluators are exported automatically — adding new node types requires no plugin changes.
- Exports: state hierarchy, tasks/conditions/evaluators with parameter values, transitions (trigger/event tag/target/priority/delay), property bindings, root & state parameters, linked assets/subtrees.
| Item | Requirement |
|---|---|
| Unreal Engine | 5.7 (tested, Mac & Win). Likely works on 5.6; not compatible with ≤5.5 (uses PropertyBindingUtils APIs). |
| Project type | C++ project (the plugin is compiled with your project). A Source/ folder must exist. |
| Plugins | StateTree — enabled automatically as a dependency of this plugin. |
- Clone into your project's
Plugins/folder:git clone https://github.com/tomsato42/StateTreeTextExporter.git <YourProject>/Plugins/StateTreeTextExporter - Rebuild your project's editor target (or just open the
.uprojectand accept the rebuild prompt). If the editor was open, restart it. - Save any StateTree asset → check
Docs/StateTreeExport/.
For AI coding agents. Follow the steps in order. Every step has a SUCCESS criterion — verify it before moving on. Define these placeholders once from the user's environment, then substitute everywhere:
Placeholder Meaning How to find it <PROJECT_ROOT>Absolute path of the directory containing the .uprojectfilels <candidate>/*.uproject<PROJECT_NAME>.uprojectfilename without extensionbasename of the above <ENGINE_ROOT>Unreal Engine install directory "EngineAssociation"in the.uproject+ local install list; or ask the user
ls "<PROJECT_ROOT>"/*.uproject # must list exactly one file
ls "<PROJECT_ROOT>/Source" # must exist (C++ project)- If
Source/does not exist, STOP: this is a Blueprint-only project. Tell the user it must be converted to a C++ project first (Editor: Tools → New C++ Class → any class → close editor), then retry. - If the engine version is below 5.6, STOP and tell the user this plugin requires UE 5.6+.
git clone https://github.com/tomsato42/StateTreeTextExporter.git "<PROJECT_ROOT>/Plugins/StateTreeTextExporter"SUCCESS: file <PROJECT_ROOT>/Plugins/StateTreeTextExporter/StateTreeTextExporter.uplugin exists.
(No git? Download the repo ZIP and extract to the same path.)
The plugin is EnabledByDefault, so this step is technically optional — but adding an explicit entry makes the project state verifiable. Edit <PROJECT_ROOT>/<PROJECT_NAME>.uproject and add to the top-level "Plugins" array (create the array if absent):
{
"Name": "StateTreeTextExporter",
"Enabled": true
}SUCCESS: .uproject is still valid JSON (verify: python3 -c "import json;json.load(open('<PROJECT_ROOT>/<PROJECT_NAME>.uproject'))").
macOS:
"<ENGINE_ROOT>/Engine/Build/BatchFiles/Mac/Build.sh" <PROJECT_NAME>Editor Mac Development -Project="<PROJECT_ROOT>/<PROJECT_NAME>.uproject"Windows:
"<ENGINE_ROOT>\Engine\Build\BatchFiles\Build.bat" <PROJECT_NAME>Editor Win64 Development -Project="<PROJECT_ROOT>\<PROJECT_NAME>.uproject"SUCCESS: output ends with Result: Succeeded.
ConflictingInstanceerror → another UnrealBuildTool is running (often the IDE). Wait untilUnrealBuildToolprocesses exit, retry the same command.- If the Unreal Editor GUI is currently open, the new binary is not picked up until the editor is restarted (on Mac there is no Live Coding).
macOS:
"<ENGINE_ROOT>/Engine/Binaries/Mac/UnrealEditor-Cmd" "<PROJECT_ROOT>/<PROJECT_NAME>.uproject" -ExecCmds="StateTree.ExportAll, QUIT_EDITOR" -Unattended -NullRHI -NoSound -NoSplash -stdoutWindows:
"<ENGINE_ROOT>\Engine\Binaries\Win64\UnrealEditor-Cmd.exe" "<PROJECT_ROOT>\<PROJECT_NAME>.uproject" -ExecCmds="StateTree.ExportAll, QUIT_EDITOR" -Unattended -NullRHI -NoSound -NoSplash -stdoutSUCCESS: the log contains a line matching:
LogStateTreeExport: Display: StateTree.ExportAll: exported N/N asset(s).
and (if the project has at least one StateTree asset) .md files exist under <PROJECT_ROOT>/Docs/StateTreeExport/.
exported 0/0 is also success — the project simply has no StateTree assets yet.
- The user saves StateTree assets in the editor → exports update automatically. Read
<PROJECT_ROOT>/Docs/StateTreeExport/**/*.mdinstead of ever trying to parse.uassetfiles. - To force-refresh without the user (e.g. if exports look stale), rerun the STEP 4 command.
- Installation is complete. Report to the user: plugin installed, verified with
StateTree.ExportAll, exports land inDocs/StateTreeExport/.
These rules keep files small; misreading them is the only real pitfall:
| Element | Meaning |
|---|---|
Instance: {...} |
Node instance parameters — only values changed from the C++ defaults. A task with no Instance: line has all parameters at their C++ default values (read the node's USTRUCT source for those). |
Node: {...} |
Settings of the node itself (e.g. disabled flags). Also delta-only. |
Bind: Target <- Source |
Property binding. Bind lines are the source of truth: a bound property's value in Instance: is just the pre-binding default. |
(Priority=…) (Delay=…) (Disabled) |
Shown on transitions only when non-default. |
| Array order | States/tasks/transitions keep authored order (selection order is meaningful). Only Bind: lines are sorted. |
## Unresolved Bindings |
Bindings whose owner could not be located — nothing is silently dropped. |
In-editor: open the console (`) and run StateTree.ExportAll.
Headless: STEP 4 command above.
- Renaming/moving an asset leaves the old
.mdbehind — delete it manually, then runStateTree.ExportAll. - Only user saves trigger the hook; cook /
ResavePackages/ PIE-duplication saves are ignored by design. - Only assets under
/Gameare exported. - Code comments are in Japanese (the plugin originated in a Japanese learning project). The logic is self-contained in two small files if you want to read it.
| Symptom | Cause | Fix |
|---|---|---|
StateTree.ExportAll → "Command not recognized" |
Plugin module not loaded | Rebuild (STEP 3); restart the editor; confirm the plugin is enabled in Edit → Plugins |
Export failed: EditorData is missing inside an .md |
Asset was loaded from cooked data, or never saved by this editor version | Open the asset in the editor and re-save it |
| Exports not updating on save | Editor running a binary built before install | Restart the editor |
Build error about PropertyBindingUtils / missing headers |
Engine older than 5.6 | Upgrade to UE 5.6+ (5.7 tested) |
ConflictingInstance when building |
Another UBT instance (IDE) holds the mutex | Wait for it to finish, retry |
Public domain (The Unlicense). Do whatever you want — no attribution required.