docs: final v0.2.0 pre-tag pass

- Drop-in ROM wording everywhere (README quick start, Pages landing,
  release notes, bundled README): first launch auto-generates the
  derived assets via the frozen converter; no Python/toolchain needed.
  PAL/JP marked not-yet-supported with issue #85 pointers.
- building.md: Linux build is CI-compiled and ships in the bundle
  (was 'never built or run on Linux'); bundle note now describes the
  frozen ge007-convert auto-spawn; PAL/JP sidecar caveat (D258).
- Status rewording across README/Pages/release notes: drop the
  'first open-source port to our knowledge' claim; cutscene glitch
  description aligned to 'mostly with James Bond'; index.md status
  no longer contradicts the open D255 Deck crash.
- Em-dash cleanup across all GitHub Pages docs (index, building,
  internals, porting-notes, dev-process, agentic-development,
  release notes); internal dev logs untouched.
This commit is contained in:
James Dansereau committed 2026-09-13 23:51:27 -04:00
1 parent b2d5551ece
commit 436484a926
9 files changed
+476 -469

No files matched your search

+28 -25
View File
@@ -1,4 +1,4 @@
## GoldenEye 007 PC Port — <version>
## GoldenEye 007 PC Port <version>
<p align="center">
<img src="https://github.com/jkdansereau/goldeneye-pc-port/raw/v0.2.0/docs/media/goldeneye-gh-preview.gif" width="480"
@@ -6,15 +6,17 @@
</p>
> The full single-player campaign runs at a steady 60 fps with audio (music +
> SFX) playing throughout, on Windows and Linux including Steam Deck — and it
> SFX) playing throughout, on Windows and Linux including Steam Deck, and it
> is completable end to end: the whole campaign has been playtested through
> all 21 missions (Agent difficulty). To our knowledge this is also the first
> open-source port of the original N64 game to ship as a public release. It's
> an early public cut: all 21 solo missions load and run crash-free, but the
> known issues below are real — feedback is very welcome.
> all 21 missions (Agent difficulty). It's an early public cut: all 21 solo
> missions load and run crash-free, but the known issues below are real;
> feedback is very welcome.
### What's new since v0.1.0
- **Drop-in ROM, no tooling**: unpack the bundle, drop your NTSC-U (US) ROM
in `data/`, launch; the first run generates the derived assets
automatically. No Python, no installer, nothing to set up.
- **Steady 60 fps** in normal play (the software RSP runs off the presentation
critical path); `Video.DisplayFPS` in the F10 overlay shows it.
- **Audio**: in-level music and sound effects throughout (the alpha was
@@ -26,38 +28,39 @@
- **Rendering**: outdoor skies render correctly; water no longer renders
green/pulsing; reflective surfaces (glass, chrome weapon skins) work.
- **Crash fixes**: the two v0.1.0-era crashing levels (Bunker ii, Statue) and
the AI-pacing bug that broke Cradle are fixed and playtest-verified — all 21
the AI-pacing bug that broke Cradle are fixed and playtest-verified: all 21
solo missions load and run crash-free. Also fixed: the Steam Deck / Linux
Facility crash triggered by walking into the crouch-forcing spot at the
level's opening (D253) — this also revives the auto-crouch and ladder
level's opening (D253); this also revives the auto-crouch and ladder
signals, which were dead on PC before.
- **QoL**: F10 in-game options overlay (fullscreen, resolution, frame cap,
MSAA, texture filtering, FOV/draw distance, sensitivity), F12 screenshot.
- **Everything unlocked by default** — all 21 solo levels are selectable at
- **Everything unlocked by default**: all 21 solo levels are selectable at
every difficulty from the first launch, 007 mode is available, and the cheat
menu is fully populated. No *active* cheats are enabled (weapons remain
per-mission pickups, as on N64); F10 → *All unlocked* switches back to
faithful N64 progression.
- **Steam Deck first-run preset** — on SteamOS the first launch seeds
- **Steam Deck first-run preset**: on SteamOS the first launch seeds
Deck-friendly defaults (native 1280×800 fullscreen, VSync, MSAA 4, 150%
draw/LOD distance); an existing `ge007.ini` always wins. Two more F10 rows:
*No hit flash* (suppresses the damage-flash overlay) and *Skip intro*.
- **Modern dual-stick controller layout** (the scheme used by the console
re-releases): left stick move/strafe, right stick look, right trigger fire,
left trigger aim, A/X use, B/Y crouch/cancel, **RB/LB cycle weapons**.
- **Linux / Steam Deck**: the Linux bundle now ships its own SDL2 — it runs
- **Linux / Steam Deck**: the Linux bundle now ships its own SDL2, so it runs
as-is on any distro, and sideloads onto a Steam Deck with nothing
installed. Saves and F10 settings now persist no matter which directory you
launch from (previously Linux wrote them relative to the launch directory
only, so they silently failed elsewhere — D256); the options overlay is
only, so they silently failed elsewhere; D256); the options overlay is
fully gamepad-driven on the Deck.
### Known issues
- **Cutscenes frequently glitch** — skipped beats, wrong camera, misplaced or
hovering actors, wrong timing; the Dam level-end cutscene is racy (D243).
The most visible gap in this release.
- **Particle colours cycle through a rainbow palette** — bullet-impact sparks
- **Cutscenes still glitch, mostly with James Bond**: in scripted sequences
Bond is the one who gets misplaced, hovers, or spins; the other actors are
fine for the most part now. The Dam level-end cutscene is racy (D243).
Still the most visible gap in this release.
- **Particle colours cycle through a rainbow palette**: bullet-impact sparks
and lingering smoke/explosion residue drift through the hues over time
instead of holding their intended grey/orange palette (D252).
- Water on `IsWater` levels shows a moving seam between two patterns (D245);
@@ -69,14 +72,14 @@
selected** (e.g. the MSAA value appears both on its own row and again at
the panel bottom); earlier builds showed it as an intermittent 4K-
fullscreen ghost of the top row.
- **Steam Deck: one intermittent crash remains** — the v0.1.0-era Facility
- **Steam Deck: one intermittent crash remains**: the v0.1.0-era Facility
crash is confirmed fixed on Deck hardware, but a SIGSEGV can occasionally
occur during heavy firefights (D255; seen on Bunker and Frigate). The
faulting-register capture in `ge007.crash.log` has pinned it: an object
record whose model reference is NULL while the record is still active —
record whose model reference is NULL while the record is still active;
i.e. something in a mid-firefight destruction leaves the record live one
tick too long. We're tracking down the exact destruction path; more Deck
playtime across levels is welcome — please report any Deck-specific faults.
playtime across levels is welcome; please report any Deck-specific faults.
### Downloads
@@ -87,13 +90,13 @@
Each contains the engine executable, a README, license texts, and the
`prepare-assets` tool. **No ROM, no game assets.** The Windows bundle carries
its runtime DLLs; the Linux bundle carries SDL2 — on both platforms nothing
its runtime DLLs; the Linux bundle carries SDL2, so on both platforms nothing
needs to be installed first.
### Running it
You supply your own **GoldenEye 007 N64 ROM** (`.z64`, big-endian) that you
legally own — the **NTSC-U (US)** release is what this build supports (PAL / JP
legally own: the **NTSC-U (US)** release is what this build supports (PAL / JP
are on the roadmap). No Python, no toolchain, nothing to install.
1. Unpack the archive.
@@ -103,13 +106,13 @@ are on the roadmap). No Python, no toolchain, nothing to install.
seconds: it detects your ROM, generates the two derived asset folders
(`data/pcmodels-ntsc-final/`, `data/pccg-ntsc-final/`) once, and saves them
for every future run. (The generator is `prepare-assets/ge007-convert`
inside the bundle; you can also run it manually — it prints what it's doing.)
inside the bundle; you can also run it manually; it prints what it's doing.)
**Steam Deck:** sideload the unpacked folder (USB or a file manager), do steps
2–3, then add the executable to Games → *Add Game* as a non-Steam game.
**In-game settings on the Deck:** the options overlay is fully gamepad-driven
— it opens with **Select**, the D-pad or left stick (up/down) moves between
**In-game settings on the Deck:** the options overlay is fully gamepad-driven:
it opens with **Select**, the D-pad or left stick (up/down) moves between
options, **A** steps the selected option forward, **B** steps it back, and
**Start** (or Select again) closes. No keyboard needed.
@@ -124,7 +127,7 @@ sha256sum -c goldeneye-pc-port-<version>-linux-x86_64.tar.gz.sha256
### Source & docs
<https://github.com/jkdansereau/goldeneye-pc-port> — built on the
<https://github.com/jkdansereau/goldeneye-pc-port>, built on the
[GoldenEye 007 decompilation](https://github.com/n64decomp/007), architecture
after the [Perfect Dark PC port](https://github.com/fgsfdsfgs/perfect_dark).
Non-commercial fan preservation/research project; not affiliated with any
+65 -68
View File
@@ -12,11 +12,10 @@ in a dedicated `port/` layer, following the architecture of the
[Perfect Dark PC port](https://github.com/fgsfdsfgs/perfect_dark), the same
Rare "Indy" engine family, one hardware generation apart.
**v0.2.0** is out for Windows and Linux — including Steam Deck, where the
Linux bundle sideloads as-is — and runs the full campaign at a steady 60 fps
with known rough edges ([Status](#status)). To our knowledge it's also the
first open-source port of the original N64 game to ship as a public release:
free to download, build on and modify (you bring the ROM).
**v0.2.0** is out for Windows and Linux (including Steam Deck, where the
Linux bundle sideloads as-is) and runs the full campaign at a steady 60 fps
with known rough edges ([Status](#status)). Free to download, build on and
modify (you bring the ROM).
It's also a case study in AI-agent collaboration on a large, low-level
codebase: two coding agents, driven by one person part-time, porting ~230
@@ -26,47 +25,45 @@ See [Background](#background).
> [!IMPORTANT]
> **You must supply your own GoldenEye 007 ROM.** This repository contains no
> Nintendo code or assets, and no ROM. Nothing here is distributable as a
> playable game — see [Requirements](#requirements) and [Legal](#legal).
> playable game: see [Requirements](#requirements) and [Legal](#legal).
<p align="center">
<img src="docs/img/shots/shot-06.jpg" width="32%" alt="Bunker 1, in-engine">
<img src="docs/media/goldeneye-gh-preview.gif" width="32%"
<img src="docs/media/goldeneye-gh-preview.gif" width="64%"
alt="~32 s gameplay montage from live play sessions">
<img src="docs/img/shots/shot-01.jpg" width="32%" alt="Dam, in-engine">
<br><em>All in-engine, running in the port — Bunker&nbsp;1 and Dam captures plus a
~32&nbsp;s gameplay montage loop from the v0.2.0 playtest.</em>
<br><em>All in-engine, running in the port, a ~32&nbsp;s gameplay montage loop
from the v0.2.0 playtest.</em>
</p>
## Download
| Platform | Bundle | Notes |
|---|---|---|
| **Windows** (x86_64) | [win64.zip](../../releases) | Engine + runtime DLLs + the one-time asset tool. |
| **Linux** (x86_64) / **Steam Deck** | [linux tarball](../../releases) | SDL2 is bundled — runs as-is on any distro, and sideloads onto a Deck with nothing installed. |
| **Windows** (x86_64) | [win64.zip](/jkdansereau/goldeneye-pc-port/releases) | Engine + runtime DLLs + the one-time asset tool. |
| **Linux** (x86_64) / **Steam Deck** | [linux tarball](/jkdansereau/goldeneye-pc-port/releases) | SDL2 is bundled, so it runs as-is on any distro, and sideloads onto a Deck with nothing installed. |
Both bundles contain **no ROM and no game assets** — you supply your own
Both bundles contain **no ROM and no game assets**: you supply your own
(see [Requirements](#requirements)), which keeps the release legal to
distribute. Earlier builds: v0.1.0 alpha, same page. You can also build it
yourself; see [Building](#building).
### Quick start
You need a GoldenEye 007 N64 ROM (`.z64`, big-endian; NTSC-U recommended — all
three regions are supported). No ROM or game asset is included or distributed.
Then:
You need a GoldenEye 007 N64 ROM (`.z64`, big-endian). This release supports
the **NTSC-U (US)** version; PAL and JP are on the roadmap ([issue
#85](/jkdansereau/goldeneye-pc-port/issues/85)). No ROM or game asset is
included or distributed. Then:
1. Download the Windows or Linux bundle from [Releases](../../releases) and unpack it.
1. Download the Windows or Linux bundle from [Releases](/jkdansereau/goldeneye-pc-port/releases) and unpack it.
2. Make a `data/` folder next to the executable and drop the ROM in as `ge007.ntsc-final.z64`.
3. Run the one-time asset step: `python3 prepare-assets/prepare-assets.py` (Python 3.8+, stdlib only).
4. Launch the executable from that folder.
3. Launch the executable from that folder. The first run takes a few extra seconds: it detects the ROM and generates the derived asset folders once (no Python or other tooling needed).
Read the [Status](#status) caveats first — v0.2.0 has known rough edges,
Read the [Status](#status) caveats first: v0.2.0 has known rough edges,
listed plainly there.
## Status
**v0.2.0 — playable, with known rough edges.** The full single-player
campaign is completable end to end (all 21 missions, Agent difficulty —
**v0.2.0 - playable, with known rough edges.** The full single-player
campaign is completable end to end (all 21 missions, Agent difficulty,
playtested), at a steady 60 fps; all 21 solo missions load, render and run
crash-free, verified on Windows, Linux and real Steam Deck hardware. Feedback
is very welcome.
@@ -74,8 +71,7 @@ is very welcome.
**Working:** boot sequence and front end (menu → mission select → briefing →
start); all 21 solo missions load, render and are crash-free (full campaign
playtested end to end at Agent difficulty); steady 60 fps
(software RSP off the presentation critical path); full audio — in-level music
and SFX; keyboard + mouse (click-to-lock, proportional aim mode) and a modern
(software RSP off the presentation critical path); full audio: in-level music and SFX; keyboard + mouse (click-to-lock, proportional aim mode) and a modern
dual-stick controller layout; file-backed saves; all levels, 007 mode and the full cheat menu unlocked by
default (F10 → *All unlocked* restores faithful N64 progression); F10 in-game
options overlay (resolution, frame cap, MSAA, filtering, FOV, sensitivity);
@@ -83,17 +79,16 @@ Windows and Linux.
**Known issues:**
- **Cutscenes glitch frequently** — skipped beats, wrong camera, misplaced or
hovering actors, wrong timing; the Dam level-end cutscene is racy (D243).
The most visible gap in this release.
- A few in-level music tracks sound wrong — a wrong-sounding bass instrument
on some elevator/level tracks (D230).
- **Cutscenes still glitch, mostly with James Bond**: in scripted sequences
Bond is the one who gets misplaced, hovers, or spins; the other actors are
fine for the most part now. The Dam level-end cutscene is racy (D243).
Still the most visible gap in this release.
- Particle colours drift through a rainbow palette instead of holding their
grey/orange intent (bullet sparks, lingering smoke/explosion residue) (D252).
- Water levels show a moving seam between two water patterns (D245); thin
pixel strips at the left/right screen edges at non-integer window scales
(D246).
- Some front-end 3D models are off — the spinning Nintendo logo renders as two
- Some front-end 3D models are off: the spinning Nintendo logo renders as two
white blobs and the Rareware logo's texture filtering looks wrong (D75).
- The F10 overlay's bottom row duplicates whatever item is currently selected
(D251).
@@ -103,23 +98,23 @@ Windows and Linux.
[`docs/dev/GRAPHICS-BACKLOG.md`](docs/dev/GRAPHICS-BACKLOG.md).
- No macOS or ARM support; no controller rebinding UI.
Root causes and fix status for every item: the [release notes](../../releases)
Root causes and fix status for every item: the [release notes](/jkdansereau/goldeneye-pc-port/releases)
and the finding log in [`docs/dev/findings.md`](docs/dev/findings.md).
### Steam Deck
The Linux bundle is the Deck build. SFTP it over from your PC, or download
it straight from the [releases page](../../releases) on the Deck itself:
unzip, drop your ROM in `data/`, run `prepare-assets` once, and add the
executable as a non-Steam game. SDL2 is bundled, so no dependencies need
it straight from the [releases page](/jkdansereau/goldeneye-pc-port/releases) on the Deck itself:
unzip, drop your ROM in `data/`, launch it once (the first run generates the
derived assets), and add the executable as a non-Steam game. SDL2 is bundled, so no dependencies need
installing. On SteamOS the first launch seeds `ge007.ini` with Deck-friendly
defaults — native 1280×800 fullscreen, VSync, MSAA 4, and 150% draw/LOD
defaults: native 1280×800 fullscreen, VSync, MSAA 4, and 150% draw/LOD
distance (the authored N64 fade distances read short on the close-up panel);
everything is changeable in the options overlay and persists afterwards. The renderer is CPU-bound (software RSP); expect original N64-era
performance at 60 fps rather than more. This release was playtested on real
Deck hardware — the v0.1.0-era Facility crash was never reproduced there, and
its prime suspect (D253) is fixed; one intermittent SIGSEGV in heavy
firefights remains open (D255).
Deck hardware; the v0.1.0-era Facility crash (D203) did not recur: its root
cause was identified and fixed (D253), verified on the Deck; one intermittent
SIGSEGV in heavy firefights remains open (D255).
**In-game settings on the Deck.** The options overlay is fully gamepad-driven:
it opens with **Select**, the D-pad or left stick (up/down) moves between
@@ -130,29 +125,29 @@ overlay is `F10` + arrows/Enter.
## Beyond playing
- **Tweak it** — `ge007.ini` and the F10 in-game overlay expose resolution,
- **Tweak it**: `ge007.ini` and the F10 in-game overlay expose resolution,
frame cap, MSAA, texture filtering, FOV/draw distance and mouse feel;
launch with `-fresh` for a clean-slate run.
- **Read it** — [`docs/internals.md`](docs/internals.md) maps the
- **Read it**: [`docs/internals.md`](docs/internals.md) maps the
architecture and the software RSP; [`docs/porting-notes.md`](docs/porting-notes.md)
is the catalogue of N64→PC bug classes hit along the way. Game logic in
`src/` is unmodified decompilation; every hardware surface lives in the
MIT-licensed `port/` layer.
- **Mod it** — the port layer, build system and `tools_pc/` are yours to
- **Mod it**: the port layer, build system and `tools_pc/` are yours to
extend (see [License](#license)); [`CONTRIBUTING.md`](CONTRIBUTING.md) has
the ground rules for getting changes in, and [`docs/dev/`](docs/dev/) is
the raw engineering record behind every fix.
## Background
The port was built by two coding agents — a local open-weight model
The port was built by two coding agents, a local open-weight model
(`unsloth/Qwen3.8-27B-GGUF` on one RTX 5090, via the [pi](https://pi.dev/)
agent) doing the groundwork (build, boot chain, software-RSP integration,
asset pipeline, first frames), and **Claude Code** (Sonnet 5, Opus 5 for the
hardest bugs) joining for the collaborative phase (the 21-level sweep, the
ABI finding catalog, SDL input, front end) — handing work back and forth
ABI finding catalog, SDL input, front end), handing work back and forth
through shared written notes, directed by one person part-time. In short:
~3.5 weeks, ~430 commits, 200+ root-caused bugs logged.
~3.5 weeks, ~430 commits, 200+ bugs logged and tracked to resolution.
The full write-up (timeline, handoff mechanism, effort breakdown, an honest
"what worked / what didn't"): [`docs/dev/agentic-development.md`](docs/dev/agentic-development.md).
@@ -169,18 +164,18 @@ different: they machine-translate the shipped binary of the *unreleased Xbox
360 XBLA remaster*, a different game on a different codebase with no shared
code with this one.
| | This project | [GoldenEye-Recomp](https://github.com/SunJaycy/GoldenEye-Recomp) / [Steam Deck build](https://github.com/couchk1ng/GoldenEye-Recomp-SteamDeck) |
| | This project | The other well-known "GoldenEye on PC" recompilation projects (and their Steam Deck builds) |
|---|---|---|
| **What it ports** | The original **Nintendo 64** game (1997) | The **Xbox 360 XBLA** HD remaster (built ~2007, never released) |
| **How** | Decompilation-based source port — human-reconstructed C, compiled for the host; game logic runs as written | Static binary recompilation — the shipped machine code is auto-translated to C; no source-level understanding |
| **How** | Decompilation-based source port: human-reconstructed C, compiled for the host; game logic runs as written | Static binary recompilation: the shipped machine code is auto-translated to C; no source-level understanding |
| **Lineage** | [GoldenEye 007 decompilation](https://github.com/n64decomp/007) + [Perfect Dark PC port](https://github.com/fgsfdsfgs/perfect_dark) engine family | Xbox 360 "…Recompiled" static-recompilation family |
| **Renderer** | Software RSP → OpenGL | Hardware (Vulkan) |
| **Status** | v0.2.0; see [Status](#status) | Playable full game, higher frame rates, online multiplayer |
| **Why it exists** | A [case study in AI-agent collaboration](#background) on a hard low-level codebase | A polished, playable PC release of the remaster |
| **Status** | v0.2.0 public release; full campaign playable at 60 fps (see [Status](#status)) | Playable full game with online multiplayer |
| **Why it exists** | To run the *original* N64 game from source, and as a [case study in AI-agent collaboration](#background) on a hard low-level codebase | To get a playable PC release of the remaster |
If you just want to play GoldenEye on PC today, use one of the recompilation
projects: they are finished and this is not. What's here is the other half,
getting the *original* game running from source.
They answer a different question: how to get the *remaster* onto PC by
machine translation. This project answers how to get the *original 1997
game* onto PC, running from its reconstructed source.
## Requirements
@@ -193,7 +188,9 @@ big-endian (`.z64`) format, matching one of:
| PAL (EU) | `pal-final` | `ge007.pal-final.z64` | `167c3c433dec1f1eb921736f7d53fac8cb45ee31` |
| NTSC-J (JP) | `jpn-final` | `ge007.jpn-final.z64` | `2a5dade32f7fad6c73c659d2026994632c1b3174` |
US is the recommended and best-tested version.
This release supports the US (NTSC-U) version; PAL and JP ROMs are
recognised by region but not yet supported (on the roadmap, [issue
#85](/jkdansereau/goldeneye-pc-port/issues/85)).
The port also relies on the decompilation's asset-extraction step, which pulls
the level, model, texture and music data out of your ROM at build time. That
@@ -219,7 +216,7 @@ git clone https://github.com/jkdansereau/goldeneye-pc-port.git
cd goldeneye-pc-port
# 1. extract assets from your ROM (see docs/building.md)
# 2. build the port
./build-pc.sh ntsc-final # or pal-final / jpn-final
./build-pc.sh ntsc-final # NTSC-U; PAL/JP engine builds compile, but their asset sidecars are not yet producible (issue #85)
```
### Linux
@@ -314,8 +311,8 @@ Key docs are also published as a site:
| [`docs/internals.md`](docs/internals.md) | Architecture, the RSP-emulation approach, GE-vs-PD engine differences, the phased plan. |
| [`docs/porting-notes.md`](docs/porting-notes.md) | The recurring N64→PC bug classes hit during the port, with fixes. |
| [`docs/dev/agentic-development.md`](docs/dev/agentic-development.md) | The research angle: the two-agent setup, timeline, handoff workflow, and an assessment of what did and didn't work. |
| [`docs/dev-process.md`](docs/dev-process.md) | The investigation workflow in detail — budgets, file partitioning, the finding-log discipline. |
| [`docs/dev/`](docs/dev/) | The raw engineering record: the full finding log, per-level status, graphics backlog, playtest matrices, and [`docs/dev/game-behavior-reference.md`](docs/dev/game-behavior-reference.md) (a secondary-sourced playtest reference for how the retail game is meant to behave — repo-only, code is ground truth). |
| [`docs/dev-process.md`](docs/dev-process.md) | The investigation workflow in detail: budgets, file partitioning, the finding-log discipline. |
| [`docs/dev/`](docs/dev/) | The raw engineering record: the full finding log, per-level status, graphics backlog, playtest matrices, and [`docs/dev/game-behavior-reference.md`](docs/dev/game-behavior-reference.md) (a secondary-sourced playtest reference for how the retail game is meant to behave; repo-only, code is ground truth). |
| [`docs/SetupGuide.md`](docs/SetupGuide.md), [`docs/StyleGuide.md`](docs/StyleGuide.md) | Inherited from the decompilation this repo forks. |
## Credits
@@ -324,30 +321,30 @@ This port is a thin layer on a large amount of other people's work.
**Prior work it is built on**
- The [GoldenEye 007 decompilation](https://github.com/n64decomp/007) — years of
- The [GoldenEye 007 decompilation](https://github.com/n64decomp/007), years of
effort by Larry Ficken ("kholdfuzion") and the project's contributors; plus
zoinkity's GoldenEye documentation, which the decomp started from. This port
is a fork of that repository.
- The [Perfect Dark PC port](https://github.com/fgsfdsfgs/perfect_dark)
(Ryan Dwyer and contributors) — the reference architecture for this port and
(Ryan Dwyer and contributors), the reference architecture for this port and
the source of the `fast3d` software RSP.
- The [Perfect Dark decompilation](https://github.com/n64decomp/perfect_dark) —
- The [Perfect Dark decompilation](https://github.com/n64decomp/perfect_dark),
the sibling decomp the PD port is built on.
- **Carnivorous** — author of the *Mouse Injector* input plugin for 1964 (the
- **Carnivorous**: author of the *Mouse Injector* input plugin for 1964 (the
"GEPD Edition" bundle). Its mouse-aim behaviour for GoldenEye/Perfect Dark is
what our in-game GEPD-style aim mode is modelled on; the implementation here
what the in-game GEPD-style aim mode is modelled on; the implementation here
is an independent reimplementation of that behaviour, not derived code.
Thanks also to **Rice** and **schibo** of the 1964 team for the emulator it
shipped with.
**Vendored / adapted code**
- `port/fast3d/` — the software RSP, adapted from the PD port. It originates
- `port/fast3d/`: the software RSP, adapted from the PD port. It originates
with the [Ship of Harkinian](https://github.com/HarbourMasters) /
libultraship fast3d (© Emill, MaikelChan; MIT — see `port/fast3d/LICENSE.txt`),
libultraship fast3d (© Emill, MaikelChan; MIT, see `port/fast3d/LICENSE.txt`),
which itself descends from
[sm64-port](https://github.com/sm64-port/sm64-port)'s fast3d and audio mixer.
- `port/fast3d/glad/` — OpenGL loader generated by
- `port/fast3d/glad/`: OpenGL loader generated by
[glad](https://github.com/Dav1dde/glad) (David Herberth, MIT).
- The decompilation toolchain: [`ido-static-recomp`](https://github.com/decompals/ido-static-recomp)
(Emill / decompals), [`qemu-irix`](https://github.com/n64decomp/qemu-irix) and
@@ -357,7 +354,7 @@ This port is a thin layer on a large amount of other people's work.
**Methodology**
- Chris Lewis, [*"Decompiling a Nintendo 64 Game in 84 Days"*](https://blog.chrislewis.au/decompiling-a-nintendo-64-game-in-84-days/) (the Snowboard
Kids decompilation write-up) — the agent-workflow practices in
Kids decompilation write-up), the agent-workflow practices in
[`docs/dev-process.md`](docs/dev-process.md) are adapted from it.
**Tools and models used to develop the port**
@@ -367,7 +364,7 @@ This port is a thin layer on a large amount of other people's work.
`UD-Q4_K_XL` quant;
[Unsloth](https://unsloth.ai) (the GGUF quantisation and Unsloth Desktop,
used as the local model server).
- [pi](https://pi.dev/) — the local coding-agent harness.
- [pi](https://pi.dev/): the local coding-agent harness.
- [Claude / Claude Code](https://claude.com/claude-code) (Anthropic).
## Legal
@@ -376,7 +373,7 @@ This is a non-commercial fan preservation/research project, in the same
category as the many other N64 decompilation and native-port repositories on
GitHub. It follows the same conventions they do:
- **No ROM and no game assets are distributed** — not in this repository and
- **No ROM and no game assets are distributed**: not in this repository and
not in any release. Textures, audio, models, level data and in-game text are
extracted from a ROM *you already own*, on *your* machine, at build time.
- The repository is a fork of the public
@@ -385,7 +382,7 @@ GitHub. It follows the same conventions they do:
- No official logos, box art, or marketing assets are used. "GoldenEye 007",
"007", "James Bond" and related marks belong to their respective owners
(Nintendo, Microsoft/Rare, MGM, Danjaq, EON Productions).
- Pre-built binaries published under [Releases](../../releases) contain
- Pre-built binaries published under [Releases](/jkdansereau/goldeneye-pc-port/releases) contain
only the engine (the `port/` layer plus the compiled decompilation, with no
game data of any kind), bundled with permissively-licensed runtime libraries
(SDL2, zlib, the MinGW runtime; their licenses travel in the download). Any
+19 -13
View File
@@ -7,13 +7,13 @@ description: Full build and asset-extraction guide for the GoldenEye 007 PC port
Stages:
1. **Extract assets from your ROM** (§2) — a one-time step using the
1. **Extract assets from your ROM** (§2): a one-time step using the
decompilation's own toolchain to pull levels, models, textures, fonts and
music into `assets/`. *(Only needed to regenerate the committed data files;
a plain `git clone` already has what the PC build compiles.)*
2. **Build the port** (§3) — a CMake build compiling the game sources plus the
2. **Build the port** (§3): a CMake build compiling the game sources plus the
`port/` layer into a native executable. Needs no ROM.
3. **Generate the PC asset sidecars** (§4) — two pure-Python converters turn
3. **Generate the PC asset sidecars** (§4): two pure-Python converters turn
ROM model / stage data into the PC-layout `data/pcmodels-*` / `data/pccg-*`
files the port loads at runtime. **Required to run.**
@@ -27,10 +27,11 @@ for accepted versions and hashes.
### Port build
> **Only the Windows (MSYS2 MINGW64) path is tested.** The Debian/Ubuntu and
> macOS columns below are best-effort guidance — the port has never been built
> or run on Linux or macOS. Expect to fix build breaks yourself on those
> platforms.
> **The Windows (MSYS2 MINGW64) path is the primary one.** The Linux build is
> compiled by CI on every push and ships in the release bundle (also
> playtested on Steam Deck hardware); the macOS column is best-effort
> guidance and has never been built or run there. Expect to fix build breaks
> yourself on untested platforms.
| Need | Windows (MSYS2 MINGW64) | Debian/Ubuntu | macOS (Homebrew) |
|------|------------------------|---------------|------------------|
@@ -45,10 +46,10 @@ for accepted versions and hashes.
The extraction scripts need `binutils-mips-linux-gnu` (or an equivalent MIPS
binutils), `make`, `git`, and `python3`. They build a small host-compiled
`tools/extractor` and slice blobs straight out of the ROM — **no IDO / IRIX
`tools/extractor` and slice blobs straight out of the ROM; **no IDO / IRIX
toolchain is involved in extraction or in the PC build.** (The IDO toolchain is
only needed to build the N64 ROM itself, and its proprietary SGI binaries are
not distributed here — see [`SetupGuide.md`](https://github.com/jkdansereau/goldeneye-pc-port/blob/main/docs/SetupGuide.md) "Recompile IDO".)
not distributed here; see [`SetupGuide.md`](https://github.com/jkdansereau/goldeneye-pc-port/blob/main/docs/SetupGuide.md) "Recompile IDO".)
On Windows this is easiest under WSL or a Linux VM. Full details and
alternatives (Docker) are in [`SetupGuide.md`](https://github.com/jkdansereau/goldeneye-pc-port/blob/main/docs/SetupGuide.md).
@@ -108,7 +109,7 @@ builds are named `ge007.pal-final.x86_64` / `ge007.jpn-final.x86_64`.
## 4. Generate the PC asset sidecars (required to run)
The port does **not** read model geometry, stage bg/stan data, or per-level
setup data from the raw ROM at runtime — it reads them from PC-layout *sidecar*
setup data from the raw ROM at runtime; it reads them from PC-layout *sidecar*
files under `data/`, produced offline by three converters. **Without them the
game shows the intro logos and then crashes** in
`modelPromoteNodeOffsetsToPointers` (finding D179) or on the first level load
@@ -130,6 +131,9 @@ python3 tools_pc/d69_emit.py ntsc-final # -> data/pccg-ntsc-final/{pccg
python3 tools_pc/d88_emit.py ntsc-final --regen # appends the 21 per-level Usetup*Z stage-setup files -> ~3.6 MB
```
**PAL / JP note:** sidecar generation for these regions is currently broken at
the source-data level (finding D258); use an NTSC-U ROM until issue #85 lands.
These are **pure-stdlib Python 3** (no MIPS toolchain, independent of the
step-2 asset extraction) and read only the ROM plus files already committed to
the repo (`scripts/filelist.u.csv`, `assets/obseg/file_resource_table.inc.c`,
@@ -138,10 +142,12 @@ deterministic function of the ROM. Re-run after any change to `d43_emit.py` /
`d69_emit.py` / `d88_emit.py` or the model/bg converters (`d43_*`, `d69_*`,
`d88_propdefs.py`).
> The release bundle ships `prepare-assets/prepare-assets.py`, which runs all
> three passes against your ROM automatically — see the bundled `README.md`.
> The release bundle ships the same converter frozen as
> `prepare-assets/ge007-convert`; the game spawns it on first launch when the
> sidecars are missing, so end users never run it by hand. See the bundled
> `README.md`.
> `data/pcmodels-*/` and `data/pccg-*/` are gitignored ROM-derived game data —
> `data/pcmodels-*/` and `data/pccg-*/` are gitignored ROM-derived game data;
> never commit or redistribute them.
---
+23 -23
View File
@@ -1,37 +1,37 @@
---
title: Development Process
description: The investigation workflow behind the port — task budgets, file partitioning, and the finding-log discipline used across sessions and agents.
description: The investigation workflow behind the port; task budgets, file partitioning, and the finding-log discipline used across sessions and agents.
---
# How this port is developed
Most of this port's work is not writing code — it is **diagnosis**: figuring
Most of this port's work is not writing code; it is **diagnosis**: figuring
out which N64 hardware or ABI behavior a piece of unmodified game code is
silently relying on, and satisfying it in the `port/` layer without touching
the game's logic. A lot of that diagnosis is done with LLM coding agents, and
the workflow below is what makes that productive rather than chaotic.
For the project context — the two-model split, the timeline, and an honest
assessment of what did and did not work — see
For the project context (the two-model split, the timeline, and an honest
assessment of what did and did not work), see
[`dev/agentic-development.md`](dev/agentic-development.md).
It is adapted from Chris Lewis's write-up
[*"Decompiling a Nintendo 64 Game in 84 Days"*](https://blog.chrislewis.au/decompiling-a-nintendo-64-game-in-84-days/)
(Snowboard Kids, 2026), an AI-assisted decompilation that ran several times
faster than its predecessor. That project bit-matches compiler output;
this one matches runtime behavior, so the mechanics differ — but the
this one matches runtime behavior, so the mechanics differ; but the
project-structure lessons carry over directly.
## 1. Every investigation task gets a visible budget
An open-ended tool — for them the permuter, for us "rebuild and run the game
and stare at a frame dump" — wrecks throughput when an agent will grind it
An open-ended tool; for them the permuter, for us "rebuild and run the game
and stare at a frame dump"; wrecks throughput when an agent will grind it
indefinitely. Giving the agent a **deadline it can see** lets it trade
tool-time against thinking and decide when to give up.
So every investigation brief states:
- a **budget** — "≤ N build → run → inspect cycles" or "~M minutes"; and
- a **budget**; "≤ N build → run → inspect cycles" or "~M minutes"; and
- the **fallback on expiry**: stop, revert any temporary probes, and write up
what was found with an explicit confidence rating. A good write-up of a
half-solved bug is a deliverable, not a failure.
@@ -45,7 +45,7 @@ more room.
Lewis's agents recorded generalisable IDO quirks in a learnings file; later
agents read it and did better. Our equivalent is
[`porting-notes.md`](porting-notes.md) — the recurring N64→PC bug classes,
[`porting-notes.md`](porting-notes.md); the recurring N64→PC bug classes,
each entry a terse index into the full
[`dev/findings.md`](https://github.com/jkdansereau/goldeneye-pc-port/blob/main/docs/dev/findings.md)
log. Every investigation brief links it, and every investigation ends by
@@ -54,8 +54,8 @@ appending any new generalisable quirk.
The classes it currently tracks:
- pointer-width struct growth (32→64) in ROM-serialized or pun-allocated
structs — the dominant class;
- 16-byte host `Gfx`/`Vtx` vs 8-byte N64 — reservation and copy sizing;
structs; the dominant class;
- 16-byte host `Gfx`/`Vtx` vs 8-byte N64; reservation and copy sizing;
- big-endian rodata read on a little-endian host: `f32` word-pairs, header
offset tables, packed bitfields;
- N64 hardware idioms the software RSP does not emulate (fill-rect Z clear,
@@ -71,7 +71,7 @@ Lewis ran multiple git worktrees and found the real cost was
- **Partition tracks by the files they will touch**, so patches never collide.
A task that can't be cleanly file-partitioned shouldn't be parallelised.
- Each agent reverts its own temporary probes before reporting, leaving only
committed, env-gated, capped diagnostics — and never touches another track's
committed, env-gated, capped diagnostics; and never touches another track's
uncommitted edits.
- One integrator merges each track with its write-up, then the next round
starts from a clean tree. Investigation branches are not allowed to drift.
@@ -85,7 +85,7 @@ Before dispatching an investigation agent:
- capture a baseline frame dump;
- grep the finding log for a prior instance of the same bug class;
- check the [Perfect Dark port](https://github.com/fgsfdsfgs/perfect_dark) for
the analogous code — same engine family.
the analogous code; same engine family.
Then hand the agent the *findings*, not just the problem.
@@ -94,12 +94,12 @@ Then hand the agent the *findings*, not just the problem.
- **The match-percentage loop.** This port doesn't bit-match. "Done" is: no
fault, and visually correct against N64 reference footage.
- **"Understanding the function is the easy part."** True when decompiling;
inverted here — the hard part is identifying the implicit hardware/ABI
inverted here; the hard part is identifying the implicit hardware/ABI
contract the already-readable C depends on.
## 6. Keep PR/git-history noise low
A session produces a lot of small, independently-verifiable units of work —
A session produces a lot of small, independently-verifiable units of work;
one Dxx row, one docs pass, one mechanical fix. Left unmanaged that turns
into a pile of small open PRs that's harder to review than the work
justifies. Rules:
@@ -107,31 +107,31 @@ justifies. Rules:
- **Squash-merge single-purpose and docs-only PRs.** The repo has squash
merge enabled; use it (`gh pr merge --squash --delete-branch`) for anything
whose in-branch commit history (iteration, probe-add, probe-strip) isn't
itself useful to keep — which is most PRs. Reserve a plain merge commit for
itself useful to keep; which is most PRs. Reserve a plain merge commit for
a PR whose individual commits are each a distinct, reviewable unit someone
might want to `git revert` independently (e.g. this session's PR #50: a
fix commit + a separate analysis-only commit).
- **Batch same-session, same-flavor docs updates into one PR/branch**
instead of opening a new PR per finding row. A runtime re-check that
updates one `findings.md` row (like #48) doesn't need its own PR if
another docs-only branch is already open in the same session — fold it in.
another docs-only branch is already open in the same session; fold it in.
Only split into separate PRs when the pieces have genuinely different
review/merge timing (e.g. one needs a human playtest, the other doesn't).
- **A branch takes only the change it's named for.** Don't let unrelated
housekeeping (a stray gitignore fix, a config tweak) ride along on an
active feature/fix branch just because it's the one checked out — cut a
active feature/fix branch just because it's the one checked out; cut a
separate branch, even for a one-line change.
- **Stacked PRs declare the dependency in the title/body** ("step 2 of N,
step 1 is #N") and get rebased/merged in order promptly — don't let a
step 1 is #N") and get rebased/merged in order promptly; don't let a
later step sit open so long the earlier step's content drifts under it.
- **Triage the open-PR list at least once a session**, ordered by
time-to-close (docs-only and non-draft first, human-playtest-gated last).
A PR idle long enough that `main` has moved past the finding rows it
touches is **stale, not just old** — check for real textual conflict
touches is **stale, not just old**; check for real textual conflict
(`git merge-tree`), not just calendar age. If `main` already has more
current information than the PR (a bug the PR still lists `OPEN` that's
since been fixed and verified), **close it rather than force a merge or
spend a cycle rebasing it** — re-derive only whatever part of its content
spend a cycle rebasing it**; re-derive only whatever part of its content
is still true as a fresh, small PR against current `main`. Merging stale
content back over newer information is a regression, not a save.
@@ -141,11 +141,11 @@ justifies. Rules:
TASK: <one bug, one subsystem>.
READ FIRST: docs/porting-notes.md; docs/dev/findings.md <specific Dxx entries>.
FILES YOU MAY TOUCH: <disjoint from any other in-flight work>.
KNOWN-GOOD / RULED OUT: <list — do not re-investigate>.
KNOWN-GOOD / RULED OUT: <list; do not re-investigate>.
PRE-FLIGHT ATTACHED: <probe output, baseline capture, PD-port pointer>.
BUDGET: <N build->run cycles / ~M min>. On expiry: revert probes, write up with confidence.
CONSTRAINTS: no game-logic changes; ABI/layout/format only; #ifdef PORT; documented in the finding log.
VERIFY: <the exact tools_pc/verify.sh (or probe) invocation that proves this done — or, if runtime verification is impossible in this environment, say so and name what a human must run>.
VERIFY: <the exact tools_pc/verify.sh (or probe) invocation that proves this done; or, if runtime verification is impossible in this environment, say so and name what a human must run>.
REPORT: (a) root cause + file:line evidence (b) fix diff, or why not
(c) probes left in tree (d) confidence.
Append any generalisable quirk to docs/porting-notes.md.
+26 -26
View File
@@ -1,6 +1,6 @@
---
title: Agentic Development
description: A case study in two AI coding agents porting a Nintendo 64 game to PC — the setup, timeline, handoff workflow, and an honest assessment of what worked.
description: A case study in two AI coding agents porting a Nintendo 64 game to PC; the setup, timeline, handoff workflow, and an honest assessment of what worked.
---
# Agentic development: two AI coding agents porting GoldenEye 007
@@ -16,7 +16,7 @@ what did and didn't work.*
- [Why this project exists](#why-this-project-exists)
- [The setup](#the-setup)
- [Timeline](#timeline)
- [By the numbers](#by-the-numbers) — [Commit velocity](#commit-velocity) · [Who did what](#who-did-what)
- [By the numbers](#by-the-numbers); [Commit velocity](#commit-velocity) · [Who did what](#who-did-what)
- [The handoff workflow](#the-handoff-workflow)
- [Assessment](#assessment)
@@ -24,7 +24,7 @@ what did and didn't work.*
The playable port is real, but it is not the primary deliverable. The goal was
to **test how well coding agents hold up on a large, unfamiliar, low-level
codebase** — one with none of the properties that make web-app work easy for
codebase**; one with none of the properties that make web-app work easy for
an LLM:
- ~230 translation units of decompiled Nintendo 64 game C, compiled
@@ -39,7 +39,7 @@ an LLM:
Concretely it set out to validate a **two-agent arrangement**: a
locally-hosted open-weight model doing the bulk of the work on a single
consumer GPU, a hosted frontier model brought in for a collaborative phase,
and — the part that turned out most interesting — the two **handing work back
and, the part that turned out most interesting, the two **handing work back
and forth** through shared written artifacts, directed by one human.
## The setup
@@ -47,17 +47,17 @@ and forth** through shared written artifacts, directed by one human.
| | |
|---|---|
| Local agent | `unsloth/Qwen3.8-27B-GGUF:UD-Q4_K_XL` on a single **NVIDIA RTX 5090**, driven mainly through the **[pi](https://pi.dev/)** coding agent. Unsloth Desktop (Unsloth's local model runtime, which can drive agents such as Claude Code) was also trialed but not used significantly. |
| Hosted agent | **Claude**, via **Claude Code**, on a Claude Pro subscription — mostly **Sonnet 5**, with **Opus 5** used as an escalation tier for the hardest problems and whenever there was subscription budget to spend on it |
| Hosted agent | **Claude**, via **Claude Code**, on a Claude Pro subscription; mostly **Sonnet 5**, with **Opus 5** used as an escalation tier for the hardest problems and whenever there was subscription budget to spend on it |
| Human | one person: direction, work partitioning, integration, and every build / playtest / frame-capture the agents could not run |
| Base | fork of the [GoldenEye 007 decompilation](https://github.com/n64decomp/007) (years of prior work by Larry Ficken ("kholdfuzion") and contributors) |
| Reused | the [Perfect Dark PC port](https://github.com/fgsfdsfgs/perfect_dark)'s `fast3d` software RSP — same Rare engine family |
| Reused | the [Perfect Dark PC port](https://github.com/fgsfdsfgs/perfect_dark)'s `fast3d` software RSP; same Rare engine family |
The port is the GoldenEye-specific porting work **on top of** those two
existing bodies of work; it is not a from-scratch reimplementation of either.
In practice the models formed a **three-tier escalation**: the local model
handled well-scoped work, Sonnet 5 took what it stalled on, and Opus 5 was
reserved for the bugs that needed the most reasoning held at once — the same
reserved for the bugs that needed the most reasoning held at once; the same
"escalate when stuck" move applied at every level.
## Timeline
@@ -68,7 +68,7 @@ All dates from this repository's own commit history (August 2026).
gantt
dateFormat YYYY-MM-DD
axisFormat %b %d
title GoldenEye 007 PC port — from fork to playable front end
title GoldenEye 007 PC port; from fork to playable front end
section Local model - Qwen 3.8 via pi
Fork + PC-port scaffolding :m1, 2026-08-16, 1d
Full compile + link (~230 TUs) :m2, 2026-08-20, 1d
@@ -90,7 +90,7 @@ gantt
- **Day 4** (20 Aug): the entire ~230-TU game + libultra set compiles and
links as a host binary.
- **Day 6** (22 Aug): first real frames render.
- **Day 8** (24 Aug): the whole intro sequence renders — logos, gun-barrel,
- **Day 8** (24 Aug): the whole intro sequence renders; logos, gun-barrel,
cast roll.
- **Day 11** (27 Aug): second agent joins.
- **Day 13** (29 Aug): **all 21 solo missions load, render, and survive an
@@ -100,7 +100,7 @@ gantt
So roughly **two weeks**, one person part-time, to take a decompilation from
"builds an N64 ROM" to "boots on desktop, renders every solo level, playable
through the front end into the early game" — with audio and a set of cosmetic
through the front end into the early game"; with audio and a set of cosmetic
issues still outstanding.
## By the numbers
@@ -139,7 +139,7 @@ pie showData title "Commits by agent (raw count)"
"Local model (Qwen 3.8 / pi)" : 62
```
(Phase A — the first 26 commits, to 24 Aug — was entirely the local model,
(Phase A, the first 26 commits, to 24 Aug, was entirely the local model,
solo; from 27 Aug on the two agents worked in parallel.)
| Milestone / workstream | Primary agent | Weight |
@@ -150,20 +150,20 @@ solo; from 27 Aug on the two agents worked in parallel.)
| Offline asset-conversion architecture + first converters (`tools_pc/`) | local model | large |
| Intro rendering (logos → gun-barrel → cast) | local model | medium |
| Stage load unblocked (`D69`–`D87`) | Claude | medium |
| 21-level crash sweep — ~12 crash classes root-caused (`D88`–`D169`) | Claude | large |
| 21-level crash sweep; ~12 crash classes root-caused (`D88`–`D169`) | Claude | large |
| SDL input layer (keyboard / mouse / gamepad, mouse-look) | Claude | medium |
| Front-end flow (menu → briefing → start), EEPROM saves | Claude | medium |
| Parallel struct-layout / converter static audits | local model | medium |
| Continuing tasks after Claude hit a usage limit | local model | small |
| The hardest structural bugs (matrix handedness, format specs) | Claude | — |
| Every build, playtest, frame capture, integration, and direction | human | — |
| The hardest structural bugs (matrix handedness, format specs) | Claude | n/a |
| Every build, playtest, frame capture, integration, and direction | human | n/a |
**Estimated effort split.** The raw commit count above (~28% local / ~72%
Claude) undercounts the local model: Phase A landed the build system and boot
chain in relatively few, large commits, and the local model kept contributing
~15–20% of Phase B in parallel. Weighting by milestone difficulty rather than
raw commits — the foundation is a heavier third of the project than its commit
share suggests — the developer's estimate is roughly:
raw commits; the foundation is a heavier third of the project than its commit
share suggests; the developer's estimate is roughly:
```mermaid
pie showData title "Agent effort, milestone-weighted"
@@ -202,28 +202,28 @@ flowchart LR
Both agents worked against the **same three written artifacts**, which is what
let them substitute for each other:
1. **`HANDOFF.md`** — the current state, the immediate next task, and the
1. **`HANDOFF.md`**; the current state, the immediate next task, and the
environment gotchas. Originally a session-to-session note for one agent, it
became the **interface between the two agents**: when Claude reached a
usage limit mid-problem, the local model picked the task up from the
HANDOFF state and continued; when the local model hit a bug that needed
deeper structural reasoning, it wrote up where it was and Claude took over.
2. **`findings.md`** — the chronological finding log. 162 numbered entries,
2. **`findings.md`**; the chronological finding log. 162 numbered entries,
each a root cause with `file:line` evidence and the fix. New agents (either
model) are pointed at the relevant entries before they start.
3. **`porting-notes.md`** — the append-only "recurring bug classes" file. The
3. **`porting-notes.md`**; the append-only "recurring bug classes" file. The
single highest-leverage artifact: it stopped both models from
re-deriving the same class of N64→PC bug over and over.
Around these, the working rules (full detail in
[`../dev-process.md`](../dev-process.md)):
- **file-partitioned tasks** — each agent's task scoped to a disjoint set of
- **file-partitioned tasks**; each agent's task scoped to a disjoint set of
files so patches never collided;
- **visible budgets** — every investigation task carried an explicit
- **visible budgets**; every investigation task carried an explicit
"N build→run cycles" limit and a defined fallback (revert probes, write up
with a confidence rating);
- **the human owns verification** — building, running the game, capturing a
- **the human owns verification**; building, running the game, capturing a
frame, and judging it against N64 reference footage was never delegated.
## Assessment
@@ -232,7 +232,7 @@ Honest notes, for anyone weighing whether this transfers.
**Worked well**
- The **local model carried the groundwork phase** — build system, boot
- The **local model carried the groundwork phase**; build system, boot
chain, OS shims, and the offline-converter architecture. None of it was
rewritten later. A 27B open model on one consumer GPU was genuinely productive
on this.
@@ -241,14 +241,14 @@ Honest notes, for anyone weighing whether this transfers.
because the accumulated notes were good. This is also what made the two
models interchangeable on a given task.
- **Handoff on limit** turned Claude's usage cap from a hard stop into a
slowdown — the local model kept the problem moving.
slowdown; the local model kept the problem moving.
- Bounded behavioural bugs (a truncated pointer, a byte-swap off by one) are a
good fit for an agent given a tight loop and a reference to diff against.
**Worked poorly / needed the human**
- **Anything requiring the running game.** Build, playtest, capture a frame,
decide whether it looks right — that loop was the human's job throughout,
decide whether it looks right; that loop was the human's job throughout,
and it was the bottleneck.
- **Non-deterministic bugs.** Frame-timing stalls and concurrent-build
flakiness repeatedly fooled agents into "fixing" regressions that were not
@@ -258,7 +258,7 @@ Honest notes, for anyone weighing whether this transfers.
rather than a fix, even with the budget raised.
- **The capability gap is a gradient, not a wall.** The local model was strong
on well-scoped work and weaker when a bug needed several interacting facts
held at once — those went to Sonnet 5, and the few that stalled Sonnet went
held at once; those went to Sonnet 5, and the few that stalled Sonnet went
to Opus 5. Each tier earned its place on the problems the tier below it
couldn't close.
+50 -47
View File
@@ -3,7 +3,7 @@ title: GoldenEye 007 PC Port
description: >-
A native PC port of the original Nintendo 64 GoldenEye 007, built from its
decompiled source with a software RSP. v0.2.0 is out for Windows
and Linux (including Steam Deck) — download it, drop in your own ROM, and
and Linux (including Steam Deck): download it, drop in your own ROM, and
play; or dig into the code and the engineering record behind it.
---
@@ -11,16 +11,16 @@ description: >-
A native PC port of the original 1997 Nintendo 64 _GoldenEye 007_, compiled
from the game's [decompiled source](https://github.com/n64decomp/007) with the
N64's graphics coprocessor (RSP) running in software — the same architecture
N64's graphics coprocessor (RSP) running in software, the same architecture
as the [Perfect Dark PC port](https://github.com/fgsfdsfgs/perfect_dark), the
same Rare "Indy" engine family, one hardware generation apart.
**Status: v0.2.0** — to our knowledge, the first open-source port of the
original N64 game to ship as a public release. The full single-player
campaign runs at a steady 60 fps with no known crashes, and audio (music +
SFX) plays throughout.
Known rough edges — cutscenes still glitch, a few music tracks sound wrong, a
handful of cosmetic rendering defects remain — are listed plainly under
**Status: v0.2.0.** The full single-player campaign runs at a steady 60 fps
and is completable end to end; all 21 missions load and run clean on Windows
and Linux (one intermittent Steam Deck crash remains, listed below), and
audio (music + SFX) plays throughout. The known
rough edges (cutscenes that still glitch, a few music tracks that sound
wrong, a handful of cosmetic rendering defects) are listed plainly under
[Honest status](#honest-status).
<p align="center">
@@ -34,13 +34,15 @@ handful of cosmetic rendering defects remain — are listed plainly under
| Platform | Bundle | Notes |
|---|---|---|
| **Windows** (x86_64) | [win64.zip](https://github.com/jkdansereau/goldeneye-pc-port/releases) | Engine + runtime DLLs + the one-time asset tool. |
| **Linux** (x86_64) / **Steam Deck** | [linux tarball](https://github.com/jkdansereau/goldeneye-pc-port/releases) | SDL2 is bundled — it runs as-is on any distro, and sideloads onto a Deck with nothing installed. |
| **Linux** (x86_64) / **Steam Deck** | [linux tarball](https://github.com/jkdansereau/goldeneye-pc-port/releases) | SDL2 is bundled, so it runs as-is on any distro, and sideloads onto a Deck with nothing installed. |
**Bring your own ROM.** Both bundles contain no ROM and no game assets — you
**Bring your own ROM.** Both bundles contain no ROM and no game assets: you
supply your own GoldenEye 007 N64 ROM (the
[Requirements table](https://github.com/jkdansereau/goldeneye-pc-port#requirements)
has the three region filenames and SHA-1s). Then: unpack, drop the ROM in
`data/`, run `prepare-assets` once, launch. The full four steps are in the
has the region filenames and SHA-1s). This release supports the NTSC-U (US)
ROM; PAL and JP are on the roadmap. Then: unpack, drop the ROM in `data/`,
and launch; the first run generates the derived assets automatically (no
Python or other tooling needed). The full steps are in the
[Quick start](https://github.com/jkdansereau/goldeneye-pc-port#quick-start);
pre-built releases are legal to distribute precisely because they're useless
without a ROM you already own.
@@ -53,83 +55,83 @@ without a ROM you already own.
</p>
<details>
<summary><strong>Full playtest gallery</strong> — 19 in-engine captures from the v0.2.0-pre Windows playtest, across the campaign</summary>
<summary><strong>Full playtest gallery</strong>: 19 in-engine captures from the v0.2.0 Windows playtest, across the campaign</summary>
<p align="center">
<div style="width:32%;text-align:center;margin:4px">
<img src="img/shots/shot-01.jpg" width="100%" alt="In-engine — Dam (v0.2.0-pre)">
<img src="img/shots/shot-01.jpg" width="100%" alt="In-engine: Dam (v0.2.0)">
<div><small>Dam</small></div>
</div>
<div style="width:32%;text-align:center;margin:4px">
<img src="img/shots/shot-02.jpg" width="100%" alt="In-engine — Facility (v0.2.0-pre)">
<img src="img/shots/shot-02.jpg" width="100%" alt="In-engine: Facility (v0.2.0)">
<div><small>Facility</small></div>
</div>
<div style="width:32%;text-align:center;margin:4px">
<img src="img/shots/shot-03.jpg" width="100%" alt="In-engine — Runway (v0.2.0-pre)">
<img src="img/shots/shot-03.jpg" width="100%" alt="In-engine: Runway (v0.2.0)">
<div><small>Runway</small></div>
</div>
<div style="width:32%;text-align:center;margin:4px">
<img src="img/shots/shot-04.jpg" width="100%" alt="In-engine — Surface (v0.2.0-pre)">
<img src="img/shots/shot-04.jpg" width="100%" alt="In-engine: Surface (v0.2.0)">
<div><small>Surface</small></div>
</div>
<div style="width:32%;text-align:center;margin:4px">
<img src="img/shots/shot-05.jpg" width="100%" alt="In-engine — Surface (v0.2.0-pre)">
<img src="img/shots/shot-05.jpg" width="100%" alt="In-engine: Surface (v0.2.0)">
<div><small>Surface</small></div>
</div>
<div style="width:32%;text-align:center;margin:4px">
<img src="img/shots/shot-06.jpg" width="100%" alt="In-engine — Bunker 1 (v0.2.0-pre)">
<img src="img/shots/shot-06.jpg" width="100%" alt="In-engine: Bunker 1 (v0.2.0)">
<div><small>Bunker 1</small></div>
</div>
<div style="width:32%;text-align:center;margin:4px">
<img src="img/shots/shot-07.jpg" width="100%" alt="In-engine — Silo (v0.2.0-pre)">
<img src="img/shots/shot-07.jpg" width="100%" alt="In-engine: Silo (v0.2.0)">
<div><small>Silo</small></div>
</div>
<div style="width:32%;text-align:center;margin:4px">
<img src="img/shots/shot-09.jpg" width="100%" alt="In-engine — Frigate (v0.2.0-pre)">
<img src="img/shots/shot-09.jpg" width="100%" alt="In-engine: Frigate (v0.2.0)">
<div><small>Frigate</small></div>
</div>
<div style="width:32%;text-align:center;margin:4px">
<img src="img/shots/shot-10.jpg" width="100%" alt="In-engine — Frigate (v0.2.0-pre)">
<img src="img/shots/shot-10.jpg" width="100%" alt="In-engine: Frigate (v0.2.0)">
<div><small>Frigate</small></div>
</div>
<div style="width:32%;text-align:center;margin:4px">
<img src="img/shots/shot-11.jpg" width="100%" alt="In-engine — Surface 2 (v0.2.0-pre)">
<img src="img/shots/shot-11.jpg" width="100%" alt="In-engine: Surface 2 (v0.2.0)">
<div><small>Surface 2</small></div>
</div>
<div style="width:32%;text-align:center;margin:4px">
<img src="img/shots/shot-13.jpg" width="100%" alt="In-engine — Bunker 2 (v0.2.0-pre)">
<img src="img/shots/shot-13.jpg" width="100%" alt="In-engine: Bunker 2 (v0.2.0)">
<div><small>Bunker 2</small></div>
</div>
<div style="width:32%;text-align:center;margin:4px">
<img src="img/shots/shot-16.jpg" width="100%" alt="In-engine — Statue (v0.2.0-pre)">
<img src="img/shots/shot-16.jpg" width="100%" alt="In-engine: Statue (v0.2.0)">
<div><small>Statue</small></div>
</div>
<div style="width:32%;text-align:center;margin:4px">
<img src="img/shots/shot-19.jpg" width="100%" alt="In-engine — Statue (v0.2.0-pre)">
<img src="img/shots/shot-19.jpg" width="100%" alt="In-engine: Statue (v0.2.0)">
<div><small>Statue</small></div>
</div>
<div style="width:32%;text-align:center;margin:4px">
<img src="img/shots/shot-20.jpg" width="100%" alt="In-engine — Archives (v0.2.0-pre)">
<img src="img/shots/shot-20.jpg" width="100%" alt="In-engine: Archives (v0.2.0)">
<div><small>Archives</small></div>
</div>
<div style="width:32%;text-align:center;margin:4px">
<img src="img/shots/shot-21.jpg" width="100%" alt="In-engine — Cradle (v0.2.0-pre)">
<img src="img/shots/shot-21.jpg" width="100%" alt="In-engine: Cradle (v0.2.0)">
<div><small>Cradle</small></div>
</div>
<div style="width:32%;text-align:center;margin:4px">
<img src="img/shots/shot-23.jpg" width="100%" alt="In-engine — Cradle (v0.2.0-pre)">
<img src="img/shots/shot-23.jpg" width="100%" alt="In-engine: Cradle (v0.2.0)">
<div><small>Cradle</small></div>
</div>
<div style="width:32%;text-align:center;margin:4px">
<img src="img/shots/shot-24.jpg" width="100%" alt="In-engine — Aztec (v0.2.0-pre)">
<img src="img/shots/shot-24.jpg" width="100%" alt="In-engine: Aztec (v0.2.0)">
<div><small>Aztec</small></div>
</div>
<div style="width:32%;text-align:center;margin:4px">
<img src="img/shots/shot-25.jpg" width="100%" alt="In-engine — Aztec (v0.2.0-pre)">
<img src="img/shots/shot-25.jpg" width="100%" alt="In-engine: Aztec (v0.2.0)">
<div><small>Aztec</small></div>
</div>
<div style="width:32%;text-align:center;margin:4px">
<img src="img/shots/shot-26.jpg" width="100%" alt="In-engine — Frigate (v0.2.0-pre)">
<img src="img/shots/shot-26.jpg" width="100%" alt="In-engine: Frigate (v0.2.0)">
<div><small>Frigate</small></div>
</div>
</p>
@@ -137,23 +139,23 @@ without a ROM you already own.
More captures may land here as playtesting continues.
## Play it — or take it apart
## Play it, or take it apart
- **Try it yourself** — grab a bundle above, bring your own ROM, and play the
- **Try it yourself**: grab a bundle above, bring your own ROM, and play the
campaign. It's an early cut for exactly this: if something breaks, an
[issue](https://github.com/jkdansereau/goldeneye-pc-port/issues) with what
you were doing is genuinely useful.
- **Read the code** — the game logic in `src/` is unmodified decompilation;
- **Read the code**: the game logic in `src/` is unmodified decompilation;
every hardware surface (video, audio, input, save storage, and the
software-RSP renderer) is shimmed in the MIT-licensed `port/` layer.
[Internals](internals.md) is the map; [Porting notes](porting-notes.md) is
the catalogue of N64→PC bug classes hit along the way — a good read even if
the catalogue of N64→PC bug classes hit along the way, a good read even if
you never touch the code.
- **Mod it** — the port layer, build system and `tools_pc/` helpers are MIT
- **Mod it**: the port layer, build system and `tools_pc/` helpers are MIT
licensed and yours to extend: new video options, input tweaks, your own
asset sidecar. [CONTRIBUTING](https://github.com/jkdansereau/goldeneye-pc-port/blob/main/CONTRIBUTING.md)
has the ground rules that keep it faithful to the original game.
- **The research angle** — this is also a case study in AI-agent collaboration
- **The research angle**: this is also a case study in AI-agent collaboration
on a large, low-level codebase: two coding agents (a local open-weight model
on a single RTX 5090, and Claude / Claude Code), driven by one person
part-time through ~230 translation units of unmodified big-endian MIPS game
@@ -162,20 +164,21 @@ More captures may land here as playtesting continues.
## How it works
The R4300 game code is compiled completely unmodified — the decompilation's
The R4300 game code is compiled completely unmodified; the decompilation's
control flow is ground truth. The N64's Reality Signal Processor, the graphics
coprocessor that builds and executes each frame's display list, is emulated in
software: the port interprets the GBI stream the game emits and translates it
to OpenGL, bypassing the RDP entirely. Everything else that would touch N64
hardware — video, audio, input, timers, save storage — is shimmed in a small
hardware (video, audio, input, timers, save storage) is shimmed in a small
dedicated layer, following the architecture of the Perfect Dark PC port from
the same Rare engine family. Full detail: [Internals](internals.md); the bug
catalogue: [Porting notes](porting-notes.md).
## Honest status
- **Cutscenes glitch frequently** — skipped beats, wrong camera, misplaced or
hovering actors. The most visible gap in this release.
- **Cutscenes still glitch, mostly with James Bond**: in scripted sequences
Bond is the one who gets misplaced, hovers, or spins; the other actors are
fine for the most part now. Still the most visible gap in this release.
- A few in-level music tracks sound wrong (wrong instruments, occasional garbling).
- Particle colours drift through a rainbow palette instead of holding grey/orange.
- Water levels show a moving seam; pixel strips at screen edges at non-integer
@@ -190,11 +193,11 @@ and the [finding log](https://github.com/jkdansereau/goldeneye-pc-port/tree/main
## Documentation
- [The two-agent development case study](dev/agentic-development.md) — goal, setup, timeline, the handoff workflow, and an honest assessment of what did and didn't work.
- [Development process](dev-process.md) — how work was scoped, partitioned, and budgeted across agents; the finding-log discipline.
- [Internals](internals.md) — architecture, the software RSP-emulation approach, GoldenEye-vs-Perfect-Dark engine differences, the phased plan.
- [Porting notes](porting-notes.md) — the recurring Nintendo 64 → PC bug classes hit during the port, with fixes.
- [Building](building.md) — full build and asset-extraction guide.
- [The two-agent development case study](dev/agentic-development.md): goal, setup, timeline, the handoff workflow, and an honest assessment of what did and didn't work.
- [Development process](dev-process.md): how work was scoped, partitioned, and budgeted across agents; the finding-log discipline.
- [Internals](internals.md): architecture, the software RSP-emulation approach, GoldenEye-vs-Perfect-Dark engine differences, the phased plan.
- [Porting notes](porting-notes.md): the recurring Nintendo 64 → PC bug classes hit during the port, with fixes.
- [Building](building.md): full build and asset-extraction guide.
---
+57 -57
View File
@@ -1,14 +1,14 @@
---
title: Internals
description: Architecture behind the PC port — the software RSP-emulation approach, GoldenEye-vs-Perfect-Dark engine differences, and the phased development plan.
description: Architecture behind the PC port; the software RSP-emulation approach, GoldenEye-vs-Perfect-Dark engine differences, and the phased development plan.
---
# GoldenEye 007 — PC Port: architecture & plan
# GoldenEye 007 PC Port: architecture & plan
> This began as the pre-implementation research note and is kept as the
> architecture reference. Sections 1–9 describe the design; section 10 lists
> external references. The phased plan in section 8 is largely done through
> Phase 2 — for current status see the
> Phase 2; for current status see the
> [README](https://github.com/jkdansereau/goldeneye-pc-port#status) and
> [`dev/LEVEL-STATUS.md`](https://github.com/jkdansereau/goldeneye-pc-port/blob/main/docs/dev/LEVEL-STATUS.md);
> for the blow-by-blow finding log see
@@ -28,18 +28,18 @@ platforms.
1. [Executive summary](#1-executive-summary)
2. [What the PD port actually does (the reference architecture)](#2-what-the-pd-port-actually-does-the-reference-architecture)
— [2.1 Emulate the RSP, bypass the RDP](#21-the-key-architectural-insight-emulate-the-rsp-bypass-the-rdp)
· [2.1 Emulate the RSP, bypass the RDP](#21-the-key-architectural-insight-emulate-the-rsp-bypass-the-rdp)
· [2.2 How the RSP is invoked](#22-how-the-rsp-is-invoked)
· [2.3 Build system](#23-build-system)
· [2.4 PD-port copy-candidate audit](#24-pd-port-copy-candidate-audit-session-2026-08-22)
3. [GoldenEye decomp: what we're porting](#3-goldeneye-decomp-what-were-porting)
— [3.1 Entry / main loop](#31-entry--main-loop)
· [3.1 Entry / main loop](#31-entry--main-loop)
· [3.2 The two libultra trees](#32-the-two-libultra-trees-srclibultra-and-srclibultrare)
4. [N64 hardware surfaces that must be shimmed](#4-n64-hardware-surfaces-that-must-be-shimmed)
5. [GE-specific graphics differences vs PD (the RSP work)](#5-ge-specific-graphics-differences-vs-pd-the-rsp-work)
6. [Audio](#6-audio)
7. [Input & saves](#7-input--saves)
8. [Recommended plan](#8-recommended-plan) — phases 0–4
8. [Recommended plan](#8-recommended-plan); phases 0–4
9. [Open questions / risks](#9-open-questions--risks)
10. [References](#10-references)
@@ -70,7 +70,7 @@ platforms.
* **Saves** are **EEPROM-based** (controller EEPROM via `osEeprom*`), not
Memory Pak. The PFS/motor code in `joy.c` is only for accessory (Rumble Pak
/ Memory Pak) detection and can be stubbed. Phase 4 is therefore a
file-backed EEPROM plus no-op PFS/motor shims — simpler than a full Memory
file-backed EEPROM plus no-op PFS/motor shims; simpler than a full Memory
Pak emulation.
---
@@ -127,7 +127,7 @@ R4300 builds a Gfx display list
The PD port **emulates the RSP in software** (`fast3d/gfx_pc.cpp`) and
**bypasses the RDP entirely**: the software RSP translates GBI commands
directly into OpenGL calls. The R4300 game code is run natively and is
unaware of the difference — it just builds display lists and "starts the
unaware of the difference; it just builds display lists and "starts the
RSP" as usual.
The frame flow (from `port/src/pdsched.c` + `port/src/video.c`):
@@ -162,7 +162,7 @@ The PC build is **CMake** (the N64 build stays Make + IDO). Dependencies:
* `src/game/*.c` (all of it)
* a curated list of `src/lib/*.c` (the engine helpers that are
platform-independent: mema, memp, model, music, snd, vi, rdp, etc.)
* `src/lib/ultra/audio/*.c` (libaudio — runs fine on the CPU)
* `src/lib/ultra/audio/*.c` (libaudio; runs fine on the CPU)
* `src/lib/ultra/gu/*.c` (gu matrix helpers)
* `port/src/*.c` + `port/src/*.cpp` + `port/fast3d/*.cpp`
@@ -176,38 +176,38 @@ for this project (see CONTRIBUTING.md): same Rare "Indy"/Bond engine family, and
port layer solves the same problem classes we are currently hitting. Audited
against our remaining work items:
**Direct copy candidates (Phase 3/4 — our stubs were scaffolded to be replaced
**Direct copy candidates (Phase 3/4; our stubs were scaffolded to be replaced
by these):**
| PD file | Lines | Replaces our | Notes |
|---|---|---|---|
| `port/src/mixer.c` | 722 | 31-line stub | libaudio→SDL final mixer; same RareAL family. Adapt to GE's `audi.c` wiring (sample rate/buffering) |
| `port/src/input.c` | 1551 | 48-line stub | SDL_GameController backend: hotplug, rumble, keyboard fallback. Remap the button table to GE's scheme (C-buttons/Z-trig differ from PD) |
| `port/src/fs.c` | 294 | 81 lines | File-backed save dir (`--savedir`, `$S` path expansion) — foundation for Phase 4 EEPROM/PFS file backing (ours are no-op stubs today) |
| `port/src/fs.c` | 294 | 81 lines | File-backed save dir (`--savedir`, `$S` path expansion); foundation for Phase 4 EEPROM/PFS file backing (ours are no-op stubs today) |
| `port/src/audio.c` | 75 | 70 lines | Near-identical; diff when Phase 3 starts |
**Reference implementations (Phase 2 — the D32/D37/D43 class).** PD's port
**Reference implementations (Phase 2; the D32/D37/D43 class).** PD's port
layer has a `port/src/preprocess/` module (~4,125 lines): a per-ROM-segment
`preprocessfunc` table in their `romdata.c` that converts N64-layout asset data
to PC-native layout *at load time* — a systematic solution to the problem class
to PC-native layout *at load time*; a systematic solution to the problem class
we have been fixing ad-hoc per asset type.
- `filemodel.c` (1,114) — the direct **D43** analogue: same `PROMOTE` idiom,
- `filemodel.c` (1,114); the direct **D43** analogue: same `PROMOTE` idiom,
**same vma 0x5000000**. NOT a drop-in copy (GE's `ModelRoData` union + opcode
set differ — PD has stargunfire/headspot/gundl node types), but the node-walk
set differ; PD has stargunfire/headspot/gundl node types), but the node-walk
order, placement/alignment choices, and record handling are Rare-validated
against near-identical data: adapt rather than design from scratch.
- `filebg.c` (524) — BG tables (an expected D43 follow-on fault).
- `segaudio.c` (362) — audio bank-tree conversion; cross-check for our D37
- `filebg.c` (524); BG tables (an expected D43 follow-on fault).
- `segaudio.c` (362); audio bank-tree conversion; cross-check for our D37
`romdataFixupAudioBank`.
- `filelang.c`, `filetiles.c`, `filepads.c`, `filesetup.c`, `gbi.c`,
`segfonts.c` — the remaining asset types we will hit.
`segfonts.c`; the remaining asset types we will hit.
**Not copyable:** GE-specific `ModelRoData` record map; fast3d CC/RM
correctness (GE's custom GBI modes vs `gmain.s` do not exist in PD); PD extras
(`config.c`, `optionsmenu.c`, `mpsetups.c`, `mod.c`) — options menu, MP setup,
(`config.c`, `optionsmenu.c`, `mpsetups.c`, `mod.c`); options menu, MP setup,
MOD player; not part of 1:1 fidelity.
**Caveats:** copy **port-layer files only** — their decomp was modified for PC
**Caveats:** copy **port-layer files only**; their decomp was modified for PC
(e.g. `types.h` keeps N64 offset comments while using real pointers); our
non-negotiables are unchanged. Same family ≠ identical format: validate every
copied conversion per-field against GE headers + ROM ground truth (the standing
@@ -221,19 +221,19 @@ D32 procedure).
US/EU/JP ROMs. Game code lives in `src/game/` (~242 files) plus engine
files in `src/`.
* **Engine layout** (same family as PD):
* `src/sched.c` — RCP scheduler (`osCreateScheduler`, `__scExec`,
* `src/sched.c`; RCP scheduler (`osCreateScheduler`, `__scExec`,
`__scYield`). Structurally near-identical to PD's `src/lib/sched.c`.
* `src/game/rsp.c` — builds the Gfx display list, wraps it in an `OSScTask`,
* `src/game/rsp.c`; builds the Gfx display list, wraps it in an `OSScTask`,
and starts it via the scheduler (`rspGfxTaskStart`).
* `src/fr.c` — frame/VI management, video modes (`osViSetMode`).
* `src/audi.c`, `src/snd.c`, `src/music.c` — libaudio-based sound + music.
* `src/joy.c` — controllers, **EEPROM** save handling (via `joyGamePak*`
* `src/fr.c`; frame/VI management, video modes (`osViSetMode`).
* `src/audi.c`, `src/snd.c`, `src/music.c`; libaudio-based sound + music.
* `src/joy.c`; controllers, **EEPROM** save handling (via `joyGamePak*`
-> `osEeprom*`), plus PFS/motor code for accessory (Rumble Pak / Memory
Pak) detection only.
* `src/init.c` — `init()` -> `mainproc()` -> `bossEntry()` (game entry).
* `src/init.c`; `init()` -> `mainproc()` -> `bossEntry()` (game entry).
**Compiled for the PC** (provides `mainproc()`); its N64-only `init()` is
stubbed (see A3).
* **Custom RSP microcode:** `rsp/graphics/gmain.s` (1545 lines) — a modified
* **Custom RSP microcode:** `rsp/graphics/gmain.s` (1545 lines); a modified
fast3d. This is the RSP-side code that consumes the display list. For the PC
port we do **not** run this; we replace it with the software RSP. But it is
the authoritative reference for which GBI commands GE actually emits.
@@ -265,23 +265,23 @@ overlap.
What the PC build must do with each:
* **`src/libultra/audio/*.c`** — standard libaudio (AL). Runs on the CPU;
* **`src/libultra/audio/*.c`**; standard libaudio (AL). Runs on the CPU;
**compile** (the game's `audi.c`/`snd.c`/`music.c` depend on it).
* **`src/libultrare/audio/*.c`** (`drvrNew.c`, `env.c`, `reverb.c`) — Rare's
* **`src/libultrare/audio/*.c`** (`drvrNew.c`, `env.c`, `reverb.c`); Rare's
audio "New" driver. `synthesizer.c` calls `alSaveNew`/`alAuxBusNew`/
`alMainBusNew`/`alLoadNew`/`alResampleNew`/`alEnvmixerNew`/`alEnvmixerParam`/
`alFxParam`, all defined here. Runs on the CPU; **compile**.
* **`src/libultra/gu/*.c`** — matrix helpers (`guMtxF`, `guOrtho`, ...).
* **`src/libultra/gu/*.c`**; matrix helpers (`guMtxF`, `guOrtho`, ...).
**Compile**.
* **`src/libultrare/io/vitbl.c`** — defines `osViModeTable` (a data table),
* **`src/libultrare/io/vitbl.c`**; defines `osViModeTable` (a data table),
referenced ~15× by `fr.c`. **Compile** (it's data, not a driver). This is the
*only* `io/` file we compile.
* **All other `src/libultra/io/*.c` and `src/libultrare/io/*.c`** — hardware
* **All other `src/libultra/io/*.c` and `src/libultrare/io/*.c`**; hardware
drivers (PI, SI, SP, DP, VI, controller, PFS, motor, EEPROM, ...). **Exclude
and shim** in `port/src/libultra.c`. Notably `pfsinit.c`/`pfsisplug.c`
(`osPfsInit`/`osPfsIsPlug`) and `motor.c` (`osMotor*`) are called by
`joy.c` only for accessory detection, so they are shimmed as no-ops (see §7).
* **`src/libultra/os/*.c` + `src/libultrare/os/*.c`** — OS core (threads,
* **`src/libultra/os/*.c` + `src/libultrare/os/*.c`**; OS core (threads,
message queues, timers, cache, TLB). **Exclude and shim** in
`port/src/libultra.c` (+ `n64stubs.c` for the boot/TLB/FPU symbols).
@@ -296,7 +296,7 @@ What the PC build must do with each:
| Subsystem | GE API used | Port strategy (from PD) |
|-----------|-------------|--------------------------|
| RSP (coproc 0) | `osSpTaskLoad/StartGo/Yield`, display lists | Software RSP (`fast3d`) — **main work** |
| RSP (coproc 0) | `osSpTaskLoad/StartGo/Yield`, display lists | Software RSP (`fast3d`); **main work** |
| RDP (coproc 1) | `osDpSetStatus`, `osDpSetNextBuffer`, render modes | Bypassed; OpenGL backend |
| VI (video) | `osViSetMode`, `osViVSyncCallback`, `osViWaitVSync` | SDL2 window + GL context + frame pacing |
| AI (audio) | `osAiSetFrequency/SetNextBuffer/GetLength` | SDL audio device + queue |
@@ -312,32 +312,32 @@ What the PC build must do with each:
GE's `include/gbi_extension.h` defines the custom GBI surface. Compared to the
PD port's `fast3d`, the deltas are:
1. **`G_TRI4`** — draws up to 4 triangles in one command using 4-bit vertex
1. **`G_TRI4`**; draws up to 4 triangles in one command using 4-bit vertex
indices (0–15). A memory-saving optimization (Rare packed 4 tris into the
slot normally used for `G_TRI2`).
* **Status: already supported** by the PD `fast3d` (`gfx_sp_tri4`, and the
PD game itself uses it). ✅
2. **`G_SETTEX`** (`0xc0`) — "use texture from bank": selects a texture by
2. **`G_SETTEX`** (`0xc0`); "use texture from bank": selects a texture by
bank/tile with detail/mipmap type, min-level, detail-id and texture-id.
Emitted only by `gsSPUseTexture` (`include/gbi_extension.h:193`).
* **Status: appears UNUSED.** `gsSPUseTexture` is defined but never called
anywhere in the game code or the RSP ucode (`rsp/graphics/gmain.s`), and
`G_SETTEX` appears nowhere outside its `#define`. The game uses the
standard texture commands (`gSPTexture`, `gSPTextureL`,
`gSPTextureRectangle`, `gSPTextureRectangleFlip`) — all already handled
`gSPTextureRectangle`, `gSPTextureRectangleFlip`); all already handled
by the PD `fast3d`. **If this holds (verify the decomp is complete),
Phase 2 shrinks to verifying the custom CC/RM modes and the PD fast3d
may work largely as-is.** Keep a `G_SETTEX` decode path as a safety net,
but it is no longer the headline task.
3. **Custom color-combiner modes** — `G_CC_MODULATEIFADE`, `G_CC_FADE`,
3. **Custom color-combiner modes**; `G_CC_MODULATEIFADE`, `G_CC_FADE`,
`G_CC_DECALFADE`, `G_CC_BLENDRGBFADEA`, etc. (fade/blend variants).
* **Status: handled generically** by the fast3d color-combiner -> GLSL
shader compiler (`gfx_cc.cpp`), which compiles arbitrary CC equations.
Needs verification that each GE mode produces correct GLSL.
4. **Custom render mode** — `G_RM_CUSTOM_AA_ZB_XLU_SURF` (AA_ZB_XLU with
4. **Custom render mode**; `G_RM_CUSTOM_AA_ZB_XLU_SURF` (AA_ZB_XLU with
`Z_UPD`).
* **Status: handled** by the render-mode -> GL state mapping; verify.
5. **`gDPLoadTLUT06/07`** — custom TLUT load variants.
5. **`gDPLoadTLUT06/07`**; custom TLUT load variants.
* **Status: minor**, map onto the existing `G_LOADTLUT` path.
**Conclusion:** the PD `fast3d` is a strong starting point. `G_SETTEX` appears
@@ -347,7 +347,7 @@ safety net. Everything else (matrices, lights, fog, tri1/tri4, texture load,
sync/flush) is shared.
> Note: GE's on-hardware RSP ucode is `rsp/graphics/gmain.s`. We do not run it
> on PC, but it is the ground truth for the exact command encodings GE emits —
> on PC, but it is the ground truth for the exact command encodings GE emits;
> use it to validate the software RSP's command decoding.
---
@@ -355,7 +355,7 @@ sync/flush) is shared.
## 6. Audio
* GE uses **libaudio (AL)** on the R4300 (`src/audi.c`, `src/snd.c`,
`src/music.c`) — identical architecture to PD. Sound synthesis (ADPCM
`src/music.c`); identical architecture to PD. Sound synthesis (ADPCM
decode, mixing, FX) runs on the CPU; the RSP audio ucode is a thin
pass-through to the AI DMA.
* The PD port runs libaudio natively and routes the mixed output through
@@ -370,7 +370,7 @@ sync/flush) is shared.
* **Controllers:** `src/joy.c` uses `osContInit` / `osContStartReadData`.
The port maps SDL2 keyboard/mouse/gamepad into the N64 `OSError`/controller
structs. PD implements 1964GEPD-style and Xbox-style bindings — a good
structs. PD implements 1964GEPD-style and Xbox-style bindings; a good
default for GE too (fire=Z, aim=R, etc.).
* **Saves:** GE saves are **EEPROM-based**, not Memory Pak. The actual save
I/O (`src/game/file2.c`) uses `joyGamePakProbe/LongRead/LongWrite`, which
@@ -386,35 +386,35 @@ sync/flush) is shared.
## 8. Recommended plan
### Phase 0 — Scaffolding (this change)
### Phase 0: Scaffolding (this change)
* Add `port/` directory structure + headers + stub sources.
* Add a top-level `CMakeLists.txt` (+ `cmake/` modules) for the PC build,
parallel to the N64 `Makefile`.
* This document + `port/README.md`.
### Phase 1 — Boot to a window
### Phase 1: Boot to a window
* Port `system.c`, `fs.c`, `romdata.c`, `config.c`, `main.c`.
* Port `video.c` + a minimal `fast3d` (clear color, present).
* Goal: load `ge007.u.z64`, open a window, draw a clear color.
### Phase 1.5 — Boot to first frame (ABI reconciliation)
### Phase 1.5: Boot to first frame (ABI reconciliation)
* Get mainThread through all of `bossInitMainthreadData()` → `bossEntry()` →
`bossMainloop()` and render frame 1. (Done — D34–D58; see §G.)
* Recurring mechanism: **ROM-data struct ABI/layout fixes** (the D32 pattern) —
`bossMainloop()` and render frame 1. (Done; D34–D58; see §G.)
* Recurring mechanism: **ROM-data struct ABI/layout fixes** (the D32 pattern);
a 32-bit-pointer struct read as a 64-bit-pointer struct misaligns; convert
embedded pointer fields to `u32` + cast at use sites (PD ground truth), then
verify the load-time rebase yields valid DRAM addresses. See §H for the
step-by-step procedure and the standing "non-negotiable #2 ABI exception."
* Goal: title screen / first level actually drawn on the GL surface.
### Phase 2 — RSP / rendering
### Phase 2: RSP / rendering
* Bring in the PD `fast3d` (gfx_pc / gfx_opengl / gfx_cc / gfx_sdl2).
* Verify the custom CC/RM modes against `gmain.s`; add a `G_SETTEX` decode
path only if it turns out to be used (see §5 — it appears unused).
path only if it turns out to be used (see §5; it appears unused).
* Port `pdsched.c` (GE variant) to drive the software RSP.
* Goal: render the title screen / first level.
### Phase 3 — Audio + input
### Phase 3: Audio + input
* Port `audio.c`, `mixer.c`, `mod.c`; wire libaudio output to SDL.
* **Decide the ASP strategy** (see §11 C2): if audio runs the `aspMain`
microcode, wire `aspMainTextStart`/`aspMainDataStart` to the real microcode
@@ -422,7 +422,7 @@ sync/flush) is shared.
* Port `input.c` (keyboard/mouse/gamepad).
* Goal: playable with sound.
### Phase 4 — Saves + polish
### Phase 4: Saves + polish
* File-backed EEPROM (saves); PFS/motor already stubbed as no-ops.
* Widescreen, mouse-look, FPS options, config file, crash handler.
* Goal: feature-parity with the original + QoL extras.
@@ -431,21 +431,21 @@ sync/flush) is shared.
## 9. Open questions / risks
1. **`G_SETTEX` (low priority)** — appears unused (`gsSPUseTexture` is never
1. **`G_SETTEX` (low priority)**; appears unused (`gsSPUseTexture` is never
called). If a future decomp revision or a missed call site shows it is used,
reverse the texture-bank selection (bank -> image, tile, detail/mipmap type)
from `gmain.s` + `tex.c` / `initmttex.c`. Not currently the main unknown.
2. **Custom CC correctness** — the GLSL compiler must handle every fade/blend
2. **Custom CC correctness**; the GLSL compiler must handle every fade/blend
mode GE uses; validate per-mode against the original. This is now the main
rendering unknown.
3. **Scheduler fidelity** — GE's `sched.c` has speed-graph / profiling hooks
3. **Scheduler fidelity**; GE's `sched.c` has speed-graph / profiling hooks
(`speedgraphMarkerHandler`) and a slightly different task model than PD;
the port scheduler must reproduce the gfx/audio interleaving and VSync
pacing.
4. **Decomp completeness** — the decomp is WIP; some functions may still be
4. **Decomp completeness**; the decomp is WIP; some functions may still be
stubs/`unk_`. The PC port inherits whatever state the decomp is in. Track
the upstream `n64decomp/007` and rebase.
5. **Endianness / alignment** — GE, like PD, is big-endian N64 code with
5. **Endianness / alignment**; GE, like PD, is big-endian N64 code with
unaligned accesses; the PD port handles this with careful casts and
`-fno-strict-aliasing`. Reuse those flags.
+186 -186
View File
File diff suppressed because it is too large. Load diff
+22 -24
View File
@@ -1,16 +1,17 @@
# GoldenEye 007 PC Port — @VERSION@ (pre-release)
# GoldenEye 007 PC Port - @VERSION@
A native PC port of the original Nintendo 64 *GoldenEye 007*, compiled from the
[GoldenEye 007 decompilation](https://github.com/n64decomp/007).
> **Pre-release — playable, with known rough edges.**
> **Playable, with known rough edges.**
> The full single-player campaign runs at a steady 60 fps with no known
> crashes, and in-level music + sound effects play throughout. Known issues:
> cutscenes glitch frequently (the Dam level-end in particular), a few music
> tracks have wrong-sounding instruments, some front-end 3D models are broken
> (the spinning Nintendo logo, the MISSION COMPLETE / mode-select models), and
> assorted cosmetic rendering defects remain. This cut is for playtesting —
> report what you find.
> cutscenes still glitch, mostly with James Bond (the Dam level-end in
> particular), a few music tracks have wrong-sounding instruments, some
> front-end 3D models are broken (the spinning Nintendo logo, the MISSION
> COMPLETE / mode-select models), and assorted cosmetic rendering defects
> remain. It's an early public cut: report what you find, feedback is very
> welcome.
Project & source: <https://github.com/jkdansereau/goldeneye-pc-port>
@@ -30,8 +31,8 @@ NTSC-U (US):
| PAL (EU) | `ge007.pal-final.z64` | `167c3c433dec1f1eb921736f7d53fac8cb45ee31` |
| NTSC-J (JP) | `ge007.jpn-final.z64` | `2a5dade32f7fad6c73c659d2026994632c1b3174` |
US is the best-tested. The asset step below detects the region from the ROM's
SHA-1, so any of the three works as-is.
This release supports the **NTSC-U (US)** ROM. PAL and JP ROMs are recognised
by their SHA-1 but not yet supported; they are on the roadmap.
@DEPS@
## 2. Set up (one time)
@@ -39,26 +40,22 @@ SHA-1, so any of the three works as-is.
1. Unzip this folder anywhere.
2. Make a `data` folder next to `@EXE@`.
3. Copy your ROM into it, named exactly: `data/ge007.ntsc-final.z64`
4. Prepare the ROM-derived data (needs Python 3.8+ on your PATH):
```
python3 prepare-assets/prepare-assets.py
```
(On Windows, `python prepare-assets\prepare-assets.py`.)
This reads your ROM and writes `data/pcmodels-ntsc-final/` and
`data/pccg-ntsc-final/` next to the executable. It uses only the Python
standard library — no compiler or N64 toolchain — and takes a few seconds.
Run it again only if you replace the ROM.
4. That's all the setup. On first launch the game detects the ROM and
generates the derived data (`data/pcmodels-ntsc-final/` and
`data/pccg-ntsc-final/`) automatically; that first run takes a few extra
seconds. No Python, no compiler, no N64 toolchain: nothing to install.
If you replace the ROM later, delete those two folders and the game will
regenerate them on the next launch.
## 3. Run
Run `@EXE@` **from this folder**. Configuration is written to `ge007.ini` on
first run.
> If the game exits immediately reporting missing data, re-run step 2.4 above
> and check it printed `ALL CHECKS PASSED` for both passes.
> If the game exits immediately reporting missing data, run the generator
> manually from this folder (`prepare-assets/ge007-convert`; on Windows,
> `prepare-assets\ge007-convert.exe`). On success it prints one line per pass
> and ends with `prepare-assets: done.`
## 4. Controls (defaults)
@@ -74,7 +71,8 @@ first run.
| Start | `Enter` / `Tab` | Start |
| Options overlay | `F10` | Select (D-pad/stick + A/B navigate, Start closes) |
Mouse sensitivity and Y-inversion are in the `[Input]` section of `ge007.ini`.
Mouse sensitivity (master and aim-mode), Y-inversion and the other input
settings are in the `[Input]` section of `ge007.ini`, or in the F10 overlay.
@DECK@
## 5. Legal