mirror of
https://github.com/maxartz15/UnitySerializedReferenceUI.git
synced 2024-11-22 07:35:36 +01:00
Merge pull request #2 from TextusGames/Development
Ready to push new Major version
This commit is contained in:
commit
ae197c1a9b
3
.gitignore
vendored
3
.gitignore
vendored
@ -7,10 +7,11 @@
|
|||||||
[Tt]emp/
|
[Tt]emp/
|
||||||
[Oo]bj/
|
[Oo]bj/
|
||||||
[Bb]uild/
|
[Bb]uild/
|
||||||
[Bb]uilds/
|
[Bb]uilds/
|
||||||
[Ll]ogs/
|
[Ll]ogs/
|
||||||
[Mm]emoryCaptures/
|
[Mm]emoryCaptures/
|
||||||
|
|
||||||
|
.[Ii]dea/
|
||||||
[Pp]rojectSettings/
|
[Pp]rojectSettings/
|
||||||
[Pp]ackages/
|
[Pp]ackages/
|
||||||
|
|
||||||
|
@ -0,0 +1,95 @@
|
|||||||
|
#if UNITY_EDITOR
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
using Object = UnityEngine.Object;
|
||||||
|
|
||||||
|
public static class ManagedReferenceUtility
|
||||||
|
{
|
||||||
|
/// Creates instance of passed type and assigns it to managed reference
|
||||||
|
public static object AssignNewInstanceOfTypeToManagedReference(this SerializedProperty serializedProperty, Type type)
|
||||||
|
{
|
||||||
|
var instance = Activator.CreateInstance(type);
|
||||||
|
|
||||||
|
serializedProperty.serializedObject.Update();
|
||||||
|
serializedProperty.managedReferenceValue = instance;
|
||||||
|
serializedProperty.serializedObject.ApplyModifiedProperties();
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets managed reference to null
|
||||||
|
public static void SetManagedReferenceToNull(this SerializedProperty serializedProperty)
|
||||||
|
{
|
||||||
|
serializedProperty.serializedObject.Update();
|
||||||
|
serializedProperty.managedReferenceValue = null;
|
||||||
|
serializedProperty.serializedObject.ApplyModifiedProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Collects appropriate types based on managed reference field type and filters. Filters all derive
|
||||||
|
public static IEnumerable<Type> GetAppropriateTypesForAssigningToManagedReference(this SerializedProperty property, List<Func<Type, bool>> filters = null)
|
||||||
|
{
|
||||||
|
var fieldType = property.GetManagedReferenceFieldType();
|
||||||
|
return GetAppropriateTypesForAssigningToManagedReference(fieldType, filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Filters derived types of field typ parameter and finds ones whose are compatible with managed reference and filters.
|
||||||
|
public static IEnumerable<Type> GetAppropriateTypesForAssigningToManagedReference(Type fieldType, List<Func<Type, bool>> filters = null)
|
||||||
|
{
|
||||||
|
var appropriateTypes = new List<Type>();
|
||||||
|
|
||||||
|
// Get and filter all appropriate types
|
||||||
|
var derivedTypes = TypeCache.GetTypesDerivedFrom(fieldType);
|
||||||
|
foreach (var type in derivedTypes)
|
||||||
|
{
|
||||||
|
// Skips unity engine Objects (because they are not serialized by SerializeReference)
|
||||||
|
if (type.IsSubclassOf(typeof(Object)))
|
||||||
|
continue;
|
||||||
|
// Skip abstract classes because they should not be instantiated
|
||||||
|
if (type.IsAbstract)
|
||||||
|
continue;
|
||||||
|
// Filter types by provided filters if there is ones
|
||||||
|
if (filters != null && filters.All(f => f == null || f.Invoke(type)) == false)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
appropriateTypes.Add(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return appropriateTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets real type of managed reference
|
||||||
|
public static Type GetManagedReferenceFieldType(this SerializedProperty property)
|
||||||
|
{
|
||||||
|
var realPropertyType = GetRealTypeFromTypename(property.managedReferenceFieldTypename);
|
||||||
|
if (realPropertyType != null)
|
||||||
|
return realPropertyType;
|
||||||
|
|
||||||
|
Debug.LogError($"Can not get field type of managed reference : {property.managedReferenceFieldTypename}");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets real type of managed reference's field typeName
|
||||||
|
public static Type GetRealTypeFromTypename(string stringType)
|
||||||
|
{
|
||||||
|
var names = GetSplitNamesFromTypename(stringType);
|
||||||
|
var realType = Type.GetType($"{names.ClassName}, {names.AssemblyName}");
|
||||||
|
return realType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get assembly and class names from typeName
|
||||||
|
public static (string AssemblyName, string ClassName) GetSplitNamesFromTypename(string typename)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(typename))
|
||||||
|
return ("","");
|
||||||
|
|
||||||
|
var typeSplitString = typename.Split(char.Parse(" "));
|
||||||
|
var typeClassName = typeSplitString[1];
|
||||||
|
var typeAssemblyName = typeSplitString[0];
|
||||||
|
return (typeAssemblyName, typeClassName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
@ -9,7 +9,7 @@ using UnityEngine;
|
|||||||
public static class SerializeReferenceGenericSelectionMenu
|
public static class SerializeReferenceGenericSelectionMenu
|
||||||
{
|
{
|
||||||
/// Purpose.
|
/// Purpose.
|
||||||
/// This is generic selection menu.
|
/// This is generic selection menu.
|
||||||
/// Filtering.
|
/// Filtering.
|
||||||
/// You can add substring filter here to filter by search string.
|
/// You can add substring filter here to filter by search string.
|
||||||
/// As well ass type or interface restrictions.
|
/// As well ass type or interface restrictions.
|
||||||
@ -22,72 +22,39 @@ public static class SerializeReferenceGenericSelectionMenu
|
|||||||
context.ShowAsContext();
|
context.ShowAsContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static void FillContextMenu(IEnumerable<Func<Type, bool>> enumerableFilters, GenericMenu contextMenu, SerializedProperty property)
|
private static void FillContextMenu(IEnumerable<Func<Type, bool>> enumerableFilters, GenericMenu contextMenu, SerializedProperty property)
|
||||||
{
|
{
|
||||||
var filters = enumerableFilters.ToList();// Prevents possible multiple enumerations
|
var filters = enumerableFilters.ToList();// Prevents possible multiple enumerations
|
||||||
|
|
||||||
// Adds "Make Null" menu command
|
// Adds "Make Null" menu command
|
||||||
contextMenu.AddItem(new GUIContent("Null"), false, () => MakeSerializedPropertyNull(property));
|
contextMenu.AddItem(new GUIContent("Null"), false, property.SetManagedReferenceToNull);
|
||||||
|
|
||||||
// Find real type of managed reference
|
|
||||||
var realPropertyType = SerializeReferenceTypeNameUtility.GetRealTypeFromTypename(property.managedReferenceFieldTypename);
|
|
||||||
if (realPropertyType == null)
|
|
||||||
{
|
|
||||||
Debug.LogError("Can not get type from");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get and filter all appropriate types
|
// Collects appropriate types
|
||||||
var types = TypeCache.GetTypesDerivedFrom(realPropertyType);
|
var appropriateTypes = property.GetAppropriateTypesForAssigningToManagedReference(filters);
|
||||||
foreach (var type in types)
|
|
||||||
{
|
// Adds appropriate types to menu
|
||||||
// Skips unity engine Objects (because they are not serialized by SerializeReference)
|
foreach (var appropriateType in appropriateTypes)
|
||||||
if(type.IsSubclassOf(typeof(UnityEngine.Object)))
|
AddItemToContextMenu(appropriateType, contextMenu, property);
|
||||||
continue;
|
|
||||||
// Skip abstract classes because they should not be instantiated
|
|
||||||
if(type.IsAbstract)
|
|
||||||
continue;
|
|
||||||
// Filter types by provided filters if there is ones
|
|
||||||
if (FilterTypeByFilters(filters, type) == false)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
AddItemToContextMenu(type, contextMenu, property);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void MakeSerializedPropertyNull(SerializedProperty serializedProperty)
|
|
||||||
{
|
|
||||||
serializedProperty.serializedObject.Update();
|
|
||||||
serializedProperty.managedReferenceValue = null;
|
|
||||||
serializedProperty.serializedObject.ApplyModifiedPropertiesWithoutUndo(); // undo is bugged for now
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AddItemToContextMenu(Type type, GenericMenu genericMenuContext, SerializedProperty property)
|
private static void AddItemToContextMenu(Type type, GenericMenu genericMenuContext, SerializedProperty property)
|
||||||
{
|
{
|
||||||
var assemblyName = type.Assembly.ToString().Split('(', ',')[0];
|
var assemblyName = type.Assembly.ToString().Split('(', ',')[0];
|
||||||
var entryName = type + " ( " + assemblyName + " )";
|
var entryName = type + " ( " + assemblyName + " )";
|
||||||
genericMenuContext.AddItem(new GUIContent(entryName), false, AssignNewInstanceOfType, new AssignInstanceGenericMenuParameter(type, property));
|
genericMenuContext.AddItem(new GUIContent(entryName), false, AssignNewInstanceCommand, new GenericMenuParameterForAssignInstanceCommand(type, property));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AssignNewInstanceOfType(object objectGenericMenuParameter )
|
private static void AssignNewInstanceCommand(object objectGenericMenuParameter )
|
||||||
{
|
{
|
||||||
var parameter = (AssignInstanceGenericMenuParameter) objectGenericMenuParameter;
|
var parameter = (GenericMenuParameterForAssignInstanceCommand) objectGenericMenuParameter;
|
||||||
var type = parameter.Type;
|
var type = parameter.Type;
|
||||||
var property = parameter.Property;
|
var property = parameter.Property;
|
||||||
var instance = Activator.CreateInstance(type);
|
property.AssignNewInstanceOfTypeToManagedReference(type);
|
||||||
property.serializedObject.Update();
|
}
|
||||||
property.managedReferenceValue = instance;
|
|
||||||
property.serializedObject.ApplyModifiedPropertiesWithoutUndo(); // undo is bugged for now
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool FilterTypeByFilters (IEnumerable<Func<Type,bool>> filters, Type type) =>
|
|
||||||
filters.All(f => f == null || f.Invoke(type));
|
|
||||||
|
|
||||||
|
private readonly struct GenericMenuParameterForAssignInstanceCommand
|
||||||
private readonly struct AssignInstanceGenericMenuParameter
|
|
||||||
{
|
{
|
||||||
public AssignInstanceGenericMenuParameter(Type type, SerializedProperty property)
|
public GenericMenuParameterForAssignInstanceCommand(Type type, SerializedProperty property)
|
||||||
{
|
{
|
||||||
Type = type;
|
Type = type;
|
||||||
Property = property;
|
Property = property;
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
/// This utility exists, because serialize reference managed reference typename returns combined string
|
|
||||||
/// and not data class that contains separate strings for assembly name and for class name (and possibly namespace name)
|
|
||||||
public static class SerializeReferenceTypeNameUtility
|
|
||||||
{
|
|
||||||
public static Type GetRealTypeFromTypename(string stringType)
|
|
||||||
{
|
|
||||||
var names = GetSplitNamesFromTypename(stringType);
|
|
||||||
var realType = Type.GetType($"{names.ClassName}, {names.AssemblyName}");
|
|
||||||
return realType;
|
|
||||||
}
|
|
||||||
public static (string AssemblyName, string ClassName) GetSplitNamesFromTypename(string typename)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(typename))
|
|
||||||
return ("","");
|
|
||||||
|
|
||||||
var typeSplitString = typename.Split(char.Parse(" "));
|
|
||||||
var typeClassName = typeSplitString[1];
|
|
||||||
var typeAssemblyName = typeSplitString[0];
|
|
||||||
return (typeAssemblyName, typeClassName);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
public static class SerializeReferenceTypeRestrictionFilters
|
public static class SerializeReferenceTypeRestrictionFilters
|
@ -20,7 +20,7 @@ public class SerializeReferenceButtonAttributeDrawer : PropertyDrawer
|
|||||||
var labelPosition = new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight);
|
var labelPosition = new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight);
|
||||||
EditorGUI.LabelField(labelPosition, label);
|
EditorGUI.LabelField(labelPosition, label);
|
||||||
|
|
||||||
var typeRestrictions = SerializedReferenceUIBuiltInTypeRestrictions.GetAllBuiltInTypeRestrictions(fieldInfo);
|
var typeRestrictions = SerializedReferenceUIDefaultTypeRestrictions.GetAllBuiltInTypeRestrictions(fieldInfo);
|
||||||
property.DrawSelectionButtonForManagedReference(position, typeRestrictions);
|
property.DrawSelectionButtonForManagedReference(position, typeRestrictions);
|
||||||
|
|
||||||
EditorGUI.PropertyField(position, property, GUIContent.none, true);
|
EditorGUI.PropertyField(position, property, GUIContent.none, true);
|
@ -15,7 +15,7 @@ public class SerializeReferenceMenuAttributeDrawer : PropertyDrawer
|
|||||||
{
|
{
|
||||||
EditorGUI.BeginProperty(position, label, property);
|
EditorGUI.BeginProperty(position, label, property);
|
||||||
|
|
||||||
var typeRestrictions = SerializedReferenceUIBuiltInTypeRestrictions.GetAllBuiltInTypeRestrictions(fieldInfo);
|
var typeRestrictions = SerializedReferenceUIDefaultTypeRestrictions.GetAllBuiltInTypeRestrictions(fieldInfo);
|
||||||
property.ShowContextMenuForManagedReferenceOnMouseMiddleButton(position, typeRestrictions);
|
property.ShowContextMenuForManagedReferenceOnMouseMiddleButton(position, typeRestrictions);
|
||||||
|
|
||||||
EditorGUI.PropertyField(position, property, true);
|
EditorGUI.PropertyField(position, property, true);
|
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 3fbe55d72b5fd59459fdb52e0f301ea1
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c0c77910f7962a14cb85132596cb8d24
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -2,7 +2,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
public static class SerializedReferenceUIBuiltInTypeRestrictions
|
public static class SerializedReferenceUIDefaultTypeRestrictions
|
||||||
{
|
{
|
||||||
public static IEnumerable<Func<Type, bool>> GetAllBuiltInTypeRestrictions(FieldInfo fieldInfo)
|
public static IEnumerable<Func<Type, bool>> GetAllBuiltInTypeRestrictions(FieldInfo fieldInfo)
|
||||||
{
|
{
|
@ -31,7 +31,7 @@ public static class SerializeReferenceInspectorButton
|
|||||||
GUI.backgroundColor = backgroundColor;
|
GUI.backgroundColor = backgroundColor;
|
||||||
|
|
||||||
|
|
||||||
var names = SerializeReferenceTypeNameUtility.GetSplitNamesFromTypename(property.managedReferenceFullTypename);
|
var names = ManagedReferenceUtility.GetSplitNamesFromTypename(property.managedReferenceFullTypename);
|
||||||
var className = string.IsNullOrEmpty(names.ClassName) ? "Null (Assign)" : names.ClassName;
|
var className = string.IsNullOrEmpty(names.ClassName) ? "Null (Assign)" : names.ClassName;
|
||||||
var assemblyName = names.AssemblyName;
|
var assemblyName = names.AssemblyName;
|
||||||
if (GUI.Button(buttonPosition, new GUIContent(className, className + " ( "+ assemblyName +" )" )))
|
if (GUI.Button(buttonPosition, new GUIContent(className, className + " ( "+ assemblyName +" )" )))
|
@ -165,25 +165,23 @@ MonoBehaviour:
|
|||||||
classWithChildReferences:
|
classWithChildReferences:
|
||||||
- integerValue: 0
|
- integerValue: 0
|
||||||
animals:
|
animals:
|
||||||
id: 0
|
|
||||||
animalInterfaces:
|
|
||||||
id: 6
|
id: 6
|
||||||
|
animalInterfaces:
|
||||||
|
id: 7
|
||||||
references:
|
references:
|
||||||
version: 1
|
version: 1
|
||||||
00000000:
|
00000000:
|
||||||
type: {class: BlackApe, ns: , asm: SerializedReferenceExample}
|
type: {class: GoldenApe, ns: , asm: SerializedReferenceExample}
|
||||||
data:
|
data:
|
||||||
age: 0
|
age: 1231
|
||||||
food: {fileID: 0}
|
food: {fileID: 1131539293}
|
||||||
numberOfBones: 0
|
numberOfBones: 33
|
||||||
Tag:
|
Tag: dd
|
||||||
00000001:
|
00000001:
|
||||||
type: {class: RedCat, ns: , asm: SerializedReferenceExample}
|
type: {class: AnimalChild, ns: , asm: AmimalWorld}
|
||||||
data:
|
data:
|
||||||
age: 0
|
age: 3213
|
||||||
food: {fileID: 0}
|
food: {fileID: 0}
|
||||||
numberOfBones: 0
|
|
||||||
Tag:
|
|
||||||
00000002:
|
00000002:
|
||||||
type: {class: , ns: , asm: }
|
type: {class: , ns: , asm: }
|
||||||
00000003:
|
00000003:
|
||||||
@ -208,6 +206,13 @@ MonoBehaviour:
|
|||||||
numberOfBones: 0
|
numberOfBones: 0
|
||||||
Tag:
|
Tag:
|
||||||
00000006:
|
00000006:
|
||||||
|
type: {class: BlackApe, ns: , asm: SerializedReferenceExample}
|
||||||
|
data:
|
||||||
|
age: 0
|
||||||
|
food: {fileID: 0}
|
||||||
|
numberOfBones: 0
|
||||||
|
Tag:
|
||||||
|
00000007:
|
||||||
type: {class: GreenFish, ns: , asm: SerializedReferenceExample}
|
type: {class: GreenFish, ns: , asm: SerializedReferenceExample}
|
||||||
data:
|
data:
|
||||||
age: 0
|
age: 0
|
Loading…
Reference in New Issue
Block a user