Brick & Mortar

How It's Made · Step 17 of 27

Step17

Seventy achievements, a fake Steam and the friend build

· 4 min read

achievementsmultiplayersteambuilds

The Achievements screen, a grid of brick-icon achievements such as First Brick and Quick Brick, with progress bars on the locked ones.

The stretch before you show a game to friends is mostly unglamorous work: things that make a game feel finished, and things that make it safe to hand over. On 21 and 22 October we did three of them.

Achievements that cannot change the game

An achievement system has an awkward requirement in a lockstep game. It needs to know what happened in the simulation: how many infantry you crushed, how many missiles you shot down, which ship sank. But the simulation must never depend on it, or two PCs with different achievement states could drift apart.

The rule we chose: the sim writes counters and never reads them. Event counters live on the player object (infantry crushed, buildings sold, ships sunk per ship, which support power fired and so on). They are written at the places where the event already happens, are not part of the state hash and are not saved. A watcher on the interface side reads them once a second, for this PC's seat only. If the achievement code were deleted, the game would play identically.

The first build, on 21 October, shipped 42 of the 68 achievements the writer had listed; the others were waiting for events the sim did not record. On the 22nd we added the missing counters, and 67 of the 70 now ship, with three left hidden. Mission-specific ones read the mission director's flags instead: never let a boat through, never hit the school, never lose a rocket.

We checked the claim, not only the code: the lockstep run produced the same fingerprints as before the change.

Seventy badges, drawn by a script

Every achievement needs an icon, locked and unlocked. A script draws them: seventy brick-shaped badges, two states each, 140 images, plus a contact sheet so a person can check them all at a glance. No image generator was involved. A missing icon file shows a placeholder instead of an empty square, and there is a test for it.

A contact sheet of dozens of small square brick-shaped achievement icons, in colour and in grey for locked ones
Part of the contact sheet: unlocked in colour, locked in grey beneath.

Testing Steam without Steam

Online play through Steam means lobbies: you create one, friends see it or are invited, they join, the match connects. Testing that on one PC with a single account is a problem.

We built the layer so that the session talks only to a small interface, a pipe that sends and receives messages. Two real pipes plug into it: one over plain UDP (a LAN or a direct address) and one over Steam's peer-to-peer sockets. A third, FakeSteam, imitates the lobby service with files on disk and loopback UDP, and is compiled out of the shipped game.

With it, two headless game instances ran the whole path: create a lobby, list it, check the version, join, connect, play. 601 state hashes and 81 commands matched on the UDP road and on the fake Steam road, and an invite-only lobby never appeared in the public list. The menus gained a host screen (friends, invite only or public), a list of games to join, a direct-IP road behind a button, chat with a mute per player, and a filter on chat text.

The real thing still has to be tested with real friends on two PCs, and our notes say so in capital letters.

The friend build, and the audits that said no

A friend build is a zip of about 8.8 GB with 1,140 files that someone can unpack and play. Before it is zipped, a script, release_audit, checks the package: the right content, nothing that should not ship, the first-launch legal screen, no leftover old names.

A smoke test of the packaged exe won three Tower Defense levels with the balanced bot. The log's last line is the one we like best: not verified: a played session; real two-PC Steam multiplayer from the packaged exe. Nothing uploaded.

What we would do differently

Try it yourself

When a feature has to look at a deterministic system, make the dependency one-way: it can read, the system must not know it exists. Then prove it with the hash you already have.

Next: Juice - bricks that scatter, buildings that assemble and a pixel counter that caught us (22 October 2026)

Start at Step 1All 27 steps

Written afterwards from our project notes and commit history; dated to when the work happened.