189 Commits
Author SHA1 Message Date
Stefan MaierandClaude Opus 5.5 9ef32d4304 Merge upstream/main (2026-10-24): OpenCE network version 38
OpenCE gametypes named in the server browser (network version 37), and
the host may leave the shield effects to each player (SHIELD EFFECTS'
PLAYERS' OWN, network version 38). The conflict: our Android listing
declarations stay beside upstream's p2p_set_game_listing with its new
kind.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 10:00:39 +02:00
MrBruh dc7feb1c41 Name OpenCE gametypes in the server browser (SWAT, HC CTF), sending each game's kind with its LAN advertisement and internet listing in network version 37. 2026-10-24 13:44:16 +13:00
Stefan MaierandClaude Opus 5.5 24ddaecd78 Merge upstream/main (2026-10-23): OpenCE network version 36
New gametypes (SWAT, Infection, Gun Game, Hardcore), shield effects the
host's choice in network games, co-op ally friendly fire, network fixes
(scenery shields, tripmines, co-op teleports), Custom Edition HUD and
texture fixes, ASTC for Android GPUs without S3TC.

Left out on purpose: upstream's two Android workarounds for Mali phones,
the GL shadow state refreshed before every draw (prepare_draw) and the
geometry cache bypassed (mirror_range). Both would cost every draw of
both eyes on the Quest, which never showed the corruption they work
around; their tests are skipped. Conflicts: the GL capabilities log
keeps multiview and adds ASTC; xbox_textures.c keeps vr.c's texture work
counters; README.md stays the player's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 21:58:11 +02:00
GuvenandClaude Opus 5.5 1d38b3f936 Co-op hosts can make the players' AI allies immune to their fire
Server Setup's Co-op Options has ALLY FRIENDLY FIRE
(network.coop_ally_friendly_fire), ON by default as in the campaign. OFF,
the players' weapons, grenades, melee and vehicles do their AI allies no
damage, so that no player can kill Captain Keyes on Truth and
Reconciliation, the Marines, or the other allies a level needs. The AI's
own hits of its allies, the enemies' damage, and FRIENDLY FIRE between
players are unchanged. A hit is the players' when its owner is a player
and the victim is a friendly unit that is no player's, so friendly-team
vehicles are immune to the players too, splatter included. An ally that
cannot die cannot raise an allegiance incident, so the players cannot turn
the Marines hostile either.

The rule is in game_engine_friendly_damage (game_engine.c), which only the
host's damage reaches: a client's hits are the host's to deal. The host
sends the choice with the game's settings, as bit 1 of network_game's
cooperative_flags beside PLAYER COLLISIONS', so network version 33: a
client of version 32 would play the game's settings without it. NETCODE.md
says so, and network_format.txt is recorded for 33.

The menu row is tools/port_settings.py's (COOP_SETUP_SCREENS); only the
server settings screen was written again. Its 8 rows fit above the help
area.

Checked: the Windows build; the harness tests, the new
test_coop_ally_friendly_fire (a player's hit of an ally ON and OFF, the
AI's own hit, players' friendly fire in every mode, no unit, the campaign
without co-op, and four negative controls) and test_coop_scaling_menu with
the eighth row; network_format.py; the Co-op Options screen drawn with the
row; and in play as the host on a10 and a50 (Keyes and the Marines
unharmed with OFF) and b30 (no splatter). Not yet: a client's hits online,
d20's ending, c20's Sentinels.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 10:45:03 +01:00
Stefan MaierandClaude Opus 5.5 8097ac23b0 Merge OpenCE upstream: network version 32, HDR, model detail, texture filtering, co-op options, aim assist policy, its local bots, 5.1 sound
Ringfall's side of it:
- The bots: OpenCE's own (bots.c, a local split screen game's) are not
  used in VR builds (their lobby hook would take Ringfall's host bots
  off, and their bots.count and bots.skill differ); Ringfall's are now
  host_bots.c, so that OpenCE's bots.c merges as it changes. Each
  platform's bots.count and bots.skill are its own (config_setting_index
  takes this platform's of two of a name).
- HDR is never on in VR (d3d8_gl.c); the flat window's present is
  OpenCE's, inside the VR port's branch for it.
- The VR frame begins where the events are pumped (sdl_platform.c), as
  before, now that exit_after_check is apart.
