Commit Graph
2610 Commits
Author SHA1 Message Date
MrBruh 5a35ea2b20 Network version 18
Fixups for #99 and #112: the version raised for the object message's
shader permutation, NETCODE.md brought up to date, a networked glass
break's sound placed where it broke, a frame scratch pool that runs out
logged once, and the new comments marked as the port's.
2026-10-06 13:39:26 +13:00
MrBruh 2e179ea90f Merge pull request #112 from innerhat-dev/networked-break-and-frame-scratch 2026-10-06 13:34:53 +13:00
MrBruh 595bbc5611 Merge pull request #113 from xshxdex98/quiet-garbage-collection 2026-10-06 13:29:02 +13:00
MrBruh 761210d405 Harden map and network input 2026-10-06 13:26:43 +13:00
xshxdex98 7ba780ef59 Garbage collection's notices are chatter: on screen only with console_log = "all"
With many enemies (co-op's extra enemies) object memory runs low and the
garbage collector prints "garbage collection critical" and "removing
objects" at every pass, filling the screen for the host and every client.
They are the game's own chatter, so they show as game.console_log says, as
the sound and texture caches' already do; the log keeps every line.
2026-10-05 18:55:53 -05:00
justinfilip d9c43e3478 Keep a networked glass break from reading the scenario as a damage effect.
The host's notice of a broken surface carries no damage effect. The client filled a damage record with zeros and then read tag 0, which is the scenario, and halted. Shards still spawn. They skip the kick from an effect this machine never received.

The frame scratch pool was still the Xbox size after the particle pool grew eight times, so a busy level spent it every frame. It now grows with that particle pool, and a frame that still runs out is logged once.

A console line longer than the buffer halted inside the error printer, before the reason was written to the log. Long lines are cut to fit, and the reason is written first.
2026-10-05 17:19:35 -05:00
MrBruh 2b0327bc80 Network version 17
Fixups for #102, #103 and #105-#107: the version raised for the glass,
scenery, cutscene cluster and revert messages, NETCODE.md brought up to
date, co-op's followers' object lists freed as soon as they are used, and
extra enemies that find no free ground placed on the rings they used before
rather than left out (at 32x a quarter of them were), with the places found
taken not tried again for the rest of the squad, and the way to a place
looked along level.
2026-10-06 08:59:22 +13:00
MrBruh 58aa352705 Merge pull request #107 from xshxdex98/sync-glass-and-scenery 2026-10-06 08:40:24 +13:00
MrBruh 59c4b2160e Merge pull request #106 from xshxdex98/coop-scripts-for-everyone 2026-10-06 08:40:24 +13:00
MrBruh 1cf336f0ff Merge pull request #105 from xshxdex98/coop-enemy-spread 2026-10-06 08:40:24 +13:00
MrBruh d10969dc83 Merge pull request #103 from xshxdex98/coop-backtrack-team 2026-10-06 08:40:24 +13:00
MrBruh 197c199473 Improve performance by ~80% with many enemies
The Silent Cartographer with 32x co-op enemies (484 actors) went from 53
to about 97 fps on the Linux PC, with the same game and the same picture:
cluster list removals start where the reference was put, full data arrays
are not walked again, object lighting keeps each cluster's drawn lights
and passes over far ones without their distance, the per-texture profile
timer only runs while something reads it, and the renderer binds streams
once per draw, caches its texture, target and shader lookups, and no
longer makes Mesa's GL thread wait on large uploads or visibility tests.
2026-10-06 08:13:44 +13:00
xshxdex98 1e74e9b03e Co-op scripts: follower actions named, the skip's revert plainer
What the followers of player0 do (teleport, suspend, get out, board) is a
function each in coop_scripts.c, so every engine hook is one call. The
cutscene skip reverts only in a local game or on a co-op host, written as
two plain branches; a non-co-op network host no longer reverts alone.
2026-10-05 13:10:29 -05:00
xshxdex98 7a1ffca28b Network: glass and destructible scenery break the same for everyone
Breakable surfaces (glass) are broken by each machine's own projectiles
with its own random damage, so a pane could shatter on the host and stay
whole, still blocking, on a client. In co-op the host now sends each break
(and a few again every refresh, for late joiners), and a client breaks the
same surface with its shards.

Destructible scenery and devices (lights, panels) are the map's, at the
same index on every machine, but only damage to units was synced: a
client's shots never damaged them, and what the host broke didn't break
or play its effects on the clients. A client now reports its hits on them
like any other, the host checks and deals them, and every client deals the
host's damage to its own copy, which breaks, plays its effects and is
destroyed as the host's was.

Both are new message kinds that a client without them ignores, so the
network version is unchanged.
2026-10-05 13:00:01 -05:00
xshxdex98 b843156fe8 Network: a client never reverts its game on its own
The pause menu's revert (main_revert_map) reverted a network client's own
game state, leaving it out of step with the host. A client now ignores it,
and the cutscene skip's local revert, which a client only reaches outside
the co-op vote, is the host's or a local game's alone.
2026-10-05 12:59:00 -05:00
xshxdex98 99a31ca82d Co-op: a cutscene waiting until it's safe waits for one safe player
The scripts check game_safe_to_save before some cutscenes (the Maw's
bridge). The game's test fails while any enemy sees any player, so with
players spread out a fight elsewhere held up the cutscene a player had
reached. For the scripts in co-op, one player alive, on the ground and
unseen is enough; checkpoints keep the game's own test.
2026-10-05 12:58:59 -05:00
xshxdex98 8e6b9a211e Co-op: triggers, cutscenes and failed missions work for every player
The campaign scripts only run on the host, against every player's unit,
but some of their habits assumed split-screen:

- volume_test_objects_all on the players waited for every player in the
  volume at once: the Maw's bridge cutscene, a30's Pelican pickups. In
  co-op one player arriving is enough now.
- Scripts name players as player0 and player1, so everyone past the
  second was left out of what they did: Pelican loads (a30's pickups,
  insertions), getting out, cutscene teleports and freezes, starting
  profiles. Those players now follow player0 (coop_scripts.c).
- A cutscene filmed far from every player (b30's sword Elite at the
  shaft door) wasn't active on clients: the cluster the scripts force
  active (object_pvs_activate) now rides in the presentation's spare
  bytes, and what the host's camera films is sent to clients as often as
  what is next to their players.
- A mission the scripts fail (d40's timer, a50's Keyes) only respawned the
  players, leaving them in the failure cutscene for good. It now reverts
  like the cutscene skip does; everyone dying still respawns at the last
  checkpoint. The scripts' game_revert reverts the same way.

The network version is unchanged: the presentation keeps its size, and a
host without the active cluster sends zeroes, which read as none.
2026-10-05 12:43:48 -05:00
xshxdex98 d0016bca89 Co-op extra enemies: spread onto free ground, never stacked
An extra enemy was placed on a ring around its starting location, trying
one spot per ring, and checked only against walls. When the 8 tries failed
(tight corridors, the Maw's interiors) it went on the starting location
itself, on top of the squad's own actor, and nothing stopped it landing on
another starting location's actor a metre away.

Now every spot of each ring is tried (a ring holds more spots the further
out it is), and a spot needs ground under it, no wall in the way and no
biped within 0.6 m or vehicle around it. A starting location with no room
passes its enemy to the squad's next one, and with no room anywhere the
enemy isn't placed. Dropship riders released beside the ones who jumped
out are spread the same way.
2026-10-05 12:41:08 -05:00
xshxdex98 a143d9490d Co-op: tell a player held back at a loading zone what it waits for
Going back to a BSP the team has been in waits for two thirds of the team,
and a player on the trigger was never told so. They now see "Waiting for
your team to go back: 1 of 2 here", at once and every three seconds while
they wait. Each machine works it out for its own players with the count the
host decides by, now one function, so nothing new goes over the network.
2026-10-05 08:51:49 -05:00
xshxdex98 e55c29a97e Co-op: going back counts the team within 45 metres, not 12
Two thirds of the players had to be in the loading zone or within 4 world
units of whoever was in it. A team walking back through a doorway in a line
is longer than that, so going back almost never switched: the first player
walked on past the loaded level, fell and was brought back to the team.
15 world units fits a team moving together and still not a player who ran
back alone.
2026-10-05 08:51:49 -05:00
xshxdex98 087ca8a875 Co-op: every machine stays on the host's BSP
Players in big sessions ended up on different BSPs:

- The host told clients about a switch only every half second, and not
  reliably, so a client could predict its player for a while in a BSP it
  hadn't loaded. A switch is now sent at once, reliably, ahead of the
  players' new positions.
- A client still loading reports so: its input carries the BSP it has
  loaded. Until it has the host's, the host takes none of its movement
  (which falls there with no floor) and none of its loading zones.
- After a switch, by a trigger, a script or a skipped cutscene, no trigger
  can switch again until every machine has loaded the new BSP (at most
  ten seconds), so no client falls two switches behind.
- A player the host can't place beside whoever crossed, when a big team
  runs out of room there, is placed beside another teammate instead of
  being left where they were.
2026-10-05 08:09:46 -05:00
MrBruh d1825ab08d Merge pull request #96 from xshxdex98/coop-backtrack-gate 2026-10-06 01:24:22 +13:00
xshxdex98 8dc796028e Co-op: going back to a visited BSP needs two thirds of the team
One player who stayed behind or went AFK no longer blocks the team.
2026-10-05 07:14:28 -05:00
xshxdex98 c3f82fa9b2 Co-op: going back to a BSP already visited needs the whole team there
A loading zone brings the whole team to whoever crosses it. Into a new part
of the level that's what you want, but it let one player drag everyone
back. A switch back to a BSP the team has been in now waits until every
living player is in the trigger or near the player in it.
2026-10-05 07:01:32 -05:00
xshxdex98 5ff4b6ee8d Co-op: clients take the host's allegiances
The scripts make allegiances (ai_allegiance player human) and only the host
runs them, so on clients marines stayed enemies of the players: red reticles
and the wrong team. The host sends its ally and friend tables with the
presentation each tick.
2026-10-05 07:01:26 -05:00
MrBruh 2ed4a7b49d Merge pull request #92 from xshxdex98/coop-flood-dropships 2026-10-06 00:51:36 +13:00
MrBruh 503992d544 Merge pull request #91 from xshxdex98/coop-device-states 2026-10-06 00:51:35 +13:00
xshxdex98 862d88737e Co-op: Flood bodies get up on clients; dropship doors open and close there
- A body the host's unit got back up from (a Flood combat form feigning
  death) gets up on the clients too, instead of its ragdoll being dragged
  about. The resurrection is one function both use (unit_port_resurrect).
- The scripts' unit_open and unit_close go to the clients, so dropships'
  doors aren't left open there.
2026-10-05 06:36:27 -05:00
xshxdex98 8610b28376 Co-op: doors and elevators are where the host has them
The host sends each device's position and power when they change (and with
the resent state), and a client puts its device there when the host's is at
rest and they differ, or when they drift apart while it moves. Clients only
had the device groups' values, which aim a device: a door could stop half
open, and an elevator be somewhere else on a client, so its players fell.
2026-10-05 06:36:27 -05:00
xshxdex98 9e6247e0cb Co-op: a loading zone brings the team along; only someone falling is rescued
- Crossing a BSP loading zone moves every other player to whoever crossed,
  as split screen does. Moving only some players left the rest where the
  next switch threw them back to a hallway, or under a floor.
