hud: match lifecycle and teammate rendering

This commit is contained in:
Jonas Volman committed 2026-09-01 23:39:10 -07:00
1 parent f101b2fc36
commit 226bdaefad
12 files changed
+428 -63

No files matched your search

-19
View File
@@ -913,25 +913,6 @@
"objdiff_percent": 99.934784
}
},
{
"unit": "source/bitmaps/bitmap_utilities",
"function": "_bitmap_2d_uncompress_from_mipmap",
"class": "instruction-scheduling",
"evidence": "Fuzzy-parked under the current house rule after retaining the correct DXT3 alpha4 block type and DecodeBlockAlpha4 owner-header prototype. HCEA commit 570c83fd9c365dad6f2a3e7041705d5b84c7847c corroborates the 2D decompression topology and semantic private name. Target and candidate have the same 880-byte padded envelope, 297 aligned instructions, and all 49 relocation identities. The only normalized difference is the order of two independent final-loop reloads at +0x33A/+0x33D: January reloads the cached height into EDI before source_mipmap_index into EBX, while VC7 emits the reverse order. A bounded diagnostic confirmed that the donor's erroneous DXT3 alpha3 cast/sizeof spelling does not control this tie; it was rejected in favor of the canonical alpha4 definition. No wrong type, volatile access, barrier, fake dependency, assembly, undefined behavior, or exact-only control flow is retained. Reopen only for authoritative January source/local records or a natural same-compiler scheduling donor.",
"measurements": {
"target": {
"size": 880,
"relocation_count": 49,
"normalized_sha256": "4f4b53aed0db63a496b4c239249e9adaaa70adee056f6e6bc6118dc30dc2b4ab"
},
"base": {
"size": 880,
"relocation_count": 49,
"normalized_sha256": "0d0264895ee68a288dde6eb4dcbd425500971c01ba59158e1fe21ea4f05b456c"
},
"objdiff_percent": 99.922264
}
},
{
"unit": "source/render/render_particles",
"function": "_render_particles",
+3 -3
View File
@@ -3326,8 +3326,8 @@
{ "file_offset": 786464, "flags": 32, "name": "_code_000c0020" },
{ "file_offset": 786672, "flags": 32, "name": "_hud_load" },
{ "file_offset": 786768, "flags": 32, "name": "_hud_autosave" },
{ "file_offset": 786992, "flags": 32, "name": "_code_000c0230" },
{ "file_offset": 787344, "flags": 32, "name": "_code_000c0390" },
{ "file_offset": 786992, "flags": 32, "name": "_hud_draw_friendly_indicator", "static": true },
{ "file_offset": 787344, "flags": 32, "name": "_hud_draw_players" },
{ "file_offset": 787504, "flags": 32, "name": "_code_000c0430" },
{ "file_offset": 788384, "flags": 32, "name": "_hud_draw_screen" },
{ "file_offset": 788704, "flags": 32, "name": "_get_return_eip" },
@@ -22040,7 +22040,7 @@
{ "file_offset": 3033952, "flags": 0, "name": "_hs_source_files_block" },
{ "file_offset": 3034132, "flags": 0, "name": "_hs_syntax_data_definition" },
{ "file_offset": 3034148, "flags": 0, "name": "_hs_string_data_definition" },
{ "file_offset": 3034164, "flags": 0, "name": "_data_002e4c34" },
{ "file_offset": 3034164, "flags": 0, "name": "_default_string" },
{ "file_offset": 3034168, "flags": 0, "name": "_global_hud_anchor_names" },
{ "file_offset": 3034188, "flags": 0, "name": "_button_mappings", "static": true },
{ "file_offset": 3034204, "flags": 0, "name": "_time_code_time" },
@@ -0,0 +1,111 @@
# `hud.obj` small-family exact closeout (2026-09-01)
This pass reconstructs six previously unwritten HUD functions as ordinary,
typed source and makes all six strict COFF matches. `hud.obj` advances from
10/22 to 16/22 exact functions, from 448 to 1,488 strict padded code bytes,
and retains every inherited exact function. No HUD function is parked.
## Authority and provenance
- Integration base: `9db5116bd94114dc7a315cd181b944fdf587b3c9`.
- Fresh park-metric correction in the isolated lane:
`bcddc674659d394d7c45474ee14c56db412e1eb0`.
- January target `hud.obj` SHA-256:
`fe352130fe6a915c706e634f7c8e1bc7fc268a7eaa1094ede0549c27ae88756f`.
- Candidate `hud.obj` SHA-256:
`989de9ad2321625af53756f97758b32451b40391cd56a9365595d7298a311f7b`.
- Compiler: the pinned Microsoft VC7/XDK compiler through the normal Ninja
edge and PID-isolated `tools/campaign/gate.py` checks.
- Primary semantic donor: HCEA commit
`570c83fd9c365dad6f2a3e7041705d5b84c7847c`, especially
`hud_initialize_for_new_map.c`, `hud_get_item_string.c`, `hud_load.c`,
`hud_autosave.c`, `hud_draw_friendly_indicator.c`, and
`hud_draw_players.c`.
- Independent control-flow corroboration: Stian Halo commit
`fc11d861865735877d5b8b4c408b1a0c06dde3cf`, whose HUD reconstruction
preserves the natural `hud_get_item_string` call inside `hud_autosave`.
- Marathon commit `ce4fdc63f20f6fa39616a86e717118f4d8bdf25c`
was reviewed for contemporary C-series style and conversion idioms. It has
no direct Halo HUD donor.
All registered local branches/worktrees and the Pastudan, PUNPCKHDQ, HCEA,
and Stian trees were searched before implementation. No more-complete exact
HUD source existed locally. The PUNPCKHDQ HUD file remained the older
skeleton; Pastudan and Stian supplied compatible semantic/address evidence,
not a January build artifact.
## Strict result
| Function | Meaningful bytes | Padded bytes | Relocations | Normalized SHA-256 |
| --- | ---: | ---: | ---: | --- |
| `_hud_initialize_for_new_map` | 119 | 128 | 16 | `738d39e24d9f747b2bfdfd4fb8a9069d1149aecd62eec283d6d088b2fa0d7522` |
| `_hud_get_item_string` | 76 | 80 | 4 | `88279655b02010490e2b9306363a215576b892ae68d6f74deba1c6aadea198fa` |
| `_hud_load` | 84 | 96 | 6 | `8ee25cd45250028e76624da1cf4ca7117f17a8dcb1aa83b4a420e3bd31fd8fe6` |
| `_hud_autosave` | 213 | 224 | 11 | `88e97440a0d4627444bfe405793d4b3bf9df676a446f4396e454972baf31a25b` |
| `_hud_draw_friendly_indicator` | 337 | 352 | 26 | `eca01cb04a23898537bd12e78268cc6c94369cf999adf333915e04eb6ac2d010` |
| `_hud_draw_players` | 149 | 160 | 9 | `9077b15c4b4a6b8b1b2f4940f890f5aaa39de4aad230fd15c23cc987c9d2629d` |
| **Total** | **978** | **1,040** | **72** | |
The owned four-byte `_default_string` data section is also exact, including
its single relocation to the compiler-owned empty wide-string literal. The
previous address-derived `_data_002e4c34` name is replaced with the
HCEA-authenticated semantic name.
## Source reconstruction
The lifecycle path uses the real `hud_globals_definition` field offsets,
typed `hud_globals_definition_get` and Unicode-list access macros, named
interface enums, and owner-header subsystem prototypes. The exact assertion
uses January's attested expression spelling and line number. `hud_load` and
`hud_autosave` select the named loading/checkpoint fields and use the normal
local-player APIs.
`hud_get_item_string` initializes a semantic fallback pointer and replaces it
only after a valid typed Unicode-list lookup. This is the coherent source
shape that explains January's EDI fallback lifetime; it is not a synthetic
register carrier. `hud_autosave` calls that helper normally. VC7 performs the
same natural inline expansion present in January, preserving the intended TU
inline schedule without a forced-inline directive.
The teammate-marker pair uses `player_get`, `data_iterator`, `render` camera
and frustum fields, the named multiplayer-HUD interface tag, the bitmap and
texture-cache APIs, project `real`/point/rectangle types, and `PIN`. The two
screen-coordinate conversions use the existing `fast_ftol` C-series helper,
which is the target-supported sparse math-assembly boundary. The private
helper is named `hud_draw_friendly_indicator`, marked static, and naturally
receives its argument in EAX; its public caller is `hud_draw_players`.
The shared camera projection declaration is isolated in
`render/render_camera_projection.h`. Putting it in the widely included camera
structure header moved the already-exact `render_sky` allocator schedule, so
the narrow owner header preserves both correct prototype ownership and the
January declaration schedule in unrelated translation units.
## Natural adjacent exact gain
Placing the missing `bitmap_group_get_bitmap_from_sequence` declaration in
its real owner header naturally resolves the final independent-reload order in
`bitmap_utilities.obj::_bitmap_2d_uncompress_from_mipmap`. That function is
now strict exact at 866 meaningful / 880 padded bytes with all 49 relocation
identities and normalized hash
`4f4b53aed0db63a496b4c239249e9adaaa70adee056f6e6bc6118dc30dc2b4ab`.
Its obsolete park entry is removed. This is a semantic header correction, not
an optimizer-only source variation.
## Validation
- Focused gate: `hud.obj` 16 exact / 0 residual / 6 unwritten.
- Focused bitmap gate: `_bitmap_2d_uncompress_from_mipmap` exact.
- Whole-tree verdict replay against the pre-pass build: seven gains and zero
exact-function regressions.
- Full `ninja`: pass; semantic report has zero unit errors.
- `python -m pytest -q`: 255 passed.
- Park validator: 77 active / 0 stale / 0 invalid.
- Strict board after the pass: 278/619 complete objects,
717,027/1,922,413 padded bytes, and 5,020/8,245 functions.
The six remaining HUD functions are still unwritten:
`_code_000bf660` (48 padded bytes), `_code_000bf840` (48),
`_code_000bf870` (1,744), `_code_000c0020` (208),
`_code_000c0430` (880), and `_hud_draw_screen` (320). They total 3,248
padded bytes and were left fail-closed for a later coherent cluster pass.
+6 -1
View File
@@ -72,7 +72,12 @@ struct bitmap_group
struct tag_block bitmap_data;
};
/* ---------- prototypes/EXAMPLE.C */
/* ---------- prototypes/BITMAP_GROUP.C */
struct bitmap_data *bitmap_group_get_bitmap_from_sequence(
long bitmap_group_index,
short sequence_index,
short frame_index);
/* ---------- globals */
+223 -32
View File
@@ -39,9 +39,9 @@ symbols in this file:
000C0150 00e0:
_hud_autosave (0000)
000C0230 0160:
_code_000c0230 (0000)
_hud_draw_friendly_indicator (0000)
000C0390 00a0:
_code_000c0390 (0000)
_hud_draw_players (0000)
000C0430 0370:
_code_000c0430 (0000)
000C07A0 0140:
@@ -67,7 +67,7 @@ symbols in this file:
0026FD18 001a:
??_C@_0BK@NJIPBDGF@?$CFs?5?$CIpress?5WHITE?5to?5use?$CJ?$HMn?$AA@ (0000)
002E4C34 0004:
_data_002e4c34 (0000)
_default_string (0000)
00453AAC 0008:
_hud_globals (0000)
_hud_scripted_globals (0004)
@@ -76,19 +76,32 @@ symbols in this file:
/* ---------- headers */
#include "cseries/cseries.h"
#include "bitmaps/bitmap_group.h"
#include "cache/texture_cache.h"
#include "game/game_engine.h"
#include "game/players.h"
#include "interface/hud.h"
#include "interface/hud_messaging.h"
#include "interface/hud_unit.h"
#include "interface/hud_weapon.h"
#include "interface/interface.h"
#include "interface/motion_sensor.h"
#include "memory/data.h"
#include "objects/objects.h"
#include "render/render.h"
#include "render/render_camera_projection.h"
#include "saved games/game_state.h"
#include "sound/game_sound.h"
#include "text/text_group.h"
#include "units/units.h"
/* ---------- constants */
/* ---------- macros */
#define hud_globals_definition_get(index) \
((struct hud_globals_definition *)tag_get('hudg', (index)))
/* ---------- structures */
struct hud_scripted_globals
@@ -98,46 +111,38 @@ struct hud_scripted_globals
byte reserved2[2];
};
struct hud_globals_definition
{
byte reserved000[0x94];
struct tag_reference hud_item_messages;
byte reserved0A4[0x334];
short loading_begin_index;
short loading_end_index;
short checkpoint_begin_index;
short checkpoint_end_index;
struct tag_reference checkpoint_sound;
};
typedef char hud_scripted_globals_size_assert[
sizeof(struct hud_scripted_globals) == 0x4 ? 1 : -1];
typedef char hud_scripted_globals_show_hud_help_text_offset_assert[
offsetof(struct hud_scripted_globals, show_hud_help_text) == 0x1 ? 1 : -1];
typedef char hud_globals_hud_item_messages_index_offset_assert[
offsetof(struct hud_globals_definition, hud_item_messages.index) == 0xA0 ? 1 : -1];
typedef char hud_globals_loading_begin_index_offset_assert[
offsetof(struct hud_globals_definition, loading_begin_index) == 0x3D8 ? 1 : -1];
typedef char hud_globals_checkpoint_sound_index_offset_assert[
offsetof(struct hud_globals_definition, checkpoint_sound.index) == 0x3EC ? 1 : -1];
/* ---------- prototypes */
void hud_dispose_nav_points_from_old_map(
void);
void hud_dispose_nav_points(
void);
void hud_messaging_initialize(
void);
void hud_initialize_unit_interface(
void);
void hud_initialize_weapon_interface(
void);
void hud_initialize_nav_points(
void);
void hud_update_weapon(
void);
void hud_update_unit(
void);
void hud_update_nav_points(
void);
void hud_messaging_globals_update(
void);
void hud_play_unit_sounds(
struct player_datum const *player,
boolean show_hud);
void hud_add_item_message(
short local_player_index,
long item_definition_index,
short quantity,
char message_offset);
/* ---------- globals */
extern struct hud_globals_definition *hud_globals;
extern struct hud_scripted_globals *hud_scripted_globals;
wchar_t const *default_string = L"";
/* ---------- public code */
void hud_initialize(
@@ -170,6 +175,25 @@ void hud_dispose(
return;
}
void hud_initialize_for_new_map(
void)
{
csmemset(hud_scripted_globals, 0, sizeof(*hud_scripted_globals));
hud_scripted_globals->show_hud = TRUE;
match_assert(
"c:\\halo\\SOURCE\\interface\\hud.c",
113,
interface_get_tag_index(_interface_hud_globals)!=NONE);
hud_globals = hud_globals_definition_get(
interface_get_tag_index(_interface_hud_globals));
hud_messaging_initialize_for_new_map();
hud_initialize_unit_interface_for_new_map();
hud_initialize_weapon_interface_for_new_map();
hud_initialize_nav_points_for_new_map();
motion_sensor_initialize_for_new_map();
return;
}
void hud_dispose_from_old_map(
void)
{
@@ -223,6 +247,27 @@ void hud_update(
return;
}
wchar_t const *hud_get_item_string(
long string_index)
{
long string_list_index = hud_globals->hud_item_messages.index;
wchar_t const *string = default_string;
if (string_list_index != NONE)
{
struct string_list const *string_list =
unicode_string_list_definition_get(string_list_index);
if (string_list && VALID_INDEX(string_index, string_list->strings.count))
{
string = unicode_string_list_get_string(
string_list_index,
(short)string_index);
}
}
return string;
}
void hud_picked_up_grenade(
short local_player_index,
long grenade_definition_index)
@@ -288,4 +333,150 @@ void hud_picked_up_powerup(
return;
}
void hud_load(
boolean load)
{
short string_index = load
? hud_globals->loading_begin_index
: hud_globals->loading_end_index;
scripted_hud_messages_clear();
if (string_index != NONE)
{
hud_print_message(
local_player_get_next(NONE),
hud_get_item_string(string_index));
}
return;
}
void hud_autosave(
boolean active)
{
short string_index = active
? hud_globals->checkpoint_begin_index
: hud_globals->checkpoint_end_index;
short local_player_index;
scripted_hud_messages_clear();
if (active && hud_globals->checkpoint_sound.index != NONE)
{
unspatialized_impulse_sound_new(
hud_globals->checkpoint_sound.index,
1.0f);
}
if (string_index != NONE)
{
for (local_player_index = 0;
local_player_index < MAXIMUM_LOCAL_PLAYERS;
local_player_index++)
{
if (local_player_get_player_index(local_player_index) != NONE)
{
hud_print_message(
local_player_index,
hud_get_item_string(string_index));
}
}
}
return;
}
static void hud_draw_friendly_indicator(
long player_index)
{
struct player_datum const *player = player_get(player_index);
real_point3d head_position;
real_point3d view_position;
real_point2d screen_position;
point2d position;
real_rectangle2d clip;
struct bitmap_data *bitmap;
real depth_factor;
real fade;
unit_get_head_position(
player->unit_index,
&head_position);
head_position.z += 0.30000001f;
matrix4x3_transform_point(
&render.frustum.world_to_view,
&head_position,
&view_position);
if (render_camera_view_to_screen(
&render.camera,
&render.frustum,
&view_position,
&screen_position))
{
bitmap = bitmap_group_get_bitmap_from_sequence(
interface_get_tag_index(_interface_bitmap_multiplayer_hud),
0,
0);
if (_texture_cache_bitmap_get_hardware_format(bitmap, FALSE, TRUE))
{
position.x =
(short)fast_ftol(screen_position.x) - render.camera.viewport_bounds.x0;
position.y =
(short)fast_ftol(screen_position.y) - render.camera.viewport_bounds.y0;
depth_factor = 1.0f -
((-view_position.z - render.frustum.z_near) * 100.0f) /
(render.frustum.z_far - render.frustum.z_near);
fade = PIN(depth_factor, 0.075000003f, 1.0f);
clip.x0 = 0.0f;
clip.x1 = 1.0f;
clip.y0 = (1.0f - fade) * 0.5f;
clip.y1 = 1.0f;
interface_draw_bitmap(
bitmap,
&position,
&clip,
1.0f,
0.0f,
1.0f);
}
}
return;
}
void hud_draw_players(
void)
{
long player_index = local_player_get_player_index(render.local_player_index);
long team_index = player_get(player_index)->team_index;
if (player_index != NONE)
{
long teammate_indices[16];
long teammate_count = 0;
struct data_iterator iterator;
struct player_datum *player;
long teammate_index;
data_iterator_new(&iterator, player_data);
while ((player = data_iterator_next(&iterator)) != NULL)
{
if (player_index != iterator.datum_index &&
team_index == player->team_index &&
player->unit_index != NONE)
{
teammate_indices[teammate_count++] = iterator.datum_index;
}
}
for (teammate_index = 0;
teammate_index < teammate_count;
teammate_index++)
{
hud_draw_friendly_indicator(teammate_indices[teammate_index]);
}
}
return;
}
/* ---------- private code */
+18
View File
@@ -16,10 +16,28 @@ header included in hcex build.
/* ---------- prototypes/HUD.C */
void hud_initialize_for_new_map(
void);
void hud_initialize_nav_points(
void);
void hud_initialize_nav_points_for_new_map(
void);
void hud_dispose_nav_points_from_old_map(
void);
void hud_dispose_nav_points(
void);
void hud_update_nav_points(
void);
wchar_t const *hud_get_item_string(
long string_index);
void hud_load(
boolean load);
void hud_autosave(
boolean active);
void hud_draw_players(
void);
void hud_picked_up_powerup(
short local_player_index,
+11
View File
@@ -16,10 +16,16 @@ header included in hcex build.
/* ---------- prototypes/HUD_MESSAGING.C */
void hud_messaging_initialize(
void);
void hud_messaging_initialize_for_new_map(
void);
void hud_messaging_dispose_from_old_map(
void);
void hud_messaging_dispose(
void);
void hud_messaging_globals_update(
void);
void scripted_hud_set_flashing_state(
boolean flash);
void scripted_hud_set_timer_position(
@@ -31,6 +37,11 @@ void scripted_hud_messages_clear(
void hud_print_message(
short local_player_index,
wchar_t const *message);
void hud_add_item_message(
short local_player_index,
long item_definition_index,
short quantity,
char message_offset);
/* ---------- globals */
+13
View File
@@ -2,6 +2,13 @@
#define __HUD_UNIT_H
#pragma once
struct player_datum;
void hud_initialize_unit_interface(
void);
void hud_initialize_unit_interface_for_new_map(
void);
void hud_dispose_unit_interface_from_old_map(
void);
void hud_dispose_unit_interface(
@@ -11,4 +18,10 @@ void hud_fix_unit_data(
short old_local_player_index,
short new_local_player_index);
void hud_update_unit(
void);
void hud_play_unit_sounds(
struct player_datum const *player,
boolean show_hud);
#endif // __HUD_UNIT_H
+8
View File
@@ -2,6 +2,11 @@
#define __HUD_WEAPON_H
#pragma once
void hud_initialize_weapon_interface(
void);
void hud_initialize_weapon_interface_for_new_map(
void);
void hud_dispose_weapon_interface_from_old_map(
void);
void hud_dispose_weapon_interface(
@@ -11,4 +16,7 @@ void hud_fix_weapon_data(
short old_local_player_index,
short new_local_player_index);
void hud_update_weapon(
void);
#endif // __HUD_WEAPON_H
+11
View File
@@ -35,9 +35,20 @@ enum
/* ---------- structures */
struct bitmap_data;
union point2d;
union real_rectangle2d;
/* ---------- prototypes/INTERFACE.C */
long interface_get_tag_index(short interface_tag_index);
void interface_draw_bitmap(
struct bitmap_data const *bitmap,
union point2d const *point,
union real_rectangle2d const *clip,
real scale,
real theta,
real fade);
/* ---------- globals */
+23
View File
@@ -0,0 +1,23 @@
/*
RENDER_CAMERA_PROJECTION.H
Narrow projection interface kept separate from the shared camera-structure
header so unrelated translation units retain their January declaration order.
*/
#ifndef __RENDER_CAMERA_PROJECTION_H
#define __RENDER_CAMERA_PROJECTION_H
#pragma once
struct render_camera;
struct render_frustum;
union real_point2d;
union real_point3d;
boolean render_camera_view_to_screen(
struct render_camera const *camera,
struct render_frustum const *frustum,
union real_point3d const *view_point,
union real_point2d *screen_point);
#endif // __RENDER_CAMERA_PROJECTION_H
+1 -8
View File
@@ -130,6 +130,7 @@ symbols in this file:
#include "cseries.h"
#include "render/render_cameras.h"
#include "render/render_camera_projection.h"
/* ---------- constants */
@@ -137,14 +138,6 @@ symbols in this file:
/* ---------- structures */
/* ---------- prototypes */
boolean render_camera_view_to_screen(
const struct render_camera *camera,
const struct render_frustum *frustum,
const real_point3d *view_point,
real_point2d *screen_point);
/* ---------- globals */
/* ---------- public code */