- The message numbers: OpenCE's aim assist policy (90) before the VR
  port's poses (240), which stay last.
- The visibility counters keep the VR port's snapshot ring (both eyes'
  counts halved); OpenCE's tone mapping goes before the antialiasing, off
  the VR eyes' pass.
- Join codes, the online list and OpenCE's probes all in the signalling
  topics; the HUD's PNG helpers both ways; the disc import keeps the
  language file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 19:10:30 +02:00
MrBruh 22f8beb771 Merge pull request #367 from BirchWoodGod/feat/bots-core
Bots for local Slayer games (bots.count, off by default)
2026-10-20 01:56:14 +13:00
MrBruh 69ec31a49d Merge pull request #328 from GiovanH/fix/split-screen-start-now
Port: Allow split-screen play in PC menus
2026-10-20 00:07:31 +13:00
MrBruh 5aafe7af9e Mark the second batch's changes to the game's sources as the port's
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.
2026-10-19 23:06:19 +13:00
xshxdex98 44da7f8265 Web: no second's wait leaving a hosted game
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)
2026-10-19 22:59:22 +13:00
xshxdex98 64084d77af LAN: a game search from off the client port answered directly
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)
2026-10-19 22:30:58 +13:00
xshxdex98 1eb3db02d9 Netcode: a datagram's source port kept with it
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)
2026-10-19 22:30:58 +13:00
xshxdex98 b6dba5a621 Netcode: a second game on the host's computer gets the host's per-tick state
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)
2026-10-19 22:30:58 +13:00
Milenko 94209aaaf6 Hosts that run their own games clear the joins a finished game left queued
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)
2026-10-19 22:30:16 +13:00
MrBruh 7153e0b717 Mark the picked fixes to the game's sources as the port's
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.
2026-10-19 22:05:16 +13:00
Milenko 904fbbfc1e Network: the pregame keep-alive is a long, as on the wire
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)
2026-10-19 21:49:02 +13:00
xshxdex98 05d7fd38fc Server: players held for a map download are the pregame's again after the game
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)
2026-10-19 21:48:24 +13:00
MrBruh 951ec3b017 Merge pull request #339 from FractumSeraph/map-share-game-start
A client is not started before the map it downloads is there
2026-10-19 21:15:11 +13:00
Stefan MaierandClaude Opus 5.5 62dee62eb6 A lobby the bots fill is open to a person on the LAN too
The bots make room for a person who joins, and the server browser's
listing counted their slots as free, but the LAN advertisement and the
join's check still asked for a free slot: with 15 bots and the host a
lobby of 16 was advertised closed, and a Quest on the LAN was refused
("attempted to join a closed game"). Both now count a bot's slot in a
lobby as a person's, as the listing does (network_game_server_room_for_person).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 17:59:49 +02:00
BirchWoodGodandClaude Opus 5.5 4a275b608d Add bots to local Slayer games (bots.count, off by default)
Computer players for a game played on this computer alone: bots.count (0,
the default, to 15) of them join the lobby of a local split screen Slayer
game, as far as it has room, on the teams bots.teams asks for ("even", or
"against" the players), and follow the players' team changes there. A bot
is the one player of a machine of its own at the top of the machine indices
(113 up), which no real machine takes, so every machine of the game - only
this one - spawns, respawns and scores it as any player.
network_server_manager.c adds and removes them in the pregame;
players_update_before_game takes each bot's action of the tick from
port/linux/game/bots.c in place of its empty queue.