- The rescue for a player outside the loaded BSP waits two seconds and
  only takes someone falling: a player riding an elevator through its
  shaft is left alone.
2026-10-05 06:34:00 -05:00
MrBruh dea5fe3b1e Fix crash past 256 actors 2026-10-06 00:29:42 +13:00
MrBruh a38ede078a Co-op extra enemies per player 2026-10-05 23:25:15 +13:00
MrBruh fa85aa53f5 Kick command; co-op friendly fire on by default 2026-10-05 22:51:05 +13:00
MrBruh 8be9a038a1 Co-op friendly fire setting 2026-10-05 22:40:34 +13:00
MrBruh 783b591a6a Co-op defaults to 16 players and private 2026-10-05 22:27:36 +13:00
MrBruh e82d880060 Singleplayer and multiplayer map choice 2026-10-05 22:17:22 +13:00
MrBruh 7d0e587c51 Co-op review fixes 2026-10-05 21:02:04 +13:00
MrBruh 01586cfebf Merge pull request #89 from xshxdex98/coop-campaign 2026-10-05 20:29:19 +13:00
MrBruh de52060644 Host takes grenade damage only from grenades thrown 2026-10-05 19:54:33 +13:00
MrBruh 3f6c0c37a4 Friendly fire stops teammates' instant kills 2026-10-05 18:47:39 +13:00
xshxdex98 606109551d Co-op: friendly reticles, skipped cutscenes' sound, the end of a level, tutorial prompts
- AI units' teams go with their states, so friendlies aren't red on
  clients' reticles.
