using System; using System.Collections.Generic; using System.IO; using System.Linq; using Sirenix.OdinInspector; using Sirenix.OdinInspector.Editor; using UnityEditor; using UnityEngine; using UnityEngine.Serialization; namespace Stary.Evo.Editor { public class ArtServerManageWindow : OdinEditorWindow { [MenuItem("Evo/Art/服务器数据管理工具", false, 1)] static void Init() { // Get existing open window or if none, make a new one: ArtServerManageWindow window = (ArtServerManageWindow)EditorWindow.GetWindow(typeof(ArtServerManageWindow)); window.Show(); } [BoxGroup("Selection")] [EnumToggleButtons, HideLabel] [OnValueChanged("SetUseTypeData")] public UseType useType = UseType.Member; private static DeviceMode _DeviceMode = DeviceMode.Evo_Rokid; [BoxGroup("Selection")] [ShowInInspector, ShowIf("@useType == UseType.Art")] public DeviceMode deviceMode { get => _DeviceMode; set { _DeviceMode = value; } } private string _titleGroupName; [TitleGroup("@ _titleGroupName")] public string productName; [TitleGroup("@ _titleGroupName")] [Button("@ _titleGroupName", ButtonSizes.Large)] public void CreatDomain() { if (useType == UseType.Member) { CreatMemberFiled(); } else if (useType == UseType.Art) { CreatArtFiled(); } } /// /// 创建项目目录 /// private void CreatArtFiled() { if (string.IsNullOrEmpty(productName)) { EditorUtility.DisplayDialog("错误!", "请输入将要创建Art的编号", "确定"); return; } string artDomainPath = $"{Application.dataPath}/Art/{productName}"; if (!Directory.Exists(artDomainPath)) { Directory.CreateDirectory(artDomainPath); if (!Directory.Exists(artDomainPath)) //创建Animation文件夹 CreatDirectory(artDomainPath + "/Animation"); //创建Effects文件夹 CreatDirectory(artDomainPath + "/Effects"); //创建Fbx文件夹 CreatDirectory(artDomainPath + "/Fbx"); //创建Font文件夹 CreatDirectory(artDomainPath + "/Font"); //创建Materials文件夹 CreatDirectory(artDomainPath + "/Materials"); //创建Prefabs文件夹 CreatDirectory(artDomainPath + "/Prefabs"); //创建Scenes文件夹 CreatDirectory(artDomainPath + "/Scenes"); //创建/Scenes/Test文件夹 CreatDirectory(artDomainPath + "/Scenes"); //创建Shader文件夹 CreatDirectory(artDomainPath + "/Shader"); //创建Textures文件夹 CreatDirectory(artDomainPath + "/Textures"); File.WriteAllTextAsync( $"{artDomainPath}/这里放所有美术的资源,因涉及打包依赖等原因,不建议在上一层节点新增文件夹,如涉及文件夹规范等问题请@张铮.hint", ""); } //创建Art 测试场景 /* 2. 再建 Scenes/Test */ string sceneDir = $"{artDomainPath}/Scenes"; if (!Directory.Exists(sceneDir)) { Directory.CreateDirectory(sceneDir); } /* 3. 创建新场景 */ var newScene = UnityEditor.SceneManagement.EditorSceneManager.NewScene( UnityEditor.SceneManagement.NewSceneSetup.DefaultGameObjects, UnityEditor.SceneManagement.NewSceneMode.Single); /* 4. 删除默认相机(和灯光)*/ foreach (var go in newScene.GetRootGameObjects()) { if (go.name == "Main Camera" || go.name == "Directional Light") GameObject.DestroyImmediate(go); } /* 5. 载入并实例化 RKCameraRig.prefab */ if (deviceMode == DeviceMode.Evo_Rokid) { string prefabPath = "Prefabs/BaseSetting/RKCameraRig"; var prefab = Resources.Load(prefabPath); var spawned = (GameObject)PrefabUtility.InstantiatePrefab(prefab); spawned.name = "RKCameraRigTest"; } else { string prefabPath = "Prefabs/BaseSetting/RKCameraRig"; // 模糊搜索 GameObject prefab = LoadByFuzzy(); GameObject instance = null; if (prefab != null) { instance = (GameObject)PrefabUtility.InstantiatePrefab(prefab); instance.transform.position = Vector3.zero; Debug.Log($"✅ 已加载: {prefab.name}"); } else { Debug.LogError($"无法加载 Prefab: {prefabPath}\n请检查路径是否正确,或 XR Interaction Toolkit 样本是否已导入。"); return; } // 选中并聚焦 // Selection.activeGameObject = instance; // EditorGUIUtility.PingObject(instance); if (instance) Debug.Log($"成功加载: {instance.name}"); } /* 6. 保存场景 */ string scenePath = Path.Combine("Assets/Art", productName, "Scenes", "TestScene.unity"); UnityEditor.SceneManagement.EditorSceneManager.SaveScene(newScene, scenePath); CreatArtDomainEntity creatArtDomainEntity = new CreatArtDomainEntity(artList); creatArtDomainEntity.DomainName = productName; creatArtDomainEntity.domainPath = artDomainPath; artList.Add(creatArtDomainEntity); } GameObject LoadByFuzzy() { // 通过文件名模糊搜索,完全无视路径 var guids = AssetDatabase.FindAssets("XR Origin (XR Rig) t:Prefab"); if (guids.Length == 0) { Debug.LogError("未找到 XR Origin (XR Rig) Prefab"); return null; } // 如果找到多个,优先选择 XR Interaction Toolkit 路径下的 foreach (var guid in guids) { string path = AssetDatabase.GUIDToAssetPath(guid); if (path.Contains("XR Interaction Toolkit")) { return AssetDatabase.LoadAssetAtPath(path); } } // 默认返回第一个 return AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(guids[0])); } /// /// 创建成员目录 /// private void CreatMemberFiled() { if (string.IsNullOrEmpty(productName)) { EditorUtility.DisplayDialog("错误!", "请输入将要创建成员的编号", "确定"); return; } //检测成员是否存在 bool isExit = false; foreach (var domainEntity in domainMemberList) { if (domainEntity.DomainName == productName) { isExit = true; break; } } if (isExit) { EditorUtility.DisplayDialog("错误!", "当前成员已在服务器中存在,无需重复创建", "确定"); return; } string memberDomainPath = $"{Application.dataPath}/Member/{productName}"; if (!Directory.Exists(memberDomainPath)) { Directory.CreateDirectory(memberDomainPath); //创建Config文件夹 CreatDirectory(memberDomainPath + "/Config"); //创建Scenes文件夹 CreatDirectory(memberDomainPath + "/Scenes"); File.WriteAllTextAsync( $"{memberDomainPath}/这里是成员打包目录,因涉及打包依赖等原因,不建议在上一层节点新增文件夹,如涉及文件夹规范等问题请@张铮.hint", ""); } //创建Art 测试场景配置文件 string configDir = $"{memberDomainPath}/Config"; //模块配置资源 ArtSceneData artSceneData = CreateInstance(); AssetDatabase.CreateAsset(artSceneData, $"Assets/Member/{productName}/Config/ArtSceneData.asset"); CreatMemberServerDomainEntity creatMemberServerDomainEntity = new CreatMemberServerDomainEntity(domainMemberList); creatMemberServerDomainEntity.DomainName = productName; creatMemberServerDomainEntity.domainPath = memberDomainPath; domainMemberList.Add(creatMemberServerDomainEntity); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); creatMemberServerDomainEntity.SetArtSceneData(); } [ShowIf("IsMember")] [ListDrawerSettings(DraggableItems = false, ShowFoldout = false, ShowPaging = false, ShowItemCount = false, HideRemoveButton = true, HideAddButton = true)] public List domainMemberList; [ShowIf("IsProject")] [ListDrawerSettings(DraggableItems = false, ShowFoldout = false, ShowPaging = false, ShowItemCount = false, HideRemoveButton = true, HideAddButton = true)] public List artList; protected override async void Initialize() { base.Initialize(); SetUseTypeData(); if (domainMemberList != null) { domainMemberList.Clear(); } domainMemberList = new List(); var resDmainResponse = await ArtLoadAssetServer.GetServerDomainAll(); foreach (var response in resDmainResponse) { string domainPath = $"{Application.dataPath}/Member/{response.DomainName}"; var domainEntity = new CreatMemberServerDomainEntity(domainMemberList); domainEntity.SetDomainData(response.DomainName, domainPath, response, ArtLoadAssetServer.ip); domainMemberList.Add(domainEntity); } //添加本地Member GetMemberLocalAll(); artList = GetCreatDomainAll(); } private static void CreatDirectory(string artDomainPath) { if (!Directory.Exists(artDomainPath)) { Directory.CreateDirectory(artDomainPath); } } public void CreateDomainDirectory(string domain) { string artDomainPath = ""; if (useType == UseType.Member) { artDomainPath = $"{Application.dataPath}/Member/{domain}"; } else if (useType == UseType.Art) { artDomainPath = $"{Application.dataPath}/Art/{domain}"; if (!Directory.Exists(artDomainPath)) { EditorUtility.DisplayDialog("提示", $"不存在此Domain:{domain},无法创建", "确定"); return; } } if (useType == UseType.Member) { //创建Config文件夹 CreatDirectory(artDomainPath + "/Config"); //创建Scenes文件夹 CreatDirectory(artDomainPath + "/Scenes"); //创建/Scenes/Test文件夹 CreatDirectory(artDomainPath + "/Scenes/Test"); //创建Art 测试场景配置文件 string configDir = $"{artDomainPath}/Config"; // 检测目标文件是否已存在 string assetPath = $"Assets/Member/{domain}/Config/ArtSceneData.asset"; if (File.Exists($"{Application.dataPath}/../{assetPath}")) { Debug.LogWarning($"ArtSceneData.asset 已存在: {assetPath}"); // 可选:询问是否覆盖 if (EditorUtility.DisplayDialog("文件已存在", $"ArtSceneData.asset 已存在,是否覆盖?", "覆盖", "取消")) { // 删除现有文件 AssetDatabase.DeleteAsset(assetPath); AssetDatabase.Refresh(); // 创建新的ArtSceneData ArtSceneData artSceneData = CreateInstance(); AssetDatabase.CreateAsset(artSceneData, assetPath); Debug.Log($"已覆盖 ArtSceneData: {assetPath}"); } else { Debug.Log("用户取消创建 ArtSceneData"); } } else { // 文件不存在,直接创建 ArtSceneData artSceneData = CreateInstance(); AssetDatabase.CreateAsset(artSceneData, assetPath); Debug.Log($"已创建 ArtSceneData: {assetPath}"); } AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); } else if (useType == UseType.Art) { //创建Animation文件夹 CreatDirectory(artDomainPath + "/Animation"); //创建Effects文件夹 CreatDirectory(artDomainPath + "/Effects"); //创建Fbx文件夹 CreatDirectory(artDomainPath + "/Fbx"); //创建Font文件夹 CreatDirectory(artDomainPath + "/Font"); //创建Materials文件夹 CreatDirectory(artDomainPath + "/Materials"); //创建Prefabs文件夹 CreatDirectory(artDomainPath + "/Prefabs"); //创建Scenes文件夹 CreatDirectory(artDomainPath + "/Scenes"); //创建/Scenes/Test文件夹 CreatDirectory(artDomainPath + "/Scenes/Test"); //创建Shader文件夹 CreatDirectory(artDomainPath + "/Shader"); //创建Textures文件夹 CreatDirectory(artDomainPath + "/Textures"); } AssetDatabase.Refresh(); } /// /// 获取全部作用域 /// private static List GetCreatDomainAll() { string domainPath = $"{Application.dataPath}/Art"; string[] domains; // 新增目录获取代码 if (Directory.Exists(domainPath)) { var dirInfo = new DirectoryInfo(domainPath); // 获取直接子目录(不递归) domains = dirInfo.GetDirectories("*", SearchOption.TopDirectoryOnly) .Select(d => d.Name) .ToArray(); } else { domains = Array.Empty(); } List domainList = new List(); foreach (var item in domains) { if (Directory.Exists($"{domainPath}/{item}")) { CreatArtDomainEntity domainEntity = new CreatArtDomainEntity(domainList) { DomainName = item, domainPath = $"{domainPath}/{item}" }; domainList.Add(domainEntity); } } return domainList; } /// /// 获取全部作用域 /// private void GetMemberLocalAll() { string domainPath = $"{Application.dataPath}/Member"; string[] domains; // 新增目录获取代码 if (Directory.Exists(domainPath)) { var dirInfo = new DirectoryInfo(domainPath); // 获取直接子目录(不递归) domains = dirInfo.GetDirectories("*", SearchOption.TopDirectoryOnly) .Select(d => d.Name) .ToArray(); } else { domains = Array.Empty(); } List domainList = new List(); foreach (var item in domains) { if (File.Exists($"{domainPath}/{item}/Config/ArtSceneData.asset")) { bool isExit = domainMemberList.Any(x => x.DomainName == item); if (isExit) { continue; } CreatMemberServerDomainEntity entity = new CreatMemberServerDomainEntity(domainList) { DomainName = item, domainPath = $"{domainPath}/{item}" }; entity.SetArtSceneData(); domainList.Add(entity); } } domainMemberList.AddRange(domainList); } private void SetUseTypeData() { if (useType == UseType.Member) { _titleGroupName = "创建成员"; } else if (useType == UseType.Art) { _titleGroupName = "创建项目Art"; } } private bool IsMember() { return useType == UseType.Member; } private bool IsProject() { return useType == UseType.Art; } /// /// 使用类型 /// public enum UseType { /// /// 成员使用 /// Member, /// /// 项目使用 /// Art } public enum DeviceMode { //Xreal, Evo_Xreal, //Rokid, Evo_Rokid, } } }