Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
9928e99
Add AMPR asset pack support (WIP)
danthespal Oct 4, 2026
fe1acf4
Match ampr_emu's index lookup and flag unusable AMPR pack sets
claude Oct 4, 2026
7492822
Skip AMPR builder parity cases cleanly without fixtures
claude Oct 4, 2026
a7d1c07
Add ampr game: build a pack-based game folder ready to copy and play
claude Oct 4, 2026
cdbb3e9
Clarify that ampr pack writes only the pack set
claude Oct 4, 2026
ac6eb01
Add a unity preset that packs only StreamingAssets
claude Oct 4, 2026
e95df0a
Pick Unity or default pack rules automatically
claude Oct 4, 2026
51b17df
Mark AMPR packing as experimental
claude Oct 4, 2026
3ba0c73
README: explain AMPR packing and why it is experimental
claude Oct 4, 2026
3fe9b23
README: record PPSA03671 crashing with the default rules
claude Oct 4, 2026
5aaac60
Say whether a rules profile matched the game before packing
claude Oct 4, 2026
ff0ce0b
Add the insomniac AMPR rules, picked automatically
claude Oct 4, 2026
19e1854
Port ampr_pack_profile.py: pack rules from APR traces
claude Oct 4, 2026
a93b37f
Port ampr_pack_profile.py's metrics JSON and batch command
claude Oct 4, 2026
75e0707
Find trace runs with hidden files and re-check folders before a run
claude Oct 5, 2026
9692c01
Optionally pack untraced files of the traced file types
claude Oct 5, 2026
a0d5cd8
Leave optional free space inside exFAT images
claude Oct 5, 2026
7472199
Move the built-in pack rules out into shared TOML profiles
claude Oct 5, 2026
e458d1d
Drop the tested games table from the README
claude Oct 5, 2026
a230e7a
Drop the per-engine profile notes from the README
claude Oct 5, 2026
42ca45e
Rewrite the AMPR section of the README to be shorter and game-neutral
claude Oct 5, 2026
bdf7986
Drop the .cas example from the untraced-files option text
claude Oct 5, 2026
2e0d98b
Count trace runs off the UI thread and keep ZIP members inside the te…
claude Oct 5, 2026
53b198a
Reorder the BUILD pages and drop Pack Folder and Batch from the GUI
claude Oct 5, 2026
f74dd14
One progress bar for the whole run, a CPU core picker, and option too…
claude Oct 5, 2026
ec82edf
Count physical CPU cores, not logical processors, in the CPU picker
claude Oct 5, 2026
0ca3419
Rewrite the README and the other Markdown files
claude Oct 5, 2026
a2b26c6
Bump the version to 2.1.0
claude Oct 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<AnalysisLevel>latest</AnalysisLevel>
<Deterministic>true</Deterministic>
<InvariantGlobalization>true</InvariantGlobalization>
<Version>2.0.3</Version>
<Version>2.1.0</Version>
<Authors>arsenic9408</Authors>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup>
Expand Down
109 changes: 60 additions & 49 deletions MIGRATION.md
Original file line number Diff line number Diff line change
@@ -1,67 +1,78 @@
# Moving from Python MkPFS

