The culling tests could be changed only with the console's
structure_culling, which did not last past the game's end. The setting
(HALO_STRUCTURE_CULLING) gives the starting bits, 31 (every test) by
default as before, read in render_initialize; the console command still
changes them while the game runs. Documented in the settings table.
Checked: tools/harness (640 passed, the structure culling tests among
them), test_linux_port's config section and menu settings tests, and the
changed files compiled with -fsyntax-only for Linux, the Android guest
and the web.
Several of the fixes taken from the forks changed source/ without the
port: comment that marks a change from the original (the second copy's
datagram ports, the downloaded maps' refusals, the main menu's clock,
the one-magazine HUD states, the render lists' sizes and others), and a
comment still named a function of that fork's. Each change now says so.
A tick waits for an input update with an action for each player, and the
menus change who the local players are (signing profiles in and out, a
lobby's network game owning the queues). In a lobby, or once a client's
clock waited for a game, the main menu's scene stopped ticking; and a
screen flagged to pause game time (Mods, the map and gametype screens of
setting up a game) paused the clock that runs the scene, which then
started again from its beginning as the screen closed.
The main menu's scene now always ticks on this machine's clock
(game_time_menu_scene), its players idle where the queues have no input
for them, and at the main menu those screens no longer pause it. The
distributed netcode's per-tick work is not done for the scene: a lobby's
machines do not share it.
(cherry picked from commits 8444785804f8cfb413020da5a03fc5dd65f918e9, 6267d199117f87e56a3f41fc8932966a39a3feb2
and 3a4097bb48f34245b750028a5c0ae28e03bae037, made again on OpenCE's game_time_update,
which has no separate clock connection for the scene)
The high-res HUD draws a message's controller button by its place among
the HUD globals' button icons, but only once the map's message icons
bitmap had a picture at the button's sequence. Halo PC's message icons
have 13 sequences to the Xbox's 24, so on a Custom Edition map a prompt's
button past them was not drawn at all, and the rest only because the map
had some other picture there ("Hold [rocket launcher] to swap" on
coldsnap, with the high-res HUD off). The high-res button is now tried
first. With display.high_res_hud off, a Custom Edition map still draws
its own pictures.
Found in commit 4c3e74cf29341ff344aca09febc0fab7e1d19919, which instead
reads the Xbox's button pictures out of ui.map for every Custom Edition
map; that is not taken.
network_game_server_dispose keeps the Xbox's one-second grace period
(SleepEx) only for builds other than Windows, Android and Linux, whose
transports need none; the web build is no __linux__ to Emscripten, so it
still waited a second each time a hosted game ended. It is left out there
too.
(cherry picked from the server part of commit bea41d710988e9aeac6cec44f4fd69b5203906e2,
whose dispose change OpenCE already had for the native builds)
_data_packet_verify read an uninitialised field_size for a first field
outside the packet's version, and gave later ones the size of the field
before them. No field of the game's packets has a version limit, so no
packet changes; the size starts at 0.
(from commit c01c68537bcbda79f0e4def4211cad611dfdee74's data_packets.c
change; the rest of that commit, comments rewritten, is not taken)
A Halo PC map's animation graph may have more nodes than its model
(beavercreek_rev_beta's cyborg has a graph of 20 on a model of 19), which
Halo PC's engine posed past the biped's node matrices. Such a dead body
was left unrelaxed here. It is now posed in a copy of the biped's node
matrices with the graph's every node, the extra ones where their parents
are, and the model's taken back.
Reported by Sabriel.
(cherry picked from the limp body part of commit 5fdbccf6cdf4f5be4bcaf1b90f4fe712877ddb4b;
OpenCE's checker already let such a graph be, and its own check of the
nodes is kept for the counts and links)
A map that map sharing downloaded runs only scripts that keep to the
player's own game: one that calls what changes the player's settings or
other players' games (player0_look_invert_pitch, sv_end_game, sv_say) or
sets a global that outlives the map is disabled, as for any map's script
that calls what no map's may, and debug.txt says which. Map sharing names
each map it downloads in custom_maps/downloaded_maps.txt, so they stay
held to this in later runs; game.downloaded_maps names more, or "*" for
every map. The campaign's game_speed and game_save_totally_unsafe stay
allowed.
The setting's entry came into port_config.c with the profile commit before
this one (a conflict's side of it); it is the one entry now.
(cherry picked from commits 7d02d46210ba672512e36b39ffd2c0b0d8e4f3b3 and
d3718e78d4889140a44f8050075b56143e4b7732, wired to OpenCE's map sharing in place of that
fork's map families)
The Join Game server browser shows each ping coloured: green under 80 ms,
yellow under 160, red above. A text colour hook of the menus'
(pc_menu_text_color) gives the ping its colour; the rest keep their own.
(cherry picked from commit 335c6522e9fb7aa33762e3f2cf27c518ac0e48ce, without that fork's
Online Games screen, the thresholds and colours kept in menu_functions.c)
In Join Game's server browser a click selects a game, its row in the
yellow-outlined picture Custom Edition draws for it, and a click on the
selected game, a double click, A, Enter or JOIN joins it; one click
joined it before. The keys move the selection.
(cherry picked from commit 472d232246568ed2e3ee56bc93d97a3530feea54, without that fork's
Online Games screen; OpenCE's rows already take the focus only from a
click, not from the pointer passing over them)
The debug build this port comes from unlocked every campaign level on
every difficulty for each new profile. Retail Xbox Halo does not: a new
profile starts at The Pillar of Autumn and each level opens when the one
before it is finished. New profiles now start that way.
- game.unlock_all_levels (off by default) keeps the old behavior for new
profiles, for those who want it.
- profile_reset_campaign in the console clears the current profile's
finished levels and last played level, after a confirmation
("profile_reset_campaign yes"). Profiles made by earlier versions had
every level open and cannot be told apart from a real full clear, so
nothing is changed automatically.
(cherry picked from commit 224d9a757575509efb0dedab094bd0d34df59e96, without its top README
table, which OpenCE does not have)
A busy multiplayer fight fills the Xbox's per-frame lists of what a view
draws: 512 particle runs and 128 dynamic lights. Past them plasma bolts,
charge glows and flashlights stop drawing. The desktop builds now draw
2048 and 512. These lists are rebuilt every frame, outside the game state,
and nothing of them reaches the network. Android's and the web build keep
the Xbox's.
(cherry picked from commit f1abebdd6e89de292569ea466496fa0484476e0e; OpenCE already drew
2048 transparent geometry groups on every build, so only the particle runs
and lights are taken, with OpenCE's guards for the builds that keep the
Xbox's sizes)
The first frame that drew each HUD picture decoded its PNG, which held that
frame up. On the desktop builds a map's HUD PNGs (and its sprite sheets')
are now decoded as the map loads, on a thread of their own, so that the
first frame only uploads them; what is decoded and not drawn is let go when
the map is unloaded. Android and the web build decode each when it is
first drawn, as before.
(cherry picked from commits afa4feaee4935b118dbc6d94140587842205cbfe and
27a22a2ded1bc78323f7f4bf35033dd843f7b956, made again on OpenCE's high-res HUD, its sprite
sheets queued too, and not on the web build)
The full reference list pick left a light's clusters out under
HALO_SERVER, its dedicated server's define, and the debug.txt roll's
header check under HALO_XBOX_CONSOLE; OpenCE defines neither, so both
were dead or always true. The comment no longer cites a dedicated
server.
A dedicated server's debug.txt grew 2 GB in 12 hours, almost all of it
"maximum light cluster references per map (8192) exceeded", written each
time a light could not join a cluster: thousands of times a second on a
busy map. A full reference list now says so the first time a map, and the
times after are counted and told when the map's lists are let go or made
anew. What fits in the lists is as before.
The dedicated server draws nothing, and a light's clusters are only used
to draw (the lights of an object or the map, and a unit's illumination,
which only debug_unit_illumination reads, from the lights drawn that
frame). The server (HALO_SERVER) no longer joins lights to clusters, so
it does none of that work each tick and never fills the lists.
(cherry picked from commit 50cc6274fb5f7697c6f3c25394e15e22f87106f2)
A line the same as the one before is counted rather than written again
("last line repeated N times", when a different line comes). When
debug.txt passes 64 MB it is renamed debug.old.txt (replacing the one
before) and a new one starts, with the header again for crash reports'
addresses. A game left running for days had no limit to its log.
(cherry picked from commit d4b46c829dcdaa53ee72d7d2901bc166115b0e69, without its dedicated
server README; the web build's copy of each line to the page's log is
kept)
A one-magazine weapon's second magazine, read as empty, still set off the
secondary states: the secondary trigger ready, flash, reload and "no ammo
for reload" crosshair states, and the draw states of its total and loaded
ammunition (flashing, disabled), which coldsnap's and hugeass's master HUD
draws as NO FUEL beside the weapon's own NO AMMO. These now apply only to a
weapon with a second magazine.
(cherry picked from commit 488bd83eafaabf26a7e392eaf8b240b1319e07c3; OpenCE already cleared
the state first, kept the overlays off and checked two of the crosshair
states, so only the rest is taken, and no CHANGELOG.md)
A second game on one computer listens on another port and hears none of the
host's broadcast advertisements, and the host answered searches no more
than once each advertisement interval. Such a searcher is now answered
directly every time; the broadcast keeps its interval.
(cherry picked from commit b49c83d1c871a23f76825bdcdc52a228167f1c37)
The unreliable queue kept only a datagram's source address, so every
reader saw port 0. The host's answers to where a client's datagrams come
from (a second game on its computer, a direct answer to a game search) went
to port 0. The queue now keeps the port after the address.
(cherry picked from commit 781b98e9333c2cb85a85360267b24cc6656100c1)
Both games bound the client port (SO_REUSEADDR lets Windows share it and
hands each datagram to one of them), the host matched a distributed
datagram to the first machine at its address (its own), and sent every
client's per-tick datagrams to the fixed client port. The second game got
only the reliable messages: no units, no spawn, no co-op cutscene camera,
its camera left at the origin (the purple screen), and in PvP it waited
for space to clear.
A client now listens on any free port when another game has the client
port, the host takes a distributed datagram from the machine at its address
that isn't its own before its own, and answers each machine where its
datagrams come from. A game search from another port is answered there too.
(cherry picked from commit 0f4e71eba0787b8d3cd28c436cdb44ec6d79abda)
A machine that asked to join as a game ended, before the server switched
to the pregame, was left waiting behind the one the server holds: the
server refused every later join with "network_game_add_player() failed"
and sat in the lobby for good. A host that starts its next game by itself
(network_test.c's host, which the dedicated servers run) never recovered.
Those joins are now dropped when the next game starts. Only the host's own
bookkeeping changes; nothing on the wire does.
From JoshRob297's halo-ce-touch (18a6fc58), reworked for our tree, which
has no network_game_server_port_set_minimum_players.
Co-authored-by: JoshRob297 <99092299+JoshRob297@users.noreply.github.com>
(cherry picked from commit 4582817b2bb4241b53bfa4c523f02aa267595feb)
(cherry picked from commit be7362f2d0b9983e3e12a25f5c76871be5e9132f)
The picked log_address change declared the function inside
transport_address.c; the port's functions the game's sources call are
declared in halo_linux_source_fixups.h. Map sharing, which OpenCE added
since, logged a closed connection's address whole: it now goes through
log_address too. debug.log_addresses is in the settings table.
Players post debug.txt in public, and a host's log names everyone who
joined it. Every address the game logs now goes through one helper,
log_address: a public one is written as a tag (addr#3f2a9c), the same for
the same address all run long, so lines still match up, with its port as
it is. Local network, loopback and internet play's stand-in addresses stay
whole. debug.log_addresses in config.toml writes them all whole, for
debugging one's own network.
Display and logging only: nothing sent or compared changes.
(cherry picked from commit c76df1d00a88072d50af64cde39fb957fa5b842c, without its
64-bit-only xnet.c line)
Starting a system link game on Blood Gulch in the Windows build stopped
on two colour range asserts: rgb_colors_interpolate's result (a
structure decal's random tint) and a transparent shader stage's
animated constant colour. Both blend two valid colours by a factor in
[0, 1], and the native builds' x87 code can carry such values (and
periodic_function_evaluate's 255*(1.0f/255.0f)) at more than single
precision, a hair past 1. The blends are pinned to [0, 1] before the
asserts, and periodic functions return values in [0, 1].
(cherry picked from commit 5c1e49f189e09212d6bc9568649b1cdb7b1e005e, with
the changes marked port: in place of that fork's HALO_LINUX, which OpenCE
never defines, and without its README table)
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.
"event handler function failed" said nothing of which: the gametype
editor logged it fifteen times. It names the function's number and the
widget's tag, taken before the function runs (it may delete the widget).
(cherry picked from commit 5f4494f42b1919dc1e38c6f8e168b646768e74f1)
"attempt to play a sound that was not a mono 22k compressed sound..."
now says which sound tag, and its compression, encoding and sample
rate, so a report of it can be traced to the map that has it.
(cherry picked from commit e859daf04476ad2b0608f130e9b63ac0cf7140a8)
(cherry picked from commit 9e9104b26907b748ace50e004fd5e9f2c0167b11)
The campaign's scripts print their progress and music cues ("mission
script is running", "levels\b30\music\b30_01", the dialog lines), which
the Xbox never showed. They are the game's chatter now, on screen when
config.toml's game.console_log is "all", like the rest of it; print and
inspect typed at the console still answer whatever the setting is.
(cherry picked from commit 114453cc1a84be4fc5622053d2afb57c1ae58e7f)
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 checkpoint (game_save) waits for a safe moment and gives up after
240 ticks; it checks every 10. Those counts were advanced once a frame,
which on the Xbox was once a tick. At 60 frames a second or more a
checkpoint gave up in a few seconds or less, often before the fight it
waited for was over, so few checkpoints came: on Halo (a30) the player
could get only the first. The counts now advance once a game tick, as
the Xbox's did: 8 seconds at any frame rate.
tools/test_checkpoint_timing.py checks it at 30 to 990 frames a second.
(cherry picked from commit abc42998232b6261220a764e6de44641067ff2f5)
A screen's button bar (SELECT and BACK under a list) steps sideways, so
once the wheel scrolled past a list's last row onto the bar it went back
and forth between the two buttons until a row was chosen again with the
mouse. A touch drag already left the bar with up and down, as the d-pad
does; the wheel now does the same.
(cherry picked from commit 2ddad079fa5435a70a383d757de16b960c421505)
debug_objects_unit_mouth_apeture placed its label at an uninitialized
marker when the unit had no head.
(cherry picked from commit a56597a9666a354a0a8f9e7f2e017cc418d4922a)
A machine still downloading the map when the game started has its players held out of it until the download finishes (OpenCE's). One whose download did not finish before the game ended came back to the pregame without its players, as the reset dropped the held ones; they are put back in the game's list instead, as the other players are kept.
(cherry picked from commit 6aa90bfb59557b8c98e2c8543aa4c42d9e3918c1)
On a network client the overshield's drain arrives with the host's updates
after the HUD has taken its last shield value for the tick, so every frame
the shield looked a step lower than the HUD remembered and the shield
damage sound played for the whole overshield. The Xbox plays nothing.
The meter's flash already told the drain from a hit (a step of 0.05 or
less from past full); the sound now uses the same test, so a drain is
silent on host and client while a real hit on an overshield still flashes
and sounds.
(cherry picked from commit fd9c918313076ecc686209a0f4c75a6ef23340c4)
The kill announcement picked Running Riot whenever the killer's kills in a
row were a multiple of five, and zero is one. On the Xbox the killer had
just been credited with the kill, so it was never zero; a network client's
copy of the statistics can have the kill credited to no one or to someone
else until the host's statistics arrive, and announced Running Riot after
one or two kills.
A killer with no kills in a row now gets the plain kill message.
(cherry picked from commit 1b6cf950532f6d9590690c86c253def5395a132f)
build_game_variant_team_oddball left its variant uninitialized while
every other builder clears it, so the fields it does not set (the name
and the flags beyond those it sets among them) were whatever was on the
stack.
(cherry picked from commit 4c3e7664aab234e1b56a84a3b3dd3c8d1bebf58a)
A failed CreateVertexBuffer or CreateIndexBuffer may leave its output
unwritten, which was then tested uninitialized.
(cherry picked from commit 28f0a433093e4b7d6082123b45e19fd37beee262)
A ground contrail (or another type the renderer lacks) left its
triangle and vertex buffers locked and allocated, and the rasterizer's
lock operation set, for every frame it was drawn.
(cherry picked from commit b335386569e840c601eaf238d7585c73fa60516c)
(cherry picked from commit 56f5d99b1d6e81c30c4021c2437b2bd71475c83d)
A weapon's charging loop still on a channel as a network game ended
("still counted as playing ... let go", sound_cache_close) was finished
by the next map's sound_render against the next map's sound cache, which
halted the game as the next network game loaded (data.c: xbox sound index
is unused or changed). sound_dispose_from_old_map stops every channel
still holding a permutation, so its count is given back while the map's
sounds are there.
(cherry picked from commit 8e5b3f9f23beb9f015a0caf487caa82ada16c73e)