コガネブログ

平日更新を目標に Unity や C#、Visual Studio、ReSharper などのゲーム開発アレコレを書いていきます

【Unity】Addressables でリモートカタログが破損していないか確認する例

ソースコード

using System.Linq;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.AddressableAssets;

public class Example : MonoBehaviour
{
    // リモートカタログのファイルが破損している場合、
    // 以下のようなエラーや例外が発生するのでそれで破損しているかどうかを確認できる
    // ArgumentException: JSON parse error: The document root must not follow by other values.
    // Unable to load asset of type UnityEngine.AddressableAssets.ResourceLocators.ContentCatalogData from location XXXX/YYYY.json.
    // OperationException : Unknown error in AsyncOperation : Resource<ContentCatalogData>(catalog_X.X.X.json)
    // System.Exception: Unable to load ContentCatalogData from location Library/com.unity.addressables/aa/XXXX/catalog.json on second attempt.
    // OperationException : GroupOperation failed because one of its dependencies failed
    private static readonly string[] ERROR_MESSAGES =
    {
        "JSON parse error: The document root must not follow by other values.",
        "Unable to load asset of type UnityEngine.AddressableAssets.ResourceLocators.ContentCatalogData from location",
        "Unknown error in AsyncOperation : Resource<ContentCatalogData>",
        "Unable to load ContentCatalogData from location",
        "GroupOperation failed because one of its dependencies failed",
    };

    // ゲーム開始時に呼び出されます
    private async void Start()
    {
        // Addressables を初期化します
        await Addressables.InitializeAsync().Task;

        // カタログを更新します
        await UpdateCatalogs();
    }

    // カタログを更新します
    private static async Task UpdateCatalogs()
    {
        var isBrokenRemoteCatalog = false;

        // Addressables 内部でエラーや例外が発生した時に呼び出されます
        void OnLogMessageReceivedThreaded( string condition, string trace, LogType type )
        {
            // 既にエラーを検知している場合は無視します
            if ( isBrokenRemoteCatalog ) return;

            // 通常のログと警告ログは無視します
            if ( type == LogType.Log || type == LogType.Warning ) return;

            // リモートカタログのファイルが破損している系のメッセージならエラーとみなします
            isBrokenRemoteCatalog = ERROR_MESSAGES.Any( x => condition.Contains( x ) );

            // Addressables 内部でエラーや例外が発生した時に呼び出される関数を解除します
            Application.logMessageReceivedThreaded -= OnLogMessageReceivedThreaded;
        }

        // Addressables 内部でエラーや例外が発生した時に呼び出される関数を登録します
        Application.logMessageReceivedThreaded += OnLogMessageReceivedThreaded;

        // カタログを更新します
        var result = Addressables.UpdateCatalogs();

        // 更新が完了するのを待機します
        await result.Task;

        // Addressables 内部でエラーや例外が発生した時に呼び出される関数を解除します
        Application.logMessageReceivedThreaded -= OnLogMessageReceivedThreaded;

        if ( isBrokenRemoteCatalog )
        {
            Debug.LogError( "リモートカタログのファイルが破損している" );
            return;
        }

        Debug.Log( "成功" );
    }
}