うにてぃブログ

UnityやUnreal Engineの記事を書いていきます

【Unity】Addressable で「Use Existing Build」の際に Local Group はAddressable からロードするようにする

Addressable では 「Use Existing Build」の場合ローカルとリモートのグループともにカタログに記載されていなればロードできない

しかし、ローカルグループの量が多かったりするとテストのたびにローカルのビルドをするのは時間がかかってしまいます

そのため、ローカルのロードはAddressable からロードするようなスクリプトを作成しました

以下のように Addressables.InitializeAsync のあとに呼び出せば登録されるようになっています

    private IEnumerator Start()
    {
        yield return Addressables.InitializeAsync();

        AddressableLoadFromAddressable.Apply();

ただし、依存関係のチェックを行えていないので、バンドルの依存関係によってはロードできない可能性があります

これを確認する際には、Local Group の Include in Build のチェックを外さないとアドレスが重複してしまうため外してビルドを行ってください

スクリプト

#if UNITY_EDITOR
using UnityEditor.AddressableAssets;
using UnityEditor.AddressableAssets.Settings;
using UnityEditor.AddressableAssets.Settings.GroupSchemas;
#endif

using System.Diagnostics;
using System.Linq;
using UnityEngine.AddressableAssets;
using UnityEngine.AddressableAssets.ResourceLocators;
using UnityEngine.ResourceManagement.ResourceLocations;
using UnityEngine.ResourceManagement.ResourceProviders;

public static class AddressableLoadFromAddressable
{
    [Conditional("UNITY_EDITOR")]
    public static void Apply()
    {
#if UNITY_EDITOR
        var settings = AddressableAssetSettingsDefaultObject.Settings;
        // Use existing build の場合のみ登録する
        if (settings.ActivePlayModeDataBuilderIndex != 2)
            return;
        
        // AssetDataBaseを利用してロードしたいので登録してなければ登録
        var resourceProviders = Addressables.ResourceManager.ResourceProviders;
        if (!resourceProviders.Any(x => x.GetType() == typeof(AssetDatabaseProvider)))
            resourceProviders.Add(new AssetDatabaseProvider());
        
        var resourceLocationMap = Addressables
            .ResourceLocators
            .OfType<ResourceLocationMap>()
            .FirstOrDefault();
        
        if (resourceLocationMap == null)
            return;

        // ローカルなGroupだけを抽出
        var localGroups = settings.groups
            .Where(g =>
            {
                var schema = g.GetSchema<BundledAssetGroupSchema>();
                if (schema == null)
                    return false;
                
                return
                    schema.LoadPath.GetName(settings) == AddressableAssetSettings.kLocalLoadPath &&
                    schema.BuildPath.GetName(settings) == AddressableAssetSettings.kLocalBuildPath;
            });
        
        // ローカルなGroupに登録されているアドレスをすべて登録
        var providerName = typeof(AssetDatabaseProvider).FullName;
        foreach (var localGroup in localGroups)
        {
            foreach (var entry in localGroup.entries)
            {
                var address = entry.address;
                if (resourceLocationMap.Locations.ContainsKey(address))
                    continue;
                
                var assetPath = entry.AssetPath;
                var assetType = entry.MainAssetType;
                var location = new ResourceLocationBase(address, assetPath, providerName, assetType);
                resourceLocationMap.Add(address, location);
            }
        }
#endif
    }
}