No behaviour change. This is the pass over the last stretch of work to make sure the accumulated result hangs together rather than only each commit in isolation. Code. lit_color had grown a `let _ = (depth, lod_distances)` and a dead branch from repeated edits. The directional pass genuinely does not depend on distance, so the parameters are gone rather than discarded, with a note that the point lights -- not implemented -- will need them. lit_at folded into lit_color, which had become a wrapper around it. Checked for leftover scaffolding: only two env vars remain, both real (GC_ENGINE_SHOT and GC_ENGINE_DEBUG_BOUNDS); GC_ENGINE_UNLIT, GC_ENGINE_DEBUG_COLOR and GC_ENGINE_ABL were never actually written, because those edits silently failed to apply against rustfmt'd source. AGENTS.md. The crate table did not say that gc-engine owns hardware models. ps2.rs is the Emotion Engine's FPU and the lighting pass runs on it, so the boundary is now stated: gc-formats decodes inputs, gc-engine reproduces how the hardware computes with them. That is the distinction rule 2 depends on, and it was implicit. Docs. Three claims had been overtaken by what we learned and were actively misleading: * docs/formats/level-wad.md still said gameplay "does not decode with the WAD decoder". It does; it is a WAD stream. * docs/plan/level-assets.md carried a whole section, "a compression we have not identified", with a ruled-out list including "bit order", "header length" and "the WAD format at all". All three were ruled out against the wrong input. Replaced, with the failure mode kept: a uniform failure across 27 inputs was read as "the decoder is wrong" when it meant "the data was handed over uncompressed", and the positive control -- decompress and look -- was never run. * The same file still said the tfrag "record framing is not recovered". True, but it was a false lead that has since been superseded by the VIF1 framing. Kept as a recorded wrong turn rather than deleted. Also refreshed "Still open" to name what is actually outstanding: point lights, the GS register set, the guard-band clip test, the unread core_index class tables, and -- stated plainly -- that lighting magnitudes are unverified because there is still nothing to compare against. Verified after the changes: 148 tests pass, clippy and fmt clean, all 5,213 extracted files match the hash table, and level 0 still loads at 26,758 triangles with the same LOD split and fully lit.
136 lines
6.2 KiB
Markdown
136 lines
6.2 KiB
Markdown
# AGENTS.md — working agreements for this repository
|
|
|
|
Guidance for coding agents and for anyone picking this up cold. Read this
|
|
before changing anything.
|
|
|
|
## What this project is
|
|
|
|
A from-scratch native PC reimplementation of **Ratchet & Clank: Going Commando**
|
|
(PlayStation 2, 2003), written in Rust. The game is **reimplemented**, not
|
|
emulated and not translated: there is no MIPS interpreter and no CPU
|
|
emulator anywhere in this repository.
|
|
|
|
The goal is a build that plays the game the way the original does. "Close
|
|
enough" is not the bar — the point is that it feels like the game you remember.
|
|
|
|
## Hard rules
|
|
|
|
### 1. No game data in this repository. Ever.
|
|
|
|
Not the ISO, not extracted assets, not textures, not models, not audio, not
|
|
BIOS dumps, not SDK binaries. Not in a branch, not in a stash, not "just for a
|
|
test".
|
|
|
|
- Everything is covered by `.gitignore`.
|
|
- `.githooks/pre-commit` blocks disc images, asset directories, container
|
|
signatures and files over 50 MiB. It is activated via
|
|
`git config core.hooksPath .githooks` — **check that this is still set** in a
|
|
fresh clone, or run `git config core.hooksPath .githooks`.
|
|
- To undo the hook for a legitimate source change: `git commit --no-verify`.
|
|
Legitimate source changes should not need it.
|
|
- Game data is an **input**, supplied by the user from their own legally
|
|
obtained disc. Repositories that need the disc state its serial and hashes.
|
|
|
|
### 2. Reproduce the PS2 float model.
|
|
|
|
The Emotion Engine's FPU is not IEEE-754. It has **no denormals**, and rounding
|
|
and exception behaviour differ from x86 in ways that are visible in gameplay.
|
|
|
|
Gameplay and animation maths must model this deliberately rather than using
|
|
Rust's native `f32` and hoping. When porting a routine, find out how the
|
|
original computes it and reproduce that, including the odd cases — ReRAC's
|
|
reference implementation deliberately reproduces a "post-scale list bug" in the
|
|
moby animation evaluator because doing so is what makes the result match.
|
|
|
|
Do not "fix" something that looks like a bug until you have confirmed the
|
|
original does the same thing. Fidelity beats correctness.
|
|
|
|
### 3. Verify against the real disc, not against a guess.
|
|
|
|
A parser is correct when it round-trips your own disc's bytes, checked by hash.
|
|
Commit size-and-hash tables (never content) so a test can assert "this matches
|
|
retail" rather than "this matches whatever was on my disk".
|
|
|
|
### 4. Bound every read.
|
|
|
|
Asset data is untrusted input from a 2003 disc format. Parsers return typed
|
|
errors; they never panic and never read past the end of a buffer.
|
|
|
|
## Orientation
|
|
|
|
Read these before working in an unfamiliar area:
|
|
|
|
| Path | What it is |
|
|
|---|---|
|
|
| `docs/disc-identification.md` | Which disc we build against, verified |
|
|
| `docs/roadmap.md` | Phases, gates, and what is done |
|
|
| `docs/plan/` | One file per subsystem, written **as work proceeds** |
|
|
| `docs/formats/` | Format specs, written **as formats are reversed** |
|
|
| `PROVENANCE.md` | Upstream projects we build on, and their licences |
|
|
| `vendor/reRAC/` | Pinned reference checkout (not tracked) |
|
|
|
|
## Crates
|
|
|
|
| Crate | Responsibility |
|
|
|---|---|
|
|
| `gc-formats` | Parse asset formats into plain Rust values. No I/O beyond the caller's buffer. |
|
|
| `gc-extract` | Disc pipeline: identify, unpack, verify. |
|
|
| `gc-game` | Game logic: hero, weapons, classes, progression, saves. |
|
|
| `gc-video` | IPU/MPEG-2 decode. |
|
|
| `gc-engine` | Bevy app: GS, VU0/VU1, renderer, frame loop. Also owns the **hardware models** — `ps2.rs` is the Emotion Engine's FPU, and the tfrag lighting pass runs on it. |
|
|
|
|
The dependency direction is `gc-formats` ← `gc-extract`; `gc-formats` ←
|
|
`gc-game` ← `gc-engine`; `gc-video` ← `gc-game` ← `gc-engine`. `gc-formats`
|
|
depends on nothing of ours. Do not invert these — a format parser that can
|
|
reach into the engine cannot be tested in isolation.
|
|
|
|
A hardware model belongs in `gc-engine`, not `gc-formats`. `gc-formats`
|
|
decodes *inputs* — including the data a hardware model consumes, such as the
|
|
overlay's sine table — but arithmetic that reproduces how the PS2 computes
|
|
something is an engine concern. `tfrag_light.rs` (formats) holds the normal
|
|
table and the light bank framing; `tfrag_light.rs` (engine) holds the pass
|
|
that uses them.
|
|
|
|
## Conventions
|
|
|
|
- Rust 2021 edition, workspace inheritance for all shared config. Do not
|
|
hardcode a version in a member crate.
|
|
- `rustfmt` defaults. Clippy warnings are errors in spirit; do not silence them
|
|
without a comment explaining why.
|
|
- Error types: `thiserror` for library errors in `gc-formats` and `gc-game`,
|
|
`anyhow` at the binary/`xtask` boundary.
|
|
- Comments explain **why**, especially for anything that looks like a bug. The
|
|
`.githooks` and crate docs deliberately have few inline comments; match the
|
|
surrounding density rather than adding noise.
|
|
- Tests live beside the code (`#[cfg(test)] mod tests`) for unit-level checks,
|
|
and in `tests/` for golden-file checks against real disc data.
|
|
|
|
## Working rhythm
|
|
|
|
This is a long project. Keep it navigable:
|
|
|
|
1. Work in small, coherent commits with a substantive body explaining what was
|
|
non-obvious. Match the existing style in `git log`.
|
|
2. **Update `docs/roadmap.md`** when a phase advances or a gate is met.
|
|
3. **Write the `docs/plan/*.md` file for a subsystem when you start it**, and
|
|
update it as you learn. The reasoning is more valuable than the code; the
|
|
code is in git.
|
|
4. **Update this file** if you change a convention.
|
|
|
|
## When you get stuck
|
|
|
|
Reverse engineering means long stretches of not knowing. That is normal, not a
|
|
failure. Write down what you tried and what it ruled out in the relevant
|
|
`docs/plan/` file before moving on — the next attempt (which may be you, in
|
|
three months) needs the negative results as much as the positive ones.
|
|
|
|
If something is genuinely blocked, say so plainly and say what would unblock
|
|
it. Do not paper over a gap with an approximation that looks like it works.
|
|
|
|
## Legal
|
|
|
|
Ratchet & Clank is a trademark of Sony Interactive Entertainment, developed by
|
|
Insomniac Games. This is an unofficial fan project, not affiliated with or
|
|
endorsed by either. We redistribute no game content. Upstream projects we learn
|
|
from keep their own licences — see `PROVENANCE.md`, and keep those notices
|
|
intact when porting their code. |