1.移除了旧的冗余生成接口
2.编辑器更定制的细致化UI生成接口
3.接口开放给其它包继承生成
This commit is contained in:
陈思海 2026-03-23 14:45:55 +08:00
parent 16989c4df6
commit 24a3484668
6 changed files with 257 additions and 229 deletions

View File

@ -31,7 +31,10 @@ namespace AlicizaX.UI.Editor
private SerializedProperty commonDataProperty; private SerializedProperty commonDataProperty;
private SerializedProperty regexConfigsProperty; private SerializedProperty regexConfigsProperty;
private SerializedProperty scriptGenerateConfigsProperty; private SerializedProperty scriptGenerateConfigsProperty;
private SerializedProperty generatorRuleHelperProperty; private SerializedProperty identifierFormatterTypeProperty;
private SerializedProperty resourcePathResolverTypeProperty;
private SerializedProperty scriptCodeEmitterTypeProperty;
private SerializedProperty scriptFileWriterTypeProperty;
private SerializedProperty excludeKeywordsProperty; private SerializedProperty excludeKeywordsProperty;
private ReorderableList regexList; private ReorderableList regexList;
@ -43,14 +46,20 @@ namespace AlicizaX.UI.Editor
private TextAsset importText; private TextAsset importText;
private string previewLabel; private string previewLabel;
private string previewCompLabel; private string previewCompLabel;
private List<string> scriptGeneratorHelperTypes = new(); private List<string> identifierFormatterTypes = new();
private int scriptGeneratorHelperSelectIndex; private List<string> resourcePathResolverTypes = new();
private List<string> scriptCodeEmitterTypes = new();
private List<string> scriptFileWriterTypes = new();
private int identifierFormatterSelectIndex;
private int resourcePathResolverSelectIndex;
private int scriptCodeEmitterSelectIndex;
private int scriptFileWriterSelectIndex;
private void OnEnable() private void OnEnable()
{ {
BindConfiguration(); BindConfiguration();
SetupLists(); SetupLists();
RefreshScriptGeneratorHelperTypes(); RefreshGeneratorServiceTypes();
RefreshPreview(); RefreshPreview();
} }
@ -76,7 +85,10 @@ namespace AlicizaX.UI.Editor
commonDataProperty = serializedConfig.FindProperty(nameof(UIGenerateConfiguration.UIGenerateCommonData)); commonDataProperty = serializedConfig.FindProperty(nameof(UIGenerateConfiguration.UIGenerateCommonData));
regexConfigsProperty = serializedConfig.FindProperty(nameof(UIGenerateConfiguration.UIElementRegexConfigs)); regexConfigsProperty = serializedConfig.FindProperty(nameof(UIGenerateConfiguration.UIElementRegexConfigs));
scriptGenerateConfigsProperty = serializedConfig.FindProperty(nameof(UIGenerateConfiguration.UIScriptGenerateConfigs)); scriptGenerateConfigsProperty = serializedConfig.FindProperty(nameof(UIGenerateConfiguration.UIScriptGenerateConfigs));
generatorRuleHelperProperty = serializedConfig.FindProperty(nameof(UIGenerateConfiguration.UIScriptGeneratorRuleHelper)); identifierFormatterTypeProperty = serializedConfig.FindProperty(nameof(UIGenerateConfiguration.UIIdentifierFormatterTypeName));
resourcePathResolverTypeProperty = serializedConfig.FindProperty(nameof(UIGenerateConfiguration.UIResourcePathResolverTypeName));
scriptCodeEmitterTypeProperty = serializedConfig.FindProperty(nameof(UIGenerateConfiguration.UIScriptCodeEmitterTypeName));
scriptFileWriterTypeProperty = serializedConfig.FindProperty(nameof(UIGenerateConfiguration.UIScriptFileWriterTypeName));
excludeKeywordsProperty = commonDataProperty?.FindPropertyRelative(nameof(UIGenerateCommonData.ExcludeKeywords)); excludeKeywordsProperty = commonDataProperty?.FindPropertyRelative(nameof(UIGenerateCommonData.ExcludeKeywords));
} }
@ -256,7 +268,7 @@ namespace AlicizaX.UI.Editor
{ {
BindConfiguration(); BindConfiguration();
SetupLists(); SetupLists();
RefreshScriptGeneratorHelperTypes(); RefreshGeneratorServiceTypes();
RefreshPreview(); RefreshPreview();
} }
@ -333,33 +345,44 @@ namespace AlicizaX.UI.Editor
private void DrawCommonPane() private void DrawCommonPane()
{ {
EditorGUILayout.BeginVertical("box"); EditorGUILayout.BeginVertical("box");
EditorGUILayout.LabelField("General Generation Settings", EditorStyles.boldLabel);
EditorGUILayout.Space(4f);
EditorGUILayout.PropertyField( EditorGUILayout.PropertyField(
commonDataProperty.FindPropertyRelative(nameof(UIGenerateCommonData.ComCheckSplitName)), commonDataProperty.FindPropertyRelative(nameof(UIGenerateCommonData.ComCheckSplitName)),
new GUIContent("Component Split", "Example: Button#Close")); new GUIContent("组件分割符", "例如: Button#Close"));
EditorGUILayout.PropertyField( EditorGUILayout.PropertyField(
commonDataProperty.FindPropertyRelative(nameof(UIGenerateCommonData.ComCheckEndName)), commonDataProperty.FindPropertyRelative(nameof(UIGenerateCommonData.ComCheckEndName)),
new GUIContent("Component End", "Example: @End")); new GUIContent("组件结尾符", "例如: @End"));
EditorGUILayout.PropertyField( EditorGUILayout.PropertyField(
commonDataProperty.FindPropertyRelative(nameof(UIGenerateCommonData.ArrayComSplitName)), commonDataProperty.FindPropertyRelative(nameof(UIGenerateCommonData.ArrayComSplitName)),
new GUIContent("Array Split", "Example: *Item")); new GUIContent("数组分割", "例如: *Item"));
EditorGUILayout.PropertyField( EditorGUILayout.PropertyField(
commonDataProperty.FindPropertyRelative(nameof(UIGenerateCommonData.GeneratePrefix)), commonDataProperty.FindPropertyRelative(nameof(UIGenerateCommonData.GeneratePrefix)),
new GUIContent("Generate Prefix")); new GUIContent("生成脚本前缀"));
int nextIndex = EditorGUILayout.Popup( DrawTypePopup(
"Generator Rule Helper", "Identifier Formatter",
scriptGeneratorHelperSelectIndex, identifierFormatterTypeProperty,
scriptGeneratorHelperTypes.ToArray()); identifierFormatterTypes,
if (nextIndex != scriptGeneratorHelperSelectIndex && ref identifierFormatterSelectIndex,
nextIndex >= 0 && typeof(DefaultUIIdentifierFormatter).FullName);
nextIndex < scriptGeneratorHelperTypes.Count) DrawTypePopup(
{ "Resource Path Resolver",
scriptGeneratorHelperSelectIndex = nextIndex; resourcePathResolverTypeProperty,
generatorRuleHelperProperty.stringValue = scriptGeneratorHelperTypes[nextIndex]; resourcePathResolverTypes,
} ref resourcePathResolverSelectIndex,
typeof(DefaultUIResourcePathResolver).FullName);
DrawTypePopup(
"Script Code Emitter",
scriptCodeEmitterTypeProperty,
scriptCodeEmitterTypes,
ref scriptCodeEmitterSelectIndex,
typeof(DefaultUIScriptCodeEmitter).FullName);
DrawTypePopup(
"Script File Writer",
scriptFileWriterTypeProperty,
scriptFileWriterTypes,
ref scriptFileWriterSelectIndex,
typeof(DefaultUIScriptFileWriter).FullName);
GUILayout.Space(8f); GUILayout.Space(8f);
excludeList.DoLayoutList(); excludeList.DoLayoutList();
@ -460,26 +483,87 @@ namespace AlicizaX.UI.Editor
ApplyConfigChanges(); ApplyConfigChanges();
} }
private void RefreshScriptGeneratorHelperTypes() private void RefreshGeneratorServiceTypes()
{ {
scriptGeneratorHelperTypes = AlicizaX.Utility.Assembly RefreshTypeOptions(
.GetRuntimeTypeNames(typeof(IUIGeneratorRuleHelper)) typeof(IUIIdentifierFormatter),
identifierFormatterTypeProperty,
typeof(DefaultUIIdentifierFormatter).FullName,
ref identifierFormatterTypes,
ref identifierFormatterSelectIndex);
RefreshTypeOptions(
typeof(IUIResourcePathResolver),
resourcePathResolverTypeProperty,
typeof(DefaultUIResourcePathResolver).FullName,
ref resourcePathResolverTypes,
ref resourcePathResolverSelectIndex);
RefreshTypeOptions(
typeof(IUIScriptCodeEmitter),
scriptCodeEmitterTypeProperty,
typeof(DefaultUIScriptCodeEmitter).FullName,
ref scriptCodeEmitterTypes,
ref scriptCodeEmitterSelectIndex);
RefreshTypeOptions(
typeof(IUIScriptFileWriter),
scriptFileWriterTypeProperty,
typeof(DefaultUIScriptFileWriter).FullName,
ref scriptFileWriterTypes,
ref scriptFileWriterSelectIndex);
}
private static void RefreshTypeOptions(
Type interfaceType,
SerializedProperty property,
string defaultTypeName,
ref List<string> options,
ref int selectedIndex)
{
options = AlicizaX.Utility.Assembly
.GetRuntimeTypeNames(interfaceType)
.Distinct(StringComparer.Ordinal) .Distinct(StringComparer.Ordinal)
.OrderBy(typeName => typeName, StringComparer.Ordinal) .OrderBy(typeName => typeName, StringComparer.Ordinal)
.ToList(); .ToList();
if (scriptGeneratorHelperTypes.Count == 0) if (!options.Contains(defaultTypeName))
{ {
scriptGeneratorHelperTypes.Add(typeof(DefaultUIGeneratorRuleHelper).FullName); options.Insert(0, defaultTypeName);
} }
string currentType = generatorRuleHelperProperty?.stringValue; string currentType = string.IsNullOrWhiteSpace(property?.stringValue) ? defaultTypeName : property.stringValue;
if (!string.IsNullOrEmpty(currentType) && !scriptGeneratorHelperTypes.Contains(currentType)) if (!string.IsNullOrEmpty(currentType) && !options.Contains(currentType))
{ {
scriptGeneratorHelperTypes.Insert(0, currentType); options.Insert(0, currentType);
} }
scriptGeneratorHelperSelectIndex = Mathf.Max(0, scriptGeneratorHelperTypes.IndexOf(currentType)); selectedIndex = Mathf.Max(0, options.IndexOf(currentType));
}
private static void DrawTypePopup(
string label,
SerializedProperty property,
List<string> options,
ref int selectedIndex,
string defaultTypeName)
{
if (property == null || options == null || options.Count == 0)
{
return;
}
int currentIndex = selectedIndex;
if (currentIndex < 0 || currentIndex >= options.Count)
{
string currentType = string.IsNullOrWhiteSpace(property.stringValue) ? defaultTypeName : property.stringValue;
currentIndex = Mathf.Max(0, options.IndexOf(currentType));
selectedIndex = currentIndex;
}
int nextIndex = EditorGUILayout.Popup(label, currentIndex, options.ToArray());
if (nextIndex >= 0 && nextIndex < options.Count && nextIndex != currentIndex)
{
selectedIndex = nextIndex;
property.stringValue = options[nextIndex];
}
} }
private List<string> CollectComponentTypeNamesFallback() private List<string> CollectComponentTypeNamesFallback()
@ -596,7 +680,7 @@ namespace AlicizaX.UI.Editor
{ {
BindConfiguration(); BindConfiguration();
SetupLists(); SetupLists();
RefreshScriptGeneratorHelperTypes(); RefreshGeneratorServiceTypes();
RefreshPreview(); RefreshPreview();
Repaint(); Repaint();
} }

