12
\$\begingroup\$

Using socket.io, I have a communication similar to that of other MMORPGs, a steady connection with messages.

In my design so far, the client sends the player's position and animation frame with every update frame. When the server gets that message, it broadcasts it to all the clients, which will then move the graphic accordingly.

Would it be a better idea to 'collect' these and broadcast them, say, once in 1/10 of a second?

Also, should the client send many different messages (exp gained, clicked on item) as soon as they occur or rather just one collected? The first would be implemented easier.

\$\endgroup\$

3 Answers 3

17
\$\begingroup\$

I am going to approach this from a high-level discussion and then work towards your questions. For the sake of disclosure, I have no personal experiencing using socket.io but a lot of exposure to the problem space with regards to MMORPGs.

The design of an MMORPGs engine's network architecture and/or the selection of a middle-ware or open source project to provide the functionality is one of the more challenging decisions influenced by the game design, budget and technical expertise of the team. The ultimate choice will influence other architectural decisions (and sometimes design decisions as well).

As developers of MMORPGs, we plan for great success (often also known as catastrophic success) where large numbers trigger warning lights and sirens. One of the scary large numbers that crops up is in algorithms that are N-squared (N^2 hereafter), in your question the first thing that jumped out to me is that it sounded like the design called for an entity to broadcast information to all other connected entities. This is the classic example of an N^2 problem.

MMOs generally approach addressing N^2 issues by attacking the problem in several different ways; awareness systems (situational, spatial, etc) where an entity is aware of some subset of all of the other entities, partitioning players into different "shards", partitioning players in "zones" and/or instancing, implementing game mechanics that discourage too many players from congregating together (Asheron Call's teleport storms), etc.

Most MMORPGs and many FPS engines have fairly sophisticated networking architectures that support a variety of features including:

  • reliable and unreliable communication pathways (TCP, custom implementations of reliable UDP and UDP packets)
  • bandwidth shaping (prioritization, lifetimes, etc)
  • automatic replication of field/viarable data and function calls
  • atomic sets of data (i.e. data that is communicated together)
  • discrete updates (i.e. where every transition is important)
  • latency correction
  • a variety of tricks to make the client feel responsive

I find that the Unreal Networking Documentation and Valve Networking Documentation provide a good primer on a variety of the issues.

So, now lets approach the questions.

Would it be a better idea to 'collect' these and broadcast them, say, once in 1/10 of a second?

It's hard to provide a simple yes or no answer here...because it depends on the scale (number of observing entities), frequency of updates and size of updates. For example, collecting them all might be horridly wrong if the size of the updates could blow a buffer somewhere.

The client for MMORPGs and FPS games are generally designed such that they will visualize something that "looks" right even if they do not receive an update for many more update frames than is "normal". When using unreliable communication (UDP) you can just expect to lose some number of updates into the void, clients can make up for this by sending more frequent updates than might be used with a reliable transport.

From a cursory review of the socket.io documentation, it looks like it supports both reliable and unreliable (volatile in its terminology) communication pathways.

I'd approach this first by tackling, at what frequency are updates needed...

If a player is moving in a straight-line at a constant rate, a lower update frequency is fine because the observing clients can predict with high accuracy where the player will be at any point in time. When a player is turning in a tight circle or making rapid direction changes, then much more frequent updates are required. Conversely, when a player is not moving at all there is no reason to send out movement updates at all.

No matter what, is probably not (generally) necessary to send updates every frame from the client to the server. The server itself may choose to send messages each frame where it has them, or delay them (see bandwidth shaping, prioritization and update lifetime).

Other types of updates have different characteristics...for example consider a "health" field that is modified when a player or creature is damaged. One way to implement this is broadcast each change immediately when it happens, but this leads to wasting processing and bandwidth if the value is changed multiple times in a frame or consecutive frames (networking architectures that implement bandwidth shaping solve this issue by coalesing the updates to only the most recent is sent to an observing client when they have available bandwidth).

should the client send many different messages (exp gained, clicked on item) as soon as they occur or rather just one collected?

Again, no simple yes or no answer is going to work here. Depending on what precisely you mean by collected...both may be right under different circumstances and also depend on implementation of the networking layer.

Collecting messages for a specific entity to be sent as one message can (depending on implementation) reduce the bandwidth overhead for sending a message (reducing your costs) conversely (depending on implementation, such as field/value mappings communicated by strings) can increase bandwidth requirements compared to a simpler specific message type.

Reviewing the socket.io documentation, it would appear to me that message overhead is on the higher end of the spectrum which would favor collecting updates to send as an aggregate message as opposed to lots of single updates.

I'd recommend reviewing all of the updates you contemplate replicating, for example most MMORPGs and FPSs do not bother to send player clicked on X events to observing clients unless that would result in a state change for an object of which they were aware as well.

\$\endgroup\$
1
  • 3
    \$\begingroup\$ +1 Great answer. I would additionally suggest starting simple and optimising from there. Spam messages, sure, go wild, and see your bandwidth start to fizzle. This is why it's good to have staged stress testing. You implement the naivest possible approach and do some testing; you do some optimisations; you stress test again, you optimise further, rinse, repeat. If it's absolutely trivial to implement an optimisation on day one, go ahead; but be aware that even the most trivial optimisations may carry assumptions that may later be disproven in a production environment. \$\endgroup\$
    – Engineer
    Commented Nov 2, 2011 at 22:37
6
\$\begingroup\$

Here's a real-world example: RuneScape "ticks" once every ~0.6 seconds. You can read about it here. I imagine it simplifies things from their perspective, as in their scripts they probably specify timings and delays in ticks instead of milliseconds. And of course, with such a large/slow tick rate, users with slow connections are not at a huge disadvantage compared to other players.

\$\endgroup\$
1
\$\begingroup\$

One way of working is to decouple the actual data changes from the broadcasting of those changes. When an object changes, make the modification and set a 'dirty' flag, and when it comes time to broadcast any changes, only send data for flagged objects, and clear the flag. Values that get changed multiple times are automatically merged here because your update only sends the state at the time of the broadcast. You can also flag sub-objects or individual properties so that you only broadcast what has changed.

Oh, and usually you wouldn't send out the animation frames to the server, or the other clients. The precise animation state is usually considered a presentation detail and left to each client to resolve, and instead you just make sure each client knows which animation is currently playing.

\$\endgroup\$
2
  • \$\begingroup\$ I wouldn't? What about poses or something, I need to be sure all the clients see the same? \$\endgroup\$
    – Lanbo
    Commented Nov 7, 2011 at 18:06
  • \$\begingroup\$ It's quite impractical to ensure that every client sees exactly the same thing because information takes time to travel, different clients have different network latency, they render at different speeds, etc. So trying to get everybody to show exactly the same frame simultaneously is usually a futile endeavour. Instead you might just try to ensure they start the same animation at roughly the same time, and that is good enough. \$\endgroup\$
    – Kylotan
    Commented Nov 7, 2011 at 23:01

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .