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");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|