View File

@ -1,114 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using AlicizaX.UI.Runtime;
using UnityEngine;
namespace AlicizaX.UI.Editor
{
internal interface IContextualUIGeneratorRuleHelper
{
string GetClassGenerateName(UIGenerationContext context);
string GetUIResourceSavePath(UIGenerationContext context);
bool CheckCanGenerate(UIGenerationContext context);
string GetReferenceNamespace(UIGenerationContext context);
string GetVariableContent(UIGenerationContext context);
void WriteUIScriptContent(UIGenerationContext context, string scriptContent);
}
public interface IUIGeneratorRuleHelper
{
string GetPrivateComponentByNameRule(string regexName, string componetName, EBindType bindType);
string GetPublicComponentByNameRule(string variableName);
string GetClassGenerateName(GameObject targetObject, UIScriptGenerateData scriptGenerateData);
string GetUIResourceSavePath(GameObject targetObject, UIScriptGenerateData scriptGenerateData);
void WriteUIScriptContent(GameObject targetObject, string className, string scriptContent, UIScriptGenerateData scriptGenerateData);
bool CheckCanGenerate(GameObject targetObject, UIScriptGenerateData scriptGenerateData);
string GetReferenceNamespace(List<UIBindData> uiBindDatas);
string GetVariableContent(List<UIBindData> uiBindDatas);
}
public class DefaultUIGeneratorRuleHelper : IUIGeneratorRuleHelper, IContextualUIGeneratorRuleHelper
{
private readonly IUIIdentifierFormatter _identifierFormatter;
private readonly IUIResourcePathResolver _resourcePathResolver;
private readonly IUIScriptCodeEmitter _scriptCodeEmitter;
private readonly IUIScriptFileWriter _scriptFileWriter;
public DefaultUIGeneratorRuleHelper()
: this(
new DefaultUIIdentifierFormatter(),
new DefaultUIResourcePathResolver(),
new DefaultUIScriptCodeEmitter(),
new DefaultUIScriptFileWriter())
{
}
internal DefaultUIGeneratorRuleHelper(
IUIIdentifierFormatter identifierFormatter,
IUIResourcePathResolver resourcePathResolver,
IUIScriptCodeEmitter scriptCodeEmitter,
IUIScriptFileWriter scriptFileWriter)
{
_identifierFormatter = identifierFormatter ?? throw new ArgumentNullException(nameof(identifierFormatter));
_resourcePathResolver = resourcePathResolver ?? throw new ArgumentNullException(nameof(resourcePathResolver));
_scriptCodeEmitter = scriptCodeEmitter ?? throw new ArgumentNullException(nameof(scriptCodeEmitter));
_scriptFileWriter = scriptFileWriter ?? throw new ArgumentNullException(nameof(scriptFileWriter));
}
public string GetPrivateComponentByNameRule(string regexName, string componentName, EBindType bindType)
=> _identifierFormatter.GetPrivateComponentName(regexName, componentName, bindType);
public string GetPublicComponentByNameRule(string variableName)
=> _identifierFormatter.GetPublicComponentName(variableName);
public string GetClassGenerateName(GameObject targetObject, UIScriptGenerateData scriptGenerateData)
=> _identifierFormatter.GetClassName(targetObject);
string IContextualUIGeneratorRuleHelper.GetClassGenerateName(UIGenerationContext context)
=> _identifierFormatter.GetClassName(context.TargetObject);
public string GetUIResourceSavePath(GameObject targetObject, UIScriptGenerateData scriptGenerateData)
=> _resourcePathResolver.GetResourcePath(targetObject, scriptGenerateData);
string IContextualUIGeneratorRuleHelper.GetUIResourceSavePath(UIGenerationContext context)
=> _resourcePathResolver.GetResourcePath(context.TargetObject, context.ScriptGenerateData);
public void WriteUIScriptContent(GameObject targetObject, string className, string scriptContent, UIScriptGenerateData scriptGenerateData)
=> _scriptFileWriter.Write(targetObject, className, scriptContent, scriptGenerateData);
void IContextualUIGeneratorRuleHelper.WriteUIScriptContent(UIGenerationContext context, string scriptContent)
=> _scriptFileWriter.Write(context.TargetObject, context.ClassName, scriptContent, context.ScriptGenerateData);
public bool CheckCanGenerate(GameObject targetObject, UIScriptGenerateData scriptGenerateData)
=> _resourcePathResolver.CanGenerate(targetObject, scriptGenerateData);
bool IContextualUIGeneratorRuleHelper.CheckCanGenerate(UIGenerationContext context)
=> _resourcePathResolver.CanGenerate(context.TargetObject, context.ScriptGenerateData);
public string GetReferenceNamespace(List<UIBindData> uiBindDatas)
=> _scriptCodeEmitter.GetReferenceNamespaces(uiBindDatas);
string IContextualUIGeneratorRuleHelper.GetReferenceNamespace(UIGenerationContext context)
=> _scriptCodeEmitter.GetReferenceNamespaces(context.BindDatas?.ToList());
public string GetVariableContent(List<UIBindData> uiBindDatas)
=> _scriptCodeEmitter.GetVariableContent(uiBindDatas, GetPublicComponentByNameRule);
string IContextualUIGeneratorRuleHelper.GetVariableContent(UIGenerationContext context)
=> _scriptCodeEmitter.GetVariableContent(context.BindDatas?.ToList(), GetPublicComponentByNameRule);
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 2df48f035545426a83a384df3411755a
timeCreated: 1762516569

View File

@ -10,7 +10,7 @@ using UnityEngine;
namespace AlicizaX.UI.Editor namespace AlicizaX.UI.Editor
{ {
internal interface IUIIdentifierFormatter public interface IUIIdentifierFormatter
{ {
string GetPrivateComponentName(string regexName, string componentName, EBindType bindType); string GetPrivateComponentName(string regexName, string componentName, EBindType bindType);
@ -19,26 +19,26 @@ namespace AlicizaX.UI.Editor
string GetClassName(GameObject targetObject); string GetClassName(GameObject targetObject);
} }
internal interface IUIResourcePathResolver public interface IUIResourcePathResolver
{ {
string GetResourcePath(GameObject targetObject, UIScriptGenerateData scriptGenerateData); string GetResourcePath(GameObject targetObject, UIScriptGenerateData scriptGenerateData);
bool CanGenerate(GameObject targetObject, UIScriptGenerateData scriptGenerateData); bool CanGenerate(GameObject targetObject, UIScriptGenerateData scriptGenerateData);
} }
internal interface IUIScriptCodeEmitter public interface IUIScriptCodeEmitter
{ {
string GetReferenceNamespaces(List<UIBindData> uiBindDatas); string GetReferenceNamespaces(List<UIBindData> uiBindDatas);
string GetVariableContent(List<UIBindData> uiBindDatas, Func<string, string> publicNameFactory); string GetVariableContent(List<UIBindData> uiBindDatas, Func<string, string> publicNameFactory);
} }
internal interface IUIScriptFileWriter public interface IUIScriptFileWriter
{ {
void Write(GameObject targetObject, string className, string scriptContent, UIScriptGenerateData scriptGenerateData); void Write(GameObject targetObject, string className, string scriptContent, UIScriptGenerateData scriptGenerateData);
} }
internal sealed class DefaultUIIdentifierFormatter : IUIIdentifierFormatter public sealed class DefaultUIIdentifierFormatter : IUIIdentifierFormatter
{ {
private static readonly HashSet<string> CSharpKeywords = new HashSet<string>(StringComparer.Ordinal) private static readonly HashSet<string> CSharpKeywords = new HashSet<string>(StringComparer.Ordinal)
{ {
@ -138,7 +138,7 @@ namespace AlicizaX.UI.Editor
} }
} }
internal sealed class DefaultUIResourcePathResolver : IUIResourcePathResolver public sealed class DefaultUIResourcePathResolver : IUIResourcePathResolver
{ {
public string GetResourcePath(GameObject targetObject, UIScriptGenerateData scriptGenerateData) public string GetResourcePath(GameObject targetObject, UIScriptGenerateData scriptGenerateData)
{ {
@ -244,7 +244,7 @@ namespace AlicizaX.UI.Editor
} }
} }
internal sealed class DefaultUIScriptCodeEmitter : IUIScriptCodeEmitter public sealed class DefaultUIScriptCodeEmitter : IUIScriptCodeEmitter
{ {
public string GetReferenceNamespaces(List<UIBindData> uiBindDatas) public string GetReferenceNamespaces(List<UIBindData> uiBindDatas)
{ {
@ -305,7 +305,7 @@ namespace AlicizaX.UI.Editor
} }
} }
internal sealed class DefaultUIScriptFileWriter : IUIScriptFileWriter public sealed class DefaultUIScriptFileWriter : IUIScriptFileWriter
{ {
public void Write(GameObject targetObject, string className, string scriptContent, UIScriptGenerateData scriptGenerateData) public void Write(GameObject targetObject, string className, string scriptContent, UIScriptGenerateData scriptGenerateData)
{ {

View File

@ -60,56 +60,93 @@ namespace AlicizaX.UI.Editor
private const string GenerateInstanceIdKey = "AlicizaX.UI.Generate.InstanceId"; private const string GenerateInstanceIdKey = "AlicizaX.UI.Generate.InstanceId";
private const string GenerateAssetPathKey = "AlicizaX.UI.Generate.AssetPath"; private const string GenerateAssetPathKey = "AlicizaX.UI.Generate.AssetPath";
private static UIGenerateConfiguration _uiGenerateConfiguration; private static UIGenerateConfiguration _uiGenerateConfiguration;
private static IUIGeneratorRuleHelper _uiGeneratorRuleHelper; private static IUIIdentifierFormatter _identifierFormatter;
private static IUIResourcePathResolver _resourcePathResolver;
private static IUIScriptCodeEmitter _scriptCodeEmitter;
private static IUIScriptFileWriter _scriptFileWriter;
private static readonly List<UIBindData> _uiBindDatas = new List<UIBindData>(); private static readonly List<UIBindData> _uiBindDatas = new List<UIBindData>();
private static readonly HashSet<string> _arrayComponents = new HashSet<string>(StringComparer.Ordinal); private static readonly HashSet<string> _arrayComponents = new HashSet<string>(StringComparer.Ordinal);
private static readonly Dictionary<string, Type> _componentTypeCache = new Dictionary<string, Type>(StringComparer.Ordinal); private static readonly Dictionary<string, Type> _componentTypeCache = new Dictionary<string, Type>(StringComparer.Ordinal);
private static IUIGeneratorRuleHelper UIGeneratorRuleHelper
{
get
{
var configuredHelperTypeName = string.IsNullOrWhiteSpace(UIConfiguration.UIScriptGeneratorRuleHelper)
? typeof(DefaultUIGeneratorRuleHelper).FullName
: UIConfiguration.UIScriptGeneratorRuleHelper;
if (_uiGeneratorRuleHelper == null || _uiGeneratorRuleHelper.GetType().FullName != configuredHelperTypeName)
{
InitializeRuleHelper();
}
return _uiGeneratorRuleHelper;
}
}
private static IContextualUIGeneratorRuleHelper ContextualUIGeneratorRuleHelper =>
UIGeneratorRuleHelper as IContextualUIGeneratorRuleHelper;
private static UIGenerateConfiguration UIConfiguration => private static UIGenerateConfiguration UIConfiguration =>
_uiGenerateConfiguration ??= UIGenerateConfiguration.Instance; _uiGenerateConfiguration ??= UIGenerateConfiguration.Instance;
private static IUIGeneratorRuleHelper InitializeRuleHelper() private static IUIIdentifierFormatter IdentifierFormatter =>
ResolveConfiguredService(
ref _identifierFormatter,
UIConfiguration.UIIdentifierFormatterTypeName,
typeof(DefaultUIIdentifierFormatter),
nameof(IUIIdentifierFormatter));
private static IUIResourcePathResolver ResourcePathResolver =>
ResolveConfiguredService(
ref _resourcePathResolver,
UIConfiguration.UIResourcePathResolverTypeName,
typeof(DefaultUIResourcePathResolver),
nameof(IUIResourcePathResolver));
private static IUIScriptCodeEmitter ScriptCodeEmitter =>
ResolveConfiguredService(
ref _scriptCodeEmitter,
UIConfiguration.UIScriptCodeEmitterTypeName,
typeof(DefaultUIScriptCodeEmitter),
nameof(IUIScriptCodeEmitter));
private static IUIScriptFileWriter ScriptFileWriter =>
ResolveConfiguredService(
ref _scriptFileWriter,
UIConfiguration.UIScriptFileWriterTypeName,
typeof(DefaultUIScriptFileWriter),
nameof(IUIScriptFileWriter));
private static T ResolveConfiguredService<T>(ref T cachedService, string configuredTypeName, Type defaultType, string serviceName)
where T : class
{ {
var ruleHelperTypeName = UIConfiguration.UIScriptGeneratorRuleHelper; var resolvedTypeName = string.IsNullOrWhiteSpace(configuredTypeName) ? defaultType.FullName : configuredTypeName;
if (string.IsNullOrWhiteSpace(ruleHelperTypeName)) if (cachedService != null && cachedService.GetType().FullName == resolvedTypeName)
{ {
ruleHelperTypeName = typeof(DefaultUIGeneratorRuleHelper).FullName; return cachedService;
} }
var ruleHelperType = AlicizaX.Utility.Assembly.GetType(ruleHelperTypeName); var configuredType = AlicizaX.Utility.Assembly.GetType(resolvedTypeName);
if (ruleHelperType == null) if (configuredType == null || !typeof(T).IsAssignableFrom(configuredType))
{ {
Debug.LogError($"UIScriptGeneratorHelper: Could not load UI ScriptGeneratorHelper {ruleHelperTypeName}"); if (!string.Equals(resolvedTypeName, defaultType.FullName, StringComparison.Ordinal))
return null; {
Debug.LogError(
$"UIScriptGeneratorHelper: Could not load {serviceName} type '{resolvedTypeName}'. Falling back to {defaultType.FullName}.");
}
configuredType = defaultType;
} }
_uiGeneratorRuleHelper = Activator.CreateInstance(ruleHelperType) as IUIGeneratorRuleHelper; cachedService = Activator.CreateInstance(configuredType, true) as T;
if (_uiGeneratorRuleHelper == null) if (cachedService != null)
{ {
Debug.LogError($"UIScriptGeneratorHelper: Failed to instantiate {ruleHelperTypeName} as IUIGeneratorRuleHelper."); return cachedService;
} }
return _uiGeneratorRuleHelper; if (configuredType != defaultType)
{
Debug.LogError(
$"UIScriptGeneratorHelper: Failed to instantiate {resolvedTypeName} as {serviceName}. Falling back to {defaultType.FullName}.");
cachedService = Activator.CreateInstance(defaultType, true) as T;
}
if (cachedService == null)
{
Debug.LogError($"UIScriptGeneratorHelper: Failed to instantiate fallback {defaultType.FullName} as {serviceName}.");
}
return cachedService;
}
private static bool EnsureGenerationStrategyReady()
{
return IdentifierFormatter != null &&
ResourcePathResolver != null &&
ScriptCodeEmitter != null &&
ScriptFileWriter != null;
} }
private static Type ResolveUIElementComponentType(string uiName) private static Type ResolveUIElementComponentType(string uiName)
@ -275,7 +312,7 @@ namespace AlicizaX.UI.Editor
continue; continue;
} }
var keyName = UIGeneratorRuleHelper.GetPrivateComponentByNameRule(com, node.name, EBindType.None); var keyName = GetPrivateComponentName(com, node.name, EBindType.None);
if (_uiBindDatas.Exists(data => data.Name == keyName)) if (_uiBindDatas.Exists(data => data.Name == keyName))
{ {
Debug.LogError($"Duplicate key found: {keyName}"); Debug.LogError($"Duplicate key found: {keyName}");
@ -305,7 +342,7 @@ namespace AlicizaX.UI.Editor
return; return;
} }
var keyName = UIGeneratorRuleHelper.GetPrivateComponentByNameRule(string.Empty, node.name, EBindType.Widget); var keyName = GetPrivateComponentName(string.Empty, node.name, EBindType.Widget);
if (_uiBindDatas.Exists(data => data.Name == keyName)) if (_uiBindDatas.Exists(data => data.Name == keyName))
{ {
Debug.LogError($"Duplicate key found: {keyName}"); Debug.LogError($"Duplicate key found: {keyName}");
@ -347,7 +384,7 @@ namespace AlicizaX.UI.Editor
{ {
return componentArray.Select(com => return componentArray.Select(com =>
{ {
var keyName = UIGeneratorRuleHelper.GetPrivateComponentByNameRule(com, nodeName, EBindType.ListCom); var keyName = GetPrivateComponentName(com, nodeName, EBindType.ListCom);
return new UIBindData(keyName, new List<GameObject>(), null, EBindType.ListCom); return new UIBindData(keyName, new List<GameObject>(), null, EBindType.ListCom);
}).ToList(); }).ToList();
} }
@ -427,8 +464,7 @@ namespace AlicizaX.UI.Editor
return; return;
} }
var ruleHelper = UIGeneratorRuleHelper; if (!EnsureGenerationStrategyReady())
if (ruleHelper == null)
{ {
return; return;
} }
@ -439,10 +475,10 @@ namespace AlicizaX.UI.Editor
var generationContext = new UIGenerationContext(targetObject, scriptGenerateData, _uiBindDatas) var generationContext = new UIGenerationContext(targetObject, scriptGenerateData, _uiBindDatas)
{ {
AssetPath = UIGenerateQuick.GetPrefabAssetPath(targetObject), AssetPath = UIGenerateQuick.GetPrefabAssetPath(targetObject),
ClassName = GetClassGenerateName(ruleHelper, targetObject, scriptGenerateData) ClassName = GetClassGenerateName(targetObject, scriptGenerateData)
}; };
if (!CheckCanGenerate(ruleHelper, generationContext)) if (!CheckCanGenerate(generationContext))
{ {
CleanupContext(); CleanupContext();
return; return;
@ -456,7 +492,7 @@ namespace AlicizaX.UI.Editor
return; return;
} }
GenerateScript(generationContext, ruleHelper); GenerateScript(generationContext);
} }
private static void InitializeGenerationContext(GameObject targetObject) private static void InitializeGenerationContext(GameObject targetObject)
@ -498,50 +534,63 @@ namespace AlicizaX.UI.Editor
return UIGenerationValidationResult.Success(); return UIGenerationValidationResult.Success();
} }
private static void GenerateScript(UIGenerationContext context, IUIGeneratorRuleHelper ruleHelper) private static void GenerateScript(UIGenerationContext context)
{ {
var templateText = File.ReadAllText(UIGlobalPath.TemplatePath); var templateText = File.ReadAllText(UIGlobalPath.TemplatePath);
var processedText = ProcessTemplateText(context, templateText, ruleHelper); var processedText = ProcessTemplateText(context, templateText);
EditorPrefs.SetString(GenerateTypeNameKey, context.FullTypeName); EditorPrefs.SetString(GenerateTypeNameKey, context.FullTypeName);
if (ContextualUIGeneratorRuleHelper != null) WriteScriptContent(context, processedText);
{
ContextualUIGeneratorRuleHelper.WriteUIScriptContent(context, processedText);
return;
}
ruleHelper.WriteUIScriptContent(context.TargetObject, context.ClassName, processedText, context.ScriptGenerateData);
} }
private static string ProcessTemplateText(UIGenerationContext context, string templateText, IUIGeneratorRuleHelper ruleHelper) private static string ProcessTemplateText(UIGenerationContext context, string templateText)
{ {
var contextualRuleHelper = ContextualUIGeneratorRuleHelper;
return templateText return templateText
.Replace("#ReferenceNameSpace#", contextualRuleHelper != null ? contextualRuleHelper.GetReferenceNamespace(context) : ruleHelper.GetReferenceNamespace(_uiBindDatas)) .Replace("#ReferenceNameSpace#", GetReferenceNamespace(context))
.Replace("#ClassNameSpace#", context.ScriptGenerateData.NameSpace) .Replace("#ClassNameSpace#", context.ScriptGenerateData.NameSpace)
.Replace("#ClassName#", context.ClassName) .Replace("#ClassName#", context.ClassName)
.Replace("#TagName#", contextualRuleHelper != null ? contextualRuleHelper.GetUIResourceSavePath(context) : ruleHelper.GetUIResourceSavePath(context.TargetObject, context.ScriptGenerateData)) .Replace("#TagName#", GetResourceSavePath(context))
.Replace("#LoadType#", context.ScriptGenerateData.LoadType.ToString()) .Replace("#LoadType#", context.ScriptGenerateData.LoadType.ToString())
.Replace("#Variable#", contextualRuleHelper != null ? contextualRuleHelper.GetVariableContent(context) : ruleHelper.GetVariableContent(_uiBindDatas)); .Replace("#Variable#", GetVariableContent(context));
} }
private static string GetClassGenerateName(IUIGeneratorRuleHelper ruleHelper, GameObject targetObject, UIScriptGenerateData scriptGenerateData) private static string GetClassGenerateName(GameObject targetObject, UIScriptGenerateData scriptGenerateData)
{ {
if (ContextualUIGeneratorRuleHelper != null) return IdentifierFormatter.GetClassName(targetObject);
{
return ContextualUIGeneratorRuleHelper.GetClassGenerateName(new UIGenerationContext(targetObject, scriptGenerateData, _uiBindDatas));
}
return ruleHelper.GetClassGenerateName(targetObject, scriptGenerateData);
} }
private static bool CheckCanGenerate(IUIGeneratorRuleHelper ruleHelper, UIGenerationContext context) private static bool CheckCanGenerate(UIGenerationContext context)
{ {
if (ContextualUIGeneratorRuleHelper != null) return ResourcePathResolver.CanGenerate(context.TargetObject, context.ScriptGenerateData);
{ }
return ContextualUIGeneratorRuleHelper.CheckCanGenerate(context);
}
return ruleHelper.CheckCanGenerate(context.TargetObject, context.ScriptGenerateData); private static string GetPrivateComponentName(string regexName, string componentName, EBindType bindType)
{
return IdentifierFormatter.GetPrivateComponentName(regexName, componentName, bindType);
}
private static string GetPublicComponentName(string variableName)
{
return IdentifierFormatter.GetPublicComponentName(variableName);
}
private static string GetResourceSavePath(UIGenerationContext context)
{
return ResourcePathResolver.GetResourcePath(context.TargetObject, context.ScriptGenerateData);
}
private static string GetReferenceNamespace(UIGenerationContext context)
{
return ScriptCodeEmitter.GetReferenceNamespaces(_uiBindDatas);
}
private static string GetVariableContent(UIGenerationContext context)
{
return ScriptCodeEmitter.GetVariableContent(_uiBindDatas, GetPublicComponentName);
}
private static void WriteScriptContent(UIGenerationContext context, string scriptContent)
{
ScriptFileWriter.Write(context.TargetObject, context.ClassName, scriptContent, context.ScriptGenerateData);
} }
[DidReloadScripts] [DidReloadScripts]
@ -559,6 +608,12 @@ namespace AlicizaX.UI.Editor
return; return;
} }
if (!EnsureGenerationStrategyReady())
{
CleanupContext();
return;
}
_uiBindDatas.Clear(); _uiBindDatas.Clear();
_arrayComponents.Clear(); _arrayComponents.Clear();