- A skipped cutscene's music and dialogue stop on the clients.
- Winning a level returns every machine to the lobby with the next level
  set up, instead of leaving them on its last screen.
- Help text carries whether the host shows it, so no prompt is dropped.
2026-10-05 00:46:51 -05:00
xshxdex98 8194c5a00b Online co-op: play the campaign together over LAN and the internet
Hosting a co-op level from the Map screen (CO-OP CAMPAIGN, a level and its
difficulty, then Server Setup) makes a network game on the campaign map
with no game engine, which is what co-op is. Only the host runs the
scripts and the AI; port/linux/game/network_coop.c sends clients what the
scripts do (cutscenes, camera, fades, HUD, sounds, devices, named objects,
animations), and network_actors.c drives the host's AI units on every
machine. Players spawn beside each other, respawn beside a safe teammate,
and spectate while dead or waiting. Skipping a cutscene is a vote.
Players can join a game in progress at any time.
2026-10-05 00:31:30 -05:00
MrBruh 2853a42253 Clear an antenna's shape record when it is created 2026-10-05 17:13:27 +13:00
Fadi DerouicheandClaude Opus 5 39ece781ee Step the antenna chain in the tick and draw the frames between the ticks
An antenna's chain is a simulation of the Xbox's own step, an update a tick,
and the port was stepping it once a frame with the frame's own time. Its
springs, its carry and the points' physics then acted against the frames'
movement of it, so how far the chain moved per update depended on the frame
rate, and a vehicle at speed swung it far wider than a tick's step does.

