generic APIs or algorithms for avoiding inconsistent world-state in real time multiplayer games?

if the villain kills the damsel-in-distress at about the same time that the knight-errant kills him to save her, the server would need to figure out how to handle the situation. All of it presumably multithreaded, shared memory and generally sounding very scary. So, how do programmers deal with this in real life?

Is there a nice framework that would handle the atomization and hence ordering of the actions of remote players so that the programmer wouldn’t have to bother with it, sort of like we have the nice framework that does TCP-IP reliable communications? Or is there a standard algorithm that all game programmers implement that approximates the behavior of that idealized framework? Or what actually happens?

I guess there is one loop that handles time and the sequence of actions, and whatever this loop says is the law.

Typically the things that are “outsourced” into different threads are things like sound, loading of resources, physics, ect., but not the actual game logic. And even if there are parts of game logic in different threads, they all need to synchronize with the master from time to time to actually do something. All memory that might be influenced by different threads will be protected by a mutex or so, and whatever timestep they get synchronized in is the moment the respective action takes place.

I don’t know if there are frameworks for this, but some sort of master thread with an event queue for communication shouldn’t be too complicated.

IANA game programmer, but in general you’d need updates to your world-state to be transactionalized. And to have the precursors checked on update for no changes and roll back any transactions which assume a start-state that no longer exists.

So ultimately when the *second *world-state update takes place, either it’s the villain-kills-damsel transaction, which will roll back because Villain.Alive is now globally visible as false, or it’s the knight-kills-villain transaction, which will succeed. But which will not restore the damsel to life since villain-kills-damsel has already committed just before it did.

Generic transactions are a well-understood concept and available in many frameworks. Intelligently managing the locking scope & precondition tree would be an iron clad bitch though.

For multi-hundred thousand player scale I’m imagining a need to partition the worldspace. this will work OK since almost all object interactions are local. But how do you deal with interactions at/near the boundaries in whatever partition scheme you’ve got?

I look forward to the folks who really know something of this to give us the details.
ETA: … Must. Type. Faster.

Play online games often enough, and you’ll occasionally see a “lagwarp”, where the game state changes abruptly as a result of inconsistent state being reconciled. Most often, this is just characters abruptly jumping from one location to another, though, not things like deaths.

This is probably better suited for The Game Room than GQ.

Colibri
General Questions Moderator

I doubt that a single-threaded approach would work for the server side. Software transactional memory is getting a lot of attention for this type of situation, but the technology is very new and I’m not sure how many people are actually using this yet, but I think that this has a lot of promise.

(Forgive me if I include details you already know; I just want to be complete.)

There are different ways to run network games, but the common model used in MMORPGs is a traditional client-server model. Each person playing at home is running a client that connects into a game server hosted by the game publisher.

The server runs the ‘official’ game – it has the official copy of the game’s state. Each client has a copy of the server’s game state; although with much less info. A client won’t know the details of other players or of the hidden parts of the game. If you think of a card game being played as client-server, each client would know the cards they are holding and the cards face up on the table, but only the server would know all of the cards.

The server also has the ability to push the game state to any of the clients. If at any time the game server detects that the client is confused or out-of-sync, it will push a fresh game state out to the client. This might make a character jump to a new position instantly (the lagwarp that Chronos mentions).

During a game, each client sends a stream of actions to the server. These actions can be low-level or high-level depending on the type of a game. An arcade game like 4-player Gauntlet might just send raw controls (joystick movement and button presses). A more complex game like WoW might send higher-level actions like swing-main-weapon or cast-spell-x. The server receives all of these actions from all of the clients and processes them in order. Each of these events is processed serially (although that does not mean necessarily in a single-thread).

If you have the case similar to the one you mentioned in the OP: two clients swing their axe at a monster at exactly the same time, one of these actions is going to arrive at the server first and be processed first. In this case, that client would be the one to slay the monster. The key is that in practice it doesn’t really matter exactly which client gets its action processed first. As a player, you would never know that you both swung at the exact same instant and so you both should have hit the monster. Instead, you assume the other player swung slightly sooner. In fact, the delay of packets over the internet will introduce much larger variations in actions arriving out-of-order. In this case, it is not necessary to be perfect, just good enough. Someone swung and the monster was killed. No noticeable artifacts.

Now in the case that Chronos mentioned, where two players are moving at the same time, this is a constructive action and not a destructive one. Both players are sending a stream of move actions (move up, move up, move left, move up…). At the same time the server is telling the clients that the other player is moving with a stream of events. The clients assume that their own move actions will be accepted and they display their character moving. However, as the server is processing these streams of movement actions, it might detect that both players tried to move into the same location and it will have to prevent the second player from entering that space. In this case, the server identifies a conflict and sends a new game state to the second client so that his character can be ‘pushed’ back into an unoccupied space. Sometimes, when the network latency is very poor or the server is overloaded, you will see the characters jump greater distances as the server tries to keep everyone in-sync.

As far as “are there generic libraries that help with these activities”, I think some game libraries (e.g. DirectX) have support for syncing state and sending packets over TCP/IP, but beyond that it is really unique to the game rules. Only the specific game code could know about the differences between the way an axe action and move action should be handled. And which of these could cause conflicts. I suppose you could create a very generic framework, but it might add too much overhead.

For MMORPGs, they are handling so many clients that all of this logic is a herculean effort. As a result, it needs to be scaled and optimized in amazing ways and a generic framework wouldn’t be efficient. In these cases, the code is designed specifically for the game and optimized around the hardware and network architectures.
For less rigorous games, like a 2-person arcade game you don’t need to do a client-server model. Instead, each instance of the game talks directly to the other instance. They send the actions (joystick moves, button presses) to the other instance and the other instance treats these actions as if they happened on a local joystick or button. Then, each instance can send a game state sync to the other just to make sure they are both aligned. This is a nice solution because it does not require a game server, however, it opens the clients up to hacking since each client has to have a complete copy of the game state.

Oh, and in the case you asked about in the OP: Assuming the villain is an AI character, this is really handled by the game state. If the villain kills the damsel before the server processes the knight’s sword swing, then often the game state changes and the villain is marked as ‘unkillable’. The knight’s sword swing would be processed normally, but it would do no damage.

Likewise, if the knight’s action was processed first, then the game state would mark the villain dead and his AI would be disabled and he would never get a chance to kill the damsel.

So while the underlying software mechanisms of sending and receiving packets, synchronizing threads, protecting and updating data structures is quite complex, many of the game rules can be quite straightforward. The cool thing about asynchronous software (like this one) is that you never really know exactly which actions/events will be processed in what order. You are forced to create designs that handle all combinations. As a result, you can pretty much just fire up the systems, start sending events, and everything should be able to work.

And FTR, all of my comments are over-simplifications obviously, but I think the core points are still valid.