Dated source reference. Current release status: handoff state. Full original relative paths are in the developer archive.
OpenHoops record-state reconstruction
Current scope (October13,2026): Windows-first deep editing and a public extension API; Mac/Linux compatibility follows later. Earlier native-port goals and next-step proposals in this evidence history are superseded. Technical observations and verification limits remain as recorded.
Three original routines are reconstructed in C++17: select a record, raise record zero's 32-bit value only when the candidate is larger, and write that value unconditionally. The field's gameplay meaning is unknown. Proximity to the year accessors is a discovery lead, not evidence that this is a year, season, score or roster field.
The native ARM64 probe passed 6,434 cases against the original x86 instructions. The original lookup helper executes during the update tests; it is not replaced by a stub. The native code does not depend on the x86 oracle, Ghidra, Windows APIs or a running game.
Recovered behavior
All addresses below are preferred virtual addresses in the hash-locked original executable, whose image base is 0x400000.
| Address | Observed behavior |
|---|---|
0xA09E10 |
Read an owner pointer from 0x1F207A8, then its table pointer at +0x350CA4. Return zero if the table is absent; otherwise return table + 0x28 + index * 0x134. Index arrives in ECX. |
0xA27A40 |
Look up record zero. Compare ECX's input with the unsigned field at record +4. If larger, call lookup again and write it; otherwise leave the field alone. |
0xA27A60 |
Look up record zero and write ECX's input at record +4. |
The JBE instruction establishes the unsigned comparison: 0x80000000 is larger than 0x7FFFFFFF. The update routines do not check lookup's null result before dereferencing it. Our native API therefore requires a present record for updates; it does not invent an error recovery path.
RecordState contains only the understood field. It is not the original 308-byte record layout. Native pointers and explicit state replace the singleton and process addresses. Native record lookup accepts valid allocated indices; invalid indices, original 32-bit address wrapping and concurrent table replacement are outside this experiment's contract. The second lookup in the original raise operation is collapsed under that stable-table assumption. No original calling convention or unused return-register value is promised by the portable API.
Verification
Run from the project root:
.venv/bin/python tools/verify_record_state.py
The verifier checks the executable hash, exact routine bytes and surrounding INT3 padding before mapping isolated code and synthetic state in Unicorn. It uses the original call instructions and helper without patching them. No startup, DRM or Windows API code is executed.
Coverage includes absent/present lookup across 64 modeled records, boundary pairs around zero and the signed/unsigned split, and 2,048 seeded random sets. It compares lookup selection and all 64 values against the native program. Every other byte of the 20 KiB table mapping must remain unchanged; writes may touch only the target field and the stack. It also checks returns, stack balance, callee-saved registers and one-versus-two lookup calls on the two raise branches.
| Executed path | Cases |
|---|---|
| Null lookup | 64 |
| Present lookup | 2,112 |
| Raise without update | 1,102 |
| Raise with update | 1,027 |
| Unconditional write | 2,129 |
Exact bytes and layout evidence, validation and source hashes, and C++ implementation are preserved. The lookup/table fixture models observed offsets but does not assert that a live game's owner/table has been identified dynamically.
The native build has been executed only on macOS ARM64. Windows x86/x64, macOS x64, Linux and the provided CMake target remain untested. This adds a small branch-and-callee reconstruction to the earlier storage proof; it is not a playable engine or a full native port.