Conseils et pièges concernant les Unity Asset Bundles
![Conseils et pièges concernant les Unity Asset Bundles](/_next/image?url=https%3A%2F%2Fcdn.sanity.io%2Fimages%2Ffuvbjjlp%2Fproduction%2F6cd674424a65902db81bd0a869265fe6edf3229e-1230x410.png&w=3840&q=75)
Les Asset Bundles sont des fichiers d'archive contenant des ressources pour votre jeu. Ils sont utilisés pour diviser votre jeu en blocs logiques, ce qui vous permet de fournir et de mettre à jour du contenu à la demande tout en réduisant la taille de votre jeu. Ils sont également couramment utilisés pour fournir des correctifs et des DLC pour votre jeu. Les Asset Bundles peuvent contenir toutes sortes d'actifs, tels que des Prefabs, des matériaux, des textures, des clips audio, des scènes et bien d'autres choses encore, mais ils ne peuvent pas inclure de scripts.
Auparavant, il était nécessaire de créer manuellement des ensembles d'actifs, de marquer chaque actif en conséquence, puis de suivre et de résoudre les dépendances par soi-même au moment de l'exécution. Aujourd'hui, tout cela est pris en charge par le système Addressables, qui construira pour vous des ensembles d'actifs sur la base des groupes d'actifs que vous définissez, ainsi que le chargement et la gestion des dépendances de manière transparente.
Bien qu'il existe de nombreux guides sur le fonctionnement des Asset Bundles, j'aimerais aborder certains aspects moins connus du système, en particulier les performances des jeux, l'utilisation de la mémoire et la compatibilité générale.
Chaque fois que vous tentez d'utiliser une ressource contenue dans un paquet, Unity s'assure que le paquet correspondant est chargé en mémoire, puis charge à son tour la ressource en mémoire.
S'il est possible de charger partiellement des actifs spécifiques au sein d'un ensemble d'actifs, l'inverse n'est pas autorisé. Cela signifie que dès qu'un élément d'un ensemble d'éléments est chargé, il ne peut être déchargé que si l'ensemble du groupe d'éléments n'est plus nécessaire.
Par conséquent, si la structure de votre bundle n'est pas idéale, vous constaterez souvent une augmentation de l'utilisation de la mémoire d'exécution au fur et à mesure que le jeu avance, ce qui entraînera une détérioration des performances et d'éventuels plantages. C'est pourquoi il est préférable d'éviter les paquets contenant un grand nombre d'actifs, car ils finiront par occuper beaucoup de mémoire d'exécution et deviendront un goulot d'étranglement pour votre jeu. Il convient plutôt d'emballer les biens en fonction de la fréquence à laquelle ils seront chargés et utilisés ensemble.
Les Asset Bundles sont généralement compatibles avec les versions ultérieures, de sorte que les bundles construits avec d'anciennes versions d'Unity fonctionneront dans la plupart des cas avec des jeux construits avec des versions plus récentes d'Unity (en supposant que vous ne supprimiez pas les informations TypeTree, comme nous le verrons plus loin). L'inverse n'est pas vrai, donc les bundles construits sur une version d'Unity plus récente que celle utilisée pour la construction de votre jeu ont peu de chances de se charger correctement.
Au fur et à mesure que la différence de version entre l'offre groupée et le moteur utilisé pour la construction du jeu augmente, la compatibilité devient moins probable. Il existe également des cas où le bundle peut toujours être chargé, mais les objets contenus dans le bundle ne peuvent pas être chargés correctement dans la nouvelle version d'Unity, probablement en raison d'un changement dans la façon dont les objets sont sérialisés, créant ainsi des problèmes. Dans ce cas, vous devrez reconstruire vos paquets pour maintenir la compatibilité.
Le chargement de paquets provenant d'une version différente d'Unity a également un coût en termes de performances, comme indiqué dans la section TypeTree ci-dessous.
Pour ces raisons, il est recommandé de faire des tests approfondis à chaque fois que vous mettez à jour la version Unity de votre jeu par rapport aux Asset Bundles existants, et de les mettre également à jour chaque fois que cela est possible.
Les ensembles d'actifs n'offrent généralement pas de prise en charge multiplateforme. Lorsque vous êtes dans l'éditeur, vous pouvez charger des paquets à partir d'une autre plateforme cible, mais sur l'appareil, cette opération échoue.
Cela reste vrai pour les offres groupées qui contiennent des actifs qui ne sont pas nécessairement spécifiques à une plateforme.
La raison de cette limitation est que les données peuvent être optimisées ou compressées d'une manière qui ne fonctionne que pour la plateforme cible. En outre, les paquets peuvent contenir des données spécifiques à une plate-forme qui ne doivent pas être partagées entre différentes plates-formes, ce qui permet d'éviter la fuite de contenu qui n'est pas destiné à une autre plate-forme.
Le cache de chargement est un pool partagé de pages où Unity stocke les données récemment consultées pour vos ensembles d'actifs. Il s'agit d'une donnée globale, qui est donc partagée par tous les Asset Bundles de votre jeu.
Cela a été introduit assez récemment, je crois sur Unity 2021.3, puis rétroporté sur 2019.4. Auparavant, Unity utilisait des caches distincts pour chaque Asset Bundle, ce qui se traduisait par une utilisation de la mémoire d'exécution beaucoup plus importante (voir ci-dessous "Tampons de fichiers sérialisés").
Par défaut, cette valeur est fixée à 1 Mo, mais elle peut être modifiée en définissant AssetBundle.memoryBudgetKB.
La taille du cache par défaut devrait suffire dans la plupart des cas, mais dans certains cas, il peut être avantageux de la modifier. Par exemple, si vous avez des paquets contenant beaucoup de petits objets, l'augmentation de la taille du cache peut entraîner un plus grand nombre d'accès au cache, ce qui améliore les performances de votre jeu.
En plus de vos ressources de jeu, les Asset Bundles incluent un tas d'informations et d'en-têtes supplémentaires, utilisés par Unity pour savoir quelles ressources charger et comment, ainsi qu'un cache dédié (en fonction de la version d'Unity que vous utilisez).
Une carte des ressources d'un ensemble. C'est ce qui vous permet de rechercher et de charger chaque ressource individuelle dans l'ensemble par son nom. Sa taille en mémoire n'est normalement pas un problème, à moins que vous n'ayez des ensembles d'actifs exceptionnellement importants contenant des milliers d'objets.
Le tableau de préchargement répertorie les dépendances de chaque ressource contenue dans votre paquet. Il est utilisé par Unity pour charger et construire correctement les ressources.
Celle-ci peut devenir assez importante si les ressources contenues dans votre paquet ont de nombreuses dépendances explicites et implicites, ainsi que des dépendances en cascade provenant d'autres paquets. Pour cette raison (et bien d'autres), c'est une bonne idée de concevoir vos bundles de manière à minimiser la chaîne de dépendance.
Les arbres de types définissent la présentation sérialisée des objets contenus dans les ensembles d'actifs.
Leur taille dépend du nombre de types d'objets différents contenus dans la liasse. C'est pourquoi il est préférable d'éviter les grosses liasses où sont mélangés des objets de plusieurs types différents.
Les arbres de types sont nécessaires pour maintenir la compatibilité lors de la mise à jour de la version Unity de votre jeu tout en essayant de charger les Asset Bundles construits sur des versions plus anciennes du moteur. Par exemple, si le format ou la structure de l'objet a changé, ils vous permettent d'effectuer une lecture binaire sûre afin qu'Unity puisse tenter de le charger malgré tout. Cela a un coût en termes de performances, c'est pourquoi il est généralement recommandé de mettre à jour les bundles chaque fois que possible lors de la mise à jour du moteur.
Il peut être désactivé de manière facultative, en définissant l'option BuildAssetBundleOptions.DisableWriteTypeTree lors de la construction de vos bundles. Cela réduira la taille de vos paquets et la charge de mémoire associée, mais cela signifie également que vous devrez reconstruire tous vos paquets à chaque fois que vous mettrez à jour la version du moteur de votre jeu. Ceci est particulièrement pénible si vous comptez sur les bundles construits à partir de vos lecteurs pour le contenu généré par l'utilisateur, donc à moins que vous n'ayez une très bonne raison de le faire, il est recommandé de garder les TypeTrees activés.
Un cas où les TypeTrees peuvent normalement être désactivés en toute sécurité est celui des bundles inclus directement dans la construction de votre jeu. Dans ce cas, la mise à jour du moteur nécessiterait de toute façon la création d'une nouvelle version du jeu et de nouveaux Asset Bundles, de sorte que l'aspect rétrocompatibilité n'est pas pertinent.
Chaque liasse possède ses propres arbres de types. Le fait d'avoir plusieurs petites liasses contenant le même type d'objets augmentera légèrement la taille totale sur le disque. D'autre part, lorsqu'ils sont chargés, les arbres de types sont stockés dans un cache global en mémoire, de sorte que vous n'aurez pas à supporter un coût de mémoire d'exécution plus élevé si plusieurs ensembles d'actifs stockent le même type d'objets.
Remarque : Depuis Unity 2019.4, cela a été remplacé par un cache de chargement global et partagé, comme décrit ci-dessus.
Lorsqu'un ensemble d'actifs est chargé, Unity alloue des tampons internes pour stocker leurs fichiers sérialisés en mémoire.
Les lots de ressources ordinaires contiennent un fichier sérialisé, tandis que les lots de ressources de scènes en continu contiennent jusqu'à deux fichiers pour chaque scène contenue dans le lot. La taille de ces tampons dépend de la plate-forme. Sur Switch, PlayStation et Windows RT, elle sera de 128 Ko, tandis que toutes les autres plateformes ont des tampons de 14 Ko.
C'est pourquoi il est préférable d'éviter d'avoir un grand nombre de très petits ensembles d'actifs, car la mémoire occupée par ces tampons peut devenir importante par rapport aux actifs qu'ils fournissent réellement.
Un CRC (Cyclic Redundancy Check) est utilisé pour valider la somme de contrôle de vos Asset Bundles, ce qui garantit que le contenu fourni à votre jeu est exactement ce que vous attendez. Les CRC sont calculés sur la base du contenu non compressé du paquet.
Sur les consoles, les Asset Bundles sont normalement inclus dans l'installation du titre sur le stockage local ou téléchargés en tant que DLC, ce qui rend les contrôles CRC inutiles. Sur d'autres plateformes, comme les PC ou les mobiles, il est important d'effectuer des contrôles CRC sur les offres groupées téléchargées à partir d'un CDN. Cela permet de s'assurer que le fichier n'est pas corrompu ou tronqué, ce qui pourrait entraîner des pannes, et d'éviter toute altération potentielle.
Les vérifications CRC sont assez coûteuses en termes d'utilisation du processeur, en particulier sur les consoles et les mobiles. Pour ces raisons, c'est normalement un bon compromis de désactiver les contrôles CRC sur les paquets locaux et sur les paquets mis en cache, en les activant seulement sur les paquets distants non mis en cache.
Par défaut, Unity propose trois façons de rechercher des actifs au sein des bundles :
- Chemin relatif du projet (Assets/Prefabs/Characters/Hero.prefab)
- Nom de fichier de l'actif (Hero)
- Nom de fichier de l'actif avec extension (Hero.prefab)
Bien que cela soit pratique, cela a un coût. Afin de prendre en charge les deux dernières méthodes, Unity doit construire des tables de consultation, ce qui peut consommer une quantité importante de mémoire pour les gros paquets.
En outre, le chargement d'actifs à l'aide d'une méthode différente de celle du chemin relatif du projet entraînera un coût de performance, toujours en raison de la consultation de la table requise.
Pour ces raisons, il est recommandé d'éviter d'utiliser ces méthodes. Vous pouvez même les désactiver lors de la création des asset bundles, ce qui améliorera les performances de chargement de vos asset bundles et l'utilisation de la mémoire d'exécution.
Pour ce faire, vous pouvez définir ces deux drapeaux lors de la construction de vos bundles :
- BuildAssetBundleOptions.DisableLoadAssetByFileName
- BuildAssetBundleOptions.DisableLoadAssetByFileNameWithExtension
Pour en savoir plus sur la gestion des actifs, faire part de vos commentaires ou dialoguer avec la communauté et le personnel d'Unity, consultez le forum sur la gestion des actifs.