Files
goldeneye-pc-port/tools_pc/abpad/README.md
T
James Dansereau daa2522511 D489-D502: settings persistence, collision, A/B harnesses, D441 census
F10 pad slider persistence (D489), glass collision hull (D490), A/B input
harnesses (1964 virtual pad, GE_INPUTSCRIPT, live one-pad launcher), adjacent
global struct reads (D491), vibration percent, D441 complete pointer-width
census with high-arena tier-1 build, fix batches 1-5 and an ABI warning
ratchet, playtest verification of D493-D502.

Refs: D489 D490 D491 D492-D502 D441
2026-10-06 18:35:42 -04:00

131 lines
6.5 KiB
Markdown

# abpad — 1964 vs PC port A/B input harness
One millisecond timeline drives both sides of a faithful-vs-port comparison:
- **1964** reads a ViGEmBus virtual Xbox 360 pad (`vgamepad`) through NRage
2.3c in XInput mode. abpad reads NRage's own mapping file and presses
whatever Xbox input your profile maps to each N64 input, so you can keep
your normal play profile.
- **The port** is launched with the same timeline converted to its own
`GE_INPUTSCRIPT` (exact N64 bits, works unfocused, reproducible). It does
not read the virtual pad. Its default pad layout (Jinx 1.1) maps buttons
by context: in a level Y = N64 A and pad A = N64 B, while in menus A/X =
N64 A. A single NRage mapping can't follow that switch.
Runs are **not frame-identical**: 1964 has no seed pin or frame dump, and the
port's script counts controller reads, not milliseconds. Use it to compare
timing and feel (fire rates, AI reactions, menus), not pixels.
## One-time setup
1. ViGEmBus 1.22 installed (it is: Sunshine's driver). `pip install vgamepad`
is done. Note that a plain `pip install vgamepad` runs its bundled
ViGEmBus 1.17 MSI if it doesn't recognise the installed bus. On
2026-10-02 that downgraded the bus and had to be reverted.
2. 1964 → Plugins → Input = `NRage_Input_V2.dll` (2.3c), Controller 1 with
**XInput** ticked. Any button layout works. abpad inverts
`plugin/XInput Controller 1 Config.xcc` (`--nrage-dir`, default the
`ge-port-reference` 1964 copy) and errors if a timeline needs an N64
input that the profile leaves unmapped. File format, from NRage's
`XInputController.cpp` ([libertyernie/nrage-input](https://github.com/libertyernie/nrage-input)):
- Button keys (`A=`, `Z=`, `DUp=`, ...) are XInput button bitmasks.
- `LeftTrigger=`/`RightTrigger=` are N64 button codes (Z = 0x20,
L = 0x2000, ...).
- Each `*Axis=` is either the N64 analog axis (0x4000 X, 0x8000 Y) or
`(positive-direction code << 16) | negative-direction code` for a
stick used as C or D buttons.
3. **The virtual pad must be XInput slot 0.** NRage reads N64 controller 1
from XInput slot 0 only, and a real pad that is already connected holds
it. Switch the real pad off, or unplug it, before a run. abpad probes
slot 0 at startup and refuses to run otherwise.
4. Stick range is handled automatically. The port's script deflects the
stick to ±80. abpad computes the thumb value that NRage turns into 80
after its `PadDeadZone` (21248 at the default 5%); `--stick` changes the
target.
5. `1964.cfg`: `PauseWhenInactive 0` (set 2026-10-02). Only one window
has focus, and 1964 pauses when it's in the background.
## Timeline
`<ms>:<tok>[,<tok>...]` entries separated by `;` or newlines; `#` starts a
comment. Times are from harness start.
| Tokens | Meaning |
|---|---|
| `A B Z START L R UP DOWN LEFT RIGHT CUP CDOWN CLEFT CRIGHT` | 50 ms press (the port's `INPUTSCRIPT_PULSE_MS`) |
| `SUP SDOWN SLEFT SRIGHT` (combinable) / `SNONE` | analog stick, held until changed / recentre |
| `ZHOLD` / `ZREL` | hold / release fire |
| `RHOLD` / `LHOLD` / `RREL` | hold R or L (one aim hold) / release |
Port-only `GE_INPUTSCRIPT` tokens (`MDX`/`MDY`, `CHOLD`, `UHOLD`,
`RELOADHOLD`, ...) are rejected. The port caps a script at 64 entries.
## Running
The full side-by-side run (PowerShell; the real pad must be off):
```powershell
tools_pc\abpad\run_ab.ps1 -Timeline "19000:START;25000:SRIGHT;25300:SNONE;27000:SLEFT;27300:SNONE;29000:A" `
-QuitFrame 2400 -Seconds 36 -Step 0.5
python tools_pc\abpad\sheet.py $env:TEMP\abpad-run 16 36 1 # side-by-side contact sheet
```
`run_ab.ps1` starts abpad (which launches the port), then 1964 with
`-c NRage_Input_V2.dll -g <Rom>` 1.2 s later, and screenshots both windows
every `-Step` seconds on one clock (`capture.ps1`, DPI-aware PrintWindow, so
overlapping windows are fine). 1964's `-g` takes a file name inside its
configured ROM directory and can't contain spaces, so keep a copy such as
`GoldenEyeUSA.n64` there. The port exits by itself through `GE_QUITFRAME`;
the script closes 1964 normally.
abpad on its own:
```sh
python tools_pc/abpad/abpad.py t.txt --print-script # the port's GE_INPUTSCRIPT
python tools_pc/abpad/abpad.py t.txt --quitframe 2400 # both sides
python tools_pc/abpad/abpad.py t.txt --no-port # 1964 only
python tools_pc/abpad/abpad.py t.txt --no-pad # port only
```
- **Port timing:** abpad sets `GE_INPUTSCRIPT_MS=1`, so the port reads entry
times as milliseconds since its SDL init instead of controller reads. Read
rates vary through the intro and menus, so read counts can't be lined up
with 1964. `--reads-per-ms` converts to a read-count script instead, for
exes that don't have the millisecond mode.
- **1964 lags by ~2 s** (measured 2026-10-02): the 1.2 s launch gap plus
1964's slower startup. `run_ab.ps1` defaults `-PadOffset 2000`, which
delivers each input at the same game state on both sides. The screenshots
then show 1964 about 2 s behind the port throughout.
- **Menus use the analog stick** (`SUP`/`SDOWN`/`SLEFT`/`SRIGHT` + `SNONE`),
not the D-pad.
- The port is `build-pc/ge007.x86_64.exe`, launched from the repo root, so
it uses the repo's `data/` (`SkipIntro = 0`). `build-pc/data` has the
maintainer's play settings and skips the intro.
Verified 2026-10-02: START during the gun-barrel dots skipped to the title,
file select came up, stick right and left moved the folder cursor, and A
opened the folder. Both sides went through the same sequence.
## Checks before trusting a run
1. With `--no-port` and a long `0:ZHOLD` timeline, NRage's XInput dialog
(or 1964 firing in a level) should show the profile's Z input held.
2. The port side needs no pad check. `GE_INPUTSCRIPT` is the port's sole
controller-0 source when set, focused or not.
3. The two sides use different save files (the port's `data/ge007.eep`,
1964's `save/`), so file-select contents can differ.
## Live A/B (one real pad)
`live_ab.ps1` launches 1964 GEPD and the port side by side at 1280x720 each (1964: GLideN64 windowed size; port: `data/ge007.ini` [Window]; the script only moves windows, never resizes), driven by ONE
real gamepad: the port reads it unfocused (`GE_PAD_BACKGROUND=1`), 1964 gets
it on click. 1964 starts ~0.8 s slower, so it launches first and the port
follows after `-PortDelayMs` (tune if the intros drift).
```
powershell -ExecutionPolicy Bypass -File tools_pc\abpad\live_ab.ps1 [-PortDelayMs 800] [-NoArrange]
```
The real pad must be ON (no virtual pad), and the NRage profile should match
the port's pad layout. `-DryRun` prints the launch lines without launching.