diff --git a/Assets/RicUtils/Editor/ClassBuilder.cs b/Assets/RicUtils/Editor/ClassBuilder.cs new file mode 100644 index 0000000..ed546ca --- /dev/null +++ b/Assets/RicUtils/Editor/ClassBuilder.cs @@ -0,0 +1,172 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace RicUtils.Editor +{ + public sealed class ClassBuilder + { + private string namespaceName; + + private int indentation; + private ClassData classData; + private List usings = new List(); + + public ClassBuilder SetNamespace(string namespaceName) + { + this.namespaceName = namespaceName; + return this; + } + + /*public ClassBuilder AddIndentation(int amount = 1) + { + indentation += amount; + return this; + } + + public ClassBuilder RemoveIndentation(int amount = 1) + { + indentation -= amount; + return this; + }*/ + + public ClassBuilder SetClassName(AccessModifier accessModifier, Keyword keyword, string name, string baseClass = "") + { + classData = new ClassData(accessModifier, keyword, name, ClassType.Class, baseClass); + return this; + } + + public ClassBuilder AddUsing(string usingName) + { + usings.Add(usingName); + return this; + } + + public string Build() + { + string toReturn = ""; + + foreach (var @using in usings) + { + toReturn += $"using {@using}"; + AddEndLine(ref toReturn); + AddNewLine(ref toReturn); + } + + AddNewLine(ref toReturn); + + if (!string.IsNullOrEmpty(namespaceName)) + { + toReturn += $"namespace {namespaceName}"; + AddNewLine(ref toReturn); + AddOpenCurlyBrackets(ref toReturn); + indentation++; + } + + { + toReturn += AddIndentation(classData.accessModifier.ToString().ToLower() + " "); + if (classData.keyword != Keyword.None) + { + toReturn += classData.keyword.ToString().ToLower() + " "; + } + toReturn += classData.type.ToString().ToLower() + " "; + toReturn += classData.name; + if (!string.IsNullOrEmpty(classData.baseClass)) + { + toReturn += " : " + classData.baseClass; + } + AddNewLine(ref toReturn); + AddOpenCurlyBrackets(ref toReturn); + indentation++; + } + + while (indentation > 0) + { + indentation--; + AddCloseCurlyBrackets(ref toReturn); + } + + return toReturn; + } + + private string AddIndentation(string toAdd) + { + var text = ""; + for (int i = 0; i < indentation; i++) + { + text += "\t"; + } + return text + toAdd; + } + + private void AddNewLine(ref string text) + { + text += Environment.NewLine; + } + + private void AddEndLine(ref string text) + { + text += ";"; + } + + private void AddOpenCurlyBrackets(ref string text, bool addNewLine = true) + { + text += AddIndentation("{"); + if (addNewLine) + { + AddNewLine(ref text); + } + } + + private void AddCloseCurlyBrackets(ref string text, bool addNewLine = true) + { + text += AddIndentation("}"); + if (addNewLine) + { + AddNewLine(ref text); + } + } + } + + public enum AccessModifier + { + Public, + Private, + Protected, + Internal, + } + + public enum Keyword + { + None, + Static, + Abstract + } + + internal enum ClassType + { + Class, + Enum, + Struct, + Interface, + } + + internal struct ClassData + { + public AccessModifier accessModifier; + public Keyword keyword; + public string name; + public ClassType type; + public string baseClass; + + public ClassData(AccessModifier accessModifier, Keyword keyword, string name, ClassType type, string baseClass) + { + this.accessModifier = accessModifier; + this.keyword = keyword; + this.name = name; + this.type = type; + this.baseClass = baseClass; + } + } +} diff --git a/Assets/RicUtils/Editor/ClassBuilder.cs.meta b/Assets/RicUtils/Editor/ClassBuilder.cs.meta new file mode 100644 index 0000000..41ecace --- /dev/null +++ b/Assets/RicUtils/Editor/ClassBuilder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 71fc66ac8b4bec747a06a94be3235817 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/RicUtils/Editor/ContextMenus.meta b/Assets/RicUtils/Editor/ContextMenus.meta new file mode 100644 index 0000000..93c23d7 --- /dev/null +++ b/Assets/RicUtils/Editor/ContextMenus.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 061a5de56d80b6244b93664fd9e3b3e6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/RicUtils/Editor/ContextMenus/CreateAvailableContextMenu.cs b/Assets/RicUtils/Editor/ContextMenus/CreateAvailableContextMenu.cs new file mode 100644 index 0000000..c0617fc --- /dev/null +++ b/Assets/RicUtils/Editor/ContextMenus/CreateAvailableContextMenu.cs @@ -0,0 +1,52 @@ +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Security.Cryptography; +using UnityEditor; +using UnityEngine; + +namespace RicUtils.Editor +{ + public static class CreateAvailableContextMenu + { + [MenuItem("Assets/Create/Available Scriptable Object", priority = -9)] + public static void Create() + { + var mono = Selection.activeObject as MonoScript; + + string className = $"Available{mono.GetClass().Name}"; + + ToolUtilities.TryGetActiveFolderPath(out string path); + + string defaultNewFileName = Path.Combine(path, className + ".cs"); + + string templatePath = "Assets/RicUtils/Editor/Templates/Script-NewAvailableScriptableObject.cs.txt"; + + var endAction = ScriptableObject.CreateInstance(); + + endAction.scriptableObject = mono.GetClass().Name; + + ToolUtilities.CreateNewScript(endAction, defaultNewFileName, templatePath); + } + + [MenuItem("Assets/Create/Available Scriptable Object", true)] + public static bool IsValid() + { + if (!(Selection.activeObject is MonoScript mono)) return false; + if (mono.GetClass() == null) return false; + if (!mono.GetClass().IsSubclassOf(typeof(GenericScriptableObject))) return false; + return true; + } + } + + internal class DoCreateAvailableAsset : DoCreateScriptAsset + { + internal string scriptableObject; + + protected override string CustomReplaces(string content) + { + content = content.Replace("#SCRIPTABLEOBJECT#", scriptableObject); + return content; + } + } +} diff --git a/Assets/RicUtils/Editor/CreateAvailableContext.cs.meta b/Assets/RicUtils/Editor/ContextMenus/CreateAvailableContextMenu.cs.meta similarity index 100% rename from Assets/RicUtils/Editor/CreateAvailableContext.cs.meta rename to Assets/RicUtils/Editor/ContextMenus/CreateAvailableContextMenu.cs.meta diff --git a/Assets/RicUtils/Editor/ContextMenus/CreateEditorContextMenu.cs b/Assets/RicUtils/Editor/ContextMenus/CreateEditorContextMenu.cs new file mode 100644 index 0000000..acfb354 --- /dev/null +++ b/Assets/RicUtils/Editor/ContextMenus/CreateEditorContextMenu.cs @@ -0,0 +1,91 @@ +using System.Collections; +using System.Collections.Generic; +using System.IO; +using UnityEditor; +using UnityEngine; + +namespace RicUtils.Editor +{ + public static class CreateEditorContextMenu + { + + [MenuItem("Assets/Create/Editor Window", priority = -8)] + public static void Create() + { + string scriptableObject = ""; + string availableScriptableObject = ""; + + foreach (var obj in Selection.objects) + { + var mono = obj as MonoScript; + var @class = mono.GetClass(); + if (@class.IsSubclassOf(typeof(GenericScriptableObject))) scriptableObject = @class.Name; + else if (IsSubclassOfRawGeneric(typeof(AvailableScriptableObject<>), @class)) availableScriptableObject = @class.Name; + } + + string className = $"{scriptableObject}EditorWindow"; + + ToolUtilities.TryGetActiveFolderPath(out string path); + + string defaultNewFileName = Path.Combine(path, className + ".cs"); + + string templatePath = "Assets/RicUtils/Editor/Templates/Script-NewGenericEditorWindow.cs.txt"; + + var endAction = ScriptableObject.CreateInstance(); + + endAction.scriptableObject = scriptableObject; + endAction.availableScriptableObject = availableScriptableObject; + + ToolUtilities.CreateNewScript(endAction, defaultNewFileName, templatePath); + } + + [MenuItem("Assets/Create/Editor Window", true)] + public static bool IsValid() + { + if (Selection.objects.Length < 2) return false; + + bool hasGenericScriptableObject = false; + bool hasAvailableScriptableObject = false; + + foreach (var obj in Selection.objects) + { + if (obj is not MonoScript) return false; + var mono = obj as MonoScript; + var @class = mono.GetClass(); + if (mono.GetClass() == null) continue; + if (@class.IsSubclassOf(typeof(GenericScriptableObject))) hasGenericScriptableObject = true; + else if (IsSubclassOfRawGeneric(typeof(AvailableScriptableObject<>), @class)) hasAvailableScriptableObject = true; + } + + return hasGenericScriptableObject && hasAvailableScriptableObject; + } + + // https://stackoverflow.com/questions/457676/check-if-a-class-is-derived-from-a-generic-class + private static bool IsSubclassOfRawGeneric(System.Type generic, System.Type toCheck) + { + while (toCheck != null && toCheck != typeof(object)) + { + var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck; + if (generic == cur) + { + return true; + } + toCheck = toCheck.BaseType; + } + return false; + } + } + + internal class DoCreateEditorAsset : DoCreateScriptAsset + { + internal string scriptableObject; + internal string availableScriptableObject; + + protected override string CustomReplaces(string content) + { + content = content.Replace("#SCRIPTABLEOBJECT#", scriptableObject); + content = content.Replace("#AVAILABLESCRIPTABLEOBJECT#", availableScriptableObject); + return content; + } + } +} diff --git a/Assets/RicUtils/Editor/ContextMenus/CreateEditorContextMenu.cs.meta b/Assets/RicUtils/Editor/ContextMenus/CreateEditorContextMenu.cs.meta new file mode 100644 index 0000000..0681441 --- /dev/null +++ b/Assets/RicUtils/Editor/ContextMenus/CreateEditorContextMenu.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: aee3f308c71b49f40ab960236312b79c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/RicUtils/Editor/ContextMenus/CreateScriptableObjectContextMenu.cs b/Assets/RicUtils/Editor/ContextMenus/CreateScriptableObjectContextMenu.cs new file mode 100644 index 0000000..84ae521 --- /dev/null +++ b/Assets/RicUtils/Editor/ContextMenus/CreateScriptableObjectContextMenu.cs @@ -0,0 +1,33 @@ +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text.RegularExpressions; +using UnityEditor; +using UnityEditor.Compilation; +using UnityEditor.ProjectWindowCallback; +using UnityEditorInternal; +using UnityEngine; + +namespace RicUtils.Editor +{ + public static class CreateScriptableObjectContextMenu + { + + [MenuItem("Assets/Create/Generic Scriptable Object", priority = -10)] + public static void Create() + { + ToolUtilities.TryGetActiveFolderPath(out string path); + + string defaultNewFileName = Path.Combine(path, "NewGenericScriptableObject.cs"); + + string templatePath = "Assets/RicUtils/Editor/Templates/Script-NewGenericScriptableObject.cs.txt"; + + ToolUtilities.CreateNewScript(defaultNewFileName, templatePath); + + //ProjectWindowUtil.CreateScriptAssetFromTemplateFile("Assets/RicUtils/Editor/Templates/Script-NewGenericScriptableObject.cs.txt", Path.Combine(path, "NewGenericScriptableObject.cs")); + + } + } +} diff --git a/Assets/RicUtils/Editor/ContextMenus/CreateScriptableObjectContextMenu.cs.meta b/Assets/RicUtils/Editor/ContextMenus/CreateScriptableObjectContextMenu.cs.meta new file mode 100644 index 0000000..00e07eb --- /dev/null +++ b/Assets/RicUtils/Editor/ContextMenus/CreateScriptableObjectContextMenu.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2abe891cda63e7c4f8d643cb4a991577 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/RicUtils/Editor/CreateAvailableContext.cs b/Assets/RicUtils/Editor/CreateAvailableContext.cs deleted file mode 100644 index 60ed2af..0000000 --- a/Assets/RicUtils/Editor/CreateAvailableContext.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Security.Cryptography; -using UnityEditor; -using UnityEngine; - -namespace RicUtils.Editor -{ - public class CreateAvailableContext : MonoBehaviour - { - [MenuItem("Assets/Create Available Scriptable Object", priority = -10)] - public static void Create() - { - var mono = Selection.activeObject as MonoScript; - - string className = $"Available{mono.GetClass().Name}"; - - string s = "using RicUtils;\n\n"; - - string @namespace = mono.GetClass().Namespace; - - int indentation = 0; - - if (!string.IsNullOrEmpty(@namespace)) - { - s += AddIndentation("namespace " + @namespace + "\n{\n", indentation); - indentation++; - } - - s += AddIndentation("public class " + className + " : AvailableScriptableObject<" + mono.GetClass().Name + ">\n", indentation); - s += AddIndentation("{\n", indentation); - indentation++; - - while(indentation > 0) - { - indentation--; - s += AddIndentation("}\n", indentation); - } - - var path = ""; - var obj = Selection.activeObject; - if (obj == null) path = "Assets"; - else path = Path.GetDirectoryName(AssetDatabase.GetAssetPath(obj.GetInstanceID())); - - string outfile = Path.Combine(path, className + ".cs"); - using (System.IO.StreamWriter sw = - new System.IO.StreamWriter(outfile, false)) - { - sw.Write(s); - } - - AssetDatabase.Refresh(); - } - - private static string AddIndentation(string toAdd, int indentation) - { - var text = ""; - for (int i = 0; i < indentation; i++) - { - text += "\t"; - } - return text + toAdd; - } - - [MenuItem("Assets/Create Available Scriptable Object", true)] - public static bool IsValid() - { - if (!(Selection.activeObject is MonoScript mono)) return false; - if(!mono.GetClass().IsSubclassOf(typeof(CustomScriptableObject))) return false; - return true; - } - } -} diff --git a/Assets/RicUtils/Editor/CustomEditor/AvailableScriptableObjectCustomEditor.cs b/Assets/RicUtils/Editor/CustomEditor/AvailableScriptableObjectCustomEditor.cs index 63425fa..df93012 100644 --- a/Assets/RicUtils/Editor/CustomEditor/AvailableScriptableObjectCustomEditor.cs +++ b/Assets/RicUtils/Editor/CustomEditor/AvailableScriptableObjectCustomEditor.cs @@ -16,7 +16,7 @@ public override void OnInspectorGUI() var availableScriptableObjectType = target.GetType(); var availableScriptableObject = target; var itemsField = availableScriptableObjectType.GetField("items"); - var itemsArray = (CustomScriptableObject[])itemsField.GetValue(availableScriptableObject); + var itemsArray = (GenericScriptableObject[])itemsField.GetValue(availableScriptableObject); GUI.enabled = false; EditorGUILayout.ObjectField("Script", MonoScript.FromScriptableObject((ScriptableObject)target), typeof(AvailableScriptableObject<>), false); diff --git a/Assets/RicUtils/Editor/CustomEditor/CustomScriptableObjectCustomEditor.cs b/Assets/RicUtils/Editor/CustomEditor/CustomScriptableObjectCustomEditor.cs index 19f311a..ec52d4a 100644 --- a/Assets/RicUtils/Editor/CustomEditor/CustomScriptableObjectCustomEditor.cs +++ b/Assets/RicUtils/Editor/CustomEditor/CustomScriptableObjectCustomEditor.cs @@ -5,7 +5,7 @@ namespace RicUtils.Editor { - [CustomEditor(typeof(CustomScriptableObject), true)] + [CustomEditor(typeof(GenericScriptableObject), true)] [CanEditMultipleObjects] public class CustomScriptableObjectCustomEditor : UnityEditor.Editor { @@ -14,7 +14,7 @@ public override void OnInspectorGUI() if (ToolUtilities.HasCustomEditor(target.GetType())) { GUI.enabled = false; - EditorGUILayout.ObjectField("Script", MonoScript.FromScriptableObject((CustomScriptableObject)target), typeof(CustomScriptableObject), false); + EditorGUILayout.ObjectField("Script", MonoScript.FromScriptableObject((GenericScriptableObject)target), typeof(GenericScriptableObject), false); GUI.enabled = true; EditorGUILayout.BeginHorizontal(); diff --git a/Assets/RicUtils/Editor/RicUtils_EditorSettings.cs b/Assets/RicUtils/Editor/RicUtils_EditorSettings.cs index e5246a6..ebeab4f 100644 --- a/Assets/RicUtils/Editor/RicUtils_EditorSettings.cs +++ b/Assets/RicUtils/Editor/RicUtils_EditorSettings.cs @@ -15,7 +15,7 @@ public class RicUtils_EditorSettings : ScriptableObject public static string version { - get { return "1.2.1"; } + get { return "1.3.0"; } } public static ScriptableEditor[] scriptableEditors diff --git a/Assets/RicUtils/Editor/ScriptableEditor.cs b/Assets/RicUtils/Editor/ScriptableEditor.cs index bbbdee6..03b03f9 100644 --- a/Assets/RicUtils/Editor/ScriptableEditor.cs +++ b/Assets/RicUtils/Editor/ScriptableEditor.cs @@ -1,13 +1,13 @@ using TypeReferences; -using UnityEngine; using UnityEditor; +using UnityEngine; namespace RicUtils.Editor { [System.Serializable] public class ScriptableEditor { - [Inherits(typeof(CustomScriptableObject), ShortName = true, AllowAbstract = false, IncludeBaseType = false, ShowAllTypes = true)] + [Inherits(typeof(GenericScriptableObject), ShortName = true, AllowAbstract = false, IncludeBaseType = false, ShowAllTypes = true)] public TypeReference customScriptableObjectType; [Inherits(typeof(GenericEditorWindow<,>), ShortName = true, AllowAbstract = false, IncludeBaseType = false, ShowAllTypes = true)] @@ -25,7 +25,7 @@ public class ScriptableEditor public bool IsSameKeyType(System.Type type) { - if(type == null || CustomScriptableObjectType == null) return false; + if (type == null || CustomScriptableObjectType == null) return false; return type == CustomScriptableObjectType || type.IsSubclassOf(CustomScriptableObjectType); } diff --git a/Assets/RicUtils/Editor/Templates.meta b/Assets/RicUtils/Editor/Templates.meta new file mode 100644 index 0000000..d5662ba --- /dev/null +++ b/Assets/RicUtils/Editor/Templates.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0b7f00c81e14ccd4bb581af38e5b13b0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/RicUtils/Editor/Templates/Script-NewAvailableScriptableObject.cs.txt b/Assets/RicUtils/Editor/Templates/Script-NewAvailableScriptableObject.cs.txt new file mode 100644 index 0000000..1fdef5e --- /dev/null +++ b/Assets/RicUtils/Editor/Templates/Script-NewAvailableScriptableObject.cs.txt @@ -0,0 +1,11 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using RicUtils; + + #ROOTNAMESPACEBEGIN# +public class #SCRIPTNAME# : AvailableScriptableObject<#SCRIPTABLEOBJECT#> +{ + +} +#ROOTNAMESPACEEND# \ No newline at end of file diff --git a/Assets/RicUtils/Editor/Templates/Script-NewAvailableScriptableObject.cs.txt.meta b/Assets/RicUtils/Editor/Templates/Script-NewAvailableScriptableObject.cs.txt.meta new file mode 100644 index 0000000..6753412 --- /dev/null +++ b/Assets/RicUtils/Editor/Templates/Script-NewAvailableScriptableObject.cs.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ce50f18bfb567b242be57fe2cb65f04a +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/RicUtils/Editor/Templates/Script-NewGenericEditorWindow.cs.txt b/Assets/RicUtils/Editor/Templates/Script-NewGenericEditorWindow.cs.txt new file mode 100644 index 0000000..be9e551 --- /dev/null +++ b/Assets/RicUtils/Editor/Templates/Script-NewGenericEditorWindow.cs.txt @@ -0,0 +1,25 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using RicUtils; +using RicUtils.Editor; + + #ROOTNAMESPACEBEGIN# +public class #SCRIPTNAME# : GenericEditorWindow<#SCRIPTABLEOBJECT#, #AVAILABLESCRIPTABLEOBJECT#> +{ + public static #SCRIPTNAME# ShowWindow() + { + return GetWindow<#SCRIPTNAME#>(); + } + + protected override void CreateAsset(ref #SCRIPTABLEOBJECT# asset) + { + + } + + protected override void DrawGUI() + { + + } +} +#ROOTNAMESPACEEND# \ No newline at end of file diff --git a/Assets/RicUtils/Editor/Templates/Script-NewGenericEditorWindow.cs.txt.meta b/Assets/RicUtils/Editor/Templates/Script-NewGenericEditorWindow.cs.txt.meta new file mode 100644 index 0000000..b214925 --- /dev/null +++ b/Assets/RicUtils/Editor/Templates/Script-NewGenericEditorWindow.cs.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 058ac5e2d722ff64d8fe0f371107b97c +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/RicUtils/Editor/Templates/Script-NewGenericScriptableObject.cs.txt b/Assets/RicUtils/Editor/Templates/Script-NewGenericScriptableObject.cs.txt new file mode 100644 index 0000000..6bd932c --- /dev/null +++ b/Assets/RicUtils/Editor/Templates/Script-NewGenericScriptableObject.cs.txt @@ -0,0 +1,11 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using RicUtils; + + #ROOTNAMESPACEBEGIN# +public class #SCRIPTNAME# : GenericScriptableObject +{ + +} +#ROOTNAMESPACEEND# \ No newline at end of file diff --git a/Assets/RicUtils/Editor/Templates/Script-NewGenericScriptableObject.cs.txt.meta b/Assets/RicUtils/Editor/Templates/Script-NewGenericScriptableObject.cs.txt.meta new file mode 100644 index 0000000..2bbd43f --- /dev/null +++ b/Assets/RicUtils/Editor/Templates/Script-NewGenericScriptableObject.cs.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 7fce254ac4c98fd45b640f2adbbe62e1 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/RicUtils/Editor/ToolUtilities.cs b/Assets/RicUtils/Editor/ToolUtilities.cs index 538c426..33f779e 100644 --- a/Assets/RicUtils/Editor/ToolUtilities.cs +++ b/Assets/RicUtils/Editor/ToolUtilities.cs @@ -1,8 +1,12 @@ using System.Collections; using System.Collections.Generic; using System.IO; +using System.Reflection; +using System.Text.RegularExpressions; using UnityEditor; using UnityEditor.Callbacks; +using UnityEditor.Compilation; +using UnityEditor.ProjectWindowCallback; using UnityEngine; namespace RicUtils.Editor @@ -56,7 +60,7 @@ public static System.Type GetAvailableScriptableObjectType(System.Type type) [OnOpenAsset] public static bool OnOpenAsset(int instanceId, int line) { - var temp = EditorUtility.InstanceIDToObject(instanceId) as CustomScriptableObject; + var temp = EditorUtility.InstanceIDToObject(instanceId) as GenericScriptableObject; if (temp != null) { return OpenScriptableObjectFile(temp); @@ -64,15 +68,14 @@ public static bool OnOpenAsset(int instanceId, int line) return false; } - private static bool OpenScriptableObjectFile(CustomScriptableObject so) + private static bool OpenScriptableObjectFile(GenericScriptableObject so) { foreach (var keyValuePair in GetScriptableEditors()) { if (keyValuePair.HasCustomEditor(so.GetType())) { - //var actualSo = System.Convert.ChangeType(so, keyValuePair.Key); var showWindow = keyValuePair.EditorType.GetMethod("ShowWindow", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); - if(showWindow == null) + if (showWindow == null) { Debug.LogError(keyValuePair.EditorType + " has no ShowWindow static function"); return false; @@ -86,6 +89,41 @@ private static bool OpenScriptableObjectFile(CustomScriptableObject so) } return false; } + + public static bool TryGetActiveFolderPath(out string path) + { + var _tryGetActiveFolderPath = typeof(ProjectWindowUtil).GetMethod("TryGetActiveFolderPath", BindingFlags.Static | BindingFlags.NonPublic); + + object[] args = new object[] { null }; + bool found = (bool)_tryGetActiveFolderPath.Invoke(null, args); + path = (string)args[0]; + + return found; + } + + public static void CreateNewScript(string defaultNewFileName, string templatePath) + { + CreateNewScript(defaultNewFileName, templatePath); + } + + public static void CreateNewScript(string defaultNewFileName, string templatePath) where T : EndNameEditAction + { + var endAction = ScriptableObject.CreateInstance(); + CreateNewScript(endAction, defaultNewFileName, templatePath); + } + + public static void CreateNewScript(T endAction, string defaultNewFileName, string templatePath) where T : EndNameEditAction + { + ProjectWindowUtil.StartNameEditingIfProjectWindowExists(icon: Path.GetExtension(defaultNewFileName) switch + { + ".cs" => EditorGUIUtility.IconContent("cs Script Icon").image as Texture2D, + ".shader" => EditorGUIUtility.IconContent("Shader Icon").image as Texture2D, + ".asmdef" => EditorGUIUtility.IconContent("AssemblyDefinitionAsset Icon").image as Texture2D, + ".asmref" => EditorGUIUtility.IconContent("AssemblyDefinitionReferenceAsset Icon").image as Texture2D, + _ => EditorGUIUtility.IconContent("TextAsset Icon").image as Texture2D, + }, instanceID: 0, endAction: endAction, pathName: defaultNewFileName, resourceFile: templatePath); + AssetDatabase.Refresh(); + } } internal class CustomScriptableObjectProcessing : UnityEditor.AssetModificationProcessor @@ -99,7 +137,7 @@ public static AssetDeleteResult OnWillDeleteAsset(string AssetPath, RemoveAssetO var availableScriptableObjectType = ToolUtilities.GetAvailableScriptableObjectType(temp.GetType()); var availableScriptableObject = AssetDatabase.LoadMainAssetAtPath(RicUtilities.GetAvailableScriptableObjectPath(availableScriptableObjectType)); var baseType = temp.GetType(); - while(baseType.BaseType != null && baseType.BaseType != typeof(CustomScriptableObject)) + while (baseType.BaseType != null && baseType.BaseType != typeof(GenericScriptableObject)) { baseType = baseType.BaseType; } @@ -123,146 +161,125 @@ public static AssetDeleteResult OnWillDeleteAsset(string AssetPath, RemoveAssetO return AssetDeleteResult.DidNotDelete; } + } - /*public static string[] OnWillSaveAssets(string[] paths) + public class DoCreateScriptAsset : EndNameEditAction + { + public override void Action(int instanceId, string pathName, string resourceFile) { - foreach (string path in paths) - { - var temp = AssetDatabase.LoadMainAssetAtPath(path); - if (temp == null) continue; - if (ToolUtilities.HasCustomEditor(temp.GetType())) - { - var availableScriptableObjectType = ToolUtilities.GetAvailableScriptableObjectType(temp.GetType()); - var availableScriptableObject = AssetDatabase.LoadMainAssetAtPath(ToolUtilities.GetAvailableScriptableObjectPath(availableScriptableObjectType)); - if (availableScriptableObject == null) - { - availableScriptableObject = ScriptableObject.CreateInstance(availableScriptableObjectType); - var items = (IList)System.Activator.CreateInstance(typeof(List<>).MakeGenericType(temp.GetType())); - availableScriptableObjectType.GetMethod("SetItems").Invoke(availableScriptableObject, new object[] { items }); - - AssetDatabase.CreateAsset(availableScriptableObject, ToolUtilities.GetAvailableScriptableObjectPath(availableScriptableObjectType)); + Object o = CreateScriptAssetFromTemplate(pathName, resourceFile); + ProjectWindowUtil.ShowCreatedAsset(o); + } - AssetDatabase.SaveAssets(); - } - if (availableScriptableObject != null) - { - var itemsField = availableScriptableObjectType.GetField("items"); - var itemsArray = (object[])itemsField.GetValue(availableScriptableObject); - var items = (IList)System.Activator.CreateInstance(typeof(List<>).MakeGenericType(temp.GetType())); - foreach (var item in itemsArray) - { - items.Add(item); - } - items.Add(temp); - availableScriptableObjectType.GetMethod("SetItems").Invoke(availableScriptableObject, new object[] { items }); - - EditorUtility.SetDirty(availableScriptableObject); - } - } - } - return paths; - }*/ + private Object CreateScriptAssetFromTemplate(string pathName, string resourceFile) + { + string content = File.ReadAllText(resourceFile); + var method = typeof(ProjectWindowUtil).GetMethod("CreateScriptAssetWithContent", BindingFlags.Static | BindingFlags.NonPublic); + return (Object)method.Invoke(null, new object[] { pathName, PreprocessScriptAssetTemplate(pathName, content) }); + } - /*public static string[] OnWillSaveAssets(string[] paths) + // https://github.com/Unity-Technologies/UnityCsReference/blob/master/Editor/Mono/ProjectWindow/ProjectWindowUtil.cs + private string PreprocessScriptAssetTemplate(string pathName, string resourceContent) { - Debug.Log("OnWillSaveAssets"); - foreach (string path in paths) + string rootNamespace = null; + + if (Path.GetExtension(pathName) == ".cs") { - Debug.Log(path); - if (!path.EndsWith(".meta")) continue; - var assetName = path.Replace(".meta", ""); - var temp = AssetDatabase.LoadMainAssetAtPath(assetName); - Debug.Log(temp); - continue; - if (temp == null) continue; - if (ToolUtilities.HasCustomEditor(temp.GetType())) - { - var availableScriptableObjectType = ToolUtilities.GetAvailableScriptableObjectType(temp.GetType()); - var availableScriptableObject = AssetDatabase.LoadMainAssetAtPath(ToolUtilities.GetAvailableScriptableObjectPath(availableScriptableObjectType)); - if (availableScriptableObject == null) - { - availableScriptableObject = ScriptableObject.CreateInstance(availableScriptableObjectType); - var items = (IList)System.Activator.CreateInstance(typeof(List<>).MakeGenericType(temp.GetType())); - availableScriptableObjectType.GetMethod("SetItems").Invoke(availableScriptableObject, new object[] { items }); + rootNamespace = CompilationPipeline.GetAssemblyRootNamespaceFromScriptPath(pathName); + } - AssetDatabase.CreateAsset(availableScriptableObject, ToolUtilities.GetAvailableScriptableObjectPath(availableScriptableObjectType)); + string content = resourceContent; - AssetDatabase.SaveAssets(); - } - if (availableScriptableObject != null) - { - var itemsField = availableScriptableObjectType.GetField("items"); - var itemsArray = (object[])itemsField.GetValue(availableScriptableObject); - var items = (IList)System.Activator.CreateInstance(typeof(List<>).MakeGenericType(temp.GetType())); - foreach (var item in itemsArray) - { - items.Add(item); - } - items.Add(temp); - availableScriptableObjectType.GetMethod("SetItems").Invoke(availableScriptableObject, new object[] { items }); - - EditorUtility.SetDirty(availableScriptableObject); - - //AssetDatabase.SaveAssets(); - } - } + // #NOTRIM# is a special marker that is used to mark the end of a line where we want to leave whitespace. prevent editors auto-stripping it by accident. + content = content.Replace("#NOTRIM#", ""); + + // macro replacement + string baseFile = Path.GetFileNameWithoutExtension(pathName); + + content = content.Replace("#NAME#", baseFile); + string baseFileNoSpaces = baseFile.Replace(" ", ""); + content = content.Replace("#SCRIPTNAME#", baseFileNoSpaces); + + content = CustomReplaces(content); + + content = RemoveOrInsertNamespace(content, rootNamespace); + + // if the script name begins with an uppercase character we support a lowercase substitution variant + if (char.IsUpper(baseFileNoSpaces, 0)) + { + baseFileNoSpaces = char.ToLower(baseFileNoSpaces[0]) + baseFileNoSpaces.Substring(1); + content = content.Replace("#SCRIPTNAME_LOWER#", baseFileNoSpaces); + } + else + { + // still allow the variant, but change the first character to upper and prefix with "my" + baseFileNoSpaces = "my" + char.ToUpper(baseFileNoSpaces[0]) + baseFileNoSpaces.Substring(1); + content = content.Replace("#SCRIPTNAME_LOWER#", baseFileNoSpaces); } - return paths; - }*/ - /*public static void OnWillCreateAsset(string assetName) + return content; + } + + protected virtual string CustomReplaces(string content) { - if (!assetName.EndsWith(".meta")) return; - assetName = assetName.Replace(".meta", ""); - AssetDatabase.Refresh(); - var temp = AssetDatabase.LoadMainAssetAtPath(assetName); - Debug.Log(temp + "__"); - if (temp == null) return; - EditorUtility.SetDirty(temp); - AssetDatabase.SaveAssets(); - //AssetDatabase.ImportAsset(assetName); - }*/ - - /*public static void OnWillCreateAsset(string assetName) + return content; + } + + private string RemoveOrInsertNamespace(string content, string rootNamespace) { - if (!assetName.EndsWith(".meta")) return; - assetName = assetName.Replace(".meta", ""); - AssetDatabase.Refresh(); - var temp = AssetDatabase.LoadMainAssetAtPath(assetName); - Debug.Log(temp); - if(temp == null) return; - if (ToolUtilities.HasCustomEditor(temp.GetType())) + var rootNamespaceBeginTag = "#ROOTNAMESPACEBEGIN#"; + var rootNamespaceEndTag = "#ROOTNAMESPACEEND#"; + + if (!content.Contains(rootNamespaceBeginTag) || !content.Contains(rootNamespaceEndTag)) + return content; + + if (string.IsNullOrEmpty(rootNamespace)) { - var availableScriptableObjectType = ToolUtilities.GetAvailableScriptableObjectType(temp.GetType()); - var availableScriptableObject = AssetDatabase.LoadMainAssetAtPath(ToolUtilities.GetAvailableScriptableObjectPath(availableScriptableObjectType)); - if(availableScriptableObject == null) - { - availableScriptableObject = ScriptableObject.CreateInstance(availableScriptableObjectType); - var items = (IList)System.Activator.CreateInstance(typeof(List<>).MakeGenericType(temp.GetType())); - availableScriptableObjectType.GetMethod("SetItems").Invoke(availableScriptableObject, new object[] { items }); + content = Regex.Replace(content, $"((\\r\\n)|\\n)[ \\t]*{rootNamespaceBeginTag}[ \\t]*", string.Empty); + content = Regex.Replace(content, $"((\\r\\n)|\\n)[ \\t]*{rootNamespaceEndTag}[ \\t]*", string.Empty); - AssetDatabase.CreateAsset(availableScriptableObject, ToolUtilities.GetAvailableScriptableObjectPath(availableScriptableObjectType)); + return content; + } - AssetDatabase.SaveAssets(); - } - if (availableScriptableObject != null) - { - var itemsField = availableScriptableObjectType.GetField("items"); - var itemsArray = (object[])itemsField.GetValue(availableScriptableObject); - var items = (IList)System.Activator.CreateInstance(typeof(List<>).MakeGenericType(temp.GetType())); - foreach (var item in itemsArray) - { - items.Add(item); - } - items.Add(temp); - availableScriptableObjectType.GetMethod("SetItems").Invoke(availableScriptableObject, new object[] { items }); + // Use first found newline character as newline for entire file after replace. + var newline = content.Contains("\r\n") ? "\r\n" : "\n"; + var contentLines = new List(content.Split(new[] { "\r\n", "\r", "\n" }, System.StringSplitOptions.None)); - EditorUtility.SetDirty(availableScriptableObject); + int i = 0; + + for (; i < contentLines.Count; ++i) + { + if (contentLines[i].Contains(rootNamespaceBeginTag)) + break; + } + + var beginTagLine = contentLines[i]; + + // Use the whitespace between beginning of line and #ROOTNAMESPACEBEGIN# as identation. + var indentationString = beginTagLine.Substring(0, beginTagLine.IndexOf("#")); - AssetDatabase.SaveAssets(); + contentLines[i] = $"namespace {rootNamespace}"; + contentLines.Insert(i + 1, "{"); + + i += 2; + + for (; i < contentLines.Count; ++i) + { + var line = contentLines[i]; + + if (string.IsNullOrEmpty(line) || line.Trim().Length == 0) + continue; + + if (line.Contains(rootNamespaceEndTag)) + { + contentLines[i] = "}"; + break; } + + contentLines[i] = $"{indentationString}{line}"; } - }*/ - } + return string.Join(newline, contentLines.ToArray()); + } + } } diff --git a/Assets/RicUtils/Editor/Tools/GenericEditorWindow.cs b/Assets/RicUtils/Editor/Tools/GenericEditorWindow.cs index 3530d7b..2969a9a 100644 --- a/Assets/RicUtils/Editor/Tools/GenericEditorWindow.cs +++ b/Assets/RicUtils/Editor/Tools/GenericEditorWindow.cs @@ -6,7 +6,7 @@ namespace RicUtils.Editor { - public abstract class GenericEditorWindow : EditorWindow where T : CustomScriptableObject where D : AvailableScriptableObject + public abstract class GenericEditorWindow : EditorWindow where T : GenericScriptableObject where D : AvailableScriptableObject { public T scriptableObject; diff --git a/Assets/RicUtils/Editor/Tools/RicUtils_SettingsEditor.cs b/Assets/RicUtils/Editor/Tools/RicUtils_SettingsEditor.cs index 52fddbc..fe57df5 100644 --- a/Assets/RicUtils/Editor/Tools/RicUtils_SettingsEditor.cs +++ b/Assets/RicUtils/Editor/Tools/RicUtils_SettingsEditor.cs @@ -18,8 +18,8 @@ internal class Styles public static readonly GUIContent scriptableEditorsAddButtonLabel = new GUIContent("Add Scriptable Editor"); } - RicUtils_EditorSettings editorSettings; - RicUtils_Settings settings; + private RicUtils_EditorSettings editorSettings; + private RicUtils_Settings settings; private ReorderableList m_scriptableEditorsList; private ReorderableList m_singletonManagersList; @@ -35,7 +35,7 @@ public static RicUtils_SettingsEditor ShowWindow() return GetWindow("RicUtils Settings"); } - void OnEnable() + private void OnEnable() { editorSettings = RicUtils_EditorSettings.instance; settings = RicUtils_Settings.instance; @@ -113,7 +113,7 @@ void OnEnable() }; } - void OnGUI() + private void OnGUI() { editorSerializedObject.Update(); serializedObject.Update(); diff --git a/Assets/RicUtils/Runtime/AvailableScriptableObject.cs b/Assets/RicUtils/Runtime/AvailableScriptableObject.cs index 784a638..fe971b3 100644 --- a/Assets/RicUtils/Runtime/AvailableScriptableObject.cs +++ b/Assets/RicUtils/Runtime/AvailableScriptableObject.cs @@ -4,7 +4,7 @@ namespace RicUtils { - public class AvailableScriptableObject : ScriptableObject where T : CustomScriptableObject + public class AvailableScriptableObject : ScriptableObject where T : GenericScriptableObject { public T[] items; @@ -14,7 +14,7 @@ public void SetItems(IList items) items.CopyTo(temp, 0); this.items = temp; } - + public T this[int index] { get { return items[index]; } diff --git a/Assets/RicUtils/Runtime/CustomScriptableObject.cs b/Assets/RicUtils/Runtime/GenericScriptableObject.cs similarity index 70% rename from Assets/RicUtils/Runtime/CustomScriptableObject.cs rename to Assets/RicUtils/Runtime/GenericScriptableObject.cs index c4a701d..1e2bdf9 100644 --- a/Assets/RicUtils/Runtime/CustomScriptableObject.cs +++ b/Assets/RicUtils/Runtime/GenericScriptableObject.cs @@ -4,7 +4,7 @@ namespace RicUtils { - public class CustomScriptableObject : ScriptableObject + public class GenericScriptableObject : ScriptableObject { public string id; } diff --git a/Assets/RicUtils/Runtime/CustomScriptableObject.cs.meta b/Assets/RicUtils/Runtime/GenericScriptableObject.cs.meta similarity index 100% rename from Assets/RicUtils/Runtime/CustomScriptableObject.cs.meta rename to Assets/RicUtils/Runtime/GenericScriptableObject.cs.meta diff --git a/Assets/RicUtils/Runtime/Managers/DataManagerScriptableObject.cs b/Assets/RicUtils/Runtime/Managers/DataManagerScriptableObject.cs new file mode 100644 index 0000000..7cad25a --- /dev/null +++ b/Assets/RicUtils/Runtime/Managers/DataManagerScriptableObject.cs @@ -0,0 +1,11 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace RicUtils.Managers +{ + public class DataManagerScriptableObject : ScriptableObject + { + + } +} diff --git a/Assets/RicUtils/Runtime/Managers/DataManagerScriptableObject.cs.meta b/Assets/RicUtils/Runtime/Managers/DataManagerScriptableObject.cs.meta new file mode 100644 index 0000000..9e16ec6 --- /dev/null +++ b/Assets/RicUtils/Runtime/Managers/DataManagerScriptableObject.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 76bd5dd4742ebfc40b12a7e464380380 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/RicUtils/Runtime/Managers/SingletonCreation.cs b/Assets/RicUtils/Runtime/Managers/SingletonCreation.cs index 42ce261..b39e09b 100644 --- a/Assets/RicUtils/Runtime/Managers/SingletonCreation.cs +++ b/Assets/RicUtils/Runtime/Managers/SingletonCreation.cs @@ -10,7 +10,7 @@ public static class SingletonCreation [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] private static void OnLoad() { - foreach(var manager in RicUtils_Settings.singletonManagers) + foreach (var manager in RicUtils_Settings.singletonManagers) { var type = manager.manager.Type; var method = type.GetMethod("CreateManager", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod | BindingFlags.FlattenHierarchy); diff --git a/Assets/RicUtils/Runtime/RicUtilities.cs b/Assets/RicUtils/Runtime/RicUtilities.cs index d593d1d..bc89ccf 100644 --- a/Assets/RicUtils/Runtime/RicUtilities.cs +++ b/Assets/RicUtils/Runtime/RicUtilities.cs @@ -9,7 +9,7 @@ namespace RicUtils { public static class RicUtilities { - public static T GetAvailableScriptableObject() where T : AvailableScriptableObject where D : CustomScriptableObject + public static T GetAvailableScriptableObject() where T : AvailableScriptableObject where D : GenericScriptableObject { return Resources.Load("Availables/" + GetAvailableScriptableObjectName(typeof(T))); } diff --git a/Assets/RicUtils/package.json b/Assets/RicUtils/package.json index ab48fc0..05d4bb3 100644 --- a/Assets/RicUtils/package.json +++ b/Assets/RicUtils/package.json @@ -1,6 +1,6 @@ { "name": "io.github.app24.ricutils", - "version": "1.2.1", + "version": "1.3.0", "displayName": "RicUtils", "dependencies": { "com.solidalloy.type-references": "2.16.0"