Skip to content

Decomp Project Mode

laqieer edited this page Jun 28, 2026 · 2 revisions

Decomp Project Mode

Decomp project mode lets FEBuilderGBA treat a Fire Emblem decompilation source tree (e.g. an agbcc-built pret-style project) as the source of truth, instead of a single .gba binary. You open the project directory rather than a ROM; the built ROM is loaded only as a read-only preview, and edits are written back to the owning C struct array or JSON element in the source tree — producing a clean, reviewable diff that survives a rebuild.

This is the opposite workflow from classic ROM mode: in classic mode the .gba is canonical and edits mutate ROM bytes; in decomp mode the source is canonical and the ROM is a build artifact.

Classic ROM mode is completely unchanged. Decomp mode is purely additive and opt-in — you only enter it by opening a project directory (Avalonia Open Decomp Project) or passing --project=<dir> to the CLI.

At a glance

Step CLI What it does
Open project --project=<dir> (+ --rom-info) Detect the project, load the built ROM for preview, show the mode badge
Resolve address --resolve-addr=<hex> Map a ROM address to a source symbol (name / source artifact / offset)
Diff-to-source --migrate-diff Classify built-vs-edited ROM changes by symbol/category/confidence (advisory)
Write to source --write-source Rewrite the owning C-struct / JSON element instead of mutating the ROM
Write a shop list --write-shop Rewrite the owning u16 ITEM_NONE-terminated shop list in source
Export an asset --export-asset Dump a ROM asset to a source-tree path (palette / graphics / map / text)
Validate an asset --validate-asset Structurally validate an import asset on disk (never touches the ROM)
Build & reload --build-project [--reload] [--yes] Run the manifest build command (explicit opt-in) and reload the rebuilt ROM
Audit coverage --decomp-audit Print the round-trip coverage matrix (source-backed / exporter / preview / manual / ROM-only)
NMM ↔ manifest --nmm-to-manifest / --manifest-to-nmm Bridge Nightmare .nmm table schemas ↔ decomp manifest table defs

See Command-Line Interface for the full per-command reference.

Project detection & the manifest

When you open a directory, FEBuilderGBA detects a decomp project by looking for a Makefile declaring the ROM (ROM/BUILD_NAME/agbcc usage). Detection works without any extra file, but an optional manifest unlocks the source-backed writers, builds, and schema bridge:

your-decomp-project/
├── Makefile                     # ROM / BUILD_NAME / agbcc — used for auto-detection
├── febuilder.project.json       # optional manifest (see below)
├── <build_name>.gba             # built ROM — loaded as a read-only preview
├── <build_name>.map             # GNU-ld map — layered into symbol resolution
├── <build_name>.elf             # ELF symbols — layered into symbol resolution
└── src/ data/ ...               # C/JSON source the writers edit

febuilder.project.json (the manifest) declares:

  • A build section — the build command, working dir, and the path of the ROM it produces (used by --build-project).
  • A tables section — for each structured table (items, units, classes, …), the owning C struct array or JSON file, so --write-source knows which source element to rewrite.

When no manifest is present you still get preview, address resolution, diff migration, and asset export; the source-backed writers and builds require the manifest's owner/build declarations.

Address → source symbol resolution

--resolve-addr=<hex> (requires --project) maps a ROM address to a source symbol, layering the project's own symbols over the shipped symbol set:

  • GNU-ld .map file
  • ELF symbols
  • .sym / JSON symbol files

It prints the symbol name, the source artifact it came from (map / elf / sym / json / shipped), and the byte offset into that symbol. The same resolution also lights up the Pointer Tool ("What is this address?") inside the GUI.

FEBuilderGBA.CLI --resolve-addr=0x08012345 --project=decomp/

Diff-to-source migration assistant

--migrate-diff is an advisory, read-only assistant for moving an existing FEBuilder-edited ROM back onto a decomp source tree. It treats the project's built ROM as the canonical baseline, compares it against your edited ROM (--rom2), and classifies each changed range by symbol, category, source artifact, and a confidence score. It never writes the ROM or the source — it just tells you what changed and where it likely belongs.

FEBuilderGBA.CLI --migrate-diff --project=decomp/ --rom2=edited.gba --out=migrate.tsv

Source-backed table writers

