Explorar el Código

feat:新增工程结构自动监测工具以及ET Project资源管理工具 (#389)

Carson - 宝鱼 hace 3 años
padre
commit
40940a25ab

+ 3 - 3
Unity/Assets/Bundles/Config/UnitConfigCategory.bytes

@@ -1,4 +1,4 @@
 
-1é	米克尔"带有强力攻击技能(0²8D
-3ê
-米克尔2"带有强力攻击技能2(0–8N
+/é	米克尔"带有强力攻击技能(0²
+1ê
+米克尔2"带有强力攻击技能2(0–

+ 15 - 0
Unity/Assets/Resources/ETProjectBrowserSettings.asset

@@ -0,0 +1,15 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!114 &11400000
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 0}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 75bfe7d53936a9d4694e2356f5b97304, type: 3}
+  m_Name: ETProjectBrowserSettings
+  m_EditorClassIdentifier: 
+  ListenFolderPath: ../Codes

+ 8 - 0
Unity/Assets/Resources/ETProjectBrowserSettings.asset.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: d940d8328ba537f4f92b20cf82cb733e
+NativeFormatImporter:
+  externalObjects: {}
+  mainObjectFileID: 11400000
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Unity/Assets/Resources/background.png


+ 98 - 0
Unity/Assets/Resources/background.png.meta

@@ -0,0 +1,98 @@
+fileFormatVersion: 2
+guid: 6c8adde126519b1468d6cba84997792c
+TextureImporter:
+  internalIDToNameTable: []
+  externalObjects: {}
+  serializedVersion: 11
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 1
+    sRGBTexture: 1
+    linearTexture: 0
+    fadeOut: 0
+    borderMipMap: 0
+    mipMapsPreserveCoverage: 0
+    alphaTestReferenceValue: 0.5
+    mipMapFadeDistanceStart: 1
+    mipMapFadeDistanceEnd: 3
+  bumpmap:
+    convertToNormalMap: 0
+    externalNormalMap: 0
+    heightScale: 0.25
+    normalMapFilter: 0
+  isReadable: 0
+  streamingMipmaps: 0
+  streamingMipmapsPriority: 0
+  vTOnly: 0
+  ignoreMasterTextureLimit: 0
+  grayScaleToAlpha: 0
+  generateCubemap: 6
+  cubemapConvolution: 0
+  seamlessCubemap: 0
+  textureFormat: 1
+  maxTextureSize: 2048
+  textureSettings:
+    serializedVersion: 2
+    filterMode: 1
+    aniso: 1
+    mipBias: 0
+    wrapU: 0
+    wrapV: 0
+    wrapW: 0
+  nPOTScale: 1
+  lightmap: 0
+  compressionQuality: 50
+  spriteMode: 0
+  spriteExtrude: 1
+  spriteMeshType: 1
+  alignment: 0
+  spritePivot: {x: 0.5, y: 0.5}
+  spritePixelsToUnits: 100
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spriteGenerateFallbackPhysicsShape: 1
+  alphaUsage: 1
+  alphaIsTransparency: 0
+  spriteTessellationDetail: -1
+  textureType: 0
+  textureShape: 1
+  singleChannelComponent: 0
+  flipbookRows: 1
+  flipbookColumns: 1
+  maxTextureSizeSet: 0
+  compressionQualitySet: 0
+  textureFormatSet: 0
+  ignorePngGamma: 0
+  applyGammaDecoding: 0
+  platformSettings:
+  - serializedVersion: 3
+    buildTarget: DefaultTexturePlatform
+    maxTextureSize: 2048
+    resizeAlgorithm: 0
+    textureFormat: -1
+    textureCompression: 1
+    compressionQuality: 50
+    crunchedCompression: 0
+    allowsAlphaSplitting: 0
+    overridden: 0
+    androidETC2FallbackOverride: 0
+    forceMaximumCompressionQuality_BC6H_BC7: 0
+  spriteSheet:
+    serializedVersion: 2
+    sprites: []
+    outline: []
+    physicsShape: []
+    bones: []
+    spriteID: 
+    internalID: 0
+    vertices: []
+    indices: 
+    edges: []
+    weights: []
+    secondaryTextures: []
+    nameFileIdTable: {}
+  spritePackingTag: 
+  pSDRemoveMatte: 0
+  pSDShowRemoveMatteOption: 0
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 107 - 107
Unity/Assets/Scripts/Editor/AssetPostProcessor/OnGenerateCSProjectProcessor.cs

@@ -1,128 +1,128 @@
-using System;
-using UnityEditor;
-using UnityEngine;
-using System.Xml;
-using System.IO;
-using System.Text;
+//using System;
+//using UnityEditor;
+//using UnityEngine;
+//using System.Xml;
+//using System.IO;
+//using System.Text;
 
