Search Unity

Catalog from editor

Discussion in 'Game Foundation' started by DenariiGames, Jul 27, 2021.

  1. DenariiGames

    DenariiGames

    Joined:
    Dec 29, 2019
    Posts:
    13
    Well I'm back at the well (of knowledge)...

    Working on a custom editor and wanted to get a list of catalog items. Do I need to initialize to get that list? Was hoping to get at GameFoundationCatalog.
     
    erika_d likes this.
  2. tony_c-unity3d

    tony_c-unity3d

    Unity Technologies

    Joined:
    Jul 18, 2019
    Posts:
    35
    Thanks for the question @DenariiGames . @richj_unity has an idea how to address this and will reply as soon as he can. He's looking for the simplest solution, one that doesn't involve reflection, if possible so it might not be ready tonight, but will post an answer as soon as possible. Please continue to be patient.
     
    TomTrottel, erika_d and DenariiGames like this.
  3. richj_unity

    richj_unity

    Unity Technologies

    Joined:
    Sep 23, 2019
    Posts:
    40
    Initializing Game Foundation is only needed for Play Mode and shouldn't be done in Edit Mode. What you want is to create some custom tools to manipulate the catalog assets.

    GameFoundationCatalog is an instance of CatalogAsset, which inherits ScriptableObject. Like any ScriptableObject, if you select the asset (or any of its child objects), you can make edits directly in the Inspector.

    Normally, you could use the [CustomEditor] attribute to override the Inspector for the CatalogAsset.

    Code (CSharp):
    1. [CustomEditor(typeof(CatalogAsset))]
    2. public class CatalogAssetCustomEditor : Editor
    3. {
    4.     public override void OnInspectorGUI()
    5.     {
    6.         base.OnInspectorGUI();
    7.  
    8.         GUILayout.Box("custom stuff...");
    9.     }
    10. }
    But unfortunately in this case, you can't, because we already did that.

    Another way of doing it is with a new EditorWindow, and loading the asset and writing some fully custom editor GUI code. Using the SerializedObject/SerializedProperty APIs as much as possible is highly recommended.

    The following example opens a custom editor window that just lists all the CatalogItemAssets in the loaded CatalogAsset. To start organizing and editing stuff will take a lot more code.

    Code (CSharp):
    1. using UnityEditor;
    2. using UnityEngine;
    3. using UnityEngine.GameFoundation.DefaultCatalog;
    4.  
    5. public class ListAllCatalogItemsEditorWindow : EditorWindow
    6. {
    7.     [MenuItem("My Game/Catalog Items")]
    8.     public static void GetWindowMenuItem()
    9.     {
    10.         GetWindow<ListAllCatalogItemsEditorWindow>(false, "Catalog Items", true);
    11.     }
    12.  
    13.     SerializedObject catalogSerializedObject;
    14.  
    15.     private void OnEnable()
    16.     {
    17.         var catalogAssetPath = "Assets/GameFoundation/GameFoundationCatalog.asset";
    18.         var catalogAsset = AssetDatabase.LoadAssetAtPath<CatalogAsset>(catalogAssetPath);
    19.         catalogSerializedObject = new SerializedObject(catalogAsset);
    20.     }
    21.  
    22.     void OnGUI()
    23.     {
    24.         if (catalogSerializedObject == null) return;
    25.  
    26.         catalogSerializedObject.Update();
    27.  
    28.         var itemsProperty = catalogSerializedObject.FindProperty("m_Items");
    29.  
    30.         for (var i = 0; i < itemsProperty.arraySize; i++)
    31.         {
    32.             if (itemsProperty.GetArrayElementAtIndex(i).objectReferenceValue is CatalogItemAsset itemAsset)
    33.             {
    34.                 GUILayout.Label(itemAsset.displayName);
    35.             }
    36.         }
    37.     }
    38. }
    Let me know if this helps!
     
    TomTrottel, erika_d and DenariiGames like this.
  4. tony_c-unity3d

    tony_c-unity3d

    Unity Technologies

    Joined:
    Jul 18, 2019
    Posts:
    35
    Thanks @richj_unity for the detailed answer!

    One thing to keep in mind @DenariiGames is that we are still a preview package and are in the process of reorganizing our code base based on backend changes and feedback from our customers so there's a good chance some of the fields or even entire classes will be modified, renamed or even removed. Since you're accessing the catalog directly, your code will almost-certainly require modification or even complete rewrites with each update of the Game Foundation package. You're welcome to continue your editor work of course, but you may find it easier to wait until we progress out of preview and our design & code base stabilizes. Either way, best of luck and please keep us updated on any progress you make!
     
    saskenergy likes this.
  5. DenariiGames

    DenariiGames

    Joined:
    Dec 29, 2019
    Posts:
    13
    Booyah! Thanks Rich.



    Abbreviated version of the EconomyItemEditor class if anyone wants to do similar...

    Code (CSharp):
    1.     using System;
    2.     using System.Collections;
    3.     using System.Collections.Generic;
    4.     using UnityEngine;
    5.     using UnityEngine.GameFoundation.DefaultCatalog;  
    6.     using UnityEditor;
    7.  
    8.     [CustomEditor(typeof(EconomyItem))]
    9.     public class EconomyItemEditor : Editor
    10.     {
    11.         private SerializedProperty spItemKey;
    12.         List<string> itemList = new List<string>();
    13.         string[] items;
    14.         int selectedItem = 0;
    15.  
    16.         void OnEnable()
    17.         {
    18.             this.spItemKey = this.serializedObject.FindProperty("itemKey");
    19.             //get items
    20.             var catalogAssetPath = "Assets/GameFoundation/GameFoundationCatalog.asset";
    21.             var catalogAsset = AssetDatabase.LoadAssetAtPath<CatalogAsset>(catalogAssetPath);
    22.             SerializedObject catalogSerializedObject = new SerializedObject(catalogAsset);
    23.             var itemsProperty = catalogSerializedObject.FindProperty("m_Items");
    24.             for (var i = 0; i < itemsProperty.arraySize; i++)
    25.             {
    26.                 if (itemsProperty.GetArrayElementAtIndex(i).objectReferenceValue is CatalogItemAsset itemAsset)
    27.                 {
    28.                     if (itemAsset.key != "main") itemList.Add(itemAsset.key);
    29.                 }
    30.             }
    31.             itemList.Sort((p1,p2)=>p1.CompareTo(p2));
    32.             items = itemList.ToArray();
    33.             selectedItem = itemList.IndexOf(this.spItemKey.stringValue);
    34.         }
    35.  
    36.         void OnDisable()
    37.         {
    38.             this.spItemKey = null;
    39.         }
    40.  
    41.         public override void OnInspectorGUI()
    42.         {
    43.             this.serializedObject.Update();
    44.             selectedItem = EditorGUILayout.Popup("Item Key", selectedItem, items);
    45.             this.spItemKey.stringValue = items[selectedItem];
    46.             this.serializedObject.ApplyModifiedProperties();
    47.         }
    48.     }
    49.  
     
    Last edited: Jul 29, 2021
  6. SmartCarrion

    SmartCarrion

    Joined:
    Jul 27, 2013
    Posts:
    27
    This seems close to what I need, but it also seems complicated for something I thought would be simple. I'm trying to associate a prefab or scene object with a particular catalog item without having to type in a string as the identifier. I want to select it from a drop-down so I don't get random string typo errors. So how do I get a drop down in the editor on an arbitrary script that has a reference to inventory item X?

    I had hoped something simple like this would work:
    public InventoryItem inventoryItem;


    Do i need to write a custom inspector for anything like this? The example prefabs like "Inventory Item HUD View" do this with a very neat UI, but it looks like that is all with a moderately complex custom inspector, right?

    Thanks!
     
  7. erika_d

    erika_d

    Joined:
    Jan 20, 2016
    Posts:
    413
    Hi @SmartCarrion

    Thanks for your question! You could put a reference in your script for an `InventoryItemDefinitionAsset` which would give a selector for all those assets that exist in your project directory (note that that means that if you have multiple Game Foundation Catalogs in the project items from all the catalogs will show up. I recommend making sure you're selecting items from the catalog that will be used at runtime). At runtime, you can use the key field from the InventoryItemDefinitionAsset to then look up the objects to use at runtime, which are InventoryItemDefinition and InventoryItem. The DefinitionAsset files however are not intended to be used at runtime, so it's a tiny bit of hack.

    In your example you're trying to use InventoryItem, this one in particular would be difficult to set up for selection in an inspector at editor time, because it is a specific runtime instance of the definitions you create in the editor windows.

    The custom inspectors you see in the provided prefabs are actually storing your selection as a string for the item's key, and then using that string to look up the Definition objects at runtime, which is another alternative, but does require a custom inspector.

    I hope this helps!
     
  8. tranduydyu98

    tranduydyu98

    Joined:
    Dec 30, 2021
    Posts:
    2
    tha't helpful with me. thanks.
     
    erika_d likes this.