Art_SubModule/Editor/Art_Tools/ArtBytesViewer.cs
2026-02-04 16:43:33 +08:00

453 lines
18 KiB
C#

using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Thrift;
using Thrift.Protocol;
using Thrift.Transport;
using Thrift.Transport.Client;
using Byway.Thrift.Data;
namespace ArtTools
{
/// <summary>
/// 美术资源Bytes文件查看器
/// 用于查看ArtResourceConfig.bytes和ArtAtlasConfig.bytes的内容
/// </summary>
public class ArtBytesViewer : EditorWindow
{
private enum ViewMode
{
ArtResourceConfig,
AtlasConfig
}
private ViewMode currentMode = ViewMode.ArtResourceConfig;
private Vector2 scrollPosition;
private Vector2 tableListScrollPosition;
private Vector2 itemListScrollPosition;
// ArtResourceConfig相关
private ArtResourceConfig artConfig;
private int selectedTableIndex = -1;
private string tableSearchText = "";
private string itemSearchText = "";
// AtlasConfig相关
private ArtAtlasConfig atlasConfig;
private int selectedAtlasIndex = -1;
private string atlasSearchText = "";
// 文件信息
private string artConfigPath = "Assets/Art_SubModule/Art_Bytes/ArtResourceConfig.bytes";
private string atlasConfigPath = "Assets/Art_SubModule/Art_Bytes/ArtAtlasConfig.bytes";
private FileInfo artConfigFileInfo;
private FileInfo atlasConfigFileInfo;
[MenuItem("美术工具/Thrift/Bytes查看器")]
public static void ShowWindow()
{
var window = GetWindow<ArtBytesViewer>("美术资源Bytes查看器");
window.minSize = new Vector2(800, 600);
window.Show();
}
private void OnEnable()
{
LoadBytesFiles();
}
private void OnGUI()
{
EditorGUILayout.BeginVertical();
// 顶部工具栏
DrawToolbar();
EditorGUILayout.Space(5);
// 根据模式显示不同内容
if (currentMode == ViewMode.ArtResourceConfig)
{
DrawArtResourceConfigView();
}
else
{
DrawAtlasConfigView();
}
EditorGUILayout.EndVertical();
}
private void DrawToolbar()
{
EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
// 模式切换
if (GUILayout.Toggle(currentMode == ViewMode.ArtResourceConfig, "美术资源配置", EditorStyles.toolbarButton))
{
if (currentMode != ViewMode.ArtResourceConfig)
{
currentMode = ViewMode.ArtResourceConfig;
selectedTableIndex = -1;
}
}
if (GUILayout.Toggle(currentMode == ViewMode.AtlasConfig, "图集配置", EditorStyles.toolbarButton))
{
if (currentMode != ViewMode.AtlasConfig)
{
currentMode = ViewMode.AtlasConfig;
selectedAtlasIndex = -1;
}
}
GUILayout.FlexibleSpace();
// 刷新按钮
if (GUILayout.Button("🔄 刷新", EditorStyles.toolbarButton, GUILayout.Width(60)))
{
LoadBytesFiles();
}
EditorGUILayout.EndHorizontal();
}
private void LoadBytesFiles()
{
// 加载ArtResourceConfig
try
{
string fullArtPath = Path.Combine(Application.dataPath, "..", artConfigPath);
if (File.Exists(fullArtPath))
{
byte[] bytes = File.ReadAllBytes(fullArtPath);
artConfigFileInfo = new FileInfo(fullArtPath);
using (var transport = new TMemoryBufferTransport(bytes, new TConfiguration()))
{
using (var protocol = new TBinaryProtocol(transport))
{
artConfig = new ArtResourceConfig();
artConfig.ReadAsync(protocol, System.Threading.CancellationToken.None).GetAwaiter().GetResult();
}
}
Debug.Log($"[ArtBytesViewer] 成功加载 ArtResourceConfig.bytes ({bytes.Length / 1024f:F2} KB, {artConfig.Tables.Count} 个表)");
}
else
{
Debug.LogWarning($"[ArtBytesViewer] 找不到文件: {fullArtPath}");
}
}
catch (System.Exception ex)
{
Debug.LogError($"[ArtBytesViewer] 加载ArtResourceConfig失败: {ex.Message}");
}
// 加载AtlasConfig
try
{
string fullAtlasPath = Path.Combine(Application.dataPath, "..", atlasConfigPath);
if (File.Exists(fullAtlasPath))
{
byte[] bytes = File.ReadAllBytes(fullAtlasPath);
atlasConfigFileInfo = new FileInfo(fullAtlasPath);
using (var transport = new TMemoryBufferTransport(bytes, new TConfiguration()))
{
using (var protocol = new TBinaryProtocol(transport))
{
atlasConfig = new ArtAtlasConfig();
atlasConfig.ReadAsync(protocol, System.Threading.CancellationToken.None).GetAwaiter().GetResult();
}
}
Debug.Log($"[ArtBytesViewer] 成功加载 ArtAtlasConfig.bytes ({bytes.Length / 1024f:F2} KB, {atlasConfig.Atlases.Count} 个图集)");
}
else
{
Debug.LogWarning($"[ArtBytesViewer] 找不到文件: {fullAtlasPath}");
}
}
catch (System.Exception ex)
{
Debug.LogError($"[ArtBytesViewer] 加载AtlasConfig失败: {ex.Message}");
}
}
private void DrawArtResourceConfigView()
{
if (artConfig == null)
{
EditorGUILayout.HelpBox("未加载ArtResourceConfig.bytes\n请确保文件存在: " + artConfigPath, MessageType.Warning);
return;
}
// 文件信息
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
EditorGUILayout.LabelField("文件信息", EditorStyles.boldLabel);
EditorGUILayout.LabelField($"路径: {artConfigPath}");
if (artConfigFileInfo != null)
{
EditorGUILayout.LabelField($"大小: {artConfigFileInfo.Length / 1024f:F2} KB");
EditorGUILayout.LabelField($"修改时间: {artConfigFileInfo.LastWriteTime:yyyy-MM-dd HH:mm:ss}");
}
EditorGUILayout.LabelField($"表数量: {artConfig.Tables.Count}");
EditorGUILayout.LabelField($"版本: {artConfig.Version}");
if (!string.IsNullOrEmpty(artConfig.GenerateTime))
{
EditorGUILayout.LabelField($"生成时间: {artConfig.GenerateTime}");
}
if (artConfig.PreloadTableIds != null && artConfig.PreloadTableIds.Count > 0)
{
EditorGUILayout.LabelField($"预加载表: {string.Join(", ", artConfig.PreloadTableIds)}");
}
EditorGUILayout.EndVertical();
EditorGUILayout.Space(5);
// 两栏布局
EditorGUILayout.BeginHorizontal();
// 左侧:表列表
EditorGUILayout.BeginVertical(GUILayout.Width(250));
EditorGUILayout.LabelField("资源表列表", EditorStyles.boldLabel);
// 搜索框
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("搜索:", GUILayout.Width(40));
tableSearchText = EditorGUILayout.TextField(tableSearchText);
EditorGUILayout.EndHorizontal();
tableListScrollPosition = EditorGUILayout.BeginScrollView(tableListScrollPosition, EditorStyles.helpBox);
var filteredTables = artConfig.Tables;
if (!string.IsNullOrEmpty(tableSearchText))
{
filteredTables = artConfig.Tables.Where(t =>
t.TableName.ToLower().Contains(tableSearchText.ToLower()) ||
t.TableId.ToString().Contains(tableSearchText)
).ToList();
}
for (int i = 0; i < filteredTables.Count; i++)
{
var table = filteredTables[i];
bool isSelected = selectedTableIndex == artConfig.Tables.IndexOf(table);
var style = new GUIStyle(GUI.skin.button);
style.alignment = TextAnchor.MiddleLeft;
if (isSelected)
{
style.normal.background = Texture2D.grayTexture;
}
if (GUILayout.Button($"[{table.TableId}] {table.TableName} ({table.Items.Count})", style))
{
selectedTableIndex = artConfig.Tables.IndexOf(table);
}
}
EditorGUILayout.EndScrollView();
EditorGUILayout.EndVertical();
// 右侧:详细信息
EditorGUILayout.BeginVertical();
if (selectedTableIndex >= 0 && selectedTableIndex < artConfig.Tables.Count)
{
var selectedTable = artConfig.Tables[selectedTableIndex];
EditorGUILayout.LabelField($"表: {selectedTable.TableName} (ID: {selectedTable.TableId})", EditorStyles.boldLabel);
EditorGUILayout.LabelField($"资源项数量: {selectedTable.Items.Count}");
EditorGUILayout.Space(5);
// 资源项搜索
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("筛选:", GUILayout.Width(40));
itemSearchText = EditorGUILayout.TextField(itemSearchText);
EditorGUILayout.EndHorizontal();
// 资源项列表
itemListScrollPosition = EditorGUILayout.BeginScrollView(itemListScrollPosition);
var filteredItems = selectedTable.Items;
if (!string.IsNullOrEmpty(itemSearchText))
{
filteredItems = selectedTable.Items.Where(item =>
item.Name.ToLower().Contains(itemSearchText.ToLower()) ||
item.Id.ToString().Contains(itemSearchText) ||
(!string.IsNullOrEmpty(item.Desc) && item.Desc.ToLower().Contains(itemSearchText.ToLower()))
).ToList();
}
// 表头
EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
EditorGUILayout.LabelField("ID", EditorStyles.boldLabel, GUILayout.Width(50));
EditorGUILayout.LabelField("名称", EditorStyles.boldLabel, GUILayout.Width(150));
EditorGUILayout.LabelField("描述", EditorStyles.boldLabel, GUILayout.Width(200));
EditorGUILayout.LabelField("Sprite", EditorStyles.boldLabel, GUILayout.Width(80));
EditorGUILayout.LabelField("Spine", EditorStyles.boldLabel, GUILayout.Width(80));
EditorGUILayout.EndHorizontal();
foreach (var item in filteredItems)
{
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField(item.Id.ToString(), GUILayout.Width(50));
EditorGUILayout.LabelField(item.Name, GUILayout.Width(150));
EditorGUILayout.LabelField(item.Desc ?? "", GUILayout.Width(200));
EditorGUILayout.LabelField(string.IsNullOrEmpty(item.SpritePath) ? "-" : "✓", GUILayout.Width(80));
EditorGUILayout.LabelField(string.IsNullOrEmpty(item.SpineAssetPath) ? "-" : "✓", GUILayout.Width(80));
EditorGUILayout.EndHorizontal();
// 详细路径信息
if (!string.IsNullOrEmpty(item.SpritePath))
{
EditorGUI.indentLevel++;
EditorGUILayout.LabelField("Sprite路径:", item.SpritePath, EditorStyles.wordWrappedLabel);
EditorGUI.indentLevel--;
}
if (!string.IsNullOrEmpty(item.SpineAssetPath))
{
EditorGUI.indentLevel++;
EditorGUILayout.LabelField("Spine路径:", item.SpineAssetPath, EditorStyles.wordWrappedLabel);
if (!string.IsNullOrEmpty(item.SpineAnimName))
{
EditorGUILayout.LabelField("动画名:", item.SpineAnimName);
}
EditorGUI.indentLevel--;
}
EditorGUILayout.EndVertical();
}
EditorGUILayout.EndScrollView();
EditorGUILayout.LabelField($"显示: {filteredItems.Count} / {selectedTable.Items.Count} 项");
}
else
{
EditorGUILayout.HelpBox("请在左侧选择一个资源表", MessageType.Info);
}
EditorGUILayout.EndVertical();
EditorGUILayout.EndHorizontal();
}
private void DrawAtlasConfigView()
{
if (atlasConfig == null)
{
EditorGUILayout.HelpBox("未加载ArtAtlasConfig.bytes\n请确保文件存在: " + atlasConfigPath, MessageType.Warning);
return;
}
// 文件信息
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
EditorGUILayout.LabelField("文件信息", EditorStyles.boldLabel);
EditorGUILayout.LabelField($"路径: {atlasConfigPath}");
if (atlasConfigFileInfo != null)
{
EditorGUILayout.LabelField($"大小: {atlasConfigFileInfo.Length / 1024f:F2} KB");
EditorGUILayout.LabelField($"修改时间: {atlasConfigFileInfo.LastWriteTime:yyyy-MM-dd HH:mm:ss}");
}
EditorGUILayout.LabelField($"图集数量: {atlasConfig.Atlases.Count}");
EditorGUILayout.LabelField($"版本: {atlasConfig.Version}");
if (!string.IsNullOrEmpty(atlasConfig.GenerateTime))
{
EditorGUILayout.LabelField($"生成时间: {atlasConfig.GenerateTime}");
}
EditorGUILayout.EndVertical();
EditorGUILayout.Space(5);
// 两栏布局
EditorGUILayout.BeginHorizontal();
// 左侧:图集列表
EditorGUILayout.BeginVertical(GUILayout.Width(250));
EditorGUILayout.LabelField("图集列表", EditorStyles.boldLabel);
// 搜索框
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("搜索:", GUILayout.Width(40));
atlasSearchText = EditorGUILayout.TextField(atlasSearchText);
EditorGUILayout.EndHorizontal();
tableListScrollPosition = EditorGUILayout.BeginScrollView(tableListScrollPosition, EditorStyles.helpBox);
var filteredAtlases = atlasConfig.Atlases;
if (!string.IsNullOrEmpty(atlasSearchText))
{
filteredAtlases = atlasConfig.Atlases.Where(a =>
a.Name.ToLower().Contains(atlasSearchText.ToLower())
).ToList();
}
for (int i = 0; i < filteredAtlases.Count; i++)
{
var atlas = filteredAtlases[i];
bool isSelected = selectedAtlasIndex == atlasConfig.Atlases.IndexOf(atlas);
var style = new GUIStyle(GUI.skin.button);
style.alignment = TextAnchor.MiddleLeft;
if (isSelected)
{
style.normal.background = Texture2D.grayTexture;
}
if (GUILayout.Button($"{atlas.Name} ({atlas.SpritePaths.Count})", style))
{
selectedAtlasIndex = atlasConfig.Atlases.IndexOf(atlas);
}
}
EditorGUILayout.EndScrollView();
EditorGUILayout.EndVertical();
// 右侧:详细信息
EditorGUILayout.BeginVertical();
if (selectedAtlasIndex >= 0 && selectedAtlasIndex < atlasConfig.Atlases.Count)
{
var selectedAtlas = atlasConfig.Atlases[selectedAtlasIndex];
EditorGUILayout.LabelField($"图集: {selectedAtlas.Name}", EditorStyles.boldLabel);
EditorGUILayout.LabelField($"Sprite数量: {selectedAtlas.SpritePaths.Count}");
EditorGUILayout.Space(5);
// Sprite路径列表
itemListScrollPosition = EditorGUILayout.BeginScrollView(itemListScrollPosition);
EditorGUILayout.LabelField("包含的Sprite路径:", EditorStyles.boldLabel);
int index = 1;
foreach (var spritePath in selectedAtlas.SpritePaths)
{
EditorGUILayout.BeginHorizontal(EditorStyles.helpBox);
EditorGUILayout.LabelField(index.ToString(), GUILayout.Width(30));
EditorGUILayout.LabelField(spritePath, EditorStyles.wordWrappedLabel);
EditorGUILayout.EndHorizontal();
index++;
}
EditorGUILayout.EndScrollView();
}
else
{
EditorGUILayout.HelpBox("请在左侧选择一个图集", MessageType.Info);
}
EditorGUILayout.EndVertical();
EditorGUILayout.EndHorizontal();
}
}
}