-namespace ET
-{
-    public class OnGenerateCSProjectProcessor : AssetPostprocessor
-    {
-        public static string OnGeneratedCSProject(string path, string content)
-        {
+//namespace ET
+//{
+//    public class OnGenerateCSProjectProcessor : AssetPostprocessor
+//    {
+//        public static string OnGeneratedCSProject(string path, string content)
+//        {
             
-            if (path.EndsWith("Unity.Hotfix.csproj"))
-            {
-                content =  content.Replace("<Compile Include=\"Assets\\Scripts\\Hotfix\\Empty.cs\" />", string.Empty);
-                content =  content.Replace("<None Include=\"Assets\\Scripts\\Hotfix\\Unity.Hotfix.asmdef\" />", string.Empty);
-            }
+//            if (path.EndsWith("Unity.Hotfix.csproj"))
+//            {
+//                content =  content.Replace("<Compile Include=\"Assets\\Scripts\\Hotfix\\Empty.cs\" />", string.Empty);
+//                content =  content.Replace("<None Include=\"Assets\\Scripts\\Hotfix\\Unity.Hotfix.asmdef\" />", string.Empty);
+//            }
             
-            if (path.EndsWith("Unity.HotfixView.csproj"))
-            {
-                content =  content.Replace("<Compile Include=\"Assets\\Scripts\\HotfixView\\Empty.cs\" />", string.Empty);
-                content =  content.Replace("<None Include=\"Assets\\Scripts\\HotfixView\\Unity.HotfixView.asmdef\" />", string.Empty);
-            }
+//            if (path.EndsWith("Unity.HotfixView.csproj"))
+//            {
+//                content =  content.Replace("<Compile Include=\"Assets\\Scripts\\HotfixView\\Empty.cs\" />", string.Empty);
+//                content =  content.Replace("<None Include=\"Assets\\Scripts\\HotfixView\\Unity.HotfixView.asmdef\" />", string.Empty);
+//            }
             
-            if (path.EndsWith("Unity.Model.csproj"))
-            {
-                content =  content.Replace("<Compile Include=\"Assets\\Scripts\\Model\\Empty.cs\" />", string.Empty);
-                content =  content.Replace("<None Include=\"Assets\\Scripts\\Model\\Unity.Model.asmdef\" />", string.Empty);
-            }
+//            if (path.EndsWith("Unity.Model.csproj"))
+//            {
+//                content =  content.Replace("<Compile Include=\"Assets\\Scripts\\Model\\Empty.cs\" />", string.Empty);
+//                content =  content.Replace("<None Include=\"Assets\\Scripts\\Model\\Unity.Model.asmdef\" />", string.Empty);
+//            }
             
-            if (path.EndsWith("Unity.ModelView.csproj"))
-            {
-                content =  content.Replace("<Compile Include=\"Assets\\Scripts\\ModelView\\Empty.cs\" />", string.Empty);
-                content =  content.Replace("<None Include=\"Assets\\Scripts\\ModelView\\Unity.ModelView.asmdef\" />", string.Empty);
-            }
+//            if (path.EndsWith("Unity.ModelView.csproj"))
+//            {
+//                content =  content.Replace("<Compile Include=\"Assets\\Scripts\\ModelView\\Empty.cs\" />", string.Empty);
+//                content =  content.Replace("<None Include=\"Assets\\Scripts\\ModelView\\Unity.ModelView.asmdef\" />", string.Empty);
+//            }
             
-            if (path.EndsWith("Unity.Hotfix.csproj"))
-            {
-                return GenerateCustomProject(path, content, 
-                    @"..\Codes\Hotfix\Client\**\*.cs Client", 
-                    @"..\Codes\Hotfix\Share\**\*.cs Share",
-                    @"..\Codes\Hotfix\Server\**\*.cs Server"
-                    );
-            }
+//            if (path.EndsWith("Unity.Hotfix.csproj"))
+//            {
+//                return GenerateCustomProject(path, content, 
+//                    @"..\Codes\Hotfix\Client\**\*.cs Client", 
+//                    @"..\Codes\Hotfix\Share\**\*.cs Share",
+//                    @"..\Codes\Hotfix\Server\**\*.cs Server"
+//                    );
+//            }
 
-            if (path.EndsWith("Unity.HotfixView.csproj"))
-            {
-                return GenerateCustomProject(path, content, 
-                    @"..\Codes\HotfixView\Client\**\*.cs Client", 
-                    @"..\Codes\HotfixView\Share\**\*.cs Share"); 
-            }
+//            if (path.EndsWith("Unity.HotfixView.csproj"))
+//            {
+//                return GenerateCustomProject(path, content, 
+//                    @"..\Codes\HotfixView\Client\**\*.cs Client", 
+//                    @"..\Codes\HotfixView\Share\**\*.cs Share"); 
+//            }
 
-            if (path.EndsWith("Unity.Model.csproj"))
-            {
-                return GenerateCustomProject(path, content,
-                    @"..\Codes\Model\Server\**\*.cs Server",
-                    @"..\Codes\Model\Client\**\*.cs Client",
-                    @"..\Codes\Model\Share\**\*.cs Share",
-                    @"..\Codes\Generate\Server\**\*.cs Generate"
-                    );
-            }
+//            if (path.EndsWith("Unity.Model.csproj"))
+//            {
+//                return GenerateCustomProject(path, content,
+//                    @"..\Codes\Model\Server\**\*.cs Server",
+//                    @"..\Codes\Model\Client\**\*.cs Client",
+//                    @"..\Codes\Model\Share\**\*.cs Share",
+//                    @"..\Codes\Generate\Server\**\*.cs Generate"
+//                    );
+//            }
 
-            if (path.EndsWith("Unity.ModelView.csproj"))
-            {
-                return GenerateCustomProject(path, content, 
-                    @"..\Codes\ModelView\Client\**\*.cs Client",
-                    @"..\Codes\ModelView\Share\**\*.cs Share");
-            }
+//            if (path.EndsWith("Unity.ModelView.csproj"))
+//            {
+//                return GenerateCustomProject(path, content, 
+//                    @"..\Codes\ModelView\Client\**\*.cs Client",
+//                    @"..\Codes\ModelView\Share\**\*.cs Share");
+//            }
             
-            return content;
-        }
+//            return content;
+//        }
 
-        private static string GenerateCustomProject(string path, string content, params string[] links)
-        {
-            XmlDocument doc = new XmlDocument();
-            doc.LoadXml(content);
+//        private static string GenerateCustomProject(string path, string content, params string[] links)
+//        {
+//            XmlDocument doc = new XmlDocument();
+//            doc.LoadXml(content);
 
-            var newDoc = doc.Clone() as XmlDocument;
+//            var newDoc = doc.Clone() as XmlDocument;
 
-            var rootNode = newDoc.GetElementsByTagName("Project")[0];
+//            var rootNode = newDoc.GetElementsByTagName("Project")[0];
 
-            XmlElement itemGroup = newDoc.CreateElement("ItemGroup", newDoc.DocumentElement.NamespaceURI);
-            foreach (var s in links)
-            {
-                string[] ss = s.Split(' ');
-                string p = ss[0];
-                string linkStr = ss[1];
-                XmlElement compile = newDoc.CreateElement("Compile", newDoc.DocumentElement.NamespaceURI);
-                XmlElement link = newDoc.CreateElement("Link", newDoc.DocumentElement.NamespaceURI);
-                link.InnerText = $"{linkStr}\\%(RecursiveDir)%(FileName)%(Extension)";
-                compile.AppendChild(link);
-                compile.SetAttribute("Include", p);
-                itemGroup.AppendChild(compile);
-            }
+//            XmlElement itemGroup = newDoc.CreateElement("ItemGroup", newDoc.DocumentElement.NamespaceURI);
+//            foreach (var s in links)
+//            {
+//                string[] ss = s.Split(' ');
+//                string p = ss[0];
+//                string linkStr = ss[1];
+//                XmlElement compile = newDoc.CreateElement("Compile", newDoc.DocumentElement.NamespaceURI);
+//                XmlElement link = newDoc.CreateElement("Link", newDoc.DocumentElement.NamespaceURI);
+//                link.InnerText = $"{linkStr}\\%(RecursiveDir)%(FileName)%(Extension)";
+//                compile.AppendChild(link);
+//                compile.SetAttribute("Include", p);
+//                itemGroup.AppendChild(compile);
+//            }
 
-            var projectReference = newDoc.CreateElement("ProjectReference", newDoc.DocumentElement.NamespaceURI);
-            projectReference.SetAttribute("Include", @"..\Codes\Analyzer\Share.Analyzer.csproj");
-            projectReference.SetAttribute("OutputItemType", @"Analyzer");
-            projectReference.SetAttribute("ReferenceOutputAssembly", @"false");
+//            var projectReference = newDoc.CreateElement("ProjectReference", newDoc.DocumentElement.NamespaceURI);
+//            projectReference.SetAttribute("Include", @"..\Codes\Analyzer\Share.Analyzer.csproj");
+//            projectReference.SetAttribute("OutputItemType", @"Analyzer");
+//            projectReference.SetAttribute("ReferenceOutputAssembly", @"false");
 
-            var project = newDoc.CreateElement("Project", newDoc.DocumentElement.NamespaceURI);
-            project.InnerText = @"{d1f2986b-b296-4a2d-8f12-be9f470014c3}";
-            projectReference.AppendChild(project);
+//            var project = newDoc.CreateElement("Project", newDoc.DocumentElement.NamespaceURI);
+//            project.InnerText = @"{d1f2986b-b296-4a2d-8f12-be9f470014c3}";
+//            projectReference.AppendChild(project);
 
-            var name = newDoc.CreateElement("Name", newDoc.DocumentElement.NamespaceURI);
-            name.InnerText = "Analyzer";
-            projectReference.AppendChild(project);
+//            var name = newDoc.CreateElement("Name", newDoc.DocumentElement.NamespaceURI);
+//            name.InnerText = "Analyzer";
+//            projectReference.AppendChild(project);
 
-            itemGroup.AppendChild(projectReference);
+//            itemGroup.AppendChild(projectReference);
 
-            rootNode.AppendChild(itemGroup);
+//            rootNode.AppendChild(itemGroup);
 
-            using (StringWriter sw = new StringWriter())
-            {
+//            using (StringWriter sw = new StringWriter())
+//            {
 
-                using (XmlTextWriter tx = new XmlTextWriter(sw))
-                {
-                    tx.Formatting = Formatting.Indented;
-                    newDoc.WriteTo(tx);
-                    tx.Flush();
-                    return sw.GetStringBuilder().ToString();
-                }
-            }
-        }
-    }
-}
+//                using (XmlTextWriter tx = new XmlTextWriter(sw))
+//                {
+//                    tx.Formatting = Formatting.Indented;
+//                    newDoc.WriteTo(tx);
+//                    tx.Flush();
+//                    return sw.GetStringBuilder().ToString();
+//                }
+//            }
+//        }
+//    }
+//}

