More efficient multiplayer map download
Posted: Sun Apr 03, 2016 12:27 am
This is a suggestion on how the map is downloaded from a headless server in multiplayer mode.
As it stands, when a player connects, all other clients are paused while the new client downloads the map. This is okay for high download speeds, consistent connections, and few players, but if any of these change, and as the game progresses, it starts to affect gameplay poorly.
This suggestion is simple, yields great benefit to multiplayer gameplay, but requires some work in the way of development.
Suggestion: When a new player connects, instead of copying a zip of the game, make a tar.gz of the current state of the game and copy that over. In the meantime, don't pause the game for other players. When the tar.gz file has been copied (let's call this base.tar.gz), pause the game for current players, make another tar.gz of the game (let's call this current.tar.gz), and make a binary patch with xdelta between base.tar.gz and current.tar.gz. The patch will be no more than a few hundred kilobytes, according to my tests. Send the patch over, have the new player apply the patch to their copy of base.tar.gz, and then sync up to the game as if they had downloaded the original zip and extracted.
Benefits:
I have a headless server running in a CentOS VPS. I connected to my server, and my client downloaded mp-download.zip. I then copied this to a different directory and named it mp-download-orig.zip. I then played for 2 minutes until a save occurred. After that, I disconnected and reconnected to the server, which resulted in another ~8.6 MB download of mp-download.zip. I copied this mp-download.zip and renamed it mp-download-new.zip.
I then unzipped both into mp-download-orig/ and mp-download-new/ respectively. Then I ran `tar -czf download-orig.tar.gz mp-download-orig/` and `tar -czf download-new.tar.gz mp-download-new/`. Then `xdelta delta download-new.tar.gz download-orig.tar.gz download-tar-gz-diff`. After an `ls -la`, I got this:
As you can see, the patch file is only ~319 kilobytes, while a full map download is ~8.6 MB. xdelta is an open source binary diff/patch creation/application tool. It automatically works with gzip, as well. It can be compiled freely into the client, which brings me to my last point:
Costs:
As it stands, when a player connects, all other clients are paused while the new client downloads the map. This is okay for high download speeds, consistent connections, and few players, but if any of these change, and as the game progresses, it starts to affect gameplay poorly.
This suggestion is simple, yields great benefit to multiplayer gameplay, but requires some work in the way of development.
Suggestion: When a new player connects, instead of copying a zip of the game, make a tar.gz of the current state of the game and copy that over. In the meantime, don't pause the game for other players. When the tar.gz file has been copied (let's call this base.tar.gz), pause the game for current players, make another tar.gz of the game (let's call this current.tar.gz), and make a binary patch with xdelta between base.tar.gz and current.tar.gz. The patch will be no more than a few hundred kilobytes, according to my tests. Send the patch over, have the new player apply the patch to their copy of base.tar.gz, and then sync up to the game as if they had downloaded the original zip and extracted.
Benefits:
- Current players will not have to wait around for the full duration of a download.
- A player who is momentarily disconnected will be able to reconstruct the most current version of the game by telling the server what base they have, and getting a patch instead of a full download. So this is good for inconsistent connections.
- Servers will have a greatly reduced bandwidth load for players constantly connecting and disconnecting.
- For a single player on a server, they'll never have to download the full map after the first play since the map won't change between connections.
- This doesn't have to be a required method. Both the current way of doing things, and this way can be possible with the same game. It would be up to the server to do it one way or another.
I have a headless server running in a CentOS VPS. I connected to my server, and my client downloaded mp-download.zip. I then copied this to a different directory and named it mp-download-orig.zip. I then played for 2 minutes until a save occurred. After that, I disconnected and reconnected to the server, which resulted in another ~8.6 MB download of mp-download.zip. I copied this mp-download.zip and renamed it mp-download-new.zip.
I then unzipped both into mp-download-orig/ and mp-download-new/ respectively. Then I ran `tar -czf download-orig.tar.gz mp-download-orig/` and `tar -czf download-new.tar.gz mp-download-new/`. Then `xdelta delta download-new.tar.gz download-orig.tar.gz download-tar-gz-diff`. After an `ls -la`, I got this:
Code: Select all
$ unzip mp-download-orig.zip -d mp-download-orig/
$ unzip mp-download-new.zip -d mp-download-new/
$ tar -czf download-orig.tar.gz mp-download-orig/
$ tar -czf download-new.tar.gz mp-download-new/
$ xdelta delta download-new.tar.gz download-orig.tar.gz download-tar-gz-diff
$ ls -la
drwxr-xr-x 4 domgetter domgetter 4096 Apr 2 16:12 .
drwxr-xr-x 7 domgetter domgetter 4096 Apr 2 15:51 ..
-rw-r--r-- 1 domgetter domgetter 8360935 Apr 2 16:05 download-new.tar.gz
-rw-r--r-- 1 domgetter domgetter 8353529 Apr 2 16:05 download-orig.tar.gz
-rw-r--r-- 1 domgetter domgetter 325893 Apr 2 16:12 download-tar-gz-diff
drwxr-xr-x 3 domgetter domgetter 4096 Apr 2 15:44 mp-download-new
-rw-r--r-- 1 domgetter domgetter 8968251 Apr 2 15:41 mp-download-new.zip
drwxr-xr-x 3 domgetter domgetter 4096 Apr 2 15:44 mp-download-orig
-rw-r--r-- 1 domgetter domgetter 8962909 Apr 2 15:33 mp-download-orig.zip
Costs:
- Developers will have to integrate a diffing/patching tool into the server and the client, though xdelta looks most promising.
- (added in edit 1) Xdelta is GPL, which may cause issues with integrating it directly into the client. Some research will have to be done by the devs on how to use it or any other binary diffing tool.
- There is a trade-off here between bandwidth and processing. Creating the diffs and patches isn't free, although it happened in a reasonable amount of time with my tests. With xdelta, it didn't take longer than a second to make a diff between the zipped tar files.
- (added in edit 2) The diffs and patches would require the delta-making peer to hold on to the base save file until the asking peer is ready for the delta. Of course, peers by default hold on to 3 autosaves, so this probably won't be as big of an impact. But I don't know how big save files get, so this is something to consider.
- Servers may have to hold on to more savegames from the past to have more diff bases. This is probably configurable.
- Not a silver bullet: If the client and server don't share a recent base tar, then the client will have to download the whole thing anyway.
- I don't know how this idea integrates with how the game operates normally, in terms of syncing and all that jazz. It may be un-implementable for other reasons.
- This is more beneficial for people running servers, as the download speed would be greatly reduced overall, although players still benefit from not having to wait for others as long, even if it's the first time the new player connects.
- I don't know how this would work for peer-to-peer, but since a headless server is more-or-less a peer, it would seem that this solution would work for regular multiplayer games as well.
- (added in edit 1) There are other binary diffing tools to look into. I only tried this out with xdelta.