8 ms·
Networking of a turn-based game
- wanderer_ 5y agoI have poked and prodded at making my own turn-based game, and one thing I have learned is validation. Don't trust input, and you will make robust serverside code. Assume every bit sent by the client was maliciously sent in order to bring down your service in flames. Keep this mentality, and security becomes that much easier. AJAX long polling is a good way to send data while avoiding spurious requests and/or delays, albeit with a bit more load on the server.
- MrLeap 5y agoSeconded. The way I look at this is to always build the allowable action space from nothing, and default to nothing. Most of the time it involves a state machine where each node comes with a white list of currently allowable verbs a client can send. The alternative is an infinite action soup, which opens opportunities for inspiration by lateral thinking. I'm doing it this way for a single player Lovecraftian text editor I'm working on. It's a terrible idea for multiplayer things.
- ulber 5y ago>single player Lovecraftian text editor I hope that was not a typo and would love to see what a Lovecraftian text editor looks like.
- whtrbt 5y agoIt's in their user profile https://store.steampowered.com/app/1537490/Tentacle_Typer/ https://store.steampowered.com/app/1537490/Tentacle_Typer/
- MrLeap 5y agoThank you whtrbt for linking my steam page. It's a pretty out of date I regret to say. I'm doing it from the woods and have to go a town over to the library to upload HD video. For some reason it's easier to upload to twitter via tether, so it's where I've got the latest. https://twitter.com/LeapJosh https://twitter.com/LeapJosh
- ricktdotorg 5y agoonly semi-related due to text + lovecraft but worth a few hours of dread: telnet cthulhumud.com 8889
- burntoutfire 5y agoMost of the software is Lovecraftian...
- burntoutfire 5y agoMost software is Lovecraftian...
- Spivakov 5y agoAbout deterministic propagation model: "It relies on the assumption that processing the actions of a player is deterministic." I am curious in what scenario of online gaming does this assumption fail. I remember that about a decade ago there was a mobile game called Chaos and Order (like dota/League of Legends but was played on apple device). In one game, I heavily outplayed my opponent. After winning the match we added friends and realized that we actually experienced two totally different games - he lost it in my game but won it on his side, and my in-game actions made nonsense in his one. We called it a "ghost". It is just funny to see how crappy the outcome would be if the deterministic propagation fails. Also in context such as system theory where error inevitably happens, the design shall make sure the extent of failure will not go unbounded.
- baggy_trough 5y agoUsually bugs, for example if the rng doesn't get handled in precisely the same way.
- meheleventyone 5y agoThe very worst kind of determinism errors are butterfly effect like in that you don’t notice the desync until long after the cause has occurred. It’s pretty imperative if you’re building a deterministic system to add a layer of error checking right from the start so you can ensure each party ends up in the same state and identify desync very early. On the other hand you also want to identify where desync doesn’t matter (for example most FX) so you limit the scope of what has to be deterministic to keep things simple.
- ermir 5y agoThis is called a "desync" and is a bug in a particular implementation of multiplayer networking. In this model instead of the server sending the state to each player, it sends their inputs, and allows the local device to completely determine the state of the game. If there are any differences at all in how the game's calculations are made, the game will have different states in different devices. Even different models of the iPhone may have tiny differences in how they calculate the square root for example, and over time these minor differences cascade into totally different games.
- bob1029 5y agoIn my experience, most of the pain boils down to synchronization of state between participants. This is also your principal vector for cheating. If you are willing and able to make a very extreme sacrifice regarding client-server architecture, it is feasible to consolidate all state to 1 synchronous domain while serving an arbitrary number of participants. The sacrifice is basically to build your game as a native take on the Google Stadia model. I.e. inputs are raw player events, output is a low latency A/V stream back to player. Keep in mind you don't have to always serve an x264 stream to all clients. Depending on your objectives and type of game, you can serve an intermediate view model that instructs the client on how to draw its view using local assets and resources (textures, models, gpus, etc). This would be more like how Blazor server-side model operates.
- jay_kyburz 5y agoWhat you said is kind of complicated way of saying what I do. Player client sends simple commands to the server. Server validates the command and updates game state. The server then just simply listens for other clients to request the state of the world, at which point it sends a compete blob of data that includes everything that client can see! The player can then interpret that data and send new commands as required. My games are basically turn based so I don't need to poll the server constantly, just at the start of your turn and after every action.
- jpgleeson 5y agoSpeak of the devil. I was just talking with someone about Neptune's Pride a few weeks ago and looked it up to see if it was still going. I really enjoyed that when it came out. Have you ever written about the architecture of that and Blight anywhere?
- jay_kyburz 5y agoI haven't because I really have no idea if any of it is any good. I just sort of muddled through it all. I've been slugging through a re-write of the server from python to JavaScript because the Python code base is all out of support now and I expect Google to pull the plug on the 10 year old App Engine tools that its built on.
- CyberShadow 5y agoThe second-generation Worms games (2, Armageddon, WWP) use the same approach (here called "Deterministic action propagation method"). It was implemented by Karl Morton, and we also use it for replay files (which is why the game logic is meticulously versioned). The solution we used for managing secret state, when the state is from a random source, is to delay generating the secret information for as long as possible (so, e.g., if a card is drawn, the drawn card is decided at that moment, as opposed to pre-shuffling the deck at the start of the game). We experimented with some designs in which the secret is revealed only to the player who owns it, and the rest only see a verifiable hash of the secret until the player performs an action which reveals the secret; however, it doesn't solve the general problem that any time the game must immediately (without network latency) make a random choice, the design must compromise between either allowing a hacked client to predict the result (when the RNG output is stable) or manipulate it (when the RNG output changes very often, e.g. every frame). Sadly, the newer games went for a simpler synchronization algorithm, in which if a discrepancy is detected, the entire state is simply copied over from one player's game to another. This does allow blatant cheating; I'm guessing it was a concession due to the new engine lacking in robustness or portability.
- infinite8s 5y agoThis is a really interesting approach for managing secret state. Another life ago I implemented a rule-based version of everyone's favorite collectible card game, and it was P2P (so each client ran the full rules engine and synchronized the initial random seed and the each player's actions). I could never figure out a good way of limiting cheating by peaking at either your own deck or the opponents. I looked into commutative encryption and mental poker, but at that point my interest in the project fizzled and I stopped working on it. This approach would work for keeping randomness in the game, and homomorphic encryption could be used to hide the contents of the opponent's deck.
- noduerme 5y agoThere's a third way of thinking, best exemplified by Agar.io and things like that which basically asserts that any network latency is the player's problem. There's a deterministic state on the server, and the UI doesn't bother to try to sugarcoat it to make it feel any more instantaneous than it is. IMHO this is the only way most games will be written down the line. I'm an old casino coder, so the "tricks" were things like, slow the card deal animation; keep the roulette wheel animation going longer; etc. But where money's concerned you can't take shortcuts, and in the end a player with a faster connection has a better experience, and (in casino land) those are the players with money anyway. I'm not sure I understand why there'd ever need to be an instant result (sans network latency) in a turn-based game. If the player has a visual indication that the server is waiting for their command, then any jumpy movement on the part of other players is strictly down to their own bad connection as long as the server is running well. If players understand that the alternative would be the ability to cheat, they'll generally accept that and upgrade their network connection.
- d0m3 5y agoNice article. I built my own online version of a turn based board game because none exists at the moment. I just want to play with my family so I didn't bother coding a server at all, instead all clients communicate their actions to all others so I naturally implemented the deterministic approach. I haven't thought about secret state so it's interesting to see a possible solution for that. Fun!
- sjrd 5y agoI'm also writing an online version of a board game I like, to play with family and friends. I am about to start the networking part, and I actually intended to implement the deterministic approach, although I didn't know the concept had a name before reading the article. It's nice to read some validation that it is a good design. I'm curious to know how you achieve not to need a server at all. How do you create the initial connection between clients without a server to negotiate NATs and things like that?
- infinite8s 5y agoIf your game is web-based, you could leverage WebRTC - where you only need to share a unique link between users - see peerjs (https://peerjs.com/ https://peerjs.com/) or croquet.io (https://croquet.io/docs/croquet/ https://croquet.io/docs/croquet/)
- sjrd 5y agoIt is web-based, yes. I was aware of WebRTC but assumed I would need a least to host the server myself. I'm looking at the links you provided and they seem very interesting. Thank you.
- JoeOfTexas 5y agoIf you target desktop, should be fine, but mobile users tend to use cell towers which are on Symmetric NAT, which would require a TURN server on top of the WebRTC.
- 5y ago
- yazaddaruvala 5y agoCould someone explain to me why CRDTs are more utilized by game developers for managing shared state? Aren’t game servers just chat servers with extra constraints on the messages, e.g. physics, chess rules, etc?
- hypertele-Xii 5y ago> Aren’t game servers just chat servers with extra constraints on the messages, e.g. physics, chess rules, etc? In a chat, information is simple, unordered, and public (to all parties). Now imagine a turn-based strategy game where complex moves happen in random order and are known to all players regardless of unexplored territory. For real-time games this analogy really breaks down.
- bombcar 5y agoBecause you want more than just the messages and the handshakes - you want to maintain consistency and if possible even recover from desync and other network weirdness - without allowing cheating.
- yazaddaruvala 5y agoAren’t all of those exactly the features of a CRDT? Regarding cheating and bad network, you still need all the same client side stuff and to define the conflict resolution policies into the CRDT, but the rest of the needed features (e.g. consistency, rewind, replays, etc) are all part of CRDTs.
- vore 5y agoMost games don't require merging of divergent state like in a CRDT: there's one, single, linear history of events mediated by the server. CRDTs are overkill for this use case, and something like optimistic concurrency control by the server is usually much easier to reason about and implement.
- meheleventyone 5y agoBecause usually you can use a simpler scheme.
- infinite8s 5y agoOne nice thing about turn-based games is that the logic for the game usually runs so fast that you can run it 'in-between' user events, so using a coroutine approach makes it pretty easy to write the game engine in a direct style with the rules explicitly coded in a straightforward fashion: for turn in game: for player in players: action = await player.get_action() engine.dispatch(action) The nice thing is this approach supports remote proxy players - when you get an action from the local player you can send it out to all connected clients.
- furyofantares 5y agoFor turn based games like board games, I make clients that don't have any concept of the game rules at all. The server generates a complete list of all available actions to the player and sends an array of all actions along with the game state. When you take an action the only payload the client sends is the index into this array. In this way the client has no way to express a cheat whatsoever.
- deleted 5y ago[deleted]
- hpx7 5y agoHow do you handle actions that are not enumerable? For example, in codenames where the spymaster has to give a clue which can be any english word
- 10000truths 5y agoEnglish words are enumerable. There’s just a few million of them. The dictionary is large, but it’s not like it changes frequently, so you can treat it like a static asset that gets downloaded once and only updated periodically out of band.
- reitzensteinm 5y agoThe specific example may be faulty but the general point absolutely is not. I've built turn based games where enumerating the space of actions grew at a x b x c and would have easily measured in the megabytes. It's just not a practical general solution, but it sure works fine for something like Monopoly.
- jayd16 5y agoYou don't need to be so literal. An action like "game action XYZ" with a client smart enough to know how to show a text field and enable submission is sufficient. The point is just every bit of logic about when an action is enabled must be implemented on the backend for verification, so spelling that out to the client reduces duplication.
- JoeOfTexas 5y agoI also built a similar engine to boardgames.io using the Delta-update approach, which you can try at acos.games. Deterministic lockstep is like trying to build a house with wet paper. You'll need to stack and compress millions of layers to make it solid. Delta-update while not the best for bandwidth, is the cheapest for moving forward. I don't want to waste time fixing desync issues, when I can be creating more games and more features. I'm still writing about my experience and showing exactly how I built my Delta-update networking model, but its working really well so far.
- alephnan 5y agoVery insightful thread and epitome of HN bringing out people with deep expertise on a subject. Multiplayer video game networking is a standalone discipline in its own right. It feels like most Computer Science departments are producing candidates to work for BigTech co that are focused primarily with large scale data access/processing. But video games gets so specialized that it takes on its on form. To be more concrete, A.I./M.L. for finance is going to be different than video game A.I. Occasionally something like A* can be applied to a "real world" problem, precluding video games, but almost every video game programmer knows A*. I'm curious, did you acquire your video game experience from working at Big Budget game, indie game, video game development school, self taught from special interest forums (if so, is there an equivalent of HN or Reddit), or a traditional CS education?
- forgotusername6 5y agoA similar problem exists in modern video codecs. You want to update the decoder with diffs based on some shared state. The problem is you don't really have "actions" you can do. You can say "start with this key frame" and then "this macroblock moved to here" but the fine detail of the change is likely unique and you need to send that diff explicitly.
- ghawkescs 5y agoHas anyone had success using off-the-shelf solutions that are popping up from AWS and Azure? Are there other good OTS options out there from other gaming-focused vendors for multiplayer servers and network layers?