From e8067c676d352f70bc803d69b516a80e690b7b62 Mon Sep 17 00:00:00 2001 From: zhang hongbo Date: Wed, 25 Mar 2026 11:03:13 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E5=9C=BA=E6=99=AF=E6=AD=A5=E9=AA=A4?= =?UTF-8?q?=E5=AE=A0=E7=89=A9=E5=B8=81=E6=B6=88=E8=80=97=E5=92=8C=E6=AD=A5?= =?UTF-8?q?=E9=AA=A4=E6=89=B9=E6=AC=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Scene/DecorateCostPlannerEditor.cs | 949 ++++++++++++++++++ .../Scene/DecorateCostPlannerEditor.cs.meta | 11 + 2 files changed, 960 insertions(+) create mode 100644 Scripts/Editor/Design_Tools/Scene/DecorateCostPlannerEditor.cs create mode 100644 Scripts/Editor/Design_Tools/Scene/DecorateCostPlannerEditor.cs.meta diff --git a/Scripts/Editor/Design_Tools/Scene/DecorateCostPlannerEditor.cs b/Scripts/Editor/Design_Tools/Scene/DecorateCostPlannerEditor.cs new file mode 100644 index 0000000..aef998a --- /dev/null +++ b/Scripts/Editor/Design_Tools/Scene/DecorateCostPlannerEditor.cs @@ -0,0 +1,949 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using OfficeOpenXml; +using UnityEditor; +using UnityEditor.UIElements; +using UnityEngine; +using UnityEngine.UIElements; + +namespace DesignTools.Scene +{ + /// + /// 装饰场景消耗/批次配置工具 + /// 读取 Docs/config/DecorateCost.xlsx 的 DecorateCost Sheet,供策划编辑每步消耗与批次。 + /// + public class DecorateCostPlannerEditor : BaseDesignToolEditor + { + private static readonly string[] BATCH_NAMES = + { + string.Empty, + "first", + "second", + "third", + "four", + "five", + "six", + "seven", + "eight", + "nine", + "ten", + "eleven", + "twelve", + "thirteen", + "fourteen", + "fifteen", + "sixteen", + "seventeen", + "eighteen", + "nineteen", + "twenty", + "twentyone", + "twentytwo", + "twentythree", + "twentyfour", + "twentyfive", + "twentysix", + "twentyseven", + "twentyeight", + "twentynine", + "thirty", + "thirtyone", + "thirtytwo", + "thirtythree", + "thirtyfour", + "thirtyfive", + "thirtysix", + "thirtyseven", + "thirtyeight", + "thirtynine", + "forty", + "fortyone" + }; + + private const string DECORATE_COST_EXCEL_NAME = "DecorateCost.xlsx"; + private const string DECORATE_COST_SHEET_NAME = "DecorateCost"; + private const int DATA_START_ROW = 3; + private const int TOTAL_COL_COUNT = 17; + + private const int COL_ID = 1; + private const int COL_AREA_ID = 2; + private const int COL_SORT_ID = 3; + private const int COL_COST_COUNT = 4; + private const int COL_POS = 7; + + private readonly List allRows = new List(); + private readonly Dictionary rowIndexMap = new Dictionary(); + private readonly HashSet dirtyRowIndexes = new HashSet(); + private List availableAreaIds = new List(); + private List currentAreaStepRows = new List(); + + private int selectedAreaId = -1; + private int areaIdInput = 2; + private int currentAreaExpectedStepCount; + + [MenuItem("策划工具/场景/装饰场景消耗与批次")] + public static void ShowWindow() + { + var window = GetWindow("装饰场景消耗与批次"); + window.minSize = window.GetMinWindowSize(); + window.Show(); + } + + protected override string GetDocsPathPrefKey() + { + return "DecorateCostPlannerEditor_DocsPath"; + } + + protected override string GetWindowTitle() + { + return "装饰场景消耗与批次工具"; + } + + protected override Vector2 GetMinWindowSize() + { + return new Vector2(920, 680); + } + + protected override void LoadConfigData() + { + LoadDecorateCostExcel(); + currentAreaStepRows.Clear(); + currentAreaExpectedStepCount = 0; + selectedAreaId = -1; + areaIdInput = GetDefaultAreaId(); + + if (availableAreaIds.Count == 0) + { + EditorUtility.DisplayDialog("提示", "DecorateCost 中没有可编辑的 AreaId 数据。", "确定"); + return; + } + + EditorApplication.delayCall += ShowAreaInputDialog; + } + + protected override void DrawDataEditor() + { + DrawAreaSelector(); + EditorGUILayout.Space(6); + + if (selectedAreaId < 0) + { + EditorGUILayout.HelpBox("请先输入并加载 AreaId。AreaId=1 不允许编辑;AreaId=2-5 为 20 步;AreaId>=6 为 25 步。", MessageType.Info); + return; + } + + DrawAreaSummary(); + EditorGUILayout.Space(6); + DrawQuickActions(); + EditorGUILayout.Space(6); + DrawStepTable(); + } + + protected override void SaveDataToExcel() + { + SaveDecorateCostExcel(); + } + + private void LoadDecorateCostExcel() + { + allRows.Clear(); + rowIndexMap.Clear(); + dirtyRowIndexes.Clear(); + + string excelPath = GetDocsConfigFilePath(DECORATE_COST_EXCEL_NAME); + if (!File.Exists(excelPath)) + { + throw new FileNotFoundException($"未找到 {DECORATE_COST_EXCEL_NAME}", excelPath); + } + + using (ExcelPackage package = new ExcelPackage(new FileInfo(excelPath))) + { + ExcelWorksheet worksheet = package.Workbook.Worksheets[DECORATE_COST_SHEET_NAME]; + if (worksheet == null) + { + throw new Exception($"未找到 Sheet: {DECORATE_COST_SHEET_NAME}"); + } + + if (worksheet.Dimension == null) + { + availableAreaIds = new List(); + return; + } + + int rowCount = worksheet.Dimension.End.Row; + for (int row = DATA_START_ROW; row <= rowCount; row++) + { + string idText = worksheet.Cells[row, COL_ID].Text.Trim(); + string areaIdText = worksheet.Cells[row, COL_AREA_ID].Text.Trim(); + string sortIdText = worksheet.Cells[row, COL_SORT_ID].Text.Trim(); + + if (string.IsNullOrEmpty(idText) && string.IsNullOrEmpty(areaIdText) && string.IsNullOrEmpty(sortIdText)) + { + continue; + } + + string[] fields = new string[TOTAL_COL_COUNT]; + for (int col = 1; col <= TOTAL_COL_COUNT; col++) + { + fields[col - 1] = worksheet.Cells[row, col].Text ?? string.Empty; + } + + DecorateCostExcelRow dataRow = new DecorateCostExcelRow(row, fields); + allRows.Add(dataRow); + rowIndexMap[row] = dataRow; + } + } + + availableAreaIds = allRows + .Select(row => row.AreaId) + .Where(areaId => areaId > 1) + .Distinct() + .OrderBy(areaId => areaId) + .ToList(); + } + + private void DrawAreaSelector() + { + EditorGUILayout.BeginVertical("box"); + EditorGUILayout.LabelField("AreaId 选择", EditorStyles.boldLabel); + + EditorGUILayout.BeginHorizontal(); + areaIdInput = EditorGUILayout.IntField("AreaId", areaIdInput, GUILayout.Width(240)); + + if (GUILayout.Button("加载 AreaId", GUILayout.Width(120), GUILayout.Height(24))) + { + TrySelectArea(areaIdInput, true); + } + + if (GUILayout.Button("重新输入", GUILayout.Width(100), GUILayout.Height(24))) + { + ShowAreaInputDialog(); + } + + GUILayout.FlexibleSpace(); + EditorGUILayout.EndHorizontal(); + + string previewText = availableAreaIds.Count <= 15 + ? string.Join(", ", availableAreaIds) + : string.Join(", ", availableAreaIds.Take(15)) + " ..."; + EditorGUILayout.HelpBox($"可编辑 AreaId:{previewText}", MessageType.None); + EditorGUILayout.EndVertical(); + } + + private void DrawAreaSummary() + { + List missingSortIds = GetMissingSortIds(); + int actualCount = currentAreaStepRows.Count; + string summary = $"当前 AreaId:{selectedAreaId}\n期望步数:{currentAreaExpectedStepCount}\n实际可编辑步数:{actualCount}\n未保存修改:{dirtyRowIndexes.Count} 行"; + + if (missingSortIds.Count > 0) + { + string missingText = string.Join(", ", missingSortIds.Take(10)); + if (missingSortIds.Count > 10) + { + missingText += " ..."; + } + + EditorGUILayout.HelpBox(summary + $"\n\n⚠ 缺失步骤:{missingText}", MessageType.Warning); + return; + } + + EditorGUILayout.HelpBox(summary, MessageType.Info); + } + + private void DrawQuickActions() + { + using (new EditorGUI.DisabledScope(currentAreaStepRows.Count == 0 || currentAreaExpectedStepCount <= 0)) + { + EditorGUILayout.BeginHorizontal(); + + GUI.backgroundColor = new Color(0.78f, 0.92f, 1f); + if (GUILayout.Button("快捷设置资源消耗", GUILayout.Width(180), GUILayout.Height(28))) + { + DecorateCostPlannerBatchCostWindow.ShowWindow(currentAreaExpectedStepCount, ApplyBatchCostSettings); + } + + GUI.backgroundColor = new Color(1f, 0.9f, 0.65f); + if (GUILayout.Button("快捷设置步骤批次", GUILayout.Width(180), GUILayout.Height(28))) + { + DecorateCostPlannerBatchSkipWindow.ShowWindow(currentAreaExpectedStepCount, ApplyBatchBatchSettings); + } + + GUI.backgroundColor = Color.white; + GUILayout.FlexibleSpace(); + EditorGUILayout.EndHorizontal(); + } + + GUI.backgroundColor = Color.white; + } + + private void DrawStepTable() + { + EditorGUILayout.BeginVertical("box"); + EditorGUILayout.LabelField("步骤配置", EditorStyles.boldLabel); + EditorGUILayout.Space(4); + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("SortId", EditorStyles.boldLabel, GUILayout.Width(70)); + EditorGUILayout.LabelField("CostCount", EditorStyles.boldLabel, GUILayout.Width(120)); + EditorGUILayout.LabelField("步骤批次", EditorStyles.boldLabel, GUILayout.Width(140)); + EditorGUILayout.LabelField("批次映射", EditorStyles.boldLabel, GUILayout.Width(120)); + EditorGUILayout.LabelField("Title", EditorStyles.boldLabel, GUILayout.Width(260)); + EditorGUILayout.EndHorizontal(); + + EditorGUILayout.Space(2); + scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition); + + foreach (DecorateCostExcelRow row in currentAreaStepRows.OrderBy(item => item.SortId)) + { + DrawSingleStepRow(row); + } + + EditorGUILayout.EndScrollView(); + EditorGUILayout.EndVertical(); + } + + private void DrawSingleStepRow(DecorateCostExcelRow row) + { + EditorGUILayout.BeginHorizontal("box"); + EditorGUILayout.LabelField(row.SortId.ToString(), GUILayout.Width(70)); + + EditorGUI.BeginChangeCheck(); + int newCostCount = EditorGUILayout.IntField(row.CostCount, GUILayout.Width(120)); + if (EditorGUI.EndChangeCheck()) + { + row.CostCount = Mathf.Max(0, newCostCount); + MarkRowDirty(row); + } + + EditorGUI.BeginChangeCheck(); + int newBatchValue = EditorGUILayout.IntField(row.BatchValue, GUILayout.Width(140)); + if (EditorGUI.EndChangeCheck()) + { + row.BatchValue = Mathf.Max(0, newBatchValue); + MarkRowDirty(row); + } + + EditorGUILayout.LabelField(GetBatchDisplayName(row.BatchValue), GUILayout.Width(120)); + + EditorGUILayout.LabelField(string.IsNullOrEmpty(row.Title) ? "-" : row.Title, GUILayout.Width(260)); + GUILayout.FlexibleSpace(); + EditorGUILayout.EndHorizontal(); + } + + private void ApplyBatchCostSettings(int[] costs) + { + if (costs == null || costs.Length == 0) + { + return; + } + + int updatedCount = 0; + List missingSortIds = new List(); + + for (int step = 1; step <= currentAreaExpectedStepCount; step++) + { + DecorateCostExcelRow row = currentAreaStepRows.FirstOrDefault(item => item.SortId == step); + if (row == null) + { + missingSortIds.Add(step); + continue; + } + + int groupIndex = Mathf.Clamp((step - 1) / 5, 0, costs.Length - 1); + if (row.CostCount != costs[groupIndex]) + { + row.CostCount = Mathf.Max(0, costs[groupIndex]); + MarkRowDirty(row); + updatedCount++; + } + } + + ShowBatchApplyResult("资源消耗", updatedCount, missingSortIds); + } + + private void ApplyBatchBatchSettings(int[] batches) + { + if (batches == null || batches.Length == 0) + { + return; + } + + int updatedCount = 0; + List missingSortIds = new List(); + + for (int step = 1; step <= currentAreaExpectedStepCount; step++) + { + DecorateCostExcelRow row = currentAreaStepRows.FirstOrDefault(item => item.SortId == step); + if (row == null) + { + missingSortIds.Add(step); + continue; + } + + int batchValue = step - 1 < batches.Length ? Mathf.Max(0, batches[step - 1]) : 0; + if (row.BatchValue != batchValue) + { + row.BatchValue = batchValue; + MarkRowDirty(row); + updatedCount++; + } + } + + ShowBatchApplyResult("步骤批次", updatedCount, missingSortIds); + } + + private void ShowBatchApplyResult(string label, int updatedCount, List missingSortIds) + { + string message = $"已应用{label}快捷设置,更新 {updatedCount} 步。"; + if (missingSortIds.Count > 0) + { + message += $"\n\n缺失步骤:{string.Join(", ", missingSortIds)}"; + } + + EditorUtility.DisplayDialog("完成", message, "确定"); + } + + private void SaveDecorateCostExcel() + { + if (dirtyRowIndexes.Count == 0) + { + EditorUtility.DisplayDialog("提示", "当前没有需要保存的修改。", "确定"); + return; + } + + string excelPath = GetDocsConfigFilePath(DECORATE_COST_EXCEL_NAME); + if (!File.Exists(excelPath)) + { + EditorUtility.DisplayDialog("错误", $"未找到文件:{excelPath}", "确定"); + return; + } + + try + { + using (ExcelPackage package = new ExcelPackage(new FileInfo(excelPath))) + { + ExcelWorksheet worksheet = package.Workbook.Worksheets[DECORATE_COST_SHEET_NAME]; + if (worksheet == null) + { + EditorUtility.DisplayDialog("错误", $"未找到 Sheet:{DECORATE_COST_SHEET_NAME}", "确定"); + return; + } + + foreach (int rowIndex in dirtyRowIndexes.OrderBy(index => index)) + { + if (!rowIndexMap.TryGetValue(rowIndex, out DecorateCostExcelRow row)) + { + continue; + } + + worksheet.Cells[row.RowIndex, COL_COST_COUNT].Value = row.CostCount; + worksheet.Cells[row.RowIndex, COL_POS].Value = string.IsNullOrEmpty(row.Pos) ? null : row.Pos; + } + + package.Save(); + } + + int savedCount = dirtyRowIndexes.Count; + dirtyRowIndexes.Clear(); + AssetDatabase.Refresh(); + EditorUtility.DisplayDialog("成功", $"已保存 {savedCount} 行修改到 {DECORATE_COST_EXCEL_NAME}。", "确定"); + } + catch (Exception e) + { + EditorUtility.DisplayDialog("错误", $"保存失败:{e.Message}\n{e.StackTrace}", "确定"); + } + } + + private void ShowAreaInputDialog() + { + if (availableAreaIds == null || availableAreaIds.Count == 0) + { + return; + } + + DecorateCostAreaInputWindow.ShowWindow(areaIdInput, TrySelectArea); + } + + private bool TrySelectArea(int areaId) + { + return TrySelectArea(areaId, true); + } + + private bool TrySelectArea(int areaId, bool showDialog) + { + if (areaId == 1) + { + if (showDialog) + { + EditorUtility.DisplayDialog("限制", "AreaId 1 为旧版特殊场景,不能在此工具中编辑。", "确定"); + } + return false; + } + + int expectedStepCount = GetExpectedStepCount(areaId); + if (expectedStepCount <= 0) + { + if (showDialog) + { + EditorUtility.DisplayDialog("错误", "请输入有效的 AreaId。AreaId=2-5 为 20 步,AreaId>=6 为 25 步。", "确定"); + } + return false; + } + + bool hasArea = allRows.Any(row => row.AreaId == areaId); + if (!hasArea) + { + if (showDialog) + { + EditorUtility.DisplayDialog("未找到", $"DecorateCost 中不存在 AreaId={areaId} 的配置。", "确定"); + } + return false; + } + + selectedAreaId = areaId; + areaIdInput = areaId; + currentAreaExpectedStepCount = expectedStepCount; + currentAreaStepRows = allRows + .Where(row => row.AreaId == areaId && row.SortId != 0) + .OrderBy(row => row.SortId) + .ToList(); + + if (showDialog) + { + string message = $"已加载 AreaId={areaId}\n期望步数:{currentAreaExpectedStepCount}\n可编辑步骤:{currentAreaStepRows.Count}"; + List missingSortIds = GetMissingSortIds(); + if (missingSortIds.Count > 0) + { + message += $"\n\n⚠ 缺失步骤:{string.Join(", ", missingSortIds)}"; + } + + EditorUtility.DisplayDialog("完成", message, "确定"); + } + + Repaint(); + return true; + } + + private List GetMissingSortIds() + { + if (currentAreaExpectedStepCount <= 0) + { + return new List(); + } + + HashSet existingIds = new HashSet(currentAreaStepRows.Select(row => row.SortId)); + List missingIds = new List(); + for (int sortId = 1; sortId <= currentAreaExpectedStepCount; sortId++) + { + if (!existingIds.Contains(sortId)) + { + missingIds.Add(sortId); + } + } + + return missingIds; + } + + private int GetDefaultAreaId() + { + return availableAreaIds.FirstOrDefault(); + } + + private int GetExpectedStepCount(int areaId) + { + if (areaId >= 2 && areaId <= 5) + { + return 20; + } + + if (areaId >= 6) + { + return 25; + } + + return 0; + } + + private void MarkRowDirty(DecorateCostExcelRow row) + { + dirtyRowIndexes.Add(row.RowIndex); + } + + private static string GetBatchDisplayName(int batchValue) + { + if (batchValue <= 0) + { + return "空"; + } + + if (batchValue < BATCH_NAMES.Length) + { + return BATCH_NAMES[batchValue]; + } + + return $"第{batchValue}批"; + } + + private static int ParseBatchValue(string value) + { + if (string.IsNullOrWhiteSpace(value)) + { + return 0; + } + + string trimmedValue = value.Trim(); + if (int.TryParse(trimmedValue, out int numericValue)) + { + return Mathf.Max(0, numericValue); + } + + for (int index = 1; index < BATCH_NAMES.Length; index++) + { + if (string.Equals(BATCH_NAMES[index], trimmedValue, StringComparison.OrdinalIgnoreCase)) + { + return index; + } + } + + string normalizedValue = trimmedValue.Replace("-", string.Empty).Replace(" ", string.Empty).ToLowerInvariant(); + for (int index = 1; index < BATCH_NAMES.Length; index++) + { + string normalizedBatchName = BATCH_NAMES[index].Replace("-", string.Empty).Replace(" ", string.Empty).ToLowerInvariant(); + if (normalizedBatchName == normalizedValue) + { + return index; + } + } + + switch (normalizedValue) + { + case "fourth": return 4; + case "fifth": return 5; + case "sixth": return 6; + case "seventh": return 7; + case "eighth": return 8; + case "ninth": return 9; + case "tenth": return 10; + case "eleventh": return 11; + case "twelfth": return 12; + case "thirteenth": return 13; + case "fourteenth": return 14; + case "fifteenth": return 15; + case "sixteenth": return 16; + case "seventeenth": return 17; + case "eighteenth": return 18; + case "nineteenth": return 19; + case "twentieth": return 20; + case "twentyfirst": return 21; + case "twentysecond": return 22; + case "twentythird": return 23; + case "twentyfourth": return 24; + case "twentyfifth": return 25; + case "twentysixth": return 26; + case "twentyseventh": return 27; + case "twentyeighth": return 28; + case "twentyninth": return 29; + case "thirtieth": return 30; + case "thirtyfirst": return 31; + case "thirtysecond": return 32; + case "thirtythird": return 33; + case "thirtyfourth": return 34; + case "thirtyfifth": return 35; + case "thirtysixth": return 36; + case "thirtyseventh": return 37; + case "thirtyeighth": return 38; + case "thirtyninth": return 39; + case "fortieth": return 40; + case "fortyfirst": return 41; + default: return 0; + } + } + + private static string FormatBatchValue(int batchValue) + { + if (batchValue <= 0) + { + return string.Empty; + } + + if (batchValue < BATCH_NAMES.Length) + { + return BATCH_NAMES[batchValue]; + } + + return batchValue.ToString(); + } + + private sealed class DecorateCostExcelRow + { + private readonly string[] fields; + + public DecorateCostExcelRow(int rowIndex, string[] fields) + { + RowIndex = rowIndex; + this.fields = fields ?? new string[TOTAL_COL_COUNT]; + } + + public int RowIndex { get; } + + public int AreaId => ParseInt(fields[COL_AREA_ID - 1]); + + public int SortId => ParseInt(fields[COL_SORT_ID - 1]); + + public string Title => fields[4]; + + public int CostCount + { + get => ParseInt(fields[COL_COST_COUNT - 1]); + set => fields[COL_COST_COUNT - 1] = value.ToString(); + } + + public string Pos + { + get => fields[COL_POS - 1] ?? string.Empty; + set => fields[COL_POS - 1] = value ?? string.Empty; + } + + public int BatchValue + { + get => ParseBatchValue(Pos); + set => Pos = FormatBatchValue(value); + } + + private static int ParseInt(string value) + { + return int.TryParse(value, out int result) ? result : 0; + } + } + } + + /// + /// AreaId 输入窗口 + /// + public class DecorateCostAreaInputWindow : EditorWindow + { + private Func onConfirm; + private string areaIdText = string.Empty; + + public static void ShowWindow(int defaultAreaId, Func confirmCallback) + { + DecorateCostAreaInputWindow window = CreateInstance(); + window.titleContent = new GUIContent("输入 AreaId"); + window.minSize = new Vector2(320, 120); + window.maxSize = new Vector2(320, 120); + window.areaIdText = defaultAreaId > 0 ? defaultAreaId.ToString() : string.Empty; + window.onConfirm = confirmCallback; + window.ShowUtility(); + } + + private void OnGUI() + { + EditorGUILayout.Space(10); + EditorGUILayout.LabelField("请输入要编辑的 AreaId", EditorStyles.boldLabel); + EditorGUILayout.HelpBox("AreaId=1 不允许编辑;AreaId=2-5 为 20 步;AreaId>=6 为 25 步。", MessageType.Info); + + GUI.SetNextControlName("AreaIdField"); + areaIdText = EditorGUILayout.TextField("AreaId", areaIdText); + + EditorGUILayout.Space(10); + EditorGUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + + if (GUILayout.Button("确定", GUILayout.Width(90), GUILayout.Height(24))) + { + Confirm(); + } + + if (GUILayout.Button("取消", GUILayout.Width(90), GUILayout.Height(24))) + { + Close(); + } + + EditorGUILayout.EndHorizontal(); + + if (Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Return) + { + Confirm(); + Event.current.Use(); + } + } + + private void OnFocus() + { + EditorGUI.FocusTextInControl("AreaIdField"); + } + + private void Confirm() + { + if (!int.TryParse(areaIdText, out int areaId)) + { + EditorUtility.DisplayDialog("错误", "请输入有效的整数 AreaId。", "确定"); + return; + } + + if (onConfirm == null || onConfirm.Invoke(areaId)) + { + Close(); + } + } + } + + /// + /// DecorateCost 独立的批量设置资源消耗弹窗。 + /// + public class DecorateCostPlannerBatchCostWindow : EditorWindow + { + private int groupCount = 5; + private int stepCount = 25; + private IntegerField[] costFields = Array.Empty(); + private Action onConfirm; + + public static void ShowWindow(int stepCount, Action confirmCallback) + { + DecorateCostPlannerBatchCostWindow window = CreateInstance(); + window.titleContent = new GUIContent("批量设置资源消耗"); + window.minSize = new Vector2(300, 250); + window.stepCount = Mathf.Max(1, stepCount); + window.groupCount = Mathf.CeilToInt(window.stepCount / 5f); + window.costFields = new IntegerField[window.groupCount]; + window.onConfirm = confirmCallback; + window.ShowUtility(); + } + + private void CreateGUI() + { + VisualElement root = rootVisualElement; + root.Clear(); + root.style.paddingTop = 10; + root.style.paddingBottom = 10; + root.style.paddingLeft = 10; + root.style.paddingRight = 10; + + Label title = new Label($"输入{groupCount}组资源消耗数值\n每5个步骤使用同一数值(当前共{stepCount}步)"); + title.style.fontSize = 14; + title.style.marginBottom = 10; + title.style.unityTextAlign = TextAnchor.MiddleCenter; + root.Add(title); + + for (int i = 0; i < groupCount; i++) + { + int startStep = i * 5 + 1; + int endStep = Mathf.Min((i + 1) * 5, stepCount); + IntegerField field = new IntegerField($"第{startStep}-{endStep}步:"); + field.value = 0; + field.style.marginBottom = 5; + costFields[i] = field; + root.Add(field); + } + + VisualElement buttonRow = new VisualElement(); + buttonRow.style.flexDirection = FlexDirection.Row; + buttonRow.style.marginTop = 15; + + UnityEngine.UIElements.Button confirmBtn = new UnityEngine.UIElements.Button(OnConfirmClicked) { text = "确定" }; + confirmBtn.style.flexGrow = 1; + confirmBtn.style.marginRight = 5; + buttonRow.Add(confirmBtn); + + UnityEngine.UIElements.Button cancelBtn = new UnityEngine.UIElements.Button(Close) { text = "取消" }; + cancelBtn.style.flexGrow = 1; + buttonRow.Add(cancelBtn); + + root.Add(buttonRow); + } + + private void OnConfirmClicked() + { + int[] costs = new int[groupCount]; + for (int i = 0; i < groupCount; i++) + { + costs[i] = costFields[i].value; + } + + onConfirm?.Invoke(costs); + Close(); + } + } + + /// + /// DecorateCost 独立的批量设置步骤批次弹窗。 + /// + public class DecorateCostPlannerBatchSkipWindow : EditorWindow + { + private int stepCount = 25; + private IntegerField[] skipFields = Array.Empty(); + private ScrollView scrollView; + private Action onConfirm; + + public static void ShowWindow(int stepCount, Action confirmCallback) + { + DecorateCostPlannerBatchSkipWindow window = CreateInstance(); + window.titleContent = new GUIContent("批量设置批次"); + window.minSize = new Vector2(350, 500); + window.stepCount = Mathf.Max(1, stepCount); + window.skipFields = new IntegerField[window.stepCount]; + window.onConfirm = confirmCallback; + window.ShowUtility(); + } + + private void CreateGUI() + { + VisualElement root = rootVisualElement; + root.Clear(); + root.style.paddingTop = 10; + root.style.paddingBottom = 10; + root.style.paddingLeft = 10; + root.style.paddingRight = 10; + + Label title = new Label($"输入{stepCount}个数字设置批次\n0=空 1=first 2=second 3=third..."); + title.style.fontSize = 14; + title.style.marginBottom = 10; + title.style.unityTextAlign = TextAnchor.MiddleCenter; + root.Add(title); + + scrollView = new ScrollView(); + scrollView.style.flexGrow = 1; + + for (int i = 0; i < stepCount; i++) + { + IntegerField field = new IntegerField($"步骤{i + 1}:"); + field.value = 0; + field.style.marginBottom = 3; + skipFields[i] = field; + scrollView.Add(field); + } + + root.Add(scrollView); + + VisualElement buttonRow = new VisualElement(); + buttonRow.style.flexDirection = FlexDirection.Row; + buttonRow.style.marginTop = 10; + + UnityEngine.UIElements.Button confirmBtn = new UnityEngine.UIElements.Button(OnConfirmClicked) { text = "确定" }; + confirmBtn.style.flexGrow = 1; + confirmBtn.style.marginRight = 5; + buttonRow.Add(confirmBtn); + + UnityEngine.UIElements.Button cancelBtn = new UnityEngine.UIElements.Button(Close) { text = "取消" }; + cancelBtn.style.flexGrow = 1; + buttonRow.Add(cancelBtn); + + root.Add(buttonRow); + } + + private void OnConfirmClicked() + { + int[] skips = new int[stepCount]; + for (int i = 0; i < stepCount; i++) + { + skips[i] = skipFields[i].value; + } + + onConfirm?.Invoke(skips); + Close(); + } + } +} diff --git a/Scripts/Editor/Design_Tools/Scene/DecorateCostPlannerEditor.cs.meta b/Scripts/Editor/Design_Tools/Scene/DecorateCostPlannerEditor.cs.meta new file mode 100644 index 0000000..ae3430f --- /dev/null +++ b/Scripts/Editor/Design_Tools/Scene/DecorateCostPlannerEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a80667981aa125e489cabc41b4db38c0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 1342bd4a3a5afbdb5f514444d86d866a64ee3a76 Mon Sep 17 00:00:00 2001 From: zhang hongbo Date: Wed, 25 Mar 2026 14:17:28 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E5=AD=90=E6=A8=A1=E5=9D=97=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ConfigData/AllConfigs.bytes | Bin 1770400 -> 1798557 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/ConfigData/AllConfigs.bytes b/ConfigData/AllConfigs.bytes index b66509c12b130b44d825c5b2af8bda3c924ca382..72f65c24293e3734f623e0819925e71b67f2af4d 100644 GIT binary patch delta 21427 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 delta 1836 zcmaKqdq`V%6vw@J+!J#XjW#DnttJ{Pt82vMCcf$(Qh(i6C@6!m2TY|Feq-$_j6pYH zZXLrqH<}{zXw1v5ia5KqdsR9obuac}l+l%S|I9t4g|Xp(lj30K*3rMhC7s?JGmWBSXUq$HK94Y#cjBy*M-s*>ZYe3fjj9uR49u z9FK)sB2jG3pcyy-!xRv-&0US-93tv%9BuHztx4ex~L}0orjXJYdrC;la6zP z8j?^-(@BVpCw_F&b)z(Dl(v$5lPe>d8f|L}={l_?VK)sBJhU_owbY)1I_m4UX!Mj(^QU;hu@qF(XYX6R)cvcX(bq=fd86@X3Yy3h zuxV7E=Gt|m_Fx*~4F5 z8UplO212wJS6ynPDWtdRbT9*z^hE|bXzfXx2Ju!dH^pedDD%oO%5~Z`j70Qks3qQf z=RhX}PS94GrF0hRY3-y%^G0KODAL+`$C(s3Nxx;`9_oA3s!>CZPbMiaNx>}7J(lCS z#Bs$%W89$j9PjvC4oXxA>v~A1{s3>9si?%m~cTRu1l)IKvOQe}+dkjgiJ# z@LD0bz7xJX1IQ87SK@`j>Pp4H+#m^GU|Rq)#&M2Zhpvy&-3h|!_OR!M|+PQ z8R$LQe=O>Egd=UVv8+^3U!Bbb&CRVLJ*t!Q3~zUM0o=4_3Y=;<9u4U+dKoNb^wKKt z|MfX2vds&er(xrq3T-Y*L~KACFWPK$;H=^dEDB^K+VV~h&>C8+DRsc^rf+xii>_?3y6K4v zikt3URZD53OHnEKmh%5%?+9chs(BYXNS&u(Cw1Jbmeb-2A5{m~U9|UAi}UtYs?G~! zBs%ge67Uh)-sPn9{Bd{cpk?1j#E(v5LmYPY+0vU;3GigO2BhhCjT^7hl^qWba z3S=Z!m`R@tWF+o1lfD$lNUS!Kz7oht44O&b2xKJInn~XYWF*#^N#6@(B-WcrR|GN= z?=q8q5XeYuFq5tdWF+n}ldcJ5BsQ8!KM7 Date: Wed, 25 Mar 2026 14:55:27 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E6=B5=8B=E8=AF=95=E5=AD=90=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=E6=8F=90=E4=BA=A4=E3=80=90=E7=9C=8B=E5=88=B0=E8=BF=99?= =?UTF-8?q?=E6=9D=A1=E8=AF=B4=E6=98=8E=E6=88=90=E5=8A=9F=E4=BA=86=E3=80=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ConfigData/AllConfigs.bytes | Bin 1798557 -> 1798557 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/ConfigData/AllConfigs.bytes b/ConfigData/AllConfigs.bytes index 72f65c24293e3734f623e0819925e71b67f2af4d..cc3405de6eea241478fc7858e793c7675669b551 100644 GIT binary patch delta 95 zcmWN}$q|A;006;4#DhaX-9a=9^Ws4WJf`@Xz=lCYn}~D(9n%!k^b6T{K{7c=E=MWk iBxkwERZ6L(mPT&UN+-SC Date: Wed, 25 Mar 2026 15:09:02 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E5=AD=90=E6=A8=A1=E5=9D=97=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ConfigData/AllConfigs.bytes | Bin 1798557 -> 1798557 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/ConfigData/AllConfigs.bytes b/ConfigData/AllConfigs.bytes index cc3405de6eea241478fc7858e793c7675669b551..34a9cbca9c6934e5de98e12eba1da0c424c8373b 100644 GIT binary patch delta 95 zcmWN}$q|A;006;4#DhaX-9a=A Date: Wed, 25 Mar 2026 15:21:28 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E6=B5=8B=E8=AF=95=E5=AD=90=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=E6=B6=88=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ConfigData/AllConfigs.bytes | Bin 1798557 -> 1798557 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/ConfigData/AllConfigs.bytes b/ConfigData/AllConfigs.bytes index 34a9cbca9c6934e5de98e12eba1da0c424c8373b..bf02aa2d0343f88d211d48d2bd05d4a6f0773942 100644 GIT binary patch delta 95 zcmWN}$q|A;006;4#DhaX-9a=B)8au0Jf`@Xz=lCYn}~D(9n%!k^b6T{K{7c=E=MWk iBxkwERZ6L(mPT&UN+-SC