diff --git a/DragonECS-Unity.asmdef b/DragonECS-Unity.asmdef index eae9305..8e534db 100644 --- a/DragonECS-Unity.asmdef +++ b/DragonECS-Unity.asmdef @@ -6,7 +6,7 @@ ], "includePlatforms": [], "excludePlatforms": [], - "allowUnsafeCode": false, + "allowUnsafeCode": true, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, diff --git a/src/EcsPipelineTemplate/EcsPipelineTemplateSO.cs b/src/EcsPipelineTemplate/EcsPipelineTemplateSO.cs index 8dd3d06..b713dbc 100644 --- a/src/EcsPipelineTemplate/EcsPipelineTemplateSO.cs +++ b/src/EcsPipelineTemplate/EcsPipelineTemplateSO.cs @@ -24,11 +24,6 @@ namespace DCFApixels.DragonECS [SerializeField] private Record[] _systems; - [SerializeField] - [SerializeReference] - [ReferenceButton] - private IEcsModule[] _modules; - void IEcsModule.Import(EcsPipeline.Builder b) { b.Layers.MergeWith(_layers); @@ -123,7 +118,7 @@ namespace DCFApixels.DragonECS public struct Record { [SerializeReference] - [ReferenceButton] + [ReferenceButton(typeof(IEcsModule), typeof(IEcsProcess))] public object target; public AddParams parameters; public Record(object target, AddParams parameters) diff --git a/src/EcsPipelineTemplate/ReferenceButtonAttribute.cs b/src/EcsPipelineTemplate/ReferenceButtonAttribute.cs index 1819606..d032712 100644 --- a/src/EcsPipelineTemplate/ReferenceButtonAttribute.cs +++ b/src/EcsPipelineTemplate/ReferenceButtonAttribute.cs @@ -1,12 +1,21 @@ using DCFApixels.DragonECS; +using System; using UnityEngine; namespace DCFApixels.DragonECS.Unity.Internal { - internal sealed class ReferenceButtonAttribute : PropertyAttribute { } + internal sealed class ReferenceButtonAttribute : PropertyAttribute + { + public readonly Type[] predicateTypes; + public ReferenceButtonAttribute() : this(Array.Empty()) { } + 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 { @@ -25,15 +34,48 @@ namespace DCFApixels.DragonECS.Unity.Editors private static bool _isInit; private static Type[] _serializableTypes; - private static Dictionary _predicatTypesMenus = new Dictionary(); + private static Dictionary _predicatTypesMenus = new Dictionary(); + private ReferenceButtonAttribute TargetAttribute => (ReferenceButtonAttribute)attribute; + + #region PredicateTypesKey + private readonly struct PredicateTypesKey : IEquatable + { + 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 private class ReferenceDropDown : AdvancedDropdown { - public readonly Type PredicateType; - public ReferenceDropDown(Type predicateType) : base(new AdvancedDropdownState()) + public readonly Type[] PredicateTypes; + public ReferenceDropDown(Type[] predicateTypes) : base(new AdvancedDropdownState()) { - PredicateType = predicateType; - + PredicateTypes = predicateTypes; minimumSize = new Vector2(minimumSize.x, EditorGUIUtility.singleLineHeight * 30); } protected override AdvancedDropdownItem BuildRoot() @@ -46,7 +88,16 @@ namespace DCFApixels.DragonECS.Unity.Editors foreach (var type in _serializableTypes) { - if (PredicateType.IsAssignableFrom(type)) + bool isAssignable = false; + foreach (Type predicateTypes in PredicateTypes) + { + if (predicateTypes.IsAssignableFrom(type)) + { + isAssignable = true; + break; + } + } + if (isAssignable) { ITypeMeta meta = type.ToMeta(); string name = meta.Name; @@ -208,14 +259,14 @@ namespace DCFApixels.DragonECS.Unity.Editors _isInit = true; } - private static ReferenceDropDown GetReferenceDropDown(Type predicatType) + private static ReferenceDropDown GetReferenceDropDown(Type[] predicatTypes) { Init(); - if (_predicatTypesMenus.TryGetValue(predicatType, out ReferenceDropDown menu) == false) + if (_predicatTypesMenus.TryGetValue(predicatTypes, out ReferenceDropDown menu) == false) { - menu = new ReferenceDropDown(predicatType); + menu = new ReferenceDropDown(predicatTypes); menu.OnSelected += SelectComponent; - _predicatTypesMenus.Add(predicatType, menu); + _predicatTypesMenus.Add(predicatTypes, menu); } return menu; @@ -276,7 +327,14 @@ namespace DCFApixels.DragonECS.Unity.Editors if (GUI.Button(buttonRect, obj == null ? "Select..." : obj.GetMeta().Name, EditorStyles.layerMaskField)) { currentProperty = property; - GetReferenceDropDown(fieldInfo.FieldType).Show(buttonRect); + if (TargetAttribute.predicateTypes.Length == 0) + { + GetReferenceDropDown(new Type[1] { fieldInfo.FieldType }).Show(buttonRect); + } + else + { + GetReferenceDropDown(TargetAttribute.predicateTypes).Show(buttonRect); + } } } } diff --git a/src/Editor.meta b/src/Editor.meta new file mode 100644 index 0000000..661ce2f --- /dev/null +++ b/src/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 21a9b666ca8f69a45a40d9621424e8f4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Editor/AddParamsDrawer.cs b/src/Editor/AddParamsDrawer.cs new file mode 100644 index 0000000..3239760 --- /dev/null +++ b/src/Editor/AddParamsDrawer.cs @@ -0,0 +1,91 @@ +#if UNITY_EDITOR +using DCFApixels.DragonECS.Unity.Internal; +using UnityEditor; +using UnityEngine; + +namespace DCFApixels.DragonECS.Unity.Editors +{ + [CustomPropertyDrawer(typeof(AddParams))] + internal class AddParamsDrawer : PropertyDrawer + { + private float SingleLineHeight => EditorGUIUtility.singleLineHeight; + private float Spacing => EditorGUIUtility.standardVerticalSpacing; + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + return !property.isExpanded ? EditorGUIUtility.singleLineHeight + Spacing : EditorGUIUtility.singleLineHeight * 4f + Spacing * 3f; + } + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + var flagsProp = property.FindPropertyRelative("flags"); + + AddParamsFlags flags = (AddParamsFlags)flagsProp.enumValueFlag; + + var (foldoutRect, contentRect) = position.VerticalSliceTop(SingleLineHeight + Spacing); + + var (fieldsRects, checkboxRects) = contentRect.HorizontalSliceRight(SingleLineHeight); + + + property.isExpanded = EditorGUI.Foldout(foldoutRect, property.isExpanded, label); + //property.isExpanded = true; + using (EcsGUI.UpIndentLevel()) + { + + EditorGUI.BeginChangeCheck(); + + checkboxRects = checkboxRects.Move(EditorGUIUtility.standardVerticalSpacing, 0); + + Rect checkboxRect = checkboxRects; + checkboxRect.height = SingleLineHeight; + Rect fieldRect = fieldsRects; + fieldRect.height = SingleLineHeight; + + //LayerName + property.Next(true); + using (EcsGUI.SetIndentLevel(0)) + { + flags = flags.SetOverwriteLayerName(EditorGUI.Toggle(checkboxRect, flags.IsOverwriteLayerName())); + } + using (EcsGUI.SetEnable(flags.IsOverwriteLayerName())) + { + EditorGUI.PropertyField(fieldRect, property, UnityEditorUtility.GetLabel(property.displayName), true); + } + + checkboxRect = checkboxRect.Move(0, SingleLineHeight + Spacing); + fieldRect = fieldRect.Move(0, SingleLineHeight + Spacing); + + //SortOrder + property.Next(false); + using (EcsGUI.SetIndentLevel(0)) + { + flags = flags.SetOverwriteSortOrder(EditorGUI.Toggle(checkboxRect, flags.IsOverwriteSortOrder())); + } + using (EcsGUI.SetEnable(flags.IsOverwriteSortOrder())) + { + EditorGUI.PropertyField(fieldRect, property, UnityEditorUtility.GetLabel(property.displayName), true); + } + + checkboxRect = checkboxRect.Move(0, SingleLineHeight + Spacing); + fieldRect = fieldRect.Move(0, SingleLineHeight + Spacing); + + //IsUnique + property.Next(false); + using (EcsGUI.SetIndentLevel(0)) + { + flags = flags.SetOverwriteIsUnique(EditorGUI.Toggle(checkboxRect, flags.IsOverwriteIsUnique())); + } + using (EcsGUI.SetEnable(flags.IsOverwriteIsUnique())) + { + EditorGUI.PropertyField(fieldRect, property, UnityEditorUtility.GetLabel(property.displayName), true); + } + + if (EditorGUI.EndChangeCheck()) + { + flagsProp.enumValueFlag = (int)flags; + property.serializedObject.ApplyModifiedProperties(); + } + + } + } + } +} +#endif diff --git a/src/Editor/AddParamsDrawer.cs.meta b/src/Editor/AddParamsDrawer.cs.meta new file mode 100644 index 0000000..e1b3592 --- /dev/null +++ b/src/Editor/AddParamsDrawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1907bf7d859547d438973057c64e9656 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Internal/Editor/EcsGUI.cs b/src/Internal/Editor/EcsGUI.cs index 2efe5a0..d106947 100644 --- a/src/Internal/Editor/EcsGUI.cs +++ b/src/Internal/Editor/EcsGUI.cs @@ -125,6 +125,7 @@ namespace DCFApixels.DragonECS.Unity.Editors public static AlignmentScope SetAlignment(GUIStyle target, TextAnchor value) => new AlignmentScope(target, value); public static AlignmentScope SetAlignment(GUIStyle target) => new AlignmentScope(target); public static IndentLevelScope SetIndentLevel(int level) => new IndentLevelScope(level); + public static IndentLevelScope UpIndentLevel() => new IndentLevelScope(EditorGUI.indentLevel + 1); public static ContentColorScope SetContentColor(Color value) => new ContentColorScope(value); public static ContentColorScope SetContentColor(float r, float g, float b, float a = 1f) => new ContentColorScope(r, g, b, a); public static BackgroundColorScope SetBackgroundColor(Color value) => new BackgroundColorScope(value); diff --git a/src/Internal/Utils/RectUtility.cs b/src/Internal/Utils/RectUtility.cs index 789e2a6..1d573f3 100644 --- a/src/Internal/Utils/RectUtility.cs +++ b/src/Internal/Utils/RectUtility.cs @@ -1,4 +1,6 @@ -using UnityEngine; +using System.Runtime.CompilerServices; +using UnityEditor; +using UnityEngine; namespace DCFApixels.DragonECS.Unity.Internal { @@ -46,6 +48,36 @@ namespace DCFApixels.DragonECS.Unity.Internal return (t, b); } + #region DebugRect + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static unsafe float AsFloat(uint value) => *(float*)&value; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static float Q32ToFloat(uint value) => AsFloat((value >> 9) | 0x3F80_0000) - 1f; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint NextXorShiftState(uint state) + { + unchecked + { + state ^= state << 13; + state ^= state >> 17; + state ^= state << 5; + return state; + }; + } + public static void DebugRect_Editor(params Rect[] rects) + { + uint colorState = NextXorShiftState(3136587146); + foreach (var rect in rects) + { + colorState = NextXorShiftState(colorState); + Color color = Color.HSVToRGB(Q32ToFloat(colorState), 1, 1); + color.a = 0.3f; + GUI.Box(rect, "", EditorStyles.selectionRect); + EditorGUI.DrawRect(rect, color); + } + } + #endregion + public static Rect AddPadding(in this Rect rect, float verticalHorizontal) { return AddPadding(rect, verticalHorizontal, verticalHorizontal, verticalHorizontal, verticalHorizontal);