+ 8 - 0
Unity/Assets/Scripts/Editor/CodesListener.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 4a75a6d387d72ab4b9c5941edde72da9
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 177 - 0
Unity/Assets/Scripts/Editor/CodesListener/CodesListenerExecutor.cs

@@ -0,0 +1,177 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Xml.Linq;
+using UnityEditor;
+using UnityEngine;
+public class CodesListenerExecutor
+{
+    public enum CodeClass
+    {
+        Client,
+        Server
+    }
+    public static void Refresh()
+    {
+        //客户端Model
+        RegisterCodeFolder(CodeClass.Client, 
+            "Unity.Model.csproj", "../Codes", 
+            new Dictionary<string, List<string>>() { 
+                { "Model", new List<string>() { "Client", "Share" } }, 
+                { "Generate", new List<string> { "Client", "Share" } } });
+        //客户端Hotfix
+        RegisterCodeFolder(CodeClass.Client, 
+            "Unity.Hotfix.csproj", "../Codes", 
+            new Dictionary<string, List<string>>() { 
+                { "Hotfix", new List<string>() { "Client", "Share" } } });
+        //客户端ModelView
+        RegisterCodeFolder(CodeClass.Client, 
+            "Unity.ModelView.csproj", "../Codes", 
+            new Dictionary<string, List<string>>() { 
+                { "ModelView", new List<string>() { "Client" } } });
+        //客户端HotfixView
+        RegisterCodeFolder(CodeClass.Client, 
+            "Unity.HotfixView.csproj", "../Codes", 
+            new Dictionary<string, List<string>>() { 
+                { "HotfixView", new List<string>() { "Client" } } });
+        //服务端Model
+        RegisterCodeFolder(CodeClass.Server, 
+            "../DotNet/Model/DotNet.Model.csproj", "../Codes", 
+            new Dictionary<string, List<string>>() { 
+                { "Model", new List<string>() { "Server", "Share" ,"Client"} }, 
+                { "Generate", new List<string> { "Server", "Share" } } });
+        //服务端Hotfix
+        RegisterCodeFolder(CodeClass.Server, 
+            "../DotNet/Hotfix/DotNet.Hotfix.csproj", "../Codes", 
+            new Dictionary<string, List<string>>() { 
+                { "Hotfix", new List<string>() { "Server", "Share","Client" } } });
+    }
+
+    public static void RegisterCodeFolder(CodeClass codeClass, string csprojPath, string rootFolder, Dictionary<string, List<string>> asmNames)
+    {
+        List<FileInfo> files = new List<FileInfo>();
+        GetAssemblyCodeFiles(new DirectoryInfo(rootFolder), files, asmNames, string.Empty, 0);
+        var doc = Adjust(codeClass, rootFolder, csprojPath, files);
+        doc.Save(csprojPath);
+        string final = HandleSomeThing(csprojPath, File.ReadAllText(csprojPath));
+        FileInfo fileInfo = new FileInfo(csprojPath);
+        File.WriteAllText(fileInfo.FullName, final);
+    }
+
+    private static string HandleSomeThing(string path, string content)
+    {
+        if (path.EndsWith("Unity.Hotfix.csproj"))
+        {
+            content = content.Replace("<Compile Include=\"Assets\\Scripts\\Hotfix\\Empty.cs\" />", string.Empty);
+            content = content.Replace("<None Include=\"Assets\\Scripts\\Hotfix\\Unity.Hotfix.asmdef\" />", string.Empty);
+        }
+
+        if (path.EndsWith("Unity.HotfixView.csproj"))
+        {
+            content = content.Replace("<Compile Include=\"Assets\\Scripts\\HotfixView\\Empty.cs\" />", string.Empty);
+            content = content.Replace("<None Include=\"Assets\\Scripts\\HotfixView\\Unity.HotfixView.asmdef\" />", string.Empty);
+        }
+
+        if (path.EndsWith("Unity.Model.csproj"))
+        {
+            content = content.Replace("<Compile Include=\"Assets\\Scripts\\Model\\Empty.cs\" />", string.Empty);
+            content = content.Replace("<None Include=\"Assets\\Scripts\\Model\\Unity.Model.asmdef\" />", string.Empty);
+        }
+
+        if (path.EndsWith("Unity.ModelView.csproj"))
+        {
+            content = content.Replace("<Compile Include=\"Assets\\Scripts\\ModelView\\Empty.cs\" />", string.Empty);
+            content = content.Replace("<None Include=\"Assets\\Scripts\\ModelView\\Unity.ModelView.asmdef\" />", string.Empty);
+        }
+        return content;
+    }
+
+    private static void GetAssemblyCodeFiles(DirectoryInfo parent, List<FileInfo> files, Dictionary<string, List<string>> asmNames, string key, int depth)
+    {
+        if (depth > 1)
+        {
+            return;
+        }
+        foreach (var dir in parent.GetDirectories())
+        {
+            if (depth == 0 && asmNames.Keys.Contains(dir.Name))
+            {
+                //第一层通过,进入第二层
+                GetAssemblyCodeFiles(dir, files, asmNames, dir.Name, 1);
+            }
+            else if (depth == 1 && asmNames.TryGetValue(key, out var second) && second.Contains(dir.Name))
+            {
+                foreach (var file in dir.GetFiles("*.cs", SearchOption.AllDirectories))
+                {
+                    files.Add(file);
+                }
+            }
+            else
+            {
+                GetAssemblyCodeFiles(dir, files, asmNames, key, depth);
+            }
+        }
+    }
+
+    private static string analyzerPath = @"..\Codes\Analyzer\Share.Analyzer.csproj";
+    public static XDocument Adjust(CodeClass codeClass, string workPlace, string csprojPath, List<FileInfo> files)
+    {
+        DirectoryInfo workPlaceDir = new DirectoryInfo(workPlace);
+        workPlace = workPlaceDir.FullName.Replace("/", "\\");
+        XDocument doc = XDocument.Load(csprojPath);
+        XElement project = doc.Elements().First(e => e.Name.LocalName == "Project");
+        var comments = doc.Nodes().Where(n => n.NodeType == System.Xml.XmlNodeType.Comment).ToList();
+        foreach (var c in comments)
+        {
+            c.Remove();
+        }
+        var itemGroups = project.Elements().Where(e => e.Name.LocalName == "ItemGroup");
+        List<XElement> delCompile = new List<XElement>();
+        foreach (XElement itemGroup in itemGroups)
+        {
+            foreach (var element in itemGroup.Elements())
+            {
+                if (element.Name.LocalName == "Compile")
+                {
+                    delCompile.Add(element);
+                }
+                if (element.Name.LocalName == "ProjectReference")
+                {
+                    XAttribute includeAttr = element.Attribute("Include");
+                    if (includeAttr != null && includeAttr.Value == analyzerPath)
+                    {
+                        delCompile.Add(element);
+                    }
+                }
+            }
+        }
+        foreach (XElement item in delCompile)
+        {
+            item.Remove();
+        }
+        foreach (var csFile in files)
+        {
+            string fullPath = csFile.FullName.Replace("/", "\\");
+            XElement firstItemGroup = project.Elements().First(e => e.Name.LocalName == "ItemGroup");
+            XElement compile = new XElement(project.Name.ToString().Replace("Project", "Compile"), new XAttribute("Include", fullPath));
+            XElement link = new XElement(project.Name.ToString().Replace("Project", "Link"));
+            link.SetValue(fullPath.Substring(workPlace.Length + 1));
+            compile.Add(link);
+            firstItemGroup.Add(compile);
+        }
+        XElement lastItemGroup = project.Elements().Last(e => e.Name.LocalName == "ItemGroup");
+        XElement projectReference = new XElement(project.Name.ToString().Replace("Project", "ProjectReference"));
+        projectReference.SetAttributeValue("Include", analyzerPath);
+        projectReference.SetAttributeValue("OutputItemType", @"Analyzer");
+        projectReference.SetAttributeValue("ReferenceOutputAssembly", @"false");
+        if (codeClass == CodeClass.Client)
+        {
+            XElement projectItem = new XElement(project.Name.ToString());
+            projectItem.Value = @"{d1f2986b-b296-4a2d-8f12-be9f470014c3}";
+            projectReference.Add(projectItem);
+        }
+        lastItemGroup.Add(projectReference);
+        return doc;
+    }
+}

