From decf689cb5eee6d277387feecf79aed4466722fa Mon Sep 17 00:00:00 2001 From: Jonas Volman Date: Sun, 30 Aug 2026 22:37:57 -0700 Subject: [PATCH] Replace Director assembly transcription with credible C --- config/parked.json | 12 +- config/semantic_matches.json | 5 - config/symbols.json | 32 ++- ...rdinary_c_credibility_recovery_20260830.md | 237 ++++++++++++++++++ research/asm_credited_functions_audit.md | 84 +++++-- source/camera/director.c | 230 ++++++++--------- source/camera/director.h | 99 ++++++-- 7 files changed, 506 insertions(+), 193 deletions(-) create mode 100644 docs/object_matching_logs/director_obj_jonas_ordinary_c_credibility_recovery_20260830.md diff --git a/config/parked.json b/config/parked.json index 83f7be2a..e27bd0a0 100644 --- a/config/parked.json +++ b/config/parked.json @@ -137,8 +137,8 @@ { "unit": "source/camera/director", "function": "_director_initialize_for_new_map", - "class": "asm-implemented", - "evidence": "Parked under asm-implemented: our source implements this function with MSVC inline assembly, so it is byte-identical to January by construction rather than by reconstruction. This violates the campaign's standing 'no asm' rule, and the two rules interact badly - an assembly transcription always compares exact, so section_infos_equal cannot distinguish it from a genuine C recovery; only reading the source can. Parked rather than deleted so the exact tally stops counting it as a C reconstruction while the bytes remain reproducible. Same treatment as the pre-existing vendored-assembly park for matrix4x3_multiply. To unpark, replace the __asm with C that gates exact. Audit and full inventory: research/asm_credited_functions_audit.md. Worst case in the set: the loop body, the bounds assert, all three switch arms and the pointer walk are hand-written asm, including '_emit 07ch / _emit 006h' to plant a raw jl opcode and a comment stating the original TU 'keeps the zero constant in bx'. That is a transcription of January's listing, not a reconstruction of its source. Note objdiff reports 90.48% fuzzy here even though the strict comparator says exact.", + "class": "tu-context-optimization", + "evidence": "The 2026-08-30 source-credibility audit removed all eight hand-transcribed assembly blocks, including the raw '_emit 07ch / _emit 006h' branch bytes, register staging, direct structure offsets, helper-call setup, and pointer walk. The retained ordinary C is the coherent source-level routine corroborated independently by the January CFG/data offsets, HCEA, and the stianeklund/pastudan trees: choose game versus editor mode, clear initialize_camera, reset each player's camera-change/bored state, then call director_choose_camera(local_player_index, TRUE, FALSE) and director_initialize_variables(local_player_index). The typed static director_get accessor was recovered separately and now gates 64 padded bytes and five relocations exact while inlining naturally into the inherited exact callers. The camera-selection wrapper call is deliberately not manually inlined. January's 208-byte new-map function shows VC7 also inlined the 80-byte director_choose_camera wrapper and propagated the private conventions of its still-missing callees, so the honest form emits 128 padded bytes and ten relocations instead of reproducing that unavailable optimization context. No asm, raw emission, volatile/register forcing, undefined behavior, optimizer directive, synthetic branch, or byte patch remains. Reopen only with ordinary-C definitions for the remaining named director helper cluster so VC7 can recover the original private conventions and inlining naturally.", "measurements": { "target": { "size": 208, @@ -146,11 +146,11 @@ "normalized_sha256": "70b72e43999f76618be8ead0ece3d3a9facba546b477b5245a1f0d2f88e9c6c6" }, "base": { - "size": 208, - "relocation_count": 19, - "normalized_sha256": "70b72e43999f76618be8ead0ece3d3a9facba546b477b5245a1f0d2f88e9c6c6" + "size": 128, + "relocation_count": 10, + "normalized_sha256": "5b1d60ea43cdd981bff2360af7d12b07702fc9dc2e763aa4b5648ff28ae5d459" }, - "objdiff_percent": 90.47619 + "objdiff_percent": 55.460316 } }, { diff --git a/config/semantic_matches.json b/config/semantic_matches.json index f0599886..6606c493 100644 --- a/config/semantic_matches.json +++ b/config/semantic_matches.json @@ -124,11 +124,6 @@ "function": "_code_0007cb70", "reason": "hardened COFF comparison proves exact bytes and semantic relocations; objdiff reports a local-label/relocation encoding false negative" }, - { - "unit": "source/camera/director", - "function": "_director_initialize_for_new_map", - "reason": "hardened COFF comparison proves exact bytes and semantic relocations; objdiff reports a local-label/relocation encoding false negative" - }, { "unit": "source/bungie_net/network/transport_address", "function": "_transport_error_to_string", diff --git a/config/symbols.json b/config/symbols.json index 865232f6..4e7e9eb5 100644 --- a/config/symbols.json +++ b/config/symbols.json @@ -1447,7 +1447,7 @@ { "file_offset": 475424, "flags": 32, "name": "_code_00074120" }, { "file_offset": 475600, "flags": 32, "name": "_dead_camera_new" }, { "file_offset": 475888, "flags": 32, "name": "_dead_camera_update" }, -{ "file_offset": 477136, "flags": 32, "name": "_code_000747d0" }, +{ "file_offset": 477136, "flags": 32, "name": "_director_get", "static": true }, { "file_offset": 477200, "flags": 32, "name": "_director_initialize" }, { "file_offset": 477232, "flags": 32, "name": "_director_dispose" }, { "file_offset": 477248, "flags": 32, "name": "_director_inhibit_facing" }, @@ -1458,20 +1458,20 @@ { "file_offset": 477648, "flags": 32, "name": "_director_save_camera" }, { "file_offset": 477824, "flags": 32, "name": "_director_get_perspective" }, { "file_offset": 477984, "flags": 32, "name": "_director_desired_perspective" }, -{ "file_offset": 478224, "flags": 32, "name": "_code_00074c10" }, -{ "file_offset": 478320, "flags": 32, "name": "_code_00074c70" }, -{ "file_offset": 478432, "flags": 32, "name": "_code_00074ce0" }, +{ "file_offset": 478224, "flags": 32, "name": "_director_set_camera" }, +{ "file_offset": 478320, "flags": 32, "name": "_director_initialize_variables" }, +{ "file_offset": 478432, "flags": 32, "name": "_director_process_variables" }, { "file_offset": 478976, "flags": 32, "name": "_director_dispose_from_old_map" }, { "file_offset": 479088, "flags": 32, "name": "_director_load_camera" }, -{ "file_offset": 479424, "flags": 32, "name": "_code_000750c0" }, +{ "file_offset": 479424, "flags": 32, "name": "_director_rotate_cameras" }, { "file_offset": 479728, "flags": 32, "name": "_director_camera_deterministic" }, -{ "file_offset": 479824, "flags": 32, "name": "_code_00075250" }, +{ "file_offset": 479824, "flags": 32, "name": "_director_choose_game_perspective" }, { "file_offset": 480032, "flags": 32, "name": "_director_script_camera" }, -{ "file_offset": 480336, "flags": 32, "name": "_code_00075450" }, -{ "file_offset": 480784, "flags": 32, "name": "_code_00075610" }, -{ "file_offset": 480960, "flags": 32, "name": "_code_000756c0" }, -{ "file_offset": 481152, "flags": 32, "name": "_code_00075780" }, -{ "file_offset": 482112, "flags": 32, "name": "_code_00075b40" }, +{ "file_offset": 480336, "flags": 32, "name": "_director_choose_camera_game" }, +{ "file_offset": 480784, "flags": 32, "name": "_director_choose_camera_editor" }, +{ "file_offset": 480960, "flags": 32, "name": "_director_choose_camera_script_camera_record" }, +{ "file_offset": 481152, "flags": 32, "name": "_director_update_controls" }, +{ "file_offset": 482112, "flags": 32, "name": "_director_choose_camera" }, { "file_offset": 482192, "flags": 32, "name": "_director_initialize_for_new_map" }, { "file_offset": 482400, "flags": 32, "name": "_director_update" }, { "file_offset": 482896, "flags": 32, "name": "_director_initialize_for_saved_game" }, @@ -14062,7 +14062,12 @@ { "file_offset": 2452156, "flags": 0, "name": "??_C@_0CJ@GLCFCHKA@c?3?2halo?2SOURCE?2camera?2camera_scr@" }, { "file_offset": 2452200, "flags": 0, "name": "_rdata_00256ae8" }, { "file_offset": 2452212, "flags": 0, "name": "??_C@_0CE@LCNMEPOD@c?3?2halo?2SOURCE?2camera?2dead_camer@" }, -{ "file_offset": 2452248, "flags": 0, "name": "_rdata_00256b18" }, +{ "file_offset": 2452248, "flags": 0, "name": "_director_game_camera_modes" }, +{ "file_offset": 2452256, "flags": 0, "name": "_director_script_camera_record_camera_modes" }, +{ "file_offset": 2452264, "flags": 0, "name": "__real@3cf5c28f" }, +{ "file_offset": 2452268, "flags": 0, "name": "_friction" }, +{ "file_offset": 2452272, "flags": 0, "name": "__real@41c80000" }, +{ "file_offset": 2452276, "flags": 0, "name": "__real@3fa66666" }, { "file_offset": 2452280, "flags": 0, "name": "??_C@_0N@PCFDPHGK@first?5person?$AA@" }, { "file_offset": 2452296, "flags": 0, "name": "??_C@_06GIFLLBB@editor?$AA@" }, { "file_offset": 2452304, "flags": 0, "name": "??_C@_06CPNKLHAC@flying?$AA@" }, @@ -21942,7 +21947,8 @@ { "file_offset": 3001036, "flags": 0, "name": "_bits_per_channel_a4r4g4b4" }, { "file_offset": 3001044, "flags": 0, "name": "_data_002dcad4" }, { "file_offset": 3001184, "flags": 0, "name": "_data_002dcb60" }, -{ "file_offset": 3001248, "flags": 0, "name": "_data_002dcba0" }, +{ "file_offset": 3001248, "flags": 0, "name": "_director_camera_mode_names" }, +{ "file_offset": 3001272, "flags": 0, "name": "_variables" }, { "file_offset": 3001384, "flags": 0, "name": "_data_002dcc28" }, { "file_offset": 3001392, "flags": 0, "name": "_editor_custom_render" }, { "file_offset": 3001436, "flags": 0, "name": "_following_camera_zoom_levels" }, diff --git a/docs/object_matching_logs/director_obj_jonas_ordinary_c_credibility_recovery_20260830.md b/docs/object_matching_logs/director_obj_jonas_ordinary_c_credibility_recovery_20260830.md new file mode 100644 index 00000000..5b325291 --- /dev/null +++ b/docs/object_matching_logs/director_obj_jonas_ordinary_c_credibility_recovery_20260830.md @@ -0,0 +1,237 @@ +# `director.obj` Jonas ordinary-C credibility recovery + +## Result + +This 2026-08-30 audit starts from canonical commit +`69324deca14d7c3d96da1c4894dda79f5bf9be4c`. It revokes one false exact claim: +`_director_initialize_for_new_map` was byte-identical only because its body +contained eight hand-transcribed MSVC assembly blocks. The blocks reproduced +January's register allocation, direct offsets, private call setup and loop, +including `_emit 07ch` / `_emit 006h` raw branch bytes. That is object-code +transcription, not source reconstruction. + +The function is now ordinary, typed C with no assembly or code-generation +coercion. It is intentionally reported as an honest fuzzy residual and remains +parked under `tu-context-optimization`; it receives no exact or semantic-exact +credit. Its obsolete entry in `config/semantic_matches.json` is removed so the +strict progress gate cannot continue crediting the former transcription. + +The same source-level audit recovers the previously absent 64-byte private +accessor as `static struct director *director_get(short)`. VC7 assigns its +private SI convention naturally and emits all five target relocations exactly: +normalized SHA-256 +`ca74e12a19a2f27ec8a62ac17e08e1042b3ad679ac9e3980249f257b1aa16035`. +No register convention is declared or forced. + +The authenticated `director_camera_mode_names` and `variables` initializers +also reproduce the complete 136-byte `.data` section, including all five +string relocations, with normalized SHA-256 +`2f47b267059a50f6bee1a0a581bf1c613cf52fc664109b56756d5e288a03c88f`. +The two camera-mode arrays reproduce the first 16 bytes of the target +`.rdata` section, including their natural alignment. The named 5.0f `friction` +value also reproduces its target bytes, but appears at candidate offset 0x10 +rather than target offset 0x14 because the preceding 0.03f literal pool belongs +to a still-missing Director function. The other missing literals are 25.0f and +1.3f, so the honest candidate section is 20 bytes versus the target's 32. No +synthetic globals or padding were added to imitate those pools. + +| Candidate | Source status | Padded bytes | Relocations | Normalized SHA-256 | Objdiff fuzzy | +| --- | --- | ---: | ---: | --- | ---: | +| E00 | Rejected assembly transcription | 208 | 19 | `70b72e43999f76618be8ead0ece3d3a9facba546b477b5245a1f0d2f88e9c6c6` | strict exact by construction | +| E01 | Accepted ordinary C | 128 | 10 | `5b1d60ea43cdd981bff2360af7d12b07702fc9dc2e763aa4b5648ff28ae5d459` | 55.460316% | + +The 13 inherited sibling exact functions remain strict byte-and-relocation +exact, and `_director_get` is newly exact. The invalid assembly-backed exact +owner is therefore replaced in the strict count by one genuine ordinary-C +owner. The object remains nonmatching. + +## Accepted source shape + +The accepted routine performs only source-level work justified by the program: + +1. Set the primary Director mode to `_director_mode_editor` when + `game_in_editor()` is true, otherwise `_director_mode_game`. +2. Clear the authenticated `initialize_camera` flag. +3. For every local player, resolve the typed state through `director_get`, then + clear `camera_change_pause`, `bored_time`, and `bored`. +4. Call `director_choose_camera(local_player_index, TRUE, FALSE)` and + `director_initialize_variables(local_player_index)`. + +The wrapper call is deliberate. January's 208-byte function contains the +mode-switch work of the separate 80-byte `_director_choose_camera` wrapper +inlined into the loop. The current translation unit declares that wrapper but +does not yet define its private camera-selection callees, so VC7 cannot +recover the original whole-TU inline and register schedule. Manually expanding +the switch, forcing registers, or spelling private ABI calls in assembly would +only recreate object code. The honest residual is parked until ordinary-C +helper definitions make that optimization context available naturally. + +The January inline schedule remains otherwise untouched. In particular, this +change does not introduce or emit a `point_from_line3d` COMDAT. + +## Authenticated names and types + +`source/camera/director.h` now uses the real C-series `real`, `boolean`, `short`, +and `long` types already required by the ABI. The former overlapping +`director_player_globals[4]` model is replaced by the authenticated layout: + +- one 0x3E8-byte `struct director_globals` containing `dtime`, `game_mode`, + `initialize_camera`, and four 0xF8-byte `struct director` player states; +- the candidate common `_director_globals` symbol is now exactly 1,000 bytes, + ending at January's separately named `director_camera_switch_fast` byte; +- `camera_mode_index`, `camera_proc`, `camera_data`, `seat_state`, `command`, + and `debug_variables` now occupy their proven fields instead of anonymous + padding. + +The header also adds the DB-authenticated enum constants: + +- `_director_mode_game` +- `_director_mode_netgame` +- `_director_mode_editor` +- `_director_mode_scripted` +- `_director_mode_script_camera_record` + +Target offsets plus the HCEA type database authenticate the renamed fields: +`game_mode`, `initialize_camera`, `camera_change_pause`, `bored_time`, `bored`, +`debug_controls`, and `debug_input_scale`. + +The same Director ordering, extents, calls, and HCEA evidence map ten private +address placeholders to authenticated names. January proves the remaining +0x40-byte owner is the bounds-checking typed state accessor; because its +original name was not present in the available database or donor trees, it is +named `_director_get` under the repository's established `_get` +convention, as explicitly permitted for unresolved private names: + +| January address | Semantic symbol | +| --- | --- | +| `000747D0` | `_director_get` | +| `00074C10` | `_director_set_camera` | +| `00074C70` | `_director_initialize_variables` | +| `00074CE0` | `_director_process_variables` | +| `000750C0` | `_director_rotate_cameras` | +| `00075250` | `_director_choose_game_perspective` | +| `00075450` | `_director_choose_camera_game` | +| `00075610` | `_director_choose_camera_editor` | +| `000756C0` | `_director_choose_camera_script_camera_record` | +| `00075780` | `_director_update_controls` | +| `00075B40` | `_director_choose_camera` | + +`director_get` is defined `static` in `source/camera/director.c`; its prototype +does not leak into the public header. Only the two still-external helpers called +by the recovered routine are declared in that C file's own prototype section. +No prototype was moved into an unrelated implementation file and no missing +definition was fabricated. + +The Director-owned address-only data labels are also split at their proven +boundaries and named: `director_game_camera_modes`, +`director_script_camera_record_camera_modes`, `friction`, +`director_camera_mode_names`, and `variables`. The intervening unnamed floating +constants retain normal `__real@...` compiler names. HCEA database types and +the January bytes establish the 5-pointer name table and four 0x1C-byte +`director_variable_definition` records. + +## Provenance + +Evidence was ranked rather than copied indiscriminately: + +- January target COFF, disassembly, and relocations are authoritative for + layout, control flow, call order, object extent, and exactness. +- `research-cache/halocea-cseries-20260820/src/blam/camera/director_initialize_for_new_map.c` + independently corroborates the typed reset-and-two-calls routine. +- `research-cache/halocea-cseries-20260820/src/headers/director_game_mode.h` + supplies the database-authenticated enum names and values. The same tree's + individual Director helper files corroborate the semantic helper mapping and + field names. +- `research-cache/stian-halo-complete-history-20260828/src/halo/camera/director.c` + and + `research-cache/pastudan-halo-full-history-20260828/src/halo/camera/director.c` + independently recover the same mode selection, per-player three-field reset, + mode dispatch, and per-player initializer. +- `research-cache/punpckhdq-halo-full-history-20260828/source/camera/director.c` + contains only address placeholders for this cluster and provides no stronger + source to integrate. + +The repository `CLAUDE.md`, the accessible donor-tree `CLAUDE.md` files, +`docs/matching_methodology.md`, `docs/fake_match_review.md`, +`docs/object_matching_logs/README.md`, and +`research/asm_credited_functions_audit.md` were read and reconciled before the +edit. Scoped Marathon-source searches found no analogous camera Director +implementation, so no Marathon behavior was inferred. Community discussion +that helper/math functions may sometimes contain original inline assembly does +not establish provenance for Director control-flow assembly and was not treated +as permission to retain it. + +## Rejected shapes and do-not-repeat guidance + +Do not reintroduce any of the following to improve the score: + +- `_emit`, raw instruction bytes, inline or naked `__asm`; +- manually staged EAX/EBX/ESI/EDI values or comments that prescribe registers; +- direct Director byte offsets or a hand-maintained pointer stride; +- a manually expanded mode switch whose only purpose is to imitate the inlined + wrapper; +- `volatile`, `register`, optimizer pragmas/barriers, forced-inline attributes, + undefined behavior, fabricated branches, synthetic anchors, or byte patches; +- numeric enum cases where authenticated constants exist; +- address-derived private function or BSS names. + +Any future retry must begin with ordinary-C definitions for the authenticated +helper cluster, then let VC7 choose inlining and its private conventions. A +higher fuzzy score alone is not evidence of better source. + +## Validation record + +The target profile is XDK 3911, compiled through the repository's production +graph with `/O2 /Oy- /DDEBUG /Dxbox`. The audit uses the hardened function +comparator, which requires code bytes and relocation identity rather than an +objdiff percentage. + +Recorded gates: + +- candidate build and direct function comparison for + `_director_initialize_for_new_map`; +- exact-set comparison against the preserved E00 object: all 13 inherited + sibling exact functions retained and `_director_get` newly exact; +- scoped fake-match scan of `source/camera/director.c` and + `source/camera/director.h`: zero findings; +- parked-function validation: 13 active, zero stale, zero invalid; +- `git diff --check`: pass. + +Final production validation: + +- `halobetacache_build` and `libcmt_build`: pass; no work remained after the + final Director replay. +- Semantic report: 470 units scanned; 4,987 functions evaluated; 4,877 + semantic exact; 130 hidden exact / 78,743 hidden code bytes; 4,887 accepted + exact; zero ordinary rejected and zero unit errors. +- Strict campaign board: 384/833 files, 4,848/11,060 functions, and + 618,804/2,198,102 meaningful code bytes. +- Halo board: 282/468 files, 4,681/7,574 functions, and + 605,890/1,770,166 meaningful code bytes. +- Object-admission audit: zero candidates. Its sole contradiction/revocation + is the inherited `source/ai/action_converse` completion label, unrelated to + this wave. +- Tooling suite: 221 tests passed. +- Candidate COFF symbol audit: no `point_from_line3d` symbol or COMDAT. + +Reproducibility identities: + +- Final `director.c` Git blob: + `4f7db666d586273dc38ac03d55793b4c011eeda9`. +- Final `director.h` Git blob: + `fe455a79ad7ef4e4151eeeeab1f45b9457c78da7`. +- Final source SHA-256: + `52b4b773c43f27209241fc2df8da73d6ad4f042cd82e621e4386fe03f3124a67`. +- Final header SHA-256: + `9d3f64a45d6ac6ace89c215a229d58e49937b34b738ce380f537dd0e84262588`. +- January split object SHA-256: + `0238797739ab317ba363419ab943d929bdab4173a39a8a6a92b64dc763cb70ba`. +- Candidate raw object SHA-256: + `86d76476bf86426dbc3263135f80e00654e22446006f74fb25f258bb487a497d`. +- `build/report.json` SHA-256: + `a64bcee6234f6ac5209f9067db4e7cfc702661b639d10501fc0d341f781513f4`. +- `build/semantic_report.json` SHA-256: + `07229eada628261dfd37cfdaccb497bb855146e8fb3b46eb8e2a53ae5fe07707`. + +Raw COFF hashes include producer metadata; the normalized per-function hashes +in the result table are the stable comparison identities. diff --git a/research/asm_credited_functions_audit.md b/research/asm_credited_functions_audit.md index e612d6e2..8db8c0e9 100644 --- a/research/asm_credited_functions_audit.md +++ b/research/asm_credited_functions_audit.md @@ -3,11 +3,12 @@ Found incidentally 2026-08-16 while reading `source/camera/director.c` for an unrelated reconstruction. The initial audit parked the affected functions so assembly transcriptions were not credited as C reconstructions. Subsequent -source-credibility work recovered `object_shadows.code_0012b870` and -`action_converse_perform` in ordinary C. On 2026-08-30 the four Active -Camouflage transcriptions were deleted after stock-XDK owner evidence exposed -their address-placeholder premise as false. Four assembly implementations now -remain parked: Director, `stristr`, and two Particles functions. +source-credibility work recovered `object_shadows.code_0012b870`, +`action_converse_perform`, and `director_initialize_for_new_map` in ordinary C. +On 2026-08-30 the four Active Camouflage transcriptions were also deleted after +stock-XDK owner evidence exposed their address-placeholder premise as false. +Three assembly implementations now remain parked: `stristr` and two Particles +functions. ## The standing rule @@ -16,19 +17,17 @@ no byte-forcing, readable code only* — and, separately, *never credit anything that is not byte-identical*. At discovery, the first rule was violated in nine functions across five units, and the two rules interacted badly: an assembly transcription will always be byte-identical, so the strict comparator cannot -distinguish a genuine C recovery from a transcribed listing. Four such +distinguish a genuine C recovery from a transcribed listing. Three such implementations remain, explicitly parked and excluded from credit. The gate is not a defence here; only reading the source is. ## Historical inventory at discovery -Nine functions contain inline or naked `__asm` and compare +Seven functions contain whole-body or naked `__asm` and compare `EXACT` by `section_infos_equal`: | unit | function | asm blocks | kind | |---|---|---|---| -| `ai/action_converse` | `action_converse_perform` | 3 | inline, inside C | -| `camera/director` | `director_initialize_for_new_map` | 8 | inline, inside C | | `cseries/cseries` | `stristr` | 1 | whole body | | `effects/particles` | `code_0008fcd0` | 1 | whole body | | `effects/particles` | `code_0008ff30` | 1 | whole body | @@ -47,21 +46,20 @@ then gate each enclosing function. ## Why this matters more than the count suggests -`director_initialize_for_new_map` is the clearest case. It is not a C function -with an asm hint — the loop body, the assert, the switch arms and the pointer -walk are all hand-written asm, including `_emit 07ch / _emit 006h` to plant a -raw `jl` opcode, and comments that say the original TU "keeps the zero constant -in bx". That is a transcription of January's listing, not a reconstruction of -January's source. It will never stop matching, and it teaches the project -nothing about what the original C looked like. +`director_initialize_for_new_map` was the clearest case when this inventory was +opened. It was not a C function with an asm hint — the loop body, assert, +switch arms and pointer walk were all hand-written asm, including `_emit 07ch / +_emit 006h` to plant a raw `jl` opcode, and comments claimed the original TU +"keeps the zero constant in bx". That transcription was removed on 2026-08-30; +see the ordinary-C recovery below. The former `__declspec(naked)` cases were unambiguous by construction: a naked function has no C body at all. The inline cases (`action_converse_perform`, `director_initialize_for_new_map`) -were the subtler risk, because the function reads as C at a glance and the asm -is buried mid-body. Action Converse is now ordinary fuzzy C; -`director_initialize_for_new_map` remains parked assembly. +were the subtler risk, because each function read as C at a glance while the +assembly was buried mid-body. Both are now ordinary fuzzy C. The remaining +inventory is visibly whole-body assembly. ## Initial resolution (owner chose: park them) @@ -85,6 +83,45 @@ Two regression tests cover both directions (`test_asm_implemented_entry_stays_active_when_exact`, `test_asm_implemented_entry_is_invalid_when_not_exact`). +## Ordinary-C recovery: Director new-map initialization + +On 2026-08-30, all eight assembly blocks were removed from +`source/camera/director.c::director_initialize_for_new_map`, including the raw +branch-byte emission, manually staged registers, direct structure offsets, +private-call setup, and pointer walk. The retained source is a coherent typed C +routine: select the authenticated game/editor mode, clear `initialize_camera`, +reset each local player's `camera_change_pause`, `bored_time`, and `bored` +state, then call `director_choose_camera(local_player_index, TRUE, FALSE)` and +`director_initialize_variables(local_player_index)`. + +This shape is independently corroborated by the January control flow and data +offsets, HCEA's Director reconstruction, and the stianeklund and pastudan +histories. The authenticated `director_game_mode` constants, full Director +layout, and field names replace numeric switch labels, unknown-member names, +and the prior overlapping pseudo-array layout. Ten adjacent address +placeholders were mapped to authenticated semantic Director helper names. The +remaining 64-byte accessor, whose original name was unavailable, is named +`director_get` by the repository's getter convention and implemented as a typed +static helper. + +The former transcription was 208 padded bytes with 19 relocations and matched +January by construction. The ordinary-C candidate is 128 padded bytes with ten +relocations and an objdiff fuzzy score of 55.460316%. All 13 inherited sibling +exact functions remain strict exact. In addition, `director_get` now gates its +64 padded bytes and five relocations exact and inlines naturally into its +callers. Thus the invalid assembly-backed exact owner was replaced in the count +by a genuine ordinary-C exact helper. January also inlined the 80-byte +`director_choose_camera` wrapper and propagated the private conventions of its +callees, whose definitions are still missing from this translation unit. The +source deliberately retains that natural wrapper call instead of manually +reproducing its inline schedule. + +Accordingly, the function remains parked, but its class is now +`tu-context-optimization`. Reopen it only when ordinary-C definitions for the +named private helper cluster can restore the original VC7 translation-unit +context naturally. Full measurements and provenance are recorded in +`docs/object_matching_logs/director_obj_jonas_ordinary_c_credibility_recovery_20260830.md`. + ## Ordinary-C recovery: object shadows On 2026-08-29, `source/objects/object_shadows.c` replaced the naked assembly @@ -106,7 +143,9 @@ preserves that function's original branch topology. The complete object now gates 3/3 exact with no assembly, intrinsic, pragma, barrier, or attribute, so the obsolete `asm-implemented` park was deleted. -Unparking one means replacing its `__asm` with C that gates exact. +Unparking an `asm-implemented` entry means replacing its `__asm` with C that +gates exact. Replacing the asm with honest nonexact C is still a credibility +recovery, but the function must remain parked under the correct residual class. ## Recovery attempt, 2026-08-16 (stristr + the four naked thunks) @@ -222,8 +261,9 @@ options are: they stop counting toward the exact tally, exactly as `matrix4x3_multiply` does. This is the option that matches existing precedent. 2. **Re-reconstruct in C** — treat each as unwritten and find the real source - shape. `stristr` and the small naked helpers look tractable; the - `director_initialize_for_new_map` loop is a real piece of work. + shape. `stristr` and the small naked helpers look tractable. The Director + recovery above demonstrates that honest fuzzy C is preferable to retaining + a transcribed exact body even when missing TU context prevents admission. 3. **Leave and document** — accept them as knowingly-transcribed, but record it so the headline "N functions byte-exact" is not read as "N functions reconstructed in C". diff --git a/source/camera/director.c b/source/camera/director.c index 2a50c4aa..4f7db666 100644 --- a/source/camera/director.c +++ b/source/camera/director.c @@ -3,7 +3,7 @@ DIRECTOR.C symbols in this file: 000747D0 0040: - _code_000747d0 (0000) + _director_get (0000) 00074810 0020: _director_initialize (0000) 00074830 0010: @@ -25,41 +25,51 @@ symbols in this file: 00074B20 00f0: _director_desired_perspective (0000) 00074C10 0060: - _code_00074c10 (0000) + _director_set_camera (0000) 00074C70 0070: - _code_00074c70 (0000) + _director_initialize_variables (0000) 00074CE0 0220: - _code_00074ce0 (0000) + _director_process_variables (0000) 00074F00 0070: _director_dispose_from_old_map (0000) 00074F70 0150: _director_load_camera (0000) 000750C0 0130: - _code_000750c0 (0000) + _director_rotate_cameras (0000) 000751F0 0060: _director_camera_deterministic (0000) 00075250 00d0: - _code_00075250 (0000) + _director_choose_game_perspective (0000) 00075320 0130: _director_script_camera (0000) 00075450 01c0: - _code_00075450 (0000) + _director_choose_camera_game (0000) 00075610 00b0: - _code_00075610 (0000) + _director_choose_camera_editor (0000) 000756C0 00c0: - _code_000756c0 (0000) + _director_choose_camera_script_camera_record (0000) 00075780 03c0: - _code_00075780 (0000) + _director_update_controls (0000) 00075B40 0050: - _code_00075b40 (0000) + _director_choose_camera (0000) 00075B90 00d0: _director_initialize_for_new_map (0000) 00075C60 01f0: _director_update (0000) 00075E50 0020: _director_initialize_for_saved_game (0000) -00256B18 0020: - _rdata_00256b18 (0000) +00256B18 0008: + _director_game_camera_modes (0000) +00256B20 0008: + _director_script_camera_record_camera_modes (0000) +00256B28 0004: + __real@3cf5c28f (0000) +00256B2C 0004: + _friction (0000) +00256B30 0004: + __real@41c80000 (0000) +00256B34 0004: + __real@3fa66666 (0000) 00256B38 000d: ??_C@_0N@PCFDPHGK@first?5person?$AA@ (0000) 00256B48 0007: @@ -96,8 +106,10 @@ symbols in this file: __real@37a4b5be (0000) 00256C60 0004: __real@b824b5be (0000) -002DCBA0 0088: - _data_002dcba0 (0000) +002DCBA0 0018: + _director_camera_mode_names (0000) +002DCBB8 0070: + _variables (0000) 0031D048 03ea: _director_globals (0000) _director_camera_switch_fast (03e8) @@ -133,21 +145,61 @@ void scripted_camera_update( void *camera, void *command, void *result); -void code_00074c70( - void); -void code_00075450( - void); -void code_00075610( - void); -void code_000756c0( - void); +void director_initialize_variables( + short local_player_index); +void director_choose_camera( + short local_player_index, + boolean initialize, + boolean key); /* ---------- globals */ -struct director_player_globals director_globals[MAXIMUM_NUMBER_OF_LOCAL_PLAYERS]; +short const director_game_camera_modes[3] = +{ + _camera_first_person, + _camera_flying, + _camera_following +}; + +short const director_script_camera_record_camera_modes[4] = +{ + _camera_first_person, + _camera_flying, + _camera_following, + _camera_orbiting +}; + +real const friction = 5.f; + +char const *director_camera_mode_names[NUMBER_OF_DIRECTOR_CAMERA_MODES] = +{ + "following", + "orbiting", + "flying", + "editor", + "first person" +}; + +struct director_variable_definition variables[NUMBER_OF_DIRECTOR_VARIABLES] = +{ + { 5, 4, NONE, { 0, 0 }, 0.15f, 0.f, -REAL_MAX, REAL_MAX, TRUE, { 0, 0, 0 } }, + { 6, 7, NONE, { 0, 0 }, 0.075f, 0.f, -REAL_MAX, REAL_MAX, FALSE, { 0, 0, 0 } }, + { 1, 0, NONE, { 0, 0 }, 0.075f, 0.f, -REAL_MAX, REAL_MAX, TRUE, { 0, 0, 0 } }, + { 3, 2, NONE, { 0, 0 }, 0.075f, 0.f, -REAL_MAX, REAL_MAX, TRUE, { 0, 0, 0 } } +}; + +struct director_globals director_globals; +boolean director_camera_switch_fast; /* ---------- public code */ +static struct director *director_get( + short local_player_index) +{ + match_assert("c:\\halo\\SOURCE\\camera\\director.c", 179, local_player_index>=0 && local_player_index=0 && local_player_indexcamera_proc = NULL; + director->debug_input_scale = 1.f; + director->debug_controls = FALSE; } director_camera_scripted->camera_scripted = FALSE; @@ -182,51 +235,46 @@ void director_dispose_from_old_map( void director_inhibit_facing( short local_player_index) { - match_assert("c:\\halo\\SOURCE\\camera\\director.c", 179, local_player_index>=0 && local_player_indexinhibited_facing = TRUE; return; } void director_inhibit_input( short local_player_index) { - match_assert("c:\\halo\\SOURCE\\camera\\director.c", 179, local_player_index>=0 && local_player_indexinhibited_input = TRUE; return; } boolean director_inhibited_facing( short local_player_index) { - match_assert("c:\\halo\\SOURCE\\camera\\director.c", 179, local_player_index>=0 && local_player_indexinhibited_facing; } boolean director_inhibited_input( short local_player_index) { - match_assert("c:\\halo\\SOURCE\\camera\\director.c", 179, local_player_index>=0 && local_player_indexinhibited_input; } director_perspective director_get_perspective( short local_player_index) { - struct director_camera_state *camera; + struct director *camera; - match_assert("c:\\halo\\SOURCE\\camera\\director.c", 179, local_player_index>=0 && local_player_indexupdate == first_person_camera_update) + if (camera->camera_proc == first_person_camera_update) { - if (camera->transition == 0.f) + if (camera->camera_change_pause == 0.f) camera->perspective = 0; } - else if (camera->update == following_camera_update) + else if (camera->camera_proc == following_camera_update) { camera->perspective = 1; } - else if (camera->update == scripted_camera_update) + else if (camera->camera_proc == scripted_camera_update) { camera->perspective = 2; } @@ -293,10 +341,10 @@ void director_set_mode( short mode) { match_assert("c:\\halo\\SOURCE\\camera\\director.c", 384, mode>=0 && modecamera_change_pause = 0.f; + camera->bored_time = 0; + camera->bored = FALSE; + director_choose_camera(local_player_index, TRUE, FALSE); + director_initialize_variables(local_player_index); } - local_player_index = 0; - do - { - /* The original TU keeps the zero constant in bx for this assertion. */ - __asm - { - cmp si, bx - _emit 07ch - _emit 006h - } - if (local_player_index >= MAXIMUM_NUMBER_OF_LOCAL_PLAYERS) - { - display_assert("local_player_index>=0 && local_player_index