Merge pull request #2 from TextusGames/Development

Ready to push new Major version
This commit is contained in:
TextusGames 2020-05-16 20:19:18 +03:00 committed by GitHub
commit ae197c1a9b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
66 changed files with 149 additions and 88 deletions

1
.gitignore vendored
View File

@ -11,6 +11,7 @@
[Ll]ogs/ [Ll]ogs/
[Mm]emoryCaptures/ [Mm]emoryCaptures/
.[Ii]dea/
[Pp]rojectSettings/ [Pp]rojectSettings/
[Pp]ackages/ [Pp]ackages/

View File

@ -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

View File

@ -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 // Collects appropriate types
var realPropertyType = SerializeReferenceTypeNameUtility.GetRealTypeFromTypename(property.managedReferenceFieldTypename); var appropriateTypes = property.GetAppropriateTypesForAssigningToManagedReference(filters);
if (realPropertyType == null)
{
Debug.LogError("Can not get type from");
return;
}
// Get and filter all appropriate types // Adds appropriate types to menu
var types = TypeCache.GetTypesDerivedFrom(realPropertyType); foreach (var appropriateType in appropriateTypes)
foreach (var type in types) AddItemToContextMenu(appropriateType, contextMenu, property);
{
// Skips unity engine Objects (because they are not serialized by SerializeReference)
if(type.IsSubclassOf(typeof(UnityEngine.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 (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) => private readonly struct GenericMenuParameterForAssignInstanceCommand
filters.All(f => f == null || f.Invoke(type));
private readonly struct AssignInstanceGenericMenuParameter
{ {
public AssignInstanceGenericMenuParameter(Type type, SerializedProperty property) public GenericMenuParameterForAssignInstanceCommand(Type type, SerializedProperty property)
{ {
Type = type; Type = type;
Property = property; Property = property;

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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);

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3fbe55d72b5fd59459fdb52e0f301ea1
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c0c77910f7962a14cb85132596cb8d24
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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)
{ {

View File

@ -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 +" )" )))

View File

@ -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