+ 11 - 0
Unity/Assets/Scripts/Editor/CodesListener/CodesListenerExecutor.cs.meta

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

+ 305 - 0
Unity/Assets/Scripts/Editor/CodesListener/ETProjectBrowser.cs

@@ -0,0 +1,305 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using Unity.CodeEditor;
+using UnityEditor;
+using UnityEditor.Build.Content;
+using UnityEngine;
+public class ETProjectBrowser : EditorWindow
+{
+    [MenuItem("ET/ET Project")]
+    public static ETProjectBrowser Open()
+    {
+        var window = GetWindow<ETProjectBrowser>("ET Project");
+        window.Show();
+        return window;
+    }
+    private string _settingsAssetPath = "Assets/Resources/ETProjectBrowserSettings.asset";
+    private ETProjectBrowserSettings _settings;
+    private List<string> _ignoreDirs = new List<string>() { "Analyzer" };
+    private List<string> _selectedPaths;
+    private TreeNode _root;
+    private FileSystemWatcher _watcher;
+    private Texture2D _texture;
+    private bool _autoFresh = false;
+
+    private void OnEnable()
+    {
+        _settings = AssetDatabase.LoadAssetAtPath<ETProjectBrowserSettings>(_settingsAssetPath);
+        _selectedPaths = new List<string>(10);
+        StartListening();
+        _texture = Resources.Load<Texture2D>("background");
+    }
+
+    private void StartListening()
+    {
+        if (_settings != null)
+        {
+            _watcher = new FileSystemWatcher(_settings.ListenFolderInfo.FullName);
+            _watcher.IncludeSubdirectories = true;
+            _watcher.EnableRaisingEvents = true;
+            _watcher.Created += SetTreeNodes;
+            _watcher.Deleted += SetTreeNodes;
+        }
+        Refresh();
+    }
+    private void OnDisable()
+    {
+        if (_watcher != null)
+        {
+            _watcher.Dispose();
+        }
+    }
+    //Layout members
+    private void OnGUI()
+    {
+        if (_settings == null)
+        {
+            if (GUILayout.Button("请创建配置文件"))
+            {
+                FileInfo fi = new FileInfo(_settingsAssetPath);
+                if (!fi.Directory.Exists)
+                {
+                    fi.Directory.Create();
+                }
+                _settings = CreateInstance<ETProjectBrowserSettings>();
+                AssetDatabase.CreateAsset(_settings, _settingsAssetPath);
+            }
+            return;
+        }
+        if (string.IsNullOrEmpty(_settings.ListenFolderPath))
+        {
+            GUILayout.BeginHorizontal();
+            GUILayout.Label("请至少指定一个ET Project目录");
+            GUILayout.EndHorizontal();
+            return;
+        }
+        else
+        {
+            if (GUILayout.Button("刷新工程"))
+            {
+                Refresh(true);
+            }
+            _autoFresh = GUILayout.Toggle(_autoFresh, "开启自动刷新工程");
+            GUILayout.BeginHorizontal();
+            _scrollPos = EditorGUILayout.BeginScrollView(_scrollPos);
+            int _ = 0;
+            int min = Mathf.RoundToInt(_scrollPos.y / 20);
+            int max = min + 20;
+            DrawTreeNodes(_root, ref _, min, max);
+            EditorGUILayout.EndScrollView();
+            GUILayout.EndHorizontal();
+        }
+    }
+
+    private (string name, DateTime time) _clickToken;
+    private TreeNode currentNode;
+    private Vector2 _scrollPos;
+
+    private void DrawTreeNodes(TreeNode parent, ref int index, int min, int max)
+    {
+        foreach (var node in parent.Children)
+        {
+            bool render = true;
+            index++;
+            if (node.Type == TreeNode.NodeType.Folder)
+            {
+                if (render)
+                {
+                    EditorGUILayout.BeginHorizontal();
+                    GUILayout.Space(10 * node.Level);
+                    if (GUILayout.Button("…", GUILayout.MaxWidth(20)))
+                    {
+                        Event evt = Event.current;
+                        Vector2 pos = evt.mousePosition;
+                        ETProjectBrowserMenusItem.Path = node.FullName;
+                        ETProjectBrowserMenusItem.Refresh = EditFolder;
+                        EditorUtility.DisplayPopupMenu(new Rect(pos.x, pos.y, 0, 0), "ET/ET Project Menus/Folder", null);
+                    }
+                    var icon = EditorGUIUtility.IconContent("Folder Icon");
+                    if (node.Children == null || node.Children.Count == 0)
+                    {
+                        icon = EditorGUIUtility.IconContent("FolderEmpty Icon");
+                    }
+                    icon.text = node.Name;
+                    node.Selected = EditorGUILayout.Foldout(node.Selected, icon, true);
+                    if (node.Selected)
+                    {
+                        if (!_selectedPaths.Contains(node.FullName))
+                        {
+                            _selectedPaths.Add(node.FullName);
+                        }
+                    }
+                    else
+                    {
+                        if (_selectedPaths.Contains(node.FullName))
+                        {
+                            _selectedPaths.Remove(node.FullName);
+                        }
+                    }
+                    EditorGUILayout.EndHorizontal();
+                }
+                if (node.Selected)
+                {
+                    DrawTreeNodes(node, ref index, min, max);
+                }
+            }
+            else
+            {
+                if (render)
+                {
+                    var style = new GUIStyle();
+                    if (currentNode == node)
+                    {
+                        style.normal.background = _texture;
+                    }
+                    EditorGUILayout.BeginHorizontal(style);
+                    GUILayout.Space(10 * node.Level);
+                    if (GUILayout.Button("…", GUILayout.MaxWidth(20)))
+                    {
+                        Event evt = Event.current;
+                        Vector2 pos = evt.mousePosition;
+                        ETProjectBrowserMenusItem.Path = node.FullName;
+                        ETProjectBrowserMenusItem.Refresh = EditFolder;
+                        EditorUtility.DisplayPopupMenu(new Rect(pos.x, pos.y, 0, 0), "ET/ET Project Menus/Script", null);
+                    }
+                    GUILayout.Label(EditorGUIUtility.IconContent("cs Script Icon"), GUILayout.MaxHeight(20), GUILayout.MaxWidth(20));
+                    if (GUILayout.Button(node.Name, new GUIStyle("Label")))
+                    {
+                        currentNode = node;
+                        DateTime lastClickTime = _clickToken.time;
+                        if ((DateTime.Now - lastClickTime).TotalSeconds < 0.5 && !string.IsNullOrEmpty(_clickToken.name) && _clickToken.name == node.FullName)
+                        {
+                            CodeEditor.CurrentEditor.OpenProject(node.FullName);
+                        }
+                        _clickToken = (node.FullName, DateTime.Now);
+                    }
+                    EditorGUILayout.EndHorizontal();
+                }
+            }
+        }
+    }
+
+    private void EditFolder(string dirName)
+    {
+        if (!string.IsNullOrEmpty(dirName))
+        {
+            if (!_selectedPaths.Contains(dirName))
+            {
+                _selectedPaths.Add(dirName);
+            }
+        }
+        Refresh();
+    }
+
+    private void Refresh(bool force = false)
+    {
+        SetTreeNodes(null, null);
+        if (_autoFresh || force)
+        {
+            RefreshCsprojs();
+        }
+    }
+    private void RefreshCsprojs()
+    {
+        CodesListenerExecutor.Refresh();
+    }
+    private void SetTreeNodes(object sender, FileSystemEventArgs e)
+    {
+        if (!Directory.Exists(_settings.ListenFolderPath))
+        {
+            return;
+        }
+        TreeNode root = new TreeNode(_settings.ListenFolderInfo.FullName);
+        List<TreeNode> nodes = new List<TreeNode>(512) { root };
+        List<string> selectedPaths = new List<string>(10);
+        GetTreeNodes(root, nodes, selectedPaths, 0);
+        _root = root;
+        _selectedPaths = selectedPaths;
+    }
+
+
+    private void GetTreeNodes(TreeNode parent, List<TreeNode> list, List<string> selectedPaths, int level)
+    {
+        if (!parent.Exist)
+        {
+            return;
+        }
+        //深度优先,文件夹在上面
+        foreach (string dir in Directory.GetDirectories(parent.FullName))
+        {
+            if (_ignoreDirs.Contains(Path.GetFileName(dir)))
+            {
+                continue;
+            }
+            TreeNode node = new TreeNode(parent, dir, TreeNode.NodeType.Folder);
+            if (_selectedPaths.Contains(dir))
+            {
+                node.Selected = true;
+                selectedPaths.Add(dir);
+            }
+            list.Add(node);
+            node.Level = level;
+            GetTreeNodes(node, list, selectedPaths, level + 1);
+            node.Parent = parent;
+        }
+        foreach (string dir in Directory.GetFiles(parent.FullName, "*.cs"))
+        {
+            if (_ignoreDirs.Contains(Path.GetFileName(dir)))
+            {
+                continue;
+            }
+            TreeNode node = new TreeNode(parent, dir, TreeNode.NodeType.Item);
+            node.Parent = parent;
+            node.Level = level;
+            list.Add(node);
+        }
+    }
+}
+
+public class TreeNode
+{
+    public string Name { get; }
+    public int Level { get; set; }
+    public string FullName { get; }
+    public NodeType Type { get; }
+    public bool Selected { get; set; }
+    public List<TreeNode> Children { get; }
+    public TreeNode Parent { get; set; }
+    public bool Exist => Directory.Exists(FullName);
+
+    public enum NodeType
+    {
+        Folder,
+        Item,
+    }
+    public TreeNode(string path)
+    {
+        Name = Path.GetFileName(path);
+        FullName = path;
+        Type = NodeType.Folder;
+        Children = new List<TreeNode>();
+    }
+    public TreeNode(TreeNode parent, string path, NodeType type)
+    {
+        Parent = parent;
+        Name = Path.GetFileName(path);
+        FullName = path;
+        Type = type;
+        if (type == NodeType.Folder)
+        {
+            Children = new List<TreeNode>();
+        }
+        Parent.AddChild(this);
+    }
+
+    private void AddChild(TreeNode node)
+    {
+        Children.Add(node);
+    }
+    public override string ToString()
+    {
+        return FullName;
+    }
+}