A bot looks for enemies (the AI's line of sight, its skill's reach and
field of view), reacts, turns at a limited speed with an aim error that
settles and leads by its weapon's projectile speed, fires in bursts or a
press a shot, throws grenades, strikes close up and strafes; otherwise it
goes where an enemy was last seen, to a better weapon lying near (the
action button once the game offers the swap), or about the map's starting
locations and item spawns. It walks the paths the campaign's AI finds:
path.c's searches over the walkable surfaces every stock multiplayer map
carries, on a copy of them less those with no room above (Longest's walls)
and those under scenery or machines its path's obstacle avoidance found no
way past (Sidewinder's blast door); stuck, it jumps, sidesteps and looks
again. The searches run in the tick, three a tick at most, so two runs of
the same input play the same. bots.skill sets reaction, sight, aim, turning
and bursts; debug.bot_trace logs each bot's state.

Nothing changes in system link or internet games: no bot joins a game that
accepts remote connections, and bots_update_actions returns unless a local
game runs, so nothing the machines send each other changes and the network
version stays the same. Other gametypes get no bots yet (their goals come
in a later change). The code is BirchWoodGod's, from the Halo CE for PS
Vita port's offline bots, contributed under CC0; this is their core.

Checked (Linux, debug and release builds, SDL's offscreen video driver,
debug.network_test "local:" with debug.test_input "bot:1" as the player):
- 150 s games on Blood Gulch (Slayer, 6 bots; Team Slayer, 7, legendary),
  Chill Out (Team Slayer, 5, heroic), Longest (Slayer, 8), Sidewinder (Team
  Slayer, 9), Hang 'em High (Team Slayer, 5, "against"), Damnation (Slayer,
  6, easy) and Prisoner (Slayer, 15): every bot walked 125-280 units, the
  bots killed 7-118 times and died, teams evened or all against the
  player, and every game ended cleanly with no assert. With
  debug.bot_trace, bots took up rocket launchers, shotguns and sniper
  rifles, and debug.txt had none of the distributed netcode's idle action
  lines.
- bots.count 0: a 60 s local game logs the same lines as origin/main with
  only the network test's local mode (numbers apart), and config.toml
  differs only by the new settings' lines (and the network test's
  comment). bots.count 6 in a system link
  game (host:) and in a local CTF game: no bot joins, nothing logged.
- ninja web and ninja android (Emscripten 6.0.10, NDK r27c) build, debug
  and release.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011ucYZ9cvWn3nrnk7kK3S5X
2026-10-15 00:27:32 -05:00
Stefan MaierandClaude Opus 5.5 87fe9fc1ad Merge OpenCE upstream: network version 29, Custom Edition maps keep their names, map sharing hardened
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 13:04:54 +02:00
MrBruh 3e0ba55111 Keep Custom Edition maps' own names: the version goes in the game record
A game's level name is the map's own (custom_maps\hugeass), so no screen or
server browser listing shows a hash, and the game record's map version is
the map's hash's first 32 bits, which a client finds its file by. Maps are
no longer renamed; a download beside another version of its name is named
<name>_<hash>.map and listed as "(2)"; maps the last build renamed get
their names back. Network version 29: the level name and the map version
mean something else.
2026-10-14 23:08:39 +13:00
FractumSeraphandClaude Opus 5.5 62379e5614 A client is not started before the map it downloads is there
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>
2026-10-13 08:41:59 -05:00
Gio aa51dfccc6 Port: Allow split-screen play in PC menus
On the "pc" menu style, a LAN game whose players were all on the host's
computer could not start a local splitscreen game. This patch fixes that
check.

START NOW only starts a countdown for a game that takes no remote connections, has two machines, or
is "alone" (server_alone). server_alone only passed if there was literally one player, making splitscreen play impossible.
Note the "xbox" menu style did not have this bug since its splitscreen
didn't accept remote connections at all.

server_alone becomes server_players_on_one_machine: TRUE if there is at
least one player and every player is on the same machine.
One player still qualifies. Machines that have joined without a player are not
counted, so a lone host's countdown is not stopped when one connects (the
per-tick server_ok_to_countdown check).

The countdown is fully controlled by the host machine, so there is no
change to the network protocol.

There's an existing test failure on test_elevator_prediction which also
exists on main, ignore.
2026-10-12 20:13:42 -05:00
Stefan MaierandClaude Opus 5.5 7c6fa07cb5 Merge upstream 2026-10-12: network version 28, map sharing, pregame lobby, body and BSP fixes
Conflicts:
- rasterizer.h: upstream raised the transparent geometry groups to 2048
  as we had (halo_port_capacity.h); theirs.
- d3d8_gl.c: the ES capabilities' log with upstream's base vertex and our
  multiview.
- p2p.c, p2p_internal.h, p2p_signal.c: upstream's several joins and
  reconnect, with our join codes' state and the codes' and public list's
  updates each pass.
