场景步骤宠物币消耗和步骤批次
This commit is contained in:
parent
8f1f51c506
commit
e8067c676d
949
Scripts/Editor/Design_Tools/Scene/DecorateCostPlannerEditor.cs
Normal file
949
Scripts/Editor/Design_Tools/Scene/DecorateCostPlannerEditor.cs
Normal file
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// 装饰场景消耗/批次配置工具
|
||||
/// 读取 Docs/config/DecorateCost.xlsx 的 DecorateCost Sheet,供策划编辑每步消耗与批次。
|
||||
/// </summary>
|
||||
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<DecorateCostExcelRow> allRows = new List<DecorateCostExcelRow>();
|
||||
private readonly Dictionary<int, DecorateCostExcelRow> rowIndexMap = new Dictionary<int, DecorateCostExcelRow>();
|
||||
private readonly HashSet<int> dirtyRowIndexes = new HashSet<int>();
|
||||
private List<int> availableAreaIds = new List<int>();
|
||||
private List<DecorateCostExcelRow> currentAreaStepRows = new List<DecorateCostExcelRow>();
|
||||
|
||||
private int selectedAreaId = -1;
|
||||
private int areaIdInput = 2;
|
||||
private int currentAreaExpectedStepCount;
|
||||
|
||||
[MenuItem("策划工具/场景/装饰场景消耗与批次")]
|
||||
public static void ShowWindow()
|
||||
{
|
||||
var window = GetWindow<DecorateCostPlannerEditor>("装饰场景消耗与批次");
|
||||
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<int>();
|
||||
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<int> 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<int> missingSortIds = new List<int>();
|
||||
|
||||
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<int> missingSortIds = new List<int>();
|
||||
|
||||
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<int> 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<int> missingSortIds = GetMissingSortIds();
|
||||
if (missingSortIds.Count > 0)
|
||||
{
|
||||
message += $"\n\n⚠ 缺失步骤:{string.Join(", ", missingSortIds)}";
|
||||
}
|
||||
|
||||
EditorUtility.DisplayDialog("完成", message, "确定");
|
||||
}
|
||||
|
||||
Repaint();
|
||||
return true;
|
||||
}
|
||||
|
||||
private List<int> GetMissingSortIds()
|
||||
{
|
||||
if (currentAreaExpectedStepCount <= 0)
|
||||
{
|
||||
return new List<int>();
|
||||
}
|
||||
|
||||
HashSet<int> existingIds = new HashSet<int>(currentAreaStepRows.Select(row => row.SortId));
|
||||
List<int> missingIds = new List<int>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// AreaId 输入窗口
|
||||
/// </summary>
|
||||
public class DecorateCostAreaInputWindow : EditorWindow
|
||||
{
|
||||
private Func<int, bool> onConfirm;
|
||||
private string areaIdText = string.Empty;
|
||||
|
||||
public static void ShowWindow(int defaultAreaId, Func<int, bool> confirmCallback)
|
||||
{
|
||||
DecorateCostAreaInputWindow window = CreateInstance<DecorateCostAreaInputWindow>();
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DecorateCost 独立的批量设置资源消耗弹窗。
|
||||
/// </summary>
|
||||
public class DecorateCostPlannerBatchCostWindow : EditorWindow
|
||||
{
|
||||
private int groupCount = 5;
|
||||
private int stepCount = 25;
|
||||
private IntegerField[] costFields = Array.Empty<IntegerField>();
|
||||
private Action<int[]> onConfirm;
|
||||
|
||||
public static void ShowWindow(int stepCount, Action<int[]> confirmCallback)
|
||||
{
|
||||
DecorateCostPlannerBatchCostWindow window = CreateInstance<DecorateCostPlannerBatchCostWindow>();
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DecorateCost 独立的批量设置步骤批次弹窗。
|
||||
/// </summary>
|
||||
public class DecorateCostPlannerBatchSkipWindow : EditorWindow
|
||||
{
|
||||
private int stepCount = 25;
|
||||
private IntegerField[] skipFields = Array.Empty<IntegerField>();
|
||||
private ScrollView scrollView;
|
||||
private Action<int[]> onConfirm;
|
||||
|
||||
public static void ShowWindow(int stepCount, Action<int[]> confirmCallback)
|
||||
{
|
||||
DecorateCostPlannerBatchSkipWindow window = CreateInstance<DecorateCostPlannerBatchSkipWindow>();
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a80667981aa125e489cabc41b4db38c0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Loading…
Reference in New Issue
Block a user