Files
plugin-library/Assets/06.UIFarme/Editor/UICreateWindow.cs

480 lines
18 KiB
C#
Raw Normal View History

2025-09-23 11:18:38 +08:00
#if UNITY_EDITOR
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.Text.RegularExpressions;
using System.IO;
using Stary.Evo;
using System;
using System.Linq;
using Newtonsoft.Json;
using Stary.Evo.Editor;
public class UICreateWindow : EditorWindow
{
#region MenuItem
2025-09-24 16:21:43 +08:00
[MenuItem("Evo/UI管理/CreateUI")]
2025-09-23 11:18:38 +08:00
private static void CopyUI()
{
if (Selection.activeObject == null || !(Selection.activeObject is GameObject))
{
Debug.LogError("请选择UI预制体!");
return;
}
UICreateWindow.OpenWindow().uiPrefab = Selection.activeObject as GameObject;
}
2025-09-24 16:21:43 +08:00
[MenuItem("Evo/UI管理/OpenWindow")]
2025-09-23 11:18:38 +08:00
public static UICreateWindow OpenWindow()
{
var window = GetWindow<UICreateWindow>("UI管理");
if (window == null)
{
window = CreateWindow<UICreateWindow>("UI管理");
}
window.name = "UI管理";
window.Focus();
return window;
}
#endregion
private string _mInput;
private Vector2 _scroll;
private Vector2 _scroll2;
private Vector2 _scroll3;
private string _uiViewTemplate = "UIViewTemplate";
private string _uiConfig = "UIConfig";
private string _uiName;
2025-09-24 17:16:12 +08:00
private string _saveUIPath;
2025-09-23 11:18:38 +08:00
public GameObject uiPrefab;
private Dictionary<string, string> _uiNames = new Dictionary<string, string>();
private Dictionary<string, UIConfigJson> _uiJsonDatas = new Dictionary<string, UIConfigJson>();
private bool _isWindow = true;
private UILayer _layer = UILayer.NormalLayer;
private IEnumerable<Type> uiViews;
private string[] _domainNames;
private int _domainIndex;
private UIConfig _uiConfigObj;
private void OnEnable()
{
TryGetPath(ref _uiViewTemplate, _uiViewTemplate, ".txt");
_domainNames = CreatAssetWindow.GetCreatDomainAllName();
ValueChang();
}
private void ValueChang()
{
_uiJsonDatas.Clear();
_uiNames.Clear();
uiViews = ReflectionHelper.GetAllUIViewTypes(_domainNames[_domainIndex]);
2025-09-24 17:16:12 +08:00
_saveUIPath = EditorPrefs.GetString(nameof(_saveUIPath));
2025-09-23 11:18:38 +08:00
DomainPathField();
foreach (var uiView in uiViews)
{
string str = uiView.Name;
if (str.Equals("Max")) continue;
var jsonData = GetUIJson(str);
//if (jsonData == null || string.IsNullOrEmpty(jsonData.path)) continue;
var scriptPath = GetUIScript(str, true);
_uiNames.AddOrUpdate(str, scriptPath);
}
}
2025-09-24 17:16:12 +08:00
2025-09-23 11:18:38 +08:00
private void OnGUI()
{
2025-09-23 11:21:07 +08:00
EditorGUILayout.LabelField("通过[Evo/UI管理]可以打开");
2025-09-23 11:18:38 +08:00
_scroll = EditorGUILayout.BeginScrollView(_scroll);
{
EditorGUILayout.HelpBox("UI基础文件", MessageType.Info);
{
PathField("UI模板文件.txt", ref _uiViewTemplate, nameof(_uiViewTemplate), ".txt");
DomainPathField();
EditorGUILayout.ObjectField(_uiConfig, _uiConfigObj, typeof(UIConfig), true);
}
EditorGUILayout.Space(10);
EditorGUILayout.BeginHorizontal();
{
_scroll2 = EditorGUILayout.BeginScrollView(_scroll2, "box", GUILayout.Width(position.width * 0.4f - 6));
{
2025-09-24 17:16:12 +08:00
var tempIndex = EditorGUILayout.Popup("Domain", _domainIndex, _domainNames);
2025-09-23 11:18:38 +08:00
if (tempIndex != _domainIndex)
{
ValueChang();
_domainIndex = tempIndex;
}
2025-09-24 17:16:12 +08:00
2025-09-23 11:18:38 +08:00
EditorGUILayout.HelpBox("已创建的UI", MessageType.Info);
_mInput = EditorGUILayout.TextField(_mInput, EditorStyles.toolbarSearchField, GUILayout.Height(20));
foreach (var uiView in uiViews)
{
string str = uiView.Name;
if (str.Equals("Max")) continue;
if (!string.IsNullOrEmpty(_mInput) && !str.Contains(_mInput)) continue;
var jsonData = GetUIJson(str);
var scriptPath = GetUIScript(str);
if (jsonData == null)
{
jsonData = new UIConfigJson();
}
2025-09-24 17:16:12 +08:00
2025-09-23 11:18:38 +08:00
if (string.IsNullOrEmpty(scriptPath)) continue;
var defaultColor = GUI.color;
if (str.Equals(_uiName))
{
GUI.color = Color.yellow;
}
EditorGUILayout.BeginHorizontal("box");
if (GUILayout.Button("选中"))
{
uiPrefab = AssetDatabase.LoadAssetAtPath<GameObject>(jsonData.path);
}
EditorGUILayout.ObjectField(AssetDatabase.LoadAssetAtPath<GameObject>(jsonData.path),
typeof(GameObject), true);
EditorGUILayout.ObjectField(AssetDatabase.LoadAssetAtPath<TextAsset>(scriptPath),
typeof(TextAsset), true);
EditorGUILayout.EndHorizontal();
GUI.color = defaultColor;
}
}
EditorGUILayout.EndScrollView();
_scroll3 = EditorGUILayout.BeginScrollView(_scroll3, "box", GUILayout.Width(position.width * 0.6f - 6));
{
EditorGUILayout.HelpBox("UI操作", MessageType.Info);
uiPrefab = EditorGUILayout.ObjectField("UI预制体", uiPrefab, typeof(GameObject), true) as GameObject;
if (uiPrefab != null)
{
_uiName = uiPrefab.name;
var uiScriptPath = GetUIScript(_uiName);
if (string.IsNullOrEmpty(uiScriptPath))
{
2025-09-24 17:16:12 +08:00
if (string.IsNullOrEmpty(_saveUIPath))
{
_saveUIPath = $"Assets/Domain/{_domainNames[_domainIndex]}/HotUpdate/UI";
}
if (GUILayout.Button($"选择创建路径:{_saveUIPath}"))
2025-09-23 11:18:38 +08:00
{
2025-09-24 17:16:12 +08:00
var newPath = EditorUtility.OpenFolderPanel("UI生成路径", _saveUIPath, "");
_saveUIPath = newPath.Replace(Application.dataPath, "Assets");
EditorPrefs.SetString(nameof(_saveUIPath), _saveUIPath);
2025-09-23 11:18:38 +08:00
}
if (uiPrefab != null)
{
2025-09-24 17:16:12 +08:00
EditorGUILayout.TextField("UI生成路径", $"{_saveUIPath}/{_uiName}.cs");
2025-09-23 11:18:38 +08:00
}
_isWindow = EditorGUILayout.Toggle("是否为窗口", _isWindow);
_layer = (UILayer)EditorGUILayout.EnumPopup("UILayer设置", _layer);
var defaultColor = GUI.color;
GUI.color = Color.green;
if (GUILayout.Button("创建UI"))
{
// 生成代码
string str = Regex.Replace(File.ReadAllText(_uiViewTemplate), "UIXXXView", _uiName);
UIControlData uiControlData = uiPrefab.GetComponent<UIControlData>();
if (uiControlData != null)
{
uiControlData.CopyCodeToClipBoardPrivate();
}
str = Regex.Replace(str, "//UIControlData",
uiControlData != null ? UnityEngine.GUIUtility.systemCopyBuffer : "");
2025-09-24 17:16:12 +08:00
string newPath = $"{_saveUIPath}/{_uiName}.cs";
2025-09-23 11:18:38 +08:00
File.WriteAllText(newPath, str);
var jsonData = new UIConfigJson
{
uiType = _uiName,
pathId = $"Prefabs_{uiPrefab.name}",
path = AssetDatabase.GetAssetPath(uiPrefab),
isWindow = _isWindow,
uiLayer = _layer,
};
_uiJsonDatas.Add(_uiName, jsonData);
_uiNames.Add(_uiName, newPath);
SaveJson();
// 生成UIType
// var newStr = Regex.Replace(File.ReadAllText(_uiType), "Max,", $"{_uiName},\n\t\tMax,");
// File.Delete(_uiType);
// File.WriteAllText(_uiType, newStr);
//
// Debug.Log("生成成功:" + newPath);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
GUI.color = defaultColor;
}
else
{
var jsonData = GetUIJson(_uiName);
if (jsonData == null)
{
jsonData = new UIConfigJson();
jsonData.uiType = _uiName;
_uiJsonDatas.AddOrUpdate(_uiName, jsonData);
}
2025-09-24 17:16:12 +08:00
2025-09-23 11:18:38 +08:00
if (UnityEditor.PrefabUtility.IsPartOfPrefabAsset(uiPrefab))
{
// 预制体资源就是自身
jsonData.pathId = $"Prefabs_{uiPrefab.name}";
jsonData.path = UnityEditor.AssetDatabase.GetAssetPath(uiPrefab);
}
EditorGUILayout.ObjectField("已创建脚本",
AssetDatabase.LoadAssetAtPath(uiScriptPath, typeof(TextAsset)), typeof(TextAsset),
true);
jsonData.isWindow = EditorGUILayout.Toggle("是否为窗口", jsonData.isWindow);
jsonData.uiLayer = (UILayer)EditorGUILayout.EnumPopup("UILayer设置", jsonData.uiLayer);
var defaultColor = GUI.color;
GUI.color = Color.green;
if (GUILayout.Button("保存设置"))
{
SaveJson();
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
GUI.color = defaultColor;
GUI.color = Color.red;
if (GUILayout.Button("删除UI脚本"))
{
if (EditorUtility.DisplayDialog("是否确认删除",
$"请确认是否删除:\n{uiScriptPath}\n同时会清除JsonUIType中相关数据", "确定", "取消"))
{
// 清除UIConfig中的指定类型
_uiJsonDatas.Remove(_uiName);
_uiNames.Remove(_uiName);
SaveJson();
// 删除文件
File.Delete(uiScriptPath);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
_uiNames.Remove(_uiName);
}
}
GUI.color = defaultColor;
}
}
else
{
_uiName = "";
}
}
EditorGUILayout.EndScrollView();
}
EditorGUILayout.EndHorizontal();
}
EditorGUILayout.EndScrollView();
}
private void SaveJson()
{
List<UIConfigJson> list = new List<UIConfigJson>();
foreach (var name in _uiNames.Keys)
{
if (_uiJsonDatas.TryGetValue(name, out var data))
{
list.Add(data);
}
}
_uiConfigObj.uiConfigJsons.Clear();
_uiConfigObj.uiConfigJsons = list;
EditorUtility.SetDirty(_uiConfigObj);
AssetDatabase.SaveAssets();
}
private void TryGetPath(ref string path, string pathName, string endsWith)
{
path = PlayerPrefs.GetString(pathName);
if (!File.Exists(path))
{
string[] ids = AssetDatabase.FindAssets(pathName);
if (ids != null)
{
foreach (var id in ids)
{
var str = AssetDatabase.GUIDToAssetPath(id);
if (str.EndsWith(endsWith))
{
path = str;
}
}
}
}
}
private string GetUIScript(string name, bool tryFind = false)
{
if (_uiNames.TryGetValue(name, out string path))
{
return path;
}
if (!tryFind)
{
return string.Empty;
}
2025-09-24 17:16:12 +08:00
// if (GetUIJson(name) == null) return string.Empty;
2025-09-23 11:18:38 +08:00
string[] ids = AssetDatabase.FindAssets(name);
if (ids != null)
{
foreach (var id in ids)
{
var str = AssetDatabase.GUIDToAssetPath(id);
if (str.EndsWith(".cs"))
{
return str;
}
}
}
return string.Empty;
}
private UIConfigJson GetUIJson(string name)
{
if (_uiJsonDatas.Count == 0)
{
try
{
foreach (var item in _uiConfigObj.uiConfigJsons)
{
_uiJsonDatas.AddOrUpdate(item.uiType, item);
}
}
catch (Exception e)
{
Debug.LogError(e);
}
}
if (_uiJsonDatas.TryGetValue(name, out var jsonData))
{
return jsonData;
}
return null;
}
private void DomainPathField()
{
2025-09-24 16:33:01 +08:00
var path = $"Assets/Domain/{_domainNames[_domainIndex]}/AddressableRes/Config/UIConfig.asset";
2025-09-23 11:18:38 +08:00
if (_uiConfigObj == null)
{
_uiConfigObj = (UIConfig)AssetDatabase.LoadAssetAtPath(path, typeof(UIConfig));
}
if (_uiConfigObj == null)
{
Debug.LogError($"在{path}中未找到UIConfig");
return;
}
}
private void PathField(string name, ref string path, string pathName, string endsWith)
{
var obj = EditorGUILayout.ObjectField(name, AssetDatabase.LoadAssetAtPath(path, typeof(TextAsset)),
typeof(TextAsset), true);
if (obj != null)
{
var newPath = AssetDatabase.GetAssetPath(obj);
if (newPath.EndsWith(endsWith) && !newPath.Equals(path))
{
path = newPath;
PlayerPrefs.SetString(pathName, path);
}
}
}
}
#endif
static class ReflectionHelper
{
public static IEnumerable<T> CreateAllInstancesOf<T>()
{
return typeof(ReflectionHelper).Assembly.GetTypes() //获取当前类库下所有类型
.Where(t => typeof(T).IsAssignableFrom(t)) //获取间接或直接继承t的所有类型
.Where(t => !t.IsAbstract && t.IsClass) //获取非抽象类 排除接口继承
.Select(t => (T)Activator.CreateInstance(t)); //创造实例,并返回结果(项目需求,可删除)
}
// 新增方法专门用于查找UIView类型的所有实现类
public static IEnumerable<Type> GetAllUIViewTypes(string domainName)
{
// 查找所有程序集中的UIView类型实现
var uiviewType = typeof(UIView);
List<Type> result = new List<Type>();
// 尝试获取指定名称的程序集
var targetAssembly = AppDomain.CurrentDomain.GetAssemblies()
.FirstOrDefault(assembly => assembly.GetName().Name == $"HotUpdate_{domainName}");
if (targetAssembly == null)
{
Debug.LogError($"未找到名为HotUpdate_{domainName}的程序集");
return null;
}
2025-09-24 17:16:12 +08:00
2025-09-23 11:18:38 +08:00
try
{
result.AddRange(targetAssembly.GetTypes()
.Where(t => uiviewType.IsAssignableFrom(t))
.Where(t => !t.IsAbstract && t.IsClass));
}
catch (Exception)
{
// 忽略无法访问的程序集
}
// 遍历所有已加载的程序集
// foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
// {
// try
// {
// result.AddRange(assembly.GetTypes()
// .Where(t => uiviewType.IsAssignableFrom(t))
// .Where(t => !t.IsAbstract && t.IsClass));
// }
// catch (Exception)
// {
// // 忽略无法访问的程序集
// }
// }
return result;
}
}