Written by: Agustinus Agri Ardyan
Edited by: Monic Andyani

Game  update is one of the ways to keep our gaming experience smooth — that’s  just how important it is. The challenge is that the size of the game  update today can go up to GBs, especially when we talk about AAA games.  While this is not a problem for some countries with high internet speed  like Singapore and Baltic countries, it’s not quite the same for the  rest of the world. In that case, one of the solutions is to reduce the  update size. So how do you do that?

To  reduce the update size for a game or application, we reuse bytes from  old files. This concept is implemented in AccelByte’s BuildInfo, and as a  result, BuildInfo V2 was born. Think of it like we recycle the old file  and require users to download only the necessary parts from remote to  patch the old files to the latest version. Previously in BuildInfo V1,  we had an updated algorithm to chunk each file into smaller chunks. For a  small number of users updating simultaneously, I think the performance  is alright and everyone is happy.

However,  when the number of users rose high, the server load increases  significantly. We make it so that in every game update request, the  BuildInfo service will compare every chunk from the user’s version with  the latest version and then respond by returning only chunks that don’t  match. This process is called diffing. However,  there is no guarantee that the update size will be smaller than the  competitors’ nor that the update size will be in a small amount. In a  case, the V1 update size is two times bigger than the one on Steam.

To  figure out a way for an efficient update, our team did some research by  implementing several algorithms. We were thinking to use the  widely-known Rsync algorithm initially, however, we found out that Rsync  is one of the main causes why our server load is severely heavy, we  decided to switch to Zsync (Kudos to the team Rafi, Stradley, and  Windio!).

There  are several open-sourced MIT-licensed library for Zsync available in  public. After a thorough examination of those libraries, we need to make  sure that it doesn’t implement another proprietary library or any  licensed library that might hinder us to fully alter and use it  commercially. The next step is to alter some of the code in it and  adjust it accordingly so that it will suit our case. In this case, we  add a splitter feature to make things run smoother and I also created a  wrapper and removed some unused features, so that it is easier to be  integrated to the Launcher.

To  ensure that everything will run without fail, I helped the Quality  Assurance team by creating a script to check the download size of game  update via BuildInfo V2. I personally believe that the script is helpful  for the QA team to use as a tool to cross-check and to ensure that the  download size in the Launcher is correct. I also assisted the Launcher  team to integrate the new build into their code. I will not claim a full  credit here since I am not working alone, I am grateful that the teams  are backing up one another. For instance, just right after I finished  the integration task, it turns out there are some defects along the way,  and the Launcher team is there to help me to fix the issue.

The  technology that we use is similar to BuildUtil, which is Golang. What’s  nice about Golang is that it gives us a future maintenance advantage,  since there are a lot of our engineers that are able to speak Golang.  Can I confidently say that the technology we use is good? Well, good is a  word with a broad meaning, since every algorithm or any tech has its  own tradeoff. The BuildInfo V2 tradeoff is that it will take more time  before downloading, especially when there are lots of files because it  needs to calculate which bytes to reuse and which ones to be downloaded.  However, it’s very effective to reduce update size as much as possible  to solve the current issue. In the future, we plan to make it even  faster and more efficient by using a faster hash generator combined with  another algorithm and/or something else.

Every  project has its own obstacles. As for this project, the integration  process to our Launcher was one of the toughest obstacles that the team  managed to tackle. Our Launcher is an Electron application written in  Typescript, and while it’s good for front-end tasks general purpose,  it’s not meant for intensive computation. We spent a good amount of time  trying to implement the algorithm using Typescript and finally conclude  that we need to use another way because it was too slow.

To  solve it, we went through a series of research. After browsing for some  NodeAPI documentations, we decided to build it as an executable  instead, so that the Launcher can call it by using one of the NodeAPIs.  Other than making it as an executable, I also preserve the code that is  exported to the DLL to be used for our upcoming MiniLauncher.

I  was surprised that the BuildInfo V2 is able to save so much by reusing  the existing bytes from the old file. When our QA Team released a report  for one of the AAA games we handle, they said that our update is 7GB  smaller compared to the Steam updater. I genuinely thought that I had a  bug, even one of our QA raised his eyebrow when he acknowledged the size  difference. Only after the QA tested it by pressing Play on the  Launcher, and is sure that the game was working as expected, I felt  relieved and was also super excited at the same time. The same story  happened with another game we tested, The Steam updater calculated 1.3GB  of update size while our Launcher required only about 450MB!

It’s awesome what he can do, don’t you think? Got any question? Or wanting to learn about our technologies at AccelByte?

Stay tuned!