Skip to content

Ampr pack - #1

Merged
danthespal merged 28 commits into
mainfrom
ampr-pack
Oct 5, 2026
Merged

danthespal merged 28 commits into
mainfrom
ampr-pack

Conversation

@danthespal

Copy link
Copy Markdown
Owner

No description provided.

danthespal and others added 28 commits October 4, 2026 06:17
Port of ampr_emu ampr_pack.py: LZ4 1.9.4 native shim, AMPRPAK4 formats,
TOML config and default preset, builder, verify/unpack/list/inspect,
runtime-config, remove-sources, ampr CLI verb, GUI panel, parity tests.

Parked: packs only work for titles that read assets through the AMPR
API; Unity titles (ordinary file I/O) fail with the default ampr_emu
build.
Checked the ampr-pack branch against how ShadowMountPlus and ampr_emu
load LZ4 packs on the console:

- ampr_emu.index now folds only ASCII letters and hashes UTF-8 bytes
  with ampr_emu's FNV basis, like build_ampr_index.py and the runtime
  resolver. Lower-casing every letter and hashing code points (Python
  MkPFS) left files with non-ASCII names unfindable on the console.
  The index also skips ampr_commands.bin, apr_emu.log and paths with
  tabs or line breaks. ASCII-only trees give the same bytes as before.
- fakelib2/libSceAmpr.sprx (ShadowMountPlus's exclusive overlay) also
  triggers the index, the default preset keeps fakelib2/ loose, and
  --ampr-libs warns when fakelib2/ would hide the copied libraries.
- ampr pack warns when a set exceeds the default emulator's limits
  (2,000,000 files, 16,000,000 chunks, 1,024 volumes), which make the
  runtime reject the whole manifest, and when --root has no AMPR Emu.
- README: APR-only titles, read-only mounts, deploying one build set.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01B4TzvxgYewNT7gc6MCuF5N
When the generated AMPR goldens are absent, Fixtures.PathOrSkip skips
the case before the work directory exists, and the finally block's
Directory.Delete then threw DirectoryNotFoundException, turning 29
skips into failures. Delete the directory only when it exists, as the
other parity tests already do.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01B4TzvxgYewNT7gc6MCuF5N
New `ampr game` subcommand and default GUI action "Build playable game"
on the AMPR Packs page. From an unpacked game folder (only read) it
builds a new folder that runs from AMPR packs as is:

1. Libraries: the game's fakelib/ (or fakelib2/, which ShadowMountPlus
   mounts instead) plus every file of the selected library folder,
   skipping identical files. libSceAmpr.sprx must be AMPR Emu 0.4.2.1+,
   detected by its embedded AMPRPAK4 magic; older builds are rejected
   before anything is written.
2. ampr_emu.index of the final tree (new libraries with their real
   sizes), written before packing because the manifest addresses files
   by index row. Byte-identical to upstream build_ampr_index.py run on
   the reconstructed final folder.
3. Packs, read from the game folder (default preset unless a TOML or
   preset is given).
4. Loose files and every folder, copied after packing because the
   packer's sampling decides which large files stay loose.
5. Verification: every chunk decoded, packed files compared with the
   source, loose files checked against their indexed sizes.

A failed step empties the output so a retry starts clean. --exfat (GUI
checkbox) then builds a 64 KiB-cluster exFAT image of the folder; a
failed image keeps the finished folder.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01B4TzvxgYewNT7gc6MCuF5N
The GUI action "Pack game files" ran `ampr pack`, which (like
ampr_pack.py) writes only ampr_assets.index, the .pak volumes and the
.crc, and users expected a playable folder. Rename it "Pack files only
(manifest and .pak volumes)" and show a note pointing to Build playable
game.

Also correct the docs: the AMPR Emu 0.4.2.1 release is the PackedStdio
build, which serves packed files to ordinary open/read/pread and AIO
calls as well as AMPR reads, so Unity titles that load libSceAmpr work;
only mmap and writable opens must stay loose.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01B4TzvxgYewNT7gc6MCuF5N
Console test with God of War Sons of Sparta (Unity, IL2CPP) on AMPR Emu
0.4.2.1: packing everything except executables and system files made
the game abort at startup (SYSTEM_ABNORMAL_TERMINATION_REQUEST), while
packing only Media/StreamingAssets (Addressables bundles, FMOD banks)
ran normally. Unity's own data files (level*, sharedassets*,
globalgamemanagers, .resS) must stay loose, consistent with Unity
reading them through a path AMPR Emu does not intercept.

