修改生成用模板

This commit is contained in:
陈思海 2025-11-12 17:48:41 +08:00
parent e29c31ba87
commit 4de5156174
6 changed files with 76 additions and 125 deletions

View File

@ -34,7 +34,6 @@ namespace AlicizaX.UI.Editor
private readonly string[] toolbarTitles = { "UI基础设置", "UI构建配置", "UI元素映射" };
private ReorderableList combineList;
private ReorderableList regexList;
private ReorderableList projectList;
private ReorderableList excludeList;
@ -70,22 +69,6 @@ namespace AlicizaX.UI.Editor
private void SetupLists()
{
combineList = new ReorderableList(UIGenerateCommonData.CombineWords, typeof(StringPair), true, true, true, true);
combineList.drawHeaderCallback = (r) => EditorGUI.LabelField(r, "路径拼接映射 (Key -> Value)");
combineList.drawElementCallback = (rect, index, active, focused) =>
{
var p = UIGenerateCommonData.CombineWords[index];
rect.y += 2;
float half = rect.width / 2 - 8;
p.Key = EditorGUI.TextField(new Rect(rect.x, rect.y, half, EditorGUIUtility.singleLineHeight), p.Key);
p.Value = EditorGUI.TextField(new Rect(rect.x + half + 16, rect.y, half, EditorGUIUtility.singleLineHeight), p.Value);
};
combineList.onAddCallback = (r) => UIGenerateCommonData.CombineWords.Add(new StringPair("Key", "Value"));
combineList.onRemoveCallback = (r) =>
{
if (r.index >= 0) UIGenerateCommonData.CombineWords.RemoveAt(r.index);
};
excludeList = new ReorderableList(excludeKeywordsList, typeof(string), true, true, true, true);
excludeList.drawHeaderCallback = (r) => EditorGUI.LabelField(r, "排除关键字(匹配则不生成)");
@ -269,7 +252,7 @@ namespace AlicizaX.UI.Editor
UIGenerateCommonData.ComCheckEndName = EditorGUILayout.TextField(new GUIContent("组件结尾分隔符", "例如 @End"), UIGenerateCommonData.ComCheckEndName);
UIGenerateCommonData.ArrayComSplitName = EditorGUILayout.TextField(new GUIContent("数组组件分隔符", "例如 *Item"), UIGenerateCommonData.ArrayComSplitName);
UIGenerateCommonData.GeneratePrefix = EditorGUILayout.TextField(new GUIContent("生成脚本前缀"), UIGenerateCommonData.GeneratePrefix);
m_ScriptGeneratorHelperSelectIndex = EditorGUILayout.Popup("解密服务", m_ScriptGeneratorHelperSelectIndex, m_ScriptGeneratorHelperTypes.ToArray());
m_ScriptGeneratorHelperSelectIndex = EditorGUILayout.Popup("UI辅助生成", m_ScriptGeneratorHelperSelectIndex, m_ScriptGeneratorHelperTypes.ToArray());
string selectService = m_ScriptGeneratorHelperTypes[m_ScriptGeneratorHelperSelectIndex];
if (uiGenerateConfiguration.UIScriptGeneratorRuleHelper != selectService)
{
@ -283,10 +266,6 @@ namespace AlicizaX.UI.Editor
excludeList.DoLayoutList();
GUILayout.Space(8);
combineList.DoLayoutList();
EditorGUILayout.Space(8);
EditorGUILayout.LabelField("脚本生成预览", EditorStyles.boldLabel);

View File

@ -95,7 +95,7 @@ namespace AlicizaX.UI.Editor
}
}
private static string GetVersionType(string uiName)
private static string GetUIElementComponentType(string uiName)
{
if (string.IsNullOrEmpty(uiName)) return string.Empty;
foreach (var pair in UIConfiguration.UIElementRegexConfigs ?? Enumerable.Empty<UIEelementRegexData>())
@ -127,7 +127,7 @@ namespace AlicizaX.UI.Editor
return comStr.Split(new[] { split }, StringSplitOptions.RemoveEmptyEntries);
}
private static string GetKeyName(string key, string componentName, EBindType bindType)
private static string GetVariableName(string key, string componentName, EBindType bindType)
{
var helper = UIGeneratorRuleHelper;
if (helper == null)
@ -206,13 +206,13 @@ namespace AlicizaX.UI.Editor
foreach (var com in componentArray)
{
if (string.IsNullOrEmpty(com)) continue;
string typeName = GetVersionType(com);
string typeName = GetUIElementComponentType(com);
if (string.IsNullOrEmpty(typeName)) continue;
Component component = node.GetComponent(typeName);
if (component != null)
{
string keyName = GetKeyName(com, node.name, EBindType.None);
string keyName = GetVariableName(com, node.name, EBindType.None);
if (_uiBindDatas.Exists(a => a.Name == keyName))
{
Debug.LogError($"Duplicate key found: {keyName}");
@ -247,7 +247,7 @@ namespace AlicizaX.UI.Editor
return;
}
string keyName = GetKeyName(string.Empty, node.name, EBindType.Widget);
string keyName = GetVariableName(string.Empty, node.name, EBindType.Widget);
if (_uiBindDatas.Exists(a => a.Name == keyName))
{
Debug.LogError($"Duplicate key found: {keyName}");
@ -282,7 +282,7 @@ namespace AlicizaX.UI.Editor
List<UIBindData> tempBindDatas = new List<UIBindData>(componentArray.Length);
for (int i = 0; i < componentArray.Length; i++)
{
string keyNamePreview = GetKeyName(componentArray[i], nodeName, EBindType.ListCom);
string keyNamePreview = GetVariableName(componentArray[i], nodeName, EBindType.ListCom);
tempBindDatas.Add(new UIBindData(keyNamePreview, new List<Component>(), EBindType.ListCom));
}
@ -292,7 +292,7 @@ namespace AlicizaX.UI.Editor
string com = componentArray[index];
if (string.IsNullOrEmpty(com)) continue;
string typeName = GetVersionType(com);
string typeName = GetUIElementComponentType(com);
if (string.IsNullOrEmpty(typeName)) continue;
foreach (var node in orderedNodes)
@ -326,32 +326,22 @@ namespace AlicizaX.UI.Editor
private static string GetReferenceNamespace()
{
StringBuilder sb = new StringBuilder();
HashSet<string> namespaces = new HashSet<string>(StringComparer.Ordinal);
HashSet<string> namespaceSet = new HashSet<string>(StringComparer.Ordinal);
// 基础 namespace
namespaces.Add("UnityEngine");
sb.AppendLine("using UnityEngine;");
bool needCollectionsGeneric = _uiBindDatas.Any(d => d.BindType == EBindType.ListCom);
if (needCollectionsGeneric)
{
namespaces.Add("System.Collections.Generic");
sb.AppendLine("using System.Collections.Generic;");
}
namespaceSet.Add("UnityEngine");
if (_uiBindDatas.Any(d => d.BindType == EBindType.ListCom))
namespaceSet.Add("System.Collections.Generic");
foreach (var bindData in _uiBindDatas)
{
var comp = bindData.BindCom?.FirstOrDefault();
string ns = comp?.GetType().Namespace;
if (!string.IsNullOrEmpty(ns) && !namespaces.Contains(ns))
var ns = bindData.BindCom?.FirstOrDefault()?.GetType().Namespace;
if (!string.IsNullOrEmpty(ns) && !namespaceSet.Contains(ns))
{
namespaces.Add(ns);
sb.AppendLine($"using {ns};");
namespaceSet.Add(ns);
}
}
return sb.ToString();
return new StringBuilder().Append(string.Join(Environment.NewLine, namespaceSet.Select(n => $"using {n};"))).ToString();
}
private static string GetVariableText(List<UIBindData> uiBindDatas)
@ -362,55 +352,36 @@ namespace AlicizaX.UI.Editor
var helper = UIGeneratorRuleHelper;
if (helper == null) throw new InvalidOperationException("UIGeneratorRuleHelper is not configured.");
foreach (var bindData in uiBindDatas)
{
if (bindData == null) continue;
string variableName = bindData.Name;
if (string.IsNullOrEmpty(variableName)) continue;
string publicName = helper.GetPublicComponentByNameRule(variableName);
variableTextBuilder.Append("\t\t[SerializeField]\n");
var firstType = bindData.BindCom?.FirstOrDefault()?.GetType();
string typeName = firstType?.Name ?? "Component";
if (bindData.BindType == EBindType.None || bindData.BindType == EBindType.Widget)
var result = string.Join("\n\n", uiBindDatas
.Where(b => b != null && !string.IsNullOrEmpty(b.Name))
.Select(b =>
{
variableTextBuilder.Append($"\t\tprivate {typeName} {variableName};\n");
variableTextBuilder.Append($"\t\tpublic {typeName} {publicName} => {variableName};\n\n");
}
else if (bindData.BindType == EBindType.ListCom)
{
int count = Math.Max(0, bindData.BindCom?.Count ?? 0);
variableTextBuilder.Append($"\t\tprivate {typeName}[] {variableName} = new {typeName}[{count}];\n");
variableTextBuilder.Append($"\t\tpublic {typeName}[] {publicName} => {variableName};\n\n");
}
}
string variableName = b.Name;
string publicName = helper.GetPublicComponentByNameRule(variableName);
var firstType = b.BindCom?.FirstOrDefault()?.GetType();
string typeName = firstType?.Name ?? "Component";
return variableTextBuilder.ToString();
var sb = new StringBuilder();
sb.AppendLine("\t\t[SerializeField]");
if (b.BindType == EBindType.None || b.BindType == EBindType.Widget)
{
sb.AppendLine($"\t\tprivate {typeName} {variableName};");
sb.Append($"\t\tpublic {typeName} {publicName} => {variableName};");
}
else if (b.BindType == EBindType.ListCom)
{
int count = Math.Max(0, b.BindCom?.Count ?? 0);
sb.AppendLine($"\t\tprivate {typeName}[] {variableName} = new {typeName}[{count}];");
sb.Append($"\t\tpublic {typeName}[] {publicName} => {variableName};");
}
return sb.ToString();
}));
return variableTextBuilder.Append(result).ToString();
}
private static string GenerateScript(string className, string generateNameSpace)
{
if (string.IsNullOrEmpty(className)) throw new ArgumentNullException(nameof(className));
if (string.IsNullOrEmpty(generateNameSpace)) throw new ArgumentNullException(nameof(generateNameSpace));
StringBuilder scriptBuilder = new StringBuilder();
scriptBuilder.Append(GetReferenceNamespace());
scriptBuilder.AppendLine("using AlicizaX.UI.Runtime;");
scriptBuilder.AppendLine($"namespace {generateNameSpace}");
scriptBuilder.AppendLine("{");
scriptBuilder.AppendLine("\t#Attribute#");
scriptBuilder.AppendLine($"\tpublic class {className} : UIHolderObjectBase");
scriptBuilder.AppendLine("\t{");
scriptBuilder.AppendLine("\t\tpublic const string ResTag = #Tag#;");
scriptBuilder.AppendLine("\t\t#region Generated by Script Tool\n");
scriptBuilder.Append(GetVariableText(_uiBindDatas));
scriptBuilder.AppendLine("\t\t#endregion");
scriptBuilder.AppendLine("\t}");
scriptBuilder.AppendLine("}");
return scriptBuilder.ToString();
}
public static void GenerateAndAttachScript(GameObject targetObject, UIScriptGenerateData scriptGenerateData)
{
@ -448,15 +419,15 @@ namespace AlicizaX.UI.Editor
GetBindData(targetObject.transform);
string scriptContent = GenerateScript(className, scriptGenerateData.NameSpace);
string tagName = $"\"{ruleHelper.GetUIResourceSavePath(targetObject, scriptGenerateData)}\"";
string uiTemplateText = File.ReadAllText(UIGlobalPath.TemplatePath);
uiTemplateText = uiTemplateText.Replace("#ReferenceNameSpace#", GetReferenceNamespace());
uiTemplateText = uiTemplateText.Replace("#ClassNameSpace#", scriptGenerateData.NameSpace);
uiTemplateText = uiTemplateText.Replace("#ClassName#", className);
uiTemplateText = uiTemplateText.Replace("#TagName#", ruleHelper.GetUIResourceSavePath(targetObject, scriptGenerateData));
uiTemplateText = uiTemplateText.Replace("#LoadType#", scriptGenerateData.LoadType.ToString());
uiTemplateText = uiTemplateText.Replace("#Variable#", GetVariableText(_uiBindDatas));
string uiAttribute = $"[UIRes({className}.ResTag, EUIResLoadType.{scriptGenerateData.LoadType})]";
scriptContent = scriptContent.Replace("#Attribute#", uiAttribute);
scriptContent = scriptContent.Replace("#Tag#", tagName);
ruleHelper.WriteUIScriptContent(className, scriptContent, scriptGenerateData);
ruleHelper.WriteUIScriptContent(className, uiTemplateText, scriptGenerateData);
}
[DidReloadScripts]
@ -464,7 +435,7 @@ namespace AlicizaX.UI.Editor
{
if (!EditorPrefs.HasKey("Generate"))
return;
EditorPrefs.DeleteKey("Generate");
_uiBindDatas.Clear();
_arrayComponents.Clear();
@ -474,7 +445,7 @@ namespace AlicizaX.UI.Editor
if (instanceId == -1)
{
Debug.LogWarning("CheckHasAttach: InstanceId missing.");
EditorPrefs.DeleteKey("Generate");
return;
}
@ -483,19 +454,18 @@ namespace AlicizaX.UI.Editor
if (targetObject == null)
{
Debug.LogWarning("UI script generation attachment object missing!");
EditorPrefs.DeleteKey("Generate");
return;
}
// 重新收集 bind 数据并附加脚本
GetBindData(targetObject.transform);
AttachScriptToGameObject(targetObject, className);
BindScriptPropertyField(targetObject, className);
Debug.Log($"Generate {className} Successfully attached to game object");
EditorPrefs.DeleteKey("Generate");
}
private static void AttachScriptToGameObject(GameObject targetObject, string scriptClassName)
private static void BindScriptPropertyField(GameObject targetObject, string scriptClassName)
{
if (targetObject == null) throw new ArgumentNullException(nameof(targetObject));
if (string.IsNullOrEmpty(scriptClassName)) throw new ArgumentNullException(nameof(scriptClassName));
@ -512,19 +482,10 @@ namespace AlicizaX.UI.Editor
continue;
}
Type[] types;
try
{
types = assembly.GetTypes();
}
catch (ReflectionTypeLoadException e)
{
types = e.Types.Where(t => t != null).ToArray();
}
Type[] types= assembly.GetTypes();
foreach (var type in types)
{
if (type == null) continue;
if (!type.IsClass || type.IsAbstract) continue;
if (type.Name.Equals(scriptClassName, StringComparison.Ordinal) ||
type.Name.Contains(scriptClassName, StringComparison.Ordinal))

View File

@ -0,0 +1,15 @@
#ReferenceNameSpace#
using AlicizaX.UI.Runtime;
namespace #ClassNameSpace#
{
[UIRes(#ClassName#.ResTag, EUIResLoadType.#LoadType#)]
public class #ClassName# : UIHolderObjectBase
{
public const string ResTag = "#TagName#";
#region Generated by Script Tool
#Variable#
#endregion
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8456fdae556b474e85de477d9e5c0b6c
timeCreated: 1762938714

View File

@ -36,14 +36,6 @@ namespace AlicizaX.UI.Editor
[Tooltip("生成脚本前缀")] public string GeneratePrefix = "ui";
[Tooltip("排除的关键字(匹配则不生成)")] public string[] ExcludeKeywords = { "ViewHolder" };
[Tooltip("路径拼接映射Window -> Window 文件夹")]
public List<StringPair> CombineWords = new List<StringPair>()
{
new StringPair("Window", "Window"),
new StringPair("ViewHolder", "ViewHolder"),
new StringPair("Widget", "Widget"),
};
}
[Serializable]

View File

@ -4,5 +4,6 @@ namespace AlicizaX.UI.Editor
{
public const string DefaultComPath = "Packages/com.alicizax.unity.framework/Editor/UI/Res/default.txt";
public const string UIPrefabPath = "Packages/com.alicizax.unity.framework/Editor/UI/Res/UIRoot.prefab";
public const string TemplatePath = "Packages/com.alicizax.unity.framework/Editor/UI/Res/UITemplate.txt";
}
}