Introduction to AB package

Unity Resource Management

In Unity, resource loading is generally divided into Resources loading and AssetBundle loading.

Unity has a special folder called Resources. Resources placed in this folder can be loaded directly using Resources.load (). Resources loads Resources.

Once you have an AssetBundle, you can also call the corresponding API of the AssetBundle to load resources.

What is an AB bag

The full name of the AB package is AssetBundle. Unity is a package that Unity provides for storing resources. By distributing resources across AB packages, runtime memory stress can be minimized and content can be loaded selectively.

Why use AB bag

1, hot renewal. Hot update requires to ensure that the resources produced by the AB package are unique, and that the AB package check code of the same resource is the same.

2. Loading Resources is simple and easy, but it has a lot of problems:

  • It imposes some burden on memory management.
  • It takes a long time to load when the application is opened.
  • All the Resources in the Resources folder are consolidated into a single serialized file (you can think of it as a single big package, and there are problems with the giant AB package), which limits resource optimization.
  • Heavy use of Resources is not recommended.

Method of use

Type AB package:

`public static AssetBundleManifest BuildAssetBundles(string outputPath, BuildAssetBundleOptions assetBundleOptions, BuildTarget targetPlatform); ` * 1

The values of the buildAssetBundleOptions enumeration are all converted to binary with only one digit and all zeros. Such as UncompressedAssetBundle is 0000 0000 0001, IgnoreTypeTreeChanges is 0000 0100 0000, DisableLoadAssetByFileName is 1000 0000 0000.

The bottom layer of BuildAssetBundles processes the value of the BuildAssetBundleOptions passed in and determines which strategy is used to build the AB package based on the binary bits. So if you want to use more than one strategy when building the AB package, use the &join.

The BuildTarget parameter is used to select the platform, because the AB package is not compatible across platforms.

Set resource AB package name:

` AssetImporter. AssetBundleName / / AB package name AssetImporter assetBundleVariant / / AB package variation ` * 1 * 2

Get the AB package method:

`AssetBundle.LoadFromFile(string path)
AssetBundle.LoadFromFileAsync(string path)
AssetBundle.LoadFromMemory(byte[] binary)
AssetBundle.LoadFromMemoryAsync(byte[] binary)
AssetBundle.LoadFromStream(Stream stream)
AssetBundle.LoadFromStreamAsync(Stream stream)
WWW.assetBundle` 

*   1
*   2
*   3
*   4
*   5
*   6
*   7

LoadFromFile loads the AB package from a file. It loads the AB package from a given path. If the AB package is loaded in LZ4 mode, it will only load the AB Header, and then load the AB chunk with whatever resources are needed. Significantly reduced memory footprint. (LoadFromFileAsync is the asynchronous version of it)

LoadFromMemory loads the AB package from memory, which loads the AB package from byte[] in memory. It will load the AB package completely. (LoadFromMemoryAsync is the asynchronous version of it)

LoadFromStream loads AB packages from a Stream. It loads AB packages from a Stream. Like LoadFromFile, it will load only the Header of the AB package if it is LZ4 loaded. (LoadFromStreamAsync is the asynchronous version of this)

WWW is a network-related class in Unity that allows you to download resources from the network and load them into AB packages.

Loading resource method:

`AssetBundle.LoadAsset(string assetName, Type resType)
AssetBundle.LoadAssetAsync(string assetName, Type resType)` 

*   1
*   2

LoadAsset is a synchronous method and LoadAssetAsync is an asynchronous method.

There are many other methods for AssetBundle, which are described in detail in the official API.

AB package variation

AssetBundleVariant namely. The AB package variant is used to support custom parameters that allow different objects in different AB packages to appear as the same Object when loading and resolving instance ID references.

Conceptually, two objects are allowed to appear as sharing the same GUID and LOCAL ID, but are actually distinguished by Variant ID.

In short, it is essentially a category label for a resource.

Like a picture of HD and LHD resources, the same model of high-precision and low-precision resources.

Setting AB package name in the lower right corner of the Unity editor is followed by setting AB package variant name.