`--preset unity` for `ampr pack` and `ampr game`, and a Rules picker
(Default / Unity) on the AMPR Packs page when no TOML is chosen.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01B4TzvxgYewNT7gc6MCuF5N
Users should not have to know which engine a game uses. New preset
`auto` (the default for `ampr game` and the AMPR Packs page, available
to `ampr pack`): `unity` when globalgamemanagers, data.unity3d or
global-metadata.dat is within four folder levels of the game root,
else `default`. The log names the chosen rules and the file that
decided them. A TOML file still overrides it. The GUI Rules picker
added in the previous commit is removed.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01B4TzvxgYewNT7gc6MCuF5N
Whether a packed game runs depends on how it reads its files, which
only a console test shows, and few games have been tested. Say so:

- README: "(experimental)" in the feature list and a notice at the top
  of the ampr section (keep the original game, report failing titles
  with the ShadowMountPlus log).
- GUI: an amber notice at the top of the AMPR Packs page, in all six
  languages.
- CLI: the ampr help says experimental; `ampr game` prints a warning
  before it starts. `ampr pack` output is unchanged (ampr_pack.py
  parity).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01B4TzvxgYewNT7gc6MCuF5N
A warning under the intro links to a new explanation at the top of the
ampr section: what packing does, what a game needs (ShadowMountPlus, a
libSceAmpr title, AMPR Emu 0.4.2.1+, read-only mount), why only a
console test shows whether a game runs (reads AMPR Emu does not
intercept, such as mmap), how the automatic rules were chosen, the
games tested so far, recommended steps, and what to report. The
existing reference follows under "How the packs are made" and
"Command reference".

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01B4TzvxgYewNT7gc6MCuF5N
The CLI log (ampr game, ampr pack --preset) and the AMPR Packs page now
say whether a built-in profile matched the game, which one, the file
that identified it, and whether it has run on a PS5 ("Profile found:
unity (...). Tested: runs on ..." or "No profile found for this game:
generic rules ... Untested"). A TOML file is reported as such. The page
shows the result as soon as the game folder is chosen.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01B4TzvxgYewNT7gc6MCuF5N
Insomniac Games titles (toc, dag and d/ at the top) now get rules that
pack only the d/ archives and keep the boot, movie, sound bank and
streamed audio archives loose. PPSA03671 crashed at startup with the
default rules and runs with these. --preset auto detects the layout and
reports it as a tested profile; the README records the result.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01B4TzvxgYewNT7gc6MCuF5N
AMPR Emu's debug build records every APR read into ampr_commands.bin.
`mkpfs ampr profile generate` ports ampr_emu's ampr_pack_profile.py 4.1
(the AMPRCMD1 reader, per-file read metrics, block-size scoring, index
budget, decoded-cache model and rule emission): the TOML, the Markdown
report and the runtime header match the Python tool byte for byte on 33
synthetic trace cases (tools/oracle/check_ampr_profile.py). --metrics
JSON and batch are not ported.

`ampr game` and `ampr pack` take --traces <folder> (one run per
subfolder) and pack from those rules directly; the log says how many
runs and files were used. The AMPR Packs page has a matching trace
folder field that reports how many runs it found.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01B4TzvxgYewNT7gc6MCuF5N
`ampr profile generate --metrics` (and --full-metrics) writes the
upstream metrics document, and `ampr profile batch` writes one profile
per trace run of a folder or ZIP support bundle (TOML, report, metrics
JSON, runtime header and summary.json), with the upstream batch
defaults (hybrid patterns, no cache simulation) and --batch-jobs. The
JSON writer gains insertion-ordered objects for documents dumped
without sort_keys.

tools/oracle/check_ampr_profile.py now covers both: 45 cases, every
output byte for byte against the Python tool.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01B4TzvxgYewNT7gc6MCuF5N
The trace folder search skipped files with the Hidden or System
attribute (the .NET default), which copies off the console can carry;
Python's rglob counts them, and names now follow the platform's case
rules like rglob. The AMPR Packs page also looked at the game and trace
folders only when a path was picked, so runs copied in later kept the
"No traces in this folder" warning; it now looks again before each run.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01B4TzvxgYewNT7gc6MCuF5N
A trace session rarely reaches every level or mode: with two UFC 6
sessions, 111 of its .cas archives (24 GiB) were never read and stayed
loose. --pack-untraced-types (ampr game, ampr pack, profile generate)
and a checkbox on the AMPR Packs page add every untraced file of the
traced games' indexes whose extension a packed traced file has, with
the layout, block size and group most traced files of that type got.
Files without an extension, executables, modules, sce_sys and fakelib
are never added; the rules go before the upstream safety exclusions,
and the upstream part of the TOML is unchanged.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01B4TzvxgYewNT7gc6MCuF5N
Images were always exactly full (no free cluster), so nothing could
write to a mounted image even read-write: AMPR Emu's debug log stayed
empty when a packed game was tested. pack exfat --free-space, ampr game
--exfat-free-space and a field on the AMPR Packs page reserve zeroed
clusters at the end of the heap; only the used ones are marked in the
allocation bitmap. With the default 0 the image is unchanged.
fsck.exfat (exfatprogs 1.2.2) reports both kinds of image clean.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01B4TzvxgYewNT7gc6MCuF5N
The default, insomniac and unity presets, their auto-detection and --preset
are removed. ampr game and the AMPR Packs page now need the game's TOML
profile (--config) or a trace folder (--traces); the profiles are published
as separate files, one per game. The README describes what the tested
profiles learned and adds EA SPORTS UFC 6 to the tested games.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01B4TzvxgYewNT7gc6MCuF5N
…mp folder

- AMPR Packs page: the trace folder is searched recursively, and this ran on the
  UI thread on every keystroke, so a half-typed path such as a drive root froze
  the window. The count now runs in the background after typing pauses.
- profile batch: ZIP member names were split only on '/', so on Windows a part
  holding "..\" or a drive ("C:") could write outside the extraction folder.
  The resolved target must now stay inside it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01B4TzvxgYewNT7gc6MCuF5N
ShadowMountPlus works best with an exFAT image wrapped in FFPFSC, so BUILD now
lists Pack exFAT, Pack FFPFSC (formerly Pack File) and AMPR Packs. The Pack
Folder and Batch pages are removed from the GUI with their views, view models
and strings; `pack folder` and `batch` stay in the CLI. A trace-folder test
assertion that raced with the background count is removed.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01B4TzvxgYewNT7gc6MCuF5N
…ltips

- Runs with several progress phases (pack file with --verify, verify against
  a source, repair, ampr game with an exFAT image) now fill one bar across
  all phases, weighted by how much data each moves, and never move it back;
  the label names the step, for example "verify (2/3)".
- CPU Cores is a dropdown: Auto, which uses every core of the computer, then
  1 up to the core count. The CLI default is unchanged.
- Every Compression Tuning and Advanced option has a tooltip in all six
  languages.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01B4TzvxgYewNT7gc6MCuF5N
Environment.ProcessorCount counts logical processors, twice the cores on a CPU
with SMT. The picker and its Auto entry now use the physical core count, read
from GetLogicalProcessorInformationEx on Windows, the sysfs topology on Linux
and hw.physicalcpu on macOS, falling back to the logical count.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01B4TzvxgYewNT7gc6MCuF5N
README: a centered header with badges and a screenshot, a contents list, a
features table, a quick start with a diagram of the exFAT -> FFPFSC flow, a
"which file should I make" table, desktop app screenshots and page table,
command and exit-code tables, long option tables folded away, and diagrams for
how AMPR packs are read and how a game gets packed.

MIGRATION.md gets an at-a-glance table and a table of fixed Python bugs; the
oracle README a summary of the three oracles, the profile check and a fixed
line-ending note; the native ORIGIN notes a source table.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01B4TzvxgYewNT7gc6MCuF5N
@danthespal
danthespal merged commit b33f01e into main Oct 5, 2026
4 checks passed
@danthespal
danthespal deleted the ampr-pack branch October 5, 2026 09:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants