Commit Graph
202 Commits
Author SHA1 Message Date
Milenko ea79111994 Bounded copies and formats of tag names
The scenario's tag name was copied with strcpy into the game state
header's 256-byte map_name, a tag's name was formatted with sprintf into
the out of objects message's 512 bytes, and csprintf bounded its output
at MAXIMUM_STRING_SIZE even when it formats into temporary, which is 256
bytes and where most callers put tag names. All three are bounded by
their buffers' sizes now.
2026-10-08 08:35:50 -04:00
MrBruh 65a6bb7edd Grow the powerups' render spheres in a port file
The powerup bounds of #117 move from source/models/models.c to port/linux/game/powerup_render_bounds.c, called from scenario_tags_load beside the other tags-loaded hooks, so the game's models.c no longer takes <xtl.h> and D3D buffer locks. It uses square_root and a relative margin in place of sqrtf and nextafterf, which strict gnu89 does not declare, and the objects.h scale change is marked as the port's. tools/test_powerup_bounds.py is dropped: it redeclares the engine's types by hand and CI does not run it.

On bloodgulch the active camouflage's render radius grows from 0.1 to 0.23 and the overshield's from 0.1 to 0.21; no other equipment changes.
2026-10-08 14:15:15 +13:00
MrBruh ec23cfcf24 Merge pull request #117 from eltanschauung/fix/powerup-render-bounds 2026-10-08 14:08:53 +13:00
MrBruh bad6534e0c Forget the object bounds cache in the game state load procs
The cache is forgotten before every game state load (beside cluster_partitions_port_forget) and at each new map, after the declarations, rather than at the top of four functions.
2026-10-08 13:46:02 +13:00
Addison Bair 04713926d1 Pass over far objects on a packed copy of their bounding spheres
A collision query (collision_get_features_in_sphere) reads the bounding
sphere of every collideable object in every cluster it touches, to pass
over the far ones. Every biped queries each tick, so a crowded cluster
(co-op's extra enemies, a carrier burst) costs the square of the crowd in
scattered object reads.

object_bounds_cache.c keeps the spheres packed by absolute index, written
by their only writer (object_compute_node_matrices). The loop runs the same
point_in_sphere on the copy, so the same objects are passed over and the
same features gathered, in order. game_state.c invalidates the copy when
the game state is replaced (revert, loaded core or game, new map).

Deterministic offline crowd (c20, legendary, extra enemies x8, 24 carriers
burst, seed pinned): game state identical tick for tick; collision queries
4.2 -> 3.0 us (-28%), object updates -15%.
2026-10-07 22:11:47 +00:00
MrBruh f41c8e977a Merge pull request #145 from addisonbair/widget-pools
Fix invisible plasma bolts in large network games
2026-10-08 10:56:45 +13:00
eltanschauung 2875b505fc Merge remote-tracking branch 'upstream/main' into resolve/pr117-2026-10-07
# Conflicts:
#	source/cache/cache_files.c
2026-10-07 02:09:33 -04:00
MrBruh f823a18d59 Load, check and run Halo Custom Edition and OpenSauce maps 2026-10-07 19:02:01 +13:00
Addison Bair 35f643f376 Grow the widget and light volume pools for large games
A plasma bolt is drawn by its light volume, a widget, and both pools were
still the Xbox's: 64 widgets and 256 light volumes. Every assault rifle
holds a light volume for its flashlight beam from when it is made, held or
dropped. In network co-op the rifles left lying about are kept as garbage
in proportion to the players, and garbage that any player can see is never
collected, so a large game fills the widget pool and keeps it full; a client
that joins a game in progress makes all the rifles at once and takes every
slot. From then on widgets_new finds the pool full and skips the widget, so
every bolt flies and hits unseen.

- widgets 64 -> 2048 (HALO_PORT_MAXIMUM_WIDGETS)
- light volumes 256 -> 2048 (HALO_PORT_MAXIMUM_LIGHT_VOLUMES); with only the
  widgets grown, the light volumes run out next

At 128 players a game can hold about 1,000: the rifles in hand, the ones on
the ground (garbage collection starts at 400 and keeps those in view) and the
bolts and needles in the air. The CPU part of the game state grows by 38,144
bytes, to 18,242,828 (2,466,548 free). As with any pool size, saved games of
earlier builds no longer load.
2026-10-07 05:23:34 +00:00
MrBruh 5f1abf161c Survive and report a broken lights array 2026-10-07 15:05:11 +13:00
MrBruh 07302a866f Co-op-only garbage throttle, network version 21 2026-10-07 13:43:50 +13:00
MrBruh 929ae2d5af Merge PR #135 2026-10-07 13:38:30 +13:00
MrBruh d7efd3934a Validate map tags before loading 2026-10-07 12:01:09 +13:00
xshxdex98 b214dc1728 Host performance: the garbage collection no longer runs every tick with many enemies
Garbage (bodies, dropped weapons) is kept while a player may see it: in any player's potentially visible clusters, near them or in a 45 degree cone of where they aim, however far. With many players spread over a level and many bodies (co-op's extra enemies), every body was seen by someone, nothing could go, and the whole collection (each garbage object's visibility, the object memory pool compacted) ran again every tick on the host, which also wrote 'garbage collection critical' to debug.txt each tick while short of memory. A player now sees garbage no further than 30 world units off, a collection of active garbage that left too much is tried again only after a second, nothing collected compacts nothing, and the critical line is logged as often as the warning. Running short of memory or objects still collects at once.
2026-10-06 15:59:43 -05:00
MrBruh 76addf661f Second hardening round 2026-10-07 00:01:28 +13:00
eltanschauung 77efb01b00 Grow culling spheres with enlarged objects 2026-10-06 01:29:48 -04: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
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 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 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 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
MrBruh 01586cfebf Merge pull request #89 from xshxdex98/coop-campaign 2026-10-05 20:29:19 +13:00
MrBruh 3f6c0c37a4 Friendly fire stops teammates' instant kills 2026-10-05 18:47:39 +13: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 c9ee319ab5 Add the PC menus 2026-10-04 01:56:45 +13:00
MrBruh 4f3ce00a8e Fix third netcode review 2026-10-01 04:57:51 +13:00
MrBruh e7d1ed3a67 Harden and fix the netcode 2026-10-01 01:22:46 +13:00
MrBruh 4adc3a87a5 Remove matching tooling and HALO_LINUX ifdefs 2026-09-30 21:49:46 +13:00
MrBruh a17d89c6f1 Merge bnunu/halo-1 main 2026-09-30 18:13:05 +13:00
Jonas Volman 6bfd956737 Reconcile approved Halo fidelity packets and bounded data credit
Recover transparent geometry submit (+1,285 meaningful code, zero exact losses); reconcile COMMON ownership and Q10 85+EXT1 credit, actions/main data, and separately disclosed denominator corrections. Preserve canonical-only repairs and all held research. C09 is ordinary disclosed cleanup, not a claim of proven scaffolding intent. Clean rebuild, 1,663 tests, parks, audits, provider links and independent EXT1 check pass. Local reconciliation only.
2026-09-29 13:52:37 -07:00
Jonas Volman f3aadeab98 Reconcile five Halo functions and approved declaration batches
Integrate coherent B3, P2/K17 prerequisites, completed K1-K16 + S, and the independent profile/effects rulings. Five gains and two explicitly approved B3 debits: net +3 strict functions, +2770 meaningful/+2800 padded bytes (+2774 progress credit). No additional losses; Halo objects 394 to 396 and data unchanged.

Clean rebuild, identical 8252-row stable sweep, 68 valid parks, admission/provider checks, 467-unit warning comparison, unchanged fake scan, and 1318 tests passed. Preserve canonical helper recoveries and unrelated work. Full evidence and disclosures in docs/object_matching_logs/astra_five_function_reconciliation_20260928.md.
2026-09-28 23:17:10 -07:00
MrBruh 8fcfe9e653 Finish distributed netcode 2026-09-29 00:27:28 +13:00
MrBruh 391e83b11f Add distributed netcode 2026-09-28 22:27:37 +13:00
Jonas Volman 5a83a7234a Reconcile exact flag update and multiplayer directions with zero losses 2026-09-27 22:29:15 -07:00
MrBruh 1bcd57afe4 Merge branch 'bnunu:main' into main 2026-09-28 14:46:17 +13:00
Jonas Volman 709bfc3a3c Reconcile approved frontier ownership and admission packets
Import only independently reviewed production changes. Preserve canonical physics and virtual-keyboard repairs; keep B3 and all unresolved holds out.

Record exactly four approved canary debits (6987 meaningful bytes), six Halo admissions and two revocations. Keep vendor ioinit/storage work separate. Full build, 8252-row sweep, 1318 tests, park/admission/fake audits and 621-object binding pass within approved debit bounds.

Do not publish donor research dumps or private assets. README and unrelated user research remain untouched. See frontier_publication_reconciliation_20260927.md for complete evidence limits and accounting.
2026-09-27 17:12:48 -07:00
Jonas Volman 59757f4263 Reconcile approved type ownership, static locals and source disclosures
Independently gate storage + K, OQ-4 P-a/P-b1, four static-local packets and comment-only disclosures. Preserve all 7641 exact owner rows, 71 valid parks and 1161 passing tests; code/data credit unchanged. G and game_engine admission remain held because current canonical loses populate_statistic_buffer. Existing collision static-local repair is not duplicated. No donor tree, held candidate, scorer or private asset imported.
2026-09-27 05:17:27 -07:00
MrBruh fef8a582dd Fix release build crash on level load 2026-09-27 19:56:32 +13:00
MrBruh b0e3bc96e3 Fix framerate-dependent timing 2026-09-27 19:23:44 +13:00
MrBruh 755f610025 Fix 128-player multiplayer issues 2026-09-27 18:17:24 +13:00
MrBruh 0154ae9af5 Merge branch 'main' of https://github.com/cybersecurity/halo-ce-universal 2026-09-27 17:42:48 +13:00
MrBruh 0f38fea378 Merge remote-tracking branch 'upstream/main' 2026-09-27 16:57:47 +13:00
Jonas Volman 7c0af5f029 Reconcile approved compiler-application code, data and owner repairs 2026-09-26 12:02:50 -07:00
Jonas VolmanandClaude Opus 5.5 9a376181f5 Port: grow the game state and object pools for 128 players
The Xbox game state (0x345000 bytes at 0x80061000) ends exactly where the
map-linked tag cache begins and has 948 bytes free, so a 128-player
session cannot even allocate its player datums. The native builds now
place a 16 MB game state (CPU 0xFC0000, GPU 0x40000) at 0x81A00000, above
the tag cache and below everything the Xbox memory window hands out
top-down, and grow the pools that scale with the number of players:

- objects: 2048 -> 8192 headers, 1 MB -> 8 MB pool; the garbage limits
  keep January's proportions (5/10/20 % of the pool, 2.5/5/10 % of the
  headers, 75/50/30 active garbage objects per 16 players)