MkPFS.CSharp is a drop-in replacement for the Python [MkPFS](https://github.com/PSBrew/MkPFS) 1.0.0 command
line. Scripts keep working: the program is still `mkpfs`, the commands and every flag have the same
names, and the console output has the same layout.
MkPFS.CSharp is a **drop-in replacement** for the Python [MkPFS](https://github.com/PSBrew/MkPFS) 1.0.0
command line. Scripts keep working: the program is still `mkpfs`, every command and flag has the same name
and default, and the console output has the same layout.

## Install
## At a glance

| Python MkPFS | MkPFS.CSharp |
|---|---|
| `pip install mkpfs` or `uv tool install mkpfs` | Unpack `mkpfs-<version>-<system>` from the [releases page](https://github.com/danthespal/MkPFS.CSharp/releases) |
| Needs Python 3.9+ with `cryptography` and, on x64 and ARM, `isal` | Single native executable plus `mkpfs_zlib`; no runtime to install |
| `mkpfs-gui` (customtkinter) | `mkpfs-gui-<version>-<system>`; on macOS `MkPFS.CSharp.app` |
| | Python MkPFS | MkPFS.CSharp |
|---|---|---|
| **Install** | `pip install mkpfs` or `uv tool install mkpfs` | Unpack `mkpfs-<version>-<system>` from the [releases page](https://github.com/danthespal/MkPFS.CSharp/releases) |
| **Needs** | Python 3.9+ with `cryptography`, and `isal` on x64 and ARM | Nothing: one native executable plus `mkpfs_zlib` |
| **Desktop app** | `mkpfs-gui` (customtkinter) | `mkpfs-gui-<version>-<system>`; on macOS `MkPFS.CSharp.app` |
| **Compression** | ISA-L by default | Always zlib 1.3.1 |
| **Images** | — | Byte-identical to Python with `--compression-backend zlib` |

## Commands and flags

Every Python command and flag exists with the same name and default:

| Command | Change |
|---|---|
| `pack folder`, `pack file`, `pack exfat` | Same flags. `--compression-backend` is accepted but ignored (see below). |
| `pack folder`, `pack file`, `pack exfat` | Same flags. `--compression-backend` is accepted but ignored ([why](#compression-backend)). |
| `batch` | Same flags. |
| `verify`, `inspect`, `tree`, `unpack` | Same flags. |
| `repair` | New: finds and fixes PFSC blocks the PS5 may decode wrongly. |
| `repair` | **New:** finds and fixes PFSC blocks the PS5 may decode wrongly. |
| `ampr` | **New (experimental):** AMPR Emu LZ4 asset packs. |
| `selftest` | **New:** checks that the bundled native libraries load. |

Exit codes match Python: 0 on success, 1 on errors, 2 on usage errors (missing arguments, unknown
or conflicting options). `repair --scan` adds 3 for "blocks need repair". Usage error messages
are worded differently from Python's argparse.
**Exit codes** match Python: `0` success, `1` error, `2` usage error (missing arguments, unknown or
conflicting options). `repair --scan` adds `3` for "blocks need repair". Usage error messages are worded
differently from Python's argparse.

## Behavior that differs

**Compression backend.** Python's default `auto` backend picks ISA-L, which Python MkPFS installs
on x64 and ARM. ISA-L streams use back-references the PS5 decodes wrongly (corrupted game files
after mounting). MkPFS.CSharp always compresses with zlib 1.3.1 at the same level (7 by default):
`auto` and `zlib` are accepted silently, `isal` and `zlib-ng` print a warning and use zlib.

**Same images.** With the same source and flags, MkPFS.CSharp writes the same bytes as Python MkPFS
compressing with zlib, except for the build time stored in the image. In Python that takes
`--compression-backend zlib`, plus `--cpu-count 1` for large inputs, because its worker processes
ignore the backend option. Set `SOURCE_DATE_EPOCH` (seconds since 1970) to pin the build time for
reproducible builds.

**Fixed Python bugs.** These Python results change (details in
[tools/oracle/README.md](tools/oracle/README.md), "Findings"):

- `--skip-verification` works on its own; Python always rejected it.
- `verify` of signed images larger than 12 blocks no longer crashes.
- `verify --source-dir` reports each missing or extra path once, not twice, and compares an
exFAT-wrapped image with the files inside its exFAT instead of reporting every file missing.
- `unpack` refuses entry names that would escape the output folder.
- exFAT images use the exFAT up-case table for name hashes, so names such as `Straße` stay readable
on the console; `pack exfat` fails if a source file changes size while it is packed.
- `batch` prints the real PS4/PS5 profile, and `batch --verify` checks a folder item against the
files inside its image instead of failing every time.
- Game titles use the `param.json` default language instead of the first language in the file
(often Arabic).

**Name.** The header line reads `MkPFS.CSharp <version> - https://github.com/danthespal/MkPFS.CSharp`.
Tools that parse the first lines of the output should accept both names.
### Compression backend

Python's default `auto` backend picks ISA-L, which Python MkPFS installs on x64 and ARM. ISA-L streams use
back-references the PS5 decodes wrongly, which corrupts game files after mounting. MkPFS.CSharp always
compresses with zlib 1.3.1 at the same level (7 by default): `auto` and `zlib` are accepted silently, `isal`
and `zlib-ng` print a warning and use zlib.

### Same images

With the same source and flags, MkPFS.CSharp writes the same bytes as Python MkPFS compressing with zlib,
except for the build time stored in the image. In Python that takes `--compression-backend zlib`, plus
`--cpu-count 1` for large inputs, because its worker processes ignore the backend option. Set
`SOURCE_DATE_EPOCH` (seconds since 1970) to pin the build time for reproducible builds.

### Fixed Python bugs

These Python results change (details in [tools/oracle/README.md](tools/oracle/README.md), "Findings"):

| Area | Fix |
|---|---|
| `--skip-verification` | Works on its own; Python always rejected it. |
| `verify` | Signed images larger than 12 blocks no longer crash. |
| `verify --source-dir` | Reports each missing or extra path once, and compares an exFAT-wrapped image with the files inside its exFAT. |
| `unpack` | Refuses entry names that would escape the output folder. |
| exFAT images | Use the exFAT up-case table for name hashes, so names such as `Straße` stay readable on the console; `pack exfat` fails if a source file changes size while it is packed. |
| `batch` | Prints the real PS4/PS5 profile; `batch --verify` checks a folder item against the files inside its image. |
| Game titles | Use the `param.json` default language instead of the first language in the file (often Arabic). |
| `ampr_emu.index` | Hashed the way the console looks paths up, so files with non-ASCII names are found. |

### Name

The header line reads `MkPFS.CSharp <version> - https://github.com/danthespal/MkPFS.CSharp`. Tools that parse
the first lines of the output should accept both names.

## New in MkPFS.CSharp

- `mkpfs repair` for single-file `.ffpfsc` images, with `--scan`, `--bad-blocks` (PS5 Game Compressor
`bad_blocks.tsv`), `--recompress`, `--mode`, and `--report-dir`.
- `verify` warns when compressed blocks use back-references the PS5 may decode wrongly and points to
`repair`.
- The GUI has a Repair page with a block map of the image.
- **`mkpfs repair`** for single-file `.ffpfsc` images, with `--scan`, `--bad-blocks` (PS5 Game Compressor
`bad_blocks.tsv`), `--recompress`, `--mode` and `--report-dir`.
- **`verify` warnings** when compressed blocks use back-references the PS5 may decode wrongly, pointing to `repair`.
- **APR Emu:** `pack exfat` and `batch` also write `ampr_emu.index`, and `--ampr-libs` copies AMPR Emu into `fakelib/`.
- **`mkpfs ampr`** (experimental): LZ4 asset packs that AMPR Emu reads on the fly, with rules from a TOML
profile or from traces recorded on the console.
- **Desktop app:** a Repair page with a block map, an AMPR Packs page, tooltips on every tuning option, and a
CPU core picker. The desktop app builds exFAT and FFPFSC images; `pack folder` and `batch` stay on the
command line.
Loading
Loading