Files
psxrecomp/tools/new_project_layout
Alexandros Mandravillis d17676a5c7 setup: read .chd through libchdr in the Python disc tools
The runtime mounts a .chd natively and the launcher lists it in the disc
picker, so a player could select one and see a valid disc identity, then have
first-run setup fail: verify-disc, prepare_disc.py and probe_disc.py hash and
parse raw 2352-byte track data, which a CHD stores compressed. Nothing on the
Python side could read it, and telling players to install MAME for chdman is
not an answer.

libchdr is already vendored and compiled for the runtime and the native media
CLI. Build it once more as a shared library in recompiler/ (CMake target chdr,
output next to the emitters, static CRT on Windows so a plain python.exe can
load it) and read the CHD from Python through ctypes. tools/psx_chd.py mirrors
the layout the runtime's iso_reader.cpp uses -- 2448-byte frames, 4-frame
track padding, stored versus virtual pregaps, big-endian audio -- and
reproduces the .bin files a Redump dump of the same disc contains, in either
of Redump's two layouts (one bin per track, or one bin for the disc).

verify-disc hashes those reconstructed track bytes against [prepare_disc]
instead of the container. prepare_disc.py writes the tracks into out_dir in
whichever layout the recorded digests match and then continues down its
normal cue path, so the data track is written once, SBI companions are looked
up next to the CHD, and the receipt names the CHD the player chose.
probe_disc.py extracts to a scratch directory and probes the cue. The CLI
builds target chdr on demand for a kit whose emitters predate it, and falls
back to the extract-it-first message when it cannot.

Verified against two discs from a Redump library converted with chdman: a
single-track MODE2 disc and a four-track disc with stored audio pregaps both
reproduce their catalogued track-1 size, MD5 and SHA-1 exactly; verify-disc
and prepare_disc.py accept the four-track one end to end. Tests build a
synthetic uncompressed v5 CHD around a cooked ISO image, so no retail data is
needed; the decode tests skip with a reason when no libchdr is built.
2026-09-16 11:49:59 +03:00
..
2026-08-11 23:17:47 -04:00
2026-08-11 23:17:47 -04:00
2026-08-12 21:53:26 -04:00
2026-08-12 02:42:30 -04:00
2026-08-07 01:43:04 -04:00

New Project Layout + Project Studio

Scaffold new titles and migrate older ones onto the setup-host layout.

Policy: public releases are setup-host only (no prebuilt generated game C).

New project

sh tools/new_project_layout/setup_project.sh --disc /path/to/game.cue --dir ~/src

See docs/GAME_PROJECT_SETUP.md.

Project Studio (migrate / update)

Shared Python library under project_studio/ with CLI + CustomTkinter GUI. CLI stays stdlib-only. First GUI launch auto-creates tools/new_project_layout/.venv and installs requirements-gui.txt (network once); later launches are silent.

python3 tools/new_project_layout/project_studio_gui.py
# Audit layout gaps
python3 tools/new_project_layout/migrate_project.py audit \
  --root /path/to/ApeEscapeRecomp

# Show ordered plan
python3 tools/new_project_layout/migrate_project.py plan \
  --root /path/to/ApeEscapeRecomp

# Dry-run apply (recommended first)
python3 tools/new_project_layout/migrate_project.py apply \
  --root /path/to/ApeEscapeRecomp --dry-run

# Apply for real (rewrites CMake with .pre_migrate.bak)
python3 tools/new_project_layout/migrate_project.py apply \
  --root /path/to/ApeEscapeRecomp \
  --disc /path/to/game.cue

# GUI (auto-bootstraps .venv + customtkinter on first run)
python3 tools/new_project_layout/migrate_project.py gui
# or
python3 tools/new_project_layout/project_studio_gui.py

# Git / GitHub (also available as the GUI "Git / GitHub" tab)
python3 tools/new_project_layout/migrate_project.py git status \
  --root /path/to/ApeEscapeRecomp
python3 tools/new_project_layout/migrate_project.py git ensure-submodules \
  --root /path/to/ApeEscapeRecomp \
  --psxrecomp-branch master --recomp-ui-branch master
python3 tools/new_project_layout/migrate_project.py git set-branch \
  --root /path/to/ApeEscapeRecomp --submodule psxrecomp --branch master
python3 tools/new_project_layout/migrate_project.py git ensure-nested \
  --root /path/to/ApeEscapeRecomp \
  --recomp-net-branch main --rbengine-branch main
python3 tools/new_project_layout/migrate_project.py git update-nested \
  --root /path/to/ApeEscapeRecomp --remote
python3 tools/new_project_layout/migrate_project.py git commit-nested \
  --root /path/to/ApeEscapeRecomp -m "chore: bump nested modules"
python3 tools/new_project_layout/migrate_project.py git update-submodules \
  --root /path/to/ApeEscapeRecomp --remote
python3 tools/new_project_layout/migrate_project.py git commit \
  --root /path/to/ApeEscapeRecomp -m "chore: bump submodules"
python3 tools/new_project_layout/migrate_project.py git push \
  --root /path/to/ApeEscapeRecomp
python3 tools/new_project_layout/migrate_project.py git release \
  --root /path/to/ApeEscapeRecomp --bump patch

Git ops shell out to git / gh (no force-push, amend, or hook skips). Submodule branch in .gitmodules is for update --remote; CI builds the committed gitlink SHAs.

For bulk ops across many titles / platforms, use the sibling tool retcomm-studio (~/…/GitHub/retcomm-studio — catalog-backed CLI + plugin API).

Ops (subset)

Op Purpose
rename_psxrecomp_submodule Promote/keep psxrecomp/; delete leftover psxrecomp-v4
repair_psxrecomp_submodule Re-clone when psxrecomp/.git gitdir is broken / absorbed
ensure_recomp_ui_submodule Add recomp-ui
emit_codegen_setup Thin codegen_setup.c/.h
rewrite_cmake_setup_host psxrecomp_add_game_runtime + wizard
emit_packager scripts/package_setup_release.sh
emit_ci_workflow Setup-host release.yml
probe_disc_refresh TOC / catalog / seeds (needs --disc)
annotate_legacy_packaging Mark old prebuilt packagers obsolete

Wizard + recomp-ui are forced on for apply (setup-host requirement).

Helpers reused: probe_disc.py, fill_tokens.py, sync_symbols.py, templates/*.