BuildAssetBundleOptions:

None-0: The default mode. Using LZMA compression algorithm, the compressed packet body is very small, but it takes a long time to decompress when loading. After the first decompression, the package is compressed again using the LZ4 compression algorithm. This is why the first load time is long, and the load time after that is not so long. (LZMA requires a full decompression to load the resources in the package. LZ4 does not require a full decompression to load the resources in the package.)

UncompressedAssetBundle-1: Uncompressed. Although the package is large, it loads fast.

DisableWriteTypeTree -8: No TypeTree information. Although it is possible to make the AB package smaller, it is not compatible with lower versions. Not recommended.

DeterministicAssetBundle16: Creates a hash to map the id of the object stored in the AB package.

ForCereBuildAssetBundle-32: Forced rebuild the AB package.

IgnoreTypeTreeChanges-64: Ignores type tree changes when detecting incremental builds.

AppendHashToAssetBundleName – 128: hash is added to the AB package name.

ChunkBasedCompression-256: Uses the block-based LZ4 compression algorithm.

StrictMode-512: If there are any errors in the build, the build is not allowed to succeed.

DryRunBuild-1024: Dry build.

DisableLoadAssetByFileName – 4069: AB bag by filename load resources is prohibited.

DisableLoadAssetByFileNameWithExtension – 8192: AB bag by file extension load resources is prohibited.

AssetBundleStripUnityVersion: build when removed from the compressed file and serialization of the header Unity version number.

LZMA and LZ4

LZMA is stream-based. The same dictionary is used to process the entire block of data in stream compression, which provides the maximum compression rate possible, but only supports sequential reads. Therefore, when loading the AB package, the whole package needs to be unzipped, which will cause stalling and additional memory usage.

LZ4 is chunk-based. The block-compressed data is divided into equally sized blocks and compressed separately. If you need real-time decompression for random reads, block compression is a good choice. Both loadFromFile () and loadFromStream () load only the Header from the AB package, saving memory compared to loadFromMemory ().

Memory footprint

Here is the memory footprint of the AB package:

This is the memory footprint of a resource downloaded from the network.

Downloaded resources, including AB packages, images, materials, animations, audio, etc., are stored in memory in the form of Stream. (AB package can also have images, materials, animation, audio and other resources)

The AB package is then loaded into memory by loading the AB package.

The resources in the AB package need to be loaded into memory via assetBundle.load ().

As with GameObject, it is usually necessary to make changes to it, so it is an exact copy of the resource to instantiate. That is, when the GameObject in the AB package is unloaded from memory, the instantiated GameObject is not lost. Changes to the instantiated object will not affect the GameObject resource.

For the Shader and Texture, you don’t normally need to change it, so it’s instantiated by reference. That is, when the Shader and Texture resources in the AB package are unloaded from memory, the instantiated Shader and Texture will lose resources. And changes to the instantiated objects affect the Shader and Texture resources.

In the case of Material and Mesh, it is sometimes necessary to change it, so it is instantiated by reference + copy. That is, when the Material and Mesh resources in the AB package are unloaded from memory, the instantiated Material and Mesh will lose resources. Changes to the instantiated objects will not affect the Material and Mesh resources.

The general process is summarized as follows:

The AB package is first loaded into memory from the hard disk or network, then each resource in the AB package is loaded into memory, and then the resources are instantiated in memory. Each resource has its own different instantiation methods, so be careful when uninstalling the resource.

Internal structure of AB package

AssetBundleFileHeader: This records the main description information, such as version number, compression, etc.

AssetFileHeader: Contains a list of files that record the name, offset, length, and other information of each resource.

Asset1:

  • Assetheader: records TypeTree size, file size, format, etc.
  • TypeTree (optional, non-TypeTree construction) : records the class ID of an Asset object. Unity can serialize and deserialize a class using the Class ID. Each class has an ID, such as 0 for Object, 1 for GameObject, etc. See the Unity website for details.)
  • ObjectPath: records the path ID (resource unique index ID), etc.
  • AssetRef: records the AB package references to external resources.

Asset2…

.manifest

