using System; using System.Collections.Generic; using System.IO; using System.Linq; using OfficeOpenXml; using UnityEditor; using UnityEngine; using Debug = UnityEngine.Debug; namespace DesignTools.LimitedTimeEvent { /// /// 小猫戏法限时事件常量配置工具 /// 读取 Docs/config/LimitedTimeEvent.xlsx 的 Const Sheet,仅编辑指定 Key 的 Value。 /// public class CatTrickConstEditor : BaseDesignToolEditor { private const string LIMITED_TIME_EVENT_EXCEL_NAME = "LimitedTimeEvent.xlsx"; private const string CONST_SHEET_NAME = "Const"; private const int HEADER_ROW = 1; private const int DATA_START_ROW = 3; private const string KEY_CONSUME_ENERGY = "CatTrick_ConsumeEnergy"; private const string KEY_REWARD_DIAMOND = "CatTrick_RewardDiamond"; private const string LABEL_CONSUME_ENERGY = "小猫戏法每次获得钻石需要消耗的体力"; private const string LABEL_REWARD_DIAMOND = "每次领取的钻石数量"; private readonly List constItems = new List(); private int keyColumnIndex = -1; private int valueColumnIndex = -1; [MenuItem("策划工具/限时事件/小猫戏法")] public static void ShowWindow() { CatTrickConstEditor window = GetWindow("小猫戏法"); window.minSize = window.GetMinWindowSize(); window.Show(); } protected override string GetDocsPathPrefKey() { return "CatTrickConstEditor_DocsPath"; } protected override string GetWindowTitle() { return "小猫戏法配置工具"; } protected override Vector2 GetMinWindowSize() { return new Vector2(760, 420); } protected override void LoadConfigData() { LoadConstSheet(); } protected override void DrawDataEditor() { EditorGUILayout.BeginVertical("box"); EditorGUILayout.HelpBox("仅会写回 LimitedTimeEvent.xlsx 的 Const Sheet,并且只修改 CatTrick_ConsumeEnergy 与 CatTrick_RewardDiamond 两个 Key 的 Value。", MessageType.Info); EditorGUILayout.EndVertical(); EditorGUILayout.Space(6); scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition); foreach (CatTrickConstItem item in constItems) { DrawConstItem(item); EditorGUILayout.Space(4); } EditorGUILayout.EndScrollView(); } protected override void SaveDataToExcel() { SaveConstSheet(); } private void LoadConstSheet() { constItems.Clear(); keyColumnIndex = -1; valueColumnIndex = -1; string excelPath = GetDocsConfigFilePath(LIMITED_TIME_EVENT_EXCEL_NAME); if (!File.Exists(excelPath)) { throw new FileNotFoundException($"未找到 {LIMITED_TIME_EVENT_EXCEL_NAME}", excelPath); } using (ExcelPackage package = new ExcelPackage(new FileInfo(excelPath))) { ExcelWorksheet worksheet = package.Workbook.Worksheets[CONST_SHEET_NAME]; if (worksheet == null) { throw new Exception($"{LIMITED_TIME_EVENT_EXCEL_NAME} 中未找到 Sheet: {CONST_SHEET_NAME}"); } if (worksheet.Dimension == null) { throw new Exception($"{LIMITED_TIME_EVENT_EXCEL_NAME}/{CONST_SHEET_NAME} 没有可读取的数据"); } keyColumnIndex = FindColumnIndex(worksheet, "Key"); valueColumnIndex = FindColumnIndex(worksheet, "Value"); if (keyColumnIndex < 0 || valueColumnIndex < 0) { throw new Exception($"{LIMITED_TIME_EVENT_EXCEL_NAME}/{CONST_SHEET_NAME} 表结构不正确,缺少 Key 或 Value 列"); } int rowCount = worksheet.Dimension.End.Row; for (int row = DATA_START_ROW; row <= rowCount; row++) { string key = worksheet.Cells[row, keyColumnIndex].Text.Trim(); if (string.IsNullOrEmpty(key)) { continue; } if (key != KEY_CONSUME_ENERGY && key != KEY_REWARD_DIAMOND) { continue; } string valueText = worksheet.Cells[row, valueColumnIndex].Text.Trim(); if (!int.TryParse(valueText, out int value)) { throw new Exception($"{CONST_SHEET_NAME} Sheet 第 {row} 行 Key={key} 的 Value 不是有效整数:{valueText}"); } constItems.Add(new CatTrickConstItem { Key = key, Value = value, RowIndex = row }); } } string[] missingKeys = new[] { KEY_CONSUME_ENERGY, KEY_REWARD_DIAMOND } .Where(targetKey => constItems.All(item => item.Key != targetKey)) .ToArray(); if (missingKeys.Length > 0) { throw new Exception($"{CONST_SHEET_NAME} Sheet 缺少以下 Key:{string.Join("、", missingKeys)}"); } constItems.Sort((left, right) => string.CompareOrdinal(left.Key, right.Key)); Debug.Log($"小猫戏法配置读取完成,共加载 {constItems.Count} 条数据"); } private void DrawConstItem(CatTrickConstItem item) { EditorGUILayout.BeginVertical("box"); EditorGUILayout.LabelField(GetDisplayName(item.Key), EditorStyles.boldLabel); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Value", GUILayout.Width(60)); item.Value = EditorGUILayout.IntField(item.Value, GUILayout.Width(180)); GUILayout.FlexibleSpace(); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); GUILayout.Space(4); EditorGUILayout.LabelField($"Excel 行号:{item.RowIndex}", EditorStyles.miniLabel); EditorGUILayout.EndHorizontal(); EditorGUILayout.EndVertical(); } private void SaveConstSheet() { if (constItems.Count == 0) { EditorUtility.DisplayDialog("提示", "当前没有可保存的数据,请先加载配置。", "确定"); return; } string excelPath = GetDocsConfigFilePath(LIMITED_TIME_EVENT_EXCEL_NAME); if (!File.Exists(excelPath)) { EditorUtility.DisplayDialog("错误", $"未找到文件:{excelPath}", "确定"); return; } try { using (ExcelPackage package = new ExcelPackage(new FileInfo(excelPath))) { ExcelWorksheet worksheet = package.Workbook.Worksheets[CONST_SHEET_NAME]; if (worksheet == null) { EditorUtility.DisplayDialog("错误", $"未找到 Sheet: {CONST_SHEET_NAME}", "确定"); return; } foreach (CatTrickConstItem item in constItems) { worksheet.Cells[item.RowIndex, valueColumnIndex].Value = item.Value; } package.Save(); } EditorUtility.DisplayDialog("成功", "小猫戏法配置已保存到 Excel!", "确定"); Debug.Log("小猫戏法配置保存成功"); } catch (Exception e) { EditorUtility.DisplayDialog("错误", $"保存失败: {e.Message}", "确定"); Debug.LogError($"保存小猫戏法配置失败: {e}"); } } private int FindColumnIndex(ExcelWorksheet worksheet, string columnName) { int columnCount = worksheet.Dimension?.End.Column ?? 0; for (int col = 1; col <= columnCount; col++) { if (string.Equals(worksheet.Cells[HEADER_ROW, col].Text.Trim(), columnName, StringComparison.OrdinalIgnoreCase)) { return col; } } return -1; } private string GetDisplayName(string key) { switch (key) { case KEY_CONSUME_ENERGY: return LABEL_CONSUME_ENERGY; case KEY_REWARD_DIAMOND: return LABEL_REWARD_DIAMOND; default: return key; } } [Serializable] private class CatTrickConstItem { public string Key; public int Value; public int RowIndex; } } }