- network_server_manager.c: a machine downloading the map is not refused,
  and the bots' room logic stays.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 11:23:08 +02: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
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
justinfilip 67f2214219 A player still downloading the map no longer spawns until that player joins. 2026-10-11 17:03:37 -05: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
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
Stefan MaierandClaude Opus 5.5 74bdffb957 Merge upstream 2026-10-11: network version 26, first-person legs and shield flare, web port, fixes
Conflicts:
- render_objects.c: upstream's first-person legs and our VR body share one
  node_matrices (ours no longer shadowed it); upstream's legs never in VR
  (first_person_legs_wanted: set back behind a flat view's eye, they would
  stand behind the player; the VR body is vr.body "full").
- AndroidManifest.xml: upstream's ':game' process left out (the Steam
  Frame's Lepton waits for the app's process to end; the headsets have no
  Java heap over the Xbox window); HaloApplication kept, idle without it.
- xinput_sdl.c: the touch controls and the web port's, never in VR; the
  controllers' rumble in VR before the phone's.
- d3d8_gl.c: multiview's uniforms and upstream's blend constant, both.
- build.yml: Android only; upstream's web and pages jobs off.
- README.md: ours; upstream's in docs/OPENCE_README.md.
- menu_tags.c: our VR pause-list fit dropped: upstream now spaces the rows
  30 apart and moves the button hints below them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 14:04:08 +02:00
MrBruh acfa9a2a4d Web build 2026-10-11 12:46:28 +13:00
MrBruh fb97e52663 Stale player handles forgotten in the port's loop (#250) 2026-10-11 11:54:50 +13:00
eltanschauung 6ea142ceee Fix co-op stale player handle crash 2026-10-10 15:30:31 -04:00
Stefan MaierandClaude Opus 5.5 b6a943f1a6 Merge upstream 2026-10-10: network version 25, touch controls, in-game settings, FOV options, voice chat, votekick
248 OpenCE commits (network version 25): touch controls and touch menus for
phones, single-player in-game Settings, opt-in FOV/viewmodel settings, voice
chat and votes to kick, lens flare culling, memory leak fixes (render
targets, gamepads, the Android audio stream), profiling builds, the
HALO_ANDROID split into HALO_ARM64_GUEST / HALO_GLES / HALO_ANDROID.

Conflicts and how they were resolved:
- README.md: ours kept whole. Upstream's README changes (portable build,
  profiling builds) went into docs/OPENCE_README.md: upstream's new text
  with our header note, links rewritten to ../ and our "made from your own
  copy" wording.
- port/android/README.md: both merged; upstream's touch, WSL and save
  notes taken, with our application id in every adb path; our VR section,
  signing.properties and wording kept; the stale "How it works" list
  dropped as upstream dropped it.
- Launcher icons (mipmap-*/ic_launcher_foreground.png, art/android-icon.png):
  ours (the Ringfall art). Upstream's helmet monochrome layers,
  drawable/ic_launcher_background.xml and its ic_launcher.xml were left out;
  our ic_launcher.xml, values/ic_launcher_background.xml and
  tools/android_icon.py stay. (port/assets/icon and tools/app_icon.py come
  in for the desktop builds' window icon only; do not run app_icon.py, it
  would write the helmet into the Android resources.)
- port/android/host/host_main.c: both config helpers kept, and upstream's
  emulator write tracking (native_bridge_active); upstream's display width
  block dropped in favour of ours (640 in VR) and its display density for
  the touch controls moved into our flat (non-VR) branch.
- port/linux/game/menu_functions.c: platform_text_field(typing, password)
  from upstream; the VR keyboard launch for text fields kept after it.
- port/linux/game/network_distributed.c: upstream's profile_scope wrappers,
  with network_vr_tick and bots_tick kept in their places.
- port/linux/src/dsound_sdl.c: both (our debug.audio_log, upstream's
  audio.output_device).
- port/linux/src/port_config.c: our temp-and-rename config write kept,
  under upstream's HALO_ARM64_GUEST (it is guest file I/O).
- port/linux/src/sdl_platform.c/.h: upstream's (Android menu pointer from
  the touchscreen, Steam keyboard, scoreboard pointer); our quit marker for
  the Steam Frame launcher, clipboard_seen and VR frame hooks kept. Our
  flat-mouse menu pointer (an emulator aid) is replaced by upstream's touch
  pointer, which also drives the menus on the emulator.
