Mejoras de SerializeReference en Unity 2021 LTS

En la versión LTS más reciente, la serialización polimórfica ofrece una mejor colaboración con los usuarios y acceso a la API, además de un manejo más detallado de los tipos que faltan.
Con el atributo SerializeReference, puedes serializar un objeto asignado a un campo como referencia, en lugar de serializarlo por valor. Los objetos a los que se hace referencia se denominan «referencias administradas». Los campos con el atributo SerializeReference sirven para admitir polimorfismo y valores null. Y, más recientemente, Unity 2021 LTS introdujo ID estables para las referencias administradas, los cuales proporcionan un manejo granular de los tipos que faltan y un mejor acceso a la API. En este blog, compartimos más información sobre estos cambios y cómo pueden beneficiarte directamente.
Las referencias administradas se guardan dentro de los datos de serialización de su host, donde el host es un objeto Unity (como una clase derivada de MonoBehaviour o ScriptableObject). Para ello, asignamos un ID único a cada objeto de referencia administrado.
Un campo con el atributo SerializeReference se serializa guardando el ID del objeto referenciado. Las referencias administradas se guardan en una lista llamada ManagedReferenceRegistry, que se incluye dentro de los datos serializados del host.
En Unity 2019 y 2020 LTS, los ID se asignaban en el momento de ahorro mediante un recorrido primero por el contenido. El principal inconveniente de este enfoque es que las acciones pequeñas, como reordenar los elementos de una matriz, podrían generar un cambio significativo en el archivo afectado. Los cambios grandes dentro de los archivos podrían generar conflictos de fusión, que son difíciles de resolver cuando se trabaja en un entorno colaborativo.
Por eso presentamos Stable ID. El ID estable garantiza que, una vez que un objeto tiene asignado su propio ID único, ese mismo ID se conserva en los sucesivos ciclos de guardado y carga. En otras palabras, cambiar la asignación de campo de las referencias administradas en el host y, luego, volver a guardar no alterará el ID.
Para ilustrar el valor de Stable ID, considera el siguiente ejemplo:

Este ejemplo crea una matriz de objetos de referencia administrados, con instancias intercaladas de la clase Sandwich y Fruit. Puedes ver el contenido de la matriz inspeccionando el archivo LunchBox1.asset.

Al mover la primera entrada al final de la lista, se producirá un cambio en el archivo de assets subyacente. Las siguientes capturas de pantalla de una herramienta de diferenciación demuestran lo simple que es la diferencia de la versión 2021.3, ya que los objetos de la matriz ahora tienen ID independientes del orden de la matriz.
2020.3:

2021.3:

