Commit Graph
4221 Commits
Author SHA1 Message Date
MrBruh bbe00a4049 Merge pull request #286 from hkmodd/fix/hires-text-fit 2026-10-12 20:46:49 +13:00
MrBruh 3cd1a6622e Merge pull request #305 from hkmodd/perf/debug-model-vertices-static 2026-10-12 20:46:49 +13:00
MrBruh e71e6514f3 Merge pull request #304 from hkmodd/fix/transparent-geometry-groups 2026-10-12 20:46:49 +13:00
MrBruh 9fbbf6a628 Merge pull request #303 from hkmodd/perf/shader-key-compare 2026-10-12 20:46:49 +13:00
MrBruh 3d67397cdd Record the wire format at network version 28 (#253)
The testing branch is at version 28, whose changes (holding back the
players of a machine still downloading the map, the multiplayer scripted
BSP, lights past the Xbox limits, readying a second weapon) change no
message, kind, bit or struct the record holds; only its version changes.
2026-10-12 20:35:23 +13:00
MrBruh 5d9081e91e Merge pull request #253 from addisonbair/network-format
# Conflicts:
#	port/linux/NETCODE.md
2026-10-12 20:35:16 +13:00
MrBruh ce5e382b37 Merge pull request #262 from machinsk/web-metal-buffer-waits 2026-10-12 20:34:15 +13:00
MrBruh 065d7f2b1d Merge pull request #263 from addisonbair/pregame-lobby 2026-10-12 20:34:15 +13:00
MrBruh 5a7c655a60 Testing branch review fixes
Network version 28: the host now holds a downloading machine's players out
of the game, and keeps a multiplayer map's first scripted BSP. Dynamic lights
and the flashlight stay on past the Xbox limits, and a second weapon picked
up while firing is readied. Machines of version 27 would disagree on these.

- A large co-op game's respawn fallback no longer picks a teammate who is in
  the air, outside the BSP, or riding an AI vehicle.
- A machine still downloading the map times out when it goes silent.
- Held players join through the late-join queue, so they get the same checks.
  A machine with no held players is started instead of being refused.
- The co-op teleport uses world positions, which are right for seated players.
- Overshield drain no longer cuts off a hit's flash, and hits over 0.02 flash.
- The menu XML is the generator's (Custom Edition's layout) again.
- port: markers on two new declarations.

Checked: ninja linux, android and web build; tools/harness,
test_touch_menu and test_web_build pass.
2026-10-12 20:01:49 +13:00
hkmoddandClaude Opus 5.5 eea1c3641a Keep the debug model vertices off the stack
rasterizer_debug_model_vertices declares 2048 debug vertices of 64 bytes
on the stack. render_model calls it for each part it draws, and the
release build inlines it there, so render_model's frame was 136,304
bytes, and the Windows build probed it a page at a time (_chkstk, 33
pages) for every model drawn, although the debug display is off. Its
vertices are static now: only the vertices below debug_vertex_count are
read, each written when it is added, and the function runs on the
render thread only, so nothing it draws changes.

Measured on Windows (7800X3D, RTX 4080, release build, vsync off), b30
co-op with 32 times the enemies and a bot, 75 s a run, five runs of each
build alternated: render_model's frame is 5,360 bytes (the PDB's
S_FRAMEPROC); _chkstk fell from 2.0% to 0.5% of the game thread's
samples; fps over windows with 2000 draws a frame or more, origin/main
128, 141, 139, 134, 107 (median 134), this change 140, 139, 144, 141,
132 (median 140). Linux, Android and the web build do not probe the
stack, so the change only shortens their frame. They were not built.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 03:18:12 +02:00
Addison Bair fab098a7bd Record the wire format of the network version
AGENTS.md asks for HALO_PORT_NETWORK_VERSION to be raised with any change
to what the machines send each other; nothing checked it, and #95, #99 and
and 18 caught up after them).

tools/network_format.py takes the wire format from the sources: the game's
message numbers, sizes and fields, the distributed netcode's message kinds
and flag bits, its DISTRIBUTED_ constants and the structs it sends whole, as
hashes. port/linux/network_format.txt records them for the version, and
test_linux_port.py fails when the sources differ: an item changed or removed
asks for the version to be raised (--record refuses it until then), an item
added (a new kind or bit, which older builds may ignore) only to be recorded.
It also fails when NETCODE.md says nothing of the version.

