238 lines
7.9 KiB
C#
238 lines
7.9 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.IO;
|
||
using System.Text;
|
||
using UIInfoBuilder.ComponentExtractors;
|
||
using UIInfoBuilder.Data;
|
||
using UnityEditor;
|
||
using UnityEngine;
|
||
|
||
namespace UIInfoBuilder
|
||
{
|
||
public class UIInfoExtractor
|
||
{
|
||
private static readonly List<IComponentExtractor> _extractors = new List<IComponentExtractor>();
|
||
private static readonly DefaultComponentExtractor _defaultExtractor = new DefaultComponentExtractor();
|
||
|
||
static UIInfoExtractor()
|
||
{
|
||
// 注册特殊组件提取器(优先级高的放前面)
|
||
_extractors.Add(new RectTransformExtractor());
|
||
_extractors.Add(new ImageExtractor());
|
||
_extractors.Add(new TextExtractor());
|
||
_extractors.Add(new ButtonExtractor());
|
||
}
|
||
|
||
[MenuItem("Assets/UIInfoBuilder/ExtractPrefab")]
|
||
private static void _AssetHandle()
|
||
{
|
||
var selectedObjects = Selection.gameObjects;
|
||
foreach (var obj in selectedObjects)
|
||
{
|
||
string savePath = Application.dataPath + "/../ExtractedPrefabs/" + obj.name + ".json";
|
||
ExtractPrefab(obj, savePath);
|
||
Debug.Log($"[UIInfoBuilder] Extracted: {obj.name} -> {savePath}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 提取 Prefab 信息并保存为 JSON
|
||
/// </summary>
|
||
public static void ExtractPrefab(GameObject prefab, string savePath)
|
||
{
|
||
var rootNode = _ExtractNode(prefab);
|
||
_SaveToJson(rootNode, savePath);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 递归提取节点信息
|
||
/// </summary>
|
||
private static UIInfoNode _ExtractNode(GameObject go)
|
||
{
|
||
var node = new UIInfoNode
|
||
{
|
||
name = go.name,
|
||
active = go.activeSelf
|
||
};
|
||
|
||
// 提取所有组件
|
||
var components = go.GetComponents<Component>();
|
||
foreach (var component in components)
|
||
{
|
||
if (component == null)
|
||
continue;
|
||
|
||
var compInfo = _ExtractComponent(component);
|
||
node.components.Add(compInfo);
|
||
}
|
||
|
||
// 递归提取子节点
|
||
for (int i = 0; i < go.transform.childCount; i++)
|
||
{
|
||
var child = go.transform.GetChild(i).gameObject;
|
||
var childNode = _ExtractNode(child);
|
||
node.children.Add(childNode);
|
||
}
|
||
|
||
return node;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 提取单个组件信息
|
||
/// </summary>
|
||
private static UIInfoComponent _ExtractComponent(Component component)
|
||
{
|
||
var info = new UIInfoComponent
|
||
{
|
||
componentName = component.GetType().Name,
|
||
enable = _GetComponentEnabled(component)
|
||
};
|
||
|
||
// 查找匹配的特殊提取器
|
||
IComponentExtractor extractor = null;
|
||
foreach (var ext in _extractors)
|
||
{
|
||
if (ext.CanExtract(component))
|
||
{
|
||
extractor = ext;
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 使用特殊提取器或默认提取器
|
||
if (extractor != null)
|
||
{
|
||
extractor.Extract(component, info);
|
||
}
|
||
else
|
||
{
|
||
_defaultExtractor.Extract(component, info);
|
||
}
|
||
|
||
return info;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取组件的启用状态
|
||
/// </summary>
|
||
private static bool _GetComponentEnabled(Component component)
|
||
{
|
||
// Behaviour 类型的组件有 enabled 属性
|
||
if (component is Behaviour behaviour)
|
||
{
|
||
return behaviour.enabled;
|
||
}
|
||
|
||
// Renderer 类型的组件有 enabled 属性
|
||
if (component is Renderer renderer)
|
||
{
|
||
return renderer.enabled;
|
||
}
|
||
|
||
// Collider 类型的组件有 enabled 属性
|
||
if (component is Collider collider)
|
||
{
|
||
return collider.enabled;
|
||
}
|
||
|
||
// 其他组件默认返回 true
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 保存为 JSON 文件
|
||
/// </summary>
|
||
private static void _SaveToJson(UIInfoNode node, string savePath)
|
||
{
|
||
// 确保目录存在
|
||
string directory = Path.GetDirectoryName(savePath);
|
||
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
|
||
{
|
||
Directory.CreateDirectory(directory);
|
||
}
|
||
|
||
// 使用自定义递归序列化(JsonUtility 不支持嵌套 List 递归)
|
||
var sb = new StringBuilder();
|
||
_SerializeNode(node, sb, 0);
|
||
File.WriteAllText(savePath, sb.ToString());
|
||
}
|
||
|
||
/// <summary>
|
||
/// 递归序列化节点为 JSON
|
||
/// </summary>
|
||
private static void _SerializeNode(UIInfoNode node, StringBuilder sb, int indent)
|
||
{
|
||
string indentStr = new string(' ', indent * 2);
|
||
string indentStr1 = new string(' ', (indent + 1) * 2);
|
||
string indentStr2 = new string(' ', (indent + 2) * 2);
|
||
string indentStr3 = new string(' ', (indent + 3) * 2);
|
||
|
||
sb.AppendLine($"{indentStr}{{");
|
||
sb.AppendLine($"{indentStr1}\"name\": \"{_EscapeJsonString(node.name)}\",");
|
||
sb.AppendLine($"{indentStr1}\"active\": {node.active.ToString().ToLower()},");
|
||
|
||
// Components
|
||
sb.AppendLine($"{indentStr1}\"components\": [");
|
||
for (int i = 0; i < node.components.Count; i++)
|
||
{
|
||
var comp = node.components[i];
|
||
sb.AppendLine($"{indentStr2}{{");
|
||
sb.AppendLine($"{indentStr3}\"componentName\": \"{_EscapeJsonString(comp.componentName)}\",");
|
||
sb.AppendLine($"{indentStr3}\"enable\": {comp.enable.ToString().ToLower()},");
|
||
sb.Append($"{indentStr3}\"properties\": [");
|
||
|
||
if (comp.properties.Count > 0)
|
||
{
|
||
sb.AppendLine();
|
||
for (int j = 0; j < comp.properties.Count; j++)
|
||
{
|
||
string comma = j < comp.properties.Count - 1 ? "," : "";
|
||
sb.AppendLine($"{indentStr3} \"{_EscapeJsonString(comp.properties[j])}\"{comma}");
|
||
}
|
||
sb.AppendLine($"{indentStr3}]");
|
||
}
|
||
else
|
||
{
|
||
sb.AppendLine("]");
|
||
}
|
||
|
||
string compComma = i < node.components.Count - 1 ? "," : "";
|
||
sb.AppendLine($"{indentStr2}}}{compComma}");
|
||
}
|
||
sb.AppendLine($"{indentStr1}],");
|
||
|
||
// Children
|
||
sb.AppendLine($"{indentStr1}\"children\": [");
|
||
for (int i = 0; i < node.children.Count; i++)
|
||
{
|
||
_SerializeNode(node.children[i], sb, indent + 2);
|
||
if (i < node.children.Count - 1)
|
||
{
|
||
// 在上一个 } 后面加逗号
|
||
sb.Length -= Environment.NewLine.Length; // 移除换行
|
||
sb.AppendLine(",");
|
||
}
|
||
}
|
||
sb.AppendLine($"{indentStr1}]");
|
||
|
||
sb.AppendLine($"{indentStr}}}");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 转义 JSON 字符串中的特殊字符
|
||
/// </summary>
|
||
private static string _EscapeJsonString(string str)
|
||
{
|
||
if (string.IsNullOrEmpty(str))
|
||
return str;
|
||
|
||
return str
|
||
.Replace("\\", "\\\\")
|
||
.Replace("\"", "\\\"")
|
||
.Replace("\n", "\\n")
|
||
.Replace("\r", "\\r")
|
||
.Replace("\t", "\\t");
|
||
}
|
||
}
|
||
}
|