--write-source rewrites the owning C struct-array element (or JSON element) for a table entry instead of mutating ROM bytes. Properties:

  • Coverage: items, units (alias characters), classes, map_settings/chapter, support_units/support_attributes/support_talks.
  • Signed fields are handled (the value is taken as the two's-complement magnitude).
  • Multi-field edits in one call — repeat --field/--value pairs.
  • Churn-free minimal diffs — only the changed initializer element is rewritten.
  • Marks the project as "needs rebuild" after a write.
  • Unsupported / pointer-like fields fall back to ROM-only / manual (they aren't silently written). Shops are source-backed via the separate --write-shop command when the shop's ROM address resolves to a manifest u16-list owner (both literal raw-hex and symbolic ITEM_* item-id-only lists); otherwise they degrade to --export-asset --kind=shop / manual.
FEBuilderGBA.CLI --write-source --project=decomp/ --table=items --id=1 --field=might --value=0x0A
FEBuilderGBA.CLI --write-source --project=decomp/ --table=units --id=1 --field=hp --value=18 --field=pow --value=7

Shop list source writer (--write-shop)

Shops are a variable-length u16 ITEM_NONE-terminated list with no fixed struct owner, so they are written by their own command rather than --write-source. --write-shop rewrites the owning source list in place when the shop's ROM address (or symbol) resolves to a manifest u16-list owner — handling both literal raw-hex lists and the symbolic ITEM_* item-id-only form (include/constants/items.h is consulted for the id↔macro map). When no owner resolves it reports not owned (exit 2) and you degrade to --export-asset --kind=shop / manual.

FEBuilderGBA.CLI --write-shop --project=decomp/ --symbol=ItemList_WM_FluornArmory --items=0x01:5,0x02:3
FEBuilderGBA.CLI --write-shop --project=decomp/ --shop-addr=0xB2A18 --items=0x16:1

Asset export to the source tree

--export-asset dumps a ROM asset to a decomp source-tree path so it lives in the repo as a real file:

--kind Output
palette JASC .pal
graphics indexed PNG (4bpp/8bpp indexed)
map .mar (always LZ77-decompressed, with a .mar.json sidecar)
mapchange raw u16 map-change overlay tile block (.change + .change.json)
mapanime2pal raw u16 map tile-animation-2 palette block
mapanime1gfx raw 4bpp map tile-animation-1 graphics block
objtiles LZ77-decompressed 4bpp OBJ tile payload
mapchipconfig LZ77-decompressed chipset TSA/config payload
text directory (--out = dir) containing texts.txt + textdefs.txt
shop shop item list (EA migration artifact)

Music, portrait, and battle-animation assets are exported via the existing dedicated commands (--export-midi, --export-portrait-all, --export-battle-anime).

FEBuilderGBA.CLI --export-asset --kind=palette --rom=rom.gba --addr=0x5524 --out=gfx/palette.pal
FEBuilderGBA.CLI --export-asset --kind=map --rom=rom.gba --addr=0x200000 --out=map/chapter1.mar

Asset import validation

--validate-asset structurally validates a source-tree graphics / palette / portrait / icon / map / mapchange / mapanime2pal / mapanime1gfx / objtiles / mapchipconfig / portrait-package asset before you wire it into a rebuild. It is strictly read-only — it never mutates the ROM — and reports actionable ERROR / WARN findings so a bad asset is caught at desk rather than at build time.

FEBuilderGBA.CLI --validate-asset --kind=graphics --in=gfx/tiles.png

Build & reload

--build-project runs the manifest's declared build command — but only with explicit opt-in via --yes. It captures stdout/stderr; with --reload it reloads the freshly built ROM and re-parses symbols on success. FEBuilderGBA never runs an arbitrary build command implicitly.

FEBuilderGBA.CLI --build-project --project=decomp/ --reload --yes

Round-trip coverage matrix (--decomp-audit)

--decomp-audit prints the maintained matrix of how each editor behaves in decomp mode. Categories:

The Coverage column prints the tier enum name; the meanings are:

Coverage (enum) Meaning
SourceBackedWriter Edits rewrite the owning C/JSON source element (--write-source / --write-shop)
SourceTreeExporter Asset is dumped to the source tree (--export-asset / existing exporters)
ImportPreviewOnly The GUI previews an import but final apply is ROM-side
ManualMigration No automated source path yet — edit the source by hand
RomOnlyUnsupported Pointer-like / unsupported in source; only the ROM is written
FEBuilderGBA.CLI --decomp-audit --format=md --out=docs/decomp-coverage.md

Nightmare .nmm schema bridge

FEBuilderGBA can bridge Nightmare module (.nmm) table schemas to/from decomp manifest table definitions:

  • --nmm-to-manifest — parse a .nmm into a manifest tables[] entry JSON. Pointer / variable-length / odd-size fields are kept and flagged "unsupported": true (never dropped).
  • --manifest-to-nmm — emit .nmm text for a manifest table owner; pointer/var fields are flagged unsafe via warnings.
FEBuilderGBA.CLI --nmm-to-manifest --in=items.nmm --table=items --out=items.tables.json
FEBuilderGBA.CLI --manifest-to-nmm --project=decomp/ --table=items --out=items.nmm

What's source-backed vs manual (summary)

Area Decomp behaviour
Items, units/characters, classes, map/chapter, support (units/attributes/talks) source-backed via --write-source
Palette, graphics, map, text assets exporter via --export-asset (+ existing exporters for music/portrait/battle-anim)
Shops (item lists) source-backed via --write-shop when the list resolves to a manifest u16-list owner; else --export-asset --kind=shop / manual
Pointer-like / unsupported struct fields ROM-only / manual
Address lookups resolved against project .map/ELF/.sym/JSON, layered over shipped symbols

Run --decomp-audit for the authoritative, always-current matrix.

See also

Clone this wiki locally