This commit is contained in:
Mikhail 2024-06-30 01:12:21 +08:00
parent 250b6b275f
commit 0fd029f711
5 changed files with 419 additions and 12 deletions

View File

@ -1,4 +1,7 @@
using System;
using DCFApixels.DragonECS.Unity.Internal;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace DCFApixels.DragonECS
@ -6,8 +9,26 @@ namespace DCFApixels.DragonECS
[CreateAssetMenu(fileName = nameof(EcsPipelineTemplateSO), menuName = EcsConsts.FRAMEWORK_NAME + "/" + nameof(EcsPipelineTemplateSO), order = 1)]
public class EcsPipelineTemplateSO : ScriptableObject, IEcsModule
{
private string[] _layers;
private static string[] _defaultLayers = new string[]
{
EcsConsts.PRE_BEGIN_LAYER,
EcsConsts.BEGIN_LAYER,
EcsConsts.BASIC_LAYER,
EcsConsts.END_LAYER,
EcsConsts.POST_END_LAYER,
};
[SerializeField]
private string[] _layers = _defaultLayers.ToArray();
[SerializeField]
private SystemRecord[] _systems;
[SerializeField]
[SerializeReference]
[ReferenceButton]
private IEcsModule[] _modules;
void IEcsModule.Import(EcsPipeline.Builder b)
{
b.Layers.MergeWith(_layers);
@ -53,9 +74,64 @@ namespace DCFApixels.DragonECS
}
}
public void Validate()
{
ValidateLayers();
ValidateSystems();
}
private void ValidateLayers()
{
Dictionary<string, int> builtinLayerIndexes = new Dictionary<string, int>();
foreach (var item in _defaultLayers)
{
builtinLayerIndexes.Add(item, -1);
}
List<string> newLayers = _layers.Distinct().ToList();
for (int i = 0; i < newLayers.Count; i++)
{
var layer = newLayers[i];
if (builtinLayerIndexes.ContainsKey(layer))
{
builtinLayerIndexes[layer] = i;
}
}
int lastNewLayersCount = newLayers.Count;
foreach (var pair in builtinLayerIndexes)
{
if(pair.Value < 0)
{
newLayers.Add(pair.Key);
}
}
for (int i = lastNewLayersCount; i < newLayers.Count; i++)
{
builtinLayerIndexes[newLayers[i]] = i;
}
{
int i = 0;
foreach (var pair in builtinLayerIndexes.OrderBy(o => o.Value))
{
newLayers[pair.Value] = _defaultLayers[i];
i++;
}
}
_layers = newLayers.ToArray();
}
private void ValidateSystems()
{
}
[Serializable]
public struct SystemRecord
{
[SerializeReference]
[ReferenceButton]
public IEcsProcess system;
public string layer;
public int sortOrder;

View File

@ -1,13 +1,33 @@
#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;
using UnityEngine;
namespace DCFApixels.DragonECS.Unity.Editors
{
//[CustomEditor(typeof(EcsPipelineTemplateSO))]
//internal class EcsPipelineTemplateSOEditor
//{
//
//}
[CustomEditor(typeof(EcsPipelineTemplateSO))]
internal class EcsPipelineTemplateSOEditor : Editor
{
public override void OnInspectorGUI()
{
EditorGUI.BeginChangeCheck();
base.OnInspectorGUI();
if (EditorGUI.EndChangeCheck())
{
Validate();
}
if (GUILayout.Button("Validate"))
{
Validate();
}
}
private void Validate()
{
foreach (var target in targets)
{
((EcsPipelineTemplateSO)target).Validate();
}
}
}
}
#endif

View File

@ -0,0 +1,304 @@
using DCFApixels.DragonECS;
using UnityEngine;
namespace DCFApixels.DragonECS.Unity.Internal
{
internal sealed class ReferenceButtonAttribute : PropertyAttribute { }
}
#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<Type, ReferenceDropDown> _predicatTypesMenus = new Dictionary<Type, ReferenceDropDown>();
private class ReferenceDropDown : AdvancedDropdown
{
public readonly Type PredicateType;
public ReferenceDropDown(Type predicateType) : base(new AdvancedDropdownState())
{
PredicateType = predicateType;
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)
{
if (PredicateType.IsAssignableFrom(type))
{
ITypeMeta meta = type.ToMeta();
string name = meta.Name;
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, 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 = 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;
};
}
}
//private readonly struct Key : IEquatable<Key>
//{
// public readonly string FullName;
// public readonly int Length;
// public Key(string fullName, int length)
// {
// FullName = fullName;
// Length = length;
// }
// public bool Equals(Key other)
// {
// if (Length != other.Length)
// {
// return false;
// }
// for (int i = 0; i < Length; i++)
// {
// if (FullName[i] != other.FullName[i])
// {
// 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;
// return FullName.GetHashCode() ^ state;
// };
// }
//}
#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 predicatType)
{
Init();
if (_predicatTypesMenus.TryGetValue(predicatType, out ReferenceDropDown menu) == false)
{
menu = new ReferenceDropDown(predicatType);
menu.OnSelected += SelectComponent;
_predicatTypesMenus.Add(predicatType, 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();
}
#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;
GetReferenceDropDown(fieldInfo.FieldType).Show(buttonRect);
}
}
}
}
#endif
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.SYSTEMS_GROUP)]
[System.Serializable] public class TestSystem0 : IEcsProcess { }
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.SYSTEMS_GROUP)]
[System.Serializable] public class TestSystem1 : IEcsProcess { }
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.SYSTEMS_GROUP)]
[System.Serializable] public class TestSystem2 : IEcsProcess { }
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.SYSTEMS_GROUP)]
[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)]
[System.Serializable] public class TestSystem8 : IEcsProcess { }
[System.Serializable] public class _TestSystemX : IEcsProcess { }
[System.Serializable] public class TestSystem9 : IEcsProcess { }
[System.Serializable] public class TestSystem5 : IEcsProcess { }
[System.Serializable] public class TestSystem6 : IEcsProcess { }

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 999d5f8fb88eafc44b8a88406eb3ec39
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -61,10 +61,6 @@ namespace DCFApixels.DragonECS.Unity.Editors
name = group.Name + name;
}
if (string.IsNullOrEmpty(description) == false)
{
name = $"{name} [i]";
}
_genericMenu.AddItem(new GUIContent(name, description), false, SelectComponent, dummy);
}