- port/linux/src/d3d8_gl.c: halo_ui_pointer_update is upstream's, with the
  VR controller ray taking over while VR is active (the touchscreen then
  is not the pointer); our persistent-buffer writes kept for stream and
  index uploads, now writing upstream's exact length and under HALO_GLES
  like the code around them (stream_reserve, index_upload, mirror_refresh
  too); multiview uniforms stay under HALO_ANDROID, the counter binding
  under HALO_GLES. Visibility counters: ours kept (the snapshot ring with
  multiview views, host_gl_counters_snapshot) over upstream's per-frame
  glCopyBufferSubData into counter_snapshots: ours reads finished frames
  without stalling and counts both eyes' samples once; upstream's
  desktop query batches come in unchanged.
- port/linux/src/xinput_sdl.c: both (VR controllers and touch controls).
  In VR the touch controls neither show nor act (touch_input_gamepad,
  touch_input_controls, touch move/look skipped); rumble goes to the
  controllers in VR, to the phone otherwise.
- source/interface/first_person_weapons.c: both (VR scope pass check and
  display.viewmodel_visible).
- source/interface/ui_widget.c: upstream's reworked menu targets taken
  (ui_mouse_fit_button_targets, merged rows, widened values), which do
  what our icon_x0 key picking and the 12-unit value arrows did; our VR
  label distance (25) kept, and a VR ray counts as a coarse pointer, so it
  gets the taller legend areas and the widened values (not the merged
  rows: a row's label still presses A). Our join code and VR options
  panels kept; their early return now forgets the frame's targets too.
  The on-screen keyboard: upstream's virtual_keyboard_click for taps and
  the mouse, ours (hover highlights the key) for the VR ray only.
- source/main/main.c: both (VR phases around upstream's profile scopes).

VR guards for new upstream features:
- view_fov.c: display.fov, display.viewmodel_fov and
  display.viewmodel_visible do nothing while VR is active (the headset
  gives each eye's frustum; the weapon is in the hand).
- Touch controls: off in VR (xinput_sdl.c), the menus' touch pointer too
  (d3d8_gl.c); the overlay stays hidden as the game never reports a scene.
- Lens flare culling (744040c8, b1a71709) uses global_window_parameters'
  frustum, which in VR is each eye's (per-eye passes) or the union frustum
  of the multiview centre camera: no change needed.
- In-game Settings: VR options still open with Y on the main and pause
  menus (checked flat with debug.vr_options).
- The back button change (enableOnBackInvokedCallback=false) keeps the
  legacy KEYCODE_BACK path, which targetSdk 35 already had: no change on
  Quest or Frame.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 08:51:46 +02:00
Milenko 2db3174366 Server: a banned machine's join is refused as banned
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)
2026-10-10 13:59:03 +13:00
Milenko 0fb9b57605 Telnet console: a client sending an HTTP request is dropped
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)
2026-10-10 12:53:23 +13:00
xshxdex98 ab3c388c15 Joining: a connection made is open, whatever came before it
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)
2026-10-10 12:53:22 +13:00
MrBruh db9be6a002 Maps named com or lpt are not devices (#206)
Only con, prn, aux and nul are devices by their three letters; com and lpt are with a digit after them.
2026-10-09 21:05:07 +13:00
MrBruh 7cd56c95e4 Merge pull request #206 from ChupathingyCE/upstream-fix/map-name-devices
Refuse a host's map name that is a Windows device name
2026-10-09 21:05:02 +13:00
MrBruh f89a6fad45 Merge pull request #192 from ChupathingyCE/upstream-fix/map-name-brackets
Join games on maps whose names have [ ] ( ) or +
2026-10-09 20:48:18 +13:00
MrBruh cfa1a488ec Merge pull request #216 from eltanschauung/fix/create-game-teardown-delay
Remove redundant 1000ms hang on Create Game options
2026-10-09 18:46:28 +13:00
MrBruh f97b33391b Voice chat
Opus voice chat (port/third_party/opus 1.5.2, port/linux/src/voice_audio.c, port/linux/game/network_voice.c), relayed by the host, in the lobby too. The host decides in Server Setup > Teamplay Options: lobby voice (on by default), the game's mode (off, team near, anyone near, team, team and enemies near: the default), the near distance, and the quality, 8 to 64 kbps (24). Each player picks push to talk (V), open mic or off, the voices' volume, and the output and input devices in Settings > Audio, and mutes others from the scoreboard's menu. A speaker icon marks who talks in the lobby, on the scoreboard and in a list in game. The host takes a machine's frames only with the key it gave it over its stream, within the quality's size, 50 a second and 8 talkers at once, and sends voices only to machines that asked for them, so the network version stays.
2026-10-09 14:20:57 +13:00
eltanschauung 3a6e146fdb Remove redundant 1000ms hang on Create Game options 2026-10-08 17:25:37 -04:00
MrBruh 3b20ef879a Votes to kick
Any player of a network game can start a vote to kick another, on any team, by picking their name on the scoreboard (right-click while it is open frees the mouse) or with the console's votekick; the host's own scoreboard also has Kick and Ban (Ban picked twice). The host alone counts (port/linux/game/network_votekick.c): votes only from each voter's stream, one per real address and again per hardware id (which only removes votes), time played on the host before starting (network.votekick_minutes) and voting, more than half of everyone with the target counted and at least two, one vote at a time with cooldowns for a failed vote's starter and target, and a passed vote keeps the player out for network.votekick_ban_minutes. Builds without it drop the new messages, so the network version stays.
2026-10-09 10:07:51 +13:00
Stefan MaierandClaude Opus 5.5 a167de3873 Merge upstream 2026-10-08: network version 24, Custom Edition maps, positional stereo sound, fixes
Conflicts:
- d3d8_gl.c, xgpu.h: upstream's own snapshot ring for the visibility
  counters left out for ours (host_gl_counters_snapshot, the same idea,
  tried on both headsets, which also halves multiview's counts; its copy
  already has the memory barrier upstream added); both declarations kept.
- rasterizer_xbox.c: the mirrored skinning's winding and upstream's
  many-node matrices, both.
- main.c, network_server_manager.c: both (bots' machines and a lone host
  may count down).
- android_build.py: the OpenXR loader and upstream's SDL mouse patch
  (another SDL file than ours), both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 21:01:08 +02:00
Milenko 5aad51ac18 Refuse a host's map name that is a Windows device name
A host's map name of con, nul, com1 and the like made a client on Windows
open that device as the map, which could hang it. Such names are now
refused with the other invalid map names.
2026-10-08 08:30:56 -04:00
Milenko 9fa925c3b0 Join games on maps whose names have [ ] ( ) or +
A client refused a host's map name with any character outside letters,
digits and _ - . space and backslash, so a game on a Custom Edition map
named like [H2]_Lockout could not be joined. These five characters mean
nothing to a path and are now accepted too.
2026-10-08 08:29:26 -04:00
TwistedFlog 6b1d81c7b1 Custom Edition Map Discrepancy Fixes
Fixed: Weapons whose trigger had flag "analog rate of fire" now read how far the trigger is pulled: fully for mouse/keyboard, the actual pressure for a controller trigger. Before they never fired.
source/input/input_abstraction.c
source/input/input_abstraction.h
source/game/player_control.c

Fixed: Weapon spawn orientation on Custom Edition maps. Multiplayer weapons and items now spawn facing the way the map places them, as in Halo PC.
source/game/game_engine.c

Added: PC vehicle set. There's a new PC option in the vehicle set list, between Gun Turrets and Custom. A team set to PC gets every vehicle the map places, as in Halo PC. On Custom Edition maps that means every placement whose spawn flags name the gametype.
port/assets/menus/ce/strings.xml
port/linux/game/menu_functions.c
source/game/game_engine.h
source/game/game_engine.c

Added: Start LAN, internet and split screen games alone. A game with one machine and one player can now start. Pressing start alone begins the countdown, others can join while the game is in progress, and the lobby no longer says it's waiting for another machine or player.
source/networking/network_server_manager.c
source/interface/ui_widget_game_data_input_functions.c
2026-10-07 17:45:15 -06:00
xshxdex98 9d309f8d75 Refuse a Custom Edition map of another version than the host's
A client joining a game on a Custom Edition map checked only that it had a
file of that name. With another version of the map (an older release, a
re-edit), its tags are not the host's: the objects, weapons and vehicles the
host sends are other things there, and the game desyncs or crashes.

The host now sends its map file's header checksum as the game record's map
version, which the Xbox game always left 0, and a client whose copy has
another checksum leaves with an error saying so and where to copy the
host's. The record's layout is unchanged: a host that sends 0 (an older
one, or the game's own maps, whose builds of other regions play together)
is not checked, and older clients ignore the field.
2026-10-07 13:13:29 -05:00