- game.c steps the chain in the tick, beside the effects, which are already
  stepped there.
- antenna.c records the shape each tick leaves, relative to the point the
  vehicle's marker carries the base by. A frame drawn between two ticks is the
  part of the way between those two shapes that it is, carried to where the
  marker is now, so the chain stays on the vehicle it hangs from instead of
  lagging a tick behind it. The gate that left a chain that had not been drawn
  for five updates unstepped counted frames; it counts ticks now, which is
  what it counted on the Xbox.
- widgets.c no longer steps the chain from the widget update, which ran once a
  frame.
- game_time.c draws the per-frame effects and widgets that hang off objects
  (game_frame) with the pose between the last two ticks, the pose the renderer
  draws with, so what they place on an object is drawn where they put it.
- objects.c hands markers the matrices the renderer draws with, so an effect,
  a particle system or a contrail attached to a moving object follows it
  between the ticks too.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-05 17:13:27 +13:00
MrBruh cf17201ec8 Split screen divider spans wide screens 2026-10-05 17:13:27 +13:00
MrBruh 54faa1dab6 Merge pull request #87 from eltanschauung/fix/death-camera-timing-pr
Fix death camera and co-op respawn timing at high frame rates
2026-10-05 16:33:14 +13:00
MrBruh 9bdd7f30c0 Merge pull request #86 from thelinkin3000/fix/host-again-after-backing-out
Make a new game each time Create is chosen
2026-10-05 15:53:59 +13:00
MrBruh 685bf260a0 Either co-op player picks the level 2026-10-05 14:47:11 +13:00
eltanschauung fb1abedd8b Keep dead camera target when no living player exists 2026-10-04 20:32:59 -04:00
eltanschauung cd345aac7c Count death and co-op respawn delays in game ticks 2026-10-04 20:32:31 -04:00