2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Unity Editor拡張 with Odin】 Addressable AssetReferenceのプレビュー表示とグループでのフィルタリング

Last updated at Posted at 2020-01-01

環境

Unity 2019.2.17f1
Addressable 1.5
Odin Inspector 2.1.8 (有料プラグイン)
odin.png

AssetReferenceって何を参照しているのか分かりにくい。。。

名前を設定している場合はまだ分かりやすいですが、フォルダを指定している場合フルパスが表示されるのでかなり分かり辛いです。それを有料プラグインのOdinを使って解決してみようと思います。

まずは Before / After

Before...
Addressable.gif
After !!!!
AddressableWithOdin.gif
だいぶ分かりやすくなりましたね。
Prefab名をクリックするとProject内のPrefabをハイライトしてくれます。
そしてグループでのフィルタリングにも対応しました。

Code

OdinWithAddressableAssetReference.cs
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.AddressableAssets;
using Sirenix.OdinInspector;
using Object = UnityEngine.Object;

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

[CreateAssetMenu(menuName = "Sample/OdinWithAddressableAssetReference")]
public sealed class OdinWithAddressableAssetReference : ScriptableObject
{
    [SerializeField, HideInInspector] AssetReferenceGameObject references;

    public AssetReferenceGameObject References => references;

    #region Inspector
#if UNITY_EDITOR
#pragma warning disable 0649
    [SerializeField, ValueDropdown("ReferenceDropDownEditorOnly"), OnValueChanged("ReferenceValueChangedEditorOnly"), LabelText("References")] string referenceGuidEditorOnly;
    [ShowInInspector, ReadOnly, InlineEditor(InlineEditorModes.LargePreview), ShowIf("ReferencePreviewShowIfEditorOnly")] GameObject PreviewOnEditor;
    [SerializeField, ValueDropdown("AssetGroupDropDownEditorOnly", IsUniqueList = true), LabelText("Addressable Group Filter")] string[] targetAssetGroupGuidsEditorOnly;
#pragma warning restore 0649

    IEnumerable ReferenceDropDownEditorOnly()
    {
        return GetAllAssetEntrys(targetAssetGroupGuidsEditorOnly)
                .Select(x => new ValueDropdownItem(x.AssetPath, x.guid));
    }

    IEnumerable AssetGroupDropDownEditorOnly()
    {
        return GetAllAssetGroups()
                .Select(x => new ValueDropdownItem(x.Name, x.Guid));
    }

    void ReferenceValueChangedEditorOnly(string guid)
    {
        var entrys = GetAllAssetEntrys(targetAssetGroupGuidsEditorOnly);
        var item = entrys.FirstOrDefault(x => x.guid == guid);

        if (item != default)
        {
            references = new AssetReferenceGameObject(item.guid);
            UpdatePreviewAssetEditorOnly();
        }
    }

    bool ReferencePreviewShowIfEditorOnly()
    {
        if(PreviewOnEditor == default)
        {
            UpdatePreviewAssetEditorOnly();
        }

        return PreviewOnEditor != default;
    }

    void UpdatePreviewAssetEditorOnly()
    {
        PreviewOnEditor = default;

        if(references.RuntimeKeyIsValid())
        {
            PreviewOnEditor = LoadAsset<GameObject>(references);
        }
    }

    /// <summary>
    /// アセットの取得
    /// </summary>
    /// <returns>The asset.</returns>
    /// <param name="reference">Reference.</param>
    /// <typeparam name="T">The 1st type parameter.</typeparam>
    public static T LoadAsset<T>(AssetReference reference) where T : Object
    {
        return reference.RuntimeKeyIsValid()
                      ? AssetDatabase.LoadAssetAtPath<T>(AssetDatabase.GUIDToAssetPath(reference.AssetGUID))
                      : default;
    }

    /// <summary>
    /// グループ一覧を取得
    /// </summary>
    /// <returns>The asset groups.</returns>
    public static List<AddressableAssetGroup> GetAllAssetGroups()
    {
        var setting = AddressableAssetSettingsDefaultObject.GetSettings(false);
        var gropus = new List<AddressableAssetGroup>();

        if (setting != default)
        {
            gropus = setting.groups;
        }

        return gropus;
    }

