2
\$\begingroup\$

I'm not sure if "game state" is the correct term, as my searching shows me a lot of results that are not relevant to my question. When I say "game state", I'm talking about the internal state of the game being played: what units are spawned, where they are located and headed, what players are playing, what their current scores are, etc. Everything that would get wiped out if you were to start a "new game".

That said...

I'm curious how other people or other games handle the issues of client and servers appearing to need access to more than one copy of the game state.

For example, the client's job is to accept game state updates from the server, and render them. However, the server updates are usually much slower than the client render speed, so the client needs two copies of the state information in order to interpolate between the two and make everything appear to be moving smoothly. I'm not sure how you would accomplish this without having the client hold two copies of the game state, copying the current to the previous whenever the server sends an update.

Likewise, the server needs to make decisions on the current game state, and apply changes. However, if it only has one copy of the game state, then any changes it has already made will influence future decisions. If two players shoot at each other at the same time, and the server processes one shot before the other and writes the result to the same game state, it'll see the second player as now being dead and unable to shoot. If it had two different game states, "current" and "next", any new changes (such as player death) would be written to the "next" state, and since they are both still alive in the "current" state, each shot would get processed and both players would end up dead, as expected.

However, having multiple game states creates a lot of other problems:

  • Each copy of the game state could be very large, with many players playing, and hundreds or thousands of units moving around the game world. This would be a lot of data to be copying around just to keep multiple game states synchronized.
  • While having two separate game states fixes the server problem of two entities killing each other at the same time, it presents new problems when an entity is newly-spawned. You might spawn an object into the world, and then want to immediately have it perform an action, or have other entities start to interact with it. Problem is, that new entity doesn't exist in the "current" game state, it only exists in the "next" game state. The server would have to wait until the next cycle, when the "next" state became the new "current" state, before the new entity was available for interaction.

I'm leaning towards just having a single state for the server, just for simplicity, but I don't see how to avoid keeping two copies for the client. How do other games handle this?

\$\endgroup\$
2
\$\begingroup\$

glossary: what I call "sequence point" is a logical grouping of "when everything is done" and it's mostly synonymous with "each frame" or "each full AI cycle" depending on the game, etc...

No one sends an entire game's state at each sequence point (frame, heartbeat, whatever). Only changes are sent and, in games with large areas only changes local to the client are sent to that client.

The client uses its internal copy of the game running and the copy of the server's version of the game at time T exactly like you described. The client interpolates between the server time T and its internal time to keep things looking smooth. Note: "server's copy" is almost always just a few important variables, not everything.

Stop worrying about memory for the game state. Size of game state data is dwarfed by art/audio assets for every title except maybe Dwarf Fortress =)

To get around your simultaneous-but-not problem servers can run a simulation frame and store up commands to be executed at the end of processing. In this case both entities add "I shoot this other guy" and at the end the server shoots one and then the other with no logical sequence problems.

Spawning an enemy and activating it on the next sequence point is perfectly OK. In fact, that new enemy isn't actionable by anyone until the next cycle in the first place because it doesn't even exist in the current cycle.

The theme is to build up commands to be handled after all inputs from the current state have been processed independently. These commands set up conditions for the next cycle to process, whether the command adds a new enemy or kills something doesn't matter.

\$\endgroup\$
  • \$\begingroup\$ I'm not worried about memory usage of the game state so much as CPU time spent copying large blocks of memory over and over every frame. But I really like the idea of queuing up commands to process after handling all inputs, I hadn't considered setting it up that way. \$\endgroup\$ – Nairou May 26 '14 at 1:52
0
\$\begingroup\$

Nobody sends the entire "game state" over a network every frame.

Instead, only updates are sent.

For example:

Player 1 stopped at coordinates (-5.2, 21,8, 0.3)

Player 1 started walking in direction - current pos: (-5.2, 21,8, 0.3) dir: (1.0, 0.0, 0.0)

Player 1 started running in direction - current pos: (-4.2, 21,8, 0.3) dir: (1.0, 0.0, 0.0)

On the client side, you can track the target position, and the player will always be moving from the current position to the target position. Even if the target position changes, the player can continue to always move towards the target position.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.