When the host leaves the table
Host-authoritative multiplayer has one weakness: the match lives in one player's process. Per-player secrecy and host migration pull in opposite directions. Choose on purpose.
The design that makes Turup Chaal cheat-proof is the design that makes it fragile in one specific way. The match runs on exactly one phone, the host's, and every other player only ever sees a redacted view of it. That is the anti-cheat property, and I wrote about it in the first post. It also means the match lives in one process, on one device, on one mobile connection, in one person's pocket, and that person can walk into a lift.
What happens next is a thought experiment I ran many times before settling the design, and the answer is less comfortable than the marketing for any networking library suggests.
What the library gives you
Photon's room model has a master client, and its documentation on master client and host migration is unusually clear about what happens when that client disconnects: the server picks another actor in the room as the new master client, and it does not hand the new one any of the room state the old one held. No player properties are moved, no cached events are replayed, no events addressed to the old master are resent. The developer is responsible for making sure no state is lost across the switch. That is not a limitation of Photon; it is the honest statement of what a relay can know. The relay never had the state. The host did.
The same holds in Photon's lower-level Realtime layer, which PUN sits on: the server can tell you who the new master is, and nothing more. So a new master client is elected within a second or so, and it knows nothing about the match. The state has to come from somewhere, and the redaction rule has already decided where it cannot come from.
The succession test
The usual answer to host migration is to have every client keep a copy of the state, so that whoever becomes host can continue from it. In a game without secrets that works. In a card game it is precisely the design the anti-cheat rule forbids: if every client holds the full state, every client holds every hand, and a modified client reads them off the wire. Redaction and migration want opposite things from the same bytes.
The test I ended up with makes the conflict explicit. For every piece of authoritative state, ask two questions: who else holds it, and were they allowed to see it. State that every client holds and may see, the table, the trick counts, whose turn it is, survives the host without any work. State that only the host may see, the other hands, the undealt deck, cannot survive the host, because the only copy that was allowed to exist just left. The design has to do one of three things with it: end the round, reveal it at the moment of migration, or move it somewhere that is not a phone.
The three answers, honestly
Ending the round is the answer Turup Chaal gives, and it is the least satisfying and the most honest. When the host drops, the hand in progress cannot be reconstructed without revealing what the anti-cheat design was built to hide, so the hand is void, the score from completed tricks is kept where every client already agrees on it, and the next hand starts with a new host and a new deal. Players dislike it, and they dislike it less than they would dislike a game where hands leak.
Revealing at migration is the tempting compromise: at the moment the host drops, the remaining clients pool what they know, which is their own hands, and the undealt cards are the complement. The hand continues with a new host who now knows everything. The trouble is that "the host dropped" is an event any client can cause by disconnecting their own phone, so the compromise hands every player a button that reveals the table. The test catches it in one line: the state was not allowed to be seen, and now it is.
Moving the state off the phones is the real answer, and it costs money. A dedicated server holds the full state, deals, validates and redacts, and no phone ever holds more than its own view. The host cannot leave because the host is not a player. That is the top-right cell of the matrix, and it is a monthly bill for the life of the game, which for a free card game built by one person is the reason it is not the answer. It becomes the answer when the game earns enough to pay for it, and the code is already shaped for it, because the engine that runs on the host phone is the engine that would run on the server.
There is a fourth option that looks like an answer and is not: encrypt the full state and give every client a copy they cannot read, with the key held by the host, to be released to the successor at migration. The trouble is the release. If the host is gone, so is the key, unless it was escrowed somewhere, and the only somewhere available on phones is the other clients, which returns the problem to where it started. A key split among the remaining players so that any two can reconstruct it is a real construction, and it is also two players agreeing to see everyone's hands, which the game's rules forbid. The succession test catches this one too, one level down: the key is state only the host may hold.
How often the host actually leaves
The choice between ending the round and paying for a server should be made with a number, and the number is how often a four-player match loses its host in the length of a round. If each player disconnects at some rate, the chance a match survives a twenty-minute round is the chance that all four stay, and the chance that the specific player who is host stays is one fourth of the story; the other three dropping merely costs a seat. I modelled it simply, with independent players and a per-player hourly disconnect rate, to see the shape.
The curve says what the decision depends on. On good connections, a host drop is a few percent of rounds, and voiding the hand is a small annoyance that a server would cost a great deal to remove. On poor connections, where a player drops every couple of hours, a fifth of rounds lose their host and the annoyance is the game. The same design is right for one population and wrong for the other, which is why the number has to be measured on the players you actually have rather than assumed.
The rule
Write down, for every piece of authoritative state, who else holds it and whether they may. The state only the host may see is the state that dies with the host, and there is no clever protocol that keeps both the secret and the availability on phones alone. Choose the cell of the matrix on purpose, tell the players what happens when the host leaves, and measure how often it happens. Turup Chaal ends the hand. It says so, and a game that says so is more trustworthy than one that quietly reveals the table to whoever pulls the plug.
Get new posts by email
Occasional essays on engineering, AI, and building for the people technology leaves behind.
Subscribe with RSS