Checked by recording each merge's parent and checking the merge: #95, #99
and #106 fail as changed structs; #91, votes to kick, voice chat and the
integrated light bits as additions; #101, which raised the version, passes
once recorded. A comment, or a struct the netcode keeps to itself, changes
nothing.
2026-10-12 01:09:55 +00:00
Addison Bair 9180bd37c8 NETCODE.md: network versions 22 to 25
The versions' list stopped at 21. 22 to 25 as their commits give them:
Custom Edition maps named custom_maps\<name> (4e8ed2f1), their blocks kept
past the Xbox tools' limits (34e2d4fd), the gametype's PC vehicle set
(11117d7c) and a unit's integrated light in its object state (6b55f5cc).
2026-10-12 01:09:44 +00:00
hkmoddandClaude Opus 5.5 2c6c85cf38 Raise the transparent geometry groups a frame from 384 to 2048
Every transparent thing a frame draws takes a group: each transparent
part of a model, each widget (light volumes, antennas, flags, glows),
each batch of dynamic geometry (particles, contrails), each transparent
surface of the structure. The Xbox's 384 were a limit the native builds'
larger pools of objects, widgets, effects and particles could pass: a
frame past it was drawn without the rest, and debug.txt said "too many
transparent geometry groups". A part refused a group has no sort record
(models.c checks the group's index), so nothing else changes.

Checked on Windows in b30 co-op with eight times the enemies and a bot,
75 s a run: origin/main overflowed in 3 runs of 4; a build counting the
groups asked for showed up to 464 in a frame, while the dynamic triangle
and vertex buffers peaked at 123 and 328 of their 1024 and the dynamic
triangles at 10272 of 49152, so they are left as they are. With this
change, the same count showed 391 in a frame and no overflow; two more
runs had none. The pool is 2048 * 160 bytes, malloc'd; the model order
pass keeps 14 bytes a group on the stack (28 KB). Harness: the
transparent_plane_order tests pass at the new size (natively on Windows;
the other 44 failures there are the same on origin/main, POSIX headers).
Android and web builds not built.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 02:55:40 +02:00
hkmoddandClaude Opus 5.5 1068da0c3a Compare shader keys and draw uniform inputs a word at a time
Every draw compares its pixel shader key (256 bytes) with the recent and
cached keys, and its uniforms' inputs (77 words) with the last draw's.
The Windows build's memcmp (vcruntime) compares them a byte or a word at
a time and was the game thread's largest single function: 7.9% of its
samples in a b30 co-op game with 32 times the enemies (about 3900 draws
a frame), 5.3% from fragment_shader_get and 2.2% from the uniforms.
words_equal has no early exit, so that clang compares several words at
once (four 512-bit compares a key with -march=native).

Measured on Windows (7800X3D, RTX 4080, release build, vsync off), five
runs of each build alternated, 75 s each, b30 co-op x32 with a bot:
fps over windows with 2000 draws a frame or more, origin/main 123, 139,
135, 123, 122 (median 123); this change 142, 147, 138, 149, 131 (median
142). A sampled run of this change shows memcmp gone and words_equal at
1.2%. The keys are memset before they are filled and have no padding,
so word equality is byte equality. Android and web builds not built.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 02:27:50 +02:00
bnunu 173248fd8e Merge pull request #299 from innerhat-dev/overshield-drain-testing
An overshield's drain is not a shield hit, and a second weapon is readied
2026-10-11 20:02:20 -04:00
bnunu 5181d33b49 Merge pull request #298 from innerhat-dev/menu-row-spacing-testing
Menu rows keep one vertical step
2026-10-11 20:02:09 -04:00
bnunu a33bf2d537 Merge pull request #297 from innerhat-dev/coop-respawn-fallback-testing
Respawn a large co-op fight beside the group after ten seconds
2026-10-11 20:01:58 -04:00
bnunu caad6e772a Merge pull request #296 from innerhat-dev/multiplayer-sky-bsp-testing
A multiplayer sky script no longer reloads the level
2026-10-11 20:01:43 -04:00
bnunu 4f59a20a01 Merge pull request #295 from innerhat-dev/multiplayer-flashlight-testing
A multiplayer match keeps the flashlight on
2026-10-11 20:01:21 -04:00
bnunu 9633a7c34a Merge pull request #293 from innerhat-dev/coop-grav-lift-testing
Bring a co-op team inside with a scripted teleport
2026-10-11 20:00:40 -04:00
justinfilip 2598dbe8b6 An overshield's drain is not a shield hit, and a second weapon is readied. 2026-10-11 18:34:17 -05:00
justinfilip 679bade466 Menu rows keep one vertical step. 2026-10-11 18:34:16 -05:00
justinfilip 0b4a03561b A large co-op fight respawns beside the group after ten seconds.
The wait only counted teammates the map called grounded, so jumping, riding, or standing on a beach left it with nobody to use. A late joiner after a checkpoint uses the same wait when nobody is safe to spawn beside.
2026-10-11 18:34:15 -05:00
justinfilip b71bd6a0fa Keep a multiplayer map's first scripted BSP switch so the host's game type chooses the sky. 2026-10-11 18:34:14 -05:00
justinfilip c3365b1c69 A multiplayer script that switches BSP to cycle the sky no longer reloads the level. 2026-10-11 18:34:14 -05:00
justinfilip 417de7e2ad A multiplayer match keeps the flashlight past the Xbox player and vehicle limits. 2026-10-11 18:34:13 -05:00
justinfilip d6df944886 Bring a co-op team inside with a scripted teleport.
Campaign scripts only name two players, so a large group was left on the beach when Truth and Reconciliation's grav lift switched into the ship.
2026-10-11 18:27:24 -05:00
bnunu 0b2c6759bb Merge pull request #289 from innerhat-dev/late-join-same-checks
Adding a player after a map download uses the same checks as any other late join
2026-10-11 18:27:47 -04:00
justinfilip baab0780f6 Adding a player after a map download uses the same checks as any other late join. 2026-10-11 17:25:11 -05:00
bnunu 5fccdda2b1 Merge pull request #288 from innerhat-dev/lobby-map-for-testing
A downloading player's body waits until they join, and custom_maps is created when missing
2026-10-11 18:08:02 -04:00
justinfilip 05dd9ccdea Create the custom_maps folder on startup when it is missing. 2026-10-11 17:03:37 -05:00
justinfilip 67f2214219 A player still downloading the map no longer spawns until that player joins. 2026-10-11 17:03:37 -05:00
hkmoddandClaude Opus 5.5 7a6fc70eb9 Fit the high-res text's fonts to the widths of a Custom Edition loc.map's letters
The high-res text sizes Overpass by the font tag's capitals and centres
each glyph on the tag's character width, and Overpass was chosen for the
Xbox maps' widths. A Custom Edition loc.map's fonts are narrower: the
Italian one's large_ui and small_ui are the same font, its capitals 10
units tall and its letters 87% as wide as Overpass's at that height
(against 95 to 98% for the Xbox maps' interstate, large_ui and small_ui),
so the menus' and HUD's letters ran into each other. Each font is now
narrowed until its letters A to Z and a to z are, summed, as wide as the
tag's; the Xbox maps' fonts are narrowed by 2 to 5 hundredths.

The fonts were also remembered by the tag's name, and the Xbox maps and a
loc.map have tags of the same names with other measures, and by the font
tag's address, which the next map's tags may reuse: they are remembered
by their measures too, and forgotten with the map's tags.

Checked: the fonts' widths measured from the Italian loc.map and the Xbox
ui.map against Overpass's advances; the Windows build (clang 23.1.3, full
LTO) without warnings; Extinction from the Italian Custom Edition, whose
large_ui is now drawn 87% wide, its letters apart, and the main menu's
small_ui 98% wide.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 23:16:04 +02:00
bnunu 86be005acc Merge pull request #283 from innerhat-dev/lobby-countdown
A player joining or leaving the lobby no longer restarts the countdown
2026-10-11 16:36:27 -04:00
MrBruh a2aad18f65 Custom Edition map sharing
Hosts send players who join without the game's Custom Edition map the map
and the resource maps it needs; the other players help, torrent-style.
Network version 27: new map sharing messages, and players of an internet
game now reach each other.
2026-10-12 08:07:14 +13:00
justinfilip 71ceb363f1 Players who already have the map no longer wait for a machine that is still downloading it. 2026-10-11 13:37:40 -05:00
justinfilip 2059b6cef5 A player joining or leaving the lobby no longer restarts the countdown. 2026-10-11 13:37:40 -05:00
Jonathon MachinskiandClaude Opus 5.5 568f8c1fe7 Web draws' uploads put in buffers no queued draw reads, so Metal does not wait
WebGL on Metal (ANGLE, which Chrome and Safari use on a Mac) waits for the
GPU to finish everything queued before it writes a buffer that a queued
draw reads, unless its shadow buffers are on, and Chrome leaves them off.
The renderer wrote its stream and index buffers after each draw, some 2000
times a frame, so each frame waited for the GPU as many times. On an M1
Pro in Chrome the Silent Cartographer ran at 7 to 9 frames each second and
Blood Gulch at about 22, at any resolution (640x480 too): Chrome's GPU
process spent half its time in -[MTLCommandBuffer waitUntilCompleted]
(macOS sample), and --enable-angle-features=useShadowBuffersWhenAppropriate
alone tripled the rate.

Now, on the web, each draw's vertices and indices go into a buffer that no
queued draw reads: web_chunk_get takes one from pools of power-of-two sizes
(4 KB to 32 MB), one set for each frame of the ring, and a buffer is written
again only when its frame comes round again. A draw counter (draw_serial)
tells stream_reserve and index_upload when the current buffer may be read
by a draw. Android is unchanged.

Checked on an M1 Pro, Chrome 155, 3024x1626, uncapped, A/B against
e0b581b1: b30 6.1 to 170 frames each second, Blood Gulch 57 to 595; with
vsync, 60 throughout. Screenshots of Blood Gulch before and after are the
same. ninja web builds without warnings; tools/test_web_build.py and
port/web/tests/*.test.js pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 08:12:42 -06:00
Addison Bair 59a74b0c4b The pregame screen opened through the port's menus everywhere
Fast setup and the network test's join opened ui.map's pregame screen by name, where ui_widget.c opens the port's lobby; a ui.map of only the menus' tags hosts and joins with both.
2026-10-11 14:08:51 +00:00
MrBruh e0b581b157 Web: disclaimer footer 2026-10-11 23:03:29 +13:00
MrBruh 17a57832d8 Windows: tag block accessor builds again
msvc_comdat.c defines __inline as weak on Windows, which a static function cannot be; the accessor is __inline__. Checked by compiling msvc_comdat.c for i686-pc-windows-msvc.
2026-10-11 22:45:33 +13:00
MrBruh 5cd65a0cb0 Web: meter blend in the shader
WebGL refuses blendFunc(CONSTANT_ALPHA, CONSTANT_COLOR), so the meters (ammo counters) drew with the previous blend and a GL error each frame.
2026-10-11 22:38:11 +13:00
MrBruh a3277d94dc Fewer draws and GL calls
Decals and light volumes batched, web index and vertex array caches, no FULL_ES3. Prisoner, 15 players: 115 to 172 FPS (A/B).
2026-10-11 22:28:34 +13:00
MrBruh 6399ed9d4a Text drawn a string at a time, web immediate draws packed
Scoreboard text on the web: 1.41 to 0.41 ms a frame. The network test's browse joins the fullest game that is not co-op.
2026-10-11 16:16:35 +13:00
MrBruh 01afcb654a First-person shield flare kept close only with display.viewmodel_shield (#254) 2026-10-11 15:13:49 +13:00
MrBruh 3fa1f348a9 Merge pull request #254 from chestahh/codex/opence-viewmodel-shield-fit 2026-10-11 15:05:51 +13:00
MrBruh f1c31076ff Merge pull request #252 from addisonbair/bots-hardware-id 2026-10-11 15:05:51 +13:00
MrBruh 0bfe211289 Web: stable pages hashed less often, fewer clock reads
18-player Blood Gulch in Chrome at 1080p: 135 to 225 FPS.
2026-10-11 14:59:19 +13:00
chester 2e45259bea Delete tools/test_viewmodel_shield.py
not required for upstream commit
2026-10-11 01:59:40 +01:00
chestahh 248210cedb Keep first-person shield flares close to the arms 2026-10-11 01:52:48 +01:00