Source code

The source for the game we serve

The game on this site is OpenCE, which is free software under the GNU Affero General Public License, version 3 or later. You can read, change and share it under that license.

The build behind /play

We serve the browser build of build-343-hc18.

What we changed

Our copy of the browser build is the release with these changes, and nothing else. The game code is the release's with one patch, which you can read and download: halocustoms-build-343.patch (a unified diff against the release's tag).

  • halo.js and halo.wasmrebuilt from the release's source with our patch (linked below): a controller aim-assist setting with three levels (stock, strong, lock: the reticle held on the nearest target's head, firing by itself while it is; strong and lock without shot spread or recoil, with instant reloads, a faster rate of fire, a share of the damage taken, no jump recovery, higher jumps, an instant melee and a faster run), the player's own in every game, and the setting documented; and a match recorder (port/linux/game/halocustoms_stats.c) that appends lines of results to a matches.jsonl file, one for each local player of the machine (in the browser, the first local player's in the game's data folder, the browser's storage for this site, and another player's in their Halo profile's folder there; in the Linux, Windows and Android builds, each player's in their profile's folder): for each finished multiplayer game, the multiplayer map's name, the gametype, whether it was a team game, the player's kills, deaths and assists, the longest run of kills, how many kills were headshots and how many melee kills, whether the game was won, how long it lasted, how many played and when, and the game's scoreboard (every player's name, team, kills, deaths, assists and score, the player's own row marked); and for each campaign mission played alone or in co-op, a record of the enemies killed (the level, the difficulty, the enemies killed by class: grunts, jackals, elites, hunters, the Flood's infection, combat and carrier forms, sentinels and others; the allies killed, the deaths, whether the level was won, how long it was played, how many played and when). The launcher page reports the first local player's lines to the player's account here: the multiplayer ones for the rankings and the match pages, which put the reports of one game from its players together, and the campaign and co-op ones for the player's service record, which leave the rank alone. The rank the site gives a player goes before their name in multiplayer and into the main menu, and outside team games (where the team colors stay) a prestige tier's armor color is worn by every player whose name carries it; and a HALOCUSTOMS item on the main menu (port/linux/src/halocustoms_account.c, menu files under port/assets/menus) opens an account screen that shows the player's rank, experience, kills and deaths, matches and wins, best streak and the matches not yet reported, with SIGN IN (a code the game shows, entered on this site, links the game to the account; each Halo profile signs in by itself, as a game of its own named after the machine and the profile, and reports its own player's lines; the game keeps each profile's token and the rank last given to it in files in that profile's folder (halocustoms.key, halocustoms.rank), moves an earlier build's, kept beside config.toml, to the first player's profile, and takes a token written into config.toml by hand for the first player's profile) and SIGN OUT, through which the Linux, Windows and Android builds report their matches and missions and learn their rank themselves. In the browser the launcher page reports them, and the account module asks this site who is signed in (GET api/play/me, with the browser's session) from inside the game, to show the account. The main menu shows the first local player's account in a panel (the member's name, rank, experience, kills, deaths, K/D, matches and wins; or that the profile is signed out or playing as a guest, with a line inviting a sign-in), and once a run, while the first local player's profile is signed out and has not chosen to play as a guest, a welcome dialog over it offers CREATE ACCOUNT and SIGN IN (both begin the sign-in, CREATE ACCOUNT through this site's sign-up first; in the browser each opens this site's sign-up or sign-in page in a new tab, which ends on a page naming who is signed in) or PLAY AS GUEST, which the game keeps for that profile (halocustoms.guest, in its folder); halocustoms.welcome set to "never" turns the dialog off. In the browser, while nobody is signed in, the main menu asks this site again every 30 seconds. The game also shows the first local player's friends on this site: a FRIENDS item on the main menu and a FRIENDS screen (also reached from the HALOCUSTOMS screen) list them with where they play (GET api/play/friends), JOIN a friend's public game through the game's own signed listing, and ACCEPT or DECLINE friend requests (POST api/play/friends/requests/{id}/accept or decline); the account panel adds how many friends are online. While that player is signed in, the game tells this site every 30 seconds whether they are in the menus or in a public game, with the game's signed listing, map and gametype (POST api/play/presence), and that they left, at sign-out or when the game quits (DELETE api/play/presence); only the member's friends see it, and halocustoms.presence set to "off" sends none of it. The game's menu files gain three extensions that only a menu set asking for them uses (port/assets/menus/README.md; this site's theme does): theme colors (color_map, which recolors the menus' text colors, focus_text, the color of focused text, and the server browser's row colors), theme fonts (font, which draws the text of one of the game's three fonts with a static TrueType font shipped with the menus under the SIL Open Font License, its license beside it, laid out with that font's own spacing and kerning and narrowed as a whole where it is wider, so that it keeps to the room the game's own font takes) and a fluid layout (anchor, which places a widget from the display's real edges or stretches it across the display at any aspect; caps, which keeps a stretched picture's ends unscaled; text_flags="wrap", which breaks a text box's lines; and fill, which draws a bar across the first local player's experience toward the next level), with the mouse and touch following; source/interface/ui_widget.c, source/rasterizer/rasterizer_text.c and source/text/draw_string.c are changed for these where port code could not reach, each change marked port:. Without them the menus are drawn as before. The game also gets the first local player's account a pass for servers (port/linux/src/halocustoms_account.c, port/linux/src/player_link.c): this site's statement, signed with its identity key and good for 24 hours, that the account plays with the game's player key (player.key, made if there is none), which a server checks by itself. It asks for this site's keys (GET api/play/identity, unless halocustoms.identity_key names them) and for the pass (GET api/play/pass, signed with the player key; with the profile's token, or in the browser with the browser's session), again at the pass's half life and when the first player's profile or account changes, and forgets it at sign-out. Joining a game without showing a pass, it says that it holds this site's (this site's key id, in bytes of the join request that the release leaves empty and reads only beside a pass), and it shows the pass to a host that then asks for a pass, as a host that takes this site's passes does at once; halocustoms.share_account chooses this (asked, the default), always or never. With network.link_share set to "always" and the account shared when asked, a join first says that it holds this site's pass instead of showing a Discord pass, so that a server that takes this site's passes still asks for it. When a server turns a player away for want of an account, the game says which case it was: the host asked for the HaloCustoms account, the server takes only HaloCustoms accounts, the account's pass was refused, or (in the release's words) the server blocks VPNs. The game's dedicated server, which the browser does not run, gains settings to take this site's passes at the door (server.link_masters_file, server.link_ask), to turn away players without such an account (server.link_required, which this site's ranked servers use), and to write a line of results for each finished multiplayer game (server.results_file: each player's numbers and checked account, in a file that only its owner and group may read), from which this site makes the game's match page; its status shows a player's account to its owner alone. Two host settings of the netcode are also in it, both at the game's own behavior unless a host chooses otherwise: network.update_rate (how often a host sends the positions of distant and unseen players: stock, high or max) and network.anticheat (how sensitive the host's speed-hack detector is: stock or strict); neither changes what the machines send each other. The game is HaloCustoms, based on OpenCE: it names itself so where players and server owners see it (its version and labels, the server's name and web page, the HALOCUSTOMS OPTIONS screen), and keeps OpenCE's protocol names. It asks this site's services before OpenCE's: its brokers list this site's first (halocustoms.org:1883; in the browser wss://halocustoms.org/mqtt), then OpenCE's and public ones; a native build given this site's master key when it is built asks this site's master before OpenCE's (the browser's list comes from masters.json, below); the native builds take their updates from this site's release feed (halocustoms.org/updates), each only as its manifest says it, signed with HaloCustoms' offline release key that the build is given when it is built (a build without that key never updates itself; the browser build never does); and it tells the servers it joins that its source is halocustoms.org/source. The network version is the release's, and players of this build still play with those of the release. Nothing else in the game code is changed.
  • index.htmlremoved the script tag that counts visits for the upstream project (Umami at nexus.mrbruh.com).
  • index.htmlas our source has it, the page names the game HaloCustoms, based on OpenCE, and links to this site (its home and source) and to OpenCE in place of the project's Discord and GitHub; a Discord link set here replaces any the page still has.
  • index.htmlany of the project's "Linux, Windows and Android" and "Source" links left in the page point to this site's downloads page and to this page.
  • index.htmla bar and footer that link back to this site (its home, servers, maps, mods and guides pages, and this page), and the page title and masthead carry this site's name in place of the project's.
  • masters.jsonlists this site's own master server first (its /master, signed with its own key), then the master servers this site follows, in place of the empty list (which means the official master).
  • version.jsonour own version string (the release's, and a hash of every file our copy serves and of the rest of this file), so that the browsers of returning players fetch our copy again when any of it changes; and our theme's files added to its list of files, which the page's service worker keeps. A build made here has build number 0 in the version.json it is built with (the release's number is given by the project's CI): ours takes the number from the tag it is installed under, such as 343 for build-343-hc1.
  • index.htmlour look. A stylesheet (customedition/customedition.css) loads after the launcher's, the site's three colors are set in the page and its logo is in the bar, and index.html loads our script (customedition/customedition.js, described next). The launcher's style.css is as released. The fonts Orbitron, Exo 2, Rajdhani, Noto Sans and JetBrains Mono (customedition/fonts) are under the SIL Open Font License, with their licenses beside them.
  • customedition/customedition.jsour script for the launcher page. It draws: a motion-tracker ring and a readout in the masthead (the build and network version from version.json; the servers and players this site lists, asked of its servers.json every 30 seconds; whether a controller is connected; the signed-in member's rank, a link to the member's page here, or, when nobody is signed in, to this site's sign-in, each in a new tab; how the game's connections are made, in its Connection row), a clock in the site bar, and this site's name in the masthead and the tab's title. It holds the Play button, so that neither a click nor Enter starts the game, while the menus folder is checked and copied and while the relay's credentials are fetched. It keeps the menus folder in the browser's storage for the site: copying the themed menu files there, or removing the folder it copied earlier, as said under customedition/menus. It reads and writes the game's config.toml in that storage: a "Controller aim assist" row it adds to the Settings panel writes the level chosen (stock, strong or lock) to input.controller_aim_assist, and until the player has chosen there, each time the page loads and the file says anything but "lock" (the game's own default, stock, included) the script writes "lock"; it also writes halocustoms.rank_tag, the signed-in member's rank, which the game shows before the player's name, and empties it when nobody is signed in. It adds a "Connection privacy" row and offers the game's connections this site's relay, as said under net.js. It identifies the player: every 20 seconds, and when the tab is shown again, it asks this site who is signed in (GET api/play/me, with the browser's session), and while a member is, it reports the lines the game recorded in matches.jsonl for its first local player (multiplayer matches with their scoreboards, and campaign and co-op missions with their enemies killed by class) to that member's account (POST api/play/matches with the member's link token, 50 at most per request); another local player's lines are not reported. In the browser's localStorage for the site it keeps the player's two choices and how far matches.jsonl has been reported. It sends nothing to any other site.
  • app.js, index.html: the page's scripts and the game's program are fetched under URLs that name their build, so a browser that saw one build cannot keep running its program under another's page. In a build made here, app.js is also changed in the source (our patch): the dialog through which the game asks to open a page offers pages of this site too, in a new tab, which the account screen's sign-in uses; the release's offers only a master server's Discord link page.
  • net.js, p2p.js: the game's connections take the ICE configuration our script offers (window.HaloCustomsIce): when this site has a relay set up (its servers and credentials come from GET api/play/ice, and are renewed while the page is open) and the player keeps it on, every connection goes through the relay (TURN, relay-only), so other players see the relay's address, not the player's; p2p.js then hands the game its relay addresses as it would its public ones. With the relay chosen and no credentials in hand, no connection is made rather than a direct one. Without a relay, or with it off, the files behave as released.
  • customedition/menusthe game's menus restyled for this community, as files: the main menu laid out across the whole display (a one-line title and the items in a rail at its left edge, the account panel as a card across the rest with an experience bar, and a status bar along the foot), the settings screens (title and help in the rail, the options widening on the right, the buttons in a bar along the foot), the campaign, multiplayer, difficulty, server browser, lobby, welcome and HaloCustoms account screens laid out to match, the account panel's card and the welcome dialog's box (main_menu.halocustoms_bitmaps.xml, their own bitmap index), the game's bitmap index (bitmaps.xml) pointed at redrawn pictures for every other screen (backgrounds, option rows, buttons, arrows, dialog and panel boxes, the server browser and the screen headers), and theme.xml, the theme's text colors and the fonts it draws the game's text with (Exo 2 Bold for ui\large_ui, Exo 2 SemiBold for ui\small_ui and ui\interstate), which are in ce/fonts as static TrueType files under the SIL Open Font License, with the license beside them; the lettering inside the pictures is drawn in Orbitron and Exo 2. These are copies of the game's menu XML files with bitmaps, widgets, places and colors changed, plus the PNGs they draw, generated by resources/menu-art, and a manifest of their sizes and hashes. They are shipped only in a build that can load them and needs them: one made here from our patched source that does not carry the menus inside the game. For that build the launcher script copies them into the browser's storage for the site as a menus folder, which the game reads in place of its built-in files. A build made here with the overlay (configure.py --menus-overlay; "embedded_menus": true in its version.json) carries the same menus inside the game: no menu file is shipped with it, and the script removes a menus folder it copied for an earlier build, so that those files cannot override the ones built in. A menus folder the player made themselves is never written into or removed.
  • Beside the build, for the installer and not listed in version.json: the release's own index.html, version.json, app.js, net.js and p2p.js as they came (the .original copies its changes start from), and .installed-from, which names the release or the build made here.

Who made it

OpenCE is built by its own contributors, starting from the decompilation work of bnunu/halo-1 and punpckhdq/halo. We're a separate community that hosts and supports it. We're not part of that project, and Halo itself belongs to Microsoft.