453 lines
18 KiB
C#
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();
|
|
}
|
|
}
|
|
}
|