This repository ships no game data and no game artwork. Five categories of file are produced locally, gitignored, and never committed, because they are derived from Capcom-owned material that is not ours to redistribute:
| Category | Path | Needs a copy of the game? | Regenerate with |
|---|---|---|---|
| A — HUD artwork | mhfu_hud/assets/ |
no | mhfu_hud/tools/fetch_assets.py |
| B — Disassembly listings | tools/out/**/*.asm |
yes | tools/eboot_dis.py (static) or PPSSPP (live) |
| C — Game-data tables | tools/out/**/*.bin |
yes | the tools/re_*.py dumpers |
| D — Ported monster PACs | tmp/*.bin |
yes (two games) | tools/build_p3rd_port.py --manifest ports/<name>.toml |
| E — Species action intel | species/*.json |
yes | tools/em_intel.py --all |
Everything here is reproducible from your own legally obtained copy of the game. Nothing in this repo requires, distributes, or links to game files.
If you only want to run the tooling and read the RE notes, you need none of
this — the docs in docs/ stand on their own, and the HUD degrades gracefully
without artwork.
cd tools && ./setup.sh # clones mhff/mhef, creates venv
source ../venv/bin/activate
pip install -r tools/requirements.txtCategory A additionally needs pillow; categories B and C need websockets
for the PPSSPP debugger bridge:
pip install -r mhfu_hud/requirements.txt # pygame-ce, pillow, websockets
pip install -r src/ppsspp_debug/requirements.txtThe live HUD (mhfu_hud/) draws item, monster and map icons plus a village
backdrop. These are Capcom artwork hosted on the Monster Hunter Fandom wiki,
fetched at setup time rather than vendored.
No copy of the game is required for this category.
python mhfu_hud/tools/fetch_assets.pyThat populates, under mhfu_hud/assets/:
| Directory | Contents | Source |
|---|---|---|
backgrounds/ |
village.png |
fixed wiki URL |
maps/ |
snowy_mountains.png + best-effort per-location resource maps |
fixed URL + scrape |
monsters/ |
<slug>.png — the MHFU iOS icon set, via the MediaWiki allimages API |
wiki CDN |
items/ |
<slug>.png — scraped from MHFU:_Item_List |
wiki scrape |
Every directory also gets a manifest.json (slug → filename) written by the
same script, so the mapping is regenerated too — there is nothing to restore by
hand.
Useful flags:
python mhfu_hud/tools/fetch_assets.py --quick # only the two fixed-URL assets
python mhfu_hud/tools/fetch_assets.py --no-items # skip the 850 item icons (slowest part)
python mhfu_hud/tools/fetch_assets.py --no-maps
python mhfu_hud/tools/fetch_assets.py --no-monsters
python mhfu_hud/tools/fetch_assets.py --only-itemsAll images are normalised to PNG through Pillow, so webp/gif/jpg sources come out uniform. Network failures are logged and skipped, not fatal — the HUD falls back to drawn placeholders for anything missing, so a partial fetch still leaves you with a working HUD.
Wiki page structure changes over time; if a scrape comes back thin, the fixed-URL
assets (--quick) are the stable subset.
Categories B and C read the game's own code and data, so they need a dump of a copy you own. The only method described here is dumping your own disc:
- A PSP running custom firmware can dump a UMD you physically own to an ISO (CFW's VSH menu exposes a UMD-dump option; standalone dumper homebrew does the same). If you own the digital release instead, you already have the data on your own console/account.
- Put the resulting ISO in
workspace/iso/. That whole directory is gitignored.
tools/extract_iso.py recognises known-good dumps by MD5 and will tell you
which one you have:
| MD5 | Release |
|---|---|
1f76ee9ccbd6d39158f06e6e5354a5bd |
MHP2G, UMD |
cc39d070b2d2c44c9ac8187e00b75dc4 |
MHP2G, PSN |
Then extract:
python tools/extract_iso.py workspace/iso/game.iso workspace/extracted/This yields workspace/extracted/PSP_GAME/SYSDIR/BOOT.BIN — the decrypted
EBOOT ELF that category B reads — plus the archive you can unpack further per
the "Quick Start" section of CLAUDE.md (--decrypt / --extract-data for
DATA.BIN).
Region matters. All runtime RE in this project targets MHFU EU (ULES01213), and every address in
docs/and in the listings below is an EU address. A JP (MHP2G) or NA dump loads at different addresses; the tooling still works, but the specific VAs will not line up.tools/eboot_dis.pyhardcodes the EU segment map (file0x25b4→ VA0x08804000, length0x1c7a90).
MIPS listings of the game's own code, used as working notes throughout the RE docs. They split by where the code lives, which decides how you regenerate them.
Readable straight out of BOOT.BIN:
python tools/eboot_dis.py <va> [count] # disassemble count insns from VA
python tools/eboot_dis.py --words <va> [n] # raw u32 words (data / tables)
python tools/eboot_dis.py --xref <va> [from] [to] # find lui/jal references to VAThe 13 EBOOT-range listings and their entry points:
| Listing | Entry VA | Generator |
|---|---|---|
vt8_resolver/apply_0885F848.asm |
0x0885F848 |
tools/re_vt8_and_resolver.py |
vt8_resolver/anim_resolver_0885F928.asm |
0x0885F928 |
tools/re_vt8_and_resolver.py |
vt8_resolver/vt8_picker_08865254.asm |
0x08865254 |
tools/re_vt8_and_resolver.py |
walker_re/installer_0885F9A0.asm |
0x0885F9A0 |
tools/re_installer_and_vt8.py |
walker_re/walker_088637C4.asm |
0x088637C4 |
tools/re_walker_setters.py |
walker_re/real_caller_08865648.asm |
0x08865734 |
tools/re_walker_setters.py |
slot_installer/installer_110_08860390.asm |
0x08860390 |
tools/find_slot_installer.py |
slot_installer/applier_08863E70.asm |
0x08863E70 |
tools/find_slot_installer.py |
slot_installer/caller_func_08865044.asm |
0x08865044 |
tools/disasm_driver_caller.py |
cutscene_driver/disasm_func_088637C4.asm |
0x088637C4 |
tools/disasm_cutscene_driver.py |
cutscene_driver/disasm_writer_088639A4.asm |
0x088639A4 |
tools/disasm_cutscene_driver.py |
evdemo_eu/disasm_eu_trigger_088D5754.asm |
0x088D5754 |
tools/verify_evdemo_eu.py |
ai_step_bigmonster/ai_step_callers.asm |
JAL scan of 0x08865648 |
tools/re_ai_step_and_bigmonster_list.py |
The last one is a scan rather than a linear disassembly: it sweeps
0x08800000..0x089FFFFF for the encoded jal 0x08865648 word (0x0C219592) to
enumerate callers of the per-frame AI tick.
Monster AI overlays are not in the EBOOT. They are loaded into RAM at
runtime, so they can only be disassembled from a live emulator with the target
monster loaded. Set up the PPSSPP debugger connection first — see
docs/agent_debugging.md.
PYTHONPATH=src python src/ppsspp_debug/disasm_func.py 0x09AC52DC --count 280
PYTHONPATH=src python src/ppsspp_debug/disasm_func.py 0x088637C4 --marks 0x088639A4,0x088639C0Output lands in src/ppsspp_debug/output/disasm/ (also gitignored).
| Listing | Entry VA | Generator |
|---|---|---|
tigrex_base_writers/.../func_prologue.asm |
0x09AC5080 |
tools/re_disasm_slot_loop.py |
tigrex_base_writers/.../dispatcher_09AC5200.asm |
0x09AC5200 |
tools/re_disasm_slot_loop.py |
tigrex_base_writers/.../slot_loop_09AC52DC.asm |
0x09AC52DC |
tools/re_disasm_slot_loop.py |
tigrex_base_writers/.../caller_09D26570.asm |
0x09D26500 |
tools/re_disasm_slot_loop.py |
ai_step_bigmonster/sw_0x640_writers.asm |
0x09AC46D8 region |
tools/re_ai_step_and_bigmonster_list.py |
tools/re_disasm_slot_loop.py is self-driving: it launches PPSSPP, loads a
Tigrex savestate (slot 7), disassembles the ranges, writes
tools/out/tigrex_base_writers/disasm_<timestamp>/*.asm, and exits. It sets no
breakpoints, so it cannot freeze the emulator. Savestates are yours and are not
in the repo — record one in a Tigrex quest first.
Always use
memory.disasm, never a raw RAM read. PPSSPP's JIT rewrites translated overlay code with0x68XX_XXXXEMUHACK markers, so a raw read of overlay code returns markers instead of instructions. The debugger's disasm event returns the original opcodes. This is why B2 listings come from the debugger and not from a memory dump.
Two small tables read verbatim out of a live monster's data. Both need a
running game with a Tigrex loaded, and the PPSSPP debugger enabled
(docs/agent_debugging.md).
| File | Size | Contents | Regenerate with |
|---|---|---|---|
tools/out/tigrex_prob_table/tigrex_prob_table.bin |
1024 B | the action probability table at entity+0x1AC |
PYTHONPATH=src python tools/re_tigrex_probability_table.py |
tools/out/ai_step_bigmonster/tigrex_actionlist_640.bin |
256 B | the big-monster action list at entity+0x640 |
PYTHONPATH=src python tools/re_ai_step_and_bigmonster_list.py |
re_tigrex_probability_table.py reads the table base from entity+0x1AC, dumps
0x400 bytes, scans for the 0xFFFF sentinel / 8-byte record header, walks the
records, and dumps the first 0x40 bytes at each unique pointer it finds — so
it prints a decoded view alongside the raw .bin.
Both scripts write into tools/out/<name>/ and also emit .txt / .json
companions. Only the .bin and .asm outputs are gitignored — the textual
analysis logs in tools/out/ are our own notes and remain tracked, so you can
read the conclusions without regenerating anything.
A ported monster is an MHFU big-monster PAC spliced from two games' data — an
MHP3rd donor (model, skeleton, textures, moveset) onto an MHFU host frame. Every
byte of it is Capcom's, so no built PAC is committed, and tmp/ is gitignored.
What is committed is the recipe: one port.toml per port under ports/,
hand-authored file ids and numbers, read by mhfu_monster_editor.manifest.
python tools/build_p3rd_port.py --manifest ports/zinogre.toml --out tmp/zinogre_v10.bin
python tools/build_p3rd_port.py --manifest ports/brute_tigrex.toml --out tmp/brute_tigrex_em058.binBoth need workspace/extracted/ (your MHFU dump) and workspace/extracted_mhp3/
(your MHP3rd dump), produced by tools/extract_iso.py. The manifest build is
byte-identical to the documented flag soup it replaces — pinned by
mhfu_monster_editor/tests/test_ports_build.py, which returns early when the
extracts are absent.
species/emNN.json is the host species' action table: every (main, sub) behaviour
pair its overlay dispatches, the handler address behind each one, the executor a1
animation ids it plays, what ENDS it (the clip, a cursor frame, or the +0x414
budget), and the literal spawn_effect(id, bone, frame) arguments its handlers
carry. All of that is the game's own code and data, read out of em*.ovl — the
same category as the disassembly listings in B, just in JSON — so it is gitignored
and never committed.
python tools/em_intel.py --all # all 17 -> species/em01.json ...
python tools/em_intel.py file_06108.bin # just the Tigrex -> species/em75.jsonIt reads workspace/extracted/data_files/ (your MHFU dump) and nothing else — no
emulator, no running game, ~4 s for all 17 overlays. The editor finds the result
through mhfu_monster_editor.intel.find_intel(host_species); without it the
validator warns INTEL_ABSENT and keeps going, so a checkout that has never run the
command still works.
One field is measured rather than read: the per-pair dwell census from
tools/em_state_census.py, which needs a cold boot with the observe-only probe
deployed. Absent — which is the normal state — every pair's measured block is
null and the file says why. Attach one with:
python tools/em_intel.py file_06108.bin --log <framework.log> --census-species 75The wiki artwork is Capcom's, redistributed by the wiki under fan use; bundling it in a code repository is a different act from a fan wiki hosting it. The disassembly listings are the game's own code in disassembled form, the species intel is that same code read into JSON, and the tables are its data copied byte-for-byte. All of them are trivially reproducible by anyone who owns the game, so excluding them costs contributors a single command and keeps this repository free of material we have no right to ship.
The RE findings themselves — addresses, struct layouts, offsets, behaviour —
are facts about how the game works, documented throughout docs/, and are not
affected by any of this.