Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Retrieving array size but no array was provided

Discussion in 'Scripting' started by tribaleur, Jan 23, 2020.

  1. tribaleur

    tribaleur

    Joined:
    Jan 19, 2017
    Posts:
    34
    Hello,

    I'm trying to do a custom PropertyDrawer for a custom class with a List. To format the list i use the ReordorableList classe provided by Unity.

    The problème is when i try to initialise the list, i got the error : Retrieving array size but no array was provided.

    Here my PropertyDrawer :

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. using UnityEditorInternal;
    4.  
    5. [CustomPropertyDrawer(typeof(SpellsEffectsList))]
    6. public  class Drawer_SpellsEffectsList : PropertyDrawer {
    7.     //_____ PROTECTED PROPERTIES ________________________________________________
    8.     protected ReorderableList _reorderableList;
    9.     protected SerializedProperty _serializedList;
    10.     protected string _headerText = "";
    11.  
    12.  
    13.  
    14.     //_____ CONSTRUCTOR _________________________________________________________
    15.     ~Drawer_SpellsEffectsList () {      
    16.         // Delete Callback to make sure we don't get memory leaks etc.
    17.         this._reorderableList.drawHeaderCallback -= this.DrawHeader;
    18.         this._reorderableList.drawElementCallback -= this.DrawElement;
    19.  
    20.         this._reorderableList.onAddCallback -= this.AddItem;
    21.         this._reorderableList.onRemoveCallback -= this.RemoveItem;
    22.     }
    23.  
    24.  
    25.  
    26.  
    27.  
    28.     //_____ TRIGGER _____________________________________________________________
    29.     public override void OnGUI (Rect position, SerializedProperty property, GUIContent label){
    30.         this._reorderableList = new ReorderableList(property.serializedObject, property, true, true, true, true);
    31.             // => this is where the error occured : Input elements should be an Array SerializedProperty
    32.        
    33.         // Add listeners to draw events
    34.         this._reorderableList.drawHeaderCallback += this.DrawHeader;
    35.         this._reorderableList.drawElementCallback += this.DrawElement;
    36.  
    37.         this._reorderableList.onAddCallback += this.AddItem;
    38.         this._reorderableList.onRemoveCallback += this.RemoveItem;
    39.  
    40.         // Add header
    41.         this._headerText = label.text;
    42.  
    43.         // Override logic works on the entire property
    44.         EditorGUI.BeginProperty(position, label, property);
    45.        
    46.         this._reorderableList.DoLayoutList();
    47.  
    48.         EditorGUI.EndProperty();
    49.        
    50.         // Apply changes to the serializedProperty
    51.         property.serializedObject.ApplyModifiedProperties();
    52.     }
    53.  
    54.  
    55.  
    56.     //_____ METHODES ____________________________________________________________  
    57.     /* -------------------------------------------------------------------------------------------------------------------------
    58.      * Draws one element of the list
    59.      * ------------------------------------------------------------------------------------------------------------------------- */
    60.     protected void  DrawElement (Rect rect, int index, bool active, bool focused) {
    61.         SerializedProperty item = this._serializedList.GetArrayElementAtIndex(index);
    62.         SerializedProperty element_Id = item.FindPropertyRelative("_id");
    63.  
    64.         EditorGUI.BeginChangeCheck();
    65.         EditorGUI.PropertyField(rect, element_Id);
    66.         if (EditorGUI.EndChangeCheck()){
    67.             // Set the item as modified and add the modification in the undo action list
    68.             Undo.RecordObject(this._serializedList.serializedObject.targetObject, "Cancel item's modification on " + this._serializedList.GetType().ToString() + " reorderable list");
    69.         }  
    70.     }
    71.    
    72.    
    73.     /* -------------------------------------------------------------------------------------------------------------------------
    74.      * Draws the header of the list
    75.      * ------------------------------------------------------------------------------------------------------------------------- */
    76.     private void DrawHeader(Rect rect){
    77.         GUI.Label(rect, this._headerText);
    78.     }
    79.          
    80.     /* -------------------------------------------------------------------------------------------------------------------------
    81.      * Add an item in the list
    82.      * ------------------------------------------------------------------------------------------------------------------------- */
    83.      private void AddItem(ReorderableList list){
    84.         this._serializedList.InsertArrayElementAtIndex(list.index);
    85.  
    86.         // Set the list as modified and add the modification in the undo action list
    87.         Undo.RecordObject(this._serializedList.serializedObject.targetObject, "Cancel Add item on " + this._serializedList.GetType().ToString() + " reorderable list");
    88.      }
    89.  
    90.     /* -------------------------------------------------------------------------------------------------------------------------
    91.      * Delete an item of the list
    92.      * ------------------------------------------------------------------------------------------------------------------------- */
    93.      private void RemoveItem(ReorderableList list) {
    94.         this._serializedList.DeleteArrayElementAtIndex(list.index);
    95.        
    96.         // Set the list as modified and add the modification in the undo action list
    97.         Undo.RecordObject(this._serializedList.serializedObject.targetObject, "Cancel Remove item on " + this._serializedList.GetType().ToString() + " reorderable list");
    98.      }
    99. }
    Here my SpellsEffectsList :
    Code (CSharp):
    1. using System.Collections.Generic;
    2. using System;
    3.  
    4. [Serializable]
    5. public class SpellsEffectsList : List<SpellEffect> {
    6.     // Only some methodes here ...
    7. }
    Here how the list is declared :
    Code (CSharp):
    1. [SerializeField]
    2.     private SpellsEffectsList    _spellsEffects    = new SpellsEffectsList();
    Here how the the propertyDrawer is called from a custom Editor :
    Code (CSharp):
    1. public override void OnInspectorGUI () {
    2.         // few code ...
    3.         EditorGUILayout.PropertyField(serializedSpell.FindProperty("_spellsEffects"), true);
    4.         // some other code ...
    5.     }
    When i'm in debug mode,I have this in Visual Studio :
    upload_2020-1-23_15-9-46.png

    I don't understand why i have this problème.

    Do you have an idea ?

    Thanks for your help.
     
  2. eses

    eses

    Joined:
    Feb 26, 2013
    Posts:
    2,637
    Hi @tribaleur

    Is there a specific reason you are extending generic list?

    Code (CSharp):
    1. public class SpellsEffectsList : List<SpellEffect> {}

    Try using list with type instead, and you should get your list working (in Custom Editor):

    Code (CSharp):
    1. public List<SpellEffect> list = new List<SpellEffect>();
     
  3. tribaleur

    tribaleur

    Joined:
    Jan 19, 2017
    Posts:
    34
    Hi Eses,

    I already tried it, but i have the message "nullReferenceException: Object reference not set to an instance of an object" in the Editor when i call the propertyDrawer .

    In the custom Editor :
    Code (CSharp):
    1. public override void OnInspectorGUI () {
    2.  
    3.         Spell gameObject_Spell = (Spell)target;
    4.         if (gameObject_Spell.SpellsEffects == null) { Debug.Log("Null liste"); }
    5.         else { Debug.Log("Not Null liste"); } // The log show me this message so the list is instanciate  ?
    6.         SerializedObject serializedSpell = new SerializedObject(gameObject_Spell);
    7.  
    8. *** EDIT ***
    9. SerializedProperty spl = serializedSpell.FindProperty("_spellsEffects");
    10. // This always return Null even if the serializedSpell have the property "_spellsEffects" set.
    11. // I tried as well with the name of the Get accessor but it still doesn't works.
    12. // So the question is why the List can't be found by "FindProperty()" ?
    13. *** END EDIT ***
    14.  
    15.         // ...
    16.  
    17.         EditorGUILayout.PropertyField(serializedSpell.FindProperty("_spellsEffects"), true);
    18.         // => The error message is there !
    19.  
    20.         // ...
    21.     }
    I don't understand why i have this error.

    About the extend of the generic list : it's to modify the Add() method and to create some news one
     
    Last edited: Jan 23, 2020
  4. eses

    eses

    Joined:
    Feb 26, 2013
    Posts:
    2,637
    What I mean;

    I tried this - if using just a generic list, this will find the list:
    Code (CSharp):
    1. var prop = serializedObject.FindProperty("list");
    And the classes look like this:
    Code (CSharp):
    1. public class SpellEffects : MonoBehaviour
    2. {
    3.     // this will work
    4.     public List<SpellEffect> list = new List<SpellEffect>();
    5. }
    6.  
    7. [System.Serializable]
    8. public class SpellEffect
    9. {
    10.     public string someString = "foo";
    11. }
    12.  
    But if using sub class of generic list (what you were using) Unity serialized property doesn't seem to be able to find the list... Maybe such list isn't supported.
     
  5. Errorsatz

    Errorsatz

    Joined:
    Aug 8, 2012
    Posts:
    555
    You can achieve similar results by using extension methods. For example:

    Code (CSharp):
    1. public static class SpellEffectListExtensions
    2. {
    3.    public void AddEffect(this IList<SpellEffect> self, SpellEffect item)
    4.    {
    5.       self.Add(item);
    6.       // Whatever else
    7.    }
    8. }
    9.  
    10. ...
    11.  
    12. List<SpellEffect> list;
    13. list.AddEffect(myEffect);
     
  6. tribaleur

    tribaleur

    Joined:
    Jan 19, 2017
    Posts:
    34
    Hi guys,

    Thanks for your help.

    @eses : I tried the following to understand.

    I declared 3 list :
    Code (CSharp):
    1. [SerializeField]
    2.     private SpellsEffectsList    _spellsEffects    = new SpellsEffectsList();
    3.     [SerializeField]
    4.     private List<SpellEffect>    _spellsEffects2    = new List<SpellEffect>();
    5.     [SerializeField]
    6.     private List<Object>    _objects    = new List<Object>();
    In the editor i tried this :
    Code (CSharp):
    1.  
    2.         SerializedProperty se = serializedObject.FindProperty("_spellsEffects"); // Return a serialisedProperty but not as an array
    3.         SerializedProperty se2 = serializedObject.FindProperty("_spellsEffects2"); // Return Null
    4.         SerializedProperty lo = serializedObject.FindProperty("_objects"); // Return an empty List of object (isArray = true)
    So it doesn't works when the elements have the SpellEffect type.
    After few test i found why ... SpellEffect is an abstract class for inheritance. It's looks like unity can't serialise abstract class. I have to think on how to change that classe to not abstract.

    Anyway, SpellsEffectsList is still not recognised as an array when List<SpellEffect> does. So i have to think on @ErrorStatz solution. Thanks for your help guys.