Turning an IW4x Server into a Randomness Beacon

2026-06-08

I wanted my website to know whether my MW2 server was online and read some basic gameplay statistics. It ended up becoming a live dashboard and entropy harvester.

The Problem

My IW4x server runs on LegionHosting dot com. That is great because it is easy to setup, has backups, and is cheap. The downside is that I do not have the same freedom I would have on a VPS; I can't run scripts, and I can't access the command line. The server speaks the old game-server language: UDP, RCON, status responses, DVARs, scripts, and text.

RCON can tell you some things. It can answer status, and getinfo can give you the map and gametype. However, the interesting stats for the website were not all available there: humans versus bots, unique players, live team scores, score limits, completed match records, nuke counts, and long-lived server totals.

So the question became: if the host will not give us a normal telemetry socket, can the game itself post little notes somewhere RCON can read?

The DVAR Bridge

The workaround was to use IW4x scripting as a bridge. The custom GSC script already had access to the things that mattered inside the match. It could count non-bot players, track match endings, notice nukes, remember map play counts, and read the current team scores. So instead of trying to make the script call the internet directly, it exports those values into custom DVARs with a shared prefix:

js_iw4x_humans
js_iw4x_bots
js_iw4x_unique_players
js_iw4x_score_allies
js_iw4x_score_axis
js_iw4x_total_nukes
js_iw4x_last_completed_map
js_iw4x_last_score_allies
js_iw4x_last_score_axis

That is the key idea that made everything else possible. The game writes telemetry to DVARs every 30 seconds. Then an outside machine can ask the server for dvarlist js_iw4x_ over RCON and receive a text dump that is easy enough to parse.

The game server did not need to become a web server. It only needed to broadcast its internal state.

The Poller

Recently I made a cheap homeserver with Ubuntu on an old Lenovo ThinkCentre. My homeserver runs the periodic poller. Every few minutes it sends three UDP queries to the LegionHosting box through RCON: getinfo for map/server metadata, rcon status for the player table, and rcon dvarlist js_iw4x_ for the custom telemetry exported by the script.

The poller normalizes all of that into a JSON payload and posts it to a Cloudflare Worker. It also keeps a tiny local state file so it can turn cumulative counters into deltas.

The Worker accepts that payload at /ingest/status, guarded by a bearer token, and stores the current state in D1. From there the static site gets normal HTTP endpoints:

IW4x GSC: watches the match and writes custom js_iw4x_* DVARs.
Homeserver poller: reads status and DVARs through RCON, computes deltas, then posts JSON.
Cloudflare Worker: authenticates ingestion, stores live status and match history in D1, and exposes public read APIs.
Website: renders the live server card, score board, lifetime stats, recent matches, and activity charts.

The Dashboard

The visible result lives on my games page: an online/offline card for Justin's MW2 server, current map and mode, humans and bots, score line, lifetime win and nuke totals, most played map, recent matches, and an activity heatmap. I check it every so often because it is fun to see players come and go, as well as the nuke counter slowly climb.

Live score was easy to process. Completed matches were trickier because the interesting moment is the boundary between one map and the next. If a poll happens after a reset, you can get odd behavior like accidentally recording the new map with the old match's win counter. The Worker now keeps high-water scores and a last-completed-match buffer so the final map, gametype, scores, and winner survive that transition.

That detail matters because it changes the dashboard from a decorative status badge into a small telemetry archive. Once matches and daily aggregates exist, they can be used for something else.

The Beacon

The randomness beacon came from a silly question: can a Call of Duty server be a source of public entropy?

The answer is yes. However, it is certainly not a cryptographic replacement for a real randomness source. Even so, the data has real unpredictability in it: humans join and leave, bots behave according to some PRNG, scores evolve, maps rotate, nukes happen or do not happen, and match boundaries land where they land. In total, those events produce entropy which can be harvested, distilled, and shared.

Every five minutes, the Worker emits a beacon round. It builds a transcript from the current server status, recent completed matches, daily match/nuke summaries, and the round window. Then it hashes the canonical transcript with SHA-256 to produce a source digest.

The final output also includes the previous beacon output, which chains the rounds together. If an older record changes, every later output changes too. The Worker also uses a simple commit-reveal nonce pattern: each round reveals the nonce committed in the previous round, then publishes the next commitment.

sourceDigest = SHA-256(stableStringify(transcript))
output = SHA-256(stableStringify({
  version,
  sourceDigest,
  previous,
  revealedNonce,
  round
}))

The public beacon page shows the latest output, round metadata, source hash, previous output, the live entropy feed, recent chain history, and the full JSON record. The point is that the page record contains the all of ingredients needed to verify the hash chain.

Why I think this is cool

I like absurdly specific projects which showcase the intersection of my unique tastes with interesting technical challenges. The project described here is a 2009 game server, a server-side game mod script, a homeserver poller, a serverless edge function, a SQLite-ish database, a personal website, and a randomness beacon. You really have to ask yourself why someone would build such a thing, and the answer is that I think it is cool.

Opening up the game server to the outside world was the key step. Now, I have a little army of robots that read a live game feed of humans and AI bots playing Call of Duty Modern Warfare 2 (2009). You can watch them play live, and you can use their random movements for entropy.

It is one thing to make a game, or web app, or whatever that resembles a homework project. It is another to shape those ideas into a unique and personal creation. That is what I enjoy the most: making something that only I would make.

Back to Blog