mackysoft / Unity-SerializeReferenceExtensions

Provide popup to specify the type of the field serialized by the [SerializeReference] attribute in the inspector.
https://qiita.com/makihiro_dev/items/26daeb3e5f176934bf0a
MIT License
725 stars 56 forks source link

[BUG] Duplicated element reference to the same object #35

Closed thewhitewayofdelight closed 11 months ago

thewhitewayofdelight commented 11 months ago

What happened?

Bug Desc

When an element in a list is duplicated, it'll reference to the same object!

Expected Output

When duplicated, it should create a new reference, so that it's easier to handle repetitive list that has almost identical values.

https://github.com/mackysoft/Unity-SerializeReferenceExtensions/assets/87333145/7557d715-3002-4ea6-92b7-2f13dd392ba4

Package Version

1.1.9

Unity Version

2022.2.17

mackysoft commented 11 months ago

Hi. Sorry for the inconvenience.

Duplicating array elements is the default behavior of the Unity editor array, and since SubclassSelector is built on PropertyDrawer, accessing the array from SubclassSelectorDrawer is challenging.

If you want to manipulate the elements of the array, you will need to monitor the SubclassSelector property array in the inspector editor extension and make the necessary operations.

https://github.com/mackysoft/Unity-SerializeReferenceExtensions/issues/20#issuecomment-1134248486

Below is an editor extension code from a project I created on in the past. In the ReorderableList.onAddCallback, it monitors the addition of elements, and the newly added elements are initialized with a null reference.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditorInternal;

namespace MackySoft.MyProject {

    [CustomPropertyDrawer(typeof(LevelProcessorCollection))]
    public class LevelProcessorCollectionDrawer : PropertyDrawer {

        bool m_Initialized;
        SerializedProperty m_Builders;
        ReorderableList m_BuildersList;

        float m_SingleLineHeight;
        SerializedProperty[] m_BuilderCaches;

        public override void OnGUI (Rect position,SerializedProperty property,GUIContent label) {
            Initialize(property);

            EditorGUI.BeginProperty(position,label,property);
            m_BuildersList.DoList(position);
            EditorGUI.EndProperty();
        }

        public override float GetPropertyHeight (SerializedProperty property,GUIContent label) {
            Initialize(property);
            return m_BuildersList.GetHeight();
        }

        void Initialize (SerializedProperty property) {
            if (m_Initialized) {
                return;
            }
            m_SingleLineHeight = EditorGUIUtility.singleLineHeight;

            m_Builders = property.FindPropertyRelative("m_Processors");
            m_BuildersList = ReorderableListUtility.CreateDefaultList(m_Builders.serializedObject,m_Builders);
            m_BuildersList.drawElementCallback = (rect,index,isActive,isFocused) => {
                rect.xMin += 10f;
                rect.y += 2f;
                EditorGUI.PropertyField(rect,m_BuilderCaches[index],true);
            };
            m_BuildersList.elementHeightCallback = index => {
                var builder = m_BuilderCaches[index];
                return (builder.isExpanded ? EditorGUI.GetPropertyHeight(builder) : m_SingleLineHeight) + 4f;
            };
            m_BuildersList.onAddCallback = list => {
                m_Builders.InsertArrayElementAtIndex(m_Builders.arraySize);
                var newElement = m_Builders.GetArrayElementAtIndex(m_Builders.arraySize - 1);
                newElement.managedReferenceValue = null;
                newElement.isExpanded = true;
            };
            m_BuildersList.onChangedCallback = list => UpdateCaches();
            UpdateCaches();
            m_Initialized = true;
        }

        void UpdateCaches () {
            m_BuilderCaches = new SerializedProperty[m_Builders.arraySize];
            for (int i = 0;m_Builders.arraySize > i;i++) {
                m_BuilderCaches[i] = m_Builders.GetArrayElementAtIndex(i);
            }
        }

    }
}

I hope this helps.