+ 11 - 0
Unity/Assets/Scripts/Editor/CodesListener/ETProjectBrowser.cs.meta

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

+ 50 - 0
Unity/Assets/Scripts/Editor/CodesListener/ETProjectBrowserMenusItem.cs

@@ -0,0 +1,50 @@
+using System;
+using System.IO;
+using UnityEditor;
+
+public class ETProjectBrowserMenusItem
+{
+    public static string Path;
+    public static Action<string> Refresh;
+    [MenuItem("ET/ET Project Menus/Folder/创建脚本")]
+    public static void CreateScript()
+    {
+        ETProjectMenusWindow.Open(Path, ETProjectMenusWindow.Mode.CreateScript, Refresh);
+    }
+    [MenuItem("ET/ET Project Menus/Script/重命名脚本")]
+    public static void RenameScript()
+    {
+        ETProjectMenusWindow.Open(Path, ETProjectMenusWindow.Mode.RenamScript, Refresh);
+    }
+    [MenuItem("ET/ET Project Menus/Script/删除脚本")]
+    public static void DeleteScript()
+    {
+        FileInfo fileInfo = new FileInfo(Path);
+        if (EditorUtility.DisplayDialog("删除文件", $"确定删除{fileInfo.Name}吗", "确定", "不了"))
+        {
+            File.Delete(fileInfo.FullName);
+            Refresh?.Invoke(null);
+        }
+    }
+    [MenuItem("ET/ET Project Menus/Folder/创建目录")]
+    public static void CreateFolder()
+    {
+        ETProjectMenusWindow.Open(Path, ETProjectMenusWindow.Mode.CreateFolder, Refresh);
+    }
+    [MenuItem("ET/ET Project Menus/Folder/重命名目录")]
+    public static void RenameFolder()
+    {
+        ETProjectMenusWindow.Open(Path, ETProjectMenusWindow.Mode.RenameFolder, Refresh);
+    }
+    [MenuItem("ET/ET Project Menus/Folder/删除目录")]
+    public static void DeleteFolder()
+    {
+        DirectoryInfo dirInfo = new DirectoryInfo(Path);
+
+        if (EditorUtility.DisplayDialog("删除文件夹", $"确定删除{dirInfo.Name}吗", "确定", "不了"))
+        {
+            Directory.Delete(dirInfo.FullName, true);
+            Refresh?.Invoke(null);
+        }
+    }
+}

