Add a profiling build: CPU recordings for Perfetto and a report tool
Conflicts resolved: CI runs main's tests and test_profile.py; the build
scripts take both main's opus and target flags and the PR's
configuration_defines; port_config.c keeps debug.memory_watch before the
profile settings; main.c and network_distributed.c keep voice chat, and
network_votekick_host_tick stays its own statement after the game state's
profile scope, not under its if.
render_fov.c, viewmodel_fov.c and viewmodel_visibility.c are one unit,
port/linux/game/view_fov.c, with a header comment as the others have, real
for float, _pi for its own pi, the rasterizer's target by name, and no
isfinite shim in math.h (the angles' range test already refuses NaN). The
game code's hooks are marked "port:", their include at the end of each
block, and rasterizer_lights.c's loops declare before they act (C89).
The first-person weapon's lens flares are not culled by the world's
frustum (main's new off-screen cull): they are
drawn at the weapon's own projection, which display.viewmodel_fov can make
wider than the world's.
HALO_VIEWMODEL_VIS is HALO_VIEWMODEL_VISIBLE; the settings' descriptions and
help lines say "stock" view and fit their boxes; Video Setup's XML is
written again by ce_menus.py; the README's field of view text is a section
of its own.
Split HALO_ANDROID into HALO_ARM64_GUEST, HALO_GLES and HALO_ANDROID
Conflict resolved: main's render-target eviction and mip composites are kept, with the PR's HALO_GLES guard on the ES blit fallback after them.
The raised limits' and the walk's comments are marked as the port's, with the unverified HAC2 and MCC comparison left out; the walk's says why the index is compared whole, and the once-only log of a frame reaching the limit gets a comment of its own.
The helpers' comment is marked as the port's and says plainly what the short holds; their definitions move to the file's private code, and the plane the item is moved onto is indented inside its new surface check.
The sleep's comment is marked as the port's and says what the spin cost (a core held busy, not system calls: the clock is read through the vDSO on Linux and Android), and the precache test the sleep no longer depends on is gone rather than cast to void.
The new helpers sat between widget_takes_events_of_controller's comment and the function, so the comment now heads it again; pc_menu_split_players is declared with the file's other port prototypes rather than as an extern among the functions, the players' count is read with players_port_local_player_count (safe before the players' globals are made), the comment names process_ui_widgets, and the test widget_takes_any_controller already makes is not made twice.
Halo PC reads a Custom Edition map's tags unchecked, so maps made for it
can hold an index past a block's end that never mattered there. OpenCE
already gives such an index the empty data and logs it, as it does for a
tag data's offset, but a debug build still stopped at the block's
assertions first (foundation@ce, 13 seconds in). With a Custom Edition map
loaded they are skipped, as tag_data_get_pointer's are; Xbox maps keep
their checks.
Only the assertions: OpenCE had the rest of the commit's change, made
another way (tag_empty_data).
(cherry picked from commit c953c65409ff9f3f230849bc6fc287727e3e3213)
The debug camera controls applied the height variable's hyper-scale
setting to every variable. Camera debugging only.
(cherry picked from commit 3db16e4499c7aa8ee9c82f28c3454009f877bccc)
(cherry picked from commit a5074861b2f9682e791adfd587c3a2b43e2f6daf)
The unit activation check compared the last vehicle's index where it
meant the time the unit left it, so it could report a false "unit
activation logic error" just after a vehicle exit. Messages only.
The actors.c line only; the commit's other fix, the movement point's y
printed as z, came with "Log and error messages print what their formats
ask for".
(cherry picked from commit e3089220a6bfa8479ba2e334a0070f97c97dd851)
The AI profiler's meters took the oldest sample out of their running sum
but never put the new one in, so their averages were wrong; the actor
line's units also lacked their tab and a separator.
The ai_profile.c fixes only, from a commit that is otherwise a rewording
of the AI code's comments.
(cherry picked from commit 95b838d13e276e41aa37f4646ce4acf5d18b8639)
Their attachment's movement was truncated to whole units before the
test, so it took two units of movement in one update, not one, to move
the vertices along with it. Visual only.
(cherry picked from commit 99c2db2d4da3d6d66b6ec28d459c756aeab55a64)
(cherry picked from commit eb0667bcc81ed1d970422c7856162e8aadff6fd7)
Three engine checks no longer stop the game on data Halo PC tolerated:
HUD sounds with no tag, dialogue variants with no dialogue, and non-model
shaders under camouflage (an environment shader on a first-person weapon:
not drawn while camouflaged rather than misread as a model shader).
These three only: OpenCE already had the commit's other repairs (protected
maps, node trees, scripts that fail to load, HUD meters and digits, object
functions, collision edges, weapon lists, more than 16 dialogue variants),
some made another way, and has no 64-bit build for its script stacks.
(cherry picked from commit d15b6ca913266b984966897e1be4e24c69a75b30)
A list whose focus reached its first or last row scrolled on and moved the
focus a row in; the pointer hovering that row took the focus back the next
frame it moved, so the list ran through everything and the row under the
pointer never stayed lit (the game types, the lobby, the internet lobby).
A list now scrolls on at its end only when the d-pad (keys, controller,
the wheel) put the focus there (ui_widget_port_pointer_focused).
(cherry picked from commit e74f5bbb541a480a72871adeb719472908607d12)
Particles of one kind are drawn together, at most 8 bitmaps' worth. A Halo
PC map's particle may have a bitmap a frame: beavercreek_rev_beta's fluid
bursts have up to 56. A debug build halted ("a build_sprites_begin call can
accomodate at most 8 bitmaps") when such particles were in view; a release
build drew the first 8 bitmaps' sprites and not the others. The builds that
play Halo PC's maps now do as a release build does in a debug build too, and
log it once. The Xbox's maps' particles stay within 8, and the Xbox build is
unchanged.
Without its #ifdef HALO_CUSTOM_EDITION, which OpenCE never defines (it
compiled to nothing): the log is for Custom Edition maps
(custom_edition_cache_tags_loaded), the assertion stays for the Xbox's.
(cherry picked from commit afa6413f1e922621cc04e7953e730d5571b3aae6)
Some maps' sounds have gain modifiers above 1 (foundation's Reach sniper
rifle fire, 1.5; ten on Hornet's Nest). The game asserted on them (a halt
in a debug build; in a release build the volume went on to assert again in
dsound_volume_from_gain); it now clamps the gain to 1, as Halo PC plays
them.
Written for OpenCE's dsound_channel_set_properties: the original change
only joined a 32-bit build to its 64-bit build's clamp, which OpenCE does
not have.
(cherry picked from commit 312960464ca0868746bfea19eb004635a5acbb8e)
The scope's screen effect (a warp: copies of the screen scaled a little
from the center, blended outside the scope's mask) spreads its copies by a
radius in the Xbox's pixels. At 640x480 the few copies blended into a
radial blur; at several screen pixels to the Xbox's one they stood apart as
sharp ghosts. The native builds keep the spread and split it into that
many times the passes (halo_screen_scale), each a step of it.
(cherry picked from commit b7fa7f742a72924514eef69d50daf31ef7f7f836)
(cherry picked from commit d1b40a6fc74ab46641313a6e0095e596494a1e7b)
Without its #ifdef HALO_LINUX, which OpenCE's builds never define (it compiled to nothing), and with the copied parameters declared with the others (gnu89).
(cherry picked from commit 763567dcc7ad8e6a851fec6bb5cb9f9e10452579)
rasterizer_xbox_bitmap_rebuild_hardware_format pads a linear bitmap's rows
to 64 bytes, rounding up; the texture header rounded its pitch down, so a
Custom Edition bitmap whose rows were not a whole multiple was drawn
skewed. The header now rounds up too (Xbox maps' rows always are a
multiple, so they are unchanged).
The texture header's pitch only: OpenCE never had the misalignment log the commit's custom_edition_bitmaps.c part removes.
(cherry picked from commit 90a057778f76eb96d45a112b95be2a0c1e1d69a2)
A machine whose address or hardware id is in bans.txt, or that was dropped
for cheating, was told the game is not open when it tried to join again;
it is told it is kept out (_rejection_code_blacklisted_machine), as at the
ban itself.
(cherry picked from commit 73c78610c67cd3827592673f1b06a1d38babe4ac)
Adapted: without the dedicated server's drop function it was declared
beside (in a server/ folder, not taken), and a machine kept out by a
vote (OpenCE's network_votekick.c) is told it is kept out too.
(cherry picked from commit c0191dd9beb4bfd26dd73ba0923cb7edeea44d49)
game_speed takes only finite speeds from 0 to 100.
(cherry picked from commit 4c6e68a6021204563aedb1f91e9a10d90744b5d8)
(cherry picked from commit bdbb182d0fc653960d1baf7a8b46360537eafe32)
The header's name is read only within its field.
(cherry picked from commit d4ff4cc226e25d315ca1db853ebef14953521691)
(cherry picked from commit f0dd7c9fa533a95e8e653e203064a985965f4007)
A range with no previous permutation (NONE) set the bit NONE as a byte
shifted to, 255.
(cherry picked from commit a35ddbe6bfcd31d5aa0c501dac52721fc295fa50)
(cherry picked from commit cd87b861b1203df530e22e777219255c21408984)
game_engine_predict_resources and game_engine_remap_vehicle took the
globals' multiplayer vehicles 0, 1 and 2 (warthog, ghost, scorpion)
without looking at the block's count. Every retail map has them; a Custom
Edition map's globals may not, and the game then stopped on
tag_block_get_element's assertion or, with assertions off, read past the
block and predicted or compared whatever was there. A missing one is now
NONE: not predicted, and matching no placed vehicle. Maps with all three
play as before.
(cherry picked from commit f1eb47cf3da8cf3e34ad2b6c2e304f994540ab46)
(cherry picked from commit 2f282f1aa2342af9619d5b7fcf0d92d1962b9ee8)
Deleting a saved game file moves the files after it down the memory
unit's list, but the players kept their profiles' old indices. A profile
deleted before the one in use left that one's index naming the next file,
often the next profile made: the profile in use was then saved over it,
taking its name in the list, while its folder kept the new name, which
then read as in use ("a profile with this name already exists") with no
such profile shown. The indices the players and the profile editor hold
now follow their files down the list, and one naming the file deleted is
none.
Fixes#148
(cherry picked from commit 4575f6e6ec7010de1036a3a639ee2794181874d8)
(cherry picked from commit 4bbd4965afbbaa22cb3a655a181c3770382bc505)
A network game's pause menu pauses nothing, and the controller that moved
about it also moved its player: the D-pad and sticks walked and turned
them as they chose an item. While a menu of a player's own is up
(ui_widgets_active_for_local_player), the player gets no input, as when
the director holds it, and the buttons still held as the menu closes are
let go of first, as before (ui_widget_delete).
Fixes#119
(cherry picked from commit 771a257f25ecf64fe52d84d0dbd77dc11b2a8680)
(cherry picked from commit b5fc042ca61cdfeb9a27693b2cb3f65bf93e2c0c)
The console runs what it is sent as scripts. A browser can be made to send
an HTTP request to a local port; such a client is now dropped at its first
line instead of having its lines run.
(cherry picked from commit faa2a331383f4dedce63487d813b7348c00b6f26)
(cherry picked from commit 40a6262e9be05db11317522f9ee9424405124025)
The scan kept each local player's blip count and the scan order in one
array of four, the counts first and the order from 2, and had two camera
positions: all the Xbox's two player co-op needed. With three or four
local players in split screen they were written past their ends and into
the function's stack guard, which halted the game as it started drawing
the HUD ("corrupt stack at 0!"). The counts and the order are now arrays of
their own, and there is a camera position for every local player.
(cherry picked from commit 266a556967273bfcf096c1e6009acdb7a5ee045d)
(cherry picked from commit c02cb986c2c5acc6426fcb043f39d1062617f7f7)
(cherry picked from commit ee9cbf17d1422f2b57b5ca07c98010ece1bcbad6)
25 notes ("left unassigned only by this default arm ... approval pending,
2026-09-27 audit") argued that a variable was never read unset. Where the
arm ends in system_exit they were right and simply go. A release build's
assertions return, though, so where the arm only asserts the variable now
starts with a value (a Custom Edition map's HUD data can reach hud_draw's).
A failed map precache reads as failed.
rasterizer_debug_drawing_begin had two declarations, one with an argument
its definition never takes; it now has one, and the port's macro papering
over the mismatch is gone.
(cherry picked from commit 74f8a048e4c3cc7dbc4b050dd41a8bae912bb367)
Uninitialised locals get values (debug vertex, datastore result, index
buffer, map tool direction, AI entry points, escape alignment, grenade aim
from a vehicle, game options descriptions, unreachable switch arms), the
AI's squad and platoon records move whole, a speech cause point is read,
the geosphere's out-of-memory path frees itself, a console cond clause
without a result is refused, and the crash reporter rejects truncated map
files. Gameplay the original game has, kept so it plays the same, is noted
in a line rather than a page.
(cherry picked from commit 75afc4a1e57af2ba697e8be0e33b2afeee7639f8)
Each of the 25 appends now goes through profile_append, which bounds and
terminates; a 150-tick frame could run past the 512-byte buffer.
(cherry picked from commit ecba1a0cecc7ff5d60d26654bdd50b7330d43f65)
Arguments a format never read are dropped, missing ones passed (the
migration speech type, DirectSound's result), a real printed as %f, a
target AI's name printed for it rather than the source's twice, and two
messages built from saved-game names printed through %s.
(cherry picked from commit dbcf4ab91c2e42c19f57ca436f1d4f2b41964582)
objects_can_see_object and objects_can_see_flag on player0 tested one player only, the first with a unit, so the Pillar of Autumn tutorial's panels (look at each light in turn) never lit for anyone else. In network co-op a test of the players now passes when any player looks, as volume_test_objects_all already does.
(cherry picked from commit 1e8e0f9affe212d3e30817b768d3124027b678f7)
Seven of the script engine's conversions and comparisons wrote only the
low byte or word of a long and returned the rest uninitialized, which
the scripts' stacks and globals, and so the saved games, carried along.
Every reader takes only the low byte or word (the script type sizes), so
the scripts' results are unchanged.
(cherry picked from commit bb239e2207668593679eea5de45eda8e5f635b34)
(cherry picked from commit d6811ee3264b2082ba6b943087ce26293f59768a)
The average radius of a group whose particles were all culled divided
zero by zero, leaving a NaN in the effect shader's secondary map radius.
(cherry picked from commit 11128fd78ade85c50a9a3a5a292bd2bb33bebf30)
(cherry picked from commit b52d79541dc2143de41943367542ae63ad4f384f)
bitmap_2d_get_pixel's out-of-range block messages printed a short where
they say lod=%f, and a compressed format it can't decode returned an
uninitialized pixel (release builds carry on past the assertion). Object
lighting is its only caller.
(cherry picked from commit e1169e05a374071e74b3da3d285762c45f1c2a77)
(cherry picked from commit 9d827c0dd9164196da54b10a2fbfdd63bf72a0cd)
A trail's first draw asks the texture cache for its bitmap without
waiting and is skipped until the read finishes, so a weapon's first shots
could show no trail (the sniper rifle's most of all). A weapon created or
readied now asks the cache, without waiting, for the bitmaps of its
projectiles' contrails. Only the texture cache sees it: nothing in the
game state or on the network changes.
From pfista's halo-og (4e66af91), the source/items/weapons.c part only;
that commit's spawn inventory and teleport prediction changes are not
taken, as they change what a host and its clients exchange.
Co-authored-by: Michael Pfister <pfista@gmail.com>
(cherry picked from commit 7fff24d4843758ddcb6468c9f1febecfbce68aa5)
(cherry picked from commit 965f48f5c5e2063ba025766f1276467708e8112c)
While searching for games the client wrote to its connection before it had a socket (Winsock error 10038); that marked the connection closed, and when the player then picked a game every write of the join request failed, so the first join to a host hung and gave up. Connecting now clears that, and any half-sent data. A second try worked only because it made a new connection.
(cherry picked from commit 4b18b99af6d977707203b304d104c84fb23fecb4)
A send that fails with an error the transport doesn't name became endpoint_io with nothing to say why (a first join to a host that then failed). The error is logged now, once for each. The connect wait treats a select that times out as still connecting, and sets its timeout each time (select may leave what is left of it).
(cherry picked from commit 5b02133ce00edcb7d9fd788db459a77cd98e9ac4)
Rotational sprites draw their edge-on view from the sequence after the state's. A particle bitmap on foundation has only one sequence, which halted the game in particle_system_render. Without that sequence the face-on sprite is drawn alone.
(cherry picked from commit d436a0c0c3abaf069dd34e4b8d761b49569311e6)
A structure BSP's lens flare markers are submitted for every visible
cluster, and each gets an occlusion test every frame, including those
behind the camera or off the screen, whose tests count no pixels (so
they are never drawn). On the Xbox a test was nearly free; here each is
a draw and a query of its own, and a level of many lights (Medical
Block) tested about 460 a frame (debug.gpu_trace_heavy). A flare whose
test could not reach the screen, by the frustum and a sphere taking in
the test's offset point and size, is no longer submitted.
(cherry picked from commit e020bbc58dd08b4bcd609d8cf561c94b87cf4580)
terminal_printf started its variable arguments into a char *, which is
what va_list is on the Xbox, 32-bit x86 and Apple silicon, but not on
x86-64, where va_list is a one-element array of a register-save
structure. On an Intel Mac (or under Rosetta) va_start wrote through an
uninitialised pointer and vsnprintf read garbage, so the first terminal
line printed with arguments crashed the game.
Choosing an empty profile slot is such a line: "player profile begin
editing" fails, as it does on the Xbox, and console_warning reports it
through terminal_printf, so setting up a profile crashed on Intel Macs.
(cherry picked from commit 024e41b8cb1553d7ad9b96233860848d49e5ad13)
With input.touch_aim_assist false, walking with the touch stick still let the view follow a target: the touch controls now count as aiming without the assist until a stick aims again (halo_linux_touch_aiming), as the mouse does. The stick's diagonal is full on both axes, as a controller's square stick gives. The gyroscope reaches the game apart from the swipe (nativeGyro), so the profile's invert look turns only the swipe.
The overlay shows once the game has been in play for 200 ms, so it does not flash at a level's first frame. The options dialogs are counted, so a dialog opened from another keeps the controls released, and the layout is saved when the last one closes (a slider moved without a finger was not). A floating stick rests where the thumb lands, even near an edge, and not in the bottom gesture zone. A finger's width is at most 34 logical units, so the D-pad's buttons stay apart on a small dense display. A held button that takes over the swipe from another finger starts from where it is, not from where it went down. The system bars coming and going no longer release every finger. Hide stops the gyroscope.
The libtiff comments are corrected: the screenshot_count and screenshot_size globals also reached tiff_export, but read back-buffer memory the port never draws into, so they never had the picture. Stale comments are fixed and the source exclusion test covers folders.