using System.Collections.Generic; using System.IO; using System.Linq; using UnityEditor; using UnityEngine; using OfficeOpenXml; using ArtResource; namespace DesignTools { /// /// 一次性工具:将 Item.xlsx 的 Res 字段从 "TableId,ItemId" 迁移为 "TableName,ItemName" /// 使用完毕后可删除此文件 /// public static class MigrateResFormatTool { private const string ART_SO_PATH = "Assets/Art_SubModule/Art_SO"; private const string ITEM_SHEET_NAME = "Item"; [MenuItem("策划工具/一次性迁移/Res格式 ID→Name")] public static void Execute() { // 1. 选择 Item.xlsx string excelPath = EditorUtility.OpenFilePanel("选择 Item.xlsx", "", "xlsx"); if (string.IsNullOrEmpty(excelPath)) return; if (!File.Exists(excelPath)) { EditorUtility.DisplayDialog("错误", "文件不存在", "确定"); return; } // 2. 备份 string backupPath = excelPath + ".bak"; File.Copy(excelPath, backupPath, true); Debug.Log($"已备份到: {backupPath}"); // 3. 加载所有 ArtTableSO var allArtTables = new List(); string[] guids = AssetDatabase.FindAssets("t:ArtTableSO", new[] { ART_SO_PATH }); foreach (string guid in guids) { string path = AssetDatabase.GUIDToAssetPath(guid); var so = AssetDatabase.LoadAssetAtPath(path); if (so != null) allArtTables.Add(so); } if (allArtTables.Count == 0) { EditorUtility.DisplayDialog("错误", "未找到任何 ArtTableSO 资源", "确定"); return; } // 4. 读取并修改 Excel int migratedCount = 0; int skippedCount = 0; int errorCount = 0; var errors = new List(); using (var package = new ExcelPackage(new FileInfo(excelPath))) { var ws = package.Workbook.Worksheets[ITEM_SHEET_NAME]; if (ws == null) { EditorUtility.DisplayDialog("错误", $"未找到 Sheet: {ITEM_SHEET_NAME}", "确定"); return; } // 找 Res 列 int resCol = -1; int idCol = -1; int nameCol = -1; int colCount = ws.Dimension?.Columns ?? 0; for (int c = 1; c <= colCount; c++) { string h = ws.Cells[1, c].Text; if (h == "Res") resCol = c; else if (h == "Id") idCol = c; else if (h == "Name") nameCol = c; } if (resCol < 0) { EditorUtility.DisplayDialog("错误", "未找到 Res 列", "确定"); return; } int rowCount = ws.Dimension?.Rows ?? 0; for (int row = 3; row <= rowCount; row++) { string res = ws.Cells[row, resCol].Text.Trim(); if (string.IsNullOrEmpty(res)) continue; string[] parts = res.Split(','); if (parts.Length < 2) continue; // 判断是否是旧格式(首段为数字) if (!int.TryParse(parts[0], out int tableId)) { skippedCount++; continue; } int.TryParse(parts[1], out int artItemId); string rowId = idCol > 0 ? ws.Cells[row, idCol].Text : row.ToString(); string rowName = nameCol > 0 ? ws.Cells[row, nameCol].Text : ""; var table = allArtTables.FirstOrDefault(x => x.TableId == tableId); if (table == null) { errorCount++; errors.Add($"Row {row} Id={rowId}({rowName}): TableId={tableId} 不存在"); continue; } if (artItemId < 0) { ws.Cells[row, resCol].Value = $"{table.TableName},"; migratedCount++; continue; } var artItem = table.Items.FirstOrDefault(x => x.Id == artItemId); if (artItem == null) { errorCount++; errors.Add($"Row {row} Id={rowId}({rowName}): Table={table.TableName} 中无 ItemId={artItemId}"); continue; } ws.Cells[row, resCol].Value = $"{table.TableName},{artItem.Name}"; migratedCount++; } package.Save(); } // 5. 报告结果 string msg = $"迁移完成!\n\n" + $"成功: {migratedCount} 条\n" + $"已是新格式(跳过): {skippedCount} 条\n" + $"错误: {errorCount} 条\n\n" + $"备份文件: {backupPath}"; if (errorCount > 0) { msg += $"\n\n错误详情:\n{string.Join("\n", errors)}"; } EditorUtility.DisplayDialog("Res迁移结果", msg, "确定"); Debug.Log(msg); } } }