From 62d71d2a219fa917c3a172650aff990ef39b0460 Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Fri, 27 Sep 2024 22:04:00 +0800 Subject: [PATCH] impl script finding using meta id --- src/Connectors/GameObjectConnect.cs | 1 + src/DebugUtils/Editor/SettingsEditor.cs | 1 - src/DragonDocs/Editors/DragonDocsWindow.cs | 2 +- src/Editor/MonoScriptsAssetProcessor.cs | 89 ++++++ src/Editor/MonoScriptsAssetProcessor.cs.meta | 11 + src/Editor/ScriptsCache.cs | 302 ++++++++++++++++++ src/Editor/ScriptsCache.cs.meta | 11 + src/Internal/Editor/EcsGUI.cs | 34 +- src/Internal/Editor/ExtendedEditor.cs | 11 + src/Internal/Utils/RectUtility.cs | 2 + .../Editor/EcsPipelineTemplateSOEditor.cs | 19 +- .../Editor/ComponentTemplatePropertyDrawer.cs | 2 +- .../Editor/EntityTemplateEditor.cs | 172 ++++++++-- .../Templates/MonoEntityTemplate.cs | 3 +- .../Templates/ScriptableEntityTemplate.cs | 1 + 15 files changed, 605 insertions(+), 56 deletions(-) create mode 100644 src/Editor/MonoScriptsAssetProcessor.cs create mode 100644 src/Editor/MonoScriptsAssetProcessor.cs.meta create mode 100644 src/Editor/ScriptsCache.cs create mode 100644 src/Editor/ScriptsCache.cs.meta diff --git a/src/Connectors/GameObjectConnect.cs b/src/Connectors/GameObjectConnect.cs index 03976b9..c768a8c 100644 --- a/src/Connectors/GameObjectConnect.cs +++ b/src/Connectors/GameObjectConnect.cs @@ -8,6 +8,7 @@ using UnityEditor; namespace DCFApixels.DragonECS { [MetaColor(MetaColor.DragonCyan)] + [MetaID("14AC6B239201C6A60337AF3384D237E7")] [MetaGroup(EcsUnityConsts.PACK_GROUP, EcsConsts.COMPONENTS_GROUP)] [MetaDescription(EcsConsts.AUTHOR, "This component is automatically added if an entity is connected to one of the EcsEntityConnect. It also contains a reference to the connected EcsEntityConnect.")] public readonly struct GameObjectConnect : IEcsComponent, IEcsComponentLifecycle diff --git a/src/DebugUtils/Editor/SettingsEditor.cs b/src/DebugUtils/Editor/SettingsEditor.cs index 619b127..8834948 100644 --- a/src/DebugUtils/Editor/SettingsEditor.cs +++ b/src/DebugUtils/Editor/SettingsEditor.cs @@ -1,5 +1,4 @@ #if UNITY_EDITOR -using System.Collections.Generic; using System.Linq; using System.Reflection; using UnityEditor; diff --git a/src/DragonDocs/Editors/DragonDocsWindow.cs b/src/DragonDocs/Editors/DragonDocsWindow.cs index 2d2eb2b..9635b3e 100644 --- a/src/DragonDocs/Editors/DragonDocsWindow.cs +++ b/src/DragonDocs/Editors/DragonDocsWindow.cs @@ -254,7 +254,7 @@ namespace DCFApixels.DragonECS.Unity.Docs.Editors using (EcsGUI.Layout.BeginHorizontal()) { GUILayout.TextArea(IsUseCustomNames ? meta.Name : meta.TypeName, EditorStyles.boldLabel, GUILayout.ExpandWidth(false)); - if (meta.TryGetSourceType(out System.Type targetType) && UnityEditorUtility.TryGetScriptAsset(targetType, out MonoScript script)) + if (meta.TryGetSourceType(out System.Type targetType) && ScriptsCache.TryGetScriptAsset(targetType, out MonoScript script)) { EcsGUI.Layout.ScriptAssetButton(script, GUILayout.Width(19f)); } diff --git a/src/Editor/MonoScriptsAssetProcessor.cs b/src/Editor/MonoScriptsAssetProcessor.cs new file mode 100644 index 0000000..5d9d094 --- /dev/null +++ b/src/Editor/MonoScriptsAssetProcessor.cs @@ -0,0 +1,89 @@ +#if UNITY_EDITOR +using System; +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; + +namespace DCFApixels.DragonECS.Unity.Editors +{ + internal class MonoScriptsAssetProcessor : AssetPostprocessor + { + private static long _version; + public static long Version { get { return _version; } } + private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths, bool didDomainReload) + { + _removedScriptGuids.Clear(); + _newScriptIDs.Clear(); + + foreach (string str in importedAssets) + { + Debug.Log("Reimported Asset: " + str); + ProcessAssetPath(str); + } + foreach (string str in deletedAssets) + { + Debug.Log("Deleted Asset: " + str); + RemoveAssetPath(str); + } + + for (int i = 0; i < movedAssets.Length; i++) + { + Debug.Log("Moved Asset: " + movedAssets[i] + " from: " + movedFromAssetPaths[i]); + RemoveAssetPath(movedFromAssetPaths[i]); + ProcessAssetPath(movedAssets[i]); + } + + if (didDomainReload) + { + Debug.Log("Domain has been reloaded"); + } + + foreach (var item in _removedScriptGuids) + { + Debug.Log(item); + } + foreach (var item in _newScriptIDs) + { + Debug.Log(item); + } + _version = DateTime.Now.Ticks; + } + + + private static List _removedScriptGuids = new List(); + private static List _newScriptIDs = new List(); + public static IReadOnlyCollection RemovedScriptPaths + { + get { return _removedScriptGuids; } + } + public static IReadOnlyCollection NewScriptPaths + { + get { return _newScriptIDs; } + } + + private static void RemoveAssetPath(string filePath) + { + if (IsScript(filePath) == false) { return; } + Debug.Log("RemoveAssetPath: " + filePath); + _removedScriptGuids.Add(filePath); + } + + private static void ProcessAssetPath(string filePath) + { + if (IsScript(filePath) == false) { return; } + Debug.Log("ProcessAssetPath: " + filePath); + + var script = AssetDatabase.LoadAssetAtPath(filePath).text; + _newScriptIDs.Add(filePath); + } + + private static bool IsScript(string filePath) + { + int i = filePath.Length - 3; + return filePath[i++] == '.' + && filePath[i++] == 'c' + && filePath[i++] == 's'; + } + } +} +#endif \ No newline at end of file diff --git a/src/Editor/MonoScriptsAssetProcessor.cs.meta b/src/Editor/MonoScriptsAssetProcessor.cs.meta new file mode 100644 index 0000000..7d66a80 --- /dev/null +++ b/src/Editor/MonoScriptsAssetProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 04572469768b4844aa9865ae16d3f18b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Editor/ScriptsCache.cs b/src/Editor/ScriptsCache.cs new file mode 100644 index 0000000..f8208cc --- /dev/null +++ b/src/Editor/ScriptsCache.cs @@ -0,0 +1,302 @@ +#if UNITY_EDITOR +using DCFApixels.DragonECS.Unity.Internal; +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using UnityEditor; +using UnityEngine; + +namespace DCFApixels.DragonECS.Unity.Editors +{ + [FilePath(EcsUnityConsts.LOCAL_CACHE_FOLDER + "/" + nameof(ScriptsCache) + ".prefs", FilePathAttribute.Location.ProjectFolder)] + internal class ScriptsCache : ScriptableSingleton, ISerializationCallbackReceiver + { + [SerializeField] + private bool _isInit = false; + [SerializeField] + private long _version; + + #region [SerializeField] + [SerializeField] + private Pair[] _serializableMetaIDScriptPathPairs; + [Serializable] + private struct Pair + { + public string metaID; + public string scriptPath; + + public Pair(string metaID, string scriptPath) + { + this.metaID = metaID; + this.scriptPath = scriptPath; + } + } + #endregion + private static Dictionary _metaIDScriptPathPairs = new Dictionary(); + + private static SparseArray _scriptsAssets = new SparseArray(256); + + #region Init/Update + private void InitUpdate() + { + Init(); + + if (MonoScriptsAssetProcessor.Version <= _version) { return; } + + if (MonoScriptsAssetProcessor.RemovedScriptPaths.Count > 0) + { + uint pathsLength = (uint)MonoScriptsAssetProcessor.RemovedScriptPaths.Count; + string[] paths = new string[pathsLength]; + int i = 0; + foreach (var path in MonoScriptsAssetProcessor.RemovedScriptPaths) + { + paths[i++] = path; + } + foreach (var metaIDScriptPathPair in _metaIDScriptPathPairs) + { + for (uint j = 0; j < pathsLength; j++) + { + if (paths[j] == metaIDScriptPathPair.Value) + { + _metaIDScriptPathPairs[metaIDScriptPathPair.Key] = null; + } + } + } + } + + List metaIDs = new List(); + foreach (var assetPath in MonoScriptsAssetProcessor.NewScriptPaths) + { + ExtractMetaIDs(AssetDatabase.LoadAssetAtPath(assetPath).text, metaIDs); + foreach (var metaID in metaIDs) + { + _metaIDScriptPathPairs[metaID] = assetPath; + } + } + _version = MonoScriptsAssetProcessor.Version; + + Save(true); + } + private void Init() + { + if (_isInit) { return; } + _metaIDScriptPathPairs.Clear(); + var scriptGuids = AssetDatabase.FindAssets($"* t:MonoScript"); + + List metaIDsBuffer = new List(); + + foreach (var guid in scriptGuids) + { + string scriptPath = AssetDatabase.GUIDToAssetPath(guid); + string script = AssetDatabase.LoadAssetAtPath(scriptPath).text; + + if (scriptPath.EndsWith("MetaIDAttribute.cs") == false) + { + ExtractMetaIDs(script, metaIDsBuffer); + } + + foreach (var metaID in metaIDsBuffer) + { + _metaIDScriptPathPairs[metaID] = scriptPath; + } + metaIDsBuffer.Clear(); + } + + foreach (var pair in _metaIDScriptPathPairs) + { + EcsDebug.PrintPass($"k:{pair.Key} v:{pair.Value}"); + } + + _isInit = true; + + Save(true); + } + + public void Reinit() + { + _isInit = false; + InitUpdate(); + } + #endregion + + #region Get + public static bool TryGetScriptAsset(Type meta, out MonoScript script) { return TryGetScriptAsset(meta.GetMeta(), out script); } + public static bool TryGetScriptAsset(TypeMeta meta, out MonoScript script) + { + int uniqueID = meta.GetHashCode(); + + if (_scriptsAssets.TryGetValue(uniqueID, out script) == false) + { + script = null; + + //Ищем по мета айди совпадения + string metaID = meta.MetaID; + if (string.IsNullOrEmpty(metaID) == false) + { + instance.InitUpdate(); + if (_metaIDScriptPathPairs.TryGetValue(metaID, out string assetPath)) + { + if (assetPath == null) + { + _metaIDScriptPathPairs.Remove(metaID); + } + else + { + MonoScript textAsset = AssetDatabase.LoadAssetAtPath(assetPath); + if (textAsset != null) + { + script = textAsset; + } + } + } + } + + if (script == null) + { + //Ищем совпадения имет в ассетах + string name = meta.TypeName; + int genericTypeCharIndex = name.IndexOf('<'); + if (genericTypeCharIndex >= 0) + { + name = name.Substring(0, genericTypeCharIndex); + } + var guids = AssetDatabase.FindAssets($"{name} t:MonoScript"); + for (var i = 0; i < guids.Length; i++) + { + MonoScript textAsset = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(guids[i])); + if (textAsset != null && textAsset.name == name) + { + script = textAsset; + break; + } + } + } + + _scriptsAssets.Add(uniqueID, script); + } + return script != null; + } + #endregion + + #region ParseUtils + private static void ExtractMetaIDs(string script, List outputList) + { + const string PATTERN = "MetaID"; + + int lastIndex = 0; + while (true) + { + int index = script.IndexOf(PATTERN, lastIndex) + PATTERN.Length; + if (index < lastIndex || index < PATTERN.Length) { break; } + lastIndex = index; + for (int i = index; i < script.Length; i++) + { + char chr = script[i]; + if (char.IsWhiteSpace(chr) == false) + { + if (chr != '(') + { + index = -1; + } + break; + } + } + if (index < 0) { continue; } + + int startIndex = -1, endIndex = -1; + bool isVerbal = false; + for (int i = index; i < script.Length; i++) + { + char chr = script[i]; + if (chr == '@') + { + isVerbal = true; + if (script.Length <= ++i) { break; } + chr = script[i]; + } + if (chr == '"') + { + if (script.Length <= ++i) { break; } + startIndex = i; + break; + } + } + if (startIndex < 0) { continue; } + + for (int i = startIndex; i < script.Length; i++) + { + char chr = script[i]; + if (chr == '\\') + { + if (script.Length <= ++i) { break; } + continue; + } + + if (chr == '"') + { + if (isVerbal) + { + if (script.Length <= ++i) { break; } + if (script[i] != '"') + { + endIndex = i - 2; + break; + } + } + else + { + endIndex = --i; + break; + } + } + } + + if (endIndex < startIndex) { continue; } + + string substring = script.Substring(startIndex, endIndex - startIndex + 1); + if (isVerbal) + { + outputList.Add(substring.Replace("\"\"", "\"")); + } + else + { + outputList.Add(Regex.Unescape(substring)); + } + } + } + + + private static bool IsScript(string filePath) + { + int i = filePath.Length - 3; + return filePath[i++] == '.' + && filePath[i++] == 'c' + && filePath[i++] == 's'; + } + #endregion + + #region ISerializationCallbackReceiver + void ISerializationCallbackReceiver.OnBeforeSerialize() + { + _serializableMetaIDScriptPathPairs = new Pair[_metaIDScriptPathPairs.Count]; + int i = 0; + foreach (var item in _metaIDScriptPathPairs) + { + _serializableMetaIDScriptPathPairs[i++] = new Pair(item.Key, item.Value); + } + } + void ISerializationCallbackReceiver.OnAfterDeserialize() + { + if (_serializableMetaIDScriptPathPairs == null) { return; } + foreach (var item in _serializableMetaIDScriptPathPairs) + { + if (string.IsNullOrEmpty(item.scriptPath)) + { + _metaIDScriptPathPairs.Add(item.metaID, item.scriptPath); + } + } + } + #endregion + } +} +#endif \ No newline at end of file diff --git a/src/Editor/ScriptsCache.cs.meta b/src/Editor/ScriptsCache.cs.meta new file mode 100644 index 0000000..f5f3761 --- /dev/null +++ b/src/Editor/ScriptsCache.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 82075f06aeb727149b234dffbff0cd9a +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 d9f737d..0cfe65a 100644 --- a/src/Internal/Editor/EcsGUI.cs +++ b/src/Internal/Editor/EcsGUI.cs @@ -526,7 +526,7 @@ namespace DCFApixels.DragonECS.Unity.Editors } public static bool DrawTypeMetaElementBlock(ref Rect position, SerializedProperty arrayProperty, int elementIndex, SerializedProperty elementProperty, ITypeMeta meta) { - var result = DrawTypeMetaBlock_Internal(ref position, elementProperty, meta); + var result = DrawTypeMetaBlock_Internal(ref position, elementProperty, meta, elementIndex, arrayProperty.arraySize); if (result.HasFlag(DrawTypeMetaBlockResult.CloseButtonClicked)) { arrayProperty.DeleteArrayElementAtIndex(elementIndex); @@ -549,7 +549,7 @@ namespace DCFApixels.DragonECS.Unity.Editors Drop = 1 << 0, CloseButtonClicked = 1 << 1, } - private static DrawTypeMetaBlockResult DrawTypeMetaBlock_Internal(ref Rect position, SerializedProperty property, ITypeMeta meta) + private static DrawTypeMetaBlockResult DrawTypeMetaBlock_Internal(ref Rect position, SerializedProperty property, ITypeMeta meta, int index = -1, int total = -1) { Color alphaPanelColor; if (meta == null) @@ -561,18 +561,26 @@ namespace DCFApixels.DragonECS.Unity.Editors return DrawTypeMetaBlockResult.None; } - var counter = property.Copy(); - int positionCountr = int.MaxValue; - int depth = -1; - while (counter.NextVisibleDepth(false, ref depth)) - { - positionCountr--; - } - string name = meta.Name; string description = meta.Description.Text; - alphaPanelColor = SelectPanelColor(meta, positionCountr, -1).Desaturate(EscEditorConsts.COMPONENT_DRAWER_DESATURATE); + int positionCountr; + if (index < 0) + { + positionCountr = int.MaxValue; + var counter = property.Copy(); + int depth = -1; + while (counter.NextVisibleDepth(false, ref depth)) + { + positionCountr--; + } + } + else + { + positionCountr = index; + } + + alphaPanelColor = SelectPanelColor(meta, positionCountr, total).Desaturate(EscEditorConsts.COMPONENT_DRAWER_DESATURATE); alphaPanelColor.a = EscEditorConsts.COMPONENT_DRAWER_ALPHA; DrawTypeMetaBlockResult result = DrawTypeMetaBlockResult.None; @@ -605,7 +613,7 @@ namespace DCFApixels.DragonECS.Unity.Editors return result; } //Edit script button - if (UnityEditorUtility.TryGetScriptAsset(meta.Type, out MonoScript script)) + if (ScriptsCache.TryGetScriptAsset(meta.FindRootTypeMeta(), out MonoScript script)) { optionButton = HeadIconsRect.MoveTo(optionButton.center - (Vector2.right * optionButton.width)); ScriptAssetButton(optionButton, script); @@ -1136,7 +1144,7 @@ namespace DCFApixels.DragonECS.Unity.Editors return; } //Edit script button - if (UnityEditorUtility.TryGetScriptAsset(componentType, out MonoScript script)) + if (ScriptsCache.TryGetScriptAsset(meta, out MonoScript script)) { optionButton = HeadIconsRect.MoveTo(optionButton.center - (Vector2.right * optionButton.width)); EcsGUI.ScriptAssetButton(optionButton, script); diff --git a/src/Internal/Editor/ExtendedEditor.cs b/src/Internal/Editor/ExtendedEditor.cs index f5e9a1a..f4abe62 100644 --- a/src/Internal/Editor/ExtendedEditor.cs +++ b/src/Internal/Editor/ExtendedEditor.cs @@ -43,6 +43,12 @@ namespace DCFApixels.DragonECS.Unity.Editors get { return UserSettingsPrefs.instance.IsShowHidden; } set { UserSettingsPrefs.instance.IsShowHidden = value; } } + private static ComponentColorMode ComponentColorMode + { + get { return UserSettingsPrefs.instance.ComponentColorMode; } + set { UserSettingsPrefs.instance.ComponentColorMode = value; } + } + protected bool IsMultipleTargets => targets.Length > 1; protected virtual bool IsStaticInit { get { return _isStaticInit; } } @@ -152,6 +158,11 @@ namespace DCFApixels.DragonECS.Unity.Editors get { return UserSettingsPrefs.instance.IsShowHidden; } set { UserSettingsPrefs.instance.IsShowHidden = value; } } + private static ComponentColorMode ComponentColorMode + { + get { return UserSettingsPrefs.instance.ComponentColorMode; } + set { UserSettingsPrefs.instance.ComponentColorMode = value; } + } protected virtual bool IsStaticInit { get { return _isStaticInit; } } protected virtual bool IsInit { get { return _isInit; } } protected void StaticInit() diff --git a/src/Internal/Utils/RectUtility.cs b/src/Internal/Utils/RectUtility.cs index 1d573f3..98a23fb 100644 --- a/src/Internal/Utils/RectUtility.cs +++ b/src/Internal/Utils/RectUtility.cs @@ -66,6 +66,7 @@ namespace DCFApixels.DragonECS.Unity.Internal } public static void DebugRect_Editor(params Rect[] rects) { +#if UNITY_EDITOR uint colorState = NextXorShiftState(3136587146); foreach (var rect in rects) { @@ -75,6 +76,7 @@ namespace DCFApixels.DragonECS.Unity.Internal GUI.Box(rect, "", EditorStyles.selectionRect); EditorGUI.DrawRect(rect, color); } +#endif } #endregion diff --git a/src/Templates/EcsPipelineTemplate/Editor/EcsPipelineTemplateSOEditor.cs b/src/Templates/EcsPipelineTemplate/Editor/EcsPipelineTemplateSOEditor.cs index 4fd5896..890ade1 100644 --- a/src/Templates/EcsPipelineTemplate/Editor/EcsPipelineTemplateSOEditor.cs +++ b/src/Templates/EcsPipelineTemplate/Editor/EcsPipelineTemplateSOEditor.cs @@ -99,7 +99,7 @@ namespace DCFApixels.DragonECS.Unity.Editors _reorderableRecordsList.onRemoveCallback += OnReorderableListRemove; _reorderableRecordsList.drawElementCallback += OnReorderableListDrawEmptyElement; _reorderableRecordsList.drawElementBackgroundCallback += OnReorderableRecordsListDrawElement; - _reorderableRecordsList.drawNoneElementCallback += OnReorderableRecordsListDrawNoneElement; + _reorderableRecordsList.drawNoneElementCallback += OnReorderableListDrawNoneElement; _reorderableRecordsList.elementHeightCallback += OnReorderableRecordsListElementHeight; _reorderableRecordsList.onReorderCallback += OnReorderableListReorder; _reorderableRecordsList.showDefaultBackground = false; @@ -110,19 +110,13 @@ namespace DCFApixels.DragonECS.Unity.Editors _systemsDropDown = new SystemsDropDown(); } - private void OnReorderableRecordsListDrawNoneElement(Rect rect) - { - - } - + #region _reorderableList + private void OnReorderableListDrawNoneElement(Rect rect) { } private void OnReorderableListDrawEmptyElement(Rect rect, int index, bool isActive, bool isFocused) { } - private void OnReorderableListReorder(ReorderableList list) { EcsGUI.Changed = true; } - - #region _reorderableList private void OnReorderableListRemove(ReorderableList list) { if (list.selectedIndices.Count <= 0) @@ -163,15 +157,10 @@ namespace DCFApixels.DragonECS.Unity.Editors #region _reorderableRecordsList private void OnReorderableRecordsListDrawElement(Rect rect, int index, bool isActive, bool isFocused) { - if (index < 0) { return; } + if (index < 0 || Event.current.type == EventType.Used) { return; } rect = rect.AddPadding(OneLineHeight + Spacing, Spacing * 2f, Spacing, Spacing); using (EcsGUI.CheckChanged()) { - if (Event.current.type == EventType.Used) - { - return; - } - //EcsDebug.PrintPass(index); SerializedProperty prop = _recordsProp.GetArrayElementAtIndex(index); var targetProp = prop.FindPropertyRelative(nameof(EcsPipelineTemplateSO.Record.target)); diff --git a/src/Templates/EntityTemplate/Editor/ComponentTemplatePropertyDrawer.cs b/src/Templates/EntityTemplate/Editor/ComponentTemplatePropertyDrawer.cs index 4657362..3aa0c1a 100644 --- a/src/Templates/EntityTemplate/Editor/ComponentTemplatePropertyDrawer.cs +++ b/src/Templates/EntityTemplate/Editor/ComponentTemplatePropertyDrawer.cs @@ -177,7 +177,7 @@ namespace DCFApixels.DragonECS.Unity.Editors return; } //Edit script button - if (UnityEditorUtility.TryGetScriptAsset(componentType, out MonoScript script)) + if (ScriptsCache.TryGetScriptAsset(meta.FindRootTypeMeta(), out MonoScript script)) { optionButton = HeadIconsRect.MoveTo(optionButton.center - (Vector2.right * optionButton.width)); EcsGUI.ScriptAssetButton(optionButton, script); diff --git a/src/Templates/EntityTemplate/Editor/EntityTemplateEditor.cs b/src/Templates/EntityTemplate/Editor/EntityTemplateEditor.cs index 95af9b6..ad9a74e 100644 --- a/src/Templates/EntityTemplate/Editor/EntityTemplateEditor.cs +++ b/src/Templates/EntityTemplate/Editor/EntityTemplateEditor.cs @@ -3,6 +3,7 @@ using DCFApixels.DragonECS.Unity.Internal; using System; using System.Reflection; using UnityEditor; +using UnityEditorInternal; using UnityEngine; namespace DCFApixels.DragonECS.Unity.Editors @@ -13,18 +14,140 @@ namespace DCFApixels.DragonECS.Unity.Editors private ComponentDropDown _componentDropDown; - private static ComponentColorMode AutoColorMode - { - get { return UserSettingsPrefs.instance.ComponentColorMode; } - set { UserSettingsPrefs.instance.ComponentColorMode = value; } - } + private SerializedProperty _componentsProp; + private ReorderableList _reorderableComponentsList; #region Init protected override bool IsInit => _componentDropDown != null; protected override void OnInit() { _componentDropDown = new ComponentDropDown(); + + _componentsProp = serializedObject.FindProperty(Target.ComponentsPropertyName); + + _reorderableComponentsList = new ReorderableList(serializedObject, _componentsProp, true, false, false, false); + _reorderableComponentsList.onAddCallback += OnReorderableComponentsListAdd; + _reorderableComponentsList.onRemoveCallback += OnReorderableListRemove; + _reorderableComponentsList.drawElementCallback += OnReorderableListDrawEmptyElement; + _reorderableComponentsList.drawElementBackgroundCallback += OnReorderableComponentsListDrawElement; + _reorderableComponentsList.drawNoneElementCallback += OnReorderableComponentsListDrawNoneElement; + _reorderableComponentsList.elementHeightCallback += OnReorderableComponentsListElementHeight; + _reorderableComponentsList.onReorderCallback += OnReorderableListReorder; + _reorderableComponentsList.showDefaultBackground = false; + _reorderableComponentsList.footerHeight = 0f; + _reorderableComponentsList.headerHeight = 0f; + _reorderableComponentsList.elementHeight = 0f; } + + #region ReorderableComponentsList + private void OnReorderableComponentsListDrawNoneElement(Rect rect) { } + private void OnReorderableListDrawEmptyElement(Rect rect, int index, bool isActive, bool isFocused) { } + + private void OnReorderableListReorder(ReorderableList list) + { + EcsGUI.Changed = true; + } + + private SerializedProperty GetTargetProperty(SerializedProperty prop) + { + IComponentTemplate template = prop.managedReferenceValue as IComponentTemplate; + if (template == null || prop.managedReferenceValue == null) + { + //DrawDamagedComponent_Replaced(componentRefProp, index); + return prop; + } + + SerializedProperty componentProperty = prop; + try + { + if (componentProperty.managedReferenceValue is ComponentTemplateBase customTemplate) + { + componentProperty = prop.FindPropertyRelative("component"); + } + + if (componentProperty == null) + { + throw new NullReferenceException(); + } + } + catch (Exception e) + { + Debug.LogException(e, serializedObject.targetObject); + //DrawDamagedComponent(index, "Damaged component template."); + return prop; + } + + return componentProperty; + } + private float OnReorderableComponentsListElementHeight(int index) + { + var componentProperty = GetTargetProperty(_componentsProp.GetArrayElementAtIndex(index)); + float result = EditorGUI.GetPropertyHeight(componentProperty); + return EcsGUI.GetTypeMetaBlockHeight(result) + Spacing * 2f; + } + private void OnReorderableComponentsListDrawElement(Rect rect, int index, bool isActive, bool isFocused) + { + if (index < 0 || Event.current.type == EventType.Used) { return; } + rect = rect.AddPadding(OneLineHeight + Spacing, Spacing * 2f, Spacing, Spacing); + using (EcsGUI.CheckChanged()) + { + SerializedProperty prop = _componentsProp.GetArrayElementAtIndex(index); + + IComponentTemplate template = prop.managedReferenceValue as IComponentTemplate; + if (template == null || prop.managedReferenceValue == null) + { + DrawDamagedComponent_Replaced(prop, index); + return; + } + + var componentProp = GetTargetProperty(prop); + + + ITypeMeta meta = template is ITypeMeta metaOverride ? metaOverride : template.Type.ToMeta(); + + if (EcsGUI.DrawTypeMetaElementBlock(ref rect, _componentsProp, index, componentProp, meta)) + { + return; + } + + + GUIContent label = UnityEditorUtility.GetLabel(meta.Name); + if (componentProp.propertyType == SerializedPropertyType.Generic) + { + EditorGUI.PropertyField(rect, componentProp, label, true); + } + else + { + EditorGUI.PropertyField(rect.AddPadding(0, 20f, 0, 0), componentProp, label, true); + } + + } + } + + private void OnReorderableComponentsListAdd(ReorderableList list) + { + list.serializedProperty.arraySize += 1; + list.serializedProperty.GetArrayElementAtIndex(list.serializedProperty.arraySize - 1).ResetValues(); + EcsGUI.Changed = true; + } + private void OnReorderableListRemove(ReorderableList list) + { + if (list.selectedIndices.Count <= 0) + { + if (list.serializedProperty.arraySize > 0) + { + list.serializedProperty.DeleteArrayElementAtIndex(list.serializedProperty.arraySize - 1); + } + return; + } + for (int i = list.selectedIndices.Count - 1; i >= 0; i--) + { + list.serializedProperty.DeleteArrayElementAtIndex(list.selectedIndices[i]); + } + EcsGUI.Changed = true; + } + #endregion + #endregion #region Add/Remove @@ -40,23 +163,24 @@ namespace DCFApixels.DragonECS.Unity.Editors } #endregion - protected void Draw(ITemplateInternal target) + protected override void DrawCustom() { Init(); - SerializedProperty componentsProp = serializedObject.FindProperty(target.ComponentsPropertyName); - if (componentsProp == null) + + if (_componentsProp == null) { return; } using (EcsGUI.Layout.BeginVertical(UnityEditorUtility.GetStyle(Color.black, 0.2f))) { - DrawTop(target, componentsProp); - GUILayout.Label("", GUILayout.Height(0), GUILayout.ExpandWidth(true)); - for (int i = componentsProp.arraySize - 1; i >= 0; i--) - { - DrawComponentData(componentsProp.GetArrayElementAtIndex(i), componentsProp.arraySize, i); - } + DrawTop(Target, _componentsProp); + _reorderableComponentsList.DoLayoutList(); + //GUILayout.Label("", GUILayout.Height(0), GUILayout.ExpandWidth(true)); + //for (int i = _componentsProp.arraySize - 1; i >= 0; i--) + //{ + // DrawComponentData(_componentsProp.GetArrayElementAtIndex(i), _componentsProp.arraySize, i); + //} } } private void DrawTop(ITemplateInternal target, SerializedProperty componentsProp) @@ -69,7 +193,7 @@ namespace DCFApixels.DragonECS.Unity.Editors break; case EcsGUI.AddClearButton.Clear: Init(); - serializedObject.FindProperty(target.ComponentsPropertyName).ClearArray(); + componentsProp.ClearArray(); serializedObject.ApplyModifiedProperties(); break; } @@ -151,7 +275,7 @@ namespace DCFApixels.DragonECS.Unity.Editors componentProperty.isExpanded = !componentProperty.isExpanded; } //Edit script button - if (UnityEditorUtility.TryGetScriptAsset(componentType, out MonoScript script)) + if (ScriptsCache.TryGetScriptAsset(meta.FindRootTypeMeta(), out MonoScript script)) { optionButton = HeadIconsRect.MoveTo(optionButton.center - (Vector2.right * optionButton.width)); EcsGUI.ScriptAssetButton(optionButton, script); @@ -222,18 +346,18 @@ namespace DCFApixels.DragonECS.Unity.Editors [CustomEditor(typeof(ScriptableEntityTemplate), true)] internal class EntityTemplatePresetEditor : EntityTemplateEditorBase { - protected override void DrawCustom() - { - Draw(Target); - } + //protected override void DrawCustom() + //{ + // Draw(Target); + //} } [CustomEditor(typeof(MonoEntityTemplate), true)] internal class EntityTemplateEditor : EntityTemplateEditorBase { - protected override void DrawCustom() - { - Draw(Target); - } + //protected override void DrawCustom() + //{ + // Draw(Target); + //} } } #endif diff --git a/src/Templates/EntityTemplate/Templates/MonoEntityTemplate.cs b/src/Templates/EntityTemplate/Templates/MonoEntityTemplate.cs index 19a6eb2..65f538a 100644 --- a/src/Templates/EntityTemplate/Templates/MonoEntityTemplate.cs +++ b/src/Templates/EntityTemplate/Templates/MonoEntityTemplate.cs @@ -67,7 +67,7 @@ namespace DCFApixels.DragonECS savedRecords[i] = default; } } - if(recordSingle != null) + if (recordSingle != null) { string metaid = recordSingle.GetMeta().MetaID; list.singleRecord = new SavedRecord(-1, metaid, JsonUtility.ToJson(recordSingle)); @@ -126,6 +126,7 @@ namespace DCFApixels.DragonECS public class MonoEntityTemplate : MonoEntityTemplateBase, ITemplateInternal { [SerializeReference] + [ReferenceButton(typeof(IComponentTemplate))] private IComponentTemplate[] _components; #region Properties diff --git a/src/Templates/EntityTemplate/Templates/ScriptableEntityTemplate.cs b/src/Templates/EntityTemplate/Templates/ScriptableEntityTemplate.cs index 402231e..4e89a40 100644 --- a/src/Templates/EntityTemplate/Templates/ScriptableEntityTemplate.cs +++ b/src/Templates/EntityTemplate/Templates/ScriptableEntityTemplate.cs @@ -24,6 +24,7 @@ namespace DCFApixels.DragonECS public class ScriptableEntityTemplate : ScriptableEntityTemplateBase, ITemplateInternal { [SerializeReference] + [ReferenceButton(typeof(IComponentTemplate))] private IComponentTemplate[] _components; #region Properties