Client-Side Patching Ensures a Bright Future

Client-side patching is exactly what I need for the low bandwidth of my server. 11 https://github.com/By-Ha/Checkmate/pull/11

Why Patching Overhead Matter

We are playing on a normal FFA map with players. Given a player covering of the map, for example in late-game battles. Then how much network traffic is spent on transmitting map updates?

The workload is undoubtedly acceptable if only cities and generals should be considered - and that’s usually the case - but the problem arises when it comes to incrementing empty lands.

Typically you would expect a sudden burst of patches at the beginning of each round. In this hypothetical scenario, about lands get updated from the perspective of the player. Thanks to generals.io’s compression-based patching, we are free from sending the whole patch over the web.

JavaScript implementation of generals.io’s patching algorithm: https://github.com/vzhou842/generals.io-Node.js-Bot-example/blob/master/main.js#L69

A sequence of unchanged lands are compressed into a single number, indicating how many positions we shall skip when processing a diff. Actually, it works exceptionally well in large maps where there are more consecutive lands.

Before a patch is transmitted, it’s serialized into JSON arrays and become a part of a WebSocket frame. Since the frame is plain UTF-8 on most servers (including generals.io), we are able to use the length of JSON string to estimate its size.

To simplify the calculation, we just suppose that a land ends up UTF-8 characters in JSON on average. That’s a relatively fair estimation, taking the width of land amounts, skipping points and JSON separators (,) into account.

Therefore, our payload size for the player is

Suppose there are two more players fighting and the other five spectating in late-game. Our total outbound traffic during this turn is (don’t forget spectators recieve a full patch!)

This overhead scales rapidly with more players, larger maps, faster speeds, fancier modifiers, multiple rooms and simultaneous games, ultimately evolving into a real trouble for:

  • Users whose Internet connection is poor;
  • Servers whose bandwidth is low;
  • Admins who pays for their resource usage.

Our Solution

The idea is deadly simple: a majority of map patching can be offloaded to the client side. When a new turn begins, the client first applies a partial natural update to its own view. The natural update works identical to what it does on the server: iterating through the whole map to find generals/cities/lands/swamps and update their amounts.

To keep client view synchronized, the server also holds a copy of each team’s map view, and applies the same partial natural update per turn.

After that, regular game mechanisms take effect on the server, including full natural update, player movements and modifiers, which directly operate on the real map.

Finally, the server masks the real map for each team, comparing it with corresponding view and returning the patch to the client.

Now we feel very optimistic about patch sizes: natural updates stay the same even after masking, so it will not end up in the patch at all! As a result, the patch contains nothing but updates caused by player movements, bounded by the maximum player count ().

Wait, what if one captures another? Well, although it’s still worst-case, captures cannot happen repeatedly as , which is guaranteed by game logics. In other words, their contributions are definitely negligible.

By means of eliminating natural updates from map diff, we could achieve an averaged complexity in the network overhead of per-player patching, in contrast to the previous method’s . More specifically, the payload size for a single player has shrinked to

Realworld Application

This patching strategy has already been implemented in polygen22 https://codeberg.org/polygen/polygen and has dramatically reduced our overall I/O resource usage. We believe this approach is both simple and effective, production-ready for your generals-like games, whether you are working on the official site or building a custom server.

  1. 1https://github.com/By-Ha/Checkmate/pull/11
  2. 2https://codeberg.org/polygen/polygen