A combat you can replay: how the server checks your run
Prismloot has depth and collection leaderboards. When there is a leaderboard, you have to be able to trust it. This is the technical decision we made for that (on October 6th) and how it is working out.
The alternatives
We compared four options:
- JavaScript functions that roll the loot. Loot, forge and salvage would have to be written twice: once in the game and once on the server.
- The phone is in charge and the server only validates the top. Gear can be faked, and replaying a run with fake gear proves nothing.
- Another online-games provider. Same problem as the first one.
- A rented server. Kept as plan B in case costs ever get out of hand.
The decision: the server is the game itself
The server is the same Godot code as the game, just without a window, running on Cloud Run. That way combat is written only once. The flow goes like this:
- When a run starts, the server hands out the seed.
- You play on your phone and see the loot instantly, because the phone computes the same thing with the same code.
- When it ends, the phone sends the doors you picked. The server replays the run with the seed and with the gear it holds itself, and writes the loot.
- If the two do not match, the server wins.
The phone never touches the database: it only talks to our server, which is the only thing that reads and writes.
What a replayable combat demands
For two different machines to play exactly the same thing, combat follows strict rules: only addition, subtraction, multiplication and division (no powers, exponentials, logarithms or clock) and all randomness comes from a seeded generator per floor. Even the ±10% variation on every hit comes from that generator.
And still, one detail bit us: Godot does not always read a decimal back the way it wrote it. When affix rolls went through JSON, 2,853 out of every 20,000 changed in the last bit. Players would never notice, but the phone and the server would be playing with slightly different numbers. Every roll is now stored in a canonical three-decimal form.
What it costs
The simulator plays about 8,000 runs in two minutes, roughly 15 milliseconds each. Replaying a run on the server is cheap.
Versions
Whenever the code that decides outcomes (combat, loot, account) changes, a “rules fingerprint” changes. The server keeps one revision per rules version, and each version of the game talks to its own. So while Apple reviews a new version, the previous one keeps working.
All of this is in internal testing. If you want to see it with your own eyes, join the beta.
This post is also available in: Español