📜 ⬆️ ⬇️

Features of the development of mobile MMO RTS. Part 4



Content:


  1. Game size optimization
  2. Bundles and downloadable resources. What is required of the system?
  3. Dify Manifesto
  4. Savings on code generation

We have gone through the equator cycle on creating MMO RTS. Today's article is about optimization.

Game size optimization


Remember the warning from the AppStore and GooglePlay that you are trying to download an application of more than 100 MB through a mobile network? This message greatly reduces conversion rates. Promoting such voluminous games is very expensive. We conducted a study and found that the conversion drops by almost 20%. For free games, this indicator is on the verge of survival, for paid games it is not so critical.

On iOS, it's still harder. Starting with ARM64, 2 different executable files are included in the build, for a 32-bit architecture and a 64-bit one. That is, instead of 70 MB for embedded resources, only 30 remain.
')
On each iOS build, we perform a pessimistic calculation of its size. For this xCode-archive is divided into resources and executable file. Resources are compressed in .zip, and the result is added to the size of the executable file. This indicator is enough to find out how the size of the project changes. More guidance and formulas are available on the Unity website.

If the entire graphics is pressed correctly, the meshes are optimized, and unnecessary dependencies are eliminated, not many solutions remain - for example, putting content into bundles and optimizing code generation.

Bundles and downloadable resources. What is required of the system?


All the basic graphics needed to display the UI to the user after login remain in the build.



We started working with the bundles on the fourth version of the engine. In the fifth version, Unity offers a different approach, but we do not use it, because we already have a ready system.

In short, the system works like this:

  1. In the Unity-project there is a set of folders whose names end with .bundle. The contents of these bundles are the resources requested by the client in runtime by the file name of this resource.
  2. Through a special utility, the developer builds the modified bundles and forms the manifest. This is a text file with information required by the client.
  3. The formed bundles are poured onto the content server, and the manifest is sent to the server, which is returned to its clients during login. Bundles can be updated or added without updating the client.
  4. The client parses the manifest, loads and caches the bundles as soon as the code requests them.

As a result, we have formed the requirements for the manifest.



Working with the bundle cache in Unity is done through the numerical version of the version. We store this information in the manifest. When a file needs to be updated, the path to the bundle on the content server is generated from the version. This ensures that any change is a new file.

The system supports dependencies of bundles from each other. Often, different 3D models depend on a common texture bundle. The information is stored in the manifest and is used in the client to prioritize the loading of resources.

We added the ability to localize the bundles. This is necessary for gaming banners with texts in different languages ​​and voice acting wizard.

Bundles are formed for all the compression we support. The client knows with which compression it works, and forms the path to the requested bundle, adding to it the name of the compression.



We may have different versions of the application in production. Therefore, it is possible to use different resources. We store information for different versions of the application in the same manifest, but not in the form of a heap of data sets. They are stored as diffs from some basic version, the smaller of which is no longer in production. On the client, from the basic version and all the imposed diffs, we form the final data set, which we use.

Savings on code generation


As for code generation, you need to understand how the .NET / Mono platform and IL2CPP work. Pay attention to generic types. For .NET / Mono, each generic specialization is a separate type. For reference types, specializations refer to one - Object. In the case of value-types, the compiler needs to consider the size of an object of this type. Then he creates a separate specialization.

The main problem areas are classes with a large implementation and generic collections. In addition to the typed arrays, the unpleasant moment for us was that using enum enum values ​​as the key value in the dictionary results in the generation of a new copy of the Dictionary code.

To identify such implementations, we used ReSharper and its Find generic substitutions option. After we discovered them, we try to keep the number of specializations to a minimum.

Other articles from the series:


Source: https://habr.com/ru/post/323448/


All Articles