Dated source reference. Current release status: handoff state. Full original relative paths are in the developer archive.
OpenHoops extra roster fields, version 1
Extra fields are optional authoring data. The original NBA 2K14 game ignores them. Private API52 reads checked companions, supports per-match overrides and freezes selected metadata in match/results. The DLL does not parse sidecars directly or render a custom presentation from them. Native61 verifies these fields through the live public API and reconciled persistent results; see the linked API52 ledger for exact scope. A consumer must advertise its supported namespaces and behaviors before a field can be described as an in-game presentation feature.
Private editor dev8 adds college vocabulary1, with the machine-readable catalog. Its91 published fields have type, scope, enum/format/range and consistency validation on edit/import/fresh open. All are optional. Unknown custom/future fields retain the scalar rules below. The companion format itself remains version1; this does not change native/API ABI versions or turn a field into an implemented in-game feature.
The editor saves Example.ROS.openhoops.json beside Example.ROS. Keep the pair together. The JSON contains format: "openhoops.roster.extensions", integer version: 1, roster_sha256, roster_bytes, roster-level fields, and a records array. Each record contains an integer section, physical row, and fields object. Every named roster table is eligible. Values may be text, a finite number, a boolean or null.
Use namespaced keys you control, such as com.yourmod.identity.player_id, com.yourmod.career.class_year, or org.openhoops.ui.display_name. The org.openhoops namespace is reserved for documented OpenHoops contracts. Example names are not current native capabilities. Store external identities as text to preserve formatting and leading zeros. A value of null is retained; remove a field to delete it.
A reader must reject an unsupported format/version, duplicate JSON keys, missing or unexpected top-level members, mismatched SHA256/size, invalid record bounds or duplicate records. Do not attach a mismatched companion by name alone. Row IDs are valid only for the exact bound roster bytes. Native game saving can change those bytes and invalidate the companion; the current API keeps frozen source context and does not automatically reconcile native game saves. The current editor refuses a mismatched pair instead of guessing.
The editor binds a new companion when saving a new copy and independently reads back both files. It preserves the source pair, checks both for external changes, refuses existing output files, writes the companion first and publishes the ROS last. Handled failures remove only files created by that operation. This is not a filesystem transaction across power loss: an orphan companion can remain if execution stops between writes; it is not a committed roster. Remove or rename only that orphan before retrying with the same filename.
Extra-field edits share native edit undo/redo. Explicit row moves remap the companion; deleting a row removes its fields and undo restores them. Clones and cross-roster imports intentionally start without source extra fields, so external identity/career data is not accidentally duplicated. Assign those fields explicitly afterward. Native fields, text arenas, schema and CRC layout remain unchanged by metadata-only edits.
Limits: 16 MiB serialized companion, 256 fields per scope/record, keys up to160 ASCII characters with3–8 dot-separated lowercase components, text values up to16,384 characters without NUL or invalid Unicode, portable JSON integers within ±9,007,199,254,740,991. Objects/arrays and executable callbacks are not accepted as field values. Use a separate versioned application document for complex state.
Consumers beyond the current API context can include presentation display names/pronunciation, team branding keys, broadcast themes, conference/career classification and managed external identities. Those consumers must remain independent of one first-party application and keep executable-specific addresses private to the adapter.