- cluster partition reference lists 2048 -> 8192 (collideable and
  noncollideable objects, lights); a full list drops objects out of
  rendering, collision and sphere queries
- effects 256 -> 2048, effect locations 512 -> 4096
- particles 1024 -> 8192 (render_particles' visible list, filled without
  a bound check, follows), particle systems 64 -> 256, their particles
  512 -> 4096
- contrails 256 -> 1024, contrail points 1024 -> 8192
  (MAXIMUM_CONTRAIL_POINTS stays the pool size for the same reason)
- lights 896 -> 4096, object looping sounds 1024 -> 4096
- cached object render states and rendered objects 256 -> 1024
- script object-list references 128 -> 1024, objects one explosion can
  damage 64 -> 256

The values live in port/linux/include/halo_port_capacity.h, included by
halo_port_limits.h. With 128 player datums the CPU part holds 14,256,908
bytes (2,258,164 free). Saved games and cores grow to 16 MB. Every change
is under HALO_LINUX; the MSVC objects are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 10:18:07 -07:00
MrBruh a06ef74eec Detach framerate from gameplay simulation 2026-09-26 21:49:07 +12:00
MrBruh e29125b50e Port decomp to Android 2026-09-26 16:16:00 +12:00
Jonas Volman cc0effa8d3 lightning: correct file-static globals ownership 2026-09-24 16:11:10 -07:00