mirror of
https://github.com/DCFApixels/DragonECS-Unity.git
synced 2025-09-18 01:54:35 +08:00
323 lines
12 KiB
C#
323 lines
12 KiB
C#
using DCFApixels.DragonECS;
|
|
using System;
|
|
using UnityEngine;
|
|
|
|
namespace DCFApixels.DragonECS.Unity.Internal
|
|
{
|
|
internal sealed class ReferenceButtonAttribute : PropertyAttribute
|
|
{
|
|
public readonly Type[] predicateTypes;
|
|
public ReferenceButtonAttribute() : this(Array.Empty<Type>()) { }
|
|
public ReferenceButtonAttribute(params Type[] predicateTypes)
|
|
{
|
|
this.predicateTypes = predicateTypes;
|
|
Array.Sort(predicateTypes, (a, b) => string.Compare(a.AssemblyQualifiedName, b.AssemblyQualifiedName, StringComparison.Ordinal));
|
|
}
|
|
}
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
namespace DCFApixels.DragonECS.Unity.Editors
|
|
{
|
|
using DCFApixels.DragonECS.Unity.Internal;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using UnityEditor;
|
|
using UnityEditor.IMGUI.Controls;
|
|
using UnityObject = UnityEngine.Object;
|
|
|
|
[CustomPropertyDrawer(typeof(ReferenceButtonAttribute))]
|
|
internal sealed class ReferenceButtonAttributeDrawer : PropertyDrawer
|
|
{
|
|
private static bool _isInit;
|
|
|
|
private static Type[] _serializableTypes;
|
|
private static Dictionary<PredicateTypesKey, ReferenceDropDown> _predicatTypesMenus = new Dictionary<PredicateTypesKey, ReferenceDropDown>();
|
|
private ReferenceButtonAttribute TargetAttribute => (ReferenceButtonAttribute)attribute;
|
|
|
|
#region PredicateTypesKey
|
|
private readonly struct PredicateTypesKey : IEquatable<PredicateTypesKey>
|
|
{
|
|
public readonly Type[] types;
|
|
public PredicateTypesKey(Type[] types)
|
|
{
|
|
this.types = types;
|
|
}
|
|
public bool Equals(PredicateTypesKey other)
|
|
{
|
|
if (types.Length != other.types.Length) { return false; }
|
|
for (int i = 0; i < types.Length; i++)
|
|
{
|
|
if (types[i] != other.types[i])
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
public override bool Equals(object obj)
|
|
{
|
|
return obj is PredicateTypesKey key && Equals(key);
|
|
}
|
|
public override int GetHashCode()
|
|
{
|
|
return HashCode.Combine(types);
|
|
}
|
|
public static implicit operator PredicateTypesKey(Type[] types) { return new PredicateTypesKey(types); }
|
|
public static implicit operator Type[](PredicateTypesKey key) { return key.types; }
|
|
}
|
|
#endregion
|
|
|
|
#region ReferenceDropDown
|
|
private class ReferenceDropDown : AdvancedDropdown
|
|
{
|
|
public readonly Type[] PredicateTypes;
|
|
public ReferenceDropDown(Type[] predicateTypes) : base(new AdvancedDropdownState())
|
|
{
|
|
PredicateTypes = predicateTypes;
|
|
minimumSize = new Vector2(minimumSize.x, EditorGUIUtility.singleLineHeight * 30);
|
|
}
|
|
protected override AdvancedDropdownItem BuildRoot()
|
|
{
|
|
int increment = 0;
|
|
var root = new Item(null, "Select Type", increment++);
|
|
root.AddChild(new Item(null, "<NULL>", increment++));
|
|
|
|
Dictionary<Key, Item> dict = new Dictionary<Key, Item>();
|
|
|
|
foreach (var type in _serializableTypes)
|
|
{
|
|
bool isAssignable = false;
|
|
foreach (Type predicateTypes in PredicateTypes)
|
|
{
|
|
if (predicateTypes.IsAssignableFrom(type))
|
|
{
|
|
isAssignable = true;
|
|
break;
|
|
}
|
|
}
|
|
if (isAssignable)
|
|
{
|
|
ITypeMeta meta = type.ToMeta();
|
|
string description = meta.Description.Text;
|
|
MetaGroup group = meta.Group;
|
|
var splitedGroup = group.Splited;
|
|
|
|
Item parent = root;
|
|
if (splitedGroup.Count > 0)
|
|
{
|
|
int i = 1;
|
|
foreach (var subgroup in splitedGroup)
|
|
{
|
|
Key key = new Key(group, i);
|
|
if (dict.TryGetValue(key, out Item item) == false)
|
|
{
|
|
item = new Item(null, subgroup, increment++);
|
|
parent.AddChild(item);
|
|
dict.Add(key, item);
|
|
}
|
|
parent = item;
|
|
i++;
|
|
}
|
|
}
|
|
|
|
var leafItem = new Item(type, meta.Name, increment++);
|
|
parent.AddChild(leafItem);
|
|
}
|
|
}
|
|
return root;
|
|
}
|
|
|
|
protected override void ItemSelected(AdvancedDropdownItem item)
|
|
{
|
|
base.ItemSelected(item);
|
|
OnSelected((Item)item);
|
|
}
|
|
|
|
public event Action<Item> OnSelected = delegate { };
|
|
|
|
public class Item : AdvancedDropdownItem
|
|
{
|
|
public readonly Type Type;
|
|
public Item(Type type, string name, int id) : base(name)
|
|
{
|
|
Type = type;
|
|
this.id = id;
|
|
}
|
|
}
|
|
|
|
#region Key
|
|
private readonly struct Key : IEquatable<Key>
|
|
{
|
|
public readonly MetaGroup Group;
|
|
public readonly int Length;
|
|
public Key(MetaGroup group, int length)
|
|
{
|
|
Group = group;
|
|
Length = length;
|
|
}
|
|
public bool Equals(Key other)
|
|
{
|
|
if (Length != other.Length)
|
|
{
|
|
return false;
|
|
}
|
|
IEnumerator<string> splitedEnum = Group.Splited.GetEnumerator();
|
|
IEnumerator<string> splitedEnumOther = other.Group.Splited.GetEnumerator();
|
|
for (int i = 0; i < Length; i++)
|
|
{
|
|
splitedEnum.MoveNext();
|
|
splitedEnumOther.MoveNext();
|
|
if (splitedEnum.Current != splitedEnumOther.Current)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
public override bool Equals(object obj)
|
|
{
|
|
return obj is Key key && Equals(key);
|
|
}
|
|
public override int GetHashCode()
|
|
{
|
|
unchecked
|
|
{
|
|
int state = Length;
|
|
state ^= state << 13;
|
|
state ^= state >> 17;
|
|
state ^= state << 5;
|
|
var x = Group.Splited.GetEnumerator();
|
|
x.MoveNext();
|
|
return x.Current.GetHashCode() ^ state;
|
|
};
|
|
}
|
|
}
|
|
#endregion
|
|
}
|
|
#endregion
|
|
|
|
#region Init
|
|
private static void Init()
|
|
{
|
|
if (_isInit) { return; }
|
|
|
|
List<Type> types = new List<Type>();
|
|
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
|
{
|
|
var targetTypes = assembly.GetTypes().Where(type =>
|
|
(type.IsGenericType || type.IsAbstract || type.IsInterface) == false &&
|
|
type.IsSubclassOf(typeof(UnityObject)) == false &&
|
|
type.GetCustomAttribute<SerializableAttribute>() != null);
|
|
|
|
types.AddRange(targetTypes);
|
|
}
|
|
_serializableTypes = types.ToArray();
|
|
_isInit = true;
|
|
}
|
|
|
|
private static ReferenceDropDown GetReferenceDropDown(Type[] predicatTypes)
|
|
{
|
|
Init();
|
|
if (_predicatTypesMenus.TryGetValue(predicatTypes, out ReferenceDropDown menu) == false)
|
|
{
|
|
menu = new ReferenceDropDown(predicatTypes);
|
|
menu.OnSelected += SelectComponent;
|
|
_predicatTypesMenus.Add(predicatTypes, menu);
|
|
}
|
|
|
|
return menu;
|
|
}
|
|
|
|
[ThreadStatic]
|
|
private static SerializedProperty currentProperty;
|
|
private static void SelectComponent(ReferenceDropDown.Item item)
|
|
{
|
|
Type type = item.Type;
|
|
if (type == null)
|
|
{
|
|
currentProperty.managedReferenceValue = null;
|
|
}
|
|
else
|
|
{
|
|
currentProperty.managedReferenceValue = Activator.CreateInstance(type);
|
|
currentProperty.isExpanded = true;
|
|
}
|
|
|
|
currentProperty.serializedObject.ApplyModifiedProperties();
|
|
|
|
EcsGUI.Changed = true;
|
|
}
|
|
#endregion
|
|
|
|
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
|
{
|
|
if (property.managedReferenceValue != null)
|
|
{
|
|
return EditorGUI.GetPropertyHeight(property, label, true);
|
|
}
|
|
else
|
|
{
|
|
return EditorGUIUtility.singleLineHeight;
|
|
}
|
|
}
|
|
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
|
{
|
|
Rect selButtnoRect = position;
|
|
selButtnoRect.height = EditorGUIUtility.singleLineHeight;
|
|
DrawSelectionPopup(selButtnoRect, property, label);
|
|
|
|
if (property.managedReferenceValue != null)
|
|
{
|
|
EditorGUI.PropertyField(position, property, label, true);
|
|
}
|
|
else
|
|
{
|
|
EditorGUI.BeginProperty(position, label, property);
|
|
EditorGUI.LabelField(position, label);
|
|
EditorGUI.EndProperty();
|
|
}
|
|
}
|
|
|
|
private void DrawSelectionPopup(Rect position, SerializedProperty property, GUIContent label)
|
|
{
|
|
Rect buttonRect = RectUtility.AddPadding(position, EditorGUIUtility.labelWidth, 0f, 0f, 0f);
|
|
object obj = property.hasMultipleDifferentValues ? null : property.managedReferenceValue;
|
|
if (GUI.Button(buttonRect, obj == null ? "Select..." : obj.GetMeta().Name, EditorStyles.layerMaskField))
|
|
{
|
|
currentProperty = property;
|
|
if (TargetAttribute.predicateTypes.Length == 0)
|
|
{
|
|
GetReferenceDropDown(new Type[1] { fieldInfo.FieldType }).Show(buttonRect);
|
|
}
|
|
else
|
|
{
|
|
GetReferenceDropDown(TargetAttribute.predicateTypes).Show(buttonRect);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.SYSTEMS_GROUP)]
|
|
[System.Serializable] public class TestSystem0 : IEcsProcess { }
|
|
[System.Serializable] public class TestSystem1 : IEcsProcess { }
|
|
[System.Serializable] public class TestSystem2 : IEcsProcess { }
|
|
[System.Serializable] public class TestSystem3 : IEcsProcess { }
|
|
[MetaGroup(EcsConsts.PACK_GROUP)]
|
|
[System.Serializable] public class TestSystem4 : IEcsProcess { }
|
|
[MetaGroup(EcsConsts.PACK_GROUP)]
|
|
[System.Serializable] public class TestSystem7 : IEcsProcess { }
|
|
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.AUTHOR)]
|
|
[System.Serializable] public class TestSystem8 : IEcsProcess { }
|
|
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.AUTHOR)]
|
|
[System.Serializable] public class _TestSystemX : IEcsProcess { }
|
|
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.AUTHOR)]
|
|
[System.Serializable] public class TestSystem9 : IEcsProcess { }
|
|
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.AUTHOR)]
|
|
[System.Serializable] public class TestSystem5 : IEcsProcess { }
|
|
[System.Serializable] public class TestSystem6 : IEcsProcess { } |