📜 ⬆️ ⬇️

Simplify build builds in Unity3D

Most recently, I realized that with the growing number of finished projects, more and more time has to be devoted to building builds. It cannot be said that the unit somehow complicates this process, but it certainly does not simplify it. Especially when each project is built for several platforms and even in different configurations. In principle, the problem is not new and has many different solutions. But for several reasons, I stopped writing my own plugin.


It looks like this:



And why, why, where to get and how to use, I will tell below.


Pain


The first discomfort is usually felt when more than one platform is being prepared for release. It turns out that in the unit some project settings are common for all platforms, and some are not. And it must always be remembered and taken into account. But in general, you can live.


Then it turns out that there is no possibility to save different settings within the same platform. A simple example: build one, and there are many sites on which it will be distributed. And for each you need something different. Partially this problem is solved by removing the settings in the runtime configuration in StreamingAssets. But only partially, because only what is happening inside the game can be configured this way. The icon in this way can not be replaced. Icon each time you need to change yourself. Whether by code, by hand, but by hand. And at some point, the responsible manager, whom you trained for a month to work with StreamingAssets, goes on vacation, but builds are needed yesterday.


Later you will learn that a separate Korean version is planned, everything should be different there and without #ifdef.


And then you are told that the game needs to be launched on mobile platforms, playstation, nintendo and washing machines.


As a result, the preparation of each new build over time becomes similar to this:



Check the instrument readings, turn on the toggle switch on the left, turn the lever on the right, turn the red valve on. Do not confuse and do not forget.


At first, it can still and nothing, but quickly tires. And remember all the manipulations in a month or two.


What are your options?


Internets and folk wisdom offer us the following:



Solved. We write our plugin with UI and fairies.


We need a plan


First you need to decide what we actually want to get and why.


  1. Storage of project settings for each configuration (here you can go to the terminology of the plugin itself and call them options). It is desirable to implement the inheritance options. For example, for all standalone builds, the project settings will be common, and the options from each other will differ only in the icon and the name of the project. It is quite logical to solve this by inheritance, not by copy-paste.
  2. A visual representation of what varied in a particular version and how it differs from the current project settings.
  3. Combining options in the collection. In order to be able to collect a subset of builds at once with one button or one static method.
  4. Packaging build archive. This is an optional requirement. In the case of using the plugin together with the build server, this item can be implemented on its side. But to simplify life I want to simplify everything, but the build server is not always there.
  5. Moving files at different stages of assembly. For example, you need to replace some asset (icon, splash, scene, etc.) before building (replacing assets should be reversible, the build of the build should not change the current state of the project). Or rename it in the finished Windows {exe_name} _Data build to Data (a very annoying unit behavior, without this manipulation you cannot rename the file). Or, again, in the Windows builds, arrange the necessary StreamingAssets. This should be done before the archive is packaged. And then for example drag all the archives somewhere in one place.
  6. Unity projects have a huge amount of settings and we absolutely do not want to write our own UI for all of them. Especially since he already is in the unit itself. Therefore, the project settings will change as usual, and in the plugin just follow the changes in settings and save to the desired options.
  7. I would like to store each option in a separate file so that I can carry them between projects.
  8. It is desirable to work with the unit since version 5.6. There are some legacy projects with a lot of fuss around builds.

Drove


The main part of our plugin is working with project settings, as well as storing and processing individual options settings. Therefore, we focus on this.


All unit settings are stored in the ProjectSettings directory in the project root. First of all, during initialization, we will save these settings in the plug-in directory (by the way, this is BuildVariants at the root of the project). This will be required so that we can track all subsequent changes. Next we need to somehow store them. The simplest thing would be to simply copy ProjectSettings to a separate place for each option. And at the time of its activation just replace them entirely. The idea is quite working and at first I looked at it. But this completely prevents us from inheriting options. And if we are already writing a plugin, we will immediately make it beautiful. So we need to learn how to read and write the contents of ProjectSettings.


For this you need to understand what is stored there. And the most ordinary assets are stored there, which are serialized and deserialized in a regular way. This means that we can read them through AssetsDatabase and get a SerializedObject. This is already something. Because we can go through all the SerializedProperty, track their differences with the original "snapshot" and save them in the version. Then, when assembling or activating a variant, we collect changes along the entire inheritance chain, apply them to the "snapshot" and drop them in ProjectSettings. Voila


But SerializedProperty has some unpleasant features: the way of storing values ​​(all these intValue, floatValue, isArray), the absence of a normal mechanism for comparing them (there are two related objects, how do we understand all of them have the same values) and paradoxical (or no) the absence of the Serializable attribute (which means we will need some kind of wrapper to save). I can not say that these are some fatal flaws, All this was done more than once in numerous editor scripts. But I still want something more simple, understandable and universal.


Or maybe we will slightly limit the use of our plugin? Let it work only on projects with textual serialization of assets (and someone else uses binary?). Then all ProjectSettings will be stored as yaml documents. You can take the YamlDotNet library and use it to parse and save the settings. At the same time and keep your configs in yaml. So even clearer. It is only necessary to add a few extensions for diffs yaml documents and their combination.


A little mess with the editor window (I don’t even want to describe it, I hope that with UIElements it will be easier and more fun to live), collecting everything in a heap and ready.


Result


It's time to show what I did . You have already familiarized with the main mechanisms of the plug-in operation, so further on some features:



Future plans


Of course, I want to feed the plugin with features to infinity, but it's time to return to real projects, and at the same time test the existing functionality. A little later, I want to apply UIElements for fresh versions of the unit, I hope this will make everything more beautiful and comfortable. I would also like to tie in versioning and some semblance of environment variables. Maybe the public will tell you something else in terms of functionality or usability.


Therefore, I will be glad to any wishes, comments, questions and bug reports. Easy builds to you!


')

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


All Articles