+ 11 - 0
Unity/Assets/Scripts/Editor/CodesListener/ETProjectBrowserMenusItem.cs.meta

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

+ 10 - 0
Unity/Assets/Scripts/Editor/CodesListener/ETProjectBrowserSettings.cs

@@ -0,0 +1,10 @@
+using System.Collections.Generic;
+using System.IO;
+using UnityEngine;
+
+public class ETProjectBrowserSettings : ScriptableObject
+{
+    public string ListenFolderPath = "../Codes";
+    private DirectoryInfo _dir;
+    public DirectoryInfo ListenFolderInfo => _dir ??= new DirectoryInfo(ListenFolderPath);
+}

+ 11 - 0
Unity/Assets/Scripts/Editor/CodesListener/ETProjectBrowserSettings.cs.meta

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

+ 156 - 0
Unity/Assets/Scripts/Editor/CodesListener/ETProjectMenusWindow.cs

@@ -0,0 +1,156 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using UnityEditor;
+using UnityEngine;
+
+public class ETProjectMenusWindow : EditorWindow
+{
+    public enum Mode
+    {
+        CreateScript,
+        CreateFolder,
+        RenameFolder,
+        RenamScript
+    }
+    public static ETProjectMenusWindow Open(string fullPath, Mode mode, Action<string> refresh)
+    {
+        if (string.IsNullOrEmpty(fullPath))
+        {
+            return null;
+        }
+        string title = (mode) switch
+        {
+            Mode.CreateScript => "创建脚本",
+            Mode.CreateFolder => "创建目录",
+            Mode.RenameFolder => "重命名脚本",
+            Mode.RenamScript => "重命名目录",
+            _ => mode.ToString(),
+        };
+        var window = GetWindow<ETProjectMenusWindow>(false, title);
+        window._fullPath = fullPath;
+        window._mode = mode;
+        window._refresh = refresh;
+        window.minSize = new Vector2(200, 40);
+        window.maxSize = new Vector2(200, 40);
+
+        window.Show();
+        return window;
+    }
+    string _fullPath;
+    private Mode _mode;
+    string _textFieldStr = string.Empty;
+    private Action<string> _refresh;
+    private bool _focus = false;
+
+    private void OnEnable()
+    {
+        _focus = true;
+    }
+    private void OnDisable()
+    {
+        ETProjectBrowserMenusItem.Path = string.Empty;
+        ETProjectBrowserMenusItem.Refresh = null;
+    }
+    private void OnGUI()
+    {
+        GUI.SetNextControlName("TextField");
+        _textFieldStr = GUILayout.TextField(_textFieldStr, new GUIStyle("TextField") { alignment = TextAnchor.MiddleCenter });
+        if (_focus)
+        {
+            EditorGUI.FocusTextInControl("TextField");
+            _focus = false;
+        }
+        string btnName = (_mode) switch
+        {
+            Mode.CreateScript => "创建脚本",
+            Mode.CreateFolder => "创建目录",
+            Mode.RenameFolder => "重命名脚本",
+            Mode.RenamScript => "重命名目录",
+            _ => _mode.ToString(),
+        };
+        if (GUILayout.Button(btnName))
+        {
+            switch (_mode)
+            {
+                case Mode.CreateScript:
+                    {
+                        if (_textFieldStr.Contains("/") || _textFieldStr.Contains("\\"))
+                        {
+                            EditorUtility.DisplayDialog("错误", "这个名字不合法", "关闭");
+                            return;
+                        }
+                        if (!_textFieldStr.EndsWith(".cs"))
+                        {
+                            _textFieldStr += ".cs";
+                        }
+                        DirectoryInfo dirInfo = new DirectoryInfo(_fullPath);
+                        string name = Path.GetFileNameWithoutExtension(_textFieldStr);
+                        string template = File.ReadAllText("Assets/Scripts/Editor/CodesListener/template.txt");
+                        File.WriteAllText(Path.Combine(dirInfo.FullName, _textFieldStr), template.Replace("#CLASS_NAME#", name));
+                        _refresh?.Invoke(dirInfo.FullName);
+                        Close();
+                        break;
+                    }
+                case Mode.CreateFolder:
+                    {
+                        if (_textFieldStr.Contains("/") || _textFieldStr.Contains("\\"))
+                        {
+                            EditorUtility.DisplayDialog("错误", "这个名字不合法", "关闭");
+                            return;
+                        }
+                        DirectoryInfo dirInfo = new DirectoryInfo(_fullPath);
+                        Directory.CreateDirectory(Path.Combine(dirInfo.FullName, _textFieldStr));
+                        _refresh?.Invoke(dirInfo.FullName);
+                        Close();
+                        break;
+                    }
+                case Mode.RenamScript:
+                    {
+                        FileInfo file = new FileInfo(_fullPath);
+                        if (_textFieldStr.Contains("/") || _textFieldStr.Contains("\\"))
+                        {
+                            EditorUtility.DisplayDialog("错误", "这个名字不合法", "关闭");
+                            return;
+                        }
+                        if (!_textFieldStr.EndsWith(".cs"))
+                        {
+                            _textFieldStr += ".cs";
+                        }
+                        string dest = Path.Combine(file.Directory.FullName, _textFieldStr);
+
+                        if (File.Exists(dest))
+                        {
+                            EditorUtility.DisplayDialog("错误", "这个已存在同名文件", "关闭");
+                            return;
+                        }
+                        File.Move(file.FullName, dest);
+                        _refresh?.Invoke(null);
+                        break;
+                    }
+                case Mode.RenameFolder:
+                    {
+                        if (_textFieldStr.Contains("/") || _textFieldStr.Contains("\\"))
+                        {
+                            EditorUtility.DisplayDialog("错误", "这个名字不合法", "关闭");
+                            return;
+                        }
+                        DirectoryInfo dirInfo = new DirectoryInfo(_fullPath);
+                        string dest = Path.Combine(dirInfo.Parent.FullName, _textFieldStr);
+
+                        if (File.Exists(dest))
+                        {
+                            EditorUtility.DisplayDialog("错误", "这个已存在同名文件", "关闭");
+                            return;
+                        }
+                        Directory.Move(dirInfo.FullName, dest);
+                        _refresh?.Invoke(dest);
+                        Close();
+                        break;
+                    }
+            }
+        }
+
+    }
+}

+ 11 - 0
Unity/Assets/Scripts/Editor/CodesListener/ETProjectMenusWindow.cs.meta

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

+ 6 - 0
Unity/Assets/Scripts/Editor/CodesListener/template.txt

@@ -0,0 +1,6 @@
+namespace ET
+{
+    public class #CLASS_NAME#
+    {
+    }
+}

+ 7 - 0
Unity/Assets/Scripts/Editor/CodesListener/template.txt.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: ddd64cbe8631d0249b3ac2ce658aa48d
+TextScriptImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: