using System; using System.Collections.Generic; using System.Reflection; using UnityEditor.AddressableAssets.GUI; using UnityEngine; using UnityEngine.ResourceManagement.Util; using UnityEngine.Serialization; namespace UnityEditor.AddressableAssets.Settings { /// <summary> /// Contains data for AddressableAssetGroups. /// </summary> public class AddressableAssetGroupSchema : ScriptableObject { [FormerlySerializedAs("m_group")] [AddressableReadOnly] [SerializeField] AddressableAssetGroup m_Group; SerializedObject m_SchemaSerializedObject = null; internal SerializedObject SchemaSerializedObject { get { if (m_SchemaSerializedObject == null) m_SchemaSerializedObject = new SerializedObject(this); return m_SchemaSerializedObject; } set { m_SchemaSerializedObject = value; } } /// <summary> /// Get the group that the schema belongs to. /// </summary> public AddressableAssetGroup Group { get { return m_Group; } internal set { m_Group = value; if (m_Group != null) { OnSetGroup(m_Group); Validate(); } } } /// <summary> /// Override this method to perform post creation initialization. /// </summary> /// <param name="group">The group that the schema is added to.</param> protected virtual void OnSetGroup(AddressableAssetGroup group) { } internal virtual void Validate() { } /// <summary> /// Used to display the GUI of the schema. /// </summary> public virtual void OnGUI() { var type = GetType(); var p = SchemaSerializedObject.GetIterator(); p.Next(true); while (p.Next(false)) { var prop = type.GetField(p.name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); if (prop != null) EditorGUILayout.PropertyField(p, true); } SchemaSerializedObject.ApplyModifiedProperties(); } /// <summary> /// Used to display the GUI of multiple selected groups. /// </summary> /// <param name="otherSchemas">Schema instances in the other selected groups</param> public virtual void OnGUIMultiple(List<AddressableAssetGroupSchema> otherSchemas) { } /// <summary> /// Used to notify the addressables settings that data has been modified. This must be called by subclasses to ensure proper cache invalidation. /// </summary> /// <param name="postEvent">Determines if this method call will post an event to the internal addressables event system</param> protected void SetDirty(bool postEvent) { m_SchemaSerializedObject = null; if (m_Group != null) { if (m_Group.Settings != null && m_Group.Settings.IsPersisted) { EditorUtility.SetDirty(this); AddressableAssetUtility.OpenAssetIfUsingVCIntegration(this); } if (m_Group != null) m_Group.SetDirty(AddressableAssetSettings.ModificationEvent.GroupSchemaModified, this, postEvent, false); } } /// <summary> /// Used for drawing properties in the inspector. /// </summary> public virtual void ShowAllProperties() { } /// <summary> /// Display mixed values for the specified property found in a list of schemas. /// </summary> /// <param name="property">The property.</param> /// <param name="otherSchemas">The list of schemas that may contain the property.</param> /// <param name="type">The property type.</param> /// <param name="propertyName">The property name.</param> protected void ShowMixedValue(SerializedProperty property, List<AddressableAssetGroupSchema> otherSchemas, Type type, string propertyName) { foreach (var schema in otherSchemas) { var s_prop = schema.SchemaSerializedObject.FindProperty(propertyName); if ((property.propertyType == SerializedPropertyType.Enum && (property.enumValueIndex != s_prop.enumValueIndex)) || (property.propertyType == SerializedPropertyType.String && (property.stringValue != s_prop.stringValue)) || (property.propertyType == SerializedPropertyType.Integer && (property.intValue != s_prop.intValue)) || (property.propertyType == SerializedPropertyType.Boolean && (property.boolValue != s_prop.boolValue))) { EditorGUI.showMixedValue = true; return; } if (type == typeof(ProfileValueReference)) { var field = property.serializedObject.targetObject.GetType().GetField(property.name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); string lhsId = (field?.GetValue(property.serializedObject.targetObject) as ProfileValueReference)?.Id; string rhsId = (field?.GetValue(s_prop.serializedObject.targetObject) as ProfileValueReference)?.Id; if (lhsId != null && rhsId != null && lhsId != rhsId) { EditorGUI.showMixedValue = true; return; } } if (type == typeof(SerializedType)) { var field = property.serializedObject.targetObject.GetType().GetField(property.name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); Type lhs = ((SerializedType)field?.GetValue(property.serializedObject.targetObject)).Value; Type rhs = ((SerializedType)field?.GetValue(s_prop.serializedObject.targetObject)).Value; if (lhs != null && rhs != null && lhs != rhs) { EditorGUI.showMixedValue = true; return; } } } } } }