Dated source reference. Current release status: handoff state. Full original relative paths are in the developer archive.
Portable saves — external mode v0.2
Current combined source is0.2.0.dev37, snapshotABI15/eventABI4, collegeprofile4/courtdefinition3; see current internal state and API verification. The standalone external-mode versions, installer behavior and historical tests below retain their original identities. Current documentation updates do not migrate/overwrite saves, install a DLL or publish a package.
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.
The OpenHoops adapter redirects the original game's common user-data directory builder to saves beside nba2k14.exe, before the game caches any paths. It retains the v0.1 startup onboarding skip and generic missing-profile initialization. The game EXE file remains unchanged. This is an x86 runtime adapter, not native engine reconstruction.
Layout and use
| Original category | Portable destination relative to EXE |
|---|---|
| Saves | saves/ (USR, STG, Config.cfg, ROS and other save files) |
| Cache | saves/cache/ |
| shoes | saves/shoes/ |
| Online Data | saves/online-data/ |
Source and installer: native/external-mode. Package: build/external-mode-v0.2, with usage instructions. -MigrateAppData copies the four original categories recursively into a new portable folder, verifies every copied file, and retains originals. It refuses to merge into an existing portable folder. Without migration, the adapter creates missing generic player/settings files on launch and preserves existing files. The installer backs up the known v0.1 DLL when upgrading and rejects unrelated loaders. Disabling the adapter resumes the unmodified game's AppData behavior; portable files remain, with no automatic reverse migration.
The executable's directory, not the current working directory, determines the root. It must be writable and fit original game path buffers. The game converts cached paths to Windows short names: OPENHO~1/REFERE~1 still resolves to the same reference-game directory. Every user of one installation shares its portable saves. Simultaneous instances, read-only installs and long paths are not supported by this prototype. Loader chaining remains unimplemented.
Attribution and version scope
Game code belongs to the supplied NBA 2K14 build by Visual Concepts / 2K. Runtime evidence comes from the user-supplied ISO variant, archived at resources/executable-variants/rld-iso/Crack/nba2k14.exe. Supported EXE SHA-256: 7cb5fdaa30586558a3146dcf9023880b1cceeaabfe0f92f967f461c4644f3704. Original CD build is unsupported. The adapter is local OpenHoops source, built MSVC 19.51 x86, C++17, /W4 /WX /O2 /MT /LD. Generic seed provenance and hashes remain in seed manifest.
Final v0.2 DLL SHA-256: 003a0c821b81f4abd0851b276fa7f5854de849c07ddb1723d9bd3259a0d2daf4. Tested on one Windows 11 x64 host (OptiPlex), original x86 game. The new early bootstrap has not been verified under macOS/Wine or Linux. Mac/Linux game compatibility is a later phase after the Windows feature set; no native engine rewrite is required by the current scope.
Recovered directory boundary
The common builder at 0x4DF150 begins with e9 3b b3 c9 01, targeting protected runtime code at 0x217A490. Its recovered usercall contract is ECX = wchar output, EAX = wchar category, [ESP+4] = character capacity, callee ret 4. The original builder tries the existing override/registry route and AppData helper, then appends game/category directories. The replacement makes a bounded directory, writes a trailing-backslash path, and returns 1 using that same register/stack contract.
Runtime guards require the pinned EXE, image base 0x400000, exact builder/onboarding/helper bytes and zero initialized flags at 0x15D2168, 0x15D2378, 0x15D2588. Unknown category names fail explicitly. Final runtime capture confirms paths at 0x15D1F60 (saves), 0x15D2170 (cache), 0x15D2380 (shoes), 0x15D2590 (online data), and secondary copies at 0x15D29D0, 0x15D3C10, 0x15D4E1C. See decoded paths. Those buffers are observed, not heuristically rewritten.
Why initialization moved earlier
The v0.1 DirectInput8Create boundary occurs after the game caches user-data paths. paths-at-input.bin and its receipt show initialized flags and AppData paths. Patching only at that point cannot meet first-launch portable behavior.
The final bootstrap temporarily hotpatches process-local kernel32!GetModuleHandleA, selecting the first verified WinMain call (return 0x6A8216) before game initialization. It supports the observed supplied-runtime wrapper by checking its exact call-site prefix 55 8b ec 8b 45 08 56 50 ff 15 and the original return at stack slot 4; the stack bound is checked. The wrapper preserves EBP/ESI and pushes the API argument, accounting for that slot.
The system function must have aligned 8b ff 55 8b ec entry and five preceding cc bytes. A five-byte jump is written into padding, then an atomic two-byte backward jump publishes it. Other calls forward after the two-byte no-op. At the selected game boundary the original API entry is restored before file hashing, directory creation and game patching; the padding jump is dormant afterward. No system DLL file is edited. DllMain performs no filesystem/hash/library-load operations and retains static-CRT notifications. This guarded Windows-specific bootstrap is deliberately not described as a universal Wine-compatible loader.
An IAT hook alone failed because supplied protected startup replaces that import. A direct-return-only API hook failed because this build routes the API through a wrapper. Runs 06/07 reached early initialization but rejected the initially unmapped Online Data category; final source maps all four observed categories. Attempts and diagnostic source are retained. capture-paths-02 crossed an unreadable page and failed; subsequent bounded reads succeeded. The capture-redirected receipt's method label says v0.1 due to a copied diagnostic label: PID 8628 and its recorded installed hash identify final v0.2. Do not use that label as a version assertion.
Verification and evidence
Evidence lives in analysis/portable-saves; final validation summary and file hashes are stored there. Run08 final DLL reached HOME without onboarding, wrote Config.cfg/cache under portable saves, and created Roster1.ROS through the game's Save Roster screen. AppData game directory remained absent. Roster1 is a default-roster verification artifact, not a custom league roster.
Installer fixtures verify fresh install, identical reinstall, known-v0.1 upgrade with exact backup, unrelated-loader refusal without replacement, unsupported EXE refusal, recursive four-category migration with matching source/destination hashes, and refusal to merge into existing portable saves. The test changes only its own process APPDATA variable to isolated fixtures and restores it afterward. No user/machine environment change.
Before testing, the previous reference user's AppData folder was preserved at C:\Users\brent\OpenHoops\profile-backups\before-portable-v02\NBA 2K14; original user-profile backups from onboarding work also remain. Active saves were copied to the executable-local folder. Original corpus and archived variants remain untouched. Game-created configuration/cache content is validated by exact location and hashes; individual shoe editing, online downloads and every optional game mode are not separately exercised.
Run09 restarted the final DLL and successfully loaded Roster1 through the game's Load UI; its 2,672,672-byte file remained SHA-256 758b219407d45eb408d869ad270421ec82e6f2eae7c508185ad9969d9a6167fc. Run10 began with both saves and the entire old AppData game directory absent, created the portable files automatically, skipped onboarding and reached HOME. Screenshots: roster-save-08.png, roster-loaded-09.png, fresh-menu-10.png. No debugger was attached to these launches.
After verification, run10's fresh data was preserved in profile-backups/portable-10-fresh; the run09 portable saves were restored by hash-verified copy from profile-backups/portable-09-results. The Dell game is closed, with v0.2 installed and the verified roster retained. No launch tasks remain. No automation was enabled.