From 5e55d8f83ad7142962946b8a023d9638cd900b69 Mon Sep 17 00:00:00 2001 From: Jonas Volman Date: Thu, 1 Oct 2026 19:40:22 -0700 Subject: [PATCH 01/17] Reconcile exact triangle predicate and nav-point renderer (+1998 Halo bytes) Cleaned punpck donor reconstructions; strict bytes and all relocations match January. Fresh cold whole-board gate: 2 gains, 0 losses; 1663 tests pass. Retire the two parks. Disclose six HUD /W3 C4244 narrowing warnings and six identical shared-inline helper copies; provider links pass both orders. No object or data credit changes; inherited README and research excluded. --- config/parked.json | 38 --- .../connected_geometry_obj.md | 33 +++ .../hud_nav_points_obj.md | 38 +++ .../upstream_two_reconcile_20261001.md | 77 ++++++ source/interface/hud_nav_points.c | 220 ++++++------------ source/tool/connected_geometry.c | 54 ++--- 6 files changed, 232 insertions(+), 228 deletions(-) create mode 100644 docs/object_matching_logs/connected_geometry_obj.md create mode 100644 docs/object_matching_logs/hud_nav_points_obj.md create mode 100644 docs/object_matching_logs/upstream_two_reconcile_20261001.md diff --git a/config/parked.json b/config/parked.json index 1dae785a..77096b5c 100644 --- a/config/parked.json +++ b/config/parked.json @@ -387,25 +387,6 @@ "objdiff_percent": 91.02597 } }, - { - "unit": "source/tool/connected_geometry", - "function": "_triangle_coplanar", - "class": "instruction-scheduling", - "evidence": "Fuzzy-parked under the current house rule after recovering the natural typed C predicate from the independently corroborating Stian reconstruction and HCEA geometry types. Target and current candidate have the same 384-byte padded envelope, 11 relocation destinations and addresses, and 151 decoded instructions. The 2026-09-15 and 2026-09-24 remeasurements corrected an earlier stale claim: this production body differs in three x87 scheduling hunks (10 decoded instructions), not one operand pair. A scratch dot_product3d helper form reduces that to four instructions but introduces three point-to-vector view casts and remains residual, so it earns zero credit and is not in production. The retained source uses real_point3d/real_plane3d, typed dynamic-array records, and authenticated private symbols, with no assembly, volatile access, fake dependency, raw address name, undefined offset access, or nonsensical control flow. Reopen for first-party source/local records or a natural same-compiler x87 scheduling donor; see connected_geometry_obj_opus5_next150_n2_20260915.md.", - "measurements": { - "target": { - "size": 384, - "relocation_count": 11, - "normalized_sha256": "02acd868e062aee29df8e260c3fbd62221e3f2ced5e5f43573a1a288e6129d54" - }, - "base": { - "size": 384, - "relocation_count": 11, - "normalized_sha256": "4a01cf6dc779006e22869160f05e1640de65f3f9559f720f03f2ab716e7eff99" - }, - "objdiff_percent": 99.87755 - } - }, { "unit": "source/ai/actions", "function": "_actor_action_handle_vehicle_entry", @@ -425,25 +406,6 @@ "objdiff_percent": 96.54422 } }, - { - "unit": "source/interface/hud_nav_points", - "function": "_custom_render_nav_point", - "class": "instruction-scheduling", - "evidence": "Fuzzy-parked under the current house rule after reconstructing the complete January four-argument waypoint renderer from the January target and the later HCEA semantic donor. The retained ordinary C implements camera-distance scaling, view projection, ellipse clamping and optional rotation, typed waypoint bitmap retrieval, opacity/fade color packing, the on-screen meter readout, and January's full stack guard. Target and candidate have the same 1632-byte padded envelope, all 95 relocation identities at the same addresses, and the same instruction boundaries throughout. Only eight normalized bytes remain at +0x58A: January pushes the zero override-scale argument before loading decimal_value and distance, while VC7 hoists those two independent loads before that push. Direct and block-local decimal expressions, explicit and implicit short conversion, and literal/local zero spellings reproduce the same schedule. The complete Git/worktree/COFF census, HCEA commit 570c83fd9c365dad6f2a3e7041705d5b84c7847c, and Marathon commit ce4fdc63f20f6fa39616a86e717118f4d8bdf25c provide no closer source. No volatile access, compiler barrier, artificial alias, forced inlining, pragma, fake dependency, assembly, undefined behavior, or nonsensical control flow is retained. Reopen only for authoritative January source/local records or a natural same-compiler donor explaining that final argument-load schedule.", - "measurements": { - "target": { - "size": 1632, - "relocation_count": 95, - "normalized_sha256": "287a20cd338648964303d1f60b46e9cdf94753f43718b48f8c648a0dd9e60306" - }, - "base": { - "size": 1632, - "relocation_count": 95, - "normalized_sha256": "ad77c226edfd32a6644d9d531123945d71c2341f7b2aaa929edef572045157ca" - }, - "objdiff_percent": 99.579155 - } - }, { "unit": "source/cache/xbox_sound_cache", "function": "_sound_cache_debug_render", diff --git a/docs/object_matching_logs/connected_geometry_obj.md b/docs/object_matching_logs/connected_geometry_obj.md new file mode 100644 index 00000000..2ecf43e1 --- /dev/null +++ b/docs/object_matching_logs/connected_geometry_obj.md @@ -0,0 +1,33 @@ +# connected_geometry: canonical reconciliation ledger + +## 2026-10-01: triangle predicate exact + +Reconciled against canonical `6bfd95673719d54b92d0b23f01dc9df4c0679768`. +The natural same-compiler donor is punpckhdq/halo commit +`5d7fddc37f76194e5d151ce829a1cf25ca821ce8`, inspected at upstream +`6a23ce979ac09f7ca032449ca205ceb82eac4b81`. This is a reconstruction, +not recovered Bungie source text. + +`_triangle_coplanar` now uses the existing real-math helpers and ordinary +typed dynamic-array access. The donor's accessor macro was removed in a +pre-registered control; exactness survived. The plain 0.01f coplanarity +constant replaces the same existing literal. No shared header was changed. + +Strict extent, bytes and all relocation identities match January: +380 meaningful / 384 padded bytes, 11 relocations, normalized SHA-256 +`02acd868e062aee29df8e260c3fbd62221e3f2ced5e5f43573a1a288e6129d54`. +The new 48-byte `_plane3d_distance_to_point` select-any copy equals both +January's selected copy and the current decals provider. It earns no +duplicate credit; provider links pass in both orders. + +The unit is 9/10 strict exact. `_connected_geometry_find_or_add_vertex` +remains residual and parked; its epsilon/grouping-macro diagnostic remains +held. The inherited January/current COMDAT-selection discrepancy for +`_plane3d_from_points` is unchanged. No object admission is claimed. + +The triangle park is retired after fresh verification. Full checkpoint, +independent ownership/provider review and receipt pins are recorded in +[the two-function reconciliation](upstream_two_reconcile_20261001.md). +Earlier negative probes and reopen history remain in +`connected_geometry_obj_opus5_next150_n2_20260915.md` and the other +date-stamped connected-geometry records. diff --git a/docs/object_matching_logs/hud_nav_points_obj.md b/docs/object_matching_logs/hud_nav_points_obj.md new file mode 100644 index 00000000..4c1a319c --- /dev/null +++ b/docs/object_matching_logs/hud_nav_points_obj.md @@ -0,0 +1,38 @@ +# hud_nav_points: canonical reconciliation ledger + +## 2026-10-01: custom waypoint renderer exact + +Reconciled against canonical `6bfd95673719d54b92d0b23f01dc9df4c0679768`. +The natural same-compiler donor is punpckhdq/halo commit +`2e5b1da` (HUD nav-points reconstruction), inspected at upstream +`6a23ce979ac09f7ca032449ca205ceb82eac4b81`. This is a reconstruction, +not recovered Bungie source text. Names not separately authenticated are +descriptive donor names. + +Only `custom_render_nav_point` changes. Canonical types, API signature, +constant names and assertions remain authoritative. The donor's pointless +multiply by 1.f is removed; exactness survives. All alpha shifts use +unsigned `pixel32`. The existing bitmap const-API adaptation is retained, +and the known long argument uses integer zero. No header, prototype, +helper body, compiler option or held single-axis parenthesis patch changes. + +Strict extent, bytes and all relocation identities match January: +1,618 meaningful / 1,632 padded bytes, 95 relocations, normalized SHA-256 +`287a20cd338648964303d1f60b46e9cdf94753f43718b48f8c648a0dd9e60306`. +The five new shared-inline copies (`distance3d`, `distance_squared3d`, +`magnitude_squared3d`, `power`, `vector_from_points3d`) match January and +current providers in code and relocations. No duplicate credit is added. + +Six new /W3 C4244 warnings are deliberately disclosed: clamped long-to-byte +alpha; two real-to-short pixel offsets; two long-to-short number arguments; +one double-to-real fmod result. These are existing narrowing boundaries +previously written with explicit casts, not new ABI mismatches. Alpha is +bounded by PIN to 0..255; offset/number range assumptions are not newly +claimed proven. No warning-silencing casts are introduced. + +The unit is 32/32 strict exact and its ownership audit passes. It remains +NonMatching pending a separate object-admission decision; this landing +does not grant object credit. The renderer park is retired after fresh +verification. Historical negative probes and holds remain in the +date-stamped hud-nav-points ledgers. See +[the full reconciliation receipt](upstream_two_reconcile_20261001.md). diff --git a/docs/object_matching_logs/upstream_two_reconcile_20261001.md b/docs/object_matching_logs/upstream_two_reconcile_20261001.md new file mode 100644 index 00000000..60b98627 --- /dev/null +++ b/docs/object_matching_logs/upstream_two_reconcile_20261001.md @@ -0,0 +1,77 @@ +# Upstream two-function reconciliation, 2026-10-01 + +Base: `6bfd95673719d54b92d0b23f01dc9df4c0679768`. +Donor: punpckhdq/halo `6a23ce979ac09f7ca032449ca205ceb82eac4b81` (CC0). +Scope: cleaned triangle predicate and custom waypoint renderer only. +User authorized reconciliation and publication after the research review. + +| Function | Meaningful bytes | Padded bytes | Relocations | +| --- | ---: | ---: | ---: | +| `_triangle_coplanar` | 380 | 384 | 11 | +| `_custom_render_nav_point` | 1,618 | 1,632 | 95 | +| Total | 1,998 | 2,016 | | + +## Fresh production checkpoint + +- Clean baseline and final builds of all source outputs, unchanged compiler + flags and production comparator. The first baseline attempt encountered + a compiler intermediate-file permission failure; both successful clean + builds use a dedicated scratch TEMP/TMP directory. No source workaround. +- Rename-stable whole-board comparison: 8,252 rows, exactly these two gains, + zero losses and no other verdict changes (7,646 -> 7,648 all-category exact). +- Halo functions: 7,473 -> 7,475 of 7,573. Halo code: + 1,597,714 -> 1,599,712 of 1,770,166 meaningful bytes (90.37%). +- Halo data unchanged: 3,311,591 / 3,922,163. Objects unchanged: 396 / 468. + Fresh Q10 receipts retain precisely 661,012 bytes / 93 records. +- Parks: 68 -> 66, exactly the two new exact functions retired by line + surgery; zero stale or invalid parks. Earlier research history preserved. +- Admission: 7 -> 8 review candidates (HUD becomes a candidate only); + zero contradicted, rejected or revoked admissions. No status flips. +- Full default-build warning set unchanged. Independent /W3 compiles add + only the six disclosed HUD C4244 narrowing warnings; triangle adds none. +- Fake scan: the same 26 inherited leads; no new leads. +- Tools tests, baseline and final: 1,663 passed, 5 skipped, + 159 subtests passed. Whitespace checks pass. +- Canonical's inherited dirty README and unrelated research are preserved + and excluded from the commit. Source/config scope is exactly two bodies, + a plain epsilon constant and two park retirements. No tool/scorer changes. + +## Independent ownership and provider audit + +Final production objects equal the cleaned research candidates in all +73 HUD and 27 triangle non-debug sections, including symbol attributes +and COMDAT metadata. January's 46 HUD and 13 triangle owned symbols agree. +All 39 surplus code/data definitions match both January and current +selected providers. All six newly emitted helper copies have the correct +ANY selection, flags and alignment. No new COMMON, import or storage +disagreements are introduced. The triangle's sole inherited residual is +find_or_add_vertex; its unrelated selection discrepancy remains disclosed. + +18 provider pairs in both orders (36 probes) produce only the expected +unresolved-external exit 1120; no duplicate definitions, unexpected linker +diagnostics or output images. 864 pinned inputs remained unchanged. +This is bounded duplicate/provider evidence, not a whole-program-link +proof. Surplus copies receive no duplicate credit. + +Independent source review found no new filler, instruction emission, +representation-punning view or held-donor bleed-in. The held vertex, +bitmap text, plane-header and assembly-dependent upstream forms remain out. + +## Local receipts (private assets not published) + +Reconciliation directory: `scratch/astra_upstream_two_20261001/` in the +canonical checkout. Separate independent review directory: +`scratch/punpck_rest_check_20261001/` in the task workspace. +The following SHA-256 pins refer to persisted receipt files, not binaries. + +| Receipt | SHA-256 | +| --- | --- | +| reconciliation `final.json` | `822618c8f985e735fd4c545959d4bd412055cc02e3b541a104f09436dff387b8` | +| reconciliation `final_build.log` | `b3bde6cacbe2040bc652717cf65671f59e04bc0e410186171d19acc7162b486c` | +| reconciliation `final_pytest.log` | `a731d14e8c2f720f60272bf412646de8d03ebb089744c6e3ad92097af242e92f` | +| independent `admission/REPORT_final_hud_final_triangle.json` | `b2690904dca233fdee7a05da2b1ce391c54b48b8d6d786bf67324ab4902da627` | +| independent `connected_geometry/INDEPENDENT_FINAL_POLICY_REVIEW.json` | `235fc01a4762151d4caa5ff9b12e3b00778fe0c0d978c732afaeb7d9ae6ab58d` | + +Publication destinations authorized in the current task: both bnunu/halo +and bnunu/halo-1 `jonas/exact-pilots`, plus bnunu/halo-1 `main` through a +normal merge preserving main's README. No force push or other repository. diff --git a/source/interface/hud_nav_points.c b/source/interface/hud_nav_points.c index c0718e75..ba2b1833 100644 --- a/source/interface/hud_nav_points.c +++ b/source/interface/hud_nav_points.c @@ -668,109 +668,67 @@ short hud_get_nav_point_render_type( void custom_render_nav_point( short local_player_index, - real_point3d const *position, + real_point3d const *position_pointer, short nav_index, short waypoint_type) { long return_eip = get_return_eip(); long stack_buffer[STACK_BUFFER_LENGTH]; struct hud_waypoint_arrow *arrow; - real_point3d view_point; + real_point3d position; real distance; - real arrow_scale; + real scale; real_point2d screen_position; - real horizontal_radius; - real vertical_radius; - real vertical_component; - real horizontal_component; - real radius_product; + real a, b, ab, bx, ay; real theta; - csmemset(stack_buffer, 0x62, sizeof(stack_buffer)); - - arrow = TAG_BLOCK_GET_ELEMENT( - &hud_globals->waypoint.arrows, - nav_index, - struct hud_waypoint_arrow); - view_point = *position; + memset(stack_buffer, 0x62, sizeof(stack_buffer)); + arrow = TAG_BLOCK_GET_ELEMENT(&hud_globals->waypoint.arrows, nav_index, struct hud_waypoint_arrow); + position = *position_pointer; { - long unit_index = local_player_get_player_index(local_player_index)==NONE ? - NONE : - player_get(local_player_get_player_index(local_player_index))->unit_index; real_point3d cam_pos; - real delta_x; - real delta_y; - real delta_z; - unit_get_camera_position(unit_index, &cam_pos); - - delta_x = position->x-cam_pos.x; - delta_y = position->y-cam_pos.y; - delta_z = position->z-cam_pos.z; - distance = square_root( - delta_x*delta_x + (delta_y*delta_y + delta_z*delta_z)); + unit_get_camera_position(local_player_get_player_index(local_player_index) == NONE ? NONE : player_get(local_player_get_player_index(local_player_index))->unit_index, &cam_pos); + distance = distance3d(&cam_pos, position_pointer); } - if (distance>15.0f) + if (distance > 15.f) { - arrow_scale = 0.5f; + scale = 0.5f; } else { - arrow_scale = (real)pow( - 1.0f-distance*(1.0f/15.0f), - 0.7) + 0.5f; + scale = (real)pow(1.f - distance / 15.f, 0.7) + 0.5f; } - matrix4x3_transform_point( - &render.frustum.world_to_view, - &view_point, - &view_point); - - if (waypoint_type==_waypoint_off_screen || - !render_camera_view_to_screen( - &render.camera, - &render.frustum, - &view_point, - &screen_position)) + matrix4x3_transform_point(&render.frustum.world_to_view, &position, &position); + if (waypoint_type == _waypoint_off_screen || !render_camera_view_to_screen(&render.camera, &render.frustum, &position, &screen_position)) { - screen_position.x = view_point.x; - screen_position.y = -view_point.y; + screen_position.x = position.x; + screen_position.y = -position.y; waypoint_type = _waypoint_off_screen; } else { - screen_position.x -= (real)( - ((render.camera.viewport_bounds.x1-render.camera.viewport_bounds.x0)/2) + - render.camera.viewport_bounds.x0); - screen_position.y -= (real)( - ((render.camera.viewport_bounds.y1-render.camera.viewport_bounds.y0)/2) + - render.camera.viewport_bounds.y0); + screen_position.x -= render.camera.viewport_bounds.x0 + (render.camera.viewport_bounds.x1 - render.camera.viewport_bounds.x0) / 2; + screen_position.y -= render.camera.viewport_bounds.y0 + (render.camera.viewport_bounds.y1 - render.camera.viewport_bounds.y0) / 2; } - horizontal_radius = - ((real)(render.camera.window_bounds.x1-render.camera.window_bounds.x0) - - (hud_globals->waypoint.right_offset+hud_globals->waypoint.left_offset))*0.5f; - vertical_radius = - ((real)(render.camera.window_bounds.y1-render.camera.window_bounds.y0) - - (hud_globals->waypoint.bottom_offset+hud_globals->waypoint.top_offset))*0.5f; - radius_product = vertical_radius*horizontal_radius; - vertical_component = vertical_radius*screen_position.x; - horizontal_component = horizontal_radius*screen_position.y; - theta = 0.0f; + a = ((render.camera.window_bounds.x1 - render.camera.window_bounds.x0) - (hud_globals->waypoint.right_offset + hud_globals->waypoint.left_offset)) / 2.f; + b = ((render.camera.window_bounds.y1 - render.camera.window_bounds.y0) - (hud_globals->waypoint.bottom_offset + hud_globals->waypoint.top_offset)) / 2.f; + ab = a * b; + bx = b * screen_position.x; + ay = a * screen_position.y; + theta = 0.f; - if (waypoint_type==_waypoint_off_screen || - radius_product*radius_product <= - vertical_component*vertical_component + horizontal_component*horizontal_component) + if (waypoint_type == _waypoint_off_screen || ab * ab <= bx * bx + ay * ay) { - real scale = square_root( - (radius_product*radius_product) / - (vertical_component*vertical_component + horizontal_component*horizontal_component)); + real factor = square_root(ab * ab / (bx * bx + ay * ay)); + screen_position.x *= factor; + screen_position.y *= factor; waypoint_type = _waypoint_off_screen; - screen_position.x *= scale; - screen_position.y *= scale; if (!TEST_FLAG(arrow->flags, _hud_waypoint_dont_rotate_offscreen_bit)) { @@ -778,112 +736,64 @@ void custom_render_nav_point( } } - screen_position.x += (real)( - (render.camera.viewport_bounds.x1-render.camera.viewport_bounds.x0)/2); - screen_position.y += (real)( - (render.camera.viewport_bounds.y1-render.camera.viewport_bounds.y0)/2); - - match_assert( - "c:\\halo\\SOURCE\\interface\\hud_nav_points.c", - 615, - waypoint_type!=NONE); - + screen_position.x += (render.camera.viewport_bounds.x1 - render.camera.viewport_bounds.x0) / 2; + screen_position.y += (render.camera.viewport_bounds.y1 - render.camera.viewport_bounds.y0) / 2; + match_assert("c:\\halo\\SOURCE\\interface\\hud_nav_points.c", 615, waypoint_type!=NONE); { - long bitmap_group_index = hud_globals->waypoint.arrow_bitmap.index; + long bitmap_index = hud_globals->waypoint.arrow_bitmap.index; struct bitmap_data const *bitmap = NULL; real_rectangle2d const *clip = NULL; - hud_retrieve_bitmap_and_bounding_rect( - bitmap_group_index, - arrow->sequence_indices[waypoint_type], - 0, - &bitmap, - &clip); - - if (bitmap && _texture_cache_bitmap_get_hardware_format( - (struct bitmap_data *)bitmap, FALSE, TRUE)) + hud_retrieve_bitmap_and_bounding_rect(bitmap_index, arrow->sequence_indices[waypoint_type], 0, &bitmap, &clip); + if (bitmap && _texture_cache_bitmap_get_hardware_format((struct bitmap_data *)bitmap, FALSE, TRUE)) { - point2d point; - real_rgb_color rgb_temp; + point2d corner; byte alpha; - real fade; + real_rgb_color rgb_temp; - point.x = (short)(long)screen_position.x; - point.y = (short)(long)screen_position.y; - alpha = (byte)PIN(fast_ftol_C(arrow->opacity)*255, 0, 255); + corner.x = (short)screen_position.x; + corner.y = (short)screen_position.y; + alpha = PIN(255 * fast_ftol_C(arrow->opacity), 0, 255); pixel32_to_real_rgb_color(arrow->color, &rgb_temp); - fade = 1.0f-arrow->fade; - rgb_temp.red *= PIN(fade, 0.0f, 1.0f); - rgb_temp.green *= PIN(fade, 0.0f, 1.0f); - rgb_temp.blue *= PIN(fade, 0.0f, 1.0f); + rgb_temp.red *= PIN(1.f - arrow->fade, 0.f, 1.f); + rgb_temp.green *= PIN(1.f - arrow->fade, 0.f, 1.f); + rgb_temp.blue *= PIN(1.f - arrow->fade, 0.f, 1.f); + hud_draw_bitmap_direct(bitmap, _hud_anchor_center, &corner, clip, scale, theta, ((pixel32)alpha << 24) | real_rgb_color_to_pixel32(&rgb_temp), FALSE); - hud_draw_bitmap_direct( - bitmap, - _hud_anchor_center, - &point, - clip, - arrow_scale, - theta, - ((pixel32)alpha<<24) | real_rgb_color_to_pixel32(&rgb_temp), - FALSE); - - if (waypoint_type!=_waypoint_off_screen) + if (waypoint_type != _waypoint_off_screen) { - struct number_hud_element_definition numbers; struct hud_absolute_placement_definition placement; - real decimal_modulus; - real bitmap_extent; - - distance *= 3.0480001f; - csmemset(&placement, 0, sizeof(placement)); - csmemset(&numbers, 0, sizeof(numbers)); + struct number_hud_element_definition numbers; + real fractional_value; + distance *= 3.048f; + memset(&placement, 0, sizeof(struct hud_absolute_placement_definition)); + memset(&numbers, 0, sizeof(struct number_hud_element_definition)); placement.corner = _hud_anchor_top_left; - numbers.colors.color = - ((pixel32)alpha<<24) | real_rgb_color_to_pixel32(&rgb_temp); - numbers.colors.flash_color = - ((pixel32)alpha<<24) | real_rgb_color_to_pixel32(&rgb_temp); + numbers.colors.color = ((pixel32)alpha << 24) | real_rgb_color_to_pixel32(&rgb_temp); + numbers.colors.flash_color = ((pixel32)alpha << 24) | real_rgb_color_to_pixel32(&rgb_temp); numbers.digits = 3; numbers.fractional_digits = 1; - numbers.number_flags = - FLAG(_hud_number_show_all_leading_zeros_bit) | - FLAG(_hud_number_show_trailing_m_bit); + numbers.number_flags = FLAG(_hud_number_show_all_leading_zeros_bit) | FLAG(_hud_number_show_trailing_m_bit); - bitmap_extent = - ((clip->x1-clip->x0)*(real)bitmap->width)*0.5f; - numbers.placement.offset.x = (short)(long)( - bitmap_extent*arrow_scale*0.33000001f + (real)point.x); - bitmap_extent = - ((clip->y1-clip->y0)*(real)bitmap->height)*0.5f; - numbers.placement.offset.y = (short)(long)( - bitmap_extent*arrow_scale*0.66000003f + (real)point.y); - numbers.placement.offset.x -= render.camera.window_bounds.x0; - numbers.placement.offset.x += render.camera.viewport_bounds.x0; - numbers.placement.offset.y -= render.camera.window_bounds.y0; - numbers.placement.offset.y += render.camera.viewport_bounds.y0; + numbers.placement.offset.x = corner.x + (bitmap->width * (clip->x1 - clip->x0) / 2.f) * scale * 0.33f; + numbers.placement.offset.y = corner.y + (bitmap->height * (clip->y1 - clip->y0) / 2.f) * scale * 0.66f; + numbers.placement.offset.x -= render.camera.window_bounds.x0 - render.camera.viewport_bounds.x0; + numbers.placement.offset.y -= render.camera.window_bounds.y0 - render.camera.viewport_bounds.y0; - decimal_modulus = (real)pow(10.0, 4.0); - { - short decimal_value = (short)fast_ftol( - (real)fmod( - fabs(decimal_modulus*distance), - decimal_modulus)); - - hud_draw_numbers( - local_player_index, - &placement, - &numbers, - (short)fast_ftol_C(distance), - decimal_value, - 0, - 0, - 0.0f); - } + fractional_value = power(10.f, 4.f); + hud_draw_numbers(local_player_index, &placement, &numbers, + fast_ftol_C(distance), fast_ftol(fmod(fabs((real)(fractional_value * distance)), fractional_value)), + 0, 0, 0.f); } } } - match_assert_stack_frame("c:\\halo\\SOURCE\\interface\\hud_nav_points.c", 675); + { + short corrupt_index = check_stack_buffer(stack_buffer); + match_vassert("c:\\halo\\SOURCE\\interface\\hud_nav_points.c", 675, return_eip == get_return_eip(), "corrupt return address!"); + match_vassert("c:\\halo\\SOURCE\\interface\\hud_nav_points.c", 675, corrupt_index == NONE, csprintf(temporary, "corrupt stack at %d!", corrupt_index)); + } return; } diff --git a/source/tool/connected_geometry.c b/source/tool/connected_geometry.c index e89bac11..1fdd6873 100644 --- a/source/tool/connected_geometry.c +++ b/source/tool/connected_geometry.c @@ -46,6 +46,8 @@ enum /* ---------- macros */ +#define CONNECTED_GEOMETRY_COPLANAR_EPSILON 0.01f + /* ---------- structures */ struct intermediate_geometry_triangle @@ -458,13 +460,12 @@ long connected_geometry_add_triangle( } static boolean triangle_coplanar( - void *predicate_data, + void *data, struct connected_geometry *geometry, struct connected_geometry_triangle *triangle, long group_index) { - real_plane3d *plane = predicate_data; - real_point3d *point0 = dynamic_array_get_element( + real_point3d const *point0= dynamic_array_get_element( &geometry->points, ((struct connected_geometry_edge *)dynamic_array_get_element( &geometry->edges, @@ -472,7 +473,7 @@ static boolean triangle_coplanar( sizeof(struct connected_geometry_edge)))->point_indices[ (triangle->edge_designators[0] & LONG_MIN) != 0], sizeof(real_point3d)); - real_point3d *point1 = dynamic_array_get_element( + real_point3d const *point1= dynamic_array_get_element( &geometry->points, ((struct connected_geometry_edge *)dynamic_array_get_element( &geometry->edges, @@ -480,48 +481,31 @@ static boolean triangle_coplanar( sizeof(struct connected_geometry_edge)))->point_indices[ (triangle->edge_designators[1] & LONG_MIN) != 0], sizeof(real_point3d)); - real_point3d *point2 = dynamic_array_get_element( + real_point3d const *point2= dynamic_array_get_element( &geometry->points, ((struct connected_geometry_edge *)dynamic_array_get_element( &geometry->edges, triangle->edge_designators[2] & LONG_MAX, sizeof(struct connected_geometry_edge)))->point_indices[ (triangle->edge_designators[2] & LONG_MIN) != 0], - sizeof(real_point3d)); + sizeof(real_point3d)); real_plane3d triangle_plane; - real point_distance; - real point_product; - real facing; + boolean coplanar; - if (fabs( - point0->y*plane->n.j + - point0->z*plane->n.k + - point0->x*plane->n.i - - plane->d) < 0.01f && - fabs( - point1->y*plane->n.j + - point1->z*plane->n.k + - point1->x*plane->n.i - - plane->d) < 0.01f) + if (fabs(plane3d_distance_to_point((real_plane3d const *)data, point0))n)>0.f) { - point_distance = point2->y*plane->n.j; - point_distance += point2->z*plane->n.k; - point_product = point2->x*plane->n.i; - point_distance += point_product; - if (fabs(point_distance - plane->d) < 0.01f && - plane3d_from_points(&triangle_plane, point0, point2, point1) != NULL) - { - facing = triangle_plane.n.i*plane->n.i; - facing += triangle_plane.n.k*plane->n.k; - facing += triangle_plane.n.j*plane->n.j; - if (facing > 0.0f) - { - return TRUE; - } - } + coplanar= TRUE; + } + else + { + coplanar= FALSE; } - return FALSE; + return coplanar; } void connected_geometry_add_intermediate_triangle( From 25f719236d4bec7621357e89b95e02b006824727 Mon Sep 17 00:00:00 2001 From: Jonas Volman Date: Fri, 2 Oct 2026 00:30:24 -0700 Subject: [PATCH 02/17] Reconcile transport pair: +2 exact functions, zero losses Independently reconciled lane e191c0f1 under Q-UP1. Header and definition return long together; January startup-store and cleanup topology retained. Retire only the two verified parks. Fresh clean build and stable sweep: +457 meaningful / +464 padded bytes, 0 losses, unchanged data and object status. Affected /W4 warning counts unchanged; inherited WSA narrowing moves to initialization. Admission/parks/fake scan pass; tools 1663 passed, 5 skipped, 159 subtests. No new providers or section/data changes beyond the two intended functions. README and unrelated research preserved. --- config/parked.json | 30 ------- source/bungie_net/network/transport.h | 2 +- .../network/transport_endpoint_set_winsock.c | 90 ++++++++++++------- 3 files changed, 61 insertions(+), 61 deletions(-) diff --git a/config/parked.json b/config/parked.json index 77096b5c..ea4b7323 100644 --- a/config/parked.json +++ b/config/parked.json @@ -183,36 +183,6 @@ "objdiff_percent": 96.878784 } }, - { - "unit": "source/bungie_net/network/transport_endpoint_set_winsock", - "function": "_transport_initialize", - "class": "unclassified", - "evidence": "Complete January initialization, link diagnostics, optional bypass file, startup/cleanup ordering, short WSA error handling, unsigned deadline address polling and nonce initialization reconstructed with genuine stock SDK owners. Target416 meaningful/padded33 relocations versus candidate398/400 and33; ordinary frozen objdiff78.47794%. Natural zero initialization removes repeated inert config stores, uses a different zero register and branch/tail layout, and retains the existing inferred short status API (AX, not a full-EAX equivalence claim). All22 inherited code/18 data owners and six existing parks unchanged. Nine new target-owned literals201B are strict/property-exact; two pooled copies3B match real selected target owners and receive no duplicate credit. No new helper/COMMON/global/point owner. Do not reopen with spelling/flags/barriers or couple to withheld dispose/client_start; see docs/object_matching_logs/transport_endpoint_set_winsock_obj_initialize_natural_boundary_20260905.md.", - "measurements": { - "target": { - "size": 416, - "relocation_count": 33, - "normalized_sha256": "47bd2187b394eb1f7975b4bc618fc0d041f563687eb841257fcae4296bd71db0" - }, - "base": { - "size": 400, - "relocation_count": 33, - "normalized_sha256": "a125c3a8cdab486c1d6414d8644d27b067a58b2ce26c9d769a3a41ef0562b45e" - }, - "objdiff_percent": 78.47794 - } - }, - { - "unit": "source/bungie_net/network/transport_endpoint_set_winsock", - "function": "_poll_ep_array_compare_proc", - "class": "unclassified", - "evidence": "Natural typed qsort callback reconstructed with its real poll caller. Both entries are loaded, non-NULL entries precede NULL entries, and the callback returns the January -1/0/1 relation. Private semantic name is inferred and mapped to the original target owner at 0x70B10 without an alias or linkage change. Both48B/0relocs; only EAX/ECX assignment differs. No register/declaration-order search or ABI steering. All12 inherited exact owners and the nonce park are unchanged; no candidate-only code or point_from_line3d is emitted. Reopen only for authentic source/type/compiler-context evidence. See docs/object_matching_logs/transport_endpoint_set_winsock_obj_set_operations_cluster_20260904.md. Renamed 2026-09-24 (critic_3) to the first-party Sept-2001 cachebeta.map static name _poll_ep_array_compare_proc: the Sept body is instruction-identical at the same anchor position; the rename is byte-inert.", - "measurements": { - "target": {"size": 48, "relocation_count": 0, "normalized_sha256": "10d0cbdd04c0ad15a3cd14bffdde707c085ce85c4b9fed4c036fb4c103ca9c55"}, - "base": {"size": 48, "relocation_count": 0, "normalized_sha256": "6621f23910b74ac690b7593956ec7d8b7feb44be8401480ceaff51642dcd6c1f"}, - "objdiff_percent": 97.61905 - } - }, { "unit": "source/bungie_net/network/transport_endpoint_set_winsock", "function": "_poll_endpoint_set", diff --git a/source/bungie_net/network/transport.h b/source/bungie_net/network/transport.h index 6b385cd9..82835ae6 100644 --- a/source/bungie_net/network/transport.h +++ b/source/bungie_net/network/transport.h @@ -70,7 +70,7 @@ struct transport_address /* ---------- prototypes */ -short transport_initialize( +long transport_initialize( void); short transport_dispose( void); diff --git a/source/bungie_net/network/transport_endpoint_set_winsock.c b/source/bungie_net/network/transport_endpoint_set_winsock.c index 25509740..fbbb9732 100644 --- a/source/bungie_net/network/transport_endpoint_set_winsock.c +++ b/source/bungie_net/network/transport_endpoint_set_winsock.c @@ -258,25 +258,27 @@ void transport_pop_key( return; } -short transport_initialize( +long transport_initialize( void) { + long result = _transport_error_none; + if (!transport_initialized) { WSADATA info = { 0 }; XNetStartupParams startup_params = { 0 }; DWORD link_status; - DWORD address_status; - unsigned long deadline; FILE *bypass_file; - short wsa_error; startup_params.cfgSizeOfStruct = sizeof(startup_params); + startup_params.cfgFlags = 0; startup_params.cfgPrivatePoolSizeInPages = 24; startup_params.cfgEnetReceiveQueueLength = 8; startup_params.cfgIpFragMaxSimultaneous = 4; startup_params.cfgIpFragMaxPacketDiv256 = 8; startup_params.cfgSockMaxSockets = 128; + startup_params.cfgSockDefaultRecvBufsizeInK = 0; + startup_params.cfgSockDefaultSendBufsizeInK = 0; startup_params.cfgKeyRegMax = 1; startup_params.cfgSecRegMax = 32; @@ -290,6 +292,9 @@ short transport_initialize( (link_status & XNET_ETHERNET_LINK_FULL_DUPLEX) ? " in full-duplex mode" : "", (link_status & XNET_ETHERNET_LINK_HALF_DUPLEX) ? " in half-duplex mode" : ""); + /* January stores these two fields a second time here. */ + startup_params.cfgSizeOfStruct = sizeof(startup_params); + startup_params.cfgFlags = 0; bypass_file = fopen("d:\\bypass_security.txt", "r"); if (bypass_file) { @@ -299,35 +304,53 @@ short transport_initialize( } if (XNetStartup(&startup_params) != 0) - return _transport_error_not_initialized; - - wsa_error = WSAStartup(MAKEWORD(2, 0), &info); - if (wsa_error != 0) { - XNetCleanup(); - winsock_error_to_string(wsa_error); - return _transport_error_not_initialized; + result = _transport_error_not_initialized; } - - deadline = system_milliseconds() + 10000; - do + else { - address_status = XNetGetTitleXnAddr(&global_address); - if (system_milliseconds() > deadline || - address_status == XNET_GET_XNADDR_NONE) + short wsa_error = WSAStartup(MAKEWORD(2, 0), &info); + + if (wsa_error != 0) { - WSACleanup(); XNetCleanup(); + winsock_error_to_string(wsa_error); + return _transport_error_not_initialized; } - } - while (address_status == XNET_GET_XNADDR_PENDING); + else + { + unsigned long deadline = system_milliseconds() + 10000; + DWORD address_status; - XNetRandom(global_nonce, sizeof(global_nonce)); - transport_initialized = TRUE; + do + { + address_status = XNetGetTitleXnAddr(&global_address); + if (system_milliseconds() > deadline) + { + address_status = XNET_GET_XNADDR_NONE; + break; + } + } + while (address_status == XNET_GET_XNADDR_PENDING); + + if (address_status == XNET_GET_XNADDR_NONE) + { + WSACleanup(); + XNetCleanup(); + result = _transport_error_not_initialized; + } + else + { + XNetRandom(global_nonce, sizeof(global_nonce)); + result = _transport_error_none; + transport_initialized = TRUE; + } + } + } } - return _transport_error_none; + return result; } void transport_client_stop( @@ -477,18 +500,25 @@ static int __cdecl poll_ep_array_compare_proc( void const *a, void const *b) { - struct transport_endpoint *endpoint_a = *(struct transport_endpoint *const *)a; - struct transport_endpoint *endpoint_b = *(struct transport_endpoint *const *)b; + int result; - if (!endpoint_a && endpoint_b) + a = *(struct transport_endpoint const *const *)a; + b = *(struct transport_endpoint const *const *)b; + + if (!a && b) { - return 1; + result = 1; } - else if (endpoint_a && !endpoint_b) + else if (a && !b) { - return -1; + result = -1; } - return 0; + else + { + result = 0; + } + + return result; } /* ---------- public code */ From 38fdd8cb2431d1cc4793d40f9a4e21e81c040136 Mon Sep 17 00:00:00 2001 From: Jonas Volman Date: Fri, 2 Oct 2026 00:34:46 -0700 Subject: [PATCH 03/17] Reconcile plane-helper pair: +2 exact functions, zero losses Approved coherent packet 78294dd3 (Q-UP1), independently gated on canonical. Remove only outer helper parentheses, preserving /Od argument order, together with the attested float argument repair in item_accelerate. Items object remains identical. +1126 meaningful / +1136 padded bytes; data/object/provider sets unchanged. Fresh full build, stable sweep, admission, fake scan (26), parks and tests (1663 passed, 5 skipped, 159 subtests) pass; no new warnings. Retire only two exact parks. Remeasure four residuals on canonical, preserving previous measurements/rejection history: frustum 88.8082->90.11173; pill 97.21691->98.086395; polygon clip 80.76382->82.37186; lens flares 99.29274->99.198944 (disclosed decrease). Do not import unrelated lane fidelity changes or held parentheses/DD2/DD3/casts. --- config/parked.json | 132 ++++++++++++++++++++++++++-------------- source/items/items.c | 9 ++- source/math/real_math.h | 2 +- 3 files changed, 90 insertions(+), 53 deletions(-) diff --git a/config/parked.json b/config/parked.json index ea4b7323..e3fe2f22 100644 --- a/config/parked.json +++ b/config/parked.json @@ -5,7 +5,7 @@ "unit": "source/render/render_cameras", "function": "_render_camera_build_frustum", "class": "unclassified", - "evidence": "Complete typed ordinary-C January frustum reconstruction retained after one natural house-rule pass. It builds the view/world transforms, six named clip planes, five world vertices, midpoint, world bounds, optional projection state, and all 22 integrity checks using project real/math types and owned helpers. The equivalent PC reverse-engineering corpus independently names the private warning helper render_camera_check_warning_condition and confirms its 64-entry state and behavior. A narrow per-object /Ob1 option is required by January's 22 real helper calls: default /O2 duplicates the ordinary private helper at every site, whereas /Ob1 preserves the target boundary while retaining all 12 inherited exact functions and still permits explicitly inline math helpers. Under that independently evidenced schedule the target is 3,376 padded bytes and 113 relocations versus 3,408 and 112 at 88.98603 percent objdiff; differences remain distributed x87/local scheduling plus one zero-literal relocation and the current project _pi folding bit. No constant tuning, raw array/offset lift, address name, local foreign prototype, source-pressure steering, UB, pragma, barrier, or fake dependency is retained. The separately emitted 160-byte semantic helper has equal normalized bytes and relocation shape after the January-proven >= threshold correction, but still receives no credit until the renamed private globals are regenerated into the split target. This main body remains zero-credit fuzzy source. Reopen only with authoritative January source/local records or a natural same-compiler donor. See docs/object_matching_logs/render_cameras_obj_frustum_natural_reconstruction_20260913.md. 2026-09-25 R3 batch 3: base refreshed after the attested real_math.h plane3d_negate body (negate_vector3d + d) landed with bipeds P1+P2+P3; the render_cameras.c build_frustum site is not a plane3d_negate caller in /Od; size/relocs unchanged.", + "evidence": "Complete typed ordinary-C January frustum reconstruction retained after one natural house-rule pass. It builds the view/world transforms, six named clip planes, five world vertices, midpoint, world bounds, optional projection state, and all 22 integrity checks using project real/math types and owned helpers. The equivalent PC reverse-engineering corpus independently names the private warning helper render_camera_check_warning_condition and confirms its 64-entry state and behavior. A narrow per-object /Ob1 option is required by January's 22 real helper calls: default /O2 duplicates the ordinary private helper at every site, whereas /Ob1 preserves the target boundary while retaining all 12 inherited exact functions and still permits explicitly inline math helpers. Under that independently evidenced schedule the target is 3,376 padded bytes and 113 relocations versus 3,408 and 112 at 88.98603 percent objdiff; differences remain distributed x87/local scheduling plus one zero-literal relocation and the current project _pi folding bit. No constant tuning, raw array/offset lift, address name, local foreign prototype, source-pressure steering, UB, pragma, barrier, or fake dependency is retained. The separately emitted 160-byte semantic helper has equal normalized bytes and relocation shape after the January-proven >= threshold correction, but still receives no credit until the renamed private globals are regenerated into the split target. This main body remains zero-credit fuzzy source. Reopen only with authoritative January source/local records or a natural same-compiler donor. See docs/object_matching_logs/render_cameras_obj_frustum_natural_reconstruction_20260913.md. 2026-09-25 R3 batch 3: base refreshed after the attested real_math.h plane3d_negate body (negate_vector3d + d) landed with bipeds P1+P2+P3; the render_cameras.c build_frustum site is not a plane3d_negate caller in /Od; size/relocs unchanged. 2026-10-02 canonical reconciliation of approved plane-helper packet 78294dd3: outer helper parentheses removed with the independently attested item_accelerate repair; this existing residual body is otherwise untouched. Fresh canonical measurement, not donor measurement; prior rejection/reopen evidence and measurement retained. Zero exact credit; pill-parenthesis and other recorded holds remain in force.", "measurements": { "target": { "size": 3376, @@ -15,10 +15,25 @@ "base": { "size": 3408, "relocation_count": 112, - "normalized_sha256": "d42e420f90156644a2ebac2bc234df8017efbb0c8c8fe22fb79a7a02e3ad3e07" + "normalized_sha256": "bee4fcbd93e3bc0fb0e25a7b68c5e19273ab6d61f05a26b1a784fdba4b0c8e8d" }, - "objdiff_percent": 88.8082 - } + "objdiff_percent": 90.11173 + }, + "previous_measurements": [ + { + "target": { + "size": 3376, + "relocation_count": 113, + "normalized_sha256": "3ce4fcfdbd126174185b73ca92843cb6f68335fafddd54599a1b8cbf392748ef" + }, + "base": { + "size": 3408, + "relocation_count": 112, + "normalized_sha256": "d42e420f90156644a2ebac2bc234df8017efbb0c8c8fe22fb79a7a02e3ad3e07" + }, + "objdiff_percent": 88.8082 + } + ] }, { "unit": "source/units/bipeds", @@ -323,7 +338,7 @@ "unit": "source/structures/structure_lens_flares", "function": "_build_structure_lens_flares", "class": "instruction-scheduling", - "evidence": "Fuzzy-parked under the current house rule after retaining the coherent Fable witness topology and authenticating the private name compare_temp_markers from the September 2001 cachebeta linker map in the local Halo symbol atlas. Target and candidate have the same 4336-byte padded envelope, 156 relocations, and 1327 decoded instructions; three sibling functions and all owned data are strict exact. The remaining differences are instruction scheduling and local/register lifetime choices in the recovered plane/grid packet, which also move several relocation positions while preserving the call and constant topology. The retained source uses project real/plane types, named shader enum constants, the witnessed scoped ds_x temporary, and the late offset assignment. It expands the three scalar point updates directly to preserve the January inline schedule without emitting a point_from_line3d COMDAT. The candidate-only 32-byte fast_ftol helper COMDAT is authenticated shared helper code but receives no object-completion credit. The closest shared structures header was rejected because the correct void prototype regressed protected units.obj from 189/189 to 188/189 through VC7 definition-position sensitivity; a dedicated natural owner header preserves both units.obj and hs.obj while removing the use-site prototype. No volatile access, compiler barrier, artificial alias, wrong fi4 cast, address-derived name, fake dependency, undefined behavior, assembly, or nonsensical control flow is retained. Reopen only for authoritative January source/local records or a natural same-compiler scheduling donor.", + "evidence": "Fuzzy-parked under the current house rule after retaining the coherent Fable witness topology and authenticating the private name compare_temp_markers from the September 2001 cachebeta linker map in the local Halo symbol atlas. Target and candidate have the same 4336-byte padded envelope, 156 relocations, and 1327 decoded instructions; three sibling functions and all owned data are strict exact. The remaining differences are instruction scheduling and local/register lifetime choices in the recovered plane/grid packet, which also move several relocation positions while preserving the call and constant topology. The retained source uses project real/plane types, named shader enum constants, the witnessed scoped ds_x temporary, and the late offset assignment. It expands the three scalar point updates directly to preserve the January inline schedule without emitting a point_from_line3d COMDAT. The candidate-only 32-byte fast_ftol helper COMDAT is authenticated shared helper code but receives no object-completion credit. The closest shared structures header was rejected because the correct void prototype regressed protected units.obj from 189/189 to 188/189 through VC7 definition-position sensitivity; a dedicated natural owner header preserves both units.obj and hs.obj while removing the use-site prototype. No volatile access, compiler barrier, artificial alias, wrong fi4 cast, address-derived name, fake dependency, undefined behavior, assembly, or nonsensical control flow is retained. Reopen only for authoritative January source/local records or a natural same-compiler scheduling donor. 2026-10-02 canonical reconciliation of approved plane-helper packet 78294dd3: outer helper parentheses removed with the independently attested item_accelerate repair; this existing residual body is otherwise untouched. Fresh canonical measurement, not donor measurement; prior rejection/reopen evidence and measurement retained. Zero exact credit; pill-parenthesis and other recorded holds remain in force.", "measurements": { "target": { "size": 4336, @@ -333,10 +348,25 @@ "base": { "size": 4336, "relocation_count": 156, - "normalized_sha256": "57d6f033f379373528ec40ed132b8af7db73b6f1a087be9ddc3ad2f30d55fc46" + "normalized_sha256": "fc22b7884f6f4762052a743b00dbd529c8112843538187404db2af8dd18e9a5e" }, - "objdiff_percent": 99.29274 - } + "objdiff_percent": 99.198944 + }, + "previous_measurements": [ + { + "target": { + "size": 4336, + "relocation_count": 156, + "normalized_sha256": "40aa8e486e52fe258065ae9cc9bd892679b15fd7845008cc0ebe1651788cf33b" + }, + "base": { + "size": 4336, + "relocation_count": 156, + "normalized_sha256": "57d6f033f379373528ec40ed132b8af7db73b6f1a087be9ddc3ad2f30d55fc46" + }, + "objdiff_percent": 99.29274 + } + ] }, { "unit": "source/tool/connected_geometry", @@ -661,30 +691,11 @@ "objdiff_percent": 86.4106 } }, - { - "unit": "source/physics/collision_bsp", - "function": "_bsp3d_test_sphere_recursive", - "class": "unclassified", - "evidence": "Fuzzy-parked under the current house rule after reconstructing the complete typed recursive 3D BSP sphere traversal and recovering its semantic private name from independent HCEA and Stian evidence. January COFF remains the sole byte authority. The retained function descends single-sided nodes, recursively visits both sides while maintaining the authenticated 128-entry signed plane stack, records overlapping leaves, resolves matching 2D references, projects the sphere center, and invokes the reconstructed 2D walker. Audit retracted the earlier claim that the residual was three equivalent unordered-value branch encodings: the shared projection_from_vector3d body actually selected the wrong axis for x- or y-dominant vectors, and different x87 unordered branches are not generally equivalent for NaNs. The retained named-axis conditional implements the HCEA semantics and matches January's dominant-axis comparisons instruction-for-instruction, including their unordered/NaN behavior, while direct projected-point and sign expressions avoid non-target _point_from_line3d, _projection_from_vector3d, and _projection_sign_from_vector3d COMDATs. January's embedded real_math.h assertion string and line prove that projection-sign logic was expanded in this caller even though no helper section exists in the target. Target and candidate both occupy 800 padded bytes and carry the same 22 ordered relocation identities; the candidate has 290 instructions versus January's 287 and objdiff reports 99.08602 percent similarity. The remaining aligned differences are a commutative y/z plane-distance evaluation order and the natural byte boolean's mov al/xor al sequence versus January's 32-bit mov eax/xor eax sequence; the latter shifts the final two call relocations three bytes earlier and leaves three bytes of alignment padding. The conservative unclassified label reflects that this is not instruction scheduling alone. No forced inline, shared-header edit, optimizer control, representation cast, assembly, fake dependency, undefined behavior, or nonsensical branch is retained. Reopen for authoritative January source or a natural type/helper context that accounts for the 32-bit boolean materialization without reintroducing non-target COMDATs or changing the protected January inline schedule. On September 14 (lane opus/100k-consolidated-20260914, wave D, adversarially verified) the parked body was refreshed to the helper-form reconstruction with January's 287-instruction count (800 bytes, 22 relocations), still fuzzy, alongside the exact bsp2d sphere/pill reopens. See docs/object_matching_logs/collision_bsp_obj_opus5_100k_waveD_20260914.md.", - "measurements": { - "target": { - "size": 800, - "relocation_count": 22, - "normalized_sha256": "35304d9cd3dbf061092fc383fa53e18c78003d1c12cb9cddce7cf9b6e69381ed" - }, - "base": { - "size": 800, - "relocation_count": 22, - "normalized_sha256": "947b581780131f4c0dd9d48e75bd08ef8a29d7e7c9b07aac8df7adaff8665574" - }, - "objdiff_percent": 99.985664 - } - }, { "unit": "source/physics/collision_bsp", "function": "_bsp3d_test_pill_recursive", "class": "unclassified", - "evidence": "Complete typed private 3D BSP pill traversal reconstructed from January disassembly with independent HCEA corroboration. It preserves the authenticated traversal stack, real_math assertion, semantic projection state, leaf/reference walks, surface/edge tests and global projection mapping while expanding natural math at call sites so no target-absent helper or point_from_line3d owner is emitted. The target is 1504 padded bytes with 31 relocations; the natural candidate is 1472 with 28 relocations and objdiff is 85.46875 percent. The structural schedule remains fuzzy and receives zero exact credit. Reopen only for authoritative January source or genuine compiler-context evidence, never fake dependencies, forced inlining, raw offsets or nonsensical logic. On September 14 (lane opus/100k-consolidated-20260914, wave D, adversarially verified) the parked body was refreshed with the projection_sign helper and a third project_point3d call (size and relocation count now equal the target, 1504 bytes, 31 relocations), still fuzzy. See docs/object_matching_logs/collision_bsp_obj_opus5_100k_waveD_20260914.md.", + "evidence": "Complete typed private 3D BSP pill traversal reconstructed from January disassembly with independent HCEA corroboration. It preserves the authenticated traversal stack, real_math assertion, semantic projection state, leaf/reference walks, surface/edge tests and global projection mapping while expanding natural math at call sites so no target-absent helper or point_from_line3d owner is emitted. The target is 1504 padded bytes with 31 relocations; the natural candidate is 1472 with 28 relocations and objdiff is 85.46875 percent. The structural schedule remains fuzzy and receives zero exact credit. Reopen only for authoritative January source or genuine compiler-context evidence, never fake dependencies, forced inlining, raw offsets or nonsensical logic. On September 14 (lane opus/100k-consolidated-20260914, wave D, adversarially verified) the parked body was refreshed with the projection_sign helper and a third project_point3d call (size and relocation count now equal the target, 1504 bytes, 31 relocations), still fuzzy. See docs/object_matching_logs/collision_bsp_obj_opus5_100k_waveD_20260914.md. 2026-10-02 canonical reconciliation of approved plane-helper packet 78294dd3: outer helper parentheses removed with the independently attested item_accelerate repair; this existing residual body is otherwise untouched. Fresh canonical measurement, not donor measurement; prior rejection/reopen evidence and measurement retained. Zero exact credit; pill-parenthesis and other recorded holds remain in force.", "measurements": { "target": { "size": 1504, @@ -694,10 +705,25 @@ "base": { "size": 1504, "relocation_count": 31, - "normalized_sha256": "0f9c2342ca7c0c0dc86469278e10d2526e247e35eb5dc2b1be4a923e2e196019" + "normalized_sha256": "031415cd3980a89088bc4236acd786b07efd74a6907ca74cb342453430536358" }, - "objdiff_percent": 97.21691 - } + "objdiff_percent": 98.086395 + }, + "previous_measurements": [ + { + "target": { + "size": 1504, + "relocation_count": 31, + "normalized_sha256": "057a2c8bfb82a96726d0e834b8c8724e71bfa42180cb31b7dab6f725f154667c" + }, + "base": { + "size": 1504, + "relocation_count": 31, + "normalized_sha256": "0f9c2342ca7c0c0dc86469278e10d2526e247e35eb5dc2b1be4a923e2e196019" + }, + "objdiff_percent": 97.21691 + } + ] }, { "unit": "source/units/bipeds", @@ -748,17 +774,6 @@ "objdiff_percent": 54.791668 } }, - { - "unit": "source/physics/physics", - "function": "_compute_ground_plane", - "class": "instruction-scheduling", - "evidence": "Complete typed ground-plane reconstruction retained at 336 padded bytes and 14 relocations on both sides. January/HCEA behavior, named collision flags, typed definition access, and cseries flag macros are preserved. The remaining normalized-code delta is ordinary instruction scheduling; no raw layout, compiler anchor, or fake branch is retained. Zero exact credit. See docs/object_matching_logs/claude_fable_opus_reconciliation_checkpoint_20260908.md.", - "measurements": { - "target": { "size": 336, "relocation_count": 14, "normalized_sha256": "edeff771d101548840cb5f3b2949765f5455b6e452e22f5f4ba90d79ca918ad2" }, - "base": { "size": 336, "relocation_count": 14, "normalized_sha256": "ea2976dc239424a039b1757b5205221fb153ff5c44f73a792260dae2868c6aa4" }, - "objdiff_percent": 96.61404 - } - }, { "unit": "source/physics/physics", "function": "_physics_compute_new", @@ -977,12 +992,35 @@ "unit": "source/math/geometry", "function": "_convex_polygon3d_clip_to_plane", "class": "unclassified", - "evidence": "Complete typed 3D convex-polygon plane clipping reconstruction retained from the reconciled Fable geometry packet with its declarations in the Geometry owner header. Target and candidate share the 1120-byte extent and all 26 relocations but remain normalized-code residuals. No representation punning, artificial branch shape, or helper-ownership trick is admitted; zero credit. Donor provenance: commit f9dd42218.", + "evidence": "Complete typed 3D convex-polygon plane clipping reconstruction retained from the reconciled Fable geometry packet with its declarations in the Geometry owner header. Target and candidate share the 1120-byte extent and all 26 relocations but remain normalized-code residuals. No representation punning, artificial branch shape, or helper-ownership trick is admitted; zero credit. Donor provenance: commit f9dd42218. 2026-10-02 canonical reconciliation of approved plane-helper packet 78294dd3: outer helper parentheses removed with the independently attested item_accelerate repair; this existing residual body is otherwise untouched. Fresh canonical measurement, not donor measurement; prior rejection/reopen evidence and measurement retained. Zero exact credit; pill-parenthesis and other recorded holds remain in force.", "measurements": { - "target": { "size": 1120, "relocation_count": 26, "normalized_sha256": "0d106198b6d9ccb8c0d74d8af566876f04b2610ae714fb5cabb28254b33e0d20" }, - "base": { "size": 1120, "relocation_count": 26, "normalized_sha256": "9c1611d216717b6d0ba6792f37f6dde55d3fbbffac81c875f48a0e934072f6a3" }, - "objdiff_percent": 80.76382 - } + "target": { + "size": 1120, + "relocation_count": 26, + "normalized_sha256": "0d106198b6d9ccb8c0d74d8af566876f04b2610ae714fb5cabb28254b33e0d20" + }, + "base": { + "size": 1120, + "relocation_count": 26, + "normalized_sha256": "e9f7ac9898e8768f75c696cbc236a6a03de61a2e69f61329d47b321ea4d113ad" + }, + "objdiff_percent": 82.37186 + }, + "previous_measurements": [ + { + "target": { + "size": 1120, + "relocation_count": 26, + "normalized_sha256": "0d106198b6d9ccb8c0d74d8af566876f04b2610ae714fb5cabb28254b33e0d20" + }, + "base": { + "size": 1120, + "relocation_count": 26, + "normalized_sha256": "9c1611d216717b6d0ba6792f37f6dde55d3fbbffac81c875f48a0e934072f6a3" + }, + "objdiff_percent": 80.76382 + } + ] }, { "unit": "libs/libcmt/frnd", diff --git a/source/items/items.c b/source/items/items.c index 3e2c7c0c..7b1ab9c4 100644 --- a/source/items/items.c +++ b/source/items/items.c @@ -421,7 +421,6 @@ void item_accelerate( { real acceleration_magnitude = magnitude3d(acceleration); real_vector3d rotation_axis; - double rotation_magnitude; if (acceleration_magnitude < 0.0001f) { @@ -437,10 +436,10 @@ void item_accelerate( &rotation_axis); } - rotation_magnitude = - real_seed_random(get_global_random_seed_address()) * - acceleration_magnitude * 1.5707964f; - scale_vector3d(&rotation_axis, (real)rotation_magnitude, &rotation_axis); + scale_vector3d( + &rotation_axis, + real_seed_random(get_global_random_seed_address()) * 1.5707964f * acceleration_magnitude, + &rotation_axis); add_vectors3d( &item->object.angular_velocity, &rotation_axis, diff --git a/source/math/real_math.h b/source/math/real_math.h index 80ff069e..7dd225b8 100644 --- a/source/math/real_math.h +++ b/source/math/real_math.h @@ -1553,7 +1553,7 @@ __inline real plane3d_distance_to_point( real_plane3d const *plane, real_point3d const *point) { - return (dot_product3d((real_vector3d *)point, &plane->n) - plane->d); + return dot_product3d((real_vector3d *)point, &plane->n) - plane->d; } #endif From 09255f0e789d888217452b4f9e607d6ed21a7ce2 Mon Sep 17 00:00:00 2001 From: Jonas Volman Date: Fri, 2 Oct 2026 00:44:12 -0700 Subject: [PATCH 04/17] Reconcile main static storage: +1 exact function, zero losses Approved coherent packet 41640b4d, independently clean-built after transport and plane-helper reconciliation. +538 meaningful / +544 padded bytes; main 95/95. Replace the invented packed aggregate with January's separate storage, add exactly eight private symbol rows and retire the frame-rate park. Names, six static scopes and exact main_game_render placement remain disclosed as inferred. Full stable sweep, parks, admission, fake scan and 1663 tools tests pass; no new warnings, data, objects or providers. Cumulative reconciliation +5 functions, +2121 meaningful / +2144 padded bytes, zero exact losses. Preserve dirty README and unrelated research. No PCH, scorer, verifier, status or held-source changes. Detailed independent receipts and limits recorded in docs/object_matching_logs/upstream_tmp_reconcile_20261002.md. --- config/parked.json | 11 - config/symbols.json | 8 + ...main_obj_static_storage_packet_20261001.md | 87 +++++ .../upstream_tmp_reconcile_20261002.md | 95 +++++ source/main/main.c | 327 +++++++++--------- 5 files changed, 350 insertions(+), 178 deletions(-) create mode 100644 docs/object_matching_logs/main_obj_static_storage_packet_20261001.md create mode 100644 docs/object_matching_logs/upstream_tmp_reconcile_20261002.md diff --git a/config/parked.json b/config/parked.json index e3fe2f22..16949de9 100644 --- a/config/parked.json +++ b/config/parked.json @@ -917,17 +917,6 @@ "objdiff_percent": 95.241234 } }, - { - "unit": "source/main/main", - "function": "_main_frame_rate_debug", - "class": "unclassified", - "evidence": "Complete natural frame-rate diagnostic state machine retained from the 2026-09-09 Main packet. It uses the authenticated Main state, project types, and ordinary file/time APIs. The candidate is 528 padded bytes with 51 relocations versus January's 544 bytes and 52 relocations; the remaining code-generation difference is explicitly fuzzy. No barrier, volatile carrier, fake dependency, raw address, or exact-only branch is retained. Zero exact credit. See docs/object_matching_logs/main_obj_natural_state_and_render_packet_20260909.md. 2026-09-22: two January-attested corrections landed. The sample-index wrap is a SIGNED modulo in January (movsx/and 0x80000007/jns fixup), so NUMBEROF (size_t) was wrong and the divisor is a signed 8; this closed the whole 16-byte size gap and the candidate is now 544 padded bytes, exactly January's size. The slow-frame threshold literal is 0.036000000000000004 (__real@3fa26e978d4fdf3c), one ULP above the decimal 0.036 we had, so January's source folds an expression rather than writing the decimal; spelled 1.08/TICKS_PER_SECOND, which reproduces the constant exactly. The remaining residual is one duplicated framerate_sample_index load that January's jump-threading emits on the debug-true edge (51 vs 52 relocations) plus the register assignment that follows from it. 2026-09-24 (fifty-objects lane batch 4b): re-baselined after the reviewed zero-credit packet; see docs/object_matching_logs/claude_fifty_objects_20260925.md.", - "measurements": { - "target": { "size": 544, "relocation_count": 52, "normalized_sha256": "17546b1f02410f30e6fc728300d275c40d65bf6cb6a35a096a8d735f96512d83" }, - "base": { "size": 544, "relocation_count": 51, "normalized_sha256": "3c132f904203944a7f5f7c3b746a7458964f073c1fc4374aba0988bb5f3db4ff" }, - "objdiff_percent": 98.65385 - } - }, { "unit": "source/interface/motion_sensor", "function": "_motion_sensor_update", diff --git a/config/symbols.json b/config/symbols.json index a1ca2d62..deff2f41 100644 --- a/config/symbols.json +++ b/config/symbols.json @@ -23099,6 +23099,14 @@ { "file_offset": 4546085, "flags": 0, "name": "_display_vblank_deltas" }, { "file_offset": 4546086, "flags": 0, "name": "_display_precache_progress" }, { "file_offset": 4546088, "flags": 0, "name": "_global_screenshot_count" }, +{ "file_offset": 4546096, "flags": 0, "name": "?window@?1??main_game_render@@9@9", "static": true }, +{ "file_offset": 4546956, "flags": 0, "name": "?last_spf@?1??main_frame_rate_debug@@9@9", "static": true }, +{ "file_offset": 4546988, "flags": 0, "name": "?bad_frame_flags@?1??main_frame_rate_debug@@9@9", "static": true }, +{ "file_offset": 4546990, "flags": 0, "name": "?current_spf_index@?1??main_frame_rate_debug@@9@9", "static": true }, +{ "file_offset": 4546991, "flags": 0, "name": "?wait_for_good_framerate@?1??main_frame_rate_debug@@9@9", "static": true }, +{ "file_offset": 4546992, "flags": 0, "name": "?good_framerate_count@?1??main_frame_rate_debug@@9@9", "static": true }, +{ "file_offset": 4546993, "flags": 0, "name": "?need_to_initialize@?1??main_frame_rate_debug@@9@9", "static": true }, +{ "file_offset": 4546994, "flags": 0, "name": "?recursion_lock@?1??halt_and_catch_fire@@9@9", "static": true }, { "file_offset": 4546995, "flags": 0, "name": "_warned_about_duplicate_triangles", "static": true }, { "file_offset": 4546996, "flags": 0, "name": "_error_geometry_file", "static": true }, { "file_offset": 4547000, "flags": 0, "name": "_integer_origin2d", "static": true }, diff --git a/docs/object_matching_logs/main_obj_static_storage_packet_20261001.md b/docs/object_matching_logs/main_obj_static_storage_packet_20261001.md new file mode 100644 index 00000000..0e2b4711 --- /dev/null +++ b/docs/object_matching_logs/main_obj_static_storage_packet_20261001.md @@ -0,0 +1,87 @@ +# main.obj static-storage packet, 2026-10-01 + +Lane `claude/remaining-frontier-20260926`. Independently reconciled on canonical on 2026-10-02; +see `upstream_tmp_reconcile_20261002.md` for the fresh clean-build gate and canonical measurements. +Owner rulings Q-UP4 (measure), Q-UP5 (land as measured) and Q-UP6 (names), 2026-10-01. Donor shape: +punpckhdq/halo pull request #84 (`a5ad6b2c`, CC0), rewritten with the lane's text and checked against January. +Research record: `research/remaining_frontier_20260926/lead/upstream_punpck/cards/UP-10_main_static_storage.md`. + +| Function | Meaningful bytes | Padded bytes | Relocations | +| --- | ---: | ---: | ---: | +| `_main_frame_rate_debug` | 538 | 544 | 52 | + +## What changed + +- `source/main/main.c` + - The packed 0x38B-byte `struct _screenshot_and_framerate_globals` (with `byte reserved002[6]` and a `pack(1)` + pragma) and its size assert are removed. January has nine separately aligned objects there. + - `short global_screenshot_count = 0;` at file scope. Three other units already declare it `extern short`, and + January's script-global table types it `_hs_type_short_integer`. + - `main_game_render`: `static struct render_window window[MAXIMUM_LOCAL_PLAYERS + 1] = { 0 };`. The function + moves up, directly after `main_get_window_count`; `screenshot_render` gets a prototype because it is now + called before its definition. The pointer local is renamed `current_window`. + - `main_frame_rate_debug`: a local enum (`NUMBER_OF_FRAME_SAMPLES = 8`, `RUNS_BEFORE_RESET = 60`), six static + locals, and the natural body: `if (need_to_initialize && !debug_frame_rate) { clear }` then + `if (debug_frame_rate) { ... }`, with direct access to the statics. The hand-threaded `sample_index` local, the + two early returns and the `(char)(... % (long)NUMBEROF(...))` casts are gone. + - `halt_and_catch_fire`: `static boolean recursion_lock = FALSE;`. +- `config/symbols.json`: eight `"static": true` rows for the January addresses of the new statics (line surgery, + directly after `_global_screenshot_count`). +- `config/parked.json`: the `_main_frame_rate_debug` park is retired. + +No padding member, filler declaration or pragma is added. No compiler flag, scorer or credit rule changes. + +## Evidence + +| Claim | Status | Basis | +| --- | --- | --- | +| The public symbol is a `short` | proven | word-width access at +0 in ten functions of three objects; the script-global table | +| The span is nine objects, not one aggregate | proven by a controlled ablation | the same body on the packed struct is residual at all 64 C1 shifts: VC7 keeps a scalar static in a register across the two `if` statements (January's `xor dl, dl`, `mov dl, [index]`, `movsx ecx, dl`) and reloads a struct member from memory | +| Sizes, widths, signedness and `.bss` offsets (+0x6D8, +0x6E0, +0xA3C, +0xA5C, +0xA5E..+0xA62; section 0xA63) | proven | January's references and access widths; the rebuilt object has every object at January's offset | +| The 6-byte hole at +0x6DA | explained | ordinary 8-byte alignment of the array; nothing references it anywhere on the board | +| Internal linkage of the eight statics | proven | January's PDB lists no public symbol in the span | +| Explicit zero initialisers and the declaration order | measured by perturbation | without the initialisers the statics move to the front of `.bss` in name-hash order (section 0xA65) | +| Two stores of zero to the reset flag | proven | January +0x25 (before the `csmemset` call) and +0x4E | +| The values 8 and 60 | proven | 0x20-byte array, `and eax, 0x80000007` with the signed fixup, `cmp al, 0x3c` | +| `window`: name, type, function scope, local players + 1 | attested by later first-party builds | PC demo PDB 2003 (`[2]`), HCEX PDBs 2011 (`[3]`); January has five | +| `recursion_lock`: name, type, function scope | attested by a later first-party build | HCEX_Release.pdb 2011 | +| Function scope of the six frame-rate statics | INFERRED | each is referenced by this one function; the two attested neighbours are function-local; file scope gives identical bytes | +| The six frame-rate names and the two constant names | INFERRED descriptive names, not recovered Bungie names | no later build keeps the function body; every spelling gives identical bytes | +| `main_game_render` before `main_frame_rate_debug` and before `screenshot_render` | measured | `.bss` declaration order; January emits the function one sweep after `screenshot_render` (VC7 emits callee first, in repeated textual sweeps) | +| The exact line of `main_game_render` | INFERRED | PR #84's relative position, directly after `main_get_window_count` | +| `current_window` | descriptive | the attested static takes the name `window`; no PDB records the pointer local | +| The threshold spelling `1.08/TICKS_PER_SECOND` | unchanged, a disclosed choice | it folds to January's constant | + +## Not part of this packet + +- `scenario_paths` (a function-local static in the 2011 PDB only): untouched. +- Precompiled-header settings: untouched. January's `main.obj` function order shows the precompiled-header + pattern; that is recorded as research evidence only. +- `main`'s object admission: untouched. `main` stays NonMatching; its `.data` keeps the 2026-09-27 semantic + exception (+52). +- The lane's function order elsewhere in `main.c`, and the later-PDB local names of `main_game_render`. + +This is a narrow packet approval, not a general permission for function moves or guessed globals. + +## Original lane gate + +Measured first in a shadow of lane HEAD `78294dd3` (checkpoint `SH_VA` against `SH_P`), then gated fresh in the +lane: `R114i_M` against `R113i_P` (incremental build, objdiff 3.3.1). Zero exact losses. + +- Stable diff: gained 1 (544 padded bytes), regressions 0. +- Functions 7,479 -> 7,480 of 7,573. Code 1,601,295 -> 1,601,833 of 1,770,166 (+538 meaningful bytes). +- Data 3,311,591 / 3,922,163 and objects 396 / 468 unchanged. +- Strict section owners 7,652 -> 7,653 of 8,252. +- Parks 62 -> 61, 0 stale, 0 invalid. Admission candidates 8 -> 9 (`source/main/main` becomes an audit candidate + only; no status flip), 0 contradicted, 0 rejected. +- Tools tests 1,700 passed, 5 skipped. Fake-match scan: the same 26 inherited leads. Whitespace checks pass. +- One object differs on the whole board, `main.obj` (1 of 621). By content, three code sections differ: + `_main_frame_rate_debug` (the gain) and `_halt_and_catch_fire`, `_main_game_render`, whose relocation targets + change from `_global_screenshot_count+N` to the statics' own symbols with the same destinations. Both stay + exact. Six sections change position with identical content: `_main_game_render`, `_create_local_players` and + the latter's four assert literals. The compiler emits the moved function later, so the two swap places. +- /W3 4,082 = 4,082, no unit differs. /W4 for `main.c` 90 = 90. +- Without the eight symbol rows `main` `.bss` would score 82.94% and the progress step would fail; they are part + of the packet. +- C1 shift sweep (diagnostic only): `_main_frame_rate_debug` is exact at all 64 shifts, so the result does not + depend on a declaration count. diff --git a/docs/object_matching_logs/upstream_tmp_reconcile_20261002.md b/docs/object_matching_logs/upstream_tmp_reconcile_20261002.md new file mode 100644 index 00000000..0606c9ed --- /dev/null +++ b/docs/object_matching_logs/upstream_tmp_reconcile_20261002.md @@ -0,0 +1,95 @@ +# Transport, plane helper and main static-storage reconciliation — 2026-10-02 + +Independently reconciled against canonical `5e55d8f83ad7142962946b8a023d9638cd900b69` on +`jonas/exact-pilots`. Three owner-approved coherent packets were applied separately, with a fresh +clean build and full gate after each. No whole-lane merge or unpublished research was imported. + +| Packet | Donor commit | Canonical commit | Exact functions | Meaningful / padded code gain | +| --- | --- | --- | ---: | ---: | +| T, transport | `e191c0f1436939f5a98c088b1dfb46e2c336cc0d` | `25f719236d4bec7621357e89b95e02b006824727` | 2 | 457 / 464 B | +| P, plane helper | `78294dd367ca3014ddd2eda28cd5744a2ef386aa` | `38fdd8cb2431d1cc4793d40f9a4e21e81c040136` | 2 | 1,126 / 1,136 B | +| M, main storage | `41640b4db320570d38173f9620cd0eab1a0f2d0d` | this commit | 1 | 538 / 544 B | + +## Exact section receipts + +All five fresh canonical sections are strictly identical to their January split counterparts, +including relocation identities. The SHA-256 values below are normalized by the unchanged strict +COFF comparator, not hashes of a linked executable. + +| Function | Meaningful B | Padded B | Relocations | Normalized SHA-256 | +| --- | ---: | ---: | ---: | --- | +| `_transport_initialize` | 416 | 416 | 33 | `47bd2187b394eb1f7975b4bc618fc0d041f563687eb841257fcae4296bd71db0` | +| `_poll_ep_array_compare_proc` | 41 | 48 | 0 | `10d0cbdd04c0ad15a3cd14bffdde707c085ce85c4b9fed4c036fb4c103ca9c55` | +| `_compute_ground_plane` | 334 | 336 | 14 | `edeff771d101548840cb5f3b2949765f5455b6e452e22f5f4ba90d79ca918ad2` | +| `_bsp3d_test_sphere_recursive` | 792 | 800 | 22 | `35304d9cd3dbf061092fc383fa53e18c78003d1c12cb9cddce7cf9b6e69381ed` | +| `_main_frame_rate_debug` | 538 | 544 | 52 | `17546b1f02410f30e6fc728300d275c40d65bf6cb6a35a096a8d735f96512d83` | +| Total | 2,121 | 2,144 | | | + +## Source-policy scope + +- T changes the return type to `long` in both the owner header and definition, consistent with + January's full-EAX return. The repeated startup stores and natural single-exit/callback form are + reconstructed from the approved evidence. No shared declaration was moved merely to steer bytes. +- P removes only the outer parentheses of the approved plane helper, preserving the `/Od` argument + order. Its coupled `_item_accelerate` repair removes the unattested double local and passes the + float expression directly in the attested order. The entire items object remains identical. +- M replaces the invented packed aggregate and six padding bytes with January's nine objects. + `window` and `recursion_lock` are later-first-party-attested function-local statics. The six + frame-rate statics' function scope, their six names, two enum identifiers, `current_window`, and + the exact textual position of `main_game_render` remain disclosed as inferred/descriptive as + narrowly approved. Explicit zero initializers reproduce declaration-order storage. The eight + private symbol rows and the exact function's park retirement are in the same commit. +- No new assembly, cast device, padding, filler, pragma, compiler flag, PCH change, scorer change, + verifier change, semantic exception or object status flip was introduced. DD2, DD3, the ai_debug + casts, pill parentheses and other held forms remain held and unchanged. `scenario_paths` is + untouched. Main remains NonMatching; 95/95 exact functions are not a whole-object admission. + +## Canonical park reconciliation + +The five exact entries were retired with their source changes. Four residuals affected by P were +remeasured on canonical rather than copied from the lane. Their original rejection/reopen text and +previous measurements are retained in `config/parked.json`. These receive no exact credit. + +| Residual | Previous objdiff % | Fresh canonical % | Size / relocations | +| --- | ---: | ---: | ---: | +| `_render_camera_build_frustum` | 88.8082 | 90.11173 | 3,408 / 112 | +| `_bsp3d_test_pill_recursive` | 97.21691 | 98.086395 | 1,504 / 31 | +| `_convex_polygon3d_clip_to_plane` | 80.76382 | 82.37186 | 1,120 / 26 | +| `_build_structure_lens_flares` | 99.29274 | 99.198944 | 4,336 / 156 | + +The lens-flare percentage decreases; its source is untouched and it was non-exact before and after. +The lane's separate unpublished fidelity rebaselines were not imported. + +## Fresh canonical gates + +Each packet passed: clean compile, progress, the unchanged 8,252-row strict stable sweep, parks, +object-admission audit, fake-match scan, tools tests and whitespace checks. + +- Exact sweep: +2 after T, +4 after T+P, +5 after T+P+M; zero regressions at every gate. +- Halo functions: 7,475 -> 7,480 of 7,573. +- Halo meaningful code: 1,599,712 -> 1,601,833 of 1,770,166 (+2,121). +- Halo data: unchanged at 3,311,591 / 3,922,163. Halo objects: unchanged at 396 / 468. +- Strict section-owner rows: 7,648 -> 7,653 of 8,252. Main is freshly strict exact 95/95. +- Parks: 66 -> 64 -> 62 -> 61, zero stale and zero invalid. +- Admission candidates: 8 -> 9 (main added as a review candidate only); no revocation or contradiction. +- Tests at every gate: 1,663 passed, 5 skipped, 159 subtests passed. The lane's 1,700 figure is not + claimed for this canonical tree; its additional unpublished tools changes were not imported. +- Fake-match scan: the same 26 inherited review leads. +- Fresh board-wide `/W3` compiles: 4,091 before and after, identical per unit and warning code over + all 612 CL targets. Fresh `/W4` checks across the nine affected units: 603 before and after, also + identical by unit/code (including main's 90). Existing warning locations may move with source. +- All 621 configured build objects plus the inherited extra libcmt/chkstk object were fingerprinted + at every checkpoint. T changes one object; P changes five objects/six text sections; M changes + only main.obj. No external/COMMON provider attribute changes or new helper copies occur. +- M's `.bss` is 0xA63, align 8, with the public short at +0x6D8 and eight class-3 objects at +0x6E0, + +0xA3C, +0xA5C and +0xA5E..+0xA62. The halt/render relocation target names change to these statics + without changing their destinations; both functions stay exact. Function/section order changes + are confined to the approved main packet. +- All tracked production files outside the seven approved source/config paths are hash-identical + to the baseline. The existing dirty README and unrelated untracked research were preserved. +- Q10 credit and all scorer/verifier pins are unchanged: 93 records, 661,012 bytes. This is bounded + object/section verification, not proof of a complete executable link or playability. + +Private full receipts are in `scratch/astra_tmp_reconcile_20261002/` (before, T, P, M gates; +warning compilations; object fingerprints; final scope/storage assertions). They include local +build artifacts and are not published. The approved production changes and this audit log are. diff --git a/source/main/main.c b/source/main/main.c index 590aa130..4c8b990f 100644 --- a/source/main/main.c +++ b/source/main/main.c @@ -636,25 +636,6 @@ struct game_options typedef char game_options_size_assert[ sizeof(struct game_options) == 0x10C ? 1 : -1]; -#pragma pack(push, 1) -struct _screenshot_and_framerate_globals -{ - short count; - byte reserved002[6]; - struct render_window windows[MAXIMUM_WINDOWS + 1]; - real framerate_samples[8]; - word framerate_flags; - char framerate_sample_index; - boolean framerate_active; - char framerate_counter; - boolean framerate_reset; - boolean halt_recursion_lock; -}; -#pragma pack(pop) - -typedef char screenshot_and_framerate_globals_size_assert[ - sizeof(struct _screenshot_and_framerate_globals) == 0x38B ? 1 : -1]; - /* ---------- prototypes */ static long sort_desired_local_player_controllers( @@ -675,6 +656,8 @@ static void main_new_map( struct game_options *options); static void main_game_render( double time_delta_since_tick_sec); +static void screenshot_render( + struct render_window *windows); /* ---------- globals */ @@ -705,7 +688,7 @@ boolean debug_frame_rate = FALSE; boolean display_framerate = FALSE; boolean display_vblank_deltas = FALSE; boolean display_precache_progress = FALSE; -struct _screenshot_and_framerate_globals global_screenshot_count = { 0 }; +short global_screenshot_count = 0; boolean debug_render_freeze; /* ---------- public code */ @@ -1180,7 +1163,7 @@ void main_present_frame( char path[512]; render_frame_present(NULL, main_globals.movie); - if (global_screenshot_count.count <= 0 && main_globals.movie) + if (global_screenshot_count <= 0 && main_globals.movie) { _snprintf( path, @@ -1406,6 +1389,110 @@ short main_get_window_count( return single_window ? 1 : PIN(local_player_count(), 1, MAXIMUM_WINDOWS); } +static void main_game_render( + double time_delta_since_tick_sec) +{ + /* Name, type and function scope from the 2003 PC demo PDB and the HCEX PDB (static local + struct render_window window[local players + 1] of main_game_render: two and three elements + there, five in January). January corroborates: .bss +0x6E0, 0x35C bytes, referenced only by + this function, declared after global_screenshot_count and before main_frame_rate_debug's + statics, with an explicit zero initialiser (an uninitialised static is placed first, by name + hash). That order, and January emitting this function a sweep after screenshot_render, put + the definition before both; its exact line is inferred. */ + static struct render_window window[MAXIMUM_LOCAL_PLAYERS + 1] = { 0 }; + boolean force_single_screen; + long window_index; + struct render_window *current_window; /* descriptive name; no PDB records this local */ + struct observer_result const *observer; + long player_window_count; + long window_count; + short last_local_player_index; + + lock_global_random_seed(); + collision_log_continue_period(TRUE); + sound_render(); + force_single_screen = game_engine_force_single_screen(); + last_local_player_index = NONE; + + window_count = PIN(local_player_count(), 1, MAXIMUM_LOCAL_PLAYERS); + player_window_count = window_count; + if (force_single_screen || cinematic_in_progress()) + { + window_count = 1; + player_window_count = 1; + } + + for (window_index = 0; window_index < player_window_count; window_index++) + { + current_window = &window[window_index]; + observer = NULL; + + compute_window_bounds( + window_index, + player_window_count, + ¤t_window->rasterizer_camera.viewport_bounds, + ¤t_window->rasterizer_camera.window_bounds); + if (force_single_screen) + { + current_window->local_player_index = NONE; + } + else if (window_index < window_count) + { + if (!rasterizer_debug_options.force_all_player_views_to_default_player || + last_local_player_index == NONE) + { + if (game_connection() == _game_connection_film_playback) + { + last_local_player_index = 0; + } + else + { + last_local_player_index = local_player_get_next(last_local_player_index); + } + } + + current_window->local_player_index = last_local_player_index; + observer = observer_get_camera(current_window->local_player_index); + } + else + { + current_window->local_player_index = NONE; + } + + set_window_camera_values(current_window, observer); + current_window->console_window = FALSE; + } + + current_window = &window[player_window_count]; + compute_window_bounds( + 0, + 1, + ¤t_window->rasterizer_camera.viewport_bounds, + ¤t_window->rasterizer_camera.window_bounds); + current_window->local_player_index = NONE; + current_window->console_window = TRUE; + set_window_camera_values(current_window, NULL); + + if (global_screenshot_count <= 0) + { + render_frame( + window, + player_window_count + 1, + NULL, + NULL, + main_globals.movie, + (real)time_delta_since_tick_sec); + } + else + { + screenshot_render(window); + } + + collision_log_end_period(); + unlock_global_random_seed(); + return; +} + static void main_new_map( struct game_options *options) { @@ -1615,7 +1702,7 @@ void main_queue_map_name( boolean main_taking_screenshot( void) { - return global_screenshot_count.count > 0 || main_globals.movie != NULL; + return global_screenshot_count > 0 || main_globals.movie != NULL; } void main_movie_start( @@ -1998,69 +2085,67 @@ static void main_run_demos_private( static void main_frame_rate_debug( void) { - char sample_index; + /* NUMBER_OF_FRAME_SAMPLES, RUNS_BEFORE_RESET and the six static names below are inferred + descriptive names, not recovered Bungie names: no later build keeps this function's body. + The values 8 and 60 are January's (a 0x20-byte sample array, a signed modulo by 8, a + compare with 60). So are the six objects: .bss +0xA3C..+0xA61 in this order, these types, + referenced only by this function, each with an explicit zero initialiser. Their function + scope is inferred from that and from the two attested static locals beside them. */ + enum + { + NUMBER_OF_FRAME_SAMPLES = 8, + RUNS_BEFORE_RESET = 60 + }; - if (global_screenshot_count.framerate_reset) + static real last_spf[NUMBER_OF_FRAME_SAMPLES] = { 0 }; + static word bad_frame_flags = 0; + static char current_spf_index = 0; + static boolean wait_for_good_framerate = FALSE; + static char good_framerate_count = 0; + static boolean need_to_initialize = FALSE; + + if (need_to_initialize && !debug_frame_rate) { - if (debug_frame_rate) - { - sample_index = global_screenshot_count.framerate_sample_index; - } - else - { - global_screenshot_count.framerate_reset = FALSE; - csmemset( - global_screenshot_count.framerate_samples, - 0, - sizeof(global_screenshot_count.framerate_samples)); - sample_index = 0; - global_screenshot_count.framerate_flags = 0; - global_screenshot_count.framerate_sample_index = sample_index; - global_screenshot_count.framerate_active = FALSE; - global_screenshot_count.framerate_counter = 0; - global_screenshot_count.framerate_reset = FALSE; - } - } - else - { - sample_index = global_screenshot_count.framerate_sample_index; + need_to_initialize = FALSE; + csmemset(last_spf, 0, sizeof(last_spf)); + bad_frame_flags = 0; + current_spf_index = 0; + wait_for_good_framerate = FALSE; + good_framerate_count = 0; + need_to_initialize = FALSE; /* January stores the flag a second time here */ } if (debug_frame_rate) { - global_screenshot_count.framerate_samples[sample_index] = - main_globals.seconds_elapsed; + last_spf[current_spf_index] = main_globals.seconds_elapsed; SET_FLAG( - global_screenshot_count.framerate_flags, - sample_index, + bad_frame_flags, + current_spf_index, main_globals.seconds_elapsed > 1.08/TICKS_PER_SECOND); - sample_index++; - sample_index = (char)(sample_index % (long)NUMBEROF(global_screenshot_count.framerate_samples)); - global_screenshot_count.framerate_sample_index = sample_index; - global_screenshot_count.framerate_reset = TRUE; + current_spf_index++; + current_spf_index %= NUMBER_OF_FRAME_SAMPLES; + need_to_initialize = TRUE; - if (global_screenshot_count.framerate_active) + if (wait_for_good_framerate) { - if (global_screenshot_count.framerate_sample_index == 0) + if (current_spf_index == 0) { - if (global_screenshot_count.framerate_flags == 0) + if (bad_frame_flags == 0) { - if (++global_screenshot_count.framerate_counter >= 60) + if (++good_framerate_count >= RUNS_BEFORE_RESET) { - global_screenshot_count.framerate_counter = 0; - global_screenshot_count.framerate_active = FALSE; - return; + good_framerate_count = 0; + wait_for_good_framerate = FALSE; } } else { - global_screenshot_count.framerate_counter = 0; - return; + good_framerate_count = 0; } } } - else if (global_screenshot_count.framerate_flags == 0xFF) + else if (bad_frame_flags == 0xFF) { SYSTEMTIME system_time; char core_name[256]; @@ -2098,7 +2183,7 @@ static void main_frame_rate_debug( fprintf(file, ";core_load_name_at_startup %s\n", core_name); fflush(file); fclose(file); - global_screenshot_count.framerate_active = TRUE; + wait_for_good_framerate = TRUE; } } @@ -2593,11 +2678,11 @@ static void screenshot_render( console_close(); for (screenshot_page_index.y = 0; - screenshot_page_index.y < global_screenshot_count.count; + screenshot_page_index.y < global_screenshot_count; screenshot_page_index.y++) { for (screenshot_page_index.x = 0; - screenshot_page_index.x < global_screenshot_count.count; + screenshot_page_index.x < global_screenshot_count; screenshot_page_index.x++) { for (screenshot_index.y = 0; @@ -2608,7 +2693,7 @@ static void screenshot_render( screenshot_index.x < global_screenshot_size; screenshot_index.x++) { - if (global_screenshot_count.count > 1 || + if (global_screenshot_count > 1 || global_screenshot_size > 1) { render_frame( @@ -2643,7 +2728,7 @@ static void screenshot_render( bitmap_delete(bitmap); } - global_screenshot_count.count = 0; + global_screenshot_count = 0; return; } @@ -2764,16 +2849,20 @@ void main_framerate_render( void halt_and_catch_fire( void) { + /* Name, type and function scope from the HCEX PDB (static local unsigned char recursion_lock + of halt_and_catch_fire). January corroborates: .bss +0xA62, the last byte of the section, + referenced only by this function, explicitly zero-initialised. */ + static boolean recursion_lock = FALSE; short gamepad_index; long font_tag_index; struct scenario *scenario; struct rasterizer_frame_begin_parameters frame_parameters; struct rasterizer_window_begin_parameters window_parameters; - if (!global_screenshot_count.halt_recursion_lock) + if (!recursion_lock) { scenario = global_scenario_try_and_get(); - global_screenshot_count.halt_recursion_lock = TRUE; + recursion_lock = TRUE; for (gamepad_index = 0; gamepad_index < MAXIMUM_GAMEPADS; gamepad_index++) { if (input_has_gamepad(gamepad_index)) @@ -2895,102 +2984,6 @@ void main_loop_of_death( return; } -static void main_game_render( - double time_delta_since_tick_sec) -{ - boolean force_single_screen; - long window_index; - struct render_window *window; - struct observer_result const *observer; - long player_window_count; - long window_count; - short last_local_player_index; - - lock_global_random_seed(); - collision_log_continue_period(TRUE); - sound_render(); - force_single_screen = game_engine_force_single_screen(); - last_local_player_index = NONE; - - window_count = PIN(local_player_count(), 1, MAXIMUM_LOCAL_PLAYERS); - player_window_count = window_count; - if (force_single_screen || cinematic_in_progress()) - { - window_count = 1; - player_window_count = 1; - } - - for (window_index = 0; window_index < player_window_count; window_index++) - { - window = &global_screenshot_count.windows[window_index]; - observer = NULL; - - compute_window_bounds( - window_index, - player_window_count, - &window->rasterizer_camera.viewport_bounds, - &window->rasterizer_camera.window_bounds); - if (force_single_screen) - { - window->local_player_index = NONE; - } - else if (window_index < window_count) - { - if (!rasterizer_debug_options.force_all_player_views_to_default_player || - last_local_player_index == NONE) - { - if (game_connection() == _game_connection_film_playback) - { - last_local_player_index = 0; - } - else - { - last_local_player_index = local_player_get_next(last_local_player_index); - } - } - - window->local_player_index = last_local_player_index; - observer = observer_get_camera(window->local_player_index); - } - else - { - window->local_player_index = NONE; - } - - set_window_camera_values(window, observer); - window->console_window = FALSE; - } - - window = &global_screenshot_count.windows[player_window_count]; - compute_window_bounds( - 0, - 1, - &window->rasterizer_camera.viewport_bounds, - &window->rasterizer_camera.window_bounds); - window->local_player_index = NONE; - window->console_window = TRUE; - set_window_camera_values(window, NULL); - - if (global_screenshot_count.count <= 0) - { - render_frame( - global_screenshot_count.windows, - player_window_count + 1, - NULL, - NULL, - main_globals.movie, - (real)time_delta_since_tick_sec); - } - else - { - screenshot_render(global_screenshot_count.windows); - } - - collision_log_end_period(); - unlock_global_random_seed(); - return; -} - void main_loop( void) { From 606d0a24582b2ffb6e1f16347d751eeb66c8e322 Mon Sep 17 00:00:00 2001 From: Jonas Volman Date: Fri, 2 Oct 2026 16:44:38 -0700 Subject: [PATCH 05/17] Reconcile approved biped sight and placement matches (+2 functions, +495 meaningful bytes) Independently verified donor edbdbf729e9b7c0c09557f1ccb45f94ad6c8a06a against canonical 09255f0e: fresh clean full build, strict whole-board sweep with zero losses, parks 61 to 59, unchanged data/object credit and warnings, 1663 tools tests passed. Folded helper identity and all selected-provider pair links passed. Per-site parentheses, descriptive constants and coupled jumping form remain narrowly disclosed as inferred; no general hold lifted. Unrelated canonical biped_accelerate shape and README edit preserved. Co-Authored-By: Claude Opus 5.5 --- config/parked.json | 30 ----- .../bipeds_sight_position_packet_20261002.md | 108 ++++++++++++++++++ source/units/bipeds.c | 62 +++------- 3 files changed, 127 insertions(+), 73 deletions(-) create mode 100644 docs/object_matching_logs/bipeds_sight_position_packet_20261002.md diff --git a/config/parked.json b/config/parked.json index 16949de9..e3d61872 100644 --- a/config/parked.json +++ b/config/parked.json @@ -725,25 +725,6 @@ } ] }, - { - "unit": "source/units/bipeds", - "function": "_biped_adjust_placement", - "class": "unclassified", - "evidence": "Fuzzy-parked under the current house rule after restoring the complete typed placement correction in ordinary C. The retained public function obtains the biped and its definition through the owning typed accessors, applies the named pill-centered-at-origin and non-flying flag predicates, loads the semantic collision_radius field, and adds up*radius to all three placement-position components. January disassembly independently confirms those flags, offsets, direct component arithmetic, and the two call relocations; the later HCEA implementation and independent Stian/Pastudan lifts corroborate the behavior. Target and candidate are both 96 padded / 88 meaningful bytes with the same two relocation identities and objdiff reports 98.3871 percent. The only emitted-code difference is the equivalent choice of ECX in January versus EAX in the candidate for the data pointer across the three coordinate updates. The fail-closed classifier returns UNKNOWN, so no compiler recipe or exact credit is claimed. No declaration-order search, register/volatile forcing, barrier, pragma, assembly, raw offset, fake dependency, forced inline, undefined behavior, nonsensical branch, extra code/data/COMMON owner, or point_from_line3d COMDAT is retained. Reopen only for authoritative January source/local records or a natural compatible-compiler donor explaining the pointer-register allocation.", - "measurements": { - "target": { - "size": 96, - "relocation_count": 2, - "normalized_sha256": "41db59000f9eb782eedfa45b2457e16898749fd2a3bc25a0e687c762181a40d4" - }, - "base": { - "size": 96, - "relocation_count": 2, - "normalized_sha256": "5fb478d5414138003fa6ec1126c191fe0383f3c68c42523b28e455dd62e39f10" - }, - "objdiff_percent": 98.3871 - } - }, { "unit": "source/bink/bink_playback", "function": "_bink_query_analog_controller_buttons", @@ -796,17 +777,6 @@ "objdiff_percent": 82.79332 } }, - { - "unit": "source/units/bipeds", - "function": "_biped_get_sight_position", - "class": "unclassified", - "evidence": "Best complete typed sight-position reconstruction retained using biped/tag access macros, project real types, named estimate modes, and existing vector helpers. Target and candidate now share the 416-byte padded envelope and all 19 relocation identities, scoring 97.74286% objdiff; the remaining difference is an x87/local-spill choice with no proved source-level compiler mechanism. No fake dependency, barrier, volatile/register steering, pragma, assembly or nonsensical logic is retained. This is zero-credit fuzzy source. Reopen only with authoritative January source/local records or a natural compatible-compiler donor explaining the spill schedule. See docs/object_matching_logs/bipeds_obj_batch7_exact_and_fuzzy_20260912.md.", - "measurements": { - "target": { "size": 416, "relocation_count": 19, "normalized_sha256": "59e27e5e5b6f7a7ca3ec56c3ff8f347e70de4848ad52d8c8dfe257e7ef3dffc8" }, - "base": { "size": 416, "relocation_count": 19, "normalized_sha256": "46b593827ea2de5386183bd8c60fdaab2c986990dbde4e7ec9e6fa33edc9e951" }, - "objdiff_percent": 97.74286 - } - }, { "unit": "source/units/bipeds", "function": "_biped_accelerate", diff --git a/docs/object_matching_logs/bipeds_sight_position_packet_20261002.md b/docs/object_matching_logs/bipeds_sight_position_packet_20261002.md new file mode 100644 index 00000000..3e9c6039 --- /dev/null +++ b/docs/object_matching_logs/bipeds_sight_position_packet_20261002.md @@ -0,0 +1,108 @@ +# bipeds.obj sight-position packet, 2026-10-02 + +Lane `claude/remaining-frontier-20260926`. **Lane-verified, pending independent canonical reconciliation.** Not pushed. +Owner rulings of 2026-10-02, verbatim in `research/remaining_frontier_20260926/OWNER_PACKET.md`: Q-UP9 (investigate +the two direct parenthesised arguments), Q-UP10 (land form An), Q-UP11 (the four names), Q-UP12 (restorations in +the same packet), Q-UP13 (the third site, narrowly; the `biped_jump` restoration held). +Research record: `research/remaining_frontier_20260926/lead/upstream_punpck/cards/UP-13_biped_get_sight_position_direct_arguments.md` +and `OWNER_BRIEF_UP13_BIPED_SIGHT_POSITION_20261002.md` beside it. + +| Function | Meaningful bytes | Padded bytes | Relocations | +| --- | ---: | ---: | ---: | +| `_biped_get_sight_position` (form An: the two approved sites and the coupled jumping correction) | 407 | 416 | 19 | +| `_biped_adjust_placement` (the third site, approved narrowly) | 88 | 96 | 2 | +| Total: 2 functions | 495 | 512 | | + +The two `biped_find_ground_surface` restorations are zero-credit fidelity cleanup: the function was exact and its +section is byte-identical before and after. + +## What changed + +- `source/units/bipeds.c` + - `#define REAL_MATH_EXTERNAL_POINT_FROM_LINE3D` is removed. In this unit `point_from_line3d` is again the + shared-header `__inline` of `real_math.h`, which the compiler expands at some sites and calls at others, as + January's object does (ten relocations to `_point_from_line3d` in four functions, expansions elsewhere). + - `biped_get_sight_position`: the two hand-written expansions and their block locals `forward_distance` and + `sideways_distance` become + `point_from_line3d(sight_position, desired_facing, (desired_gun_offset->i), sight_position);` and + `point_from_line3d(sight_position, &left, (desired_gun_offset->j), sight_position);`. + - `biped_adjust_placement`: the hand-written expansion and its local `height_offset` become + `point_from_line3d(&data->position, &data->up, (definition->biped.collision_radius), &data->position);`. + - `biped_find_ground_surface`: the two hand-written expansions become + `point_from_line3d(&origin, global_up3d, 0.4f, &origin);` and + `point_from_line3d(&origin, &vector, result.t, point);`. The three expansion-only locals (`line_point`, + `line_vector`, `line_t`) and the comment "Preserve January's inline schedule without owning point_from_line3d + here" go. + - `biped_update_jumping`: four constant locals in the jetpack block, `minimum_acceleration = 0.01f`, + `maximum_acceleration = 0.05f`, `maximum_velocity = 1.4f`, `damping = 0.8f`, used where their values appeared as + literals (`forward_velocity / maximum_velocity`, `damping - 1.f` twice, the third scale). The crouch brake is + `else if (...)` with `&biped->object.translational_velocity` passed directly; its `!impulse` test and pointer + local go. +- `config/parked.json`: the parks of `_biped_get_sight_position` and `_biped_adjust_placement` are retired + (`tools.campaign.unpark --write`). + +No cast is added. No compiler flag, precompiled-header setting, scorer, credit rule, header or `symbols.json` row +changes. + +## Evidence + +| Claim | Status | Basis | +| --- | --- | --- | +| Two calls of the helper in `biped_get_sight_position`, the scales passed directly, no local | attested by a later first-party build | the unoptimised build (2020), calls at 0x8c04ca and 0x8c04ec; neither scale is stored to a frame slot | +| One call in `biped_adjust_placement`, the scale passed directly | attested by the same build | call at 0x8bcbcd | +| The parentheses around the three scales | **INFERRED from per-site first-party codegen; not authenticated source spelling** | that build loads each scale before reserving its argument slot (`movss xmm0, [reg]; push ecx; movss [esp], xmm0` at 0x8c04b8, 0x8c04d9, 0x8bcbb1), the order a whole-value parenthesised lvalue produces; a macro that parenthesises its argument or a comma expression would leave the same trace | +| January needs them | measured | the second sight scale and the placement scale are defined through the FPU in January; with a bare argument both functions are residual. The first sight scale's parentheses change no byte of January and rest on the later build alone | +| Nothing else produces that definition | measured, sixteen spellings of the second sight scale with January's compiler | cast, unary plus, value-preserving arithmetic, an index, partial parentheses, a `(double)` cast and a local copy all compile to the previous text's section; only whole-value forms are exact | +| The compiler-version gap | **disclosed, not closed** | the unoptimised build was made with MSVC 19.00.24234, which is not on the measuring machine (whole-disk inventory: 13.00.8943, 13.00.9044, 13.00.9210, 13.00.9254, 13.00.9254.1, 19.12.25835 with an x64 target only, 19.51.36252). A 35-spelling lab on 13.00.9254, 19.12 and 19.51 agrees row for row; 19.00 itself is bracketed, not tested | +| Lifting the guard in this unit | owner ruling 2026-09-21 no. 1 | `units/bipeds.obj` is one of the 17 January objects that reference `_point_from_line3d` out of line | +| The new folded copy of `_point_from_line3d` | verified | 48 bytes, no relocations, COMDAT selection ANY, strictly equal to January's selected copy in `ai/action_charge.obj`; all 33 copies on the board are strictly equal to it; it receives no credit | +| Four constant locals in `biped_update_jumping` | attested by the later build, corroborated by January | four stores of 0.01, 0.05, 1.4 and 0.8 into frame slots that are never read (0x8c532c .. 0x8c535b); January pushes 0xbe4ccccc, which is `0.8f - 1.f` in single precision (the literal -0.2f is 0xbe4ccccd), and multiplies by the folded reciprocal of 1.4f | +| Why they matter | measured | in C `local - 1.f` is not a constant expression, so the inliner leaves the second call a call, as January has it; the literal `0.8f - 1.f` is folded by the front end and the call is expanded (the function is lost) | +| `const` on the four locals | inferred | a C++ compile at /Od stores a const-qualified local and folds its uses (lab on test code, MSVC 19.51); non-const locals give the same January bytes | +| The four names | **INFERRED descriptive names, not recovered Bungie identifiers** | no PDB records a local of this block (the demo and 2011 builds compile it out); read off the arithmetic: thrust = (1 - s)(0.01 + 0.05 s) with s = forward speed / 1.4 pinned to 0..1, lateral velocity kept at 0.8 per tick | +| The crouch brake as `else if`, address passed directly | attested by the later build; January cannot tell | the impulse branch jumps past the brake (0x8c5550); the address is computed twice (0x8c556e, 0x8c5583). With the constants as locals every spelling of the brake gives January's bytes; with literals only the previous `if (!impulse && ...)` plus a pointer local did | +| The third scale's expression | unchanged, January-exact; constants spelled by name | the later build computes `s*s*(-0.05) + 0.04*s + 0.01`; that order is not January's bytes, so it is not taken | +| The two `biped_find_ground_surface` calls | attested by the later build; byte-identical | calls at 0x8beb35 and 0x8bebc9; the function's section is identical before and after | + +Differences of the later build that are NOT imported: its third-scale term order, its named local for that scale, +its missing rumble block, and its later crouch interpolation in the other branch of `biped_get_sight_position`. + +## Not part of this packet + +- The parenthesis class in general: still held. This approves three sites, one by one. +- The `biped_jump` restoration: held pending evidence and a ruling, because the genuine call there needs + `(real_point3d *)&jump_velocity` twice. Its hand-written expansion and the local `velocity_delta` stay. +- The other hand-written expansions of the helper in this unit: `biped_fix_position` (four), `biped_snap_facing` + (one), `biped_accelerate` (one), `biped_update_physics` (several). Writing the first two as calls loses their + exactness through an operand-order tie inside a `cross_product3d` expansion elsewhere in the function; nothing + was steered. +- The avoidance functions, the pill's negation parentheses, the two-local `cross_product3d`, the `ai_debug` casts. + +## Lane gate + +Measured first in a shadow of the lane HEAD (checkpoint `SH_Q9_AnL_GP` against `SH_Q9BASE`), then gated fresh in +the lane: `R116i_B` against `R115i_merge` (incremental build, objdiff 3.3.1). Zero exact losses. + +- Stable diff: gained 2 (512 padded bytes), regressions 0. +- Functions 7,480 -> 7,482 of 7,573. Code 1,601,833 -> 1,602,328 of 1,770,166 (+495 meaningful bytes). +- Data 3,311,591 / 3,922,163 and objects 396 / 468 unchanged. +- Strict section owners 7,653 -> 7,655 of 8,252. +- Parks 61 -> 59, 0 stale, 0 invalid. Admission candidates 9, 0 contradicted, 0 rejected, 0 revoked. +- Tools tests 1,700 passed, 5 skipped. Fake-match scan: the same 26 inherited leads. Whitespace checks pass. +- One object differs on the whole board, `bipeds.obj` (1 of 621). Its changed function sections: + `_biped_get_sight_position` and `_biped_adjust_placement` (the gains), `_point_from_line3d` (new, uncredited) and + `_biped_update_physics`, a 5,376-byte residual that is not exact before or after and whose frame slots are + renumbered (objdiff 88.408554% -> 88.398636%; its five real calls of the helper stay five). +- Identical before and after, and exact: `_biped_find_ground_surface`, `_biped_update_jumping`, `_biped_jump`, + `_biped_fix_position`, `_biped_snap_facing`. +- Symbols of `bipeds.obj`: one new external definition (`_point_from_line3d`), one undefined reference fewer (the + same symbol), nothing else: no new data, COMMON, constant or string. +- Real calls of the helper per function equal January's: `_biped_update_airborne` 1, `_biped_update_jumping` 3, + `_biped_update_moving` 1, `_biped_update_physics` 5. +- Selected-provider pair link in both input orders: PASS for the new copy, and for all 84 surplus external + definitions of the object. Whole-board diagnostic link before and after: LNK1120 419 = 419, the same 398 + unresolved names, LNK2005 only the inherited `_real_local_random`; no image was produced. +- /W3 4,082 = 4,082, no unit differs. /W4 for `bipeds.c` 101 = 101. +- C1 shift sweep (diagnostic only): the two gains, `_biped_update_jumping`, `_biped_find_ground_surface`, + `_biped_jump`, `_biped_fix_position` and `_biped_snap_facing` are exact at all 64 shifts, so the result does not + depend on a declaration count. diff --git a/source/units/bipeds.c b/source/units/bipeds.c index 11960a70..dc493ff8 100644 --- a/source/units/bipeds.c +++ b/source/units/bipeds.c @@ -233,7 +233,6 @@ symbols in this file: /* ---------- headers */ -#define REAL_MATH_EXTERNAL_POINT_FROM_LINE3D #define REAL_MATH_EXTERNAL_REAL_RANDOM_RANGE #include "cseries.h" #include "ai/ai_communication.h" @@ -924,11 +923,7 @@ void biped_adjust_placement( if (TEST_FLAG(flags, _biped_pill_centered_at_origin_bit) && !TEST_FLAG(flags, _biped_flying_bit)) { - real height_offset = definition->biped.collision_radius; - - data->position.x += data->up.i*height_offset; - data->position.y += data->up.j*height_offset; - data->position.z += data->up.k*height_offset; + point_from_line3d(&data->position, &data->up, (definition->biped.collision_radius), &data->position); } return; @@ -997,20 +992,8 @@ void biped_get_sight_position( left.j = desired_facing->i; left.k = 0.f; - { - real forward_distance = desired_gun_offset->i; - - sight_position->x += desired_facing->i*forward_distance; - sight_position->y += desired_facing->j*forward_distance; - sight_position->z += desired_facing->k*forward_distance; - { - real sideways_distance = desired_gun_offset->j; - - sight_position->x += left.i*sideways_distance; - sight_position->y += left.j*sideways_distance; - sight_position->z += left.k*sideways_distance; - } - } + point_from_line3d(sight_position, desired_facing, (desired_gun_offset->i), sight_position); + point_from_line3d(sight_position, &left, (desired_gun_offset->j), sight_position); sight_position->z += desired_gun_offset->k; } else @@ -1453,10 +1436,7 @@ static long biped_find_ground_surface( global_current_collision_users[global_current_collision_user_depth++] = _collision_user_bipeds; object_get_origin(object_index, &origin); - /* Preserve January's inline schedule without owning point_from_line3d here. */ - origin.x = global_up3d->i*0.4f + origin.x; - origin.y = global_up3d->j*0.4f + origin.y; - origin.z = global_up3d->k*0.4f + origin.z; + point_from_line3d(&origin, global_up3d, 0.4f, &origin); scale_vector3d(direction, distance, &vector); if (collision_bsp_test_vector( @@ -1471,15 +1451,7 @@ static long biped_find_ground_surface( { surface_index = result.surface_index; if (point) - { - real_point3d const *line_point = &origin; - real_vector3d const *line_vector = &vector; - real line_t = result.t; - - point->x = line_vector->i*line_t + line_point->x; - point->y = line_vector->j*line_t + line_point->y; - point->z = line_vector->k*line_t + line_point->z; - } + point_from_line3d(&origin, &vector, result.t, point); if (normal) *normal = result.plane->n; } @@ -2213,6 +2185,11 @@ static void biped_update_jumping( if (cheat.jetpack && biped->unit.player_index != NONE) { struct player_datum *player = player_get(biped->unit.player_index); + /* inferred, descriptive names (not recovered Bungie identifiers): no PDB records the locals of this block */ + const real minimum_acceleration = 0.01f; + const real maximum_acceleration = 0.05f; + const real maximum_velocity = 1.4f; + const real damping = 0.8f; boolean impulse = FALSE; if (TEST_FLAG(biped->unit.control_flags, _unit_control_weapon_primary_trigger_bit) && @@ -2223,7 +2200,7 @@ static void biped_update_jumping( dot_product3d( &biped->object.translational_velocity, &biped->unit.aiming_vector)); - real acceleration_scale = PIN(forward_velocity * 0.71428573f, 0.f, 1.f); + real acceleration_scale = PIN(forward_velocity / maximum_velocity, 0.f, 1.f); real_vector3d lateral_velocity; point_from_line3d( @@ -2234,25 +2211,24 @@ static void biped_update_jumping( point_from_line3d( (real_point3d *)&biped->object.translational_velocity, &lateral_velocity, - 0.8f - 1.f, + damping - 1.f, (real_point3d *)&biped->object.translational_velocity); point_from_line3d( (real_point3d *)&biped->object.translational_velocity, &biped->unit.aiming_vector, - acceleration_scale * 0.04f - - acceleration_scale * acceleration_scale * 0.05f + 0.01f, + acceleration_scale * (maximum_acceleration - minimum_acceleration) - + acceleration_scale * acceleration_scale * maximum_acceleration + minimum_acceleration, (real_point3d *)&biped->object.translational_velocity); SET_FLAG(biped->biped.flags, _biped_airborne_bit, TRUE); impulse = TRUE; } - - if (!impulse && - TEST_FLAG(biped->unit.control_flags, _unit_control_crouch_modifier_bit) && + else if (TEST_FLAG(biped->unit.control_flags, _unit_control_crouch_modifier_bit) && TEST_FLAG(biped->biped.flags, _biped_airborne_bit)) { - real_vector3d *velocity = &biped->object.translational_velocity; - - scale_vector3d(velocity, 0.8f - 1.f, velocity); + scale_vector3d( + &biped->object.translational_velocity, + damping - 1.f, + &biped->object.translational_velocity); } if (player->local_player_index != NONE && impulse) From 164026a7f1d6a3c71624f4eaede5bd597ad09633 Mon Sep 17 00:00:00 2001 From: Jonas Volman Date: Fri, 2 Oct 2026 16:47:08 -0700 Subject: [PATCH 06/17] Restore biped_jump helper call under the admitted two-site vector view (zero credit) Independently reconciled donor 82ea0d5e9bcee8a1a48775aab6f0c351f5ee5e2a after the biped packet. Fresh clean full gate: zero additional gains or losses, all normalized objects unchanged, parks valid, warnings unchanged and 1663 tools tests passed. Current-compiler cast ablation is byte-inert; nine layout/alignment checks pass and a deliberately false control fails. Both current selected-provider link orders pass. Cast spelling remains inferred; no new parenthesis or general view-cast exception. Co-Authored-By: Claude Opus 5.5 --- ...s_jump_helper_call_restoration_20261002.md | 67 +++++++++++++++++++ source/units/bipeds.c | 10 +-- 2 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 docs/object_matching_logs/bipeds_jump_helper_call_restoration_20261002.md diff --git a/docs/object_matching_logs/bipeds_jump_helper_call_restoration_20261002.md b/docs/object_matching_logs/bipeds_jump_helper_call_restoration_20261002.md new file mode 100644 index 00000000..be8b4eb7 --- /dev/null +++ b/docs/object_matching_logs/bipeds_jump_helper_call_restoration_20261002.md @@ -0,0 +1,67 @@ +# bipeds.obj: `biped_jump` helper-call restoration, 2026-10-02 (zero credit) + +Lane `claude/remaining-frontier-20260926`. **Lane-verified, pending independent canonical reconciliation.** Not pushed. +Owner rulings of 2026-10-02, verbatim in `research/remaining_frontier_20260926/OWNER_PACKET.md`: Q-UP13 (held until +the casts had evidence and a ruling), Q-UP14 (the vector-to-point casts admitted per site under seven conditions), +Q-UP16 (land it as a unit-scoped zero-credit fidelity correction). Research record: +`research/remaining_frontier_20260926/lead/upstream_punpck/cards/UP-13_biped_get_sight_position_direct_arguments.md`, +section 17. + +No byte changes: `_biped_jump` was exact and its section is strictly identical before and after. No credit is +claimed. + +## What changed + +`source/units/bipeds.c`, `biped_jump`: the hand-written expansion of the line helper and its local +`velocity_delta` become the helper call. + +``` +before after +real velocity_delta = jump_magnitude-upward_velocity; point_from_line3d( + (real_point3d *)&jump_velocity, +jump_velocity.i += biped->object.up.i*velocity_delta; &biped->object.up, +jump_velocity.j += biped->object.up.j*velocity_delta; jump_magnitude-upward_velocity, +jump_velocity.k += biped->object.up.k*velocity_delta; (real_point3d *)&jump_velocity); +``` + +Nothing else: no parenthesis, no scope change, no rename, no other function, no header, no configuration file. + +## The two casts (ruling Q-UP14) + +`(real_point3d *)&jump_velocity`, twice: the first and the fourth argument of the call. The helper's parameters +there are `real_point3d const *p` and `real_point3d *result`; the object is a `real_vector3d`. + +| Condition | Finding | +| --- | --- | +| The object is a vector in first-party PDBs | `union real_vector3d new_velocity`, a local of `biped_jump`, in the 2003 demo PDB and both 2011 PDBs (the lane's name for it is `jump_velocity`) | +| The unoptimised build passes that object as the point argument at this call | call of `point_from_line3d` at 0x8c08d9: `lea ecx, [ebp-0x24]; push ecx` (result), the scale `[ebp-0x14] - [ebp-0x30]` computed as the argument, `[ebp-8] + 0x3c` (`&biped->object.up`), `lea eax, [ebp-0x24]; push eax` (first argument). One object, both point parameters. No local holds the scale | +| The cast is byte-inert | measured: with the casts and without them `_biped_jump` has the same section | +| The function is strictly exact | 432 B, 10 relocations, exact before and after | +| Compatible layout and alignment | compile-time assertions with January's compiler and this unit's flags: both types are 12 bytes, alignment of `real`, members at 0, 4 and 8, the array view at 0; a control assertion that is false fails to compile | +| Constness preserved | `jump_velocity` is a non-const local; no qualifier is removed (the first parameter adds `const`) | +| Listed here | two casts, both above | + +**The view is first-party-attested; the spelling of the cast is inferred, not recovered source.** The later build is +a C++ compile and must have had an explicit conversion at this call; how it was written is not known. Without the +casts the unit gains two C4133 warnings in C. + +Not changed although first-party names differ (declaration corrections are ruled on in batches): the vector is +`new_velocity` in the PDBs. + +## Lane gate + +`R117i_J` against `R116i_B` (incremental build, objdiff 3.3.1). Zero exact losses, zero gains. + +- Stable diff: gained 0, regressions 0. Functions 7,482 / 7,573, code 1,602,328 / 1,770,166, data 3,311,591 / + 3,922,163, objects 396 / 468, strict section owners 7,655 / 8,252, parks 59: all unchanged. +- Admission candidates 9, 0 contradicted, 0 rejected, 0 revoked. Tools tests 1,700 passed, 5 skipped. Fake-match + scan: the same 26 inherited leads. Whitespace checks pass. +- `bipeds.obj`: all 85 function sections strictly identical before and after (the strict comparator); 46 exact + before and after. The object's fingerprint differs only in the numbering of compiler labels. No external symbol + is added or removed; the object already held its copy of `_point_from_line3d` (strictly equal to January's). +- Real calls of the helper per function unchanged and equal to January's (10 in four functions): the restored call + is expanded inline, as January's code is. +- Selected-provider pair links in both input orders: PASS for all 84 surplus external definitions. Whole-board + diagnostic link before and after: LNK1120 419 = 419, the same 398 unresolved names, LNK2005 only the inherited + `_real_local_random`; no image was produced. +- /W3 4,082 = 4,082, no unit differs. /W4 for `bipeds.c` 101 = 101. diff --git a/source/units/bipeds.c b/source/units/bipeds.c index dc493ff8..0105884b 100644 --- a/source/units/bipeds.c +++ b/source/units/bipeds.c @@ -1838,11 +1838,11 @@ static boolean biped_jump( if (upward_velocityobject.up.i*velocity_delta; - jump_velocity.j += biped->object.up.j*velocity_delta; - jump_velocity.k += biped->object.up.k*velocity_delta; + point_from_line3d( + (real_point3d *)&jump_velocity, + &biped->object.up, + jump_magnitude-upward_velocity, + (real_point3d *)&jump_velocity); } } From 201442d3770b95ef1538285d84742b695cf49b21 Mon Sep 17 00:00:00 2001 From: Jonas Volman Date: Fri, 2 Oct 2026 16:49:29 -0700 Subject: [PATCH 07/17] Restore actor avoidance transform helper calls with the approved guard removal (zero credit) Independently reconciled donor 41d3b992a5e5c0fbbb5f76c476d27f9c68031e82 without candidate F. Fresh clean full gate: no additional gains or losses, all prior function sections identical, one new uncredited 48-byte SELECT_ANY point_from_line3d copy identical to January, unchanged real-call schedule, warnings, data and object credit. Current-compiler cast ablation and layout controls pass, 284 ordered provider-link probes pass, 1663 tools tests pass. Six inferred casts and three byte-inert per-site parentheses are disclosed; all other actor_moving holds stay in force. Co-Authored-By: Claude Opus 5.5 --- ...nsform_helper_call_restoration_20261002.md | 89 +++++++++++++++++++ source/ai/actor_moving.c | 22 +---- 2 files changed, 92 insertions(+), 19 deletions(-) create mode 100644 docs/object_matching_logs/actor_moving_transform_helper_call_restoration_20261002.md diff --git a/docs/object_matching_logs/actor_moving_transform_helper_call_restoration_20261002.md b/docs/object_matching_logs/actor_moving_transform_helper_call_restoration_20261002.md new file mode 100644 index 00000000..9c9ef91f --- /dev/null +++ b/docs/object_matching_logs/actor_moving_transform_helper_call_restoration_20261002.md @@ -0,0 +1,89 @@ +# actor_moving.obj: `actor_move_transform_avoidance_vector` helper-call restoration, 2026-10-02 (zero credit) + +Lane `claude/remaining-frontier-20260926`. **Lane-verified, pending independent canonical reconciliation.** Not pushed. +Owner rulings of 2026-10-02, verbatim in `research/remaining_frontier_20260926/OWNER_PACKET.md`: Q-UP14 (the +vector-to-point casts admitted per site under seven conditions), Q-UP16 (land it as a unit-scoped zero-credit +fidelity correction, measured without the held `actor_move_test_avoidance_vector` candidate), Q-UP18 (land it with +the guard removal, as gated in `R118i_X`; "a narrow exception for the transform-helper restoration only"). Research +record: `research/remaining_frontier_20260926/lead/upstream_punpck/cards/UP-14_avoidance_function_sites.md`. + +No byte of any function changes. `_actor_move_transform_avoidance_vector` was exact and its section is strictly +identical before and after. No credit is claimed; the new helper copy earns none. + +## What changed, every item + +`source/ai/actor_moving.c`: + +1. `actor_move_transform_avoidance_vector`: the three hand-written expansions of the line helper and their local + `component` (no PDB lists it) become three calls, as the unoptimised build has them: + ``` + *direction_vector = *global_zero_vector3d; + point_from_line3d((real_point3d *)direction_vector, &avoidance_data->forward, (avoidance_vector->i), (real_point3d *)direction_vector); + point_from_line3d((real_point3d *)direction_vector, &avoidance_data->left, (avoidance_vector->j), (real_point3d *)direction_vector); + point_from_line3d((real_point3d *)direction_vector, &avoidance_data->up, (avoidance_vector->k), (real_point3d *)direction_vector); + ``` +2. SIX casts `(real_point3d *)direction_vector`: the first and the fourth argument of each call. +3. THREE whole-value parenthesised scales, `(avoidance_vector->i)`, `(avoidance_vector->j)`, `(avoidance_vector->k)`. + They are BYTE-INERT here: bare scales give the same section. They are per-site inferred spellings, taken from + the unoptimised build's load-first order at each of the three sites; they are not authenticated source spelling. +4. The unit's two guard lines, `#define REAL_MATH_EXTERNAL_POINT_FROM_LINE3D` before the includes and its `#undef` + after them, are removed. The restoration needs it: with the guard the three calls are real calls and two exact + functions are lost (measured). +5. Consequence of 4: `actor_moving.obj` emits one new copy of `_point_from_line3d` (48 bytes, no relocations, + COMDAT selection ANY), the 34th on the board, strictly equal to January's selected copy in + `ai/action_charge.obj`. It receives no credit. `ai/actor_moving` is one of the 17 January objects that + reference the helper out of line (owner ruling 2026-09-21 no. 1). Removing the guard by itself changes no + function section of the unit. + +Nothing else: no scope change, no rename, no other function's text, no header, no configuration file. The held +`actor_move_test_avoidance_vector` candidate is NOT in this commit; that function keeps its text and its two calls +of this helper. + +## The six casts (ruling Q-UP14) + +| Condition | Finding | +| --- | --- | +| The object is a vector in a first-party PDB | the parameter `direction_vector` is `union real_vector3d *` (2011 release PDB) | +| The unoptimised build passes that object as the point argument at each call | function at 0x467840, calls at 0x467877, 0x46789c, 0x4678c1: `mov reg, [ebp+0x10]; push reg` for the result and again for the first argument, `[ebp+8] + 0x18 / 0x24 / 0x30` for the vector | +| The casts are byte-inert | measured: with and without them the function has the same section | +| The function is strictly exact | 144 B, 1 relocation, exact before and after | +| Compatible layout and alignment | compile-time assertions with January's compiler and this unit's flags: both types 12 bytes, alignment of `real`, members at 0, 4 and 8; a false control assertion fails to compile | +| Constness preserved | `direction_vector` is a pointer to a non-const vector; no qualifier is removed | +| Listed here | six casts, item 2 above | + +**The view is first-party-attested; the spelling of the cast is inferred, not recovered source.** Without the +casts the unit gains six C4133 warnings. + +## The three parentheses + +| Site | Unoptimised build | January | +| --- | --- | --- | +| `(avoidance_vector->i)` | `mov edx, [ebp+0xc]; movss xmm0, [edx]; push ecx; movss [esp], xmm0` (0x46785f) | cannot tell: bare gives the same bytes | +| `(avoidance_vector->j)` | `movss xmm0, [eax+4]` before the slot is reserved (0x467886) | cannot tell | +| `(avoidance_vector->k)` | `movss xmm0, [ecx+8]` before the slot is reserved (0x4678ab) | cannot tell | + +Compiler-version gap, disclosed as before: that build was made with MSVC 19.00.24234, which is not on the measuring +machine; the load-first reading is bracketed by 13.00.9254, 19.12 and 19.51, not tested on 19.00. The parenthesis +class in general stays held. + +Other first-party support for the three one-line calls: the 2011 release PDB's line table gives this function the +lines 2698 (`{`), 2699, 2702, 2705, which fits a zero copy, three one-line calls, a blank line and `return;`. + +## Lane gate + +Measured alone first (the restoration without the held candidate), then gated fresh in the lane: `R118i_X` against +`R117i_J` (incremental build, objdiff 3.3.1). Zero exact losses, zero gains. + +- Stable diff: gained 0, regressions 0. Functions 7,482 / 7,573, code 1,602,328 / 1,770,166, data 3,311,591 / + 3,922,163, objects 396 / 468, strict section owners 7,655 / 8,252, parks 59: all unchanged. +- Admission candidates 9, 0 contradicted, 0 rejected, 0 revoked. Tools tests 1,700 passed, 5 skipped. Fake-match + scan: the same 26 inherited leads. Whitespace checks pass. +- `actor_moving.obj`: all 64 function sections present before are strictly identical after; 33 exact before and + after; one section is new, the helper copy. External symbols: one definition more (`_point_from_line3d`), one + undefined reference fewer (the same symbol), nothing else: no new data, COMMON, constant or string. +- Real calls of the helper per function unchanged and equal to January's: `_actor_move_calculate_movement` 1, + `_actor_move_try_evasion_vector` 1. +- Selected-provider pair links in both input orders: PASS for the new copy and for all 58 surplus external + definitions. Whole-board diagnostic link before and after: LNK1120 419 = 419, the same 398 unresolved names, + LNK2005 only the inherited `_real_local_random`; no image was produced. +- /W3 4,082 = 4,082, no unit differs. /W4 for `actor_moving.c` 95 = 95. diff --git a/source/ai/actor_moving.c b/source/ai/actor_moving.c index 1bf85b23..ee7c2e75 100644 --- a/source/ai/actor_moving.c +++ b/source/ai/actor_moving.c @@ -204,7 +204,6 @@ symbols in this file: /* ---------- headers */ -#define REAL_MATH_EXTERNAL_POINT_FROM_LINE3D #include "cseries/cseries.h" #include "cseries/errors.h" #define PATH_EXTERNAL_FLEE_ROUTINES @@ -235,7 +234,6 @@ symbols in this file: #include "objects/objects.h" #include "physics/collision_model_definitions.h" #undef PATH_EXTERNAL_FLEE_ROUTINES -#undef REAL_MATH_EXTERNAL_POINT_FROM_LINE3D /* ---------- constants */ @@ -655,24 +653,10 @@ void actor_move_transform_avoidance_vector( real_vector3d const *avoidance_vector, real_vector3d *direction_vector) { - real component; - *direction_vector = *global_zero_vector3d; - - component = avoidance_vector->i; - direction_vector->i += component * avoidance_data->forward.i; - direction_vector->j += component * avoidance_data->forward.j; - direction_vector->k += component * avoidance_data->forward.k; - - component = avoidance_vector->j; - direction_vector->i += component * avoidance_data->left.i; - direction_vector->j += component * avoidance_data->left.j; - direction_vector->k += component * avoidance_data->left.k; - - component = avoidance_vector->k; - direction_vector->i += component * avoidance_data->up.i; - direction_vector->j += component * avoidance_data->up.j; - direction_vector->k += component * avoidance_data->up.k; + point_from_line3d((real_point3d *)direction_vector, &avoidance_data->forward, (avoidance_vector->i), (real_point3d *)direction_vector); + point_from_line3d((real_point3d *)direction_vector, &avoidance_data->left, (avoidance_vector->j), (real_point3d *)direction_vector); + point_from_line3d((real_point3d *)direction_vector, &avoidance_data->up, (avoidance_vector->k), (real_point3d *)direction_vector); return; } From fccf773db3c0adcf55f110eda5034b2c0aac4987 Mon Sep 17 00:00:00 2001 From: Jonas Volman Date: Fri, 2 Oct 2026 17:04:04 -0700 Subject: [PATCH 08/17] Reconcile actor test avoidance match (+1 function, +743 meaningful bytes) Independently verified donor c694a43d4e3343eedebac48fe6f2b6052f679778 under Q-UP21 after the separately gated helper restoration. Fresh clean full gate against 09255f0e: cumulative +3 functions, +1238 meaningful / +1264 padded bytes, zero exact losses; 7483 of 7573 Halo functions, 1603071 of 1770166 code bytes, data 3311591 and objects 396 unchanged, parks 59 valid. Tools tests: 1663 passed, 5 skipped, 159 subtests. Full /W3 and unit /W4 multisets unchanged. All twenty cast ablations and layout controls passed; helper identity, real-call schedule and 284 ordered provider-link probes passed. The disclosed residual caller changes 4144 to 4128 bytes. Retain the narrow per-function parentheses ruling, inferred scopes and collision_result placement, S6 correction, single-variable alternative and compiler-version caveat. No general hold, object admission, research candidate, scorer/verifier or compiler flag change. Fresh canonical receipts and source-policy boundaries are recorded in docs/object_matching_logs/biped_avoidance_canonical_reconciliation_20261002.md. Unrelated README changes and research preserved. Co-Authored-By: Claude Opus 5.5 --- ...r_moving_test_avoidance_vector_20261002.md | 133 ++++++++++++++++++ ...dance_canonical_reconciliation_20261002.md | 97 +++++++++++++ source/ai/actor_moving.c | 96 +++++++------ 3 files changed, 280 insertions(+), 46 deletions(-) create mode 100644 docs/object_matching_logs/actor_moving_test_avoidance_vector_20261002.md create mode 100644 docs/object_matching_logs/biped_avoidance_canonical_reconciliation_20261002.md diff --git a/docs/object_matching_logs/actor_moving_test_avoidance_vector_20261002.md b/docs/object_matching_logs/actor_moving_test_avoidance_vector_20261002.md new file mode 100644 index 00000000..8c8e7773 --- /dev/null +++ b/docs/object_matching_logs/actor_moving_test_avoidance_vector_20261002.md @@ -0,0 +1,133 @@ +# actor_moving.obj: `actor_move_test_avoidance_vector` exact, 2026-10-02 (+1 function, +743 meaningful / +752 padded bytes) + +Lane `claude/remaining-frontier-20260926`. **Lane-verified, pending independent canonical reconciliation.** Not pushed. +Owner rulings of 2026-10-02, verbatim in `research/remaining_frontier_20260926/OWNER_PACKET.md`: Q-UP14 (the +vector-to-point casts admitted per site under seven conditions), Q-UP15 (the candidate held for its two scopes until +independent lifetime evidence), Q-UP21 (land after fresh full gates; it "narrowly lifts Q-UP15": January's slot +sharing plus the separately attested variables supports the disjoint-scope reconstruction, and the exact brace +placement remains inferred, not recovered source). Research record: +`research/remaining_frontier_20260926/lead/upstream_punpck/cards/UP-14_avoidance_function_sites.md` (sections 2 to 9). + +`_actor_move_test_avoidance_vector` (752 bytes, 16 relocations) goes from residual to strictly exact. One other +function's bytes move and it stays residual: `_actor_move_vector_avoidance`, 4,144 -> 4,128 bytes (January 4,144). + +## What changed, every item + +Only the body of `actor_move_test_avoidance_vector` in `source/ai/actor_moving.c` (the unit's guard lines and the +transform helper were already changed by `41d3b992`): + +1. The two calls of `actor_move_transform_avoidance_vector` (the unoptimised build's function does not call it) are + replaced by six written-out calls of `point_from_line3d` on two zero-initialised vectors, as the unoptimised build + has them, each vector first set by a struct copy `= *global_zero_vector3d`: + ``` + origin_offset = *global_zero_vector3d; + point_from_line3d((real_point3d *)&origin_offset, &avoidance_data->forward, (avoidance_ray->offset.i), (real_point3d *)&origin_offset); + ... (left, offset.j), (up, offset.k); then divergence_direction with divergence.i / .j / .k + ``` +2. The local `scale` (no PDB lists it) and its three hand-written lines become one call, + `scale_vector3d(&divergence_direction, avoidance_ray->length*avoidance_data->avoid_distance, ray_direction)`; + the operand order of that product is the unoptimised build's (byte-inert). +3. A seventh call, `point_from_line3d(&avoidance_data->origin, &origin_offset, (avoidance_data->avoid_width), + ray_origin)`, replaces the lane's hand expansion there. +4. SEVEN whole-value parenthesised scales, one per call (items 1 and 3). See "The seven parentheses". +5. TWELVE casts: `(real_point3d *)&origin_offset` and `(real_point3d *)&divergence_direction`, the first and the + fourth argument of the six axis calls. See "The twelve casts". +6. Locals renamed to the PDBs' names: `offset` -> `origin_offset`, `divergence` -> `divergence_direction`, `object_t` + -> `intersect_t`; declarations in the PDBs' record order (byte-inert). +7. Two locals added, both `real_vector3d`, names and types from the PDBs: `vector_to_origin` (the structure test's + vector) and `dummy_normal` (the pill test's normal). The lane text had reused `offset` for both roles. +8. SCOPES, INFERRED: `vector_to_origin` is declared in a new bare block around the two structure tests, and + `dummy_normal` in the body of the object loop. `collision_result` is declared inside the same bare block; that + placement is byte-inert and rests on the PDB record order alone. All three placements are inferred, not + recovered source. See "The scopes". + +Nothing else: no other function's text, no header, no guard, no configuration file, no comment. No park existed for +this function. + +## The scopes (ruling Q-UP21) + +January passes the address of ONE frame slot, `[ebp-0x14]`, to two different real calls: the structure test at ++0x173 and the pill test at +0x27a. The same slot is `origin_offset`'s. Twelve scopings were compiled with January's +compiler (`tools/tav2_probe.py`, outputs `up14/tav2_probe.txt` and `up14/tav2_probe_2.txt`): + +| Tested form | Result | +| --- | --- | +| this text: block around the structure tests, normal in the loop body | EXACT (frame 0x438, slot 0x14 at both calls) | +| the normal in a block around the loop instead | EXACT | +| the block opening earlier, before the seventh call (i.e. before `origin_offset`'s last use) | EXACT | +| one variable for both roles, in one block over the tests and the loop | EXACT | +| both vectors at function scope; either one at function scope | residual (frame 0x450 or 0x444) | +| two variables in one scope (the loop inside the block) | residual (two slots) | +| one variable reused at function scope; `origin_offset` reused for both roles; for either role | residual | + +Among the tested forms the bytes require the escaped vector storage to be out of function scope; that is a +statement about storage lifetimes, not about where an opening brace stands. The bytes do not choose between one +reused variable in one block and two variables in non-overlapping scopes: January alone still permits the +single-variable alternative. The separate-variable reconstruction relies on the later first-party records: the +2003 PC demo PDB and both 2011 PDBs list `vector_to_origin` and `dummy_normal` as separate `union real_vector3d` +locals (in the demo PDB all three vectors share one frame offset), and the unoptimised build gives them three +distinct slots. Given two variables, the tested forms require their scopes not to overlap and neither to be the +function's. Where the first block opens, and whether the normal is declared in the loop body or around the loop, +is not determined; no first-party record of a block exists. This text takes the smallest block and the loop body. + +## The seven parentheses (admitted for this function only, ruling Q-UP21) + +| Site | Unoptimised build (function 0x466b10) | January | +| --- | --- | --- | +| `(avoidance_ray->offset.i)` | load-first, `[ecx+4]`, call 0x466c09 | needs it (bare: residual) | +| `(avoidance_ray->offset.j)` | load-first, `[edx+8]`, call 0x466c2e | needs it | +| `(avoidance_ray->offset.k)` | load-first, `[eax+0xc]`, call 0x466c53 | needs it | +| `(avoidance_ray->divergence.i)` | load-first, `[edx+0x10]`, call 0x466c8e | needs it | +| `(avoidance_ray->divergence.j)` | load-first, `[eax+0x14]`, call 0x466cb3 | needs it | +| `(avoidance_ray->divergence.k)` | load-first, `[ecx+0x18]`, call 0x466cd8 | needs it | +| `(avoidance_data->avoid_width)` | load-first, `[edx+0x6040]`, call 0x466d00 | cannot tell (bare gives the same bytes) | + +Each of the six axis scales made bare alone leaves the function residual (six tests). At the second axis site, +seven spellings that are not whole-value parentheses give one and the same residual section, `(real)(x)` and +`(0, x)` are exact too, and `((x))` is not. So the spelling is inferred from per-site first-party codegen, not +authenticated source spelling. Compiler-version gap, +disclosed as before: the unoptimised build was made with MSVC 19.00.24234, which is not on the measuring machine; +the load-first reading is bracketed by 13.00.9254, 19.12 and 19.51, not tested on 19.00. The parenthesis class in +general stays held; this is no broader exception. + +## The twelve casts (ruling Q-UP14 conditions, retained) + +| Condition | Finding | +| --- | --- | +| The object is a vector in a first-party PDB | `origin_offset` and `divergence_direction` are `union real_vector3d` in the demo PDB and both 2011 PDBs | +| The unoptimised build passes that object as the point argument at each call | each local's address is the first argument and the result of three calls (0x466c09 .. 0x466cd8) | +| The casts are byte-inert | measured: the function has the same section without them (twelve C4133 warnings then) | +| The function is strictly exact | yes, with this text | +| Compatible layout and alignment | the compile-time check with January's compiler and the unit's flags (`tools/layoutcheck.py`): both types 12 bytes, alignment of `real`, members at 0, 4 and 8; a false control fails | +| Constness preserved | both locals are non-const; no qualifier is removed | +| Listed here | twelve casts, item 5 above | + +The view is first-party-attested; the spelling of the cast is inferred, not recovered source. + +## Lane gate + +Measured first in a second build shadow (gate `SG_F2`), then gated fresh in the lane: `R119i_F` against `R118i_X` +(incremental build, objdiff 3.3.1). Every requirement of ruling Q-UP21 holds. + +- Stable diff: gained 1 (`_actor_move_test_avoidance_vector`, 752 padded bytes), regressions 0. +- Functions 7,482 -> 7,483 / 7,573; code 1,602,328 -> 1,603,071 / 1,770,166 (+743 meaningful bytes); data 3,311,591 + / 3,922,163 unchanged; objects 396 / 468 unchanged (no object credit changes); strict section owners 7,655 -> + 7,656 / 8,252; parks 59, none stale or invalid. +- Admission candidates 9, 0 contradicted, 0 rejected, 0 revoked. Tools tests 1,700 passed, 5 skipped. Fake-match + scan: the same 26 inherited leads. No new warning; whitespace checks pass. +- Whole board: 1 of 621 objects differs, `actor_moving.obj`. In it: `_actor_move_test_avoidance_vector` residual + (544 bytes, 17 relocations) -> EXACT (752 bytes, 16 relocations); `_actor_move_vector_avoidance` residual -> + residual, 4,144 -> 4,128 bytes (135 relocations either way; January 4,144); every other function section is + strictly identical (three differ only in internal `$L` label numbers); 33 -> 34 exact; no section, definition or + reference is added or removed. +- Helper: the object already defines `_point_from_line3d` (since `41d3b992`); its copy is strictly equal to + January's selected copy; real calls of the helper per function 2 = 2 = January's 2 + (`_actor_move_calculate_movement`, `_actor_move_try_evasion_vector`); the expanded sites stay expanded. +- Selected-provider pair links in both input orders: PASS for all 58 surplus external definitions. Whole-board + diagnostic link before and after: LNK1120 419 = 419, the same 398 unresolved names, LNK2005 only the inherited + `_real_local_random`; no image was produced. +- /W3 4,082 = 4,082, no unit differs. /W4 for `actor_moving.c` 95 = 95. Layout assertions for the casts: PASS (nine), + the false control fails to compile. + +Transcript: `research/remaining_frontier_20260926/lead/upstream_punpck/up16/land_R119i_F.txt` (banked with the +landing records). diff --git a/docs/object_matching_logs/biped_avoidance_canonical_reconciliation_20261002.md b/docs/object_matching_logs/biped_avoidance_canonical_reconciliation_20261002.md new file mode 100644 index 00000000..77f2bbb6 --- /dev/null +++ b/docs/object_matching_logs/biped_avoidance_canonical_reconciliation_20261002.md @@ -0,0 +1,97 @@ +# Biped and actor-avoidance canonical reconciliation — 2026-10-02 + +Four specifically approved lane packets were independently reconciled against canonical +`09255f0e789d888217452b4f9e607d6ed21a7ce2` on `jonas/exact-pilots`. Each packet received its own +fresh clean full build and whole-board gate before committing. No whole-lane merge, research +candidate, build-flag change or scoring change was imported. + +| Packet | Donor commit | Canonical commit | Meaningful / padded code gain | +| --- | --- | --- | ---: | +| B: sight and placement | `edbdbf729e9b7c0c09557f1ccb45f94ad6c8a06a` | `606d0a24` | 495 / 512 B, two functions | +| J: jump call restoration | `82ea0d5e9bcee8a1a48775aab6f0c351f5ee5e2a` | `164026a7` | zero | +| X: transform call restoration | `41d3b992a5e5c0fbbb5f76c476d27f9c68031e82` | `201442d3` | zero | +| F: test avoidance vector | `c694a43d4e3343eedebac48fe6f2b6052f679778` | this commit | 743 / 752 B, one function | + +The imported per-packet logs retain their historical lane measurements and "not pushed" state. +This log supplies the fresh canonical reconciliation; the lane's additional unpublished tools +tests and other research were not imported. + +## Fresh strict section receipts + +All three sections equal their January split targets under the unchanged hardened COFF gate, +including complete relocation identities. These are normalized section hashes, not executable hashes. + +| Function | Meaningful B | Padded B | Relocations | Normalized SHA-256 | +| --- | ---: | ---: | ---: | --- | +| `_biped_get_sight_position` | 407 | 416 | 19 | `59e27e5e5b6f7a7ca3ec56c3ff8f347e70de4848ad52d8c8dfe257e7ef3dffc8` | +| `_biped_adjust_placement` | 88 | 96 | 2 | `41db59000f9eb782eedfa45b2457e16898749fd2a3bc25a0e687c762181a40d4` | +| `_actor_move_test_avoidance_vector` | 743 | 752 | 16 | `271a1af1480dd3012f9c97fc0922e0c8fbe60e97078b87d304a0eb736e1f1f0b` | +| Total | 1,238 | 1,264 | | | + +## Narrow source-policy scope + +- B uses the approved An form, coupled jumping constants/crouch brake, two ground-surface call + restorations and the separately approved placement site. Its three whole-value parentheses are + per-site inferred spellings, not recovered source. The four tuning names are descriptive; `const` + is inferred. The MSVC 19.00.24234 gap remains disclosed, not silently closed by tests on other versions. +- J restores only the genuine `biped_jump` call, removes its expansion-only local and admits its two + vector-to-point casts under the existing site conditions. No new parenthesis or scope is introduced. +- X restores three genuine transform calls, six admitted vector-to-point casts and three byte-inert + per-site parentheses. Its two guard lines are removed under the explicit narrow ruling, with one + uncredited helper copy. It was verified separately before F was applied. +- F is the approved one-function body: seven individually evidenced parenthesised scales, twelve + admitted casts, genuine calls and zero-vector copies, PDB local names, and inferred disjoint scopes. + `collision_result`'s byte-inert scope placement is inferred too. The twelve scope controls support + lifetime constraints among the tested forms, not original brace locations. S6 opens the block before + `origin_offset`'s last use and remains exact. January alone permits one reused block-local variable; + choosing the separate variables relies on the later first-party records. Neither a universal scope + impossibility proof nor a first-party lexical-block record is claimed. +- All twenty newly admitted casts were independently ablated one at a time and in their groups using + canonical's current compiler and unit flags. The listed exact functions remain byte-identical. + The private-path control also reproduces those sections. Nine size/alignment/member-offset checks + pass for each unit; a deliberately false assertion fails. The PDB-attested view is distinct from the + inferred cast spelling, and no const qualifier is removed. +- The general parenthesis and view-cast holds are not lifted. No assembly, pragma, filler, function + move, synthetic declaration, new type owner or compiler flag is introduced. + +## Canonical gates and blast radius + +- Halo functions: 7,480 -> 7,482 -> 7,482 -> 7,482 -> 7,483 of 7,573. +- Meaningful code: 1,601,833 -> 1,602,328 -> 1,603,071 of 1,770,166 (+1,238). +- Halo data stays 3,311,591 / 3,922,163; objects stay 396 / 468. No object admission is implied. +- Strict section-owner rows: 7,653 -> 7,656 of 8,252. Every stage has zero inherited exact losses. +- Parks: 61 -> 59. Only the two freshly exact biped entries are retired; no stale/invalid park, + no park rebaseline, no altered rejection/reopen criterion. +- Admission remains nine review candidates, zero contradicted/rejected/revoked. Fake scan retains + the same 26 inherited review leads. Whitespace checks pass. +- Tools tests at every clean checkpoint: 1,663 passed, five skipped, 159 subtests passed. The lane's + 1,700 figure is not claimed for this canonical tree. +- All 621 configured objects plus the inherited extra libcmt/chkstk object were fingerprinted. + B changes only bipeds.obj: the two gains, the disclosed still-residual `_biped_update_physics` + (88.408554 -> 88.398636%) and the new helper. Two extra raw-fingerprint differences are only + compiler-local switch-label names; the unchanged strict comparator verifies both exact sections + and relocation destinations as identical. Raw diagnostics were preserved, not used as credit. +- J is normalized-object-identical to B. X preserves all prior function sections and adds only the + helper copy to actor_moving.obj. F changes only its exact target and the still-residual + `_actor_move_vector_avoidance` (4,144 -> 4,128 B, 135 relocations; January 4,144). No definition, + reference or section is added by F. +- New folded helpers: two 48-byte SELECT_ANY `_point_from_line3d` copies, no relocations, no duplicate + byte credit. The board has 32 -> 33 -> 34 copies, all strictly equal to January's selected + action_charge.obj provider. Every January real helper call is preserved per function: ten in + four biped functions, two in two actor_moving functions; reconstructed inline sites stay inline. +- Current selected-provider checks cover all surplus external definitions in both units, in both + input orders: 282 ordered probes at B/J and 284 at X/F, all pass. This is bounded duplicate evidence. +- The whole-board diagnostic link is unchanged: 621 objects, 398 distinct unresolved-name tokens, + exit 1120, only the inherited `_real_local_random` duplicate; no image produced or executed. +- Fresh board-wide /W3: 4,091 before and after, identical by unit/code across all 612 CL targets. + Fresh /W4 for both units at every stage: 204 before and after (106 bipeds, 98 actor_moving), identical + warning multisets. These canonical counts differ from the lane and are reported separately. +- Production changes are confined to the two C files and the two park retirements. Tools, scorer, + verifier/pins, all other configuration and production files are unchanged. Q10 credit remains + 93 records / 661,012 bytes. The unrelated dirty README and untracked research are preserved. +- Lens-flare F3, both collisions texts, the small-function negative candidates, function-order + recovery, DD2/DD3, ai_debug casts and every other held packet stay out. + +Private receipts and controls are in `scratch/astra_biped_avoidance_reconcile_20261002/`. +They contain local build artifacts and are not published. This verification establishes bounded +object/section identity, not an exact executable link or new runtime/playability claims. diff --git a/source/ai/actor_moving.c b/source/ai/actor_moving.c index ee7c2e75..030809d7 100644 --- a/source/ai/actor_moving.c +++ b/source/ai/actor_moving.c @@ -814,10 +814,8 @@ static short actor_move_test_avoidance_vector( real *collision_t, byte *collision_timer) { - struct collision_bsp_test_vector_result collision_result; - real_vector3d offset; - real_vector3d divergence; - real scale; + real_vector3d divergence_direction; + real_vector3d origin_offset; short result = _actor_vector_avoidance_clear; short object_index; @@ -836,46 +834,51 @@ static short actor_move_test_avoidance_vector( *collision_t = REAL_MAX; - actor_move_transform_avoidance_vector(avoidance_data, &avoidance_ray->offset, &offset); - actor_move_transform_avoidance_vector(avoidance_data, &avoidance_ray->divergence, &divergence); + origin_offset = *global_zero_vector3d; + point_from_line3d((real_point3d *)&origin_offset, &avoidance_data->forward, (avoidance_ray->offset.i), (real_point3d *)&origin_offset); + point_from_line3d((real_point3d *)&origin_offset, &avoidance_data->left, (avoidance_ray->offset.j), (real_point3d *)&origin_offset); + point_from_line3d((real_point3d *)&origin_offset, &avoidance_data->up, (avoidance_ray->offset.k), (real_point3d *)&origin_offset); + divergence_direction = *global_zero_vector3d; + point_from_line3d((real_point3d *)&divergence_direction, &avoidance_data->forward, (avoidance_ray->divergence.i), (real_point3d *)&divergence_direction); + point_from_line3d((real_point3d *)&divergence_direction, &avoidance_data->left, (avoidance_ray->divergence.j), (real_point3d *)&divergence_direction); + point_from_line3d((real_point3d *)&divergence_direction, &avoidance_data->up, (avoidance_ray->divergence.k), (real_point3d *)&divergence_direction); - ray_origin->x = offset.i*avoidance_data->avoid_width + avoidance_data->origin.x; - ray_origin->y = offset.j*avoidance_data->avoid_width + avoidance_data->origin.y; - ray_origin->z = offset.k*avoidance_data->avoid_width + avoidance_data->origin.z; + point_from_line3d(&avoidance_data->origin, &origin_offset, (avoidance_data->avoid_width), ray_origin); + scale_vector3d(&divergence_direction, avoidance_ray->length*avoidance_data->avoid_distance, ray_direction); - scale = avoidance_data->avoid_distance*avoidance_ray->length; - ray_direction->i = divergence.i*scale; - ray_direction->j = divergence.j*scale; - ray_direction->k = divergence.k*scale; - - vector_from_points3d(&avoidance_data->origin, ray_origin, &offset); - if (collision_bsp_test_vector( - FLAG(_collision_test_front_facing_surfaces_bit) | - FLAG(_collision_test_back_facing_surfaces_bit), - avoidance_data->bsp, - 0, - NULL, - &avoidance_data->origin, - &offset, - 1.f, - &collision_result)) { - result = _actor_vector_avoidance_obstructed_structure; - *collision_t = 0.f; - } - else if (collision_bsp_test_vector( - FLAG(_collision_test_front_facing_surfaces_bit) | - FLAG(_collision_test_back_facing_surfaces_bit), - avoidance_data->bsp, - 0, - NULL, - ray_origin, - ray_direction, - 1.f, - &collision_result)) - { - result = _actor_vector_avoidance_obstructed_structure; - *collision_t = collision_result.t; + real_vector3d vector_to_origin; + struct collision_bsp_test_vector_result collision_result; + + vector_from_points3d(&avoidance_data->origin, ray_origin, &vector_to_origin); + if (collision_bsp_test_vector( + FLAG(_collision_test_front_facing_surfaces_bit) | + FLAG(_collision_test_back_facing_surfaces_bit), + avoidance_data->bsp, + 0, + NULL, + &avoidance_data->origin, + &vector_to_origin, + 1.f, + &collision_result)) + { + result = _actor_vector_avoidance_obstructed_structure; + *collision_t = 0.f; + } + else if (collision_bsp_test_vector( + FLAG(_collision_test_front_facing_surfaces_bit) | + FLAG(_collision_test_back_facing_surfaces_bit), + avoidance_data->bsp, + 0, + NULL, + ray_origin, + ray_direction, + 1.f, + &collision_result)) + { + result = _actor_vector_avoidance_obstructed_structure; + *collision_t = collision_result.t; + } } for (object_index = 0; @@ -884,7 +887,8 @@ static short actor_move_test_avoidance_vector( { struct vehicle_avoidance_cylinder *cylinder = &avoidance_data->avoidance_objects[object_index]; - real object_t; + real_vector3d dummy_normal; + real intersect_t; if (pill_test_vector3d( &cylinder->base, @@ -892,12 +896,12 @@ static short actor_move_test_avoidance_vector( cylinder->width, ray_origin, ray_direction, - &object_t, - &offset) && - object_t < *collision_t) + &intersect_t, + &dummy_normal) && + intersect_t < *collision_t) { result = _actor_vector_avoidance_obstructed_object; - *collision_t = object_t; + *collision_t = intersect_t; } } From a71a4ac1350500e344df6b4e9bd950c17302af5b Mon Sep 17 00:00:00 2001 From: Jonas Volman Date: Tue, 6 Oct 2026 15:40:46 -0700 Subject: [PATCH 09/17] Apply approved byte-inert cinematic shadow cleanup; record upstream exclusions --- .../upstream_punpck_review_20261006.md | 97 +++++++++++++++++++ source/cutscene/cinematics.c | 15 ++- 2 files changed, 103 insertions(+), 9 deletions(-) create mode 100644 docs/object_matching_logs/upstream_punpck_review_20261006.md diff --git a/docs/object_matching_logs/upstream_punpck_review_20261006.md b/docs/object_matching_logs/upstream_punpck_review_20261006.md new file mode 100644 index 00000000..aa9f2bd5 --- /dev/null +++ b/docs/object_matching_logs/upstream_punpck_review_20261006.md @@ -0,0 +1,97 @@ +# Upstream review and byte-inert cinematic cleanup — 2026-10-06 + +Canonical base: `fccf773db3c0adcf55f110eda5034b2c0aac4987`. +Donor: [punpckhdq/halo](https://github.com/punpckhdq/halo/tree/bc4507c1e330037fa49f9b95773f0482972ff8f9), +`bc4507c1e330037fa49f9b95773f0482972ff8f9` (cutscene #67 and the +recent models, scenario, shaders, sound, camera and network packets). + +## Independent comparison + +The donor's 468 source outputs were rebuilt with the stock local XDK compiler. +For the initial donor census only, the donor's own include/PCH context was used. +Our frozen strict COFF comparator then compared those objects against our own +January split, not a donor-generated split or donor progress score. Canonical +was separately rebuilt with its existing flags, headers and pinned tools. + +Nine donor functions are strict exact against January and not exact in this +canonical base. Their sizes below are padded section sizes, not credited gains. + +| Function | Padded bytes | Disposition | +| --- | ---: | --- | +| `_ai_debug_render_actor` | 24,976 | The donor uses the held two-local `cross_product3d` header body. No DD2 or header change imported. | +| `_poll_endpoint_set` | 560 | Immediately tested staging boolean; the existing AB #9 / Q-EU2 hold remains. | +| `_connect_async_thread_proc@4` | 304 | Unassigned thread pointer on the mutex-failure path; no new original-defect admission. | +| `_observer_update_positions` | 1,568 | Includes unused locals and held flattened-array/vector pointer views. No import. | +| `_cinematic_render` | 1,280 | Coherent body tested under canonical headers; it remains the existing residual. See below. | +| `_collision_surface_test_sphere` | 880 | Depends on a `fast_distance_squared3d` shared-header SSE helper absent from canonical. Existing reduction/helper hold remains; no helper or header import. | +| `_bsp3d_test_pill_recursive` | 1,504 | The specific negated-argument parenthesis hold remains. | +| `_bitmap_draw_string` | 304 | Donor dereferences `bounds` in the `!bounds` arm. Existing original-defect hold remains. | +| `_connected_geometry_find_or_add_vertex` | 192 | Donor uses the invented `POINT_COORDINATES_EQUAL` macro, including whole-value argument parentheses. Existing source-policy hold remains. | +| **Total, not an approved delta** | **31,568** | **No new function credited by this reconciliation.** | + +All source units were available. Seventy-seven nonexact canonical function +symbols were absent from the donor objects, so no claim of donor completeness +is made. Vendor work is not counted as Halo progress. The recent upstream +object-status and scoring changes are not automatically imported. + +## Cinematic port and retained cleanup + +The park permits research on a natural same-compiler source donor. A prediction +was recorded before compiling the complete meaningful donor statement shape, +adapted only to canonical type/member names, existing narrowing conversions, +and the unsigned shadow-alpha shift. No header, declaration-count, function +order, PCH or flag experiment was used to force the result. + +An initial adaptation mistakenly treated donor `MASK(24)` as available here; +canonical has no such macro. Replacing that with the existing `0x00FFFFFF` +literal removes the accidental implicit call. The corrected port reproduces +canonical's *existing* 1,280-byte / 57-relocation residual section exactly: +`1a9d49fc4eace03cb02268a6434f252b45496477fac007eba679c72e4b5c8d1c`. +January's hash remains +`a89dcee38e6a239615cde9f2d1f3b2fc577ced717e620de08a6397f74a0e6288`. +The remaining donor-context dependency was not isolated and is not claimed as +recovered January source. The broad body replacement did not land. + +Only the already approved OQ-FI6 B1 cleanup is retained: compute shadow alpha +inside `rasterizer_text_set_shadow_color`, instead of naming `shadow_alpha`. +The later `/Od` and demo line-table evidence for this direct expression was +previously recorded in the lane. Existing conversions, arithmetic, macros, +types and control flow are preserved. This is a zero-credit fidelity cleanup, +not a match, a recovered debit or an object admission. + +The cinematic park, its reopen criterion and the existing uncredited +`_fast_ftol` helper copy remain unchanged. No Matching status is flipped. + +## Verification contract + +Before publication: clean full build; strict whole-board snapshot (zero gains, +zero losses); normalized fingerprints of all 621 built objects identical; +owned data and provider inventory unchanged; common-pool credit unchanged; +parks and admission audit unchanged; tools tests and fake scan; unchanged +whole-board /W3 and cinematic /W4 warning multisets. Compiler, scorer, +verifiers, pins, allowlists, atlas, headers and denominators are untouched. + +Private binary inputs, scratch objects, donor checkout and receipts are not +published. This log records the unsuccessful exact port and the exclusions so +that upstream progress is not mistaken for additive canonical byte credit. + +### Fresh result + +The full before/after builds and gates passed. All 621 normalized object +fingerprints are identical, including provider attributes and section order. +Strict snapshot: 8,252 target functions, 7,656 exact on both sides (includes +vendor/helper rows); gains 0, losses 0. Credited Halo progress remains: + +- Functions: 7,483 / 7,573. +- Meaningful code: 1,603,071 / 1,770,166 bytes. +- Data: 3,311,591 / 3,922,163 bytes. +- Matching objects: 396 / 468; active parks: 59, stale 0, invalid 0. +- Admission audit: 9 candidates, 0 contradictions, 0 rejections, 0 revocations. +- Tools tests: 1,663 passed, 5 skipped, 159 passing subtests, both before and + after; fake scan: the same 26 inherited review leads. +- /W3: identical per-unit warning multisets, 4,091 board-wide warnings. + Cinematic /W4: identical multiset, 67 warnings. + +Production compiler inputs, tool hashes and common-pool credit are unchanged. +No runtime executable was launched. Only the approved expression cleanup and +this disclosure are committed. diff --git a/source/cutscene/cinematics.c b/source/cutscene/cinematics.c index f2d13e18..ca8964f1 100644 --- a/source/cutscene/cinematics.c +++ b/source/cutscene/cinematics.c @@ -425,7 +425,6 @@ void cinematic_render( { real_argb_color text_color; - long shadow_alpha; pixel32_to_real_argb_color( title->foreground_color, @@ -448,15 +447,13 @@ void cinematic_render( title->text_flags, &text_color); - shadow_alpha = PIN( - fast_ftol( - (real)(long)(byte)(title->shadow_color >> 24) * - fade_amount), - 0, - 255); - rasterizer_text_set_shadow_color( - ((pixel32)shadow_alpha << 24) | + ((pixel32)PIN( + fast_ftol( + (real)(long)(byte)(title->shadow_color >> 24) * + fade_amount), + 0, + 255) << 24) | (title->shadow_color & 0x00FFFFFF)); rasterizer_draw_unicode_string( From 73677cf26df696770a58e1838dc8ebc1cba20655 Mon Sep 17 00:00:00 2001 From: Jonas Volman Date: Fri, 9 Oct 2026 02:58:29 -0700 Subject: [PATCH 10/17] Remove empty header stubs and unused shader-stage enums Zero credit: remove 51 guard-only headers, 50 project-list entries, four useless includes and two unused enum definitions. Preserve source assertion locations and both repositories existing READMEs. Clean rebuild, unchanged 8252-row strict snapshot, unchanged code/data credit and admissions, 1663 tests plus 159 subtests pass. Disclose 76 compiler-local label renumberings and two warning source-line shifts; runtime sections and relocations remain identical. No private assets or scratch tooling published. --- config/config.json | 50 ------------ .../empty_header_cleanup_20261009.md | 80 +++++++++++++++++++ source/ai/actor_type_definitions.h | 23 ------ source/ai/ai_constants.h | 23 ------ source/bitmaps/bitmap_macros.h | 23 ------ source/bungie_net/common/memory_manager.h | 23 ------ source/camera/camera_track_definitions.h | 23 ------ source/cseries/build_number.h | 23 ------ source/cseries/headers.h | 23 ------ source/cseries/platform.h | 23 ------ source/dialogs/dialogs.h | 23 ------ source/effects/particle_definitions.h | 23 ------ source/hs/hs_compile.c | 2 +- source/hs/hs_enum.h | 23 ------ source/hs/hs_function.h | 23 ------ source/hs/hs_glue.h | 23 ------ source/hs/hs_library_internal_compile.h | 23 ------ source/hs/hs_library_internal_runtime.h | 23 ------ source/hs/hs_runtime.c | 2 +- source/input/input_device_defaults.h | 23 ------ source/input/input_windows.h | 23 ------ source/interface/hud_messaging_definitions.h | 23 ------ source/interface/interface_panels.h | 23 ------ source/interface/inventory_displays.h | 23 ------ source/interface/meter_definitions.h | 23 ------ source/interface/ui_widget_group.h | 23 ------ source/items/garbage_definitions.h | 23 ------ source/items/weapon_interface_definitions.h | 23 ------ source/math/vector_tree.h | 23 ------ source/memory/sl_list.h | 23 ------ source/objects/index_resolution.h | 23 ------ source/objects/widgets/aleph.h | 23 ------ source/objects/widgets/antenna_definitions.h | 23 ------ source/objects/widgets/cellular_automata.h | 23 ------ source/objects/widgets/cellular_automata2d.h | 23 ------ source/objects/widgets/flag_definitions.h | 23 ------ source/objects/widgets/glow_definitions.h | 23 ------ .../widgets/light_volume_definitions.h | 23 ------ .../objects/widgets/lightning_definitions.h | 23 ------ source/physics/physics_constants.h | 23 ------ source/physics/terrain_definitions.h | 23 ------ .../rasterizer_hardware_format_utilities.h | 23 ------ source/rasterizer/rasterizer_memory_pool.c | 2 +- source/rasterizer/rasterizer_memory_pool.h | 11 --- .../xbox/rasterizer_xbox_environment.c | 2 +- .../xbox/rasterizer_xbox_environment_fog.c | 5 -- .../shader_transparent_generic_preprocessor.c | 5 -- source/saved films/saved_films.h | 23 ------ source/saved games/game_state_procs.h | 23 ------ source/scenario/scenario_placement.h | 23 ------ source/scenario/structure_bsp_procs.h | 23 ------ source/shell/shell_windows.h | 23 ------ source/sound/platform_sound.h | 23 ------ source/strings/resource.h | 23 ------ source/structures/detail_object_definitions.h | 23 ------ source/structures/radiosity/radiosity.h | 23 ------ source/structures/radiosity/radiosity_io.h | 23 ------ source/text/draw_string_types.h | 23 ------ source/tool/intermediate_geometry.h | 23 ------ 59 files changed, 84 insertions(+), 1225 deletions(-) create mode 100644 docs/object_matching_logs/empty_header_cleanup_20261009.md delete mode 100644 source/ai/actor_type_definitions.h delete mode 100644 source/ai/ai_constants.h delete mode 100644 source/bitmaps/bitmap_macros.h delete mode 100644 source/bungie_net/common/memory_manager.h delete mode 100644 source/camera/camera_track_definitions.h delete mode 100644 source/cseries/build_number.h delete mode 100644 source/cseries/headers.h delete mode 100644 source/cseries/platform.h delete mode 100644 source/dialogs/dialogs.h delete mode 100644 source/effects/particle_definitions.h delete mode 100644 source/hs/hs_enum.h delete mode 100644 source/hs/hs_function.h delete mode 100644 source/hs/hs_glue.h delete mode 100644 source/hs/hs_library_internal_compile.h delete mode 100644 source/hs/hs_library_internal_runtime.h delete mode 100644 source/input/input_device_defaults.h delete mode 100644 source/input/input_windows.h delete mode 100644 source/interface/hud_messaging_definitions.h delete mode 100644 source/interface/interface_panels.h delete mode 100644 source/interface/inventory_displays.h delete mode 100644 source/interface/meter_definitions.h delete mode 100644 source/interface/ui_widget_group.h delete mode 100644 source/items/garbage_definitions.h delete mode 100644 source/items/weapon_interface_definitions.h delete mode 100644 source/math/vector_tree.h delete mode 100644 source/memory/sl_list.h delete mode 100644 source/objects/index_resolution.h delete mode 100644 source/objects/widgets/aleph.h delete mode 100644 source/objects/widgets/antenna_definitions.h delete mode 100644 source/objects/widgets/cellular_automata.h delete mode 100644 source/objects/widgets/cellular_automata2d.h delete mode 100644 source/objects/widgets/flag_definitions.h delete mode 100644 source/objects/widgets/glow_definitions.h delete mode 100644 source/objects/widgets/light_volume_definitions.h delete mode 100644 source/objects/widgets/lightning_definitions.h delete mode 100644 source/physics/physics_constants.h delete mode 100644 source/physics/terrain_definitions.h delete mode 100644 source/rasterizer/rasterizer_hardware_format_utilities.h delete mode 100644 source/rasterizer/rasterizer_memory_pool.h delete mode 100644 source/saved films/saved_films.h delete mode 100644 source/saved games/game_state_procs.h delete mode 100644 source/scenario/scenario_placement.h delete mode 100644 source/scenario/structure_bsp_procs.h delete mode 100644 source/shell/shell_windows.h delete mode 100644 source/sound/platform_sound.h delete mode 100644 source/strings/resource.h delete mode 100644 source/structures/detail_object_definitions.h delete mode 100644 source/structures/radiosity/radiosity.h delete mode 100644 source/structures/radiosity/radiosity_io.h delete mode 100644 source/text/draw_string_types.h delete mode 100644 source/tool/intermediate_geometry.h diff --git a/config/config.json b/config/config.json index f7b12f97..2d8b858b 100644 --- a/config/config.json +++ b/config/config.json @@ -59,12 +59,10 @@ "headers": [ "source/ai/actions.h", "source/ai/actor_definitions.h", - "source/ai/actor_type_definitions.h", "source/ai/actor_types.h", "source/ai/actors.h", "source/ai/ai.h", "source/ai/ai_communication.h", - "source/ai/ai_constants.h", "source/ai/ai_debug.h", "source/ai/ai_globals.h", "source/ai/ai_profile.h", @@ -76,7 +74,6 @@ "source/bink/bink_playback.h", "source/bitmaps/bitmap_drawing.h", "source/bitmaps/bitmap_group.h", - "source/bitmaps/bitmap_macros.h", "source/bitmaps/bitmaps.h", "source/bitmaps/bitmaps_inlines.h", "source/bitmaps/color_table_group.h", @@ -91,7 +88,6 @@ "source/bitmaps/libtiff/tiffioP.h", "source/bitmaps/s3tc/s3tc.h", "source/bungie_net/common/64bit_math.h", - "source/bungie_net/common/memory_manager.h", "source/bungie_net/common/message_encryption.h", "source/bungie_net/common/message_header.h", "source/bungie_net/common/public_key_crypt.h", @@ -107,7 +103,6 @@ "source/cache/texture_cache.h", "source/camera/bored_camera.h", "source/camera/camera_scripting.h", - "source/camera/camera_track_definitions.h", "source/camera/dead_camera.h", "source/camera/director.h", "source/camera/editor_flying_camera.h", @@ -117,12 +112,9 @@ "source/camera/observer.h", "source/camera/orbiting_camera.h", "source/camera/static_camera.h", - "source/cseries/build_number.h", "source/cseries/cseries.h", "source/cseries/cseries_windows.h", "source/cseries/errors.h", - "source/cseries/headers.h", - "source/cseries/platform.h", "source/cseries/progress.h", "source/cutscene/cinematics.h", "source/cutscene/recorded_animation_definitions.h", @@ -132,7 +124,6 @@ "source/devices/device_definitions.h", "source/devices/device_light_fixtures.h", "source/devices/devices.h", - "source/dialogs/dialogs.h", "source/dialogs/edit_text.h", "source/editor/editor_stubs.h", "source/effects/contrail_definitions.h", @@ -143,7 +134,6 @@ "source/effects/effects.h", "source/effects/material_effect_definitions.h", "source/effects/material_effects.h", - "source/effects/particle_definitions.h", "source/effects/particle_system_definitions.h", "source/effects/particle_systems.h", "source/effects/particles.h", @@ -158,32 +148,21 @@ "source/game/game_globals.h", "source/game/players.h", "source/hs/hs.h", - "source/hs/hs_enum.h", - "source/hs/hs_function.h", - "source/hs/hs_glue.h", "source/hs/hs_library_external.h", "source/hs/hs_library_internal.h", - "source/hs/hs_library_internal_compile.h", - "source/hs/hs_library_internal_runtime.h", "source/hs/hs_scenario_definitions.h", "source/hs/object_lists.h", "source/input/HaloAutoTest.h", "source/input/input.h", "source/input/input_abstraction.h", - "source/input/input_device_defaults.h", - "source/input/input_windows.h", "source/interface/attract_mode.h", "source/interface/event_manager.h", "source/interface/first_person_weapons.h", "source/interface/hud.h", "source/interface/hud_definitions.h", "source/interface/hud_messaging.h", - "source/interface/hud_messaging_definitions.h", "source/interface/interface.h", - "source/interface/interface_panels.h", - "source/interface/inventory_displays.h", "source/interface/marketing_and_strategic_business_development.h", - "source/interface/meter_definitions.h", "source/interface/motion_sensor.h", "source/interface/player_ui.h", "source/interface/progress_bar.h", @@ -191,7 +170,6 @@ "source/interface/ui_widget.h", "source/interface/ui_widget_event_handler_functions.h", "source/interface/ui_widget_game_data_input_functions.h", - "source/interface/ui_widget_group.h", "source/interface/ui_widget_text_search_and_replace_functions.h", "source/interface/unit_hud_interface_definition.h", "source/interface/virtual_keyboard.h", @@ -199,13 +177,11 @@ "source/items/equipment.h", "source/items/equipment_definitions.h", "source/items/garbage.h", - "source/items/garbage_definitions.h", "source/items/item_definitions.h", "source/items/items.h", "source/items/projectile_definitions.h", "source/items/projectiles.h", "source/items/weapon_definitions.h", - "source/items/weapon_interface_definitions.h", "source/items/weapons.h", "source/main/console.h", "source/main/d3d_intimacy.h", @@ -216,7 +192,6 @@ "source/math/integer_math.h", "source/math/periodic_functions.h", "source/math/real_math.h", - "source/math/vector_tree.h", "source/memory/array.h", "source/memory/byte_swapping.h", "source/memory/circular_queue.h", @@ -230,7 +205,6 @@ "source/memory/lru_cache.h", "source/memory/lruv_cache.h", "source/memory/memory_pool.h", - "source/memory/sl_list.h", "source/memory/stack_memory_pool.h", "source/memory/texture_page.h", "source/memory/zlib/deflate.h", @@ -260,7 +234,6 @@ "source/objects/damage.h", "source/objects/damage_effect_definitions.h", "source/objects/damage_resistances.h", - "source/objects/index_resolution.h", "source/objects/light_definitions.h", "source/objects/object_definitions.h", "source/objects/object_lights.h", @@ -269,19 +242,11 @@ "source/objects/placeholder_definitions.h", "source/objects/reference_lists.h", "source/objects/scenery.h", - "source/objects/widgets/aleph.h", "source/objects/widgets/antenna.h", - "source/objects/widgets/antenna_definitions.h", - "source/objects/widgets/cellular_automata.h", - "source/objects/widgets/cellular_automata2d.h", - "source/objects/widgets/flag_definitions.h", "source/objects/widgets/flags.h", "source/objects/widgets/glow.h", - "source/objects/widgets/glow_definitions.h", - "source/objects/widgets/light_volume_definitions.h", "source/objects/widgets/light_volumes.h", "source/objects/widgets/lightning.h", - "source/objects/widgets/lightning_definitions.h", "source/objects/widgets/widget_types.h", "source/objects/widgets/widgets.h", "source/physics/breakable_surfaces.h", @@ -296,27 +261,22 @@ "source/physics/collision_usage.h", "source/physics/collisions.h", "source/physics/physics.h", - "source/physics/physics_constants.h", "source/physics/physics_definitions.h", "source/physics/physics_variables.h", "source/physics/point_physics.h", - "source/physics/terrain_definitions.h", "source/rasterizer/xbox/rasterizer_xbox.h", "source/rasterizer/common/rasterizer_common.h", "source/rasterizer/rasterizer.h", "source/rasterizer/rasterizer_cinematics.h", "source/rasterizer/rasterizer_console_vars.h", "source/rasterizer/rasterizer_geometry.h", - "source/rasterizer/rasterizer_hardware_format_utilities.h", "source/rasterizer/rasterizer_swizzle.h", "source/rasterizer/rasterizer_widgets.h", "source/render/render.h", "source/render/render_cameras.h", "source/render/render_debug.h", "source/render/triangle_strips.h", - "source/saved films/saved_films.h", "source/saved games/game_state.h", - "source/saved games/game_state_procs.h", "source/saved games/player_profile.h", "source/saved games/playlist_profile.h", "source/saved games/saved_game_files.h", @@ -324,17 +284,13 @@ "source/scenario/multiplayer_scenario_description.h", "source/scenario/scenario.h", "source/scenario/scenario_definitions.h", - "source/scenario/scenario_placement.h", "source/scenario/sky_definitions.h", - "source/scenario/structure_bsp_procs.h", "source/scenario/wind_definitions.h", "source/shaders/shader_definitions.h", "source/shaders/shaders.h", "source/shell/shell.h", - "source/shell/shell_windows.h", "source/sound/game_sound.h", "source/sound/ima_adpcm.h", - "source/sound/platform_sound.h", "source/sound/sound_classes.h", "source/sound/sound_definitions.h", "source/sound/sound_dsound.h", @@ -343,26 +299,20 @@ "source/sound/sound_manager.h", "source/sound/sound_preferences.h", "source/sound/sound_scenery.h", - "source/strings/resource.h", "source/structures/cluster_partitions.h", - "source/structures/detail_object_definitions.h", "source/structures/leaf_map.h", - "source/structures/radiosity/radiosity.h", - "source/structures/radiosity/radiosity_io.h", "source/structures/structure_bsp_definitions.h", "source/structures/structures.h", "source/tag_files/files.h", "source/tag_files/tag_files.h", "source/tag_files/tag_groups.h", "source/text/draw_string.h", - "source/text/draw_string_types.h", "source/text/font_group.h", "source/text/international_strings.h", "source/text/text_group.h", "source/text/unicode.h", "source/tool/connected_geometry.h", "source/tool/error_geometry.h", - "source/tool/intermediate_geometry.h", "source/units/biped_definitions.h", "source/units/biped_limp_noodle.h", "source/units/bipeds.h", diff --git a/docs/object_matching_logs/empty_header_cleanup_20261009.md b/docs/object_matching_logs/empty_header_cleanup_20261009.md new file mode 100644 index 00000000..5da632c6 --- /dev/null +++ b/docs/object_matching_logs/empty_header_cleanup_20261009.md @@ -0,0 +1,80 @@ +# Empty-header and unused-enum cleanup — 2026-10-09 + +Exact-pilots base: `a71a4ac1350500e344df6b4e9bd950c17302af5b`. +Halo-1 main base: `b43c70168ad7040ec1a663842f5faa7e1a1bc0cd`. +Their source, library, configuration and tooling trees agree; their separate +READMEs are preserved. Owner approval: implement the tested removals and push +to both repositories only without loss of byte matching or functionality. + +## Scope and provenance + +Remove all 51 currently empty reconstructed headers, the 50 corresponding +project-header list rows, and four now-useless includes. The four includes +become explanatory one-line comments, retaining existing assertion locations. +No remaining declaration, helper, type or owning interface is moved. + +Forty-seven removed headers entered in `4bd27e82` ("Push all applicable HCEX +header stubs"); three entered in the initial reconstruction; the memory-pool +header entered in `1ad31494`. The compile/runtime HS headers and memory-pool +header once held prototypes, removed by the approved ownership reconciliation +in `f3aadeab`. Their known later-build filenames are not declared fictitious: +recreate an appropriate header when authentic content is recovered. This is +cleanup of their current empty state, not a new ownership ruling. + +Also remove the unused `NUMBER_OF_PIXEL_SHADER_STAGES = 8` enum definitions +from `rasterizer_xbox_environment_fog.c` and +`shader_transparent_generic_preprocessor.c`. They entered in `4ad9bd84` and +`e49fee8f`. Direct use scans and stock VC7 preprocessing show the identifier +occurs only at its definition in each unit. Other repeated enum families are +untouched; no shared owner header or replacement constant is invented. + +No code body, symbol atlas, credit manifest, verifier, pin, compiler flag, +library, Matching status or park is changed. No credited gain is claimed. + +## Fresh landing checks + +Clean full builds before and after, at the actual exact-pilots landing HEAD: + +- All 621 compiler commands are identical; command-stream SHA-256: + `84f787de49aa7664c364d1cd42b44eb53669a00c7209c2be45869d6545ae7512`. +- All 8,252 strict target function rows are identical, including residual + fingerprints: 7,656 strict-exact rows on each side, including vendor/helper + rows. Gained 0, lost 0; no function or data re-credit. +- All 833 split objects are identical except COFF timestamps. Of 621 rebuilt + objects, 619 are identical under that same timestamp-only exclusion. +- The remaining two objects differ only in compiler-local `$L` names: + `hs_runtime.obj` has 64 renamings; `rasterizer_xbox_environment.obj` has 12. + Each keeps its symbol-table index, storage, type, section and offset. The + complete raw objects are identical after masking only timestamps and those + 76 independently verified name fields. No comparator was changed to accept + this: the frozen strict gate already verifies every function unchanged. +- Thus runtime section bytes, relocation records, provider code/selection + attributes, owned data, source-owned symbols and storage offsets are + unchanged. No new provider or helper copy is emitted. +- Admission audit is identical: 9 candidates, 0 contradicted, 0 rejected, + 0 revoked. Fake scan retains the same 26 inherited review leads. +- Tools suite before and after: 1,663 passed, 5 skipped, 159 passing subtests. +- Separate `/W3` compilations: 612 CL units on each side, 0 failures, 4,091 + warnings. Diagnostics are identical; only two physical source positions + move in the fog unit: C4700 `previous_camera_matrix`, 944 -> 939; C4244 + double-to-real conversion, 1015 -> 1010. No warning is added or silenced. +- Whitespace checks pass. Source files retain the checkout's CRLF convention. + +Credited Halo totals are unchanged: + +- Functions: 7,483 / 7,573. +- Meaningful code: 1,603,071 / 1,770,166 bytes. +- Data: 3,311,591 / 3,922,163 bytes. +- Matching objects: 396 / 468. +- Parks: 59 valid. +- COMMON credit: 93 records, +661,012 bytes, unchanged. + +Private receipts and before/after objects remain local under +`scratch/empty_header_cleanup_20261009`. No private binary, SDK, PDB or scratch +tool is published. No reconstructed executable was launched. Behavior +preservation here is established by unchanged compiled runtime sections and +relocations, not a gameplay smoke test or a promise about other configurations. + +The same source/configuration packet is applied to Halo-1 main without changing +its README. Publication must remain fast-forward, with the remote bases +rechecked before each push; any new remote code requires fresh reconciliation. diff --git a/source/ai/actor_type_definitions.h b/source/ai/actor_type_definitions.h deleted file mode 100644 index 04b25b63..00000000 --- a/source/ai/actor_type_definitions.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -ACTOR_TYPE_DEFINITIONS.H - -file has inline function assertions. -*/ - -#ifndef __ACTOR_TYPE_DEFINITIONS_H -#define __ACTOR_TYPE_DEFINITIONS_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __ACTOR_TYPE_DEFINITIONS_H diff --git a/source/ai/ai_constants.h b/source/ai/ai_constants.h deleted file mode 100644 index 21cd8c91..00000000 --- a/source/ai/ai_constants.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -AI_CONSTANTS.H - -header included in hcex build. -*/ - -#ifndef __AI_CONSTANTS_H -#define __AI_CONSTANTS_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __AI_CONSTANTS_H diff --git a/source/bitmaps/bitmap_macros.h b/source/bitmaps/bitmap_macros.h deleted file mode 100644 index bd547c9f..00000000 --- a/source/bitmaps/bitmap_macros.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -BITMAP_MACROS.H - -header included in hcex build. -*/ - -#ifndef __BITMAP_MACROS_H -#define __BITMAP_MACROS_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __BITMAP_MACROS_H diff --git a/source/bungie_net/common/memory_manager.h b/source/bungie_net/common/memory_manager.h deleted file mode 100644 index b110f063..00000000 --- a/source/bungie_net/common/memory_manager.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -MEMORY_MANAGER.H - -header included in hcex build. -*/ - -#ifndef __MEMORY_MANAGER_H -#define __MEMORY_MANAGER_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __MEMORY_MANAGER_H diff --git a/source/camera/camera_track_definitions.h b/source/camera/camera_track_definitions.h deleted file mode 100644 index 00d97956..00000000 --- a/source/camera/camera_track_definitions.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -CAMERA_TRACK_DEFINITIONS.H - -header included in hcex build. -*/ - -#ifndef __CAMERA_TRACK_DEFINITIONS_H -#define __CAMERA_TRACK_DEFINITIONS_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __CAMERA_TRACK_DEFINITIONS_H diff --git a/source/cseries/build_number.h b/source/cseries/build_number.h deleted file mode 100644 index 5d59c92f..00000000 --- a/source/cseries/build_number.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -BUILD_NUMBER.H - -header included in hcex build. -*/ - -#ifndef __BUILD_NUMBER_H -#define __BUILD_NUMBER_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __BUILD_NUMBER_H diff --git a/source/cseries/headers.h b/source/cseries/headers.h deleted file mode 100644 index b870c2cc..00000000 --- a/source/cseries/headers.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -HEADERS.H - -header included in hcex build. -*/ - -#ifndef __HEADERS_H -#define __HEADERS_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __HEADERS_H diff --git a/source/cseries/platform.h b/source/cseries/platform.h deleted file mode 100644 index 178b0844..00000000 --- a/source/cseries/platform.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -PLATFORM.H - -header included in hcex build. -*/ - -#ifndef __PLATFORM_H -#define __PLATFORM_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __PLATFORM_H diff --git a/source/dialogs/dialogs.h b/source/dialogs/dialogs.h deleted file mode 100644 index 1bbe187c..00000000 --- a/source/dialogs/dialogs.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -DIALOGS.H - -header included in hcex build. -*/ - -#ifndef __DIALOGS_H -#define __DIALOGS_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __DIALOGS_H diff --git a/source/effects/particle_definitions.h b/source/effects/particle_definitions.h deleted file mode 100644 index aee56088..00000000 --- a/source/effects/particle_definitions.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -PARTICLE_DEFINITIONS.H - -header included in hcex build. -*/ - -#ifndef __PARTICLE_DEFINITIONS_H -#define __PARTICLE_DEFINITIONS_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __PARTICLE_DEFINITIONS_H diff --git a/source/hs/hs_compile.c b/source/hs/hs_compile.c index b77588b2..977d9ad6 100644 --- a/source/hs/hs_compile.c +++ b/source/hs/hs_compile.c @@ -413,7 +413,7 @@ symbols in this file: #include "ai/ai_script.h" #include "hs/hs.h" #include "hs/hs_library_internal.h" -#include "hs/hs_library_internal_compile.h" +/* Empty reconstructed header removed; no declarations to include. */ #include "hs/hs_scenario_definitions.h" #include "interface/hud_definitions.h" #include "interface/interface.h" diff --git a/source/hs/hs_enum.h b/source/hs/hs_enum.h deleted file mode 100644 index 32c750f1..00000000 --- a/source/hs/hs_enum.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -HS_ENUM.H - -header included in hcex build. -*/ - -#ifndef __HS_ENUM_H -#define __HS_ENUM_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __HS_ENUM_H diff --git a/source/hs/hs_function.h b/source/hs/hs_function.h deleted file mode 100644 index 06d0cf0a..00000000 --- a/source/hs/hs_function.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -HS_FUNCTION.H - -header included in hcex build. -*/ - -#ifndef __HS_FUNCTION_H -#define __HS_FUNCTION_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __HS_FUNCTION_H diff --git a/source/hs/hs_glue.h b/source/hs/hs_glue.h deleted file mode 100644 index d2b7381f..00000000 --- a/source/hs/hs_glue.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -HS_GLUE.H - -header included in hcex build. -*/ - -#ifndef __HS_GLUE_H -#define __HS_GLUE_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __HS_GLUE_H diff --git a/source/hs/hs_library_internal_compile.h b/source/hs/hs_library_internal_compile.h deleted file mode 100644 index 80ebfedf..00000000 --- a/source/hs/hs_library_internal_compile.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -HS_LIBRARY_INTERNAL_COMPILE.H - -file has inline function assertions. -*/ - -#ifndef __HS_LIBRARY_INTERNAL_COMPILE_H -#define __HS_LIBRARY_INTERNAL_COMPILE_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/HS_COMPILE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __HS_LIBRARY_INTERNAL_COMPILE_H diff --git a/source/hs/hs_library_internal_runtime.h b/source/hs/hs_library_internal_runtime.h deleted file mode 100644 index 6b51fde9..00000000 --- a/source/hs/hs_library_internal_runtime.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -HS_LIBRARY_INTERNAL_RUNTIME.H - -file has inline function assertions. -*/ - -#ifndef __HS_LIBRARY_INTERNAL_RUNTIME_H -#define __HS_LIBRARY_INTERNAL_RUNTIME_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/HS_RUNTIME.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __HS_LIBRARY_INTERNAL_RUNTIME_H diff --git a/source/hs/hs_runtime.c b/source/hs/hs_runtime.c index 51e5b910..f989a488 100644 --- a/source/hs/hs_runtime.c +++ b/source/hs/hs_runtime.c @@ -266,7 +266,7 @@ symbols in this file: #include "ai/ai_script.h" #include "hs/hs.h" #include "hs/hs_library_internal.h" -#include "hs/hs_library_internal_runtime.h" +/* Empty reconstructed header removed; no declarations to include. */ #include "hs/object_lists.h" #include "hs/hs_scenario_definitions.h" #include "math/real_math.h" diff --git a/source/input/input_device_defaults.h b/source/input/input_device_defaults.h deleted file mode 100644 index ca9989e7..00000000 --- a/source/input/input_device_defaults.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -INPUT_DEVICE_DEFAULTS.H - -header included in hcex build. -*/ - -#ifndef __INPUT_DEVICE_DEFAULTS_H -#define __INPUT_DEVICE_DEFAULTS_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __INPUT_DEVICE_DEFAULTS_H diff --git a/source/input/input_windows.h b/source/input/input_windows.h deleted file mode 100644 index c18cd27c..00000000 --- a/source/input/input_windows.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -INPUT_WINDOWS.H - -header included in hcex build. -*/ - -#ifndef __INPUT_WINDOWS_H -#define __INPUT_WINDOWS_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __INPUT_WINDOWS_H diff --git a/source/interface/hud_messaging_definitions.h b/source/interface/hud_messaging_definitions.h deleted file mode 100644 index 3d766085..00000000 --- a/source/interface/hud_messaging_definitions.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -HUD_MESSAGING_DEFINITIONS.H - -header included in hcex build. -*/ - -#ifndef __HUD_MESSAGING_DEFINITIONS_H -#define __HUD_MESSAGING_DEFINITIONS_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __HUD_MESSAGING_DEFINITIONS_H diff --git a/source/interface/interface_panels.h b/source/interface/interface_panels.h deleted file mode 100644 index dee43d2f..00000000 --- a/source/interface/interface_panels.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -INTERFACE_PANELS.H - -header included in hcex build. -*/ - -#ifndef __INTERFACE_PANELS_H -#define __INTERFACE_PANELS_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __INTERFACE_PANELS_H diff --git a/source/interface/inventory_displays.h b/source/interface/inventory_displays.h deleted file mode 100644 index de198854..00000000 --- a/source/interface/inventory_displays.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -INVENTORY_DISPLAYS.H - -header included in hcex build. -*/ - -#ifndef __INVENTORY_DISPLAYS_H -#define __INVENTORY_DISPLAYS_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __INVENTORY_DISPLAYS_H diff --git a/source/interface/meter_definitions.h b/source/interface/meter_definitions.h deleted file mode 100644 index 8dbd1846..00000000 --- a/source/interface/meter_definitions.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -METER_DEFINITIONS.H - -header included in hcex build. -*/ - -#ifndef __METER_DEFINITIONS_H -#define __METER_DEFINITIONS_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __METER_DEFINITIONS_H diff --git a/source/interface/ui_widget_group.h b/source/interface/ui_widget_group.h deleted file mode 100644 index 6d2b511f..00000000 --- a/source/interface/ui_widget_group.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -UI_WIDGET_GROUP.H - -header included in hcex build. -*/ - -#ifndef __UI_WIDGET_GROUP_H -#define __UI_WIDGET_GROUP_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __UI_WIDGET_GROUP_H diff --git a/source/items/garbage_definitions.h b/source/items/garbage_definitions.h deleted file mode 100644 index a8530c5c..00000000 --- a/source/items/garbage_definitions.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -GARBAGE_DEFINITIONS.H - -header included in hcex build. -*/ - -#ifndef __GARBAGE_DEFINITIONS_H -#define __GARBAGE_DEFINITIONS_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __GARBAGE_DEFINITIONS_H diff --git a/source/items/weapon_interface_definitions.h b/source/items/weapon_interface_definitions.h deleted file mode 100644 index 37e38014..00000000 --- a/source/items/weapon_interface_definitions.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -WEAPON_INTERFACE_DEFINITIONS.H - -header included in hcex build. -*/ - -#ifndef __WEAPON_INTERFACE_DEFINITIONS_H -#define __WEAPON_INTERFACE_DEFINITIONS_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __WEAPON_INTERFACE_DEFINITIONS_H diff --git a/source/math/vector_tree.h b/source/math/vector_tree.h deleted file mode 100644 index 856b4cbf..00000000 --- a/source/math/vector_tree.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -VECTOR_TREE.H - -header included in hcex build. -*/ - -#ifndef __VECTOR_TREE_H -#define __VECTOR_TREE_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __VECTOR_TREE_H diff --git a/source/memory/sl_list.h b/source/memory/sl_list.h deleted file mode 100644 index fd854e2e..00000000 --- a/source/memory/sl_list.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -SL_LIST.H - -header included in hcex build. -*/ - -#ifndef __SL_LIST_H -#define __SL_LIST_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __SL_LIST_H diff --git a/source/objects/index_resolution.h b/source/objects/index_resolution.h deleted file mode 100644 index 6c360e2f..00000000 --- a/source/objects/index_resolution.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -INDEX_RESOLUTION.H - -header included in hcex build. -*/ - -#ifndef __INDEX_RESOLUTION_H -#define __INDEX_RESOLUTION_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __INDEX_RESOLUTION_H diff --git a/source/objects/widgets/aleph.h b/source/objects/widgets/aleph.h deleted file mode 100644 index d32d1360..00000000 --- a/source/objects/widgets/aleph.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -ALEPH.H - -header included in hcex build. -*/ - -#ifndef __ALEPH_H -#define __ALEPH_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __ALEPH_H diff --git a/source/objects/widgets/antenna_definitions.h b/source/objects/widgets/antenna_definitions.h deleted file mode 100644 index 5788f773..00000000 --- a/source/objects/widgets/antenna_definitions.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -ANTENNA_DEFINITIONS.H - -header included in hcex build. -*/ - -#ifndef __ANTENNA_DEFINITIONS_H -#define __ANTENNA_DEFINITIONS_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __ANTENNA_DEFINITIONS_H diff --git a/source/objects/widgets/cellular_automata.h b/source/objects/widgets/cellular_automata.h deleted file mode 100644 index 2c0bdfdf..00000000 --- a/source/objects/widgets/cellular_automata.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -CELLULAR_AUTOMATA.H - -header included in hcex build. -*/ - -#ifndef __CELLULAR_AUTOMATA_H -#define __CELLULAR_AUTOMATA_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __CELLULAR_AUTOMATA_H diff --git a/source/objects/widgets/cellular_automata2d.h b/source/objects/widgets/cellular_automata2d.h deleted file mode 100644 index 0445d870..00000000 --- a/source/objects/widgets/cellular_automata2d.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -CELLULAR_AUTOMATA2D.H - -header included in hcex build. -*/ - -#ifndef __CELLULAR_AUTOMATA2D_H -#define __CELLULAR_AUTOMATA2D_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __CELLULAR_AUTOMATA2D_H diff --git a/source/objects/widgets/flag_definitions.h b/source/objects/widgets/flag_definitions.h deleted file mode 100644 index be3c394e..00000000 --- a/source/objects/widgets/flag_definitions.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -FLAG_DEFINITIONS.H - -header included in hcex build. -*/ - -#ifndef __FLAG_DEFINITIONS_H -#define __FLAG_DEFINITIONS_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __FLAG_DEFINITIONS_H diff --git a/source/objects/widgets/glow_definitions.h b/source/objects/widgets/glow_definitions.h deleted file mode 100644 index 5e73eba3..00000000 --- a/source/objects/widgets/glow_definitions.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -GLOW_DEFINITIONS.H - -header included in hcex build. -*/ - -#ifndef __GLOW_DEFINITIONS_H -#define __GLOW_DEFINITIONS_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __GLOW_DEFINITIONS_H diff --git a/source/objects/widgets/light_volume_definitions.h b/source/objects/widgets/light_volume_definitions.h deleted file mode 100644 index 4737f509..00000000 --- a/source/objects/widgets/light_volume_definitions.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -LIGHT_VOLUME_DEFINITIONS.H - -header included in hcex build. -*/ - -#ifndef __LIGHT_VOLUME_DEFINITIONS_H -#define __LIGHT_VOLUME_DEFINITIONS_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __LIGHT_VOLUME_DEFINITIONS_H diff --git a/source/objects/widgets/lightning_definitions.h b/source/objects/widgets/lightning_definitions.h deleted file mode 100644 index 19c16522..00000000 --- a/source/objects/widgets/lightning_definitions.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -LIGHTNING_DEFINITIONS.H - -header included in hcex build. -*/ - -#ifndef __LIGHTNING_DEFINITIONS_H -#define __LIGHTNING_DEFINITIONS_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __LIGHTNING_DEFINITIONS_H diff --git a/source/physics/physics_constants.h b/source/physics/physics_constants.h deleted file mode 100644 index fff8c8b2..00000000 --- a/source/physics/physics_constants.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -PHYSICS_CONSTANTS.H - -header included in hcex build. -*/ - -#ifndef __PHYSICS_CONSTANTS_H -#define __PHYSICS_CONSTANTS_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __PHYSICS_CONSTANTS_H diff --git a/source/physics/terrain_definitions.h b/source/physics/terrain_definitions.h deleted file mode 100644 index 73ba3f17..00000000 --- a/source/physics/terrain_definitions.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -TERRAIN_DEFINITIONS.H - -header included in hcex build. -*/ - -#ifndef __TERRAIN_DEFINITIONS_H -#define __TERRAIN_DEFINITIONS_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __TERRAIN_DEFINITIONS_H diff --git a/source/rasterizer/rasterizer_hardware_format_utilities.h b/source/rasterizer/rasterizer_hardware_format_utilities.h deleted file mode 100644 index 6797ecde..00000000 --- a/source/rasterizer/rasterizer_hardware_format_utilities.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -RASTERIZER_HARDWARE_FORMAT_UTILITIES.H - -header included in hcex build. -*/ - -#ifndef __RASTERIZER_HARDWARE_FORMAT_UTILITIES_H -#define __RASTERIZER_HARDWARE_FORMAT_UTILITIES_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __RASTERIZER_HARDWARE_FORMAT_UTILITIES_H diff --git a/source/rasterizer/rasterizer_memory_pool.c b/source/rasterizer/rasterizer_memory_pool.c index 1396e6f4..8e183bff 100644 --- a/source/rasterizer/rasterizer_memory_pool.c +++ b/source/rasterizer/rasterizer_memory_pool.c @@ -8,7 +8,7 @@ RASTERIZER_MEMORY_POOL.C #include "errors.h" #include "real_math.h" #include "rasterizer.h" -#include "rasterizer_memory_pool.h" +/* Empty reconstructed header removed; no declarations to include. */ /* ---------- globals */ diff --git a/source/rasterizer/rasterizer_memory_pool.h b/source/rasterizer/rasterizer_memory_pool.h deleted file mode 100644 index 29ec4acf..00000000 --- a/source/rasterizer/rasterizer_memory_pool.h +++ /dev/null @@ -1,11 +0,0 @@ -/* -RASTERIZER_MEMORY_POOL.H - -Narrow cross-translation-unit interface owned by RASTERIZER_MEMORY_POOL.C. -*/ - -#ifndef __RASTERIZER_MEMORY_POOL_H -#define __RASTERIZER_MEMORY_POOL_H -#pragma once - -#endif /* __RASTERIZER_MEMORY_POOL_H */ diff --git a/source/rasterizer/xbox/rasterizer_xbox_environment.c b/source/rasterizer/xbox/rasterizer_xbox_environment.c index 4df20253..95710f24 100644 --- a/source/rasterizer/xbox/rasterizer_xbox_environment.c +++ b/source/rasterizer/xbox/rasterizer_xbox_environment.c @@ -155,7 +155,7 @@ symbols in this file: #include "rasterizer/common/rasterizer_common.h" #include "rasterizer/rasterizer_geometry.h" #include "rasterizer/rasterizer_lights.h" -#include "rasterizer/rasterizer_memory_pool.h" +/* Empty reconstructed header removed; no declarations to include. */ #include "rasterizer/rasterizer_transparent_geometry.h" #include "shaders/shader_definitions.h" #include "shaders/shaders.h" diff --git a/source/rasterizer/xbox/rasterizer_xbox_environment_fog.c b/source/rasterizer/xbox/rasterizer_xbox_environment_fog.c index 386be1a3..6dc9a982 100644 --- a/source/rasterizer/xbox/rasterizer_xbox_environment_fog.c +++ b/source/rasterizer/xbox/rasterizer_xbox_environment_fog.c @@ -178,11 +178,6 @@ enum MAXIMUM_ATMOSPHERE_DOMINANT_WARNINGS = 20, }; -enum -{ - NUMBER_OF_PIXEL_SHADER_STAGES = 8, -}; - enum { _fog_definition_atmosphere_dominant_bit = 1, diff --git a/source/rasterizer/xbox/shader_transparent_generic_preprocessor.c b/source/rasterizer/xbox/shader_transparent_generic_preprocessor.c index c805cbd4..e6da364e 100644 --- a/source/rasterizer/xbox/shader_transparent_generic_preprocessor.c +++ b/source/rasterizer/xbox/shader_transparent_generic_preprocessor.c @@ -68,11 +68,6 @@ enum _xbox_texture_mode_cube_map = 3 }; -enum -{ - NUMBER_OF_PIXEL_SHADER_STAGES = 8 -}; - /* ---------- macros */ #define SHADER_STAGE_REGISTER_MASK 0x0f diff --git a/source/saved films/saved_films.h b/source/saved films/saved_films.h deleted file mode 100644 index f2b88ed7..00000000 --- a/source/saved films/saved_films.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -SAVED_FILMS.H - -header included in hcex build. -*/ - -#ifndef __SAVED_FILMS_H -#define __SAVED_FILMS_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __SAVED_FILMS_H diff --git a/source/saved games/game_state_procs.h b/source/saved games/game_state_procs.h deleted file mode 100644 index 5463311c..00000000 --- a/source/saved games/game_state_procs.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -GAME_STATE_PROCS.H - -header included in hcex build. -*/ - -#ifndef __GAME_STATE_PROCS_H -#define __GAME_STATE_PROCS_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __GAME_STATE_PROCS_H diff --git a/source/scenario/scenario_placement.h b/source/scenario/scenario_placement.h deleted file mode 100644 index bfb6c9da..00000000 --- a/source/scenario/scenario_placement.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -SCENARIO_PLACEMENT.H - -header included in hcex build. -*/ - -#ifndef __SCENARIO_PLACEMENT_H -#define __SCENARIO_PLACEMENT_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __SCENARIO_PLACEMENT_H diff --git a/source/scenario/structure_bsp_procs.h b/source/scenario/structure_bsp_procs.h deleted file mode 100644 index 9ed9bc80..00000000 --- a/source/scenario/structure_bsp_procs.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -STRUCTURE_BSP_PROCS.H - -header included in hcex build. -*/ - -#ifndef __STRUCTURE_BSP_PROCS_H -#define __STRUCTURE_BSP_PROCS_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __STRUCTURE_BSP_PROCS_H diff --git a/source/shell/shell_windows.h b/source/shell/shell_windows.h deleted file mode 100644 index 7375799b..00000000 --- a/source/shell/shell_windows.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -SHELL_WINDOWS.H - -header included in hcex build. -*/ - -#ifndef __SHELL_WINDOWS_H -#define __SHELL_WINDOWS_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __SHELL_WINDOWS_H diff --git a/source/sound/platform_sound.h b/source/sound/platform_sound.h deleted file mode 100644 index f0ad55ef..00000000 --- a/source/sound/platform_sound.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -PLATFORM_SOUND.H - -header included in hcex build. -*/ - -#ifndef __PLATFORM_SOUND_H -#define __PLATFORM_SOUND_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __PLATFORM_SOUND_H diff --git a/source/strings/resource.h b/source/strings/resource.h deleted file mode 100644 index f7a4e678..00000000 --- a/source/strings/resource.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -RESOURCE.H - -header included in hcex build. -*/ - -#ifndef __RESOURCE_H -#define __RESOURCE_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __RESOURCE_H diff --git a/source/structures/detail_object_definitions.h b/source/structures/detail_object_definitions.h deleted file mode 100644 index 89c61bb9..00000000 --- a/source/structures/detail_object_definitions.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -DETAIL_OBJECT_DEFINITIONS.H - -header included in hcex build. -*/ - -#ifndef __DETAIL_OBJECT_DEFINITIONS_H -#define __DETAIL_OBJECT_DEFINITIONS_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __DETAIL_OBJECT_DEFINITIONS_H diff --git a/source/structures/radiosity/radiosity.h b/source/structures/radiosity/radiosity.h deleted file mode 100644 index 37535934..00000000 --- a/source/structures/radiosity/radiosity.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -RADIOSITY.H - -header included in hcex build. -*/ - -#ifndef __RADIOSITY_H -#define __RADIOSITY_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __RADIOSITY_H diff --git a/source/structures/radiosity/radiosity_io.h b/source/structures/radiosity/radiosity_io.h deleted file mode 100644 index bc21a6b5..00000000 --- a/source/structures/radiosity/radiosity_io.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -RADIOSITY_IO.H - -header included in hcex build. -*/ - -#ifndef __RADIOSITY_IO_H -#define __RADIOSITY_IO_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __RADIOSITY_IO_H diff --git a/source/text/draw_string_types.h b/source/text/draw_string_types.h deleted file mode 100644 index 0fc8fbf3..00000000 --- a/source/text/draw_string_types.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -DRAW_STRING_TYPES.H - -header included in hcex build. -*/ - -#ifndef __DRAW_STRING_TYPES_H -#define __DRAW_STRING_TYPES_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __DRAW_STRING_TYPES_H diff --git a/source/tool/intermediate_geometry.h b/source/tool/intermediate_geometry.h deleted file mode 100644 index 22cd0756..00000000 --- a/source/tool/intermediate_geometry.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -INTERMEDIATE_GEOMETRY.H - -header included in hcex build. -*/ - -#ifndef __INTERMEDIATE_GEOMETRY_H -#define __INTERMEDIATE_GEOMETRY_H -#pragma once - -/* ---------- constants */ - -/* ---------- macros */ - -/* ---------- structures */ - -/* ---------- prototypes/EXAMPLE.C */ - -/* ---------- globals */ - -/* ---------- public code */ - -#endif // __INTERMEDIATE_GEOMETRY_H From 14ec9fc4a294b6b881362c99c76192e3f414cd89 Mon Sep 17 00:00:00 2001 From: Jonas Volman Date: Fri, 9 Oct 2026 04:23:56 -0700 Subject: [PATCH 11/17] Remove three no-op BSS pragma blocks without byte changes --- .../noop_bss_pragma_cleanup_20261009.md | 67 +++++++++++++++++++ source/math/random_math.c | 2 - source/objects/object_types.c | 3 - source/text/unicode.c | 2 - 4 files changed, 67 insertions(+), 7 deletions(-) create mode 100644 docs/object_matching_logs/noop_bss_pragma_cleanup_20261009.md diff --git a/docs/object_matching_logs/noop_bss_pragma_cleanup_20261009.md b/docs/object_matching_logs/noop_bss_pragma_cleanup_20261009.md new file mode 100644 index 00000000..e2e4c62a --- /dev/null +++ b/docs/object_matching_logs/noop_bss_pragma_cleanup_20261009.md @@ -0,0 +1,67 @@ +# No op BSS pragma cleanup + +The three existing section-directive blocks can be removed without changing +the compiled program in the stock January build. This is zero-credit cleanup: +every complete object, function verdict and progress total remains unchanged. +Owner approval is conditional on preserving functionality and byte matching. + +Main base: `73677cf26df696770a58e1838dc8ebc1cba20655`. +Exact-pilots base: `538efa0177ec385c13f1a7eed973fd0f1bdf1023`. +These bases differ only in README.md; their separate README contents are kept. + +## Scope + +Remove the opening and closing `#pragma bss_seg` lines in: + +- `source/math/random_math.c`, around static `random_math_globals`. +- `source/objects/object_types.c`, around static `processed_bsp_flags`. +- `source/text/unicode.c`, around static `bss_004c1a08`. + +Also remove object_types.c's claim that its static definition would otherwise +be emitted as COMMON. The measured object disproves that claim: without the +directive, its storage, section and offsets are identical. + +The three definitions keep their types, names, initialisers and position. +No function body, assertion, header, atlas, manifest, compiler option, +provider, Matching status, park, scorer or vendor source is changed. Other +section directives and packed structures remain outside this packet. +The source diff is three files and seven deleted lines, retaining CRLF. + +## Verification + +The removals passed individually and combined in scratch. Fresh clean +whole-board builds at the actual landing directory also establish: + +- All 621 rebuilt and 833 split objects are identical after excluding only + the four-byte COFF compilation timestamp. No local-label or debug-record + exclusion is needed for the same-directory before/after comparison. +- Consequently code, data, relocations, section flags, symbol/storage + records and provider-selection attributes are unchanged in full, including + uncredited sections. No provider or helper copy is added or removed. +- All 8,252 strict target rows are identical: 7,656 exact rows across Halo, + vendor and helpers; zero gains, zero losses and no residual movement. +- The Ninja all_source command stream is identical; SHA-256: + `2712ffc0317c1f7382cbfa8274a65199f637e958cd662c6b71da4f4d9d3f9058`. +- The tools suite passes before and after: 1,663 tests, five skips and 159 + passing subtests. The test suite and production comparators are unchanged. +- Separate /W3 compilations cover 612 CL units, with no failures and 4,091 + warnings on each side. Diagnostic content and counts are identical; physical + source line positions move following the seven source-line deletions. +- Admission reports are identical: nine candidates, none contradicted, + rejected or revoked. The same 26 inherited fake-scan leads remain. +- All 59 parks validate. COMMON credit stays at 93 records and +661,012 bytes. + +Halo totals stay at 7,483 / 7,573 functions, 1,603,071 / 1,770,166 meaningful +code bytes, 3,311,591 / 3,922,163 data bytes and 396 / 468 Matching objects. +Whitespace checks pass; no matching or functionality gain is claimed. + +Functionality preservation is established by identical complete compiler +outputs and linker inputs for this build, not by a game-launch test or a claim +about other compiler/platform configurations. Reference executables, SDK and +private symbol assets are not executed or published. + +Private receipts remain under `scratch/pragma_cleanup_20261009` in the landing +checkout; the individual controls remain in the separate scratch experiment. +Publication uses the same packet on both repository branches, with fresh +verification and fast-forward-only pushes. Canonical's unrelated README edits +and research files are preserved when it is advanced to the exact-pilots tip. diff --git a/source/math/random_math.c b/source/math/random_math.c index 76ed4239..3cc5a293 100644 --- a/source/math/random_math.c +++ b/source/math/random_math.c @@ -92,9 +92,7 @@ direction3d_from_table( /* ---------- globals */ -#pragma bss_seg(".bss") static struct random_math_globals random_math_globals; -#pragma bss_seg() /* ---------- public code */ diff --git a/source/objects/object_types.c b/source/objects/object_types.c index 1a08f1e4..dfef9a33 100644 --- a/source/objects/object_types.c +++ b/source/objects/object_types.c @@ -471,10 +471,7 @@ struct object_type_definition *object_type_definitions[NUMBER_OF_OBJECT_TYPES] = }; struct object_type_definition *first_object_type_definition; -/* VC7 otherwise emits this tentative definition as a common symbol. */ -#pragma bss_seg(".bss") static word processed_bsp_flags; -#pragma bss_seg() typedef char verify_object_type_definition_size[ sizeof(struct object_type_definition) == 0xA0 ? 1 : -1]; diff --git a/source/text/unicode.c b/source/text/unicode.c index c47bb91b..8a0b0e44 100644 --- a/source/text/unicode.c +++ b/source/text/unicode.c @@ -268,9 +268,7 @@ enum /* ---------- globals */ -#pragma bss_seg(".bss") static wchar_t bss_004c1a08[0x100]; -#pragma bss_seg() /* ---------- public code */ From 1a98636fc0748ea10a6ad25ce006062b2c8d76c5 Mon Sep 17 00:00:00 2001 From: Jonas Volman Date: Fri, 9 Oct 2026 05:14:29 -0700 Subject: [PATCH 12/17] Replace remaining BSS pragmas with verified zero initialization --- .../remaining_bss_pragma_cleanup_20261009.md | 75 +++++++++++++++++++ source/effects/material_effects.c | 4 +- source/rasterizer/rasterizer.c | 4 +- 3 files changed, 77 insertions(+), 6 deletions(-) create mode 100644 docs/object_matching_logs/remaining_bss_pragma_cleanup_20261009.md diff --git a/docs/object_matching_logs/remaining_bss_pragma_cleanup_20261009.md b/docs/object_matching_logs/remaining_bss_pragma_cleanup_20261009.md new file mode 100644 index 00000000..a035041f --- /dev/null +++ b/docs/object_matching_logs/remaining_bss_pragma_cleanup_20261009.md @@ -0,0 +1,75 @@ +# Remaining BSS pragma cleanup + +The two remaining section-directive blocks are replaced by ordinary explicit +zero initialization of their external globals. Function matching, code and +data credit, warnings, parks and admission statuses remain unchanged. The +rasterizer's two BSS offsets now agree with January and its object audit passes. + +Exact-pilots base: `cbbcb3d66e2ae6b66ddf8aabbd819346074ec9aa`. +Halo-1 main base: `14ec9fc4a294b6b881362c99c76192e3f414cd89`. +Their separate README contents are preserved. Owner approval requires no loss +of byte matching or functionality in the tested build. + +## Source scope + +In material_effects.c, remove the pragma pair and write +`boolean debug_material_effects = FALSE;`. In rasterizer.c, remove its pair and +write `real_argb_color *global_rasterizer_model_ambient_reflection_tint = NULL;`. +The adjacent `static long bss_004662ec;` stays uninitialized and unchanged. + +Both public globals are defined in January's own object BSS, not in the COMMON +pool. Explicit zero initialization preserves that ownership without a section +directive; the spelling is inferred, not recovered source. No initializer is +added to the file static merely to select a declaration-order layout. + +No function body, type, name, header, atlas, manifest, compiler flag, scorer, +Matching status, park, provider or vendor source changes. The source diff is +two files, two inserted lines and six deleted lines. Existing CRLF is retained. + +## Compiled output + +The replacements pass separately and together in scratch. Fresh full clean +builds at the landing directory repeat the combined comparison: + +- Material-effects is identical as a complete object, excluding only the COFF + compilation timestamp. No helper or surplus section changes. +- Of 621 rebuilt and 833 split objects, only rasterizer.obj changes. +- Rasterizer's 8-byte BSS moves from section 8 to section 3; old sections 3-7 + shift to 4-8. Symbol indexes and relocation indexes in three functions follow + that permutation. It is not raw-object equality. +- All 226 section payloads, flags, sizes, alignment and named relocation + targets, offsets, types and addends are unchanged. Symbol and auxiliary + records are unchanged apart from the section/index bookkeeping and two + verified BSS offsets: `_bss_004662ec` 4 to 0, and the external tint pointer + 0 to 4. Storage classes remain static 3 and external 2 respectively. +- The corrected offsets match January. Whole-object audits pass for both + units; rasterizer improves from FAIL with two symbol-offset differences. + Selected-provider links pass in both input orders for both units. + +The scratch test's initial raw prediction omitted the section/index permutation +and stopped. That failed receipt is retained. A separate read-only diagnostic +then verified the exact permutation and every payload, named reference and +symbol attribute. No production comparator or credit rule was modified. + +## Regression checks + +All 8,252 strict target rows, including residual fingerprints, are identical: +zero exact gains or losses. The Ninja all_source command stream is unchanged. +The tools suite passes 1,663 tests, with five skips and 159 passing subtests. +The separate W3 sweep covers 612 CL units with zero failures and 4,091 warnings +before and after; only deleted-source-line positions may differ. + +Admission reports are identical and the same 26 inherited fake-scan leads +remain. All 59 parks validate. COMMON credit stays at 93 records and 661,012 +bytes. Halo totals remain 7,483 of 7,573 functions, 1,603,071 of 1,770,166 code +bytes, 3,311,591 of 3,922,163 data bytes and 396 of 468 Matching objects. + +Functionality preservation rests on unchanged emitted logic, data contents, +zero initialization, symbol linkage and named references in the stock January +build. This is not a game-launch test, a completed matching executable link or +a guarantee for other compiler configurations. Supplied game executables are +not run, and private SDK assets are not published. + +Private scratch and landing receipts retain the failed prediction, individual +controls and fresh gates. Publication keeps each branch's README and preserves +canonical's unrelated README edits and research files. diff --git a/source/effects/material_effects.c b/source/effects/material_effects.c index 0e53b43e..22d5c5e4 100644 --- a/source/effects/material_effects.c +++ b/source/effects/material_effects.c @@ -45,9 +45,7 @@ enum /* ---------- globals */ -#pragma bss_seg(".bss") -boolean debug_material_effects; -#pragma bss_seg() +boolean debug_material_effects = FALSE; /* ---------- public code */ diff --git a/source/rasterizer/rasterizer.c b/source/rasterizer/rasterizer.c index b80443b8..e08c6fea 100644 --- a/source/rasterizer/rasterizer.c +++ b/source/rasterizer/rasterizer.c @@ -686,10 +686,8 @@ struct rasterizer_debug_options rasterizer_debug_options = { 0 }, /* pad8A[2] */ }; /* No PDB name survives for this target-owned BSS symbol. */ -#pragma bss_seg(".bss") static long bss_004662ec; -real_argb_color *global_rasterizer_model_ambient_reflection_tint; -#pragma bss_seg() +real_argb_color *global_rasterizer_model_ambient_reflection_tint = NULL; /* ---------- public code */ From ff2e07fac1c2e361fd20b472e42c5fb9e227ad1e Mon Sep 17 00:00:00 2001 From: Jonas Volman Date: Tue, 13 Oct 2026 16:59:49 -0700 Subject: [PATCH 13/17] Replace parked stristr assembly with exact ordinary C (zero credit) Use the natural C implementation from punpckhdq/halo 745c66b8. All 621 object fingerprints and inherited exact verdicts are unchanged; the single asm-implemented park is retired. Fresh full checkpoint: 1663 tests pass, 5 skipped, 159 subtests. Current scoring already counted the assembly: no additional function or byte credit. --- config/parked.json | 19 ----- ...nary_c_upstream_reconciliation_20261013.md | 51 ++++++++++++ source/cseries/cseries.c | 81 ++++++------------- 3 files changed, 75 insertions(+), 76 deletions(-) create mode 100644 docs/object_matching_logs/stristr_ordinary_c_upstream_reconciliation_20261013.md diff --git a/config/parked.json b/config/parked.json index e3d61872..3eac0900 100644 --- a/config/parked.json +++ b/config/parked.json @@ -228,25 +228,6 @@ "objdiff_percent": 91.115486 } }, - { - "unit": "source/cseries/cseries", - "function": "_stristr", - "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. Whole body is a single __asm block; no C remains. 2026-08-16 recovery attempt: expressible in C but a near-miss at 72/96. Semantically-correct C reaches 85 bytes off naively, 74 after moving the empty-needle return to the tail (the branch-polarity lever), and 72 with a while(*haystack) loop; prologue, csstrlen call, search loop and _strnicmp call all land correctly. Residue is a spill preference: January holds the first needle character in bl across the function and spills length into the dead needle parameter slot [ebp+0xc]; we keep length in ebx and spill the character to [ebp+0xf]. Measured inert: declaration order both ways, register on either/both locals, int/long/unsigned long length (int regresses to 103), length scoped inside the if, character hoisted out of the loop, continue- and while-form loops, length computed before the guard. Same spill class as the standing parks. Not replaced - swapping a byte-exact asm body for a 72-byte residual is not a recovery. See research/asm_credited_functions_audit.md. 2026-08-16 spill-flip attempt, refined: the 72-byte while(*haystack) form is STRUCTURALLY WRONG - it rotates the loop, duplicating the load/test at the back edge and forcing lea eax,[esi-1] instead of dec esi/mov eax,esi. The structurally correct form is the for(;;) at 74/96, whose loop body matches January instruction-for-instruction (load, inc, test, je, cmp, jne back-edge, strnicmp, test, jne back-edge, dec, return). Byte count is therefore the wrong metric here; 74 is closer than 72. With that structure fixed the residue is isolated to a single free-register contest: esi and edi hold haystack and needle in both builds, and exactly one of {first, length} can have ebx because both live ranges span a call (first across csstrlen, length across _strnicmp). January gives ebx to first (mov bl,[edi], cmp al,bl) and spills length into the dead needle slot [ebp+0xc]; we give ebx to length and spill first to [ebp+0xf] - which is also inside the dead needle slot, so both compilers reuse the same storage and differ only in which value wins the register. Additional inert levers measured this round: char/byte/unsigned char for the first character and the loop character, long/unsigned long/const long for the length, assignment inside the while condition, pointer-compare-before-increment, and length computed before the guard. Same free-register-preference class as the register-allocation parks; reachable in principle, lever not found. 2026-08-16 c2 debugger result (NEGATIVE, closes a line of investigation): built tools/c2dbg32/repro_stristr.c, a single-function TU reproducing the tie exactly (96B, ndiff 74, same mov ebx,eax for length and same spill of first to [ebp+0xf]), and breakpointed every mapped allocator site during its compile. The machinery runs - interference dispatch 0x1074d343 x6, relation 0x107091ae x8, overlap probe 0x10735a41 x5, interference test 0x1070943b x3, coalescing copy 0x10701961 x15, leaf-register write 0x10715873 x2, preference store 0x1075f5f2 x5, finalizer 0x107144cf x3 - but it never touches the registers in question: both leaf-register writes assign register byte 1, and ALL FIFTEEN coalescing copies propagate register byte 1 (ecx==1 at every hit). ebx/esi/edi are 3/6/7 zero-based and never appear. The mapped sites allocate the eax-family scratch class; the callee-saved assignment and the spill choice are made in a pass that is still unmapped. Further breakpoint work on these VAs therefore cannot reach this tie (nor the sibling register-mirror and spill parks). Progress needs the callee-saved/spill pass located from scratch - the entry point is the code that decides a live range is memory-resident, not the code that stamps [node+0x28]. See tools/c2dbg32/IR_LAYOUT.md. 2026-08-16 CORRECTION to this entry's earlier c2 claims: 0x10715873 does NOT write a physical register. Four probes differing only in the C type of the spilled locals show the byte it stamps into node[+0x28] is uniform across every node in a compile and tracks operand size - char->1, short->2, int->3, __int64->4 (13/13/13/7 hits, one distinct value each). It is an operand WIDTH class, not a register; thirteen simultaneously-live values cannot share one register. This also resolves the 'discrepancy' noted during the original record_kill work (rwprobe used short fields, every write showed al=2 while the code used ecx) - that was the width of a short, not a register quirk. Consequently the earlier 'read the register write' and 'traced the preferred-register argument' results for this function are WITHDRAWN: the physical-register assignment site and the spill decision are both still unlocated. The mechanism narrative (both candidate registers free, outcome set upstream) stands on the instruction-level evidence, but no compiler-internal site has been confirmed to make it. See tools/c2dbg32/IR_LAYOUT.md.", - "measurements": { - "target": { - "size": 96, - "relocation_count": 2, - "normalized_sha256": "8068cc55c81c4109e4d2eef813744d2c42fbea33b53c93a8c192bb7ad03e0428" - }, - "base": { - "size": 96, - "relocation_count": 2, - "normalized_sha256": "8068cc55c81c4109e4d2eef813744d2c42fbea33b53c93a8c192bb7ad03e0428" - }, - "objdiff_percent": 100 - } - }, { "unit": "libs/libcmt/stream", "function": "__getstream", diff --git a/docs/object_matching_logs/stristr_ordinary_c_upstream_reconciliation_20261013.md b/docs/object_matching_logs/stristr_ordinary_c_upstream_reconciliation_20261013.md new file mode 100644 index 00000000..e2515539 --- /dev/null +++ b/docs/object_matching_logs/stristr_ordinary_c_upstream_reconciliation_20261013.md @@ -0,0 +1,51 @@ +# stristr: ordinary C replaces the parked assembly, 2026-10-13 + +Reconciled against canonical `1a98636fc0748ea10a6ad25ce006062b2c8d76c5`. +Source donor: [punpckhdq/halo at 745c66b8](https://github.com/punpckhdq/halo/blob/745c66b82ad2ec15f787f4145caa5a618f0394ae/source/cseries/cseries.c#L402). +The owner authorized reconciling this recovery and the separately approved +single-pixel S3TC decoder, then publishing to `bnunu/halo`'s +`jonas/exact-pilots` and `bnunu/halo-1`'s `main`. No whole donor lane is merged. + +Only `stristr`'s body changes. Ordinary C replaces `__declspec(naked)` and its +assembly transcription. The meaningful locals and nested scanning loops preserve +January's behavior: an empty needle returns the original haystack; the first +character comparison is case-sensitive; `_strnicmp` compares the remaining +suffix; failure returns NULL. This does not repair or broaden those semantics. +No header, flag, declaration-count device, helper or representation cast is added. + +The function is strictly equal to January: 86 meaningful / 96 padded bytes, +two relocations, normalized SHA-256 +`8068cc55c81c4109e4d2eef813744d2c42fbea33b53c93a8c192bb7ad03e0428`. +Independent source review found no source-policy blocker. The old +`asm-implemented` park explicitly required replacement by exact C; that one row +is retired deliberately. The generic unpark tool excludes assembly parks and +is not weakened or modified. + +## Fresh canonical checkpoint + +- Clean full build and progress pass; strict sweep: 8,252 section owners, + 7,656 exact, zero gains and zero losses in machine-code equality. +- All 621 object fingerprints are identical, excluding timestamps and debug + sections. The cseries object's 54 sections retain their identities and bytes. +- Tools: 1,663 passed, five skipped, 159 subtests passed; no failures. +- Default-build warning multiset unchanged; changed-unit `/W3` 12 -> 12 and + `/W4` 46 -> 46. The clean baseline whole-board `/W3` census is 4,091 across + all 612 CL targets; the complete combined census is rechecked with the decoder. +- Parks 59 -> 58, none stale or invalid. Admission remains nine review + candidates, zero contradictions, rejections or revocations. No status flip. +- Fake scan 26 -> 24 inherited review leads as the assembly constructs disappear. + No new lead is introduced; a clean scan is not the source-credibility proof. +- Whitespace checks pass. No surplus definition, provider or data change occurs. + +Accounting correction to the audit's initial expectation: the current progress +code already counts this function despite its assembly park. Therefore this is +**zero additional credit**: Halo remains 7,483 / 7,573 functions, +1,603,071 / 1,770,166 meaningful code bytes, 3,311,591 / 3,922,163 data bytes, +and 396 / 468 objects. No scorer, pin, allowlist or denominator is changed to +manufacture a second gain. This commit replaces a transcription with credible C. + +Private receipts: `research/upstream_house_audit_20261013/landing_gates/stristr/` +in the reconciliation workspace. The first setup attempts recorded missing local +tool/scratch paths; they are not claimed as successful gates. The complete +`baseline_full` and `stristr` checkpoints pass after those local prerequisites +were supplied, without changing any production test or gate. diff --git a/source/cseries/cseries.c b/source/cseries/cseries.c index b84b4e0b..c50baceb 100644 --- a/source/cseries/cseries.c +++ b/source/cseries/cseries.c @@ -535,66 +535,33 @@ not_equal: return c1 > c2 ? 1 : -1; } -__declspec(naked) char *stristr( - const char *haystack, - const char *needle) +char *stristr( + char const *haystack, + char const *needle) { - __asm + char c; + char sc; + unsigned long length; + + if ((c = *needle++) != 0) { - push ebp - mov ebp, esp - push ebx - push esi - push edi - mov edi, needle - mov bl, byte ptr [edi] - inc edi - test bl, bl - je empty_needle - push edi - call csstrlen - mov esi, haystack - add esp, 4 - mov needle, eax - nop - search: - mov al, byte ptr [esi] - inc esi - test al, al - je no_match - cmp al, bl - jne search - mov eax, needle - push eax - push edi - push esi - call _strnicmp - add esp, 12 - test eax, eax - jne search - dec esi - pop edi - mov eax, esi - pop esi - pop ebx - pop ebp - ret - no_match: - pop edi - pop esi - xor eax, eax - pop ebx - pop ebp - ret - empty_needle: - mov esi, haystack - pop edi - mov eax, esi - pop esi - pop ebx - pop ebp - ret + length = csstrlen(needle); + do + { + do + { + if ((sc = *haystack++) == 0) + { + return NULL; + } + } + while (sc != c); + } + while (_strnicmp(haystack, needle, length) != 0); + haystack--; } + + return (char *)haystack; } unsigned long string_hash( From 2e376b992e920bcc3a094727475c17daef71ec8c Mon Sep 17 00:00:00 2001 From: Jonas Volman Date: Tue, 13 Oct 2026 17:02:57 -0700 Subject: [PATCH 14/17] Reconcile approved single-pixel S3TC decoder (+1 function, zero losses) Apply only the Q-UP25 delta from de53e9bf, preserving both original-defect BUG comments and inferred length spelling. Fresh canonical checkpoint: +493 meaningful / +496 padded code and +76 data, zero losses; 1663 tests pass, 5 skipped, 159 subtests. Whole-board W3 unchanged at 4091; only s3tc.obj changes. Encoder and object admission remain held. --- config/parked.json | 19 ----- ...pixel_canonical_reconciliation_20261013.md | 75 +++++++++++++++++++ source/bitmaps/s3tc/s3tc.c | 23 +++++- 3 files changed, 95 insertions(+), 22 deletions(-) create mode 100644 docs/object_matching_logs/s3tc_single_pixel_canonical_reconciliation_20261013.md diff --git a/config/parked.json b/config/parked.json index 3eac0900..bed9022b 100644 --- a/config/parked.json +++ b/config/parked.json @@ -92,25 +92,6 @@ }, "evidence": "Best currently integrated house-rule-compliant reconstruction from the 2026-09-07 PlayerProfile/S3TC reconciliation batch. Retain the real covariance/axis/endpoint/selector graph. Initialize axis and selector packing, and handle zero-length quantized endpoints for mixed-alpha blocks too, preventing NaN conversion and invalid palette indexing. The held Alpha3 encoder is not imported. See docs/object_matching_logs/player_profile_s3tc_batch_reconciliation_20260907.md for donor provenance, raw-target limits, full-batch review and research pointers. Zero exact credit; retain for future evidence-driven work without source-pressure tuning. On 2026-09-21 (Lane C) ColorToFcolor's byte-to-real conversion was bound to a named `real` local, which made _Quantize strict exact. This function shares the RGBToColor/ColorToFcolor inlines, so its bytes moved and the base measurement is refreshed here. Its own residual is unchanged in class: it is frame-structural (January sub esp,0x1a8 vs our 0x19c, a missing local). Separately, an EXACT body for it is measured and held at scratch/cand/s3tc_owner_gated.c, but it requires three constructs the reviewer refused and the owner has not admitted: an uninitialised `long best_axis`, deleting `block->bitmap = 0;`, and an `&& cOpaque == 16` conjunct that divides by zero and indexes mapRGB3 out of bounds when cOpaque != 16." }, - { - "unit": "source/bitmaps/s3tc/s3tc", - "function": "_DecodeBlockRGB__single_pixel", - "class": "unclassified", - "measurements": { - "target": { - "size": 496, - "relocation_count": 10, - "normalized_sha256": "430094b19ae6b9e585f8c77b2c063824b45c98e3ceea58ac1dd4e2049730247b" - }, - "base": { - "size": 496, - "relocation_count": 10, - "normalized_sha256": "fa5385c3372ba60d98ab2c82e91481d4182918f84e64cafc528ba1e666a67dfb" - }, - "objdiff_percent": 99.27545 - }, - "evidence": "Best currently integrated house-rule-compliant reconstruction from the 2026-09-07 PlayerProfile/S3TC reconciliation batch. Repair the null-source clear to four output bytes rather than the original 64-byte overrun. Require coordinates 0..3, not the original inclusive 4 which permits an invalid selector shift. Preserve the actual three/four-color palette implementation. See docs/object_matching_logs/player_profile_s3tc_batch_reconciliation_20260907.md for donor provenance, raw-target limits, full-batch review and research pointers. Zero exact credit; retain for future evidence-driven work without source-pressure tuning. On 2026-09-21 (Lane C, graphics/UI) RGBToColor's body was restored to January's in-place channel form and its `= { 0 }` initialiser dropped, which made RGBToColor and DecodeBlockRGB strict exact. This function's bytes moved as a consequence and the base measurement is refreshed here: its size and relocation count now EQUAL January's (the tag went from [size 432!=496, relocs 11!=10, sha] to [sha] only), so the remaining residual is ordering or selection rather than structure. Its January assert text (`u>=0 && u<=4` / `v<=4` against our `< 4`) is a separate owner-held January defect and is unchanged." - }, { "unit": "source/saved games/player_profile", "function": "_player_profile_write_thread_proc@4", diff --git a/docs/object_matching_logs/s3tc_single_pixel_canonical_reconciliation_20261013.md b/docs/object_matching_logs/s3tc_single_pixel_canonical_reconciliation_20261013.md new file mode 100644 index 00000000..25146421 --- /dev/null +++ b/docs/object_matching_logs/s3tc_single_pixel_canonical_reconciliation_20261013.md @@ -0,0 +1,75 @@ +# Single-pixel S3TC decoder: canonical reconciliation, 2026-10-13 + +Reconciled the narrow approved source delta from local lane commit +`de53e9bf9941b557538e10cd3acf3925775cf6d5`, not the whole lane. The owner now +authorizes publishing this packet and the separate zero-credit stristr cleanup +to `bnunu/halo`'s `jonas/exact-pilots` and `bnunu/halo-1`'s `main`. + +Q-UP25 (2026-10-04) approved this function only, with both BUG comments and fresh +zero-loss gates. It did not approve `_EncodeBlockRGBColorKey` or object admission. + +## Scope and original-defect evidence + +Only `DecodeBlockRGB__single_pixel` changes: the NULL-source clear is restored +from four bytes to `S3TC_BLOCK_PIXELS * sizeof(struct s3tc_color)` (64 bytes), +and both original assertion expressions admit four. Both detailed BUG comments +are preserved from the reviewed lane patch. The length's expression spelling is +inferred from the full-block sibling, not recovered source. + +The clear would overwrite 60 further bytes of the caller's frame if reached. +Independent canonical review scanned all 833 January split objects: the only +references are from `bitmap_2d_get_pixel` and its two alpha wrappers. Current +canonical `bitmap_2d_get_pixel`, `bitmap_mipmap_address`, both wrappers, +`system_exit` and `halt_and_catch_fire` strictly equal January. The caller requires +non-NULL backing storage, halts unless the block address is at least its base, +and masks both coordinates with three. The wrappers pass the RGB block at +8. +Thus these original defects are unreachable through January's caller chain; +they are not described as harmless. A corrected build should clear one color +and assert the 0..3 range, as the source comments say. + +January's function is reproduced exactly: 493 meaningful / 496 padded bytes, +ten complete ordered relocations, normalized SHA-256 +`430094b19ae6b9e585f8c77b2c063824b45c98e3ceea58ac1dd4e2049730247b`. +The repository unpark tool's dry run selected exactly this function; its one +park is retired in this commit. No other park or rejection criterion is changed. + +## Fresh canonical gates + +The `decoder` checkpoint follows the separately gated `stristr` checkpoint. + +- Clean full build/progress, strict sweep and all checks pass. The 8,252-owner + sweep gains exactly this 496-byte section: 7,656 -> 7,657 exact, zero losses. +- Halo: **7,483 -> 7,484 / 7,573 functions**; meaningful code + **1,603,071 -> 1,603,564 / 1,770,166** (+493); matched data + **3,311,591 -> 3,311,667 / 3,922,163** (+76). All data stays 4,176,062. + These are fresh canonical figures, not additive lane headlines. +- Objects remain **396 / 468**. `s3tc` stays NonMatching; the encoder stays + residual, unchanged and held. No object status is edited. +- Exactly one of 621 object fingerprints differs: `s3tc.obj`. Its 34 sections + retain their order; only the decoder code section and its two assertion-string + sections change. The latter shrink from 16 to 13 bytes each and replace their + compiler-generated literal labels; the matching data extent gains 76 bytes. +- All other function sections and named data/callable definitions are unchanged. + No helper or provider is added. Helper identity is **NOT APPLICABLE**, not a + claimed pass for an unrelated placeholder. No provider-link waiver is needed. +- Whole-board `/W3`: **4,091 -> 4,091** across all **612** CL targets, identical + per-unit warning multisets. `/W4`: cseries 46 -> 46, s3tc 6 -> 6, unchanged. + The default-build warning multiset is also unchanged. +- Tools: **1,663 passed, five skipped, 159 subtests passed**; zero failures. +- Parks **58 -> 57**, none stale or invalid. Admission remains nine candidates, + zero contradicted, rejected or revoked. Fake scan retains the same 24 inherited + review leads after the stristr cleanup. Whitespace checks pass. +- Q10 remains 93 records / 661,012 data bytes. Tools, flags, ABI, headers, + verifier/reader pins, scoring, allowlists and all denominators are unchanged. + +Private full receipts and ownership/warning comparisons are in +`research/upstream_house_audit_20261013/landing_gates/` in the reconciliation +workspace. No original image, PDB, SDK or other private artifact is published. + +The two publishing bases have identical source/configuration/tool trees and +differ only in README plus history. Each history and README is preserved by +applying these same two reviewed commits independently, not by force-pushing +one repository's branch over the other. The stristr cleanup is zero additional +credit; the combined packet's numerical gain is one function, 493 meaningful / +496 padded code bytes and 76 data bytes. No executable-link/playability claim +or broader original-defect approval is implied. diff --git a/source/bitmaps/s3tc/s3tc.c b/source/bitmaps/s3tc/s3tc.c index ac22649f..2d62daf9 100644 --- a/source/bitmaps/s3tc/s3tc.c +++ b/source/bitmaps/s3tc/s3tc.c @@ -655,7 +655,19 @@ void DecodeBlockRGB__single_pixel( if (pblockSrc == NULL) { - memset(colorDst, 0, sizeof(*colorDst)); + /* BUG (original, preserved for exact matching): January clears S3TC_BLOCK_PIXELS colors here, + * 0x40 bytes (0x45fc30 +0x11 push 0x40, +0x15 call _csmemset), as the full-block decoder + * DecodeBlockRGB does, but colorDst addresses ONE color. In bitmap_2d_get_pixel, the only caller + * chain, that color is the four-byte local pixel, so the clear would overwrite 60 further bytes of + * that function's frame. + * The clear is not executed in January: bitmap_2d_get_pixel decodes only when + * bitmap->base_address is not NULL and halts (display_assert, then an unconditional system_exit) + * unless block_address >= bitmap->base_address; it passes block_address here for dxt1, and + * DecodeBlockAlpha4__single_pixel and DecodeBlockAlpha3__single_pixel pass &source->rgb + * (block_address + 8) for dxt3 and dxt5. No other function references this one. + * January's bytes give the length (0x40) only; its spelling here is inferred from DecodeBlockRGB, + * not recovered source. A corrected build clears sizeof(*colorDst). */ + memset(colorDst, 0, S3TC_BLOCK_PIXELS * sizeof(struct s3tc_color)); return; } @@ -692,8 +704,13 @@ void DecodeBlockRGB__single_pixel( colors[3].rgba[S3TC_ALPHA] = 0; } - match_assert("c:\\halo\\SOURCE\\bitmaps\\s3tc\\s3tc.c", 773, u >= 0 && u < 4); - match_assert("c:\\halo\\SOURCE\\bitmaps\\s3tc\\s3tc.c", 774, v >= 0 && v < 4); + /* BUG (original, preserved for exact matching): both assertions admit 4 (0x45fc30 +0x17c cmp si,4 / + * +0x180 jle; +0x1aa cmp bx,4 / +0x1ae jle; the assertion strings are January's "u>=0 && u<=4" and + * "v>=0 && v<=4"), although a block has four columns and four rows, 0..3. With u or v equal to 4 the + * selector shift below can reach 32 or more. bitmap_2d_get_pixel masks both coordinates with 3 before + * every call, so neither value exceeds 3 in January. A corrected build asserts u<4 and v<4. */ + match_assert("c:\\halo\\SOURCE\\bitmaps\\s3tc\\s3tc.c", 773, u>=0 && u<=4); + match_assert("c:\\halo\\SOURCE\\bitmaps\\s3tc\\s3tc.c", 774, v>=0 && v<=4); *colorDst = colors[(pblockSrc->bitmap >> (2 * (4 * v + u))) & 3]; From 1b61b529294dee3bd3c90a816781400d24dcc709 Mon Sep 17 00:00:00 2001 From: MrBruh <4706866+cybersecurity@users.noreply.github.com> Date: Sun, 18 Oct 2026 23:36:08 +1300 Subject: [PATCH 15/17] Keep a browser's WebRTC channel from stalling under loss by reporting every gap and giving up old ones, and let the test's lossless run tolerate a dropped burst --- port/linux/src/p2p_webrtc.c | 65 ++++++++++++++++++++++++++++---- port/web/tests/webrtc_native.mjs | 16 ++++++-- 2 files changed, 71 insertions(+), 10 deletions(-) diff --git a/port/linux/src/p2p_webrtc.c b/port/linux/src/p2p_webrtc.c index 914a694c..d0cc6f03 100644 --- a/port/linux/src/p2p_webrtc.c +++ b/port/linux/src/p2p_webrtc.c @@ -24,7 +24,15 @@ play's, sealed as to any peer; WebRTC is only their way through. the tunnel's datagrams, whose streams KCP makes reliable, as on UDP). Messages larger than a packet are split and joined again. What this end sends and the peer has not acknowledged in ABANDON_TIME is given up - (FORWARD-TSN, RFC 3758); what it receives is acknowledged at once. + (FORWARD-TSN, RFC 3758); what it receives is acknowledged at once, every + run past a gap (a SACK of only some has the peer count the others in + flight, and fill its window), and again each SACK_INTERVAL while a gap + stays. What is missing before a TSN that came GAP_TIME ago is given up as + the peer's FORWARD-TSN would give it up (the channel's messages are + never sent again, and the peer sent it before that TSN): Firefox's SCTP, + after one loss, gives up others only once its cumulative acknowledgement + has passed the first, which the gaps after it stop, and the channel would + stall for seconds, then fall out of TSN_WINDOW. Everything runs on the p2p thread, under p2p_lock. */ @@ -54,7 +62,9 @@ enum TSN_WINDOW = 1024, /* fragments of messages kept for joining */ MAXIMUM_FRAGMENTS = 16, - MAXIMUM_GAP_BLOCKS = 16, + /* the runs past the cumulative TSN a SACK reports: all of them, at a + tenth of the datagrams lost (a SACK of 12 + 4 * this bytes) */ + MAXIMUM_GAP_BLOCKS = 128, SCTP_PORT = 5000, /* the window this end says it has: messages are passed on at once */ RECEIVE_WINDOW = 1 << 20, @@ -65,6 +75,10 @@ enum PUNCH_TIME = 30000, ABANDON_TIME = 300, FORWARD_INTERVAL = 200, + SACK_INTERVAL = 200, + /* a gap given up by this end (longer than ABANDON_TIME: what is only + late still comes, and the peer may give it up first) */ + GAP_TIME = 1000, /* a path not checked in this long is not one the browser uses */ PATH_TIME = 30000, }; @@ -178,7 +192,11 @@ struct connection unsigned int cumulative; unsigned int highest; unsigned char received[TSN_WINDOW]; + /* (system time) when each TSN past the cumulative one came */ + unsigned long arrived[TSN_WINDOW]; int sack_due; + /* when the last SACK went */ + unsigned long sack_time; struct fragment fragments[MAXIMUM_FRAGMENTS]; /* sending: the next TSN, the peer's cumulative acknowledgement, when each TSN past it was sent (by TSN modulo TSN_WINDOW), and the last @@ -528,6 +546,7 @@ static void sctp_send_sack(struct connection *connection) put_short(value + 10, 0); sctp_send_chunk(connection, _chunk_sack, 0, value, 12 + blocks * 4); connection->sack_due = 0; + connection->sack_time = p2p_now(); } /* a message on the channel (stream 0, unordered), split as needed */ @@ -663,6 +682,7 @@ static void data_received(struct connection *connection, int flags, const unsign return; } connection->received[tsn % TSN_WINDOW] = 1; + connection->arrived[tsn % TSN_WINDOW] = p2p_now(); if (tsn_after(tsn, connection->highest)) connection->highest = tsn; while (connection->received[(connection->cumulative + 1) % TSN_WINDOW] && @@ -712,14 +732,13 @@ static void data_received(struct connection *connection, int flags, const unsign } } -static void forward_tsn_received(struct connection *connection, const unsigned char *value, int length) +/* what the peer gave up (FORWARD-TSN), or this end did: the cumulative TSN +moved to forward and past what came after it, and the fragments of messages +given up let go */ +static void skip_to(struct connection *connection, unsigned int forward) { - unsigned int forward; int index; - if (length < 4) - return; - forward = get_long(value); connection->sack_due = 1; if (!tsn_after(forward, connection->cumulative)) return; @@ -750,6 +769,35 @@ static void forward_tsn_received(struct connection *connection, const unsigned c } } +static void forward_tsn_received(struct connection *connection, const unsigned char *value, int length) +{ + if (length >= 4) + skip_to(connection, get_long(value)); +} + +/* the gaps past the cumulative TSN: what is missing before a TSN that came +GAP_TIME ago given up, and the rest told again each SACK_INTERVAL */ +static void gap_check(struct connection *connection) +{ + unsigned int tsn; + + if (!tsn_after(connection->highest, connection->cumulative)) + return; + for (tsn = connection->highest; tsn_after(tsn, connection->cumulative); tsn--) + { + if (connection->received[tsn % TSN_WINDOW] && elapsed(connection->arrived[tsn % TSN_WINDOW], GAP_TIME)) + { + skip_to(connection, tsn); + break; + } + } + if (connection->sack_due || (tsn_after(connection->highest, connection->cumulative) && + elapsed(connection->sack_time, SACK_INTERVAL))) + { + sctp_send_sack(connection); + } +} + static void sack_received(struct connection *connection, const unsigned char *value, int length) { unsigned int cumulative; @@ -1138,7 +1186,10 @@ int p2p_webrtc_update(void) /* (the handshake's retransmissions) */ connection_receive(connection); if (connection->state == _sctp_established) + { sctp_forward(connection); + gap_check(connection); + } else if (!elapsed(connection->created_time, PUNCH_TIME) && elapsed(connection->punch_time, PUNCH_INTERVAL)) punch(connection); } diff --git a/port/web/tests/webrtc_native.mjs b/port/web/tests/webrtc_native.mjs index b3405a3d..46470e7e 100644 --- a/port/web/tests/webrtc_native.mjs +++ b/port/web/tests/webrtc_native.mjs @@ -11,7 +11,10 @@ // messages of every size, split across SCTP's packets and not, which it // sends back, and the browser checks them; then again with a tenth of the // datagrams each way lost, when the channel must stay open (what was lost is -// given up, FORWARD-TSN) and carry the rest. No game data is needed. +// given up, FORWARD-TSN) and carry the rest. The channel is unreliable (no +// retransmissions, as the tunnel's), and a busy computer's loopback can drop +// a burst, so even without losses a few messages may not come back: every +// size must, nearly every time. No game data is needed. import { spawn, spawnSync } from 'node:child_process'; import { mkdtempSync, readdirSync, rmSync } from 'node:fs'; @@ -122,6 +125,7 @@ async function run(program, kind, loss, rounds) { // (as large as a tunnel packet: p2p.c's MAXIMUM_PACKET_SIZE) const sizes = [1, 10, 100, 1000, 1100, 1101, 1200, 1431]; const sent = new Map(); + const echoedBySize = {}; let echoed = 0; let wrong = 0; let lastEchoed = -1; @@ -132,6 +136,7 @@ async function run(program, kind, loss, rounds) { if (!expected || expected.length !== bytes.length || expected.some((b, i) => b !== bytes[i])) wrong++; else { echoed++; + echoedBySize[bytes.length] = (echoedBySize[bytes.length] || 0) + 1; lastEchoed = Math.max(lastEchoed, number); } }; @@ -148,7 +153,7 @@ async function run(program, kind, loss, rounds) { await new Promise((resolve) => setTimeout(resolve, 25)); } await new Promise((resolve) => setTimeout(resolve, 2000)); - return { sent: number, echoed, wrong, lastEchoed, open: dc.readyState === 'open' }; + return { sent: number, echoed, wrong, lastEchoed, open: dc.readyState === 'open', rounds, echoedBySize }; }, { sdp: answer(await page.evaluate(() => window.mid)), rounds }); return result; } finally { @@ -163,7 +168,12 @@ try { for (const kind of browsers) { const clean = await run(program, kind, 0, 40); console.log(`${kind}: ${clean.echoed} of ${clean.sent} messages back`); - if (clean.wrong || clean.echoed !== clean.sent) fail(`${kind}: ${JSON.stringify(clean)}`); + // (all but a dropped burst, every size nearly every time, and to the end) + const sizes = Object.values(clean.echoedBySize); + if (clean.wrong || clean.echoed < clean.sent * 0.97 || clean.lastEchoed !== clean.sent - 1 || sizes.length !== 8 || + sizes.some((count) => count < clean.rounds - 2)) { + fail(`${kind}: ${JSON.stringify(clean)}`); + } const lossy = await run(program, kind, 10, 120); console.log(`${kind}, a tenth of the datagrams lost: ${lossy.echoed} of ${lossy.sent} messages back`); // (a message comes back if its every datagram passed each way: about From 81a768bc81fadfdaa8a1a78141e7fc2efe69a07f Mon Sep 17 00:00:00 2001 From: MrBruh <4706866+cybersecurity@users.noreply.github.com> Date: Sun, 18 Oct 2026 23:49:26 +1300 Subject: [PATCH 16/17] Export the game functions the web page calls, so its loading notice hides once the menus draw and rooms reach the game --- tools/test_web_build.py | 16 ++++++++++++++++ tools/web_build.py | 10 +++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/tools/test_web_build.py b/tools/test_web_build.py index 2045c97d..b9708e77 100644 --- a/tools/test_web_build.py +++ b/tools/test_web_build.py @@ -108,6 +108,22 @@ def test_the_link_makes_the_memory_the_window_needs(): assert "-sASSERTIONS=0" in link_flags(release).split() +def test_the_link_exports_what_the_page_calls(): + """every function the page's scripts call on the game's module (game._x, + module._x) is exported: KEEPALIVE alone leaves it off the module, and the + page then waits for frames it cannot count (the loading notice stays)""" + exported = re.search(r"-sEXPORTED_FUNCTIONS=(\S+)", link_flags(graph())).group(1).split(",") + called = set() + for script in sorted(Path("port/web/site").glob("*.js")): + called |= set(re.findall(r"\b(?:game|module)\.(_[A-Za-z0-9_]+)", script.read_text())) + assert called, "no calls found: the pattern is stale" + assert not called - set(exported), f"called on the module, not exported: {sorted(called - set(exported))}" + for name in exported: + if name.startswith("_web_"): + assert re.search(r"EMSCRIPTEN_KEEPALIVE[^;{]*\b" + name[1:] + r"\(", + "".join(path.read_text() for path in Path("port/web/src").glob("*.c"))), name + + def test_the_memory_layout_agrees_with_the_sources(): platform = (ROOT / "port/linux/src/platform.h").read_text() base = int(re.search(r"#define PLATFORM_CONTIGUOUS_BASE (0x[0-9A-Fa-f]+)", platform).group(1), 16) diff --git a/tools/web_build.py b/tools/web_build.py index c208b7d0..fa166ffe 100644 --- a/tools/web_build.py +++ b/tools/web_build.py @@ -56,6 +56,10 @@ PORT_CONFIG = LINUX_DIR / "port.json" SDL_PORT = PORT_DIR / "halo_sdl3.py" # (the release port/web/halo_sdl3.py fetches, as the other builds') SDL_TAG = "release-3.4.16" +# the game's functions the page (port/web/site) calls on its module, besides +# main: tools/test_web_build.py checks that it names them all +PAGE_EXPORTS = ["_main", "_malloc", "_free", "_web_state", "_web_net_receive", "_web_net_peer_lost", + "_web_p2p_fingerprint", "_web_p2p_described", "_web_p2p_receive"] # the page's fonts, the menus' own (port/assets/fonts) SITE_FONTS = ["OpenCE-Regular.ttf", "Overpass-750.ttf", "Overpass-900.ttf"] # the memory watch by page contents, shared with the Android host @@ -323,7 +327,11 @@ def generate_web_build(n: Writer, sln: Any) -> None: # (the memory, which the page reads web_state's words from, and what # the page hands the room's frames to the game with: net.js) "-sEXPORTED_RUNTIME_METHODS=HEAPU8,HEAPU32", - "-sEXPORTED_FUNCTIONS=_main,_malloc,_free", + # (and what the page calls on the module: the frames shown, which hide + # its loading notice, the room's frames and internet play's + # connections; EMSCRIPTEN_KEEPALIVE alone keeps a function in the wasm, + # not on the module, since Emscripten 4) + "-sEXPORTED_FUNCTIONS=" + ",".join(PAGE_EXPORTS), f"-sASSERTIONS={0 if release else 1}", # function names in stack traces (the name section only) "--profiling-funcs", From 4b09168e7fad3b0c2ac4e2aef72d7ab5cb5e6f85 Mon Sep 17 00:00:00 2001 From: MrBruh <4706866+cybersecurity@users.noreply.github.com> Date: Mon, 19 Oct 2026 20:12:12 +1300 Subject: [PATCH 17/17] Switch OpenCE to the AGPL 3.0 or later, with the disc image readers written again from a description of the format --- AGENTS.md | 16 +- LICENSE | 661 +++++++++++++++++ LICENSE.md => LICENSES/CC0-1.0.txt | 0 README.md | 31 + docs/custom_edition_caches.md | 6 +- .../java/com/halo/decomp/XisoExtractor.java | 532 ++++++++------ port/linux/game/cache_file_formats.c | 10 +- port/linux/src/updater.c | 6 +- port/linux/src/xiso.c | 682 +++++++++++------- port/third_party/extract-xiso/LICENSE.TXT | 75 -- port/third_party/extract-xiso/README.md | 16 - port/web/licenses.py | 18 +- port/web/site/xiso-worker.js | 348 +++++---- tools/ci_build.py | 6 +- tools/web_build.py | 2 +- 15 files changed, 1661 insertions(+), 748 deletions(-) create mode 100644 LICENSE rename LICENSE.md => LICENSES/CC0-1.0.txt (100%) delete mode 100644 port/third_party/extract-xiso/LICENSE.TXT delete mode 100644 port/third_party/extract-xiso/README.md diff --git a/AGENTS.md b/AGENTS.md index 20a6e0fb..5e5a277b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -190,10 +190,18 @@ otherwise. ### Third-party code and licences -The repository is CC0. Vendored code goes in `port/third_party/`, -copied unchanged, with a README naming the upstream, the version or commit, -the checksum and what uses it. GPL code (OpenSauce, Reclaimer) may be read -as documentation of file formats, never copied. +The repository is `AGPL-3.0-or-later` (`LICENSE`); the commits before the +change, and the releases built from them, stay CC0 (`LICENSES/CC0-1.0.txt`). +The README's "Licence" section says what each part is under. Vendored code +goes in `port/third_party/`, copied unchanged, with a README naming +the upstream, the version or commit, the licence, the checksum and what uses +it. Its licence must let it be combined with the AGPL 3.0: MIT, BSD (without +an advertising clause), ISC, zlib, Apache 2.0, MPL 2.0, LGPL or GPL 3.0 or +later, public domain. GPL-2.0-only code and the 4-clause BSD licence cannot +be. Code taken from another project, GPL 3.0 code included, keeps its +notices and its licence, and says where it came from. +The decompilation's upstream, punpckhdq/halo, is AGPL 3.0 from 17 October +2026; bnunu/halo-1 is CC0. ### Commits and pull requests diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..be3f7b28 --- /dev/null +++ b/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/LICENSE.md b/LICENSES/CC0-1.0.txt similarity index 100% rename from LICENSE.md rename to LICENSES/CC0-1.0.txt diff --git a/README.md b/README.md index 9af23c55..1648e52e 100644 --- a/README.md +++ b/README.md @@ -202,3 +202,34 @@ Enter `adb pull` to copy the recording parts to a computer. A profiling build plays with normal builds. It does not use `--pgo=train`. + +## Licence + +OpenCE is free software: you can give it to others and change it under the +terms of the GNU Affero General Public License as published by the Free +Software Foundation, version 3 of the License or (at your option) any later +version (`AGPL-3.0-or-later`). It comes with no warranty. The full text is in +[LICENSE](LICENSE). + +- **From the change.** The AGPL applies from the commit that made the change, + and to each release built from that commit or a later one. Earlier + releases, and the source at every earlier commit, were released under + [CC0 1.0](LICENSES/CC0-1.0.txt) and stay that way. +- **What OpenCE builds on.** The decompilation of + [punpckhdq/halo](https://github.com/punpckhdq/halo) is under the AGPL 3.0 + from 17 October 2026, and under CC0 1.0 before that date. + [bnunu/halo-1](https://github.com/bnunu/halo-1) is under CC0 1.0. +- **Contributions** are under `AGPL-3.0-or-later`. A change taken from a + project under GPL 3.0 keeps that licence and its notices; the GPL 3.0 and + the AGPL 3.0 let the two be combined (section 13 of each). +- **Hosts and servers.** If you change the game and let other persons play + with your version over a network (for example, as the host of an internet + game, or on a web site), the AGPL asks you to offer them the source of + your version (section 13). The game as released has its source here, and + each release's source is its tag (`build-`). +- **Third-party code, fonts and art** keep their own licences, which are + next to them (`port/third_party`, `port/assets/fonts`, + `port/assets/icons`, `port/assets/text_filter`). The release downloads and + the web site's `licenses.txt` carry their notices. +- **Halo is not covered.** The licence covers the work of OpenCE's authors. + It gives no rights in Halo, its maps or anything else that Microsoft owns. diff --git a/docs/custom_edition_caches.md b/docs/custom_edition_caches.md index 070a5efb..76a91cea 100644 --- a/docs/custom_edition_caches.md +++ b/docs/custom_edition_caches.md @@ -493,9 +493,9 @@ file the same as the host's; with `network.map_download` off, or a host with but their model parts have its 0x68-byte layout and their shader types its numbering, which makes them a check on what the conversion produces. -OpenSauce and Reclaimer are GPL-3.0 and this repository is CC0: no code from -either was copied. They were read as documentation of the file formats, and -every layout used was then checked against the sample maps. +No code from OpenSauce or Reclaimer (both GPL-3.0) was copied: they were +read as documentation of the file formats, and every layout used was then +checked against the sample maps. ### Documented facts (source, checked against the sample maps) diff --git a/port/android/app/src/main/java/com/halo/decomp/XisoExtractor.java b/port/android/app/src/main/java/com/halo/decomp/XisoExtractor.java index 95ce9372..31688036 100644 --- a/port/android/app/src/main/java/com/halo/decomp/XisoExtractor.java +++ b/port/android/app/src/main/java/com/halo/decomp/XisoExtractor.java @@ -4,94 +4,87 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; -import java.nio.ByteOrder; import java.nio.channels.FileChannel; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.BitSet; import java.util.List; /** - * Copies the maps folder out of an Xbox disc image (an "xiso", or a whole - * disc's ".iso"), as the desktop games do (port/linux/src/xiso.c, which this - * follows). + * Copies the maps folder out of the player's Xbox disc image of Halo, for + * LauncherActivity, as the desktop games do (port/linux/src/xiso.c; the web + * page's is port/web/site/xiso-worker.js). The image is a document the + * player picked, read through its FileChannel at absolute positions. * - * The image's file system is XDVDFS, read as extract-xiso does - * (https://github.com/XboxDev/extract-xiso, extract-xiso.c, whose format - * handling this follows; its license is below and in - * port/third_party/extract-xiso/LICENSE.TXT): 2048-byte sectors; a volume - * descriptor at 0x10000 that starts and ends with "MICROSOFT*XBOX*MEDIA" and - * gives the root directory's sector and size; and directories whose entries - * form a binary tree (each entry: left and right subtree offsets in 4-byte - * units, the start sector, the size, attributes, the name's length and the - * name, 4-byte aligned). Images made from a whole disc put the game partition - * further in, at one of the offsets below. + * Written from a description of the Xbox's disc file system, XDVDFS + * (xboxdevwiki's XDVDFS page, https://xboxdevwiki.net/XDVDFS, and the format + * facts OpenCE's readers rely on). What this class relies on: * - * The files are written to maps.partial first and moved into maps once they - * all are, so an interrupted extraction never leaves maps/ui.map behind. + * - Sectors are 2048 bytes and integers little-endian. Sector numbers count + * from the start of the game partition: an image of the partition alone + * has it at 0, an image of a whole disc further in (0x0FD90000, 0x02080000 + * or 0x18300000 for XGD2, XGD3 and XGD1 discs). They are tried in that + * order. + * - The volume descriptor is the partition's sector 32 (at 0x10000). It + * holds "MICROSOFT*XBOX*MEDIA" at its start and again at 0x7EC, and the + * root directory table's start sector (u32 at 0x14) and size in bytes (u32 + * at 0x18). + * - A directory table is a binary tree of entries whose root is the entry at + * offset 0. An entry is a left and a right subtree link (u16 each, in + * 4-byte units from the table's start, 0 for none), the start sector and + * the size of the file or of the subdirectory's table (u32 each), the + * attributes (u8, 0x10 for a directory), the name's length (u8) and the + * name. Unused bytes of a table are 0xFF, so a left link of 0xFFFF is + * padding, not an entry. + * - A file is one contiguous run of bytes from the start of its sector. * - * Some parts of this code are copyright in@fishtank.com. This product - * includes software developed by in <in@fishtank.com>. + * The image is the player's file and nothing read from it is trusted. Only + * the root's table and the maps folder's are read, each whole and at most + * 4 MB; the walk of a table visits each offset once, goes at most 64 links + * deep and looks at most 4096 entries; and a file is written only under a + * plain name that no file before it had (ignoring case). * - * Copyright (c) 2003 in <in@fishtank.com> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * - * This product includes software developed by in <in@fishtank.com>. - * - * 4. Neither the name of "in" nor the email address "in@fishtank.com" - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED `AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * AUTHOR OR ANY CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * The app starts the game once maps/ui.map exists, and makes the maps folder + * itself, so the copy is written to maps.partial (emptied first of what an + * earlier attempt left) and its files moved into maps once all are + * complete, ui.map last. */ final class XisoExtractor { private static final int SECTOR_SIZE = 2048; - private static final long VOLUME_DESCRIPTOR_OFFSET = 0x10000; - private static final int ENTRY_HEADER_SIZE = 14; + private static final int DESCRIPTOR_OFFSET = 0x10000; + private static final byte[] MAGIC = "MICROSOFT*XBOX*MEDIA".getBytes(StandardCharsets.ISO_8859_1); + private static final int SECOND_MAGIC_OFFSET = 0x7EC; + private static final int ENTRY_FIXED_SIZE = 14; private static final int ATTRIBUTE_DIRECTORY = 0x10; - /* directory tables are a few sectors; anything much larger is not one */ - private static final long MAXIMUM_DIRECTORY_SIZE = 4 << 20; - private static final int MAXIMUM_FILES = 256; - private static final int COPY_BUFFER_SIZE = 1 << 20; - private static final byte[] VOLUME_MAGIC = "MICROSOFT*XBOX*MEDIA".getBytes(StandardCharsets.US_ASCII); - - /* where the game partition starts: a plain image, and whole-disc images - (extract-xiso's GLOBAL, XGD3 and XGD1 offsets) */ - private static final long[] PARTITION_OFFSETS = { 0, 0x0FD90000L, 0x02080000L, 0x18300000L }; + private static final int PADDING_LINK = 0xFFFF; + /** where the game partition may start, in the order they are tried */ + private static final long[] PARTITION_STARTS = { + 0x00000000L, // an image of the game partition alone + 0x0FD90000L, // a whole XGD2 disc + 0x02080000L, // a whole XGD3 disc + 0x18300000L, // a whole XGD1 disc (the original Xbox's) + }; + /** directory tables are a few sectors; anything much larger is not one */ + private static final int MAXIMUM_TABLE_SIZE = 4 * 1024 * 1024; + private static final int MAXIMUM_DEPTH = 64; + private static final int MAXIMUM_VISITS = 4096; + private static final int MAXIMUM_ENTRIES = 256; + private static final int COPY_CHUNK = 1024 * 1024; + private static final String PARTIAL_DIRECTORY = "maps.partial"; + /** Told as the copy goes: the file being copied, and the bytes copied of all the files'. */ interface Progress { void report(String file, long done, long total); } - /** a reason the player can act on */ + /** A reason the player can act on: its message is shown as it is. */ static final class ExtractException extends IOException { ExtractException(String message) { super(message); } } + /** a file or folder found in a directory table */ private static final class Entry { final String name; final long sector; @@ -104,187 +97,282 @@ final class XisoExtractor { } } - private final FileChannel image; - private long partition; - - private XisoExtractor(FileChannel image) { - this.image = image; + private XisoExtractor() { } - /** copies the image's maps folder to destination/maps */ + /** Copies the image's maps folder to destination/maps. */ static void extractMaps(FileChannel image, File destination, Progress progress) throws IOException { - new XisoExtractor(image).extract(destination, progress); - } + long imageSize = image.size(); + long partition = -1; + long rootSector = 0, rootSize = 0; + ByteBuffer descriptor = ByteBuffer.allocate(SECTOR_SIZE); - private void readAt(long offset, ByteBuffer buffer) throws IOException { - while (buffer.hasRemaining()) { - int count = image.read(buffer, offset); - - if (count <= 0) - throw new ExtractException("Could not read the disc image (is it complete?)."); - offset += count; - } - buffer.flip(); - } - - private static boolean magicAt(ByteBuffer buffer, int offset) { - for (int index = 0; index < VOLUME_MAGIC.length; index++) { - if (buffer.get(offset + index) != VOLUME_MAGIC[index]) - return false; - } - return true; - } - - /** whether a name is one to write in the maps folder: no path, no "." or - * "..", and only printable ASCII that every file system takes as a plain - * name (a disc's maps folder holds .map files and loading.tga) */ - static boolean isPlainName(String name) { - if (name.isEmpty() || name.equals(".") || name.equals("..")) - return false; - for (int index = 0; index < name.length(); index++) { - char c = name.charAt(index); - if (c < 0x20 || c > 0x7E || "/\\:*?\"<>|".indexOf(c) >= 0) - return false; - } - return true; - } - - /** the partition's volume descriptor: the root directory's sector and size */ - private long[] findVolume() throws IOException { - for (long offset : PARTITION_OFFSETS) { - ByteBuffer descriptor = ByteBuffer.allocate(SECTOR_SIZE).order(ByteOrder.LITTLE_ENDIAN); - - try { - readAt(offset + VOLUME_DESCRIPTOR_OFFSET, descriptor); - } catch (IOException e) { + for (long start : PARTITION_STARTS) { + if (start + DESCRIPTOR_OFFSET + SECTOR_SIZE > imageSize) continue; - } - if (!magicAt(descriptor, 0) || !magicAt(descriptor, 0x7EC)) + descriptor.clear(); + if (!readFully(image, descriptor, start + DESCRIPTOR_OFFSET)) continue; - partition = offset; - return new long[] { - descriptor.getInt(20) & 0xFFFFFFFFL, descriptor.getInt(24) & 0xFFFFFFFFL, - }; + byte[] bytes = descriptor.array(); + if (!hasMagic(bytes, 0) || !hasMagic(bytes, SECOND_MAGIC_OFFSET)) + continue; + partition = start; + rootSector = u32(bytes, 0x14); + rootSize = u32(bytes, 0x18); + break; } - throw new ExtractException("This is not an Xbox disc image."); - } + if (partition < 0) + throw new ExtractException("This is not an Xbox disc image."); - /** a directory's table, read whole */ - private ByteBuffer readDirectory(long sector, long size, String what) throws IOException { - if (size <= 0 || size > MAXIMUM_DIRECTORY_SIZE) - throw new ExtractException(what); - ByteBuffer table = ByteBuffer.allocate((int) size).order(ByteOrder.LITTLE_ENDIAN); - readAt(partition + sector * SECTOR_SIZE, table); - return table; - } - - /** - * collects the entries of the subtree at offset (4-byte units), files or - * directories as asked - */ - private static void walk(ByteBuffer table, long offset, int depth, boolean directories, List out, - int[] visited) { - offset *= 4; - /* a malformed table must not loop or run off its end */ - if (depth > 64 || ++visited[0] > 4096 || offset + ENTRY_HEADER_SIZE > table.limit()) - return; - int at = (int) offset; - int left = table.getShort(at) & 0xFFFF; - int right = table.getShort(at + 2) & 0xFFFF; - /* 0xFFFF: padding, an empty directory */ - if (left == 0xFFFF) - return; - int nameLength = table.get(at + 13) & 0xFF; - if (left != 0) - walk(table, left, depth + 1, directories, out, visited); - boolean isDirectory = (table.get(at + 12) & ATTRIBUTE_DIRECTORY) != 0; - if (at + ENTRY_HEADER_SIZE + nameLength <= table.limit() && nameLength > 0 && isDirectory == directories - && out.size() < MAXIMUM_FILES) { - byte[] bytes = new byte[nameLength]; - for (int index = 0; index < nameLength; index++) - bytes[index] = table.get(at + ENTRY_HEADER_SIZE + index); - String name = new String(bytes, StandardCharsets.ISO_8859_1); - /* (as extract-xiso refuses them: no name may leave the folder, and - none but a plain file name is written) */ - if (isPlainName(name)) - out.add(new Entry(name, table.getInt(at + 4) & 0xFFFFFFFFL, table.getInt(at + 8) & 0xFFFFFFFFL)); - } - if (right != 0) - walk(table, right, depth + 1, directories, out, visited); - } - - private void extract(File destination, Progress progress) throws IOException { - long[] root = findVolume(); - - /* the root's maps folder */ - ByteBuffer table = readDirectory(root[0], root[1], "The disc image's file system is damaged."); - List directories = new ArrayList<>(); - walk(table, 0, 0, true, directories, new int[1]); + // the root's maps folder + byte[] root = readTable(image, partition, rootSector, rootSize, "The disc image's file system is damaged."); Entry maps = null; - for (Entry entry : directories) { - if (entry.name.equalsIgnoreCase("maps")) + for (Entry entry : walkTable(root, true)) { + if (entry.name.equalsIgnoreCase("maps")) { maps = entry; + break; + } } if (maps == null) throw new ExtractException("The disc image has no maps folder: it is not a Halo disc."); - /* its files */ - table = readDirectory(maps.sector, maps.size, "The disc image's maps folder is damaged."); - List files = new ArrayList<>(); - walk(table, 0, 0, false, files, new int[1]); - long total = 0; - boolean hasUi = false; + // its files + byte[] table = readTable(image, partition, maps.sector, maps.size, "The disc image's maps folder is damaged."); + List files = walkTable(table, false); + Entry userInterface = null; for (Entry file : files) { - total += file.size; - hasUi |= file.name.equalsIgnoreCase("ui.map"); + if (file.name.equalsIgnoreCase("ui.map")) + userInterface = file; } - if (!hasUi) + if (userInterface == null) throw new ExtractException("The disc image's maps folder has no ui.map: it is not a Halo disc."); - - File partial = new File(destination, "maps.partial"); - File finished = new File(destination, "maps"); - if (!partial.isDirectory() && !partial.mkdirs()) - throw new ExtractException("Could not create " + partial + "."); - ByteBuffer buffer = ByteBuffer.allocateDirect(COPY_BUFFER_SIZE); - long done = 0; + // (an image that ends before a file does is refused before anything + // is written; an empty file's sector need not be anywhere) + long total = 0; for (Entry file : files) { - File path = new File(partial, file.name); - long offset = partition + file.sector * SECTOR_SIZE; - long remaining = file.size; - - try (FileOutputStream out = new FileOutputStream(path)) { - FileChannel output = out.getChannel(); - - while (remaining > 0) { - buffer.clear(); - buffer.limit((int) Math.min(remaining, COPY_BUFFER_SIZE)); - readAt(offset, buffer); - int count = buffer.remaining(); - while (buffer.hasRemaining()) - output.write(buffer); - offset += count; - remaining -= count; - done += count; - progress.report(file.name, done, total); - } - } catch (ExtractException e) { - throw new ExtractException("Could not read " + file.name + " from the disc image (is it complete?)."); - } catch (IOException e) { - throw new ExtractException("Could not write " + path + " (is the storage full?)."); - } + if (file.size > 0 && partition + file.sector * SECTOR_SIZE + file.size > imageSize) + throw new ExtractException(readFailure(file)); + total += file.size; } - /* (the maps folder may be there, empty: the app makes it for adb) */ - if (!finished.isDirectory() && !finished.mkdirs()) - throw new ExtractException("Could not create " + finished + "."); - for (Entry file : files) { - File from = new File(partial, file.name); - File to = new File(finished, file.name); + // the copy, to maps.partial + File partial = new File(destination, PARTIAL_DIRECTORY); + if (partial.isDirectory()) { + File[] leftovers = partial.listFiles(); + if (leftovers != null) { + for (File leftover : leftovers) + leftover.delete(); + } + } else { + partial.delete(); + partial.mkdirs(); + } + if (!partial.isDirectory()) + throw new ExtractException("Could not create " + partial.getPath() + "."); + ByteBuffer buffer = ByteBuffer.allocate(COPY_CHUNK); + long done = 0; + for (Entry file : files) + done = copyFile(image, partition, file, new File(partial, file.name), buffer, done, total, progress); - to.delete(); - if (!from.renameTo(to)) - throw new ExtractException("Could not move " + file.name + " into " + finished + "."); + // then into maps, ui.map (the app's sign that the data is there) last + File mapsFolder = new File(destination, "maps"); + if (!mapsFolder.isDirectory() && !mapsFolder.mkdirs() && !mapsFolder.isDirectory()) + throw new ExtractException("Could not create " + mapsFolder.getPath() + "."); + List order = new ArrayList<>(files); + order.remove(userInterface); + order.add(userInterface); + for (Entry file : order) { + File target = new File(mapsFolder, file.name); + target.delete(); + if (!new File(partial, file.name).renameTo(target)) + throw new ExtractException("Could not move " + file.name + " into " + mapsFolder.getPath() + "."); } partial.delete(); } + + /** No path, no . or .., and only printable ASCII that every file system takes as a plain name. */ + static boolean isPlainName(String name) { + if (name == null || name.isEmpty() || name.equals(".") || name.equals("..")) + return false; + for (int index = 0; index < name.length(); index++) { + char character = name.charAt(index); + + if (character < 0x20 || character > 0x7E || "/\\:*?\"<>|".indexOf(character) >= 0) + return false; + } + return true; + } + + /* ---------- the image */ + + private static long u16(byte[] bytes, int offset) { + return (bytes[offset] & 0xFF) | (bytes[offset + 1] & 0xFF) << 8; + } + + private static long u32(byte[] bytes, int offset) { + return u16(bytes, offset) | u16(bytes, offset + 2) << 16; + } + + private static boolean hasMagic(byte[] bytes, int offset) { + for (int index = 0; index < MAGIC.length; index++) { + if (bytes[offset + index] != MAGIC[index]) + return false; + } + return true; + } + + /** Fills buffer from the image at position; false if the image ends first. */ + private static boolean readFully(FileChannel image, ByteBuffer buffer, long position) throws IOException { + while (buffer.hasRemaining()) { + int count = image.read(buffer, position); + + if (count <= 0) + return false; + position += count; + } + return true; + } + + private static byte[] readTable(FileChannel image, long partition, long sector, long size, String damaged) + throws IOException { + if (size == 0 || size > MAXIMUM_TABLE_SIZE) + throw new ExtractException(damaged); + ByteBuffer table = ByteBuffer.allocate((int) size); + if (!readFully(image, table, partition + sector * SECTOR_SIZE)) + throw new ExtractException("Could not read the disc image (is it complete?)."); + return table.array(); + } + + /* ---------- directory tables */ + + private static final class Walk { + final byte[] table; + final boolean directories; + final BitSet visited = new BitSet(); + final List entries = new ArrayList<>(); + int visits; + boolean stopped; + + Walk(byte[] table, boolean directories) { + this.table = table; + this.directories = directories; + } + } + + /** The folders (or the files) of a table with plain names, in the tree's order. */ + private static List walkTable(byte[] table, boolean directories) { + Walk walk = new Walk(table, directories); + + walkEntry(walk, 0, 0); + return walk.entries; + } + + /** + * The subtree whose root entry is at offset: its left subtree, the + * entry, its right subtree. A link to padding, past the table or back to + * an entry already visited ends that branch. + */ + private static void walkEntry(Walk walk, int offset, int depth) { + byte[] table = walk.table; + + if (walk.stopped || depth > MAXIMUM_DEPTH) + return; + if (offset >= table.length || table.length - offset < ENTRY_FIXED_SIZE) + return; + int left = (int) u16(table, offset); + int right = (int) u16(table, offset + 2); + if (left == PADDING_LINK || walk.visited.get(offset / 4)) + return; + walk.visited.set(offset / 4); + if (walk.visits >= MAXIMUM_VISITS) { + walk.stopped = true; + return; + } + walk.visits++; + + if (left != 0) + walkEntry(walk, left * 4, depth + 1); + int nameLength = table[offset + 13] & 0xFF; + if (nameLength != 0 && nameLength <= table.length - offset - ENTRY_FIXED_SIZE) + collect(walk, offset, nameLength); + if (right != 0) + walkEntry(walk, right * 4, depth + 1); + } + + private static void collect(Walk walk, int offset, int nameLength) { + byte[] table = walk.table; + boolean directory = (table[offset + 12] & ATTRIBUTE_DIRECTORY) != 0; + + if (directory != walk.directories || walk.entries.size() >= MAXIMUM_ENTRIES) + return; + String name = new String(table, offset + ENTRY_FIXED_SIZE, nameLength, StandardCharsets.ISO_8859_1); + if (!isPlainName(name)) + return; + // (the destination's file system may ignore case) + for (Entry entry : walk.entries) { + if (entry.name.equalsIgnoreCase(name)) + return; + } + walk.entries.add(new Entry(name, u32(table, offset + 4), u32(table, offset + 8))); + } + + /* ---------- the copy */ + + private static String readFailure(Entry file) { + return "Could not read " + file.name + " from the disc image (is it complete?)."; + } + + /** Copies one file of the image to output; returns the bytes copied of all the files so far. */ + private static long copyFile(FileChannel image, long partition, Entry file, File output, ByteBuffer buffer, + long done, long total, Progress progress) throws IOException { + String writeFailure = "Could not write " + output.getPath() + " (is the storage full?)."; + long position = partition + file.sector * SECTOR_SIZE; + long remaining = file.size; + FileOutputStream stream = null; + + try { + stream = new FileOutputStream(output); + FileChannel channel = stream.getChannel(); + while (remaining > 0) { + int count = (int) Math.min(remaining, COPY_CHUNK); + boolean read; + + buffer.clear(); + buffer.limit(count); + try { + read = readFully(image, buffer, position); + } catch (IOException exception) { + read = false; + } + if (!read) + throw new ExtractException(readFailure(file)); + buffer.flip(); + while (buffer.hasRemaining()) { + if (channel.write(buffer) <= 0) + throw new ExtractException(writeFailure); + } + position += count; + remaining -= count; + done += count; + if (progress != null) + progress.report(file.name, done, total); + } + FileOutputStream closing = stream; + stream = null; + closing.close(); + } catch (ExtractException exception) { + throw exception; + } catch (IOException exception) { + throw new ExtractException(writeFailure); + } finally { + if (stream != null) { + try { + stream.close(); + } catch (IOException ignored) { + // (the copy failed already) + } + } + } + return done; + } } diff --git a/port/linux/game/cache_file_formats.c b/port/linux/game/cache_file_formats.c index 9f856c6e..8a691c7c 100644 --- a/port/linux/game/cache_file_formats.c +++ b/port/linux/game/cache_file_formats.c @@ -14,11 +14,11 @@ Sources for the layouts, cited per structure below: - BlamLib, in the same archive: the font and unicode string list layouts. - Reclaimer (GPL-3.0, Gravemind2401; the Reclaimer-master archive): how bitmap tags and pixel data are found in bitmaps.map. -No code from either project is used: they are documentation here, and this -repository is CC0. Facts that neither source states were established by -reading the sample Custom Edition maps; the comments below say so where they -are used ("observed", "every map examined"), and -docs/custom_edition_caches.md lists each with its evidence. +No code from either project is used: they are documentation here. Facts +that neither source states were established by reading the sample Custom +Edition maps; the comments below say so where they are used ("observed", +"every map examined"), and docs/custom_edition_caches.md lists each with its +evidence. */ /* ---------- headers */ diff --git a/port/linux/src/updater.c b/port/linux/src/updater.c index c8357594..7a7b4f3d 100644 --- a/port/linux/src/updater.c +++ b/port/linux/src/updater.c @@ -521,13 +521,15 @@ static void updater_update(void) } } -/* the files a previous update left behind */ +/* the files a previous update left behind, and the notice of extract-xiso, +which releases carried until the disc image readers were written again */ static void updater_clean_up(void) { static const char *const names[] = { "halo.old", "halo.exe.old", "SDL3.dll.old", "libSDL3.so.0.old", "SDL3-LICENSE.txt.old", - "extract-xiso-LICENSE.txt.old", "mbedtls-LICENSE.txt.old", + "extract-xiso-LICENSE.txt.old", "mbedtls-LICENSE.txt.old", "LICENSE.txt.old", + "extract-xiso-LICENSE.txt", }; char path[1200]; size_t index; diff --git a/port/linux/src/xiso.c b/port/linux/src/xiso.c index 84fae910..e2097950 100644 --- a/port/linux/src/xiso.c +++ b/port/linux/src/xiso.c @@ -1,307 +1,408 @@ /* XISO.C -Copies the maps folder out of an Xbox disc image (an "xiso"), for the -desktop ports' first start without game data (sdl_platform.c). +The maps folder out of an Xbox disc image, for the desktop games (Linux and +Windows). When no data root has a maps folder, sdl_platform.c asks the player +for their disc image of Halo and this copies the image's maps folder next to +the executable. (The Android app's copy of this is XisoExtractor.java, the +web page's xiso-worker.js.) -The image's file system is XDVDFS, read as extract-xiso does -(https://github.com/XboxDev/extract-xiso, extract-xiso.c, whose format -handling this follows; its license is below and in -port/third_party/extract-xiso/LICENSE.TXT): 2048-byte sectors; a -volume descriptor at 0x10000 that starts and ends with -"MICROSOFT*XBOX*MEDIA" and gives the root directory's sector and size; and -directories whose entries form a binary tree (each entry: left and right -subtree offsets in 4-byte units, the start sector, the size, attributes, the -name's length and the name, 4-byte aligned). Images made from a whole disc -put the game partition further in, at one of the offsets below. +Written from a description of the Xbox's disc file system, XDVDFS +(xboxdevwiki's XDVDFS page, https://xboxdevwiki.net/XDVDFS, and the format +facts OpenCE's readers rely on). What this file relies on: -The files are written to /maps.partial first, which becomes -/maps once they all are, so an interrupted extraction never -leaves a maps folder that looks complete. +- Sectors are 2048 bytes and integers little-endian. Sector numbers count + from the start of the game partition: an image of the partition alone has + it at 0, an image of a whole disc further in (0x0FD90000, 0x02080000 or + 0x18300000 for XGD2, XGD3 and XGD1 discs). They are tried in that order. +- The volume descriptor is the partition's sector 32 (at 0x10000). It holds + "MICROSOFT*XBOX*MEDIA" at its start and again at 0x7EC, and the root + directory table's start sector (u32 at 0x14) and size in bytes (u32 at + 0x18). +- A directory table is a binary tree of entries whose root is the entry at + offset 0. An entry is a left and a right subtree link (u16 each, in 4-byte + units from the table's start, 0 for none), the start sector and the size + of the file or of the subdirectory's table (u32 each), the attributes (u8, + 0x10 for a directory), the name's length (u8) and the name. Unused bytes of + a table are 0xFF, so a left link of 0xFFFF is padding, not an entry. +- A file is one contiguous run of bytes from the start of its sector. -Some parts of this code are copyright in@fishtank.com. This product -includes software developed by in . +The image is the player's file and nothing read from it is trusted. Only the +root's table and the maps folder's are read, each whole and at most 4 MB; +the walk of a table visits each offset once, goes at most 64 links deep and +looks at most 4096 entries; and a file is written only under a plain name +that no file before it had (ignoring case). - * Copyright (c) 2003 in - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * - * This product includes software developed by in . - * - * 4. Neither the name of "in" nor the email address "in@fishtank.com" - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED `AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * AUTHOR OR ANY CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +The game takes a data root as having data once it has a maps folder, so the +copy is written to maps.partial (emptied first of what an earlier attempt +left) and given the name maps only when every file is complete. */ -/* (the desktop ports only: the Android app and the web page import the game -data themselves) */ -#if !defined(HALO_ANDROID) && !defined(HALO_WEB) - #include "platform.h" -#include "posix.h" #include "xiso.h" +#if !defined(HALO_ANDROID) && !defined(HALO_WEB) + +#include "posix.h" + +#include #include +#include #include #include #include #include +/* (images are larger than 4 GB; Windows has neither flag) */ #ifndef O_LARGEFILE #define O_LARGEFILE 0 #endif -#ifndef O_CLOEXEC -#define O_CLOEXEC 0 -#endif #ifndef O_NOFOLLOW #define O_NOFOLLOW 0 #endif -enum +#define XISO_SECTOR_SIZE 2048 +#define XISO_DESCRIPTOR_OFFSET 0x10000 +#define XISO_MAGIC "MICROSOFT*XBOX*MEDIA" +#define XISO_MAGIC_LENGTH 20 +#define XISO_SECOND_MAGIC_OFFSET 0x7EC +#define XISO_ENTRY_FIXED_SIZE 14 +#define XISO_ATTRIBUTE_DIRECTORY 0x10 +#define XISO_PADDING_LINK 0xFFFF + +/* directory tables are a few sectors; anything much larger is not one */ +#define XISO_MAXIMUM_TABLE_SIZE (4 * 1024 * 1024) +#define XISO_MAXIMUM_DEPTH 64 +#define XISO_MAXIMUM_VISITS 4096 +#define XISO_MAXIMUM_ENTRIES 256 +#define XISO_MAXIMUM_PATH 4096 +#define XISO_COPY_CHUNK (1024 * 1024) + +#define XISO_PARTIAL_DIRECTORY "maps.partial" + +/* where the game partition may start, in the order they are tried */ +static const unsigned long xiso_partition_starts[] = { - SECTOR_SIZE = 2048, - VOLUME_DESCRIPTOR_OFFSET = 0x10000, - ENTRY_HEADER_SIZE = 14, - ATTRIBUTE_DIRECTORY = 0x10, - /* directory tables are a few sectors; anything much larger is not one */ - MAXIMUM_DIRECTORY_SIZE = 4 << 20, - MAXIMUM_FILES = 256, - COPY_BUFFER_SIZE = 1 << 20, -}; - -static const char volume_magic[] = "MICROSOFT*XBOX*MEDIA"; - -/* where the game partition starts: a plain image, and whole-disc images -(extract-xiso's GLOBAL, XGD3 and XGD1 offsets) */ -static const unsigned long long partition_offsets[] = { 0, 0x0FD90000ull, 0x02080000ull, 0x18300000ull }; - -struct xiso_file -{ - char name[256]; - unsigned long sector; - unsigned long size; + 0x00000000, /* an image of the game partition alone */ + 0x0FD90000, /* a whole XGD2 disc */ + 0x02080000, /* a whole XGD3 disc */ + 0x18300000, /* a whole XGD1 disc (the original Xbox's) */ }; struct xiso_image { int descriptor; unsigned long long partition; - char *error; - int error_size; + /* the image's size in bytes, or ~0 when it could not be found */ + unsigned long long size; }; -static int name_is_plain(const char *name); - -static unsigned long read_u32(const unsigned char *bytes) +/* a file or folder found in a directory table */ +struct xiso_entry { - return (unsigned long)bytes[0] | (unsigned long)bytes[1] << 8 | (unsigned long)bytes[2] << 16 | - (unsigned long)bytes[3] << 24; + char name[256]; + unsigned long sector; + unsigned long size; +}; + +struct xiso_walk +{ + const unsigned char *table; + unsigned long size; + /* a bit for each 4-byte offset of the table, set once it is visited */ + unsigned char *visited; + int visits; + int stopped; + /* whether folders are collected (or else files) */ + int directories; + struct xiso_entry *entries; + int entry_count; +}; + +/* ---------- errors */ + +static void xiso_error(char *error, int error_size, const char *format, ...) +{ + va_list arguments; + + if (!error || error_size <= 0) + return; + va_start(arguments, format); + vsnprintf(error, (size_t)error_size, format, arguments); + va_end(arguments); + error[error_size - 1] = 0; } -static int fail(struct xiso_image *image, const char *format, const char *detail) +/* ---------- names */ + +static int xiso_lower(int character) { - snprintf(image->error, (size_t)image->error_size, format, detail ? detail : ""); - return 0; + return character >= 'A' && character <= 'Z' ? character - 'A' + 'a' : character; } -/* reads size bytes at offset (from the start of the file) */ -static int read_at(struct xiso_image *image, unsigned long long offset, void *buffer, unsigned long size) +/* whether a name of length bytes is name (a C string), ignoring ASCII case */ +static int xiso_name_is(const char *bytes, int length, const char *name) { - posix_ulong low, high; - unsigned char *cursor = buffer; + int index; - if (posix_seek(image->descriptor, (posix_long)(offset & 0xFFFFFFFFu), (posix_long)(offset >> 32), SEEK_SET, - &low, &high) != 0) - { + if ((int)strlen(name) != length) return 0; - } - while (size > 0) + for (index = 0; index < length; index++) { - long count = (long)read(image->descriptor, cursor, size > COPY_BUFFER_SIZE ? COPY_BUFFER_SIZE : size); - - if (count <= 0) + if (xiso_lower((unsigned char)bytes[index]) != xiso_lower((unsigned char)name[index])) return 0; - cursor += count; - size -= (unsigned long)count; } return 1; } -/* the partition's volume descriptor: the root directory's sector and size */ -static int find_volume(struct xiso_image *image, unsigned long *root_sector, unsigned long *root_size) +/* no path, no . or .., and only printable ASCII that every desktop file +system takes as a plain name */ +static int xiso_plain_name(const unsigned char *name, int length) { int index; - for (index = 0; index < (int)(sizeof(partition_offsets) / sizeof(*partition_offsets)); index++) + if (length <= 0 || (length == 1 && name[0] == '.') || (length == 2 && name[0] == '.' && name[1] == '.')) + return 0; + for (index = 0; index < length; index++) { - unsigned char descriptor[SECTOR_SIZE]; - unsigned long long offset = partition_offsets[index] + VOLUME_DESCRIPTOR_OFFSET; - - if (!read_at(image, offset, descriptor, sizeof(descriptor))) - continue; - if (memcmp(descriptor, volume_magic, 20) || memcmp(descriptor + 0x7EC, volume_magic, 20)) - continue; - image->partition = partition_offsets[index]; - *root_sector = read_u32(descriptor + 20); - *root_size = read_u32(descriptor + 24); - return 1; + if (name[index] < 0x20 || name[index] > 0x7E || strchr("/\\:*?\"<>|", name[index])) + return 0; } - return fail(image, "This is not an Xbox disc image.%s", NULL); + return 1; } -/* a directory's table, read whole */ -static unsigned char *read_directory(struct xiso_image *image, unsigned long sector, unsigned long size) +/* ---------- the image */ + +static unsigned long xiso_u16(const unsigned char *bytes) +{ + return (unsigned long)bytes[0] | (unsigned long)bytes[1] << 8; +} + +static unsigned long xiso_u32(const unsigned char *bytes) +{ + return xiso_u16(bytes) | xiso_u16(bytes + 2) << 16; +} + +/* reads size bytes at offset (from the start of the image file); returns +nonzero if all of them were read */ +static int xiso_read(struct xiso_image *image, unsigned long long offset, void *buffer, unsigned long size) +{ + posix_ulong position_low, position_high; + unsigned long count = 0; + + if (posix_seek(image->descriptor, (posix_long)(offset & 0xFFFFFFFFUL), (posix_long)(offset >> 32), SEEK_SET, + &position_low, &position_high) != 0) + { + return 0; + } + while (count < size) + { + int result = (int)read(image->descriptor, (char *)buffer + count, (unsigned int)(size - count)); + + if (result < 0 && errno == EINTR) + continue; + if (result <= 0) + return 0; + count += (unsigned long)result; + } + return 1; +} + +/* the byte offset of a sector of the game partition */ +static unsigned long long xiso_sector_offset(struct xiso_image *image, unsigned long sector) +{ + return image->partition + (unsigned long long)sector * XISO_SECTOR_SIZE; +} + +/* finds the game partition: the first start whose volume descriptor has +both magics. Returns the root table's sector and size */ +static int xiso_find_volume(struct xiso_image *image, unsigned long *root_sector, unsigned long *root_size) +{ + unsigned char descriptor[XISO_SECTOR_SIZE]; + int index; + + for (index = 0; index < (int)(sizeof(xiso_partition_starts) / sizeof(xiso_partition_starts[0])); index++) + { + unsigned long long start = xiso_partition_starts[index]; + + if (!xiso_read(image, start + XISO_DESCRIPTOR_OFFSET, descriptor, sizeof(descriptor)) || + memcmp(descriptor, XISO_MAGIC, XISO_MAGIC_LENGTH) != 0 || + memcmp(descriptor + XISO_SECOND_MAGIC_OFFSET, XISO_MAGIC, XISO_MAGIC_LENGTH) != 0) + { + continue; + } + image->partition = start; + *root_sector = xiso_u32(descriptor + 0x14); + *root_size = xiso_u32(descriptor + 0x18); + return 1; + } + return 0; +} + +/* reads a directory table whole into a new allocation; returns NULL if it +is empty, too large or cannot be read, setting *out_of_memory when that is +the reason */ +static unsigned char *xiso_read_table(struct xiso_image *image, unsigned long sector, unsigned long size, + int *out_of_memory) { unsigned char *table; - if (!size || size > MAXIMUM_DIRECTORY_SIZE) + *out_of_memory = 0; + if (size == 0 || size > XISO_MAXIMUM_TABLE_SIZE) return NULL; table = malloc(size); - if (table && !read_at(image, image->partition + (unsigned long long)sector * SECTOR_SIZE, table, size)) + if (!table) + { + *out_of_memory = 1; + return NULL; + } + if (!xiso_read(image, xiso_sector_offset(image, sector), table, size)) { free(table); - table = NULL; + return NULL; } return table; } -struct directory_walk -{ - const unsigned char *table; - unsigned long size; - struct xiso_file *entries; - int entry_count; - int maximum_count; - int visited; - int directories; -}; +/* ---------- directory tables */ -/* collects the entries of the subtree at offset (4-byte units), files or -directories as asked */ -static void walk_directory(struct directory_walk *walk, unsigned long offset, int depth) +static void xiso_walk_collect(struct xiso_walk *walk, const unsigned char *entry) +{ + struct xiso_entry *collected; + int name_length = entry[13]; + int index; + + if (((entry[12] & XISO_ATTRIBUTE_DIRECTORY) != 0) != (walk->directories != 0)) + return; + if (walk->entry_count >= XISO_MAXIMUM_ENTRIES || !xiso_plain_name(entry + XISO_ENTRY_FIXED_SIZE, name_length)) + return; + /* (the destination's file system may ignore case) */ + for (index = 0; index < walk->entry_count; index++) + { + if (xiso_name_is((const char *)entry + XISO_ENTRY_FIXED_SIZE, name_length, walk->entries[index].name)) + return; + } + collected = &walk->entries[walk->entry_count++]; + memcpy(collected->name, entry + XISO_ENTRY_FIXED_SIZE, (size_t)name_length); + collected->name[name_length] = 0; + collected->sector = xiso_u32(entry + 4); + collected->size = xiso_u32(entry + 8); +} + +/* the subtree whose root entry is at offset: its left subtree, the entry, +its right subtree. A link to padding, past the table or back to an entry +already visited ends that branch */ +static void xiso_walk_entry(struct xiso_walk *walk, unsigned long offset, int depth) { const unsigned char *entry; - unsigned long left, right; - int name_length; + unsigned long left, right, name_length; - offset *= 4; - /* a malformed table must not loop or run off its end */ - if (depth > 64 || ++walk->visited > 4096 || offset + ENTRY_HEADER_SIZE > walk->size) + if (walk->stopped || depth > XISO_MAXIMUM_DEPTH) + return; + if (offset >= walk->size || walk->size - offset < XISO_ENTRY_FIXED_SIZE) return; entry = walk->table + offset; - left = (unsigned long)entry[0] | (unsigned long)entry[1] << 8; - right = (unsigned long)entry[2] | (unsigned long)entry[3] << 8; - /* 0xFFFF: padding, an empty directory */ - if (left == 0xFFFF) + left = xiso_u16(entry); + right = xiso_u16(entry + 2); + if (left == XISO_PADDING_LINK) return; - name_length = entry[13]; + /* (links are in 4-byte units, so every offset is a multiple of 4) */ + if (walk->visited[offset >> 5] & (1 << ((offset >> 2) & 7))) + return; + walk->visited[offset >> 5] |= (unsigned char)(1 << ((offset >> 2) & 7)); + if (walk->visits >= XISO_MAXIMUM_VISITS) + { + walk->stopped = 1; + return; + } + walk->visits++; + if (left) - walk_directory(walk, left, depth + 1); - if (offset + ENTRY_HEADER_SIZE + (unsigned long)name_length <= walk->size && name_length > 0 && - !(entry[12] & ATTRIBUTE_DIRECTORY) == !walk->directories && walk->entry_count < walk->maximum_count) - { - struct xiso_file *file = &walk->entries[walk->entry_count]; - - memcpy(file->name, entry + ENTRY_HEADER_SIZE, (size_t)name_length); - file->name[name_length] = 0; - file->sector = read_u32(entry + 4); - file->size = read_u32(entry + 8); - /* (as extract-xiso refuses them: no name may leave the folder, and - none but a plain file name is written) */ - if (name_is_plain(file->name)) - { - walk->entry_count++; - } - } + xiso_walk_entry(walk, left * 4, depth + 1); + name_length = entry[13]; + if (name_length && name_length <= walk->size - offset - XISO_ENTRY_FIXED_SIZE) + xiso_walk_collect(walk, entry); if (right) - walk_directory(walk, right, depth + 1); + xiso_walk_entry(walk, right * 4, depth + 1); } -/* whether a name is one to write in the maps folder: no path, no "." or -"..", and only printable ASCII that every desktop file system takes as a -plain name (a disc's maps folder holds .map files and loading.tga) */ -static int name_is_plain(const char *name) +/* collects the folders (or the files) of a table, with plain names, into +entries (XISO_MAXIMUM_ENTRIES of them); returns how many, or -1 when out of +memory */ +static int xiso_walk_table(const unsigned char *table, unsigned long size, int directories, + struct xiso_entry *entries) { - const char *at; + struct xiso_walk walk; - if (!*name || !strcmp(name, ".") || !strcmp(name, "..")) - return 0; - for (at = name; *at; at++) + memset(&walk, 0, sizeof(walk)); + walk.table = table; + walk.size = size; + walk.directories = directories; + walk.entries = entries; + walk.visited = calloc(size / 32 + 1, 1); + if (!walk.visited) + return -1; + xiso_walk_entry(&walk, 0, 0); + free(walk.visited); + return walk.entry_count; +} + +/* ---------- the copy */ + +/* removes what an earlier, interrupted copy left in the folder at path */ +static void xiso_empty_directory(const char *path, char *file_path, size_t file_path_size) +{ + void *directory = posix_directory_open(path); + char name[260]; + + if (!directory) + return; + while (posix_directory_next(directory, name, sizeof(name))) { - unsigned char c = (unsigned char)*at; + int length = snprintf(file_path, file_path_size, "%s/%s", path, name); - if (c < 0x20 || c > 0x7e || strchr("/\\:*?\"<>|", c)) - return 0; + if (length > 0 && (size_t)length < file_path_size) + remove(file_path); } - return 1; + posix_directory_close(directory); } -static int names_match(const char *a, const char *b) +/* copies one file of the image to path, adding to *done as it goes */ +static int xiso_copy_file(struct xiso_image *image, const struct xiso_entry *entry, const char *path, + unsigned char *buffer, unsigned long long *done, unsigned long long total, xiso_progress_proc progress, + void *context, char *error, int error_size) { - for (; *a && *b; a++, b++) - { - char x = *a >= 'A' && *a <= 'Z' ? (char)(*a - 'A' + 'a') : *a; - char y = *b >= 'A' && *b <= 'Z' ? (char)(*b - 'A' + 'a') : *b; - - if (x != y) - return 0; - } - return !*a && !*b; -} - -static int copy_file(struct xiso_image *image, const struct xiso_file *file, const char *path, - unsigned char *buffer, unsigned long long *done, unsigned long long total, - xiso_progress_proc progress, void *context) -{ - unsigned long long offset = image->partition + (unsigned long long)file->sector * SECTOR_SIZE; - unsigned long remaining = file->size; - /* (not through a link left in the folder) */ + unsigned long long offset = xiso_sector_offset(image, entry->sector); + unsigned long remaining = entry->size; int output = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW, 0644); if (output < 0) - return fail(image, "Could not write %s.", path); - while (remaining > 0) { - unsigned long count = remaining > COPY_BUFFER_SIZE ? COPY_BUFFER_SIZE : remaining; + xiso_error(error, error_size, "Could not write %s.", path); + return 0; + } + while (remaining) + { + unsigned long count = remaining < XISO_COPY_CHUNK ? remaining : XISO_COPY_CHUNK; unsigned long written = 0; - if (!read_at(image, offset, buffer, count)) + if (!xiso_read(image, offset, buffer, count)) { close(output); - return fail(image, "Could not read %s from the disc image (is it complete?).", file->name); + xiso_error(error, error_size, "Could not read %s from the disc image (is it complete?).", entry->name); + return 0; } while (written < count) { - long result = (long)write(output, buffer + written, count - written); + int result = (int)write(output, buffer + written, (unsigned int)(count - written)); + if (result < 0 && errno == EINTR) + continue; if (result <= 0) { close(output); - return fail(image, "Could not write %s (is the disk full?).", path); + xiso_error(error, error_size, "Could not write %s (is the disk full?).", path); + return 0; } written += (unsigned long)result; } @@ -309,109 +410,166 @@ static int copy_file(struct xiso_image *image, const struct xiso_file *file, con remaining -= count; *done += count; if (progress) - progress(context, file->name, *done, total); + progress(context, entry->name, *done, total); } if (close(output) != 0) - return fail(image, "Could not write %s (is the disk full?).", path); + { + xiso_error(error, error_size, "Could not write %s (is the disk full?).", path); + return 0; + } return 1; } +/* ---------- public code */ + int xiso_extract_maps(const char *image_path, const char *destination, xiso_progress_proc progress, void *context, char *error, int error_size) { struct xiso_image image; - struct xiso_file *entries = NULL; + struct xiso_entry *entries = NULL; unsigned char *table = NULL; unsigned char *buffer = NULL; - unsigned long root_sector, root_size; - unsigned long long total = 0, done = 0; - char partial[1024], final[1024], path[1300]; - int result = 0; - int index; + char *partial_path = NULL, *file_path = NULL, *maps_path = NULL; + unsigned long root_sector, root_size, maps_sector = 0, maps_size = 0; + unsigned long long done = 0, total = 0; + posix_ulong size_low, size_high; + int count, index, found, out_of_memory, succeeded = 0; - image.error = error; - image.error_size = error_size; + memset(&image, 0, sizeof(image)); image.descriptor = open(image_path, O_RDONLY | O_LARGEFILE | O_CLOEXEC); if (image.descriptor < 0) - return fail(&image, "Could not open %s.", image_path); - entries = calloc(MAXIMUM_FILES, sizeof(*entries)); - buffer = malloc(COPY_BUFFER_SIZE); - if (!entries || !buffer) { - fail(&image, "Out of memory.%s", NULL); + xiso_error(error, error_size, "Could not open %s.", image_path); + return 0; + } + image.size = ~0ULL; + if (posix_seek(image.descriptor, 0, 0, SEEK_END, &size_low, &size_high) == 0) + image.size = (unsigned long long)size_high << 32 | size_low; + + entries = malloc(sizeof(*entries) * XISO_MAXIMUM_ENTRIES); + buffer = malloc(XISO_COPY_CHUNK); + partial_path = malloc(XISO_MAXIMUM_PATH); + file_path = malloc(XISO_MAXIMUM_PATH); + maps_path = malloc(XISO_MAXIMUM_PATH); + if (!entries || !buffer || !partial_path || !file_path || !maps_path) + { + xiso_error(error, error_size, "Out of memory."); goto done; } - if (!find_volume(&image, &root_sector, &root_size)) + + if (!xiso_find_volume(&image, &root_sector, &root_size)) + { + xiso_error(error, error_size, "This is not an Xbox disc image."); goto done; + } /* the root's maps folder */ - table = read_directory(&image, root_sector, root_size); + table = xiso_read_table(&image, root_sector, root_size, &out_of_memory); if (!table) { - fail(&image, "The disc image's file system is damaged.%s", NULL); + xiso_error(error, error_size, out_of_memory ? "Out of memory." : "The disc image's file system is damaged."); goto done; } + count = xiso_walk_table(table, root_size, 1, entries); + free(table); + table = NULL; + if (count < 0) { - struct directory_walk walk = { table, root_size, entries, 0, MAXIMUM_FILES, 0, 1 }; - - walk_directory(&walk, 0, 0); - for (index = 0; index < walk.entry_count && !names_match(entries[index].name, "maps"); index++) - ; - if (index == walk.entry_count) + xiso_error(error, error_size, "Out of memory."); + goto done; + } + for (found = 0, index = 0; index < count && !found; index++) + { + if (xiso_name_is(entries[index].name, (int)strlen(entries[index].name), "maps")) { - fail(&image, "The disc image has no maps folder: it is not a Halo disc.%s", NULL); - goto done; + maps_sector = entries[index].sector; + maps_size = entries[index].size; + found = 1; } - free(table); - table = read_directory(&image, entries[index].sector, entries[index].size); - if (!table) - { - fail(&image, "The disc image's maps folder is damaged.%s", NULL); - goto done; - } - root_size = entries[index].size; + } + if (!found) + { + xiso_error(error, error_size, "The disc image has no maps folder: it is not a Halo disc."); + goto done; } /* its files */ + table = xiso_read_table(&image, maps_sector, maps_size, &out_of_memory); + if (!table) { - struct directory_walk walk = { table, root_size, entries, 0, MAXIMUM_FILES, 0, 0 }; - int has_ui = 0; - - walk_directory(&walk, 0, 0); - for (index = 0; index < walk.entry_count; index++) + xiso_error(error, error_size, out_of_memory ? "Out of memory." : "The disc image's maps folder is damaged."); + goto done; + } + count = xiso_walk_table(table, maps_size, 0, entries); + free(table); + table = NULL; + if (count < 0) + { + xiso_error(error, error_size, "Out of memory."); + goto done; + } + for (found = 0, index = 0; index < count && !found; index++) + found = xiso_name_is(entries[index].name, (int)strlen(entries[index].name), "ui.map"); + if (!found) + { + xiso_error(error, error_size, "The disc image's maps folder has no ui.map: it is not a Halo disc."); + goto done; + } + /* (an image that ends before a file does is refused before anything is + written; an empty file's sector need not be anywhere) */ + for (index = 0; index < count; index++) + { + if (entries[index].size && + xiso_sector_offset(&image, entries[index].sector) + entries[index].size > image.size) { - total += entries[index].size; - has_ui |= names_match(entries[index].name, "ui.map"); - } - if (!has_ui) - { - fail(&image, "The disc image's maps folder has no ui.map: it is not a Halo disc.%s", NULL); + xiso_error(error, error_size, "Could not read %s from the disc image (is it complete?).", + entries[index].name); goto done; } - snprintf(partial, sizeof(partial), "%s/maps.partial", destination); - snprintf(final, sizeof(final), "%s/maps", destination); - posix_make_directory(partial); - for (index = 0; index < walk.entry_count; index++) + total += entries[index].size; + } + + /* the copy, to maps.partial */ + if (snprintf(partial_path, XISO_MAXIMUM_PATH, "%s/" XISO_PARTIAL_DIRECTORY, destination) >= XISO_MAXIMUM_PATH || + snprintf(maps_path, XISO_MAXIMUM_PATH, "%s/maps", destination) >= XISO_MAXIMUM_PATH) + { + xiso_error(error, error_size, "Could not create %s/maps.", destination); + goto done; + } + /* (an existing one is reused, emptied; a failure to make it shows as a + failure to write the first file) */ + posix_make_directory(partial_path); + xiso_empty_directory(partial_path, file_path, XISO_MAXIMUM_PATH); + for (index = 0; index < count; index++) + { + platform_log("extracting maps/%s (%lu bytes)", entries[index].name, entries[index].size); + if (snprintf(file_path, XISO_MAXIMUM_PATH, "%s/%s", partial_path, entries[index].name) >= XISO_MAXIMUM_PATH) { - snprintf(path, sizeof(path), "%s/%s", partial, entries[index].name); - platform_log("extracting maps/%s (%lu bytes)", entries[index].name, entries[index].size); - if (!copy_file(&image, &entries[index], path, buffer, &done, total, progress, context)) - goto done; + xiso_error(error, error_size, "Could not write %s/%s.", partial_path, entries[index].name); + goto done; } - if (rename(partial, final) != 0) + if (!xiso_copy_file(&image, &entries[index], file_path, buffer, &done, total, progress, context, + error, error_size)) { - fail(&image, "Could not create %s.", final); goto done; } } - result = 1; + if (rename(partial_path, maps_path) != 0) + { + xiso_error(error, error_size, "Could not create %s.", maps_path); + goto done; + } + succeeded = 1; done: - close(image.descriptor); free(table); - free(entries); + free(maps_path); + free(file_path); + free(partial_path); free(buffer); - return result; + free(entries); + close(image.descriptor); + return succeeded; } #endif diff --git a/port/third_party/extract-xiso/LICENSE.TXT b/port/third_party/extract-xiso/LICENSE.TXT deleted file mode 100644 index b89be76a..00000000 --- a/port/third_party/extract-xiso/LICENSE.TXT +++ /dev/null @@ -1,75 +0,0 @@ -This is an xdvdfs (xbox iso) file creation/extraction utility for linux/darwin/ -freebsd. - -If you want to port it to your OS it shouldn't be too hard, just make sure your -fseek/ftell takes 64-bit file offsets. - -I wrote this code completely from scratch today because xbiso (the one on -sourceforge) keeps seg-faulting and the code is buggy. I got useful -documentation on the xdvdfs file system from http://xbox-linux.sourceforge.net. - -I will say thanks though to the author of xbiso, it was a good start and got me -thinking! - - -Regarding licensing: - -I think the GPL sucks! (it stands for Generosity Poor License) - -My open-source code is really *FREE* so you can do whatever you want with it, as -long as 1) you don't claim that you wrote my code and 2) you retain a notice -that some parts of the code are copyright in@fishtank.com and 3) you understand -there are no warranties. I only guarantee that it will take up disk space! - -If you want to help out with this project it would be welcome, just email me at -in@fishtank.com. - -This code is copyright in@fishtank.com and is licensed under a slightly -modifified version of the Berkeley Software License, which follows: - -/* - * Copyright (c) 2003 in - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * - * This product includes software developed by in . - * - * 4. Neither the name of "in" nor the email address "in@fishtank.com" - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED `AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * AUTHOR OR ANY CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -Please send bug reports to me at in@fishtank.com - -To compile, run 'make' in the source directory. - -NOTE: You need to be running GNU make and /bin/bash must be executable - -Enjoy! - -in version 1.0 -March 10, 2003 diff --git a/port/third_party/extract-xiso/README.md b/port/third_party/extract-xiso/README.md deleted file mode 100644 index 8b61fcd5..00000000 --- a/port/third_party/extract-xiso/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# extract-xiso - -An Xbox disc image (xdvdfs) extraction and creation tool by in -, under a modified BSD license (see `LICENSE.TXT`, copied -unchanged from upstream). - -Upstream: https://github.com/XboxDev/extract-xiso, commit -3f5b62cfe68f000b0e3c8a30104973f3a297948e. - -None of its code is built as it is: `port/linux/src/xiso.c`, which copies -the maps folder out of a disc image when a desktop port starts without game -data, reads the format as `extract-xiso.c` does and carries its notice. The -desktop builds' artifacts include `LICENSE.TXT` as -`extract-xiso-LICENSE.txt`. - -This product includes software developed by in . diff --git a/port/web/licenses.py b/port/web/licenses.py index e8ef775c..98c01d33 100644 --- a/port/web/licenses.py +++ b/port/web/licenses.py @@ -1,7 +1,7 @@ -"""Writes the web site's licenses.txt (tools/web_build.py): the notices of -the code and fonts that halo.wasm and the page carry, which their licences -ask copies to include, as the other builds' releases carry them -(tools/ci_build.py). +"""Writes the web site's licenses.txt (tools/web_build.py): OpenCE's licence, +and the notices of the code and fonts that halo.wasm and the page carry, +which their licences ask copies to include, as the other builds' releases +carry them (tools/ci_build.py). python port/web/licenses.py OUTPUT SDL3-LICENSE """ @@ -21,7 +21,6 @@ NOTICES = [ ("tomlc17 (config.toml, mod.toml, load_order.toml)", "port/third_party/tomlc17/LICENSE"), ("musl (the maths functions)", "port/third_party/musl-math/COPYRIGHT"), ("stb_vorbis (Custom Edition maps' and mods' sounds)", "port/third_party/stb_vorbis/LICENSE"), - ("extract-xiso (how the disc image is read)", "port/third_party/extract-xiso/LICENSE.TXT"), ("Overpass (the menus' text and the page's)", "port/assets/fonts/Overpass-OFL.txt"), ("OpenCE (the title font, from Newtown)", "port/assets/fonts/OpenCE-OFL.txt"), ("Newtown", "port/assets/fonts/Newtown-LICENSE.txt"), @@ -33,12 +32,17 @@ def main() -> None: output, sdl_license = Path(sys.argv[1]), Path(sys.argv[2]) parts = [ "OpenCE for the web\n\n" - "OpenCE's own code is CC0 (https://github.com/OpenCommunityEdition/OpenCE). The game data\n" - "comes from the player's own disc. It carries the following, under their licences:\n", + "OpenCE is free software under the GNU Affero General Public License, version 3 or (at\n" + "your option) any later version; its text is at the end of this file. Its source is at\n" + "https://github.com/OpenCommunityEdition/OpenCE, and each release's at its tag. The game\n" + "data comes from the player's own disc. OpenCE carries the following, under their\n" + "licences:\n", f"\n==================== SDL 3 (windows, input and audio)\n\n{sdl_license.read_text(encoding='utf-8')}", ] for title, path in NOTICES: parts.append(f"\n==================== {title}\n\n{(ROOT / path).read_text(encoding='utf-8')}") + parts.append(f"\n==================== OpenCE (GNU Affero General Public License)\n\n" + f"{(ROOT / 'LICENSE').read_text(encoding='utf-8')}") output.write_text("".join(parts), encoding="utf-8") diff --git a/port/web/site/xiso-worker.js b/port/web/site/xiso-worker.js index 4aaaa49f..49e973fe 100644 --- a/port/web/site/xiso-worker.js +++ b/port/web/site/xiso-worker.js @@ -1,211 +1,245 @@ /* XISO-WORKER.JS -Copies the game's maps folder into the site's Origin Private File System, -where the game finds it (/data/maps: port/web/src/web_main.c), from the -player's own Xbox disc image of Halo: Combat Evolved (an "xiso", .iso), as -port/linux/src/xiso.c does for the desktop ports, or from a maps folder -already copied out of one. It runs in a Worker, which can write with -synchronous OPFS access handles (Safari has no OPFS writable streams), and -reads the image a slice at a time: an image is 4 to 7 GB, and nothing of it -is kept but the maps. +Copies the game data into the site's Origin Private File System, where the +game reads it (/data/maps: port/web/src/web_main.c): the maps folder of the +player's Xbox disc image of Halo: Combat Evolved, or the files of a maps +folder the player chose. It runs in a Worker, which can write with +synchronous OPFS access handles (Safari has no OPFS writable streams). Only +the maps and loading.tga are kept, and each map's header is checked as the +game checks it, so that a disc the game cannot play is refused here. -The image's file system is XDVDFS, read as extract-xiso does -(port/third_party/extract-xiso): 2048-byte sectors; a volume descriptor at -0x10000 that starts and ends with "MICROSOFT*XBOX*MEDIA" and gives the root -directory's sector and size; directories whose entries form a binary tree -(left and right subtree offsets in 4-byte units, the start sector, the size, -attributes, the name's length and the name). Images of a whole disc put the -game partition further in, at one of PARTITION_OFFSETS. The image is the -player's file, so it is untrusted: every offset and size is checked against -the image and the directory it is read from, and a directory's walk is -bounded. +Written from a description of the Xbox's disc file system, XDVDFS +(xboxdevwiki's XDVDFS page, https://xboxdevwiki.net/XDVDFS, and the format +facts OpenCE's readers rely on). What this file relies on: -Each map is checked as the game checks it when it loads it (cache_files.c): -"head" and "foot" signatures, the Xbox's cache version, and the build of a -retail disc (01.10.12.2276) or of this decompilation's (01.01.14.2342). +- Sectors are 2048 bytes and integers little-endian. Sector numbers count + from the start of the game partition: an image of the partition alone has + it at 0, an image of a whole disc further in (0x0FD90000, 0x02080000 or + 0x18300000 for XGD2, XGD3 and XGD1 discs). They are tried in that order. +- The volume descriptor is the partition's sector 32 (at 0x10000). It holds + "MICROSOFT*XBOX*MEDIA" at its start and again at 0x7EC, and the root + directory table's start sector (u32 at 0x14) and size in bytes (u32 at + 0x18). +- A directory table is a binary tree of entries whose root is the entry at + offset 0. An entry is a left and a right subtree link (u16 each, in 4-byte + units from the table's start, 0 for none), the start sector and the size + of the file or of the subdirectory's table (u32 each), the attributes (u8, + 0x10 for a directory), the name's length (u8) and the name. Unused bytes of + a table are 0xFF, so a left link of 0xFFFF is padding, not an entry. +- A file is one contiguous run of bytes from the start of its sector. -Messages from the page: { type: 'image', file } or { type: 'folder', files } -(a maps folder's File objects). To the page: { type: 'progress', file, done, -total }, then { type: 'done', files, bytes } or { type: 'error', message }. +The image is the player's file (4 to 7 GB) and nothing read from it is +trusted: it is read a slice at a time, only the root's table and the maps +folder's (each at most 1 MB), and the walk of a table visits each offset +once, goes at most 64 links deep and looks at most 4096 entries. + +Messages from the page: { type: 'image', file } (the disc image) or +{ type: 'folder', files } (a chosen folder's File objects). To the page: +{ type: 'progress', file, done, total }, then { type: 'done', files, bytes } +or { type: 'error', message }. A new copy first removes the old maps folder +and writes maps/.complete ({"files":[...],"bytes":n}) last: the page takes +the data as ready only once that marker is there. */ 'use strict'; const SECTOR_SIZE = 2048; -const VOLUME_DESCRIPTOR_OFFSET = 0x10000; -const PARTITION_OFFSETS = [0, 0x0FD90000, 0x02080000, 0x18300000]; +const DESCRIPTOR_OFFSET = 0x10000; const MAGIC = 'MICROSOFT*XBOX*MEDIA'; -const ENTRY_HEADER_SIZE = 14; +const SECOND_MAGIC_OFFSET = 0x7EC; +const ENTRY_FIXED_SIZE = 14; const ATTRIBUTE_DIRECTORY = 0x10; -const MAXIMUM_DIRECTORY_SIZE = 1024 * 1024; -const MAXIMUM_ENTRIES = 4096; +const PADDING_LINK = 0xFFFF; +// where the game partition may start, in the order they are tried: an image +// of the partition alone, then whole XGD2, XGD3 and XGD1 discs +const PARTITION_STARTS = [0x00000000, 0x0FD90000, 0x02080000, 0x18300000]; +// directory tables are a few sectors; anything much larger is not one +const MAXIMUM_TABLE_SIZE = 1024 * 1024; const MAXIMUM_DEPTH = 64; -const COPY_CHUNK = 4 * 1024 * 1024; +const MAXIMUM_ENTRIES = 4096; const MAP_HEADER_SIZE = 0x800; -const CACHE_VERSION = 5; -const BUILDS = ['01.10.12.2276', '01.01.14.2342']; -// written last: the page starts the game only when it is there -const COMPLETE_MARKER = '.complete'; +const MAP_BUILDS = ['01.10.12.2276', '01.01.14.2342']; +const COPY_CHUNK = 4 * 1024 * 1024; -async function readAt(file, offset, size) { - const end = Math.min(offset + size, file.size); - if (offset < 0 || offset >= end) return new Uint8Array(0); - return new Uint8Array(await file.slice(offset, end).arrayBuffer()); +// ---------- names + +function asciiLower(text) { + return text.replace(/[A-Z]/g, (letter) => String.fromCharCode(letter.charCodeAt(0) + 32)); } -function text(bytes, start, length) { - let result = ''; - for (let i = 0; i < length; i++) result += String.fromCharCode(bytes[start + i]); - return result; +function sameName(a, b) { + return asciiLower(a) === asciiLower(b); } -function u16(bytes, at) { - return bytes[at] | bytes[at + 1] << 8; +// A name a file of the maps folder may have: no path, nothing hidden. +function plainName(name) { + return typeof name === 'string' && /^[A-Za-z0-9_. -]{1,64}$/.test(name) && !name.startsWith('.'); } -function u32(bytes, at) { - return (bytes[at] | bytes[at + 1] << 8 | bytes[at + 2] << 16 | bytes[at + 3] << 24) >>> 0; +function latin1(bytes) { + let text = ''; + for (const byte of bytes) text += String.fromCharCode(byte); + return text; } +// ---------- the image + +async function readBytes(file, start, end) { + return new Uint8Array(await file.slice(start, end).arrayBuffer()); +} + +// The game partition: { partition, rootSector, rootSize }, from the first +// start whose volume descriptor has both magics; null if none has. async function findVolume(file) { - for (const partition of PARTITION_OFFSETS) { - const descriptor = await readAt(file, partition + VOLUME_DESCRIPTOR_OFFSET, SECTOR_SIZE); - if (descriptor.length < SECTOR_SIZE) continue; - if (text(descriptor, 0, 20) === MAGIC && text(descriptor, 0x7EC, 20) === MAGIC) { - return { partition, rootSector: u32(descriptor, 20), rootSize: u32(descriptor, 24) }; + for (const partition of PARTITION_STARTS) { + const start = partition + DESCRIPTOR_OFFSET; + if (start + SECTOR_SIZE > file.size) continue; + const descriptor = await readBytes(file, start, start + SECTOR_SIZE); + if (descriptor.length !== SECTOR_SIZE) continue; + if (latin1(descriptor.subarray(0, MAGIC.length)) !== MAGIC || + latin1(descriptor.subarray(SECOND_MAGIC_OFFSET, SECOND_MAGIC_OFFSET + MAGIC.length)) !== MAGIC) { + continue; } + const view = new DataView(descriptor.buffer, descriptor.byteOffset, descriptor.byteLength); + return { partition, rootSector: view.getUint32(0x14, true), rootSize: view.getUint32(0x18, true) }; } return null; } -// a name a file of the maps folder may have: no path, nothing hidden -function plainName(name) { - return name.length > 0 && name.length <= 64 && /^[A-Za-z0-9_.\- ]+$/.test(name) && !name.startsWith('.'); -} - -// the entries of a directory table: { name, sector, size, directory } +// A directory table's entries, { name, sector, size, directory }, for every +// entry that has a name, in the tree's order (left subtree, the entry, right +// subtree). A link to padding, past the table or to an offset already +// visited ends that branch. function walkDirectory(table) { + const view = new DataView(table.buffer, table.byteOffset, table.byteLength); + const visited = new Set(); const entries = []; - const seen = new Set(); const walk = (offset, depth) => { - offset *= 4; - // (a cycle, a tree too deep or too wide, or an entry past the table: - // what is left of it is ignored) - if (depth > MAXIMUM_DEPTH || seen.has(offset) || seen.size >= MAXIMUM_ENTRIES || - offset + ENTRY_HEADER_SIZE > table.length) { - return; - } - seen.add(offset); - const left = u16(table, offset); - const right = u16(table, offset + 2); - // (padding at the end of a sector) - if (left === 0xFFFF) return; + if (depth > MAXIMUM_DEPTH || offset + ENTRY_FIXED_SIZE > table.length) return; + const left = view.getUint16(offset, true); + const right = view.getUint16(offset + 2, true); + if (left === PADDING_LINK || visited.has(offset) || visited.size >= MAXIMUM_ENTRIES) return; + visited.add(offset); + if (left) walk(left * 4, depth + 1); const nameLength = table[offset + 13]; - if (left) walk(left, depth + 1); - if (nameLength > 0 && offset + ENTRY_HEADER_SIZE + nameLength <= table.length) { + const nameStart = offset + ENTRY_FIXED_SIZE; + if (nameLength && nameStart + nameLength <= table.length) { entries.push({ - name: text(table, offset + ENTRY_HEADER_SIZE, nameLength), - sector: u32(table, offset + 4), - size: u32(table, offset + 8), + name: latin1(table.subarray(nameStart, nameStart + nameLength)), + sector: view.getUint32(offset + 4, true), + size: view.getUint32(offset + 8, true), directory: (table[offset + 12] & ATTRIBUTE_DIRECTORY) !== 0, }); } - if (right) walk(right, depth + 1); + if (right) walk(right * 4, depth + 1); }; walk(0, 0); return entries; } -async function readDirectory(file, volume, sector, size) { - if (!size || size > MAXIMUM_DIRECTORY_SIZE) return null; - const offset = volume.partition + sector * SECTOR_SIZE; - if (offset + size > file.size) return null; - const table = await readAt(file, offset, size); - return table.length === size ? table : null; +async function readTable(file, partition, sector, size, message) { + const start = partition + sector * SECTOR_SIZE; + if (size === 0 || size > MAXIMUM_TABLE_SIZE || start + size > file.size) throw new Error(message); + const table = await readBytes(file, start, start + size); + if (table.length !== size) throw new Error(message); + return table; } -// why a map's header is not one the game loads, or null +// ---------- the maps + +// Why the game would not load a map whose first bytes are header, or null. function mapProblem(header) { if (header.length < MAP_HEADER_SIZE) return 'it is too short'; - if (text(header, 0, 4) !== 'daeh' || text(header, 0x7FC, 4) !== 'toof') return 'it is not a map'; - if (u32(header, 4) !== CACHE_VERSION) return 'it is not an Xbox map (its cache version is ' + u32(header, 4) + ')'; - const build = text(header, 0x40, 32).replace(/\0.*$/s, ''); - if (!BUILDS.includes(build)) return 'its build, ' + JSON.stringify(build) + ', is not one the game loads'; + if (latin1(header.subarray(0, 4)) !== 'daeh' || latin1(header.subarray(0x7FC, 0x800)) !== 'toof') { + return 'it is not a map'; + } + const view = new DataView(header.buffer, header.byteOffset, header.byteLength); + const version = view.getUint32(4, true); + if (version !== 5) return `it is not an Xbox map (its cache version is ${version})`; + const field = header.subarray(0x40, 0x60); + const end = field.indexOf(0); + const build = latin1(end >= 0 ? field.subarray(0, end) : field); + if (!MAP_BUILDS.includes(build)) return `its build, ${JSON.stringify(build)}, is not one the game loads`; return null; } -// the files to copy, each { name, size, read(offset, size) }; the maps are -// checked, other files (loading.tga) copied as they are +// The files to copy, of those given ({ name, size, read }): the maps (each +// checked) and loading.tga, under plain names, the first of names that +// differ only in case; throws why they cannot be used. async function checkedFiles(candidates) { - const files = []; + const kept = []; for (const candidate of candidates) { - const lower = candidate.name.toLowerCase(); if (!plainName(candidate.name)) continue; + if (kept.some((file) => sameName(file.name, candidate.name))) continue; + const lower = asciiLower(candidate.name); if (lower.endsWith('.map')) { const problem = mapProblem(await candidate.read(0, MAP_HEADER_SIZE)); if (problem) throw new Error(`${candidate.name} cannot be used: ${problem}.`); - files.push(candidate); + kept.push(candidate); } else if (lower === 'loading.tga') { - files.push(candidate); + kept.push(candidate); } } - if (!files.some((file) => file.name.toLowerCase() === 'ui.map')) { + if (!kept.some((file) => sameName(file.name, 'ui.map'))) { throw new Error('There is no ui.map among the maps: this is not Halo: Combat Evolved for the Xbox.'); } - return files; + return kept; } +// The maps folder's files in a disc image, as { name, size, read(offset, +// size) }; throws why it cannot be used. async function imageFiles(file) { const volume = await findVolume(file); if (!volume) throw new Error('This file is not an Xbox disc image (no XDVDFS volume was found).'); - const root = await readDirectory(file, volume, volume.rootSector, volume.rootSize); - if (!root) throw new Error("The disc image's file system is damaged."); - const maps = walkDirectory(root).find((entry) => entry.directory && entry.name.toLowerCase() === 'maps'); + const { partition } = volume; + const root = await readTable(file, partition, volume.rootSector, volume.rootSize, + 'The disc image\'s file system is damaged.'); + const maps = walkDirectory(root).find((entry) => entry.directory && sameName(entry.name, 'maps')); if (!maps) throw new Error('The disc image has no maps folder: it is not a Halo disc.'); - const table = await readDirectory(file, volume, maps.sector, maps.size); - if (!table) throw new Error("The disc image's maps folder is damaged."); - return checkedFiles(walkDirectory(table).filter((entry) => !entry.directory).map((entry) => { - const offset = volume.partition + entry.sector * SECTOR_SIZE; - if (offset + entry.size > file.size) { + const table = await readTable(file, partition, maps.sector, maps.size, 'The disc image\'s maps folder is damaged.'); + const candidates = []; + for (const entry of walkDirectory(table)) { + if (entry.directory) continue; + const start = partition + entry.sector * SECTOR_SIZE; + // (an empty file's sector need not be anywhere) + if (entry.size && start + entry.size > file.size) { throw new Error(`The disc image ends before ${entry.name} does: is it complete?`); } - return { name: entry.name, size: entry.size, read: (at, size) => readAt(file, offset + at, Math.min(size, entry.size - at)) }; - })); + candidates.push({ + name: entry.name, + size: entry.size, + read: (offset, size) => { + const count = Math.max(0, Math.min(size, entry.size - offset)); + return readBytes(file, Math.min(start + offset, file.size), Math.min(start + offset + count, file.size)); + }, + }); + } + return checkedFiles(candidates); } +// The same, from the files of a chosen folder. async function folderFiles(list) { - return checkedFiles(list.map((file) => ({ name: file.name, size: file.size, read: (at, size) => readAt(file, at, size) }))); + return checkedFiles(list.map((file) => ({ + name: file.name, + size: file.size, + read: (offset, size) => readBytes(file, offset, offset + size), + }))); } -async function writeFile(directory, source, onChunk) { - const handle = await directory.getFileHandle(source.name, { create: true }); - const access = await handle.createSyncAccessHandle(); - try { - access.truncate(0); - let position = 0; - while (position < source.size) { - const count = Math.min(COPY_CHUNK, source.size - position); - const bytes = await source.read(position, count); - if (bytes.length !== count) throw new Error(`Could not read ${source.name} (is the file complete?).`); - let written = 0; - while (written < count) { - const result = access.write(bytes.subarray(written), { at: position + written }); - if (!result) throw new Error(`Could not write ${source.name}: is the device full?`); - written += result; - } - position += count; - onChunk(count); - } - access.flush(); - } finally { - access.close(); +// ---------- the copy + +function writeAll(access, bytes, position, name) { + let written = 0; + while (written < bytes.length) { + const result = access.write(bytes.subarray(written), { at: position + written }); + if (!result) throw new Error(`Could not write ${name}: is the device full?`); + written += result; } } async function copy(files) { - const total = files.reduce((sum, entry) => sum + entry.size, 0); - const storage = await navigator.storage.getDirectory(); + const total = files.reduce((sum, file) => sum + file.size, 0); if (navigator.storage.estimate) { const { quota, usage } = await navigator.storage.estimate(); if (quota && quota - usage < total) { @@ -213,34 +247,54 @@ async function copy(files) { `and the maps take ${Math.ceil(total / 1e6)} MB.`); } } - // a new copy replaces whatever an earlier, perhaps interrupted, one left + const storage = await navigator.storage.getDirectory(); + // (a new copy replaces whatever an earlier, perhaps interrupted, one left) await storage.removeEntry('maps', { recursive: true }).catch(() => {}); - const directory = await storage.getDirectoryHandle('maps', { create: true }); + const maps = await storage.getDirectoryHandle('maps', { create: true }); let done = 0; let lastReport = 0; - for (const entry of files) { - await writeFile(directory, entry, (count) => { - done += count; - const now = Date.now(); - if (now - lastReport > 100 || done === total) { - lastReport = now; - postMessage({ type: 'progress', file: entry.name, done, total }); + for (const file of files) { + const handle = await maps.getFileHandle(file.name, { create: true }); + const access = await handle.createSyncAccessHandle(); + try { + access.truncate(0); + let position = 0; + while (position < file.size) { + const count = Math.min(COPY_CHUNK, file.size - position); + const bytes = await file.read(position, count); + if (bytes.length < count) throw new Error(`Could not read ${file.name} (is the file complete?).`); + writeAll(access, bytes.subarray(0, count), position, file.name); + position += count; + done += count; + const now = Date.now(); + if (now - lastReport > 100 || done === total) { + lastReport = now; + postMessage({ type: 'progress', file: file.name, done, total }); + } } - }); + access.flush(); + } finally { + access.close(); + } + } + // last: the sign that the copy is complete + const marker = await (await maps.getFileHandle('.complete', { create: true })).createSyncAccessHandle(); + try { + marker.truncate(0); + const text = new TextEncoder().encode(JSON.stringify({ files: files.map((file) => file.name), bytes: total })); + writeAll(marker, text, 0, '.complete'); + marker.flush(); + } finally { + marker.close(); } - const marker = await directory.getFileHandle(COMPLETE_MARKER, { create: true }); - const access = await marker.createSyncAccessHandle(); - access.truncate(0); - access.write(new TextEncoder().encode(JSON.stringify({ files: files.map((f) => f.name), bytes: total })), { at: 0 }); - access.flush(); - access.close(); return { files: files.length, bytes: total }; } if (typeof onmessage !== 'undefined' || typeof WorkerGlobalScope !== 'undefined') { onmessage = async (event) => { try { - const files = event.data.type === 'folder' ? await folderFiles(event.data.files) : await imageFiles(event.data.file); + const message = event.data; + const files = message.type === 'folder' ? await folderFiles(message.files) : await imageFiles(message.file); postMessage({ type: 'done', ...(await copy(files)) }); } catch (error) { postMessage({ type: 'error', message: error && error.message ? error.message : String(error) }); diff --git a/tools/ci_build.py b/tools/ci_build.py index a0f6335f..76f92cdd 100644 --- a/tools/ci_build.py +++ b/tools/ci_build.py @@ -117,10 +117,8 @@ def main() -> int: for pdb in [ROOT / "build/windows/halo.pdb", *sorted((ROOT / "build/windows/third_party").glob("SDL3-*/lib/x86/SDL3.pdb"))]: shutil.copy2(pdb, symbols) print(f"{pdb.relative_to(ROOT)} -> {symbols.relative_to(ROOT)}", flush=True) - # the disc image readers (port/linux/src/xiso.c, and the Android app's - # XisoExtractor.java) follow extract-xiso, whose license asks binaries - # to carry its notice - shutil.copy2(ROOT / "port/third_party/extract-xiso/LICENSE.TXT", dist / "extract-xiso-LICENSE.txt") + # OpenCE's own licence, the AGPL, which asks each copy to carry its text + shutil.copy2(ROOT / "LICENSE", dist / "LICENSE.txt") if args.platform != "web": # internet play's DTLS with browsers, and the Linux self-updater's TLS # (port/third_party/mbedtls), whose Apache license asks the same diff --git a/tools/web_build.py b/tools/web_build.py index fa166ffe..677fdeea 100644 --- a/tools/web_build.py +++ b/tools/web_build.py @@ -366,7 +366,7 @@ def generate_web_build(n: Writer, sln: Any) -> None: command=f"$python {PORT_DIR}/licenses.py $out {sdl_license}", description="WEB LICENSES $out", ) - n.build(outputs=licenses, rule="web_licenses", implicit=[PORT_DIR / "licenses.py", sdl_license]) + n.build(outputs=licenses, rule="web_licenses", implicit=[PORT_DIR / "licenses.py", Path("LICENSE"), sdl_license]) site_files.append(licenses) n.rule( name="web_version",