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/
[Mm]emoryCaptures/
.[Ii]dea/
[Pp]rojectSettings/
[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();
}
private static void FillContextMenu(IEnumerable<Func<Type, bool>> enumerableFilters, GenericMenu contextMenu, SerializedProperty property)
{
var filters = enumerableFilters.ToList();// Prevents possible multiple enumerations
// 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;
}
// Collects appropriate types
var appropriateTypes = property.GetAppropriateTypesForAssigningToManagedReference(filters);
// Get and filter all appropriate types
var types = TypeCache.GetTypesDerivedFrom(realPropertyType);
foreach (var type in types)
{
// 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
// Adds appropriate types to menu
foreach (var appropriateType in appropriateTypes)
AddItemToContextMenu(appropriateType, contextMenu, property);
}
private static void AddItemToContextMenu(Type type, GenericMenu genericMenuContext, SerializedProperty property)
{
var assemblyName = type.Assembly.ToString().Split('(', ',')[0];
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 property = parameter.Property;
var instance = Activator.CreateInstance(type);
property.serializedObject.Update();
property.managedReferenceValue = instance;
property.serializedObject.ApplyModifiedPropertiesWithoutUndo(); // undo is bugged for now
property.AssignNewInstanceOfTypeToManagedReference(type);
}
private static bool FilterTypeByFilters (IEnumerable<Func<Type,bool>> filters, Type type) =>
filters.All(f => f == null || f.Invoke(type));
private readonly struct AssignInstanceGenericMenuParameter
private readonly struct GenericMenuParameterForAssignInstanceCommand
{
public AssignInstanceGenericMenuParameter(Type type, SerializedProperty property)
public GenericMenuParameterForAssignInstanceCommand(Type type, SerializedProperty property)
{
Type = type;
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

@ -1,4 +1,4 @@
using System;
 using System;
using System.Linq;
public static class SerializeReferenceTypeRestrictionFilters

View File

@ -20,7 +20,7 @@ public class SerializeReferenceButtonAttributeDrawer : PropertyDrawer
var labelPosition = new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight);
EditorGUI.LabelField(labelPosition, label);
var typeRestrictions = SerializedReferenceUIBuiltInTypeRestrictions.GetAllBuiltInTypeRestrictions(fieldInfo);
var typeRestrictions = SerializedReferenceUIDefaultTypeRestrictions.GetAllBuiltInTypeRestrictions(fieldInfo);
property.DrawSelectionButtonForManagedReference(position, typeRestrictions);
EditorGUI.PropertyField(position, property, GUIContent.none, true);

View File

@ -15,7 +15,7 @@ public class SerializeReferenceMenuAttributeDrawer : PropertyDrawer
{
EditorGUI.BeginProperty(position, label, property);
var typeRestrictions = SerializedReferenceUIBuiltInTypeRestrictions.GetAllBuiltInTypeRestrictions(fieldInfo);
var typeRestrictions = SerializedReferenceUIDefaultTypeRestrictions.GetAllBuiltInTypeRestrictions(fieldInfo);
property.ShowContextMenuForManagedReferenceOnMouseMiddleButton(position, typeRestrictions);
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.Reflection;
public static class SerializedReferenceUIBuiltInTypeRestrictions
public static class SerializedReferenceUIDefaultTypeRestrictions
{
public static IEnumerable<Func<Type, bool>> GetAllBuiltInTypeRestrictions(FieldInfo fieldInfo)
{

View File

@ -31,7 +31,7 @@ public static class SerializeReferenceInspectorButton
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 assemblyName = names.AssemblyName;
if (GUI.Button(buttonPosition, new GUIContent(className, className + " ( "+ assemblyName +" )" )))

View File

@ -165,25 +165,23 @@ MonoBehaviour:
classWithChildReferences:
- integerValue: 0
animals:
id: 0
animalInterfaces:
id: 6
animalInterfaces:
id: 7
references:
version: 1
00000000:
type: {class: BlackApe, ns: , asm: SerializedReferenceExample}
type: {class: GoldenApe, ns: , asm: SerializedReferenceExample}
data:
age: 0
food: {fileID: 0}
numberOfBones: 0
Tag:
age: 1231
food: {fileID: 1131539293}
numberOfBones: 33
Tag: dd
00000001:
type: {class: RedCat, ns: , asm: SerializedReferenceExample}
type: {class: AnimalChild, ns: , asm: AmimalWorld}
data:
age: 0
age: 3213
food: {fileID: 0}
numberOfBones: 0
Tag:
00000002:
type: {class: , ns: , asm: }
00000003:
@ -208,6 +206,13 @@ MonoBehaviour:
numberOfBones: 0
Tag:
00000006:
type: {class: BlackApe, ns: , asm: SerializedReferenceExample}
data:
age: 0
food: {fileID: 0}
numberOfBones: 0
Tag:
00000007:
type: {class: GreenFish, ns: , asm: SerializedReferenceExample}
data:
age: 0