This is the.manifest file for package AB.

Manifestation fileVersion: 0 # CRC: 2657307167 # CRC checkcode: # AB package Hash of all resources, can be used for incremental updating detection serializedVersion: 2 # Unity serialization version Hash: 717 e408ba50ee41b0960161fd2d5a827 TypeTreeHash: # AB package in all types of Hash, can be used for incremental updating detection serializedVersion: 2 # Unity serialization version Hash: 8 d552bf2f5bdba1177c938cb98ca6f2f HashAppended: 0 ClassTypes: # TypeTree - Class: 1 # GameObject Script: {instanceID: 0} - Class: 21 # Material Script: {instanceID: 0} - Class: 28 # Texture2D Script: {instanceID: 0} - Class: 48 # Shader Script: {instanceID: 0} - Class: 114 # MonoBehaviour Script: {fileID: 1392445389, guid: f70555f144d8491a825f0804e09c671c, type: 3} - Class: 114 # MonoBehaviour Script: {fileID: -765806418, guid: f70555f144d8491a825f0804e09c671c, type: 3} - Class: 114 # MonoBehaviour Script: {fileID: -1200242548, guid: f70555f144d8491a825f0804e09c671c, type: 3} - Class: 114 # MonoBehaviour Script: {fileID: -146154839, guid: f70555f144d8491a825f0804e09c671c, type: 3} - Class: 114 # MonoBehaviour Script: {fileID: 708705254, guid: f70555f144d8491a825f0804e09c671c, type: 3} - Class: 114 # MonoBehaviour Script: {fileID: 1297475563, guid: f70555f144d8491a825f0804e09c671c, type: 3} - Class: 114 # MonoBehaviour Script: {fileID: 11500000, guid: 20e8969313b8e4614b498f042e99683a, type: 3} - Class: 114 # MonoBehaviour Script: {fileID: 11500000, guid: c86dbe77db44a434bb15895563508b65, type: 3} - Class: 114 # MonoBehaviour Script: {fileID: 11500000, guid: 1a7e2f4cb82d9b94a91270d550c880c0, type: 3} - Class: 115 # MonoScript Script: {instanceID: 0} - Class: 128 # Font Script: {instanceID: 0} - Class: 198 # ParticleSystem Script: {instanceID: 0} - Class: 199 # ParticleSystemRenderer Script: {instanceID: 0} - Class: 213 # Sprite Script: {instanceID: 0} - Class: 222 # CanvasRenderer Script: {instanceID: 0} - Class: 224 # RectTransform Script: {instanceID: 0} - Class: 687078895 # SpriteAtlas Script: {instanceID: 0} Assets: # Include Assets/ bundles /... /a.prefab - Assets/Bundle/... /b.prefab - Assets/Bundle/... / c.spriteAtlas Dependencies: # /Users/apple/... /AssetBundles/Android/q - /Users/apple/... /AssetBundles/Android/w - /Users/apple/... /AssetBundles/Android/e - /Users/apple/... /AssetBundles/Android/r - /Users/apple/... /AssetBundles/Android/t` * 1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14 * 15 * 16 * 17 * 18 * 19 * 20 * 21 * 22 * 23 * 24 * 25 * 26 * 27 * 28 * 29 * 31 * 32 * 33 * 35 * 36 * 37 * 38 * 39 * 40 * 41 * 42 * 43 * 44 * 45 * 46 * 47 * 48 * 49 * 50 * 51 * 52 * 53 * 54 * 55 * 56 * 57 * 59 * 60 * 61 * 62 * 63

Special path

`Resources` 

*   1

This corresponds to the Resources special folder path. (read-only)

In Unity this corresponds to: /Assets/Resources.

`Application.streamingAssetsPath` 

*   1

The corresponding path is the streamingAsset folder. (read-only)

In Unity this corresponds to: /Assets/StreamingAssets.

Under the Android corresponds to: jar: file:///data/app/xxx.apk! / assets.

Under iOS, this corresponds to: Application/… XXX. / app/Data/Raw.

`Application.persistentDataPath` 

*   1