View File

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using AlicizaX.UI.Runtime; using AlicizaX.UI.Runtime;
using UnityEngine; using UnityEngine;
@ -14,13 +14,19 @@ namespace AlicizaX.UI.Editor
[Header("UI脚本生成配置支持多个项目")] public List<UIScriptGenerateData> UIScriptGenerateConfigs = new List<UIScriptGenerateData>(); [Header("UI脚本生成配置支持多个项目")] public List<UIScriptGenerateData> UIScriptGenerateConfigs = new List<UIScriptGenerateData>();
[Header("UI脚本生成辅助类")] public string UIScriptGeneratorRuleHelper; [Header("UI脚本生成辅助类")] public string UIIdentifierFormatterTypeName;
public string UIResourcePathResolverTypeName;
public string UIScriptCodeEmitterTypeName;
public string UIScriptFileWriterTypeName;
} }
[Serializable] [Serializable]
public class UIGenerateCommonData public class UIGenerateCommonData
{ {
[Header("命名规则")] [Tooltip("组件检查分隔符例如Button#Close")] [Tooltip("组件检查分隔符例如Button#Close")]
public string ComCheckSplitName = "#"; public string ComCheckSplitName = "#";
[Tooltip("组件结尾分隔符,例如:@End")] public string ComCheckEndName = "@"; [Tooltip("组件结尾分隔符,例如:@End")] public string ComCheckEndName = "@";