111
This commit is contained in:
parent
0cce9edaef
commit
edd4bb822a
@ -1,112 +0,0 @@
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AlicizaX.UI.Editor
|
||||
{
|
||||
public class UIGenerateEditorWindow : EditorWindow
|
||||
{
|
||||
private GameObject selectedObject;
|
||||
private string[] menuItems;
|
||||
|
||||
[MenuItem("GameObject/UI生成绑定", priority = 10)]
|
||||
public static void ShowWindow()
|
||||
{
|
||||
GameObject selectedObject = Selection.gameObjects.FirstOrDefault();
|
||||
if (selectedObject == null) return;
|
||||
|
||||
var uiScriptConfigs = UIGenerateConfiguration.Instance.UIScriptGenerateConfigs;
|
||||
if (uiScriptConfigs == null || uiScriptConfigs.Count == 0) return;
|
||||
|
||||
var window = GetWindow<UIGenerateEditorWindow>(true, "UI 生成绑定", true);
|
||||
window.selectedObject = selectedObject;
|
||||
|
||||
window.menuItems = uiScriptConfigs.Select(config => $"{config.ProjectName}").ToArray();
|
||||
|
||||
var windowWidth = 300f;
|
||||
var windowHeight = Mathf.Max(1, window.menuItems.Length) * 35f + 10f;
|
||||
|
||||
|
||||
Vector3 objectWorldPosition = selectedObject.transform.position;
|
||||
Vector2 screenPoint;
|
||||
|
||||
var sceneView = SceneView.lastActiveSceneView;
|
||||
if (sceneView != null)
|
||||
{
|
||||
|
||||
Vector2 guiPointInSceneView = HandleUtility.WorldToGUIPoint(objectWorldPosition);
|
||||
|
||||
screenPoint = new Vector2(sceneView.position.x + guiPointInSceneView.x,
|
||||
sceneView.position.y + guiPointInSceneView.y);
|
||||
}
|
||||
else if (EditorWindow.mouseOverWindow != null)
|
||||
{
|
||||
|
||||
Vector2 guiPoint = HandleUtility.WorldToGUIPoint(objectWorldPosition);
|
||||
var host = EditorWindow.mouseOverWindow;
|
||||
screenPoint = new Vector2(host.position.x + guiPoint.x, host.position.y + guiPoint.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
var mainDisplay = Display.displays.Length > 0 ? Display.displays[0] : null;
|
||||
float centerX = (mainDisplay != null) ? (mainDisplay.systemWidth / 2f) : (Screen.width / 2f);
|
||||
float centerY = (mainDisplay != null) ? (mainDisplay.systemHeight / 2f) : (Screen.height / 2f);
|
||||
screenPoint = new Vector2(centerX, centerY);
|
||||
}
|
||||
|
||||
|
||||
Vector2 windowPosition = new Vector2(screenPoint.x, screenPoint.y - windowHeight - 5f);
|
||||
|
||||
|
||||
float screenW = Mathf.Max(100, Display.main.systemWidth);
|
||||
float screenH = Mathf.Max(100, Display.main.systemHeight);
|
||||
if (windowPosition.x + windowWidth > screenW) windowPosition.x = screenW - windowWidth - 5f;
|
||||
if (windowPosition.x < 5f) windowPosition.x = 5f;
|
||||
if (windowPosition.y < 5f) windowPosition.y = 5f;
|
||||
if (windowPosition.y + windowHeight > screenH) windowPosition.y = screenH - windowHeight - 5f;
|
||||
|
||||
window.minSize = new Vector2(windowWidth, windowHeight);
|
||||
window.maxSize = new Vector2(windowWidth, windowHeight);
|
||||
|
||||
window.position = new Rect(windowPosition, new Vector2(windowWidth, windowHeight));
|
||||
window.ShowPopup();
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
GUILayout.Space(5);
|
||||
if (menuItems == null || menuItems.Length == 0)
|
||||
{
|
||||
EditorGUILayout.LabelField("没有可用配置");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var item in menuItems)
|
||||
{
|
||||
if (GUILayout.Button(item, EditorStyles.toolbarButton, GUILayout.Height(28)))
|
||||
{
|
||||
GenerateScriptForConfig(selectedObject, item);
|
||||
Close();
|
||||
}
|
||||
|
||||
GUILayout.Space(6);
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateScriptForConfig(GameObject selectedObject, string itemName)
|
||||
{
|
||||
var uiScriptConfigs = UIGenerateConfiguration.Instance.UIScriptGenerateConfigs;
|
||||
var config = uiScriptConfigs.FirstOrDefault(c => $"{c.ProjectName}" == itemName);
|
||||
|
||||
if (config != null)
|
||||
{
|
||||
UIScriptGeneratorHelper.GenerateAndAttachScript(selectedObject, config);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("Configuration not found for item: " + itemName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
66
Editor/UI/GenerateWindow/UIGenerateQuick.cs
Normal file
66
Editor/UI/GenerateWindow/UIGenerateQuick.cs
Normal file
@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AlicizaX.UI.Editor
|
||||
{
|
||||
public static class UIGenerateQuick
|
||||
{
|
||||
[MenuItem("GameObject/UI生成绑定", priority = 10)]
|
||||
public static void ShowWindow()
|
||||
{
|
||||
GameObject selectedObject = Selection.gameObjects.FirstOrDefault();
|
||||
if (selectedObject == null)
|
||||
{
|
||||
Debug.LogError("没有选中物体!");
|
||||
return;
|
||||
}
|
||||
|
||||
var uiScriptConfigs = UIGenerateConfiguration.Instance.UIScriptGenerateConfigs;
|
||||
if (uiScriptConfigs == null || uiScriptConfigs.Count == 0)
|
||||
{
|
||||
Debug.Log("没有UI生成配置 请前往UISettingWindow添加");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var config in uiScriptConfigs)
|
||||
{
|
||||
if (CheckCanGenerate(selectedObject, config))
|
||||
{
|
||||
UIScriptGeneratorHelper.GenerateAndAttachScript(selectedObject, config);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Log("没有找到符合规则路径的生成配置 请检查!");
|
||||
}
|
||||
|
||||
public static bool CheckCanGenerate(GameObject targetObject, UIScriptGenerateData scriptGenerateData)
|
||||
{
|
||||
if (targetObject == null || scriptGenerateData == null) return false;
|
||||
|
||||
string assetPath = GetPrefabAssetPath(targetObject);
|
||||
if (string.IsNullOrEmpty(assetPath) || !assetPath.StartsWith("Assets/", StringComparison.Ordinal))
|
||||
return false; // 不在 Assets 下
|
||||
|
||||
assetPath = assetPath.Replace('\\', '/');
|
||||
bool result = assetPath.StartsWith(scriptGenerateData.UIPrefabRootPath, StringComparison.OrdinalIgnoreCase);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static string GetPrefabAssetPath(GameObject go)
|
||||
{
|
||||
var prefabAsset = PrefabUtility.GetCorrespondingObjectFromSource(go);
|
||||
if (prefabAsset != null)
|
||||
return AssetDatabase.GetAssetPath(prefabAsset);
|
||||
|
||||
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
if (prefabStage != null && prefabStage.IsPartOfPrefabContents(go))
|
||||
return prefabStage.assetPath;
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -28,9 +28,8 @@ namespace AlicizaX.UI.Editor
|
||||
public string GetPrivateComponentByNameRule(string regexName, string componentName, EBindType bindType)
|
||||
{
|
||||
string endPrefix = bindType == EBindType.ListCom ? "List" : string.Empty;
|
||||
int endNameIndex = componentName.IndexOf(
|
||||
UIGenerateConfiguration.Instance.UIGenerateCommonData.ComCheckEndName,
|
||||
StringComparison.Ordinal);
|
||||
var common = UIGenerateConfiguration.Instance.UIGenerateCommonData;
|
||||
int endNameIndex = componentName.IndexOf(common.ComCheckEndName, StringComparison.Ordinal);
|
||||
|
||||
string componentSuffix = endNameIndex >= 0 ? componentName.Substring(endNameIndex + 1) : componentName;
|
||||
|
||||
@ -39,12 +38,17 @@ namespace AlicizaX.UI.Editor
|
||||
|
||||
public string GetPublicComponentByNameRule(string variableName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(variableName)) return variableName;
|
||||
if (variableName.Length > 1)
|
||||
return variableName.Substring(1);
|
||||
return variableName;
|
||||
}
|
||||
|
||||
public string GetClassGenerateName(GameObject targetObject, UIScriptGenerateData scriptGenerateData)
|
||||
{
|
||||
return $"{UIGenerateConfiguration.Instance.UIGenerateCommonData.GeneratePrefix}_{targetObject.name}";
|
||||
var config = UIGenerateConfiguration.Instance.UIGenerateCommonData;
|
||||
string prefix = config.GeneratePrefix ?? "ui";
|
||||
return $"{prefix}_{targetObject.name}";
|
||||
}
|
||||
|
||||
public string GetUIResourceSavePath(GameObject targetObject, UIScriptGenerateData scriptGenerateData)
|
||||
@ -52,15 +56,11 @@ namespace AlicizaX.UI.Editor
|
||||
if (targetObject == null)
|
||||
return $"\"{nameof(targetObject)}\"";
|
||||
|
||||
// 默认返回资源名
|
||||
string defaultPath = targetObject.name;
|
||||
string assetPath = UIGenerateQuick.GetPrefabAssetPath(targetObject);
|
||||
if (string.IsNullOrEmpty(assetPath) || !assetPath.StartsWith("Assets/", StringComparison.Ordinal))
|
||||
return defaultPath;
|
||||
|
||||
// 获取对应的Prefab资源路径(支持场景Prefab实例 & Prefab编辑模式)
|
||||
string assetPath = GetPrefabAssetPath(targetObject);
|
||||
if (string.IsNullOrEmpty(assetPath) || !assetPath.StartsWith("Assets/"))
|
||||
return defaultPath; // 不在 Assets 下
|
||||
|
||||
// 统一使用正斜杠
|
||||
assetPath = assetPath.Replace('\\', '/');
|
||||
|
||||
switch (scriptGenerateData.LoadType)
|
||||
@ -82,11 +82,18 @@ namespace AlicizaX.UI.Editor
|
||||
case EUIResLoadType.AssetBundle:
|
||||
{
|
||||
string bundleRoot = scriptGenerateData.UIPrefabRootPath; // 例如 "Assets/Bundles/UI"
|
||||
var defaultPackage = YooAsset.Editor.AssetBundleCollectorSettingData.Setting.GetPackage("DefaultPackage");
|
||||
if (defaultPackage.EnableAddressable)
|
||||
return defaultPath;
|
||||
|
||||
if (!assetPath.StartsWith(bundleRoot, System.StringComparison.OrdinalIgnoreCase))
|
||||
try
|
||||
{
|
||||
var defaultPackage = YooAsset.Editor.AssetBundleCollectorSettingData.Setting.GetPackage("DefaultPackage");
|
||||
if (defaultPackage != null && defaultPackage.EnableAddressable)
|
||||
return defaultPath;
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
if (!assetPath.StartsWith(bundleRoot, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Debug.LogWarning($"[UI生成] 资源 {assetPath} 不在配置的 AssetBundle 根目录下: {bundleRoot}");
|
||||
return defaultPath;
|
||||
@ -100,43 +107,25 @@ namespace AlicizaX.UI.Editor
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取 GameObject 对应的 Prefab 资源路径,如果是 Prefab 编辑模式也可以获取
|
||||
/// </summary>
|
||||
private string GetPrefabAssetPath(GameObject go)
|
||||
{
|
||||
var prefabAsset = PrefabUtility.GetCorrespondingObjectFromSource(go);
|
||||
if (prefabAsset != null)
|
||||
return AssetDatabase.GetAssetPath(prefabAsset);
|
||||
|
||||
// Prefab 编辑模式
|
||||
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
if (prefabStage != null && prefabStage.IsPartOfPrefabContents(go))
|
||||
return prefabStage.assetPath;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取 Resources.Load 可用路径(去掉扩展名),如果不在指定的 Resources 根目录返回 null
|
||||
/// </summary>
|
||||
private string GetResourcesRelativePath(string assetPath, string resourcesRoot)
|
||||
{
|
||||
// 统一正斜杠
|
||||
if (string.IsNullOrEmpty(assetPath) || string.IsNullOrEmpty(resourcesRoot)) return null;
|
||||
assetPath = assetPath.Replace('\\', '/');
|
||||
resourcesRoot = resourcesRoot.Replace('\\', '/');
|
||||
|
||||
if (!assetPath.StartsWith(resourcesRoot, System.StringComparison.OrdinalIgnoreCase))
|
||||
if (!assetPath.StartsWith(resourcesRoot, StringComparison.OrdinalIgnoreCase))
|
||||
return null;
|
||||
|
||||
// 获取相对路径
|
||||
string relPath = assetPath.Substring(resourcesRoot.Length).TrimStart('/');
|
||||
return Path.ChangeExtension(relPath, null); // 去掉扩展名
|
||||
return Path.ChangeExtension(relPath, null);
|
||||
}
|
||||
|
||||
|
||||
public void WriteUIScriptContent(string className, string scriptContent, UIScriptGenerateData scriptGenerateData)
|
||||
{
|
||||
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));
|
||||
|
||||
string scriptFolderPath = scriptGenerateData.GenerateHolderCodePath;
|
||||
string scriptFilePath = Path.Combine(scriptFolderPath, className + ".cs");
|
||||
|
||||
@ -147,9 +136,10 @@ namespace AlicizaX.UI.Editor
|
||||
|
||||
if (File.Exists(scriptFilePath))
|
||||
{
|
||||
string oldText = File.ReadAllText(scriptFilePath);
|
||||
if (oldText.Equals(scriptContent))
|
||||
string oldText = File.ReadAllText(scriptFilePath, Encoding.UTF8);
|
||||
if (oldText.Equals(scriptContent, StringComparison.Ordinal))
|
||||
{
|
||||
// 文件未变更:标记并等待脚本 reload 去做附加
|
||||
EditorPrefs.SetString("Generate", className);
|
||||
UIScriptGeneratorHelper.CheckHasAttach();
|
||||
return;
|
||||
@ -163,13 +153,14 @@ namespace AlicizaX.UI.Editor
|
||||
|
||||
public bool CheckCanGenerate(GameObject targetObject, UIScriptGenerateData scriptGenerateData)
|
||||
{
|
||||
string assetPath = GetPrefabAssetPath(targetObject);
|
||||
if (string.IsNullOrEmpty(assetPath) || !assetPath.StartsWith("Assets/"))
|
||||
if (targetObject == null || scriptGenerateData == null) return false;
|
||||
|
||||
string assetPath = UIGenerateQuick.GetPrefabAssetPath(targetObject);
|
||||
if (string.IsNullOrEmpty(assetPath) || !assetPath.StartsWith("Assets/", StringComparison.Ordinal))
|
||||
return false; // 不在 Assets 下
|
||||
|
||||
// 统一使用正斜杠
|
||||
assetPath = assetPath.Replace('\\', '/');
|
||||
bool result = assetPath.StartsWith(scriptGenerateData.UIPrefabRootPath, System.StringComparison.OrdinalIgnoreCase);
|
||||
bool result = assetPath.StartsWith(scriptGenerateData.UIPrefabRootPath, StringComparison.OrdinalIgnoreCase);
|
||||
if (!result)
|
||||
{
|
||||
Debug.LogWarning($"UI存储位置与配置生成规则不符合 请检查对应配置的UIPrefabRootPath\n[AssetPath]{assetPath}\n[ConfigPath]{scriptGenerateData.UIPrefabRootPath}");
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@ -6,24 +7,23 @@ using System.Reflection;
|
||||
using System.Text;
|
||||
using AlicizaX.UI.Editor;
|
||||
using AlicizaX.UI.Runtime;
|
||||
using Sirenix.Utilities.Editor;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Callbacks;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public enum EBindType
|
||||
{
|
||||
None,
|
||||
Widget,
|
||||
ListCom,
|
||||
}
|
||||
|
||||
namespace AlicizaX.UI.Editor
|
||||
{
|
||||
public enum EBindType
|
||||
{
|
||||
None,
|
||||
Widget,
|
||||
ListCom,
|
||||
}
|
||||
|
||||
|
||||
[Serializable]
|
||||
class UIBindData
|
||||
internal class UIBindData
|
||||
{
|
||||
public string Name;
|
||||
public List<Component> BindCom;
|
||||
@ -31,42 +31,51 @@ namespace AlicizaX.UI.Editor
|
||||
|
||||
public UIBindData(string name, List<Component> bindCom, EBindType bindType = EBindType.None)
|
||||
{
|
||||
Name = name;
|
||||
BindCom = bindCom;
|
||||
Name = name ?? throw new ArgumentNullException(nameof(name));
|
||||
BindCom = bindCom ?? new List<Component>();
|
||||
BindType = bindType;
|
||||
}
|
||||
|
||||
public UIBindData(string name, Component bindCom, EBindType bindType = EBindType.None)
|
||||
: this(name, new List<Component> { bindCom }, bindType)
|
||||
{
|
||||
Name = name;
|
||||
BindCom = new List<Component>() { bindCom };
|
||||
BindType = bindType;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal static class UIScriptGeneratorHelper
|
||||
{
|
||||
private static UIGenerateConfiguration _uiGenerateConfiguration;
|
||||
private static IUIGeneratorRuleHelper _uiGeneratorRuleHelper;
|
||||
|
||||
/// <summary>
|
||||
/// 设置自定义命名规则助手[4](@ref)
|
||||
/// </summary>
|
||||
private static List<UIBindData> _uiBindDatas = new List<UIBindData>();
|
||||
private static HashSet<string> _arrayComponents = new HashSet<string>(StringComparer.Ordinal);
|
||||
|
||||
public static IUIGeneratorRuleHelper UIGeneratorRuleHelper
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_uiGeneratorRuleHelper == null || (_uiGeneratorRuleHelper != null && !UIConfiguration.UIScriptGeneratorRuleHelper.Equals(_uiGeneratorRuleHelper.GetType().FullName)))
|
||||
if (_uiGeneratorRuleHelper == null ||
|
||||
(_uiGeneratorRuleHelper != null && !UIConfiguration.UIScriptGeneratorRuleHelper.Equals(_uiGeneratorRuleHelper.GetType().FullName, StringComparison.Ordinal)))
|
||||
{
|
||||
Type ruleHelperType = Type.GetType(UIConfiguration.UIScriptGeneratorRuleHelper);
|
||||
var ruleHelperTypeName = UIConfiguration.UIScriptGeneratorRuleHelper;
|
||||
if (string.IsNullOrWhiteSpace(ruleHelperTypeName))
|
||||
{
|
||||
Debug.LogError("UIScriptGeneratorHelper: UIScriptGeneratorRuleHelper not configured.");
|
||||
return null;
|
||||
}
|
||||
|
||||
Type ruleHelperType = Type.GetType(ruleHelperTypeName);
|
||||
if (ruleHelperType == null)
|
||||
{
|
||||
Debug.LogError($"UIScriptGeneratorHelper: Could not load UI ScriptGeneratorHelper {UIConfiguration.UIScriptGeneratorRuleHelper}");
|
||||
Debug.LogError($"UIScriptGeneratorHelper: Could not load UI ScriptGeneratorHelper {ruleHelperTypeName}");
|
||||
return null;
|
||||
}
|
||||
|
||||
_uiGeneratorRuleHelper = Activator.CreateInstance(ruleHelperType) as IUIGeneratorRuleHelper;
|
||||
if (_uiGeneratorRuleHelper == null)
|
||||
{
|
||||
Debug.LogError($"UIScriptGeneratorHelper: Failed to instantiate {ruleHelperTypeName} as IUIGeneratorRuleHelper.");
|
||||
}
|
||||
}
|
||||
|
||||
return _uiGeneratorRuleHelper;
|
||||
@ -88,11 +97,13 @@ namespace AlicizaX.UI.Editor
|
||||
|
||||
private static string GetVersionType(string uiName)
|
||||
{
|
||||
foreach (var pair in UIConfiguration.UIElementRegexConfigs)
|
||||
if (string.IsNullOrEmpty(uiName)) return string.Empty;
|
||||
foreach (var pair in UIConfiguration.UIElementRegexConfigs ?? Enumerable.Empty<UIEelementRegexData>())
|
||||
{
|
||||
if (string.IsNullOrEmpty(pair?.uiElementRegex)) continue;
|
||||
if (uiName.StartsWith(pair.uiElementRegex, StringComparison.Ordinal))
|
||||
{
|
||||
return pair.componentType;
|
||||
return pair.componentType ?? string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,36 +112,49 @@ namespace AlicizaX.UI.Editor
|
||||
|
||||
private static string[] SplitComponentName(string name)
|
||||
{
|
||||
bool hasCom = name.Contains(UIConfiguration.UIGenerateCommonData.ComCheckEndName);
|
||||
if (!hasCom) return null;
|
||||
if (string.IsNullOrEmpty(name)) return null;
|
||||
|
||||
string comStr = name.Substring(0,
|
||||
name.IndexOf(UIConfiguration.UIGenerateCommonData.ComCheckEndName, StringComparison.Ordinal));
|
||||
return comStr.Split(UIConfiguration.UIGenerateCommonData.ComCheckSplitName);
|
||||
var common = UIConfiguration.UIGenerateCommonData;
|
||||
if (string.IsNullOrEmpty(common?.ComCheckEndName) || !name.Contains(common.ComCheckEndName))
|
||||
return null;
|
||||
|
||||
int endIndex = name.IndexOf(common.ComCheckEndName, StringComparison.Ordinal);
|
||||
if (endIndex <= 0) return null;
|
||||
|
||||
string comStr = name.Substring(0, endIndex);
|
||||
string split = common.ComCheckSplitName ?? "#";
|
||||
// 使用 string[] 重载并移除空项,防止错误 overload
|
||||
return comStr.Split(new[] { split }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
private static string GetKeyName(string key, string componentName, EBindType bindType)
|
||||
{
|
||||
return UIGeneratorRuleHelper.GetPrivateComponentByNameRule(key, componentName, bindType);
|
||||
var helper = UIGeneratorRuleHelper;
|
||||
if (helper == null)
|
||||
throw new InvalidOperationException("UIGeneratorRuleHelper is not configured.");
|
||||
return helper.GetPrivateComponentByNameRule(key, componentName, bindType);
|
||||
}
|
||||
|
||||
private static List<UIBindData> _uiBindDatas = new List<UIBindData>();
|
||||
private static List<string> _arrayComponents = new List<string>();
|
||||
|
||||
private static void GetBindData(Transform root)
|
||||
{
|
||||
if (root == null) return;
|
||||
|
||||
for (int i = 0; i < root.childCount; ++i)
|
||||
{
|
||||
Transform child = root.GetChild(i);
|
||||
if (child == null) continue;
|
||||
|
||||
// 排除关键字
|
||||
if (UIConfiguration.UIGenerateCommonData.ExcludeKeywords != null &&
|
||||
UIConfiguration.UIGenerateCommonData.ExcludeKeywords.Any(k =>
|
||||
!string.IsNullOrEmpty(k) && child.name.IndexOf(k, StringComparison.OrdinalIgnoreCase) >= 0))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
bool hasWidget = child.GetComponent<UIHolderObjectBase>() != null;
|
||||
|
||||
if (UIConfiguration.UIGenerateCommonData.ExcludeKeywords.Any(k =>
|
||||
child.name.IndexOf(k, StringComparison.OrdinalIgnoreCase) >= 0))
|
||||
continue;
|
||||
|
||||
bool isArrayComponent = child.name.StartsWith(
|
||||
UIConfiguration.UIGenerateCommonData.ArrayComSplitName, StringComparison.Ordinal);
|
||||
bool isArrayComponent = !string.IsNullOrEmpty(UIConfiguration.UIGenerateCommonData.ArrayComSplitName) &&
|
||||
child.name.StartsWith(UIConfiguration.UIGenerateCommonData.ArrayComSplitName, StringComparison.Ordinal);
|
||||
|
||||
if (hasWidget)
|
||||
{
|
||||
@ -138,27 +162,33 @@ namespace AlicizaX.UI.Editor
|
||||
}
|
||||
else if (isArrayComponent)
|
||||
{
|
||||
// 提取 array 标识文本(例如 "*Item*0" -> "Item")
|
||||
string splitCode = UIConfiguration.UIGenerateCommonData.ArrayComSplitName;
|
||||
int firstIndex = child.name.IndexOf(splitCode, StringComparison.Ordinal);
|
||||
int lastIndex = child.name.LastIndexOf(splitCode, StringComparison.Ordinal);
|
||||
string text = child.name.Substring(
|
||||
child.name.IndexOf(splitCode, StringComparison.Ordinal) + 1,
|
||||
lastIndex - 1);
|
||||
if (firstIndex < 0 || lastIndex <= firstIndex) continue;
|
||||
|
||||
// 中间文本
|
||||
string text = child.name.Substring(firstIndex + splitCode.Length, lastIndex - (firstIndex + splitCode.Length));
|
||||
if (string.IsNullOrEmpty(text)) continue;
|
||||
|
||||
if (_arrayComponents.Contains(text)) continue;
|
||||
_arrayComponents.Add(text);
|
||||
|
||||
// 在同一个父节点下收集包含该 text 的同级节点
|
||||
List<Transform> arrayComponents = new List<Transform>();
|
||||
for (int j = 0; j < root.childCount; j++)
|
||||
{
|
||||
if (root.GetChild(j).name.Contains(text, StringComparison.Ordinal))
|
||||
Transform sibling = root.GetChild(j);
|
||||
if (sibling != null && sibling.name.Contains(text, StringComparison.Ordinal))
|
||||
{
|
||||
arrayComponents.Add(root.GetChild(j));
|
||||
arrayComponents.Add(sibling);
|
||||
}
|
||||
}
|
||||
|
||||
CollectArrayComponent(arrayComponents, text);
|
||||
}
|
||||
else if (!isArrayComponent && !hasWidget)
|
||||
else // 普通组件/进一步递归
|
||||
{
|
||||
CollectComponent(child);
|
||||
GetBindData(child);
|
||||
@ -168,11 +198,14 @@ namespace AlicizaX.UI.Editor
|
||||
|
||||
private static void CollectComponent(Transform node)
|
||||
{
|
||||
if (node == null) return;
|
||||
|
||||
string[] componentArray = SplitComponentName(node.name);
|
||||
if (componentArray != null)
|
||||
{
|
||||
if (componentArray == null || componentArray.Length == 0) return;
|
||||
|
||||
foreach (var com in componentArray)
|
||||
{
|
||||
if (string.IsNullOrEmpty(com)) continue;
|
||||
string typeName = GetVersionType(com);
|
||||
if (string.IsNullOrEmpty(typeName)) continue;
|
||||
|
||||
@ -194,20 +227,27 @@ namespace AlicizaX.UI.Editor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void CollectWidget(Transform node)
|
||||
{
|
||||
if (node.name.IndexOf(UIConfiguration.UIGenerateCommonData.ComCheckEndName, StringComparison.Ordinal) != -1 &&
|
||||
node.name.IndexOf(UIConfiguration.UIGenerateCommonData.ComCheckSplitName, StringComparison.Ordinal) != -1)
|
||||
if (node == null) return;
|
||||
|
||||
var common = UIConfiguration.UIGenerateCommonData;
|
||||
if (node.name.IndexOf(common.ComCheckEndName, StringComparison.Ordinal) != -1 &&
|
||||
node.name.IndexOf(common.ComCheckSplitName, StringComparison.Ordinal) != -1)
|
||||
{
|
||||
Debug.LogWarning($"{node.name} child component cannot contain rule definition symbols!");
|
||||
return;
|
||||
}
|
||||
|
||||
UIHolderObjectBase component = node.GetComponent<UIHolderObjectBase>();
|
||||
string keyName = GetKeyName(string.Empty, node.name, EBindType.Widget);
|
||||
if (component == null)
|
||||
{
|
||||
Debug.LogError($"{node.name} expected to be a widget but does not have UIHolderObjectBase.");
|
||||
return;
|
||||
}
|
||||
|
||||
string keyName = GetKeyName(string.Empty, node.name, EBindType.Widget);
|
||||
if (_uiBindDatas.Exists(a => a.Name == keyName))
|
||||
{
|
||||
Debug.LogError($"Duplicate key found: {keyName}");
|
||||
@ -219,29 +259,47 @@ namespace AlicizaX.UI.Editor
|
||||
|
||||
private static void CollectArrayComponent(List<Transform> arrayNode, string nodeName)
|
||||
{
|
||||
if (arrayNode == null || arrayNode.Count == 0) return;
|
||||
|
||||
// 从 nodeName(例如 "*Item*0")取出组件描述部分(即名字中 @End 之前那部分)
|
||||
string[] componentArray = SplitComponentName(nodeName);
|
||||
arrayNode = arrayNode.OrderBy(s => int.Parse(s.name.Split('*').Last(),
|
||||
System.Globalization.CultureInfo.InvariantCulture)).ToList();
|
||||
|
||||
// 对 arrayNode 做基于后缀的安全排序:提取 last segment 作为索引(int.TryParse)
|
||||
string splitCode = UIConfiguration.UIGenerateCommonData.ArrayComSplitName;
|
||||
var orderedNodes = arrayNode
|
||||
.Select(n => new { Node = n, RawIndex = ExtractArrayIndex(n.name, splitCode) })
|
||||
.OrderBy(x => x.RawIndex.HasValue ? x.RawIndex.Value : int.MaxValue)
|
||||
.Select(x => x.Node)
|
||||
.ToList();
|
||||
|
||||
if (componentArray == null || componentArray.Length == 0)
|
||||
{
|
||||
Debug.LogWarning($"CollectArrayComponent: {nodeName} has no component definitions.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 准备临时 bind 列表,每个 componentArray 项对应一个 UIBindData
|
||||
List<UIBindData> tempBindDatas = new List<UIBindData>(componentArray.Length);
|
||||
for (int i = 0; i < componentArray.Length; i++)
|
||||
{
|
||||
string keyNamePreview = GetKeyName(componentArray[i], nodeName, EBindType.ListCom);
|
||||
tempBindDatas.Add(new UIBindData(keyNamePreview, new List<Component>(), EBindType.ListCom));
|
||||
}
|
||||
|
||||
if (componentArray != null)
|
||||
{
|
||||
int index = 0;
|
||||
foreach (var com in componentArray)
|
||||
{
|
||||
foreach (var node in arrayNode)
|
||||
// 遍历元素并填充
|
||||
for (int index = 0; index < componentArray.Length; index++)
|
||||
{
|
||||
string com = componentArray[index];
|
||||
if (string.IsNullOrEmpty(com)) continue;
|
||||
|
||||
string typeName = GetVersionType(com);
|
||||
if (string.IsNullOrEmpty(typeName)) continue;
|
||||
|
||||
foreach (var node in orderedNodes)
|
||||
{
|
||||
Component component = node.GetComponent(typeName);
|
||||
if (component != null)
|
||||
{
|
||||
string keyName = GetKeyName(com, nodeName, EBindType.ListCom);
|
||||
if (tempBindDatas.Count - 1 < index)
|
||||
tempBindDatas.Add(new UIBindData(keyName, new List<Component>(), EBindType.ListCom));
|
||||
|
||||
tempBindDatas[index].BindCom.Add(component);
|
||||
}
|
||||
else
|
||||
@ -249,73 +307,83 @@ namespace AlicizaX.UI.Editor
|
||||
Debug.LogError($"{node.name} does not have component of type {typeName}");
|
||||
}
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
_uiBindDatas.AddRange(tempBindDatas.ToArray());
|
||||
// 将结果合并到全局绑定数据
|
||||
_uiBindDatas.AddRange(tempBindDatas);
|
||||
}
|
||||
|
||||
private static int? ExtractArrayIndex(string nodeName, string splitCode)
|
||||
{
|
||||
if (string.IsNullOrEmpty(nodeName) || string.IsNullOrEmpty(splitCode)) return null;
|
||||
int last = nodeName.LastIndexOf(splitCode, StringComparison.Ordinal);
|
||||
if (last < 0) return null;
|
||||
string suffix = nodeName.Substring(last + splitCode.Length);
|
||||
if (int.TryParse(suffix, System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture, out int idx))
|
||||
return idx;
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string GetReferenceNamespace()
|
||||
{
|
||||
StringBuilder referenceNamespaceBuilder = new StringBuilder();
|
||||
HashSet<string> namespaces = new HashSet<string>();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
HashSet<string> namespaces = new HashSet<string>(StringComparer.Ordinal);
|
||||
|
||||
// 基础 namespace
|
||||
namespaces.Add("UnityEngine");
|
||||
referenceNamespaceBuilder.Append("using UnityEngine;\n");
|
||||
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;");
|
||||
}
|
||||
|
||||
foreach (var bindData in _uiBindDatas)
|
||||
{
|
||||
string nameSpace = bindData.BindCom.FirstOrDefault()?.GetType().Namespace;
|
||||
if (bindData.BindType == EBindType.ListCom)
|
||||
var comp = bindData.BindCom?.FirstOrDefault();
|
||||
string ns = comp?.GetType().Namespace;
|
||||
if (!string.IsNullOrEmpty(ns) && !namespaces.Contains(ns))
|
||||
{
|
||||
if (!namespaces.Contains("System.Collections.Generic"))
|
||||
{
|
||||
referenceNamespaceBuilder.Append("using System.Collections.Generic;\n");
|
||||
namespaces.Add("System.Collections.Generic");
|
||||
namespaces.Add(ns);
|
||||
sb.AppendLine($"using {ns};");
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(nameSpace) && !namespaces.Contains(nameSpace))
|
||||
{
|
||||
namespaces.Add(nameSpace);
|
||||
referenceNamespaceBuilder.Append($"using {nameSpace};\n");
|
||||
}
|
||||
}
|
||||
|
||||
return referenceNamespaceBuilder.ToString();
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static string GetVariableText(List<UIBindData> uiBindDatas)
|
||||
{
|
||||
if (uiBindDatas == null || uiBindDatas.Count == 0) return string.Empty;
|
||||
|
||||
StringBuilder variableTextBuilder = new StringBuilder();
|
||||
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;
|
||||
string publicName = UIGeneratorRuleHelper.GetPublicComponentByNameRule(variableName);
|
||||
if (string.IsNullOrEmpty(variableName)) continue;
|
||||
|
||||
string publicName = helper.GetPublicComponentByNameRule(variableName);
|
||||
variableTextBuilder.Append("\t\t[SerializeField]\n");
|
||||
|
||||
if (bindData.BindType == EBindType.None)
|
||||
var firstType = bindData.BindCom?.FirstOrDefault()?.GetType();
|
||||
string typeName = firstType?.Name ?? "Component";
|
||||
|
||||
if (bindData.BindType == EBindType.None || bindData.BindType == EBindType.Widget)
|
||||
{
|
||||
variableTextBuilder.Append(
|
||||
$"\t\tprivate {bindData.BindCom.FirstOrDefault()?.GetType().Name} {variableName};\n");
|
||||
variableTextBuilder.Append(
|
||||
$"\t\tpublic {bindData.BindCom.FirstOrDefault()?.GetType().Name} {publicName} => {variableName};\n\n");
|
||||
variableTextBuilder.Append($"\t\tprivate {typeName} {variableName};\n");
|
||||
variableTextBuilder.Append($"\t\tpublic {typeName} {publicName} => {variableName};\n\n");
|
||||
}
|
||||
else if (bindData.BindType == EBindType.ListCom)
|
||||
{
|
||||
variableTextBuilder.Append(
|
||||
$"\t\tprivate {bindData.BindCom.FirstOrDefault()?.GetType().Name}[] {variableName} = " +
|
||||
$"new {bindData.BindCom.FirstOrDefault()?.GetType().Name}[{bindData.BindCom.Count}];\n");
|
||||
variableTextBuilder.Append(
|
||||
$"\t\tpublic {bindData.BindCom.FirstOrDefault()?.GetType().Name}[] {publicName} => {variableName};\n\n");
|
||||
}
|
||||
else if (bindData.BindType == EBindType.Widget)
|
||||
{
|
||||
variableTextBuilder.Append(
|
||||
$"\t\tprivate {bindData.BindCom.FirstOrDefault()?.GetType().Name} {variableName};\n");
|
||||
variableTextBuilder.Append(
|
||||
$"\t\tpublic {bindData.BindCom.FirstOrDefault()?.GetType().Name} {publicName} => {variableName};\n\n");
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
@ -324,37 +392,45 @@ namespace AlicizaX.UI.Editor
|
||||
|
||||
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.Append("using AlicizaX.UI.Runtime;\n");
|
||||
scriptBuilder.Append($"namespace {generateNameSpace}\n");
|
||||
scriptBuilder.Append("{\n");
|
||||
scriptBuilder.Append("\t#Attribute#\n");
|
||||
scriptBuilder.Append($"\tpublic class {className} : UIHolderObjectBase\n");
|
||||
scriptBuilder.Append("\t{\n");
|
||||
|
||||
scriptBuilder.Append("\t\tpublic const string ResTag = #Tag#;\n");
|
||||
|
||||
scriptBuilder.Append("\t\t#region Generated by Script Tool\n\n");
|
||||
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.Append("\n\t\t#endregion\n");
|
||||
|
||||
scriptBuilder.Append("\t}\n");
|
||||
scriptBuilder.Append("}\n");
|
||||
|
||||
scriptBuilder.AppendLine("\t\t#endregion");
|
||||
scriptBuilder.AppendLine("\t}");
|
||||
scriptBuilder.AppendLine("}");
|
||||
return scriptBuilder.ToString();
|
||||
}
|
||||
|
||||
public static void GenerateAndAttachScript(GameObject targetObject, UIScriptGenerateData scriptGenerateData)
|
||||
{
|
||||
if (targetObject == null) throw new ArgumentNullException(nameof(targetObject));
|
||||
if (scriptGenerateData == null) throw new ArgumentNullException(nameof(scriptGenerateData));
|
||||
|
||||
if (!PrefabChecker.IsPrefabAsset(targetObject))
|
||||
{
|
||||
Debug.LogWarning("请将UI界面保存为对应的目录Prefab 在进行代码生成");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!UIGeneratorRuleHelper.CheckCanGenerate(targetObject, scriptGenerateData))
|
||||
var ruleHelper = UIGeneratorRuleHelper;
|
||||
if (ruleHelper == null)
|
||||
{
|
||||
Debug.LogError("UIGeneratorRuleHelper not available, abort.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ruleHelper.CheckCanGenerate(targetObject, scriptGenerateData))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -363,93 +439,145 @@ namespace AlicizaX.UI.Editor
|
||||
_uiBindDatas.Clear();
|
||||
_arrayComponents.Clear();
|
||||
|
||||
string className = UIGeneratorRuleHelper.GetClassGenerateName(targetObject, scriptGenerateData);
|
||||
string className = ruleHelper.GetClassGenerateName(targetObject, scriptGenerateData);
|
||||
if (string.IsNullOrEmpty(className))
|
||||
{
|
||||
Debug.LogError("Generated className is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
GetBindData(targetObject.transform);
|
||||
|
||||
string scriptContent = GenerateScript(className, scriptGenerateData.NameSpace);
|
||||
string tagName = $"\"{UIGeneratorRuleHelper.GetUIResourceSavePath(targetObject, scriptGenerateData)}\"";
|
||||
string tagName = $"\"{ruleHelper.GetUIResourceSavePath(targetObject, scriptGenerateData)}\"";
|
||||
|
||||
string uiAttribute = $"[UIRes({className}.ResTag, EUIResLoadType.{scriptGenerateData.LoadType})]";
|
||||
|
||||
scriptContent = scriptContent.Replace("#Attribute#", uiAttribute);
|
||||
scriptContent = scriptContent.Replace("#Tag#", tagName);
|
||||
|
||||
UIGeneratorRuleHelper.WriteUIScriptContent(className, scriptContent, scriptGenerateData);
|
||||
ruleHelper.WriteUIScriptContent(className, scriptContent, scriptGenerateData);
|
||||
}
|
||||
|
||||
[DidReloadScripts]
|
||||
public static void CheckHasAttach()
|
||||
{
|
||||
bool has = EditorPrefs.HasKey("Generate");
|
||||
if (has)
|
||||
{
|
||||
if (!EditorPrefs.HasKey("Generate"))
|
||||
return;
|
||||
|
||||
_uiBindDatas.Clear();
|
||||
_arrayComponents.Clear();
|
||||
|
||||
string className = EditorPrefs.GetString("Generate");
|
||||
int instanceId = EditorPrefs.GetInt("InstanceId", -1);
|
||||
|
||||
if (instanceId == -1)
|
||||
{
|
||||
Debug.LogWarning("CheckHasAttach: InstanceId missing.");
|
||||
EditorPrefs.DeleteKey("Generate");
|
||||
return;
|
||||
}
|
||||
|
||||
GameObject targetObject = (GameObject)EditorUtility.InstanceIDToObject(instanceId);
|
||||
GameObject targetObject = EditorUtility.InstanceIDToObject(instanceId) as GameObject;
|
||||
|
||||
if (!targetObject)
|
||||
if (targetObject == null)
|
||||
{
|
||||
Debug.Log("UI script generation attachment object missing!");
|
||||
Debug.LogWarning("UI script generation attachment object missing!");
|
||||
EditorPrefs.DeleteKey("Generate");
|
||||
return;
|
||||
}
|
||||
|
||||
EditorPrefs.DeleteKey("Generate");
|
||||
// 重新收集 bind 数据并附加脚本
|
||||
GetBindData(targetObject.transform);
|
||||
|
||||
AttachScriptToGameObject(targetObject, className);
|
||||
Debug.Log($"Generate {className} Successfully attached to game object");
|
||||
}
|
||||
EditorPrefs.DeleteKey("Generate");
|
||||
}
|
||||
|
||||
private static void AttachScriptToGameObject(GameObject targetObject, string scriptClassName)
|
||||
{
|
||||
if (targetObject == null) throw new ArgumentNullException(nameof(targetObject));
|
||||
if (string.IsNullOrEmpty(scriptClassName)) throw new ArgumentNullException(nameof(scriptClassName));
|
||||
|
||||
Type scriptType = null;
|
||||
|
||||
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
if (assembly.FullName.Contains("Editor")) continue;
|
||||
Type[] types = assembly.GetTypes();
|
||||
// 跳过典型的编辑器专用程序集(但只在程序集名字结束或包含 ".Editor" 时跳过)
|
||||
var asmName = assembly.GetName().Name ?? string.Empty;
|
||||
if (asmName.EndsWith(".Editor", StringComparison.OrdinalIgnoreCase) ||
|
||||
asmName.Equals("UnityEditor", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Type[] types;
|
||||
try
|
||||
{
|
||||
types = assembly.GetTypes();
|
||||
}
|
||||
catch (ReflectionTypeLoadException e)
|
||||
{
|
||||
types = e.Types.Where(t => t != null).ToArray();
|
||||
}
|
||||
|
||||
foreach (var type in types)
|
||||
{
|
||||
if (type.IsClass && !type.IsAbstract && type.Name.Contains(scriptClassName, StringComparison.Ordinal))
|
||||
if (type == null) continue;
|
||||
if (!type.IsClass || type.IsAbstract) continue;
|
||||
if (type.Name.Equals(scriptClassName, StringComparison.Ordinal) ||
|
||||
type.Name.Contains(scriptClassName, StringComparison.Ordinal))
|
||||
{
|
||||
scriptType = type;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (scriptType != null)
|
||||
if (scriptType != null) break;
|
||||
}
|
||||
|
||||
if (scriptType == null)
|
||||
{
|
||||
Component component = targetObject.GetOrAddComponent(scriptType);
|
||||
FieldInfo[] fields = scriptType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
Debug.LogError($"Could not find the class: {scriptClassName}");
|
||||
return;
|
||||
}
|
||||
|
||||
Component component = targetObject.GetOrAddComponent(scriptType);
|
||||
|
||||
FieldInfo[] fields = scriptType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
foreach (FieldInfo field in fields)
|
||||
{
|
||||
List<Component> componentInObjects = _uiBindDatas.Find(data => data.Name == field.Name)?.BindCom;
|
||||
if (componentInObjects != null)
|
||||
if (string.IsNullOrEmpty(field.Name)) continue;
|
||||
var componentInObjects = _uiBindDatas.Find(data => data.Name == field.Name)?.BindCom;
|
||||
if (componentInObjects == null)
|
||||
{
|
||||
Debug.LogError($"Field {field.Name} did not find matching component binding");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (field.FieldType.IsArray)
|
||||
{
|
||||
Type elementType = field.FieldType.GetElementType();
|
||||
Array array = Array.CreateInstance(elementType, componentInObjects.Count);
|
||||
if (elementType == null)
|
||||
{
|
||||
Debug.LogError($"Field {field.Name} has unknown element type.");
|
||||
continue;
|
||||
}
|
||||
|
||||
Array array = Array.CreateInstance(elementType, componentInObjects.Count);
|
||||
for (int i = 0; i < componentInObjects.Count; i++)
|
||||
{
|
||||
Component comp = componentInObjects[i];
|
||||
if (comp == null) continue;
|
||||
|
||||
if (elementType.IsInstanceOfType(comp))
|
||||
{
|
||||
array.SetValue(comp, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"Element {i} type mismatch, expected {elementType.Name}, actual {comp.GetType().Name}");
|
||||
Debug.LogError($"Element {i} type mismatch for field {field.Name}, expected {elementType.Name}, actual {comp.GetType().Name}");
|
||||
}
|
||||
}
|
||||
|
||||
@ -459,52 +587,42 @@ namespace AlicizaX.UI.Editor
|
||||
{
|
||||
if (componentInObjects.Count > 0)
|
||||
{
|
||||
if (field.FieldType.IsInstanceOfType(componentInObjects[0]))
|
||||
var first = componentInObjects[0];
|
||||
if (first == null) continue;
|
||||
|
||||
if (field.FieldType.IsInstanceOfType(first))
|
||||
{
|
||||
field.SetValue(component, componentInObjects[0]);
|
||||
field.SetValue(component, first);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"Field {field.Name} type mismatch, cannot assign value");
|
||||
Debug.LogError($"Field {field.Name} type mismatch, cannot assign value. Field expects {field.FieldType.Name}, actual {first.GetType().Name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"Field {field.Name} did not find matching component binding");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"Could not find the class: {scriptClassName}");
|
||||
}
|
||||
}
|
||||
|
||||
public static class PrefabChecker
|
||||
{
|
||||
public static bool IsEditingPrefabAsset(GameObject go)
|
||||
{
|
||||
// 检查当前是否在Prefab编辑模式
|
||||
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
if (prefabStage == null)
|
||||
return false;
|
||||
|
||||
// 检查选中对象是否属于当前PrefabStage
|
||||
return prefabStage.IsPartOfPrefabContents(go);
|
||||
}
|
||||
|
||||
public static bool IsPrefabAsset(GameObject go)
|
||||
{
|
||||
// 普通Asset目录中的Prefab
|
||||
if (go == null) return false;
|
||||
|
||||
var assetType = PrefabUtility.GetPrefabAssetType(go);
|
||||
if (assetType == PrefabAssetType.Regular ||
|
||||
assetType == PrefabAssetType.Variant ||
|
||||
assetType == PrefabAssetType.Model)
|
||||
return true;
|
||||
|
||||
// Prefab编辑模式下
|
||||
return IsEditingPrefabAsset(go);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user