Entry 247
One game from the four discs with piney-build, and a launcher
Documented in The Outbreak DVD.
Filescrates/piney-build/src/main.rscrates/piney-build/examples/estimate.rscrates/piney-data/src/pack.rscrates/piney-data/src/iso.rscrates/piney-game/src/launcher.rscrates/piney-game/src/main.rscrates/piney-stream/src/scene.rscrates/piney-stream/src/lib.rscrates/piney-gs/src/lib.rscrates/piney-gs/src/assets.rscrates/piney-audio/src/lib.rsdocs/disc/outbreak.mdREADME.md
Asked for: a piney-build that takes the four images, deduplicates them,
and builds one clean game that starts on the multi-game selector from
Outbreak's STRT.BIN. Players could use a single image, or build once and
not pass options after. Later in the session: deduplicate inside
DATA.BIN, the sound banks and the rest too, not whole files.
The build
A build is a folder: chunks.pak and one .disc per volume
(piney_data::pack lays out both).
- The chunks. Every file of every disc is cut into content-defined chunks (FastCDC: 16, 64, 256 KiB). A chunk is kept once, by its BLAKE3 hash, and zstd-compressed at level 15 where that makes it smaller.
- A
.disc. The disc's files, with their paths, original LBAs, sizes and BLAKE3 hashes, each as a run of chunk references. - Reading.
Iso::opentakes a.discas it takes an image, so every reader in the port works unchanged. The one reader that went roundIso,piney-audio'sBGM.BINseek, now reads through it. - The builder.
piney-buildtells the discs apart byGCMN.PRG(Volume::detect) and writes to the port's folder (~/.local/share/piney/game) unless told otherwise.- It compresses on 8 threads in 32 MiB batches.
- It reads every file back through the build and checks its hash.
- A disc of an earlier build that is not given again is read from that build.
- The images' volume identifiers are blank, so each disc is labelled by SYSTEM.CNF's boot name.
Measured on the four discs, 13,933.9 MiB of files:
| how | stored |
|---|---|
| chunks as they are | 7,756.1 MiB (55.7%) |
| chunks zstd 3 / 9 / 15 | 7,254.3 / 7,233.1 / 7,136.9 MiB |
| archives' members inflated, then chunked, zstd 3 | 7,136.5 MiB |
The whole build, with the check, took 53 s from the page cache; 101,251 chunks.
On deduplicating inside the archives: the chunks already do.
- Mutation's, Outbreak's and Quarantine's
DATA.BINadd 26.9, 11.5 and 0.8 MiB to Infection's 130.3. SNDDATA.BINadds 0.3, 0.5 and 0.2 MiB.- Stream archives shared byte for byte (Quarantine's
STR1E,STR2E,STRCMNE) add nothing.
What stays is different content.
- Outbreak's
STR1Eholds Infection's 40 scenes. 21 are the same inflated but compressed again (25.7 MiB); the other 19 differ inside (312.5 MiB), a few KiB changed early and the rest shifted. An aligned 4 KiB block search over the 19 found 24.2 of their 687.4 MiB inflated in Infection's. - Chunking the members' inflated contents (
examples/estimate.rs) saves no more than zstd 15 on the files as they are.
So the port's archive readers, which read gzip members at the tables' offsets, stay as they are.
The first run looped: Iso::list walked the root's . record as a
directory without end, and the process reached 39 GB before the OOM
killer took it. children now leaves that record out; the new test
list_walks_infection_once walks Infection's disc.
The launcher
piney-game with no disc given finds the build. With more than one disc
in it, LauncherMode plays trial_v2st.
- The scene. It has two copies of most objects: the opening's, posed
by the frames, and a still set at the origin that the scene never shows.
The still set holds each row's highlight (
men_X0with glowslig_X0,lig_X1), the demo labels (mes), extra icons and a background (docs/disc/outbreak.md). - What the launcher does. The scene holds its last frame
(
Stream::hold_end), and a push during the opening skips to it (fast_forward). The chosen row's highlight is placed on it (a node's world matrix set from outside,Scene::place) 7,504.7 units left of the row's origin, where the two models' texts line up. Its glows pulse at a third. A part the build lacks is dimmed. - Controls. Up and down move (the title's sounds 6, 4, 20). Cross or START starts that volume after 24 frames of flashing.
- The switch.
Event::Bootmakes the window open that disc: itsDATA.BINin the renderer (Gs::set_archive), its sound, its fonts, and the game mode. - Other cases.
- Without Outbreak in the build, a list in the game's font.
- The last choice is kept (
launcher.txt). --volume 1-4skips the launcher;--game DIRnames a build.- A build's card is
memcard/slot1in the port's folder.
Checked headless: the opening skipped, down, cross, Mutation's title by
frame 136. With a two-disc build (Infection and Mutation) it shows the
list. The piney-data, piney-stream and piney-audio suites pass, and so
does selector_rows_at_the_end (the four rows at y 9000 to -4500, each
with its still highlight).
A piney-gs test had not compiled since the console's overlay argument
(03fbb29); it passes None now.
The window's switch from the launcher to a part was checked headless only. Nothing tells the player that a finished part's save loads in the next; the port's New Game from a previous volume's save was not checked from a build.