com.alicizax.unity.framework/Editor/UI/Helper/IUIGeneratorRuleHelper.cs

235 lines
9.6 KiB
C#
Raw Normal View History

2025-11-10 16:01:53 +08:00
using System;
2025-11-13 11:16:31 +08:00
using System.Collections.Generic;
2025-11-10 16:01:53 +08:00
using System.IO;
2025-11-13 11:16:31 +08:00
using System.Linq;
2025-11-10 16:01:53 +08:00
using System.Text;
using AlicizaX.UI.Runtime;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
namespace AlicizaX.UI.Editor
{
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(string className, string scriptContent, UIScriptGenerateData scriptGenerateData);
bool CheckCanGenerate(GameObject targetObject, UIScriptGenerateData scriptGenerateData);
2025-11-13 11:16:31 +08:00
string GetReferenceNamespace(List<UIBindData> uiBindDatas);
string GetVariableContent(List<UIBindData> uiBindDatas);
2025-11-10 16:01:53 +08:00
}
2025-11-13 11:16:31 +08:00
public class DefaultUIGeneratorRuleHelper : IUIGeneratorRuleHelper
2025-11-10 16:01:53 +08:00
{
public string GetPrivateComponentByNameRule(string regexName, string componentName, EBindType bindType)
{
2025-11-13 11:16:31 +08:00
var endPrefix = bindType == EBindType.ListCom ? "List" : string.Empty;
2025-11-11 10:57:35 +08:00
var common = UIGenerateConfiguration.Instance.UIGenerateCommonData;
2025-11-13 11:16:31 +08:00
var endNameIndex = componentName.IndexOf(common.ComCheckEndName, StringComparison.Ordinal);
2025-11-10 16:01:53 +08:00
2025-11-13 11:16:31 +08:00
var componentSuffix = endNameIndex >= 0 ? componentName.Substring(endNameIndex + 1) : componentName;
2025-11-10 16:01:53 +08:00
return $"m{regexName}{componentSuffix}{endPrefix}";
}
public string GetPublicComponentByNameRule(string variableName)
{
2025-11-11 10:57:35 +08:00
if (string.IsNullOrEmpty(variableName)) return variableName;
2025-11-13 11:16:31 +08:00
return variableName.Length > 1 ? variableName.Substring(1) : variableName;
2025-11-10 16:01:53 +08:00
}
public string GetClassGenerateName(GameObject targetObject, UIScriptGenerateData scriptGenerateData)
{
2025-11-11 10:57:35 +08:00
var config = UIGenerateConfiguration.Instance.UIGenerateCommonData;
2025-11-13 11:16:31 +08:00
var prefix = config.GeneratePrefix ?? "ui";
2025-11-11 10:57:35 +08:00
return $"{prefix}_{targetObject.name}";
2025-11-10 16:01:53 +08:00
}
public string GetUIResourceSavePath(GameObject targetObject, UIScriptGenerateData scriptGenerateData)
{
2025-11-13 11:16:31 +08:00
if (targetObject == null) return $"\"{nameof(targetObject)}\"";
var defaultPath = targetObject.name;
var assetPath = UIGenerateQuick.GetPrefabAssetPath(targetObject);
2025-11-10 16:01:53 +08:00
2025-11-11 10:57:35 +08:00
if (string.IsNullOrEmpty(assetPath) || !assetPath.StartsWith("Assets/", StringComparison.Ordinal))
return defaultPath;
2025-11-10 16:01:53 +08:00
assetPath = assetPath.Replace('\\', '/');
2025-11-13 11:16:31 +08:00
return scriptGenerateData.LoadType switch
{
EUIResLoadType.Resources => GetResourcesPath(assetPath, scriptGenerateData, defaultPath),
EUIResLoadType.AssetBundle => GetAssetBundlePath(assetPath, scriptGenerateData, defaultPath),
_ => defaultPath
};
}
private static string GetResourcesPath(string assetPath, UIScriptGenerateData scriptGenerateData, string defaultPath)
{
var resourcesRoot = scriptGenerateData.UIPrefabRootPath;
var relPath = GetResourcesRelativePath(assetPath, resourcesRoot);
if (relPath == null)
{
Debug.LogWarning($"[UI生成] 资源 {assetPath} 不在配置的 Resources 根目录下: {resourcesRoot}");
return defaultPath;
}
2025-11-10 16:01:53 +08:00
2025-11-13 11:16:31 +08:00
return relPath;
}
private static string GetAssetBundlePath(string assetPath, UIScriptGenerateData scriptGenerateData, string defaultPath)
{
try
2025-11-10 16:01:53 +08:00
{
2025-11-13 11:16:31 +08:00
var defaultPackage = YooAsset.Editor.AssetBundleCollectorSettingData.Setting.GetPackage("DefaultPackage");
if (defaultPackage?.EnableAddressable == true)
2025-11-10 16:01:53 +08:00
return defaultPath;
}
2025-11-13 11:16:31 +08:00
catch
{
// 忽略异常,继续处理
}
var bundleRoot = scriptGenerateData.UIPrefabRootPath;
if (!assetPath.StartsWith(bundleRoot, StringComparison.OrdinalIgnoreCase))
{
Debug.LogWarning($"[UI生成] 资源 {assetPath} 不在配置的 AssetBundle 根目录下: {bundleRoot}");
return defaultPath;
}
return Path.ChangeExtension(assetPath, null);
2025-11-10 16:01:53 +08:00
}
2025-11-13 11:16:31 +08:00
private static string GetResourcesRelativePath(string assetPath, string resourcesRoot)
2025-11-10 16:01:53 +08:00
{
2025-11-11 10:57:35 +08:00
if (string.IsNullOrEmpty(assetPath) || string.IsNullOrEmpty(resourcesRoot)) return null;
2025-11-13 11:16:31 +08:00
2025-11-10 16:01:53 +08:00
assetPath = assetPath.Replace('\\', '/');
resourcesRoot = resourcesRoot.Replace('\\', '/');
2025-11-11 10:57:35 +08:00
if (!assetPath.StartsWith(resourcesRoot, StringComparison.OrdinalIgnoreCase))
2025-11-10 16:01:53 +08:00
return null;
2025-11-13 11:16:31 +08:00
var relPath = assetPath.Substring(resourcesRoot.Length).TrimStart('/');
2025-11-11 10:57:35 +08:00
return Path.ChangeExtension(relPath, null);
2025-11-10 16:01:53 +08:00
}
public void WriteUIScriptContent(string className, string scriptContent, UIScriptGenerateData scriptGenerateData)
{
2025-11-11 10:57:35 +08:00
if (string.IsNullOrEmpty(className)) throw new ArgumentNullException(nameof(className));
if (scriptContent == null) throw new ArgumentNullException(nameof(scriptContent));
if (scriptGenerateData == null) throw new ArgumentNullException(nameof(scriptGenerateData));
2025-11-13 11:16:31 +08:00
var scriptFolderPath = scriptGenerateData.GenerateHolderCodePath;
var scriptFilePath = Path.Combine(scriptFolderPath, $"{className}.cs");
2025-11-10 16:01:53 +08:00
2025-11-13 11:16:31 +08:00
Directory.CreateDirectory(scriptFolderPath);
2025-11-10 16:01:53 +08:00
2025-11-13 11:16:31 +08:00
if (File.Exists(scriptFilePath) && IsContentUnchanged(scriptFilePath, scriptContent))
2025-11-10 16:01:53 +08:00
{
2025-11-13 11:16:31 +08:00
UIScriptGeneratorHelper.BindUIScript();
return;
2025-11-10 16:01:53 +08:00
}
File.WriteAllText(scriptFilePath, scriptContent, Encoding.UTF8);
AssetDatabase.Refresh();
}
2025-11-13 11:16:31 +08:00
private static bool IsContentUnchanged(string filePath, string newContent)
{
var oldText = File.ReadAllText(filePath, Encoding.UTF8);
return oldText.Equals(newContent, StringComparison.Ordinal);
}
2025-11-10 16:01:53 +08:00
public bool CheckCanGenerate(GameObject targetObject, UIScriptGenerateData scriptGenerateData)
{
2025-11-11 10:57:35 +08:00
if (targetObject == null || scriptGenerateData == null) return false;
2025-11-13 11:16:31 +08:00
var assetPath = UIGenerateQuick.GetPrefabAssetPath(targetObject);
2025-11-11 10:57:35 +08:00
if (string.IsNullOrEmpty(assetPath) || !assetPath.StartsWith("Assets/", StringComparison.Ordinal))
2025-11-13 11:16:31 +08:00
return false;
2025-11-10 16:01:53 +08:00
assetPath = assetPath.Replace('\\', '/');
2025-11-13 11:16:31 +08:00
var isValidPath = assetPath.StartsWith(scriptGenerateData.UIPrefabRootPath, StringComparison.OrdinalIgnoreCase);
if (!isValidPath)
2025-11-10 16:01:53 +08:00
{
Debug.LogWarning($"UI存储位置与配置生成规则不符合 请检查对应配置的UIPrefabRootPath\n[AssetPath]{assetPath}\n[ConfigPath]{scriptGenerateData.UIPrefabRootPath}");
}
2025-11-13 11:16:31 +08:00
return isValidPath;
}
public string GetReferenceNamespace(List<UIBindData> uiBindDatas)
{
var namespaceSet = new HashSet<string>(StringComparer.Ordinal) { "UnityEngine" };
if (uiBindDatas?.Any(d => d.BindType == EBindType.ListCom) == true)
{
namespaceSet.Add("System.Collections.Generic");
}
uiBindDatas?
.Where(bindData => bindData?.BindCom?.FirstOrDefault() != null)
.Select(bindData => bindData.BindCom[0].GetType().Namespace)
.Where(ns => !string.IsNullOrEmpty(ns))
.ToList()
.ForEach(ns => namespaceSet.Add(ns));
return string.Join(Environment.NewLine, namespaceSet.Select(ns => $"using {ns};"));
}
public string GetVariableContent(List<UIBindData> uiBindDatas)
{
if (uiBindDatas == null || uiBindDatas.Count == 0) return string.Empty;
var variableBuilder = new StringBuilder();
var variables = uiBindDatas
.Where(b => b != null && !string.IsNullOrEmpty(b.Name))
.Select(b => GenerateVariableDeclaration(b))
.Where(declaration => !string.IsNullOrEmpty(declaration));
return string.Join("\n\n", variables);
}
private string GenerateVariableDeclaration(UIBindData bindData)
{
var variableName = bindData.Name;
var publicName = GetPublicComponentByNameRule(variableName);
var firstType = bindData.BindCom?.FirstOrDefault()?.GetType();
var typeName = firstType?.Name ?? "Component";
var declaration = new StringBuilder();
declaration.AppendLine("\t\t[SerializeField]");
switch (bindData.BindType)
{
case EBindType.None:
case EBindType.Widget:
declaration.AppendLine($"\t\tprivate {typeName} {variableName};");
declaration.Append($"\t\tpublic {typeName} {publicName} => {variableName};");
break;
case EBindType.ListCom:
var count = Math.Max(0, bindData.BindCom?.Count ?? 0);
declaration.AppendLine($"\t\tprivate {typeName}[] {variableName} = new {typeName}[{count}];");
declaration.Append($"\t\tpublic {typeName}[] {publicName} => {variableName};");
break;
}
return declaration.ToString();
2025-11-10 16:01:53 +08:00
}
}
}