The corresponding folder path is the application persistent data store. The data here will not be erased when you apply updates or overwrite the installation. (readable and writable)

In Unity this corresponds to: / the Unity project folder path.

On Android, this corresponds to: /… /data/ application name /files.

Under iOS, this corresponds to: Application/… / Documents. IOS also automatically uploads files under the PersistentDataPath path to iCloud, which can take up the user’s iCloud space. PersistentDataPath may be rejected if there are too many files in the PersistentDataPath path, so some data may need to be placed in the TemporaryCachePath path.

`Application.dataPath` 

*   1

The corresponding path is to apply the Asset folder. (read-only. Android is unreadable because the change refers to an.apk file, not a directory.)

In Unity this corresponds to: /Assets.

On Android: /data/app/… / XXX. Apk.

Under iOS, this corresponds to: Application/… XXX. / app/Data.

`Application.temporaryCachePath` 

*   1

The corresponding folder path is the application temporary data cache. (read-only)

In Unity this corresponds to: / the Unity project folder path.

On Android, this corresponds to: /… /data/ application name /cache.

Under iOS, this corresponds to: Application/… / Library/Caches.

Depend on the problem

Dependency problem, colloquially speaking is that A resource in package A uses A resource in package B. However, if package A is loaded and package B is not, the resources in package A will be lost.

After Unity5.0 BuildAssetBundleOptions CollectDependencies permanently open, namely the Unity will automatically detect the object reference resources and packaged together, prevent loss of resources missing problem.

Because of this feature, in some cases, if a common resource is not specified in the AB package, the common resource will be automatically entered into the AB package that refers to it, so there is the phenomenon of duplicate resources in different AB packages. This is resource redundancy.

In this case, even if the resources are identical, merge optimization is not possible.

To prevent resource redundancy, you need to specify in which AB package the resource resides, creating dependencies. Therefore, for some common resources, it is recommended to store them in a separate AB package.

At load time, if the AB packages depend on each other, then the resources in one AB package need to be loaded out of the resources in another AB package first. This will lead to unnecessary consumption. So try to reduce the dependencies between the AB packages, and try to load the common resources ahead of time.

Fine-grained problem

In the fine-grained problem of how many resources to put in each AB package, a good strategy is crucial.

When a resource is loaded, the AB package is loaded first, and then the resource is loaded. If the AB package uses LZMA or LZ4 compression algorithms, the AB package needs to be decompressed first.

AB has a large number of packages and fewer resources in the package

AB has fewer packages and more resources in the package

Loading an AB pack into memory takes less time, so the player doesn’t feel stuck, but each resource actually takes longer to load.

It takes a long time to load an AB pack into memory and the player feels stuck, but then every resource in the pack loads quickly.

Hot update is flexible, the package to be updated to download is small.

Hot update is not flexible, to update the download of the package body is large.

Excessive IO times increase the energy consumption and heating pressure of hardware equipment.

IO times are not many, the hardware pressure is small.

Simple strategy:

  • Frequently updated and infrequently updated objects are split into different AB packages.
  • The objects that are loaded at the same time are placed in an AB package.
  • Objects that cannot be loaded at the same time are split into different AB packages.
  • Group AB packages according to project logic function.
  • Group AB packages according to objects of the same type.
  • Public and non-public resources are split into different AB packages.

Unload problem

When Resources.unloadAsset () is called, the Object is destroyed, but the Instance ID is retained and contains valid GUID and Local ID references.

When AssetBundle.Unload(true) is called, not only is the Object destroyed, but the Instance ID’s GUID and Local ID references are invalidated.

When AssetBundle.Unload(false) is called, the Object is not destroyed, but the Instance ID GUID and Local ID references are invalidated. Objects in the scene are disconnected from the AB package. This means that the object’s instance ID references the GUID and the LOCAL ID, and the object’s instance ID references the GUID and the LOCAL ID.

If the AB package is reloaded, the detached linked object will not be managed by the newly loaded AB package. So if you don’t take care of it, it can lead to some uncontrollable problems. The Unity of the Resources. UnloadUnusedAssets () method is a good way to solve this problem.