Además de reducir los cambios dentro de los archivos Unity, la función de ID estable está diseñada para abordar desafíos de colaboración comunes. En versiones anteriores, dos usuarios que agregaban objetos de referencia administrados en el mismo host terminaban con el mismo ID, lo que dificultaba la fusión (especialmente porque un solo objeto de referencia administrado puede ser referenciado por más de un campo). A partir de Unity 2021, las ID ahora están virtualmente garantizadas para evitar un conflicto de este tipo, porque se generan en función del hash de tiempo y la información del sistema. Para situaciones más avanzadas, incluso puedes anular el sistema de asignación de ID predeterminado llamando a SerializationUtility.SetManagedReferenceIdForObject.
SerializeReference incluye compatibilidad con el polimorfismo, lo que significa que un campo se puede asignar a una instancia de una clase que deriva del tipo de campo. De hecho, admitimos el tipo de campo "System.Object", que es la clase base raíz de cada clase de C#. Pero esto abre la posibilidad de que un proyecto compilado correctamente no incluya las definiciones de clases que estaban disponibles anteriormente y se habían guardado en una escena o un archivo de assets. En algunos casos, las clases pueden desaparecer cuando se quitan los archivos fuente, se les cambia el nombre o se mueven a otro ensamblado.
Al cargar un objeto host SerializedReference, se examina el nombre de tipo completamente calificado de cada objeto de referencia administrado y se debe volver a resolver a un tipo de clase válido para poder instanciarlo. En versiones anteriores de Unity, las clases que faltaban podían poner todo el objeto «host» en un estado de error sin cargar ninguno de los objetos de referencia administrados válidos. Por lo tanto, si tuvieras un "host" con una matriz de 15 objetos de referencia administrados, pero no se pudiera resolver un solo objeto, entonces no verías ninguno en el Inspector. Habría un error registrado en la consola, aunque el objeto host no estuviera marcado visualmente como en estado de error al inspeccionarlo, y todas las ediciones realizadas se descartarían silenciosamente.
En Unity 2021, ahora instanciamos todos los objetos de referencia administrados que se pueden cargar y reemplazamos los que faltan por null. Esto les da a los usuarios la oportunidad de ver más detalles sobre el estado del objeto host y facilitar la resolución de los tipos que faltan. Mientras tanto, si el tipo que falta se restaura mientras el objeto host está cargado, la recarga de dominio activada restaurará los objetos de referencia administrados y todos los campos que hacen referencia a este tipo de objetos se actualizarán adecuadamente.
Este es un ejemplo de cómo aparecen los objetos con tipos perdidos en el Inspector:
En la versión 2020.3, falta la clase Fruit, pero el Inspector no muestra ningún elemento de matriz y no hay indicación de error:
En la versión 2021.3, el Inspector te advierte que los objetos Fruit que faltan aparecen como null entrys, mientras que los Sandwich siguen mostrándose:
Los mensajes de error en la consola relacionados con los tipos que faltan también se actualizaron para que sean menos repetitivos: simplemente identifican qué objetos del host tienen tipos que faltan.
Este es un mensaje de error en la versión 2020.3:
Compáralo con este mensaje de advertencia de la versión 2021.3:
Aprovechar esas mejoras en los ID, más los cambios realizados en los objetos de referencia administrados en los Prefabs, ahora se adhieren a esos objetos de referencia administrados. Antes, PropertyModifications se orientaba a los campos basados en la primera ruta de propiedad que llevaba a ese campo. Esto significaba que si la ruta cambiaba (por ejemplo, reordenando una matriz), PropertyModification perdería el seguimiento de la referencia administrada prevista y no se resolvería adecuadamente. A partir de Unity 2021, hay PropertyModifications que hacen referencia a objetos de referencia administrados mediante una ruta que incorpora el ID estable, es decir, managedReferences[12345].myString. Esto garantiza que un objeto de referencia administrado mantenga sus valores anulados, independientemente de dónde lo muevas en el host.
Se ha agregado una nueva clase, SerializationUtility, a la API de Unity para mostrar la funcionalidad relacionada con SerializeReference. Por ejemplo, SerializationUtility.ClearAllManagedReferencesWithMissingTypes() se puede utilizar para eliminar las referencias a tipos que faltan, como eliminar el estado de advertencia de un host si no se planea recuperar un tipo que falta.
Perfeccionamos la API para trabajar con referencias administradas en el contexto de CustomEditors, incluida la opción de acceso de lectura a SerializedProperty.managedReferenceValue.
La referencia para los nuevos métodos también incluye código de muestra. Además, agregamos más detalles para los temas de referencia relacionados con la serialización.
Tus proyectos existentes que usan SerializeReference deberían cargarse sin problemas en la nueva versión de Unity, ya que el código de serialización es compatible con el formato de referencia administrado anterior. Con frecuencia, el uso de SerializeReference no requiere un conocimiento profundo del concepto de ID estable ni de los nuevos métodos de la API. Sin embargo, incluso si se las deja «bajo techo», estas mejoras son beneficiosas para el uso típico, especialmente en un entorno colaborativo.
Esperamos que este artículo te anime a seguir explorando esta función. A medida que nuestro equipo de serialización continúa mejorando las capacidades para todos los usuarios Unity, agradecemos tus comentarios y conversaciones sobre este proceso del foro dedicado.