    /// <summary>
    /// 全エントリーを取得
    /// </summary>
    /// <returns>The asset entrys editor only.</returns>
    /// <param name="groupFilterGuids">Group filter.</param>
    public static List<AddressableAssetEntry> GetAllAssetEntrys(string[] groupFilterGuids = null)
    {
        var setting = AddressableAssetSettingsDefaultObject.GetSettings(false);
        var entrys = new List<AddressableAssetEntry>();

        if (setting != default)
        {
            foreach (var group in setting.groups)
            {
                if (groupFilterGuids != null
                    && groupFilterGuids.Length > 0
                    && !groupFilterGuids.Any(guid => guid == group.Guid))
                {
                    continue;
                }

                var _entrys = new List<AddressableAssetEntry>();
                group.GatherAllAssets(_entrys, false, true, false);
                entrys.AddRange(_entrys);
            }
        }

        return entrys;
    }
#endif
    #endregion

}

実装のポイント

AddressableAssetSettingsの取得方法が変わりました

OdinWithAddressableAssetReference.cs
var setting = AddressableAssetSettingsDefaultObject.GetSettings(false);

プレビュー用GameObjectをシリアライズされないようにする

プレビューを表示するためのGameObjectがシリアライズされないようにprivateでShowInInspectorアトリビュートを使用しています。
publicにしたい場合は、[System.NonSerialized]を追加。

更に、プレビューは参照だけで使用されることが無いので#pragma warningでCS0649警告が表示されないようにしています。

OdinWithAddressableAssetReference.cs
[ShowInInspector, ()] GameObject PreviewOnEditor;

OdinでAddressableは非対応なのでGuidを保存する

Reference.png ドロップダウンは実はテキストです(string referenceGuidEditorOnly)。 表示するリストを生成する際(ReferenceDropDownEditorOnly())、表示用のアセットパスと保存用のGuidをOdinのValueDropdownItemに代入しています。 そして、Guidに変更があった場合(ReferenceValueChangedEditorOnly(string guid))でプレビューを更新する仕様です。
OdinWithAddressableAssetReference.cs
[SerializeField, ValueDropdown("ReferenceDropDownEditorOnly"), OnValueChanged("ReferenceValueChangedEditorOnly"), LabelText("References")] string referenceGuidEditorOnly;

IEnumerable ReferenceDropDownEditorOnly()
{
    return GetAllAssetEntrys(targetAssetGroupGuidsEditorOnly)
            .Select(x => new ValueDropdownItem(x.AssetPath, x.guid));
}

void ReferenceValueChangedEditorOnly(string guid)
{
    var entrys = GetAllAssetEntrys(targetAssetGroupGuidsEditorOnly);
    var item = entrys.FirstOrDefault(x => x.guid == guid);

    if (item != default)
    {
        references = new AssetReferenceGameObject(item.guid);
        UpdatePreviewAssetEditorOnly();
    }
}

/// <summary>
/// 全エントリーを取得
/// </summary>
/// <returns>The asset entrys editor only.</returns>
/// <param name="groupFilterGuids">Group filter.</param>
public static List<AddressableAssetEntry> GetAllAssetEntrys(string[] groupFilterGuids = null)
{
    var setting = AddressableAssetSettingsDefaultObject.GetSettings(false);
    var entrys = new List<AddressableAssetEntry>();

    if (setting != default)
    {
        foreach (var group in setting.groups)
        {
            if (groupFilterGuids != null
                && groupFilterGuids.Length > 0
                && !groupFilterGuids.Any(guid => guid == group.Guid))
            {
                continue;
            }

            var _entrys = new List<AddressableAssetEntry>();
            group.GatherAllAssets(_entrys, false, true, false);
            entrys.AddRange(_entrys);
        }
    }

    return entrys;
}

グループフィルターに対応

Group.png フィルタ機能もつけてみました。 ほんとはLabel用のフィルタ機能もつけたかったのですが、 LabelTableがprivateの為一覧取得ができず断念しました。
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?