Several of the fixes taken from the forks changed source/ without the
port: comment that marks a change from the original, and three removed
the notes on the original's bugs without saying they were fixed. Each
change now says so.
The packet table had begin game, graceful exit and keep-alive each on its
neighbor's field list (the Xbox game's table order is not their type
order), so a keep-alive's short was encoded and decoded as a long: the host
sent 2 bytes of stack past it, and a client wrote 2 bytes from the network
past it on its stack. The field lists now sit under the messages whose wire
they describe, and the keep-alive is a long. Not a byte on the wire moves:
begin game still carries a short (16 bits of its long), exit and keep-alive
a long, so OpenCE and earlier builds play as before; the keep-alive's 2
bytes that came off the stack are zero now. tools/test_network_messages.py
encodes every message under AddressSanitizer and compares the bytes with
upstream's table.
(cherry picked from commit ee32bdad42615402053291344e3c89f8bcc04161)
A client that joins a lobby on a Custom Edition map it does not have
downloads it by map sharing. When the host started the game meanwhile, the
host held the client's players out, as it should, but the client, whose
download began in the lobby, did not know the game had started and asked
for its player again; the host took the request as a late joiner's and
started it at once. The client then loaded a map it did not have yet:
cache_files_precache_map_begin's damaged disc error, which stops the game
for good. Stock build-201 does the same with its own host.
- The host (network_server_manager.c): a player asked for by a machine
still downloading the map waits with those held at the start
(network_game_server_hold_requested_player), and joins with them, the
machine started as a late joiner, once its download is done
(network_game_server_release_map_fetchers).
- The client (network_client_manager.c): a start that comes while the
map is still being downloaded, from a host of an earlier build, is put
off until the map is there (network_game_client_begin_game,
network_game_client_idle_pregame), and dropped if the game it was for is
over by then (another map, or another game).
- NETCODE.md's "Map sharing" says what happens when a host starts during a
download (it said the host waited, which it has not since version 28).
Nothing sent changes: no network version.
Checked: the Linux CI steps, the web build and its tests, and the Windows
release build. End to end on Linux in Docker, the host starting the lobby
game at once while the client downloads (the case that stopped the game):
this build both ends (the host held the player and started it at game tick
296 once the map was there); build-201 hosting this build's client (the
start put off until the map was there); this build hosting build-201's
client (held, then played). Each client played the game.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Xbox game allows 16 players on 4 machines (4 split screen players
each). The native builds raise both limits to 128, keeping 4 players per
machine, and leave the byte-matching build unchanged: every change is
under HALO_LINUX (the MSVC objects compare identical).
- Limits: every local copy of the player and machine limits, and the
bare 4s and 16s that stood for them, follow halo_port_limits.h. The
player data array, the machine-to-player table (and its reset) and the
per-tick update arrays grow with them.
- Records: the copies of struct network_game agree on the larger layout
and check it against halo_port_limits.h; maximum_player_count becomes
a byte (128 does not fit a signed char); network_player_is_valid
checks the machine against the machine limit, not the split screen
one; a machine's input carries MAXIMUM_LOCAL_PLAYERS actions (16/4
would have become 128/128).
- Protocol: a message holds at most 4095 bytes (its header has a 12-bit
length), so the 13 KB game settings record is sent in 3.5 KB pieces
that clients reassemble; the per-tick update of 128 players (3,857
bytes) fits. Buffers and the packet codec's limits grow to match, and
the game search uses protocol version 2 so these builds and the Xbox
game never see each other's games.
- Connections: the host accepts a client connection per machine (the
split screen count stood in for it), FD_SETSIZE is 256, stream writes
send all of a message or drop a peer that stops reading instead of
corrupting the stream, and the input and update queues are larger.
- Host: lobby changes are sent at most every 250 ms instead of on every
change (a full lobby would otherwise send ~650 MB), in-game joins wait
in a queue instead of being dropped, the random name and colour
pickers stop looping forever once names or colours run out, machines
get 60 s to load a map, and the debug dump lists only the slots in
use (128 empty slots took seconds to log).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>