Encryption of the AB packet

Because the AB pack holds the various resources of the game, if the AB pack is not encrypted, then when someone gets the AB pack, they can see all the resources in the AB pack. After some special operations can be directly exported from the AB package, images, audio, animation, or even in Unity directly instantiated to save as Prefab.

Encryption idea is as follows:

1. After the AB package is built, the contents of the AB package can be read as byte[].

2. Then select any encryption method to encrypt the byte[].

3. Write the AB package again after encryption.

4. AB packet encryption is complete.

AssetBundle.loadFromFile () will return an error if it is used to load the encrypted AB package. Unity will not be able to recognize the encrypted content. This will prevent others from loading and reading the AB package at will and ensure the security of the resource.

The idea of decryption is as follows:

1. Byte [] is used to read the contents of the AB package.

2. Then use the corresponding decryption algorithm to decrypt the byte[].

3, after decryption byte [] by AssetBundle. LoadFromMemory () to load.

4. AB package is loaded.

In general, this binary approach to encrypting AB packets is effective, but load time and memory footprint are a concern. Many times choose not to encrypt, on the one hand, because it takes up more memory, the cost is too large. Although byte[] can be freed from memory after loading from byte[] into the AB package, there is still a peak in memory usage during loading.

Another simple encryption method, that is, can realize the direct means of loading AB packet, and compared with the above binary encryption AB packet loading faster, less cost.

The essence is to implement encryption by adding an offset to the AB packet.

`public static AssetBundle LoadFromFile(string path, uint crc, ulong offset); ` * 1

The third argument to AssetBundle.loadFromFile () is the byte offset of the contents of the AB package. This means that the contents of the AB packet are read at offset.

Therefore, if N random bytes are inserted in front of the AB package after the construction of the AB package, if the AB package is intended to be loaded at this time, if the N value is not known, the AB package cannot be read and loaded successfully. This enables encryption.

Loaded from Stream

AssetBundle. LoadFromStream () is not like AssetBundle. LoadFromMemory () will take up a more memory.

`public static AssetBundle LoadFromStream(Stream stream, uint crc, uint managedReadBufferSize)` 

*   1

This is how the AB package is loaded from a managed stream. Like loadFromFile (), it reads only the header file of the AB package.

Restrictions on using Stream loading:

1. Package AB data must start at Stream position 0.

When starting at the end of the AssetBundle data and attempting to read the data, the Stream implementation must return 0 bytes read without throwing an exception.

The Stream must be readable (canRead returns true) and searchable (canSeek returns true).

You can call Seek() and Read() from any Unity thread.

CRC check

The full method for the AB package to load the resource is actually AssetBundle. loadFromFile (String path, uint CRC, ulong offset), with three arguments. The second parameter is the CRC checksum.

Each AB package also has CRC validators in its.manifest file, which are used to verify data integrity.

All kinds of ID

After serialization, resources are managed with GUID and LOCAL ID.

The GUID corresponds to Asset. The GUID exists in the.meta file. Provides an abstraction of a specific location of a file. It’s a mapping. It doesn’t matter where the resources are on disk.

The Local ID corresponds to each Object in the Asset. (Asset)

The GUID and Local ID are easier to use, but because they are on disk, they take longer to read. So Unity caches an instance ID corresponding to an Object, and uses the instance ID to quickly find an Object. Instance ID is a quick way to retrieve an object instance ID, containing references to the GUID and the LOCAL ID. Parsing the instance ID quickly returns the loaded object represented by instance, and if the object is the target to load, the file GUID and LOCAL ID can be parsed into the object source data, allowing Unity to load the object on the fly. Each time the AB package is reloaded, a new instance ID is created for each object.

conclusion

There is no best way to pack AB, only the best way to pack AB for the project.

The resources

https://docs.unity3d.com/Scri…

https://docs.unity3d.com/Manu…

https://www.xuanyusong.com/?s…

https://blog.csdn.net/lodypig…

https://blog.csdn.net/BillCYJ…

https://learn.unity.com/tutor…