Dated source reference. Current release status: handoff state. Full original relative paths are in the developer archive.
Application loop and first Windows match
Historical supporting milestone. Runtime/build observations, paths and next-step statements below belong to their recorded source/date. They are not a current native-engine objective or current machine-installation inventory. Use current state, plan and API verification for active work; original research evidence remains unchanged.
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.
Evidence captured October 12, 2026. This is reverse engineering of the original Windows game, not a native OpenHoops game build. Original NBA2K14-extracted remains unchanged. The reference executable is the supplied ISO variant, SHA-256 7cb5fdaa30586558a3146dcf9023880b1cceeaabfe0f92f967f461c4644f3704.
Live reference result
analysis/windows/reference-interactive-02/launch.json records PID 12708 in interactive session 1, launched at 22:23:50 UTC with no debugger attached. On the Dell, the run completed offline first-run setup, entered the main menu, loaded Spurs at Heat, reached tip-off and active play. Observed first-quarter clocks: 6:00 at tip-off, 5:49, 5:44, 5:38, then 5:22 when paused. Score remained 0–0 in these observations. Arena, player animation, ball movement, shot attempts and clock progression were visible through RustDesk. This is a short gameplay smoke test, not a completed match or performance benchmark. Audio and continuous player-control behavior are not verified. Arrow input was attempted; movement causality was not isolated. Pause input is verified.
User explicitly authorized an under-18 test date to skip obsolete online enrollment. Selected February 1, 2025 as artificial test data, acknowledged the ineligibility notice, retained the generated local player name Keith Grady, and saved the local profile. This is not the user's date of birth. No online account was created and no online terms were accepted.
The game was left paused at 5:22 while the user asked about project direction. Screenshot analysis/windows/reference-interactive-02/match-paused.png was obtained through CUA's RustDesk screenshot API and saved from its returned bytes. Earlier live observations are in the conversation; no separate screenshot files are claimed for them.
Input diagnosis
Run 01 reached the date-of-birth prompt but remote input did not advance it. A read-only x86 DirectInput diagnostic (tools/windows/input_probe.cpp) found no system mouse: CreateDevice(GUID_SysMouse) returned 0x80040154, while keyboard creation succeeded. The user attached physical peripherals. The repeated diagnostic enumerated a mouse and Dell KB216 keyboard; both system-device creations and capability queries returned zero/success. Evidence is in analysis/windows/reference-interactive-01/input-devices*.json and input-probe*.log.
After restarting the game as run 02, game-menu keyboard input worked. This strongly supports a headless-device startup issue; it does not isolate every internal failure path or prove which attached device was essential. No virtual input driver was installed. RustDesk Map mode/input source 2 was used. A click inside the remote game restored key focus when keys appeared ineffective; held key durations of 150–300 ms were more reliable than instantaneous taps. Escape after refocusing opened the in-game pause menu.
The diagnostic briefly foregrounds its own console. Its foreground PID is not evidence that the game itself had the wrong focus before probing. RustDesk 1.5.0 input implementation was inspected from official source: https://raw.githubusercontent.com/rustdesk/rustdesk/1.5.0/src/server/input_service.rs (archived in analysis/windows/remote-desktop/input_service.rs). Microsoft documents DirectInput system-device creation at https://learn.microsoft.com/en-us/previous-versions/windows/desktop/ee416359(v=vs.85).
Recovered dispatcher
Three noninvasive CDB x86 snapshots from run 01 completed successfully; the game survived each. These were during first-run setup, separate from the successful no-debugger match run. Exact commands, UTC times, executable/debugger hashes and range lengths are saved in loop-entry-01, loop-platform-01, and loop-boundaries-01 under analysis/windows/.
The previously established bootstrap at 0x02164310 repeatedly calls 0x004E0190 with ECX loaded from [0x015D08F0], continuing while EAX is nonzero. We now have the complete bounded dispatcher at 0x004E0190..0x004E0513, 900 bytes, 239 decoded instructions and 78 call sites. Every instruction is reachable in the static intraprocedural CFG; every internal direct branch aligns. There are two returns, 0x004E0426 and 0x004E0513. Stopping at the first return would miss a substantial branch. Static reachability does not prove all paths execute in a given game state.
The dispatcher starts with 0x00D944C0, computes a boolean, performs a one-time conditional callback, calls the frame-delta routine, and then issues an ordered sequence of subsystem calls. A later timing-dependent branch can return before the final group of calls. Both returns invert the initial boolean. The exact call-site list and branch successors are machine-readable in analysis/windows/application-loop.json; full bounded assembly is in application-tick-disassembly.txt.
0x00D944C0 calls 0x00D9C880, gets a singleton through 0x00DE3AC0, and returns whether its +4 field is nonzero. 0x00D9C880 traverses callback lists and contains an indirect callback at 0x00D9C9AC; it has not yet been connected to the already-known Win32 message pump. Calling the field a quit flag remains a hypothesis. Likewise, capture filenames mentioning render/present are investigative labels, not proven subsystem names: 0x00DDBC50, 0x00DDA8E0, 0x00DDF710, and 0x00DB3EC0 require further semantic recovery.
Clock boundary
0x004DF6D0..0x004DF762 is 147 bytes/37 instructions. It reads the clock through 0x00D96820 (a jump to 0x00D967C0), subtracts saved 64-bit ticks, converts an unsigned delta with x87 instructions, multiplies by a captured scale and saves a raw float delta. An unresolved override branch tail-calls 0x0047E060. The other path caps the returned delta at captured float 0.06666667014360428 (approximately 1/15 second). This is an upper delta cap, not evidence of a fixed 15 Hz simulation.
0x00D967C0..0x00D9681C is 93 bytes/33 instructions. It selects QueryPerformanceCounter at IAT 0x00EC2114 when [0x020E3A80] is nonzero, otherwise GetTickCount at 0x00EC2110 with wrap extension. The captured selector is 1 and scale is 1.0000000116860974e-07 (approximately 1/10 MHz). These values describe the capture on this host, not constants guaranteed across all hosts. Exact x87 rounding and override behavior have not been validated in portable code.
Verification and limits
Run .venv/bin/python tools/windows/analyze_application_loop.py. It checks executable identity, capture success/lengths, instruction coverage, direct-branch alignment, CFG successors and return locations, resolves clock IAT names from the variant, and emits hashes and exact ordered calls. All three bounded bodies differ from the corresponding variant bytes on disk, reinforcing the need for runtime recovery.
Ghidra 12.1.4 independently decompiled transient hash-checked overlays in the existing read-only project (analysis/windows/ghidra-loop). Persistent project and executable unchanged. The dispatcher pseudocode broadly matches the assembly structure, but unresolved calls have unreliable argument/return types. The frame-delta pseudocode is incorrect/incomplete because existing analysis includes stale protected dependencies and inferred control flow. Do not compile it or substitute it for the bounded assembly. The original partial loop listing in loop-entry-01/loop-entry-disassembly.txt is superseded by the complete 900-byte application-tick-disassembly.txt.
Next useful investigation: resolve the callback linking the dispatcher to window/input processing and the branch into graphics work; distinguish UI-state updates from simulation updates using controlled menu/pause/live-match observations. No need to recover unrelated tiny routines or expand the asset viewer to advance this milestone.