723 lines
26 KiB
C#
723 lines
26 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using System.Text.RegularExpressions;
|
||
using ArtResource;
|
||
using DesignTools.Common;
|
||
using OfficeOpenXml;
|
||
using UnityEditor;
|
||
using UnityEngine;
|
||
using Debug = UnityEngine.Debug;
|
||
|
||
namespace DesignTools.Friends
|
||
{
|
||
/// <summary>
|
||
/// 好友馈赠宝箱奖励配置工具
|
||
/// 读取 Docs/config/FriendTreasure.xlsx 的 Chest Sheet
|
||
/// Items 的道具从 Item.xlsx 获取,支持查看图片、编辑数量与概率、增删行
|
||
/// </summary>
|
||
public class FriendTreasureChestEditor : BaseDesignToolEditor
|
||
{
|
||
private const string FRIEND_TREASURE_EXCEL_NAME = "FriendTreasure.xlsx";
|
||
private const string FRIEND_TREASURE_SHEET_NAME = "Chest";
|
||
private const string ITEM_EXCEL_NAME = "Item.xlsx";
|
||
private const string ITEM_SHEET_NAME = "Item";
|
||
private const string ART_SO_PATH = "Assets/Art_SubModule/Art_SO";
|
||
|
||
private const int COL_ID = 1;
|
||
private const int COL_ITEMS = 2;
|
||
private const int COL_PROB = 3;
|
||
private const int DATA_START_ROW = 3;
|
||
private const int PROB_TOTAL = 1000;
|
||
|
||
private readonly List<FriendTreasureChestRowData> chestRewardList = new List<FriendTreasureChestRowData>();
|
||
private readonly Dictionary<int, FriendTreasureItemData> itemDict = new Dictionary<int, FriendTreasureItemData>();
|
||
private readonly List<ArtTableSO> allArtTables = new List<ArtTableSO>();
|
||
private readonly List<int> allItemTypes = new List<int>();
|
||
|
||
[MenuItem("策划工具/好友/好友馈赠/宝箱奖励及概率")]
|
||
public static void ShowWindow()
|
||
{
|
||
var window = GetWindow<FriendTreasureChestEditor>("宝箱奖励及概率");
|
||
window.minSize = window.GetMinWindowSize();
|
||
window.Show();
|
||
}
|
||
|
||
protected override string GetDocsPathPrefKey()
|
||
{
|
||
return "FriendTreasureChestEditor_DocsPath";
|
||
}
|
||
|
||
protected override string GetWindowTitle()
|
||
{
|
||
return "好友馈赠宝箱奖励及概率";
|
||
}
|
||
|
||
protected override Vector2 GetMinWindowSize()
|
||
{
|
||
return new Vector2(1200, 680);
|
||
}
|
||
|
||
protected override void LoadConfigData()
|
||
{
|
||
LoadAllArtTableSO();
|
||
LoadItemData();
|
||
LoadChestData();
|
||
}
|
||
|
||
protected override void DrawDataEditor()
|
||
{
|
||
DrawTipsAndToolbar();
|
||
EditorGUILayout.Space(6);
|
||
DrawChestRewardTable();
|
||
}
|
||
|
||
protected override void SaveDataToExcel()
|
||
{
|
||
SaveToExcel();
|
||
}
|
||
|
||
private void DrawTipsAndToolbar()
|
||
{
|
||
EditorGUILayout.BeginVertical("box");
|
||
// EditorGUILayout.HelpBox("保存时只会写回 FriendTreasure.xlsx 的 Chest Sheet,不会改动其它 Sheet。", MessageType.Info);
|
||
// EditorGUILayout.HelpBox("新增只能追加到最后;删除任意一行后,后续 Id 会自动前移并从 1 开始重新编号。", MessageType.Info);
|
||
|
||
int totalProb = chestRewardList.Sum(x => x.Prob);
|
||
float totalPercent = totalProb / 10f;
|
||
MessageType messageType = totalProb == PROB_TOTAL ? MessageType.Info : MessageType.Error;
|
||
EditorGUILayout.HelpBox($"当前总概率:{totalProb}/{PROB_TOTAL}({totalPercent:F1}%)", messageType);
|
||
|
||
EditorGUILayout.BeginHorizontal();
|
||
GUI.backgroundColor = Color.green;
|
||
if (GUILayout.Button("+ 新增一行", GUILayout.Width(120), GUILayout.Height(28)))
|
||
{
|
||
AddNewRow();
|
||
}
|
||
GUI.backgroundColor = Color.white;
|
||
|
||
GUILayout.FlexibleSpace();
|
||
EditorGUILayout.EndHorizontal();
|
||
EditorGUILayout.EndVertical();
|
||
}
|
||
|
||
private void DrawChestRewardTable()
|
||
{
|
||
EditorGUILayout.BeginVertical("box");
|
||
|
||
EditorGUILayout.BeginHorizontal();
|
||
EditorGUILayout.LabelField("Id", EditorStyles.boldLabel, GUILayout.Width(50));
|
||
EditorGUILayout.LabelField("道具类型", EditorStyles.boldLabel, GUILayout.Width(130));
|
||
EditorGUILayout.LabelField("奖励道具(可输ID / 搜索)", EditorStyles.boldLabel, GUILayout.Width(470));
|
||
EditorGUILayout.LabelField("数量", EditorStyles.boldLabel, GUILayout.Width(80));
|
||
EditorGUILayout.LabelField("概率", EditorStyles.boldLabel, GUILayout.Width(80));
|
||
EditorGUILayout.LabelField("百分比", EditorStyles.boldLabel, GUILayout.Width(90));
|
||
EditorGUILayout.LabelField("预览", EditorStyles.boldLabel, GUILayout.Width(70));
|
||
EditorGUILayout.LabelField("操作", EditorStyles.boldLabel, GUILayout.Width(70));
|
||
EditorGUILayout.EndHorizontal();
|
||
|
||
EditorGUILayout.Space(4);
|
||
|
||
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
|
||
|
||
for (int i = 0; i < chestRewardList.Count; i++)
|
||
{
|
||
FriendTreasureChestRowData rowData = chestRewardList[i];
|
||
DrawSingleRow(i, rowData);
|
||
EditorGUILayout.Space(4);
|
||
}
|
||
|
||
EditorGUILayout.EndScrollView();
|
||
EditorGUILayout.EndVertical();
|
||
}
|
||
|
||
private void DrawSingleRow(int index, FriendTreasureChestRowData rowData)
|
||
{
|
||
EditorGUILayout.BeginVertical("box");
|
||
EditorGUILayout.BeginHorizontal();
|
||
|
||
EditorGUILayout.LabelField(rowData.Id.ToString(), GUILayout.Width(50));
|
||
|
||
DrawItemSelector(rowData);
|
||
|
||
rowData.Num = EditorGUILayout.IntField(rowData.Num, GUILayout.Width(80));
|
||
rowData.Prob = EditorGUILayout.IntField(rowData.Prob, GUILayout.Width(80));
|
||
EditorGUILayout.LabelField(GetPercentText(rowData.Prob), GUILayout.Width(90));
|
||
|
||
DrawItemPreview(rowData.RewardItemId);
|
||
|
||
GUI.backgroundColor = new Color(1f, 0.55f, 0.55f);
|
||
if (GUILayout.Button("删除", GUILayout.Width(60), GUILayout.Height(22)))
|
||
{
|
||
RemoveRow(index);
|
||
GUI.backgroundColor = Color.white;
|
||
GUIUtility.ExitGUI();
|
||
}
|
||
GUI.backgroundColor = Color.white;
|
||
|
||
EditorGUILayout.EndHorizontal();
|
||
|
||
if (itemDict.TryGetValue(rowData.RewardItemId, out FriendTreasureItemData itemData))
|
||
{
|
||
EditorGUILayout.BeginHorizontal();
|
||
GUILayout.Space(54);
|
||
EditorGUILayout.LabelField($"当前道具:{itemData.Name} ({itemData.Id})", EditorStyles.miniLabel);
|
||
EditorGUILayout.EndHorizontal();
|
||
}
|
||
|
||
EditorGUILayout.EndVertical();
|
||
}
|
||
|
||
private void DrawItemSelector(FriendTreasureChestRowData rowData)
|
||
{
|
||
EnsureInputItemId(rowData);
|
||
|
||
int currentType = GetCurrentItemType(rowData.RewardItemId);
|
||
if (currentType < 0 && allItemTypes.Count > 0)
|
||
{
|
||
currentType = allItemTypes[0];
|
||
}
|
||
|
||
int currentTypeIndex = Mathf.Max(0, allItemTypes.IndexOf(currentType));
|
||
string[] typeOptions = allItemTypes.Select(GetItemTypeDisplayName).ToArray();
|
||
|
||
if (typeOptions.Length == 0)
|
||
{
|
||
EditorGUILayout.LabelField("无可用类型", GUILayout.Width(130));
|
||
EditorGUILayout.LabelField("无可用道具", GUILayout.Width(470));
|
||
return;
|
||
}
|
||
|
||
int newTypeIndex = EditorGUILayout.Popup(currentTypeIndex, typeOptions, GUILayout.Width(130));
|
||
int selectedType = allItemTypes[newTypeIndex];
|
||
|
||
List<FriendTreasureItemData> itemsOfType = itemDict.Values
|
||
.Where(x => x.IType == selectedType)
|
||
.OrderBy(x => x.Id)
|
||
.ToList();
|
||
|
||
if (itemsOfType.Count == 0)
|
||
{
|
||
EditorGUILayout.LabelField("该类型无道具", GUILayout.Width(470));
|
||
return;
|
||
}
|
||
|
||
EditorGUILayout.BeginVertical(GUILayout.Width(470));
|
||
|
||
EditorGUILayout.BeginHorizontal();
|
||
int newInputItemId = EditorGUILayout.IntField(rowData.InputItemId, GUILayout.Width(90));
|
||
if (newInputItemId != rowData.InputItemId)
|
||
{
|
||
rowData.InputItemId = newInputItemId;
|
||
if (itemDict.ContainsKey(newInputItemId))
|
||
{
|
||
SetRowItem(rowData, newInputItemId);
|
||
currentType = GetCurrentItemType(rowData.RewardItemId);
|
||
selectedType = currentType;
|
||
itemsOfType = itemDict.Values
|
||
.Where(x => x.IType == selectedType)
|
||
.OrderBy(x => x.Id)
|
||
.ToList();
|
||
}
|
||
}
|
||
|
||
GUI.backgroundColor = new Color(0.75f, 0.9f, 1f);
|
||
if (GUILayout.Button("查找", GUILayout.Width(55), GUILayout.Height(20)))
|
||
{
|
||
EditorApplication.delayCall += () => OpenItemPickerWindow(rowData);
|
||
GUI.backgroundColor = Color.white;
|
||
GUIUtility.ExitGUI();
|
||
}
|
||
GUI.backgroundColor = Color.white;
|
||
|
||
if (itemDict.TryGetValue(rowData.InputItemId, out FriendTreasureItemData inputItemData))
|
||
{
|
||
EditorGUILayout.LabelField($"{inputItemData.Name} ({inputItemData.Id})", EditorStyles.miniLabel, GUILayout.Width(300));
|
||
}
|
||
else
|
||
{
|
||
Color oldColor = GUI.color;
|
||
GUI.color = new Color(1f, 0.35f, 0.35f);
|
||
EditorGUILayout.LabelField("未找到该 ItemId", EditorStyles.miniLabel, GUILayout.Width(300));
|
||
GUI.color = oldColor;
|
||
}
|
||
EditorGUILayout.EndHorizontal();
|
||
|
||
int currentItemIndex = itemsOfType.FindIndex(x => x.Id == rowData.RewardItemId);
|
||
if (currentItemIndex < 0)
|
||
{
|
||
currentItemIndex = 0;
|
||
SetRowItem(rowData, itemsOfType[0].Id);
|
||
}
|
||
|
||
string[] itemOptions = itemsOfType
|
||
.Select(x => $"{x.Name} ({x.Id})")
|
||
.ToArray();
|
||
|
||
int newItemIndex = EditorGUILayout.Popup(currentItemIndex, itemOptions, GUILayout.Width(460));
|
||
SetRowItem(rowData, itemsOfType[newItemIndex].Id);
|
||
|
||
EditorGUILayout.EndVertical();
|
||
}
|
||
|
||
private void EnsureInputItemId(FriendTreasureChestRowData rowData)
|
||
{
|
||
if (rowData.InputItemId <= 0)
|
||
{
|
||
rowData.InputItemId = rowData.RewardItemId;
|
||
}
|
||
}
|
||
|
||
private void SetRowItem(FriendTreasureChestRowData rowData, int itemId)
|
||
{
|
||
rowData.RewardItemId = itemId;
|
||
rowData.InputItemId = itemId;
|
||
}
|
||
|
||
private void OpenItemPickerWindow(FriendTreasureChestRowData rowData)
|
||
{
|
||
int currentType = GetCurrentItemType(rowData.RewardItemId);
|
||
DesignToolItemPickerWindow.ShowWindow(
|
||
itemDict.Values
|
||
.Select(x => new DesignToolItemPickerItem
|
||
{
|
||
Id = x.Id,
|
||
Name = x.Name,
|
||
IType = x.IType
|
||
})
|
||
.ToList(),
|
||
allItemTypes,
|
||
ITEM_TYPE_NAMES,
|
||
currentType,
|
||
rowData.RewardItemId,
|
||
position,
|
||
selectedItemId =>
|
||
{
|
||
SetRowItem(rowData, selectedItemId);
|
||
Repaint();
|
||
});
|
||
}
|
||
|
||
private void AddNewRow()
|
||
{
|
||
int defaultItemId = itemDict.Count > 0 ? itemDict.Values.OrderBy(x => x.Id).First().Id : 0;
|
||
|
||
chestRewardList.Add(new FriendTreasureChestRowData
|
||
{
|
||
Id = chestRewardList.Count + 1,
|
||
RewardItemId = defaultItemId,
|
||
InputItemId = defaultItemId,
|
||
Num = 1,
|
||
Prob = 0
|
||
});
|
||
}
|
||
|
||
private void RemoveRow(int index)
|
||
{
|
||
if (index < 0 || index >= chestRewardList.Count)
|
||
{
|
||
return;
|
||
}
|
||
|
||
chestRewardList.RemoveAt(index);
|
||
ReassignIds();
|
||
}
|
||
|
||
private void ReassignIds()
|
||
{
|
||
for (int i = 0; i < chestRewardList.Count; i++)
|
||
{
|
||
chestRewardList[i].Id = i + 1;
|
||
}
|
||
}
|
||
|
||
private void LoadAllArtTableSO()
|
||
{
|
||
allArtTables.Clear();
|
||
|
||
string[] guids = AssetDatabase.FindAssets("t:ArtTableSO", new[] { ART_SO_PATH });
|
||
foreach (string guid in guids)
|
||
{
|
||
string path = AssetDatabase.GUIDToAssetPath(guid);
|
||
ArtTableSO artTable = AssetDatabase.LoadAssetAtPath<ArtTableSO>(path);
|
||
if (artTable != null)
|
||
{
|
||
allArtTables.Add(artTable);
|
||
}
|
||
}
|
||
|
||
Debug.Log($"加载了 {allArtTables.Count} 个 ArtTableSO 资源");
|
||
}
|
||
|
||
private void LoadItemData()
|
||
{
|
||
itemDict.Clear();
|
||
allItemTypes.Clear();
|
||
|
||
string itemExcelPath = GetDocsConfigFilePath(ITEM_EXCEL_NAME);
|
||
if (!File.Exists(itemExcelPath))
|
||
{
|
||
throw new FileNotFoundException($"未找到 {ITEM_EXCEL_NAME}", itemExcelPath);
|
||
}
|
||
|
||
using (var package = new ExcelPackage(new FileInfo(itemExcelPath)))
|
||
{
|
||
var worksheet = package.Workbook.Worksheets[ITEM_SHEET_NAME];
|
||
if (worksheet == null)
|
||
{
|
||
throw new Exception($"{ITEM_EXCEL_NAME} 中未找到 Sheet: {ITEM_SHEET_NAME}");
|
||
}
|
||
|
||
int idCol = -1;
|
||
int nameCol = -1;
|
||
int iTypeCol = -1;
|
||
int resCol = -1;
|
||
int columnCount = worksheet.Dimension?.Columns ?? 0;
|
||
|
||
for (int col = 1; col <= columnCount; col++)
|
||
{
|
||
string header = worksheet.Cells[1, col].Text;
|
||
if (header == "Id") idCol = col;
|
||
else if (header == "Name") nameCol = col;
|
||
else if (header == "IType") iTypeCol = col;
|
||
else if (header == "Res") resCol = col;
|
||
}
|
||
|
||
if (idCol < 0 || nameCol < 0 || iTypeCol < 0)
|
||
{
|
||
throw new Exception("Item.xlsx 表结构不正确,缺少 Id / Name / IType 列");
|
||
}
|
||
|
||
int rowCount = worksheet.Dimension?.Rows ?? 0;
|
||
for (int row = DATA_START_ROW; row <= rowCount; row++)
|
||
{
|
||
string idText = worksheet.Cells[row, idCol].Text.Trim();
|
||
if (string.IsNullOrEmpty(idText))
|
||
{
|
||
continue;
|
||
}
|
||
|
||
if (!int.TryParse(idText, out int id))
|
||
{
|
||
continue;
|
||
}
|
||
|
||
string name = worksheet.Cells[row, nameCol].Text.Trim();
|
||
string iTypeText = worksheet.Cells[row, iTypeCol].Text.Trim();
|
||
string res = resCol > 0 ? worksheet.Cells[row, resCol].Text.Trim() : string.Empty;
|
||
|
||
if (!int.TryParse(iTypeText, out int iType))
|
||
{
|
||
continue;
|
||
}
|
||
|
||
itemDict[id] = new FriendTreasureItemData
|
||
{
|
||
Id = id,
|
||
Name = name,
|
||
IType = iType,
|
||
Res = res
|
||
};
|
||
}
|
||
}
|
||
|
||
foreach (int itemType in itemDict.Values.Select(x => x.IType).Distinct().OrderBy(x => x))
|
||
{
|
||
allItemTypes.Add(itemType);
|
||
}
|
||
|
||
Debug.Log($"加载了 {itemDict.Count} 个 Item 数据");
|
||
}
|
||
|
||
private void LoadChestData()
|
||
{
|
||
chestRewardList.Clear();
|
||
|
||
string excelPath = GetDocsConfigFilePath(FRIEND_TREASURE_EXCEL_NAME);
|
||
if (!File.Exists(excelPath))
|
||
{
|
||
throw new FileNotFoundException($"未找到 {FRIEND_TREASURE_EXCEL_NAME}", excelPath);
|
||
}
|
||
|
||
using (var package = new ExcelPackage(new FileInfo(excelPath)))
|
||
{
|
||
var worksheet = package.Workbook.Worksheets[FRIEND_TREASURE_SHEET_NAME];
|
||
if (worksheet == null)
|
||
{
|
||
throw new Exception($"未找到 Sheet: {FRIEND_TREASURE_SHEET_NAME}");
|
||
}
|
||
|
||
int rowCount = worksheet.Dimension?.Rows ?? 0;
|
||
for (int row = DATA_START_ROW; row <= rowCount; row++)
|
||
{
|
||
string idText = worksheet.Cells[row, COL_ID].Text.Trim();
|
||
if (string.IsNullOrEmpty(idText))
|
||
{
|
||
continue;
|
||
}
|
||
|
||
if (!int.TryParse(idText, out int id))
|
||
{
|
||
continue;
|
||
}
|
||
|
||
string itemsText = worksheet.Cells[row, COL_ITEMS].Text.Trim();
|
||
int prob = ParseInt(worksheet.Cells[row, COL_PROB].Text.Trim());
|
||
|
||
if (!TryParseItems(itemsText, out int itemId, out int num))
|
||
{
|
||
Debug.LogWarning($"{FRIEND_TREASURE_EXCEL_NAME}/{FRIEND_TREASURE_SHEET_NAME} 第 {row} 行 Items 格式异常,已使用默认值");
|
||
itemId = itemDict.Count > 0 ? itemDict.Keys.Min() : 0;
|
||
num = 1;
|
||
}
|
||
|
||
chestRewardList.Add(new FriendTreasureChestRowData
|
||
{
|
||
Id = id,
|
||
RewardItemId = itemId,
|
||
InputItemId = itemId,
|
||
Num = num,
|
||
Prob = prob,
|
||
RowIndex = row
|
||
});
|
||
}
|
||
}
|
||
|
||
ReassignIds();
|
||
}
|
||
|
||
private void SaveToExcel()
|
||
{
|
||
ReassignIds();
|
||
|
||
if (!ValidateBeforeSave(out string errorMessage))
|
||
{
|
||
EditorUtility.DisplayDialog("校验失败", errorMessage, "确定");
|
||
return;
|
||
}
|
||
|
||
try
|
||
{
|
||
string excelPath = GetDocsConfigFilePath(FRIEND_TREASURE_EXCEL_NAME);
|
||
using (var package = new ExcelPackage(new FileInfo(excelPath)))
|
||
{
|
||
var worksheet = package.Workbook.Worksheets[FRIEND_TREASURE_SHEET_NAME];
|
||
if (worksheet == null)
|
||
{
|
||
EditorUtility.DisplayDialog("错误", $"未找到 Sheet: {FRIEND_TREASURE_SHEET_NAME}", "确定");
|
||
return;
|
||
}
|
||
|
||
int rowCount = worksheet.Dimension?.Rows ?? 0;
|
||
|
||
for (int i = 0; i < chestRewardList.Count; i++)
|
||
{
|
||
FriendTreasureChestRowData rowData = chestRewardList[i];
|
||
int row = DATA_START_ROW + i;
|
||
|
||
worksheet.Cells[row, COL_ID].Value = rowData.Id;
|
||
worksheet.Cells[row, COL_ITEMS].Value = BuildItemsJson(rowData.RewardItemId, rowData.Num);
|
||
worksheet.Cells[row, COL_PROB].Value = rowData.Prob;
|
||
}
|
||
|
||
for (int row = DATA_START_ROW + chestRewardList.Count; row <= rowCount; row++)
|
||
{
|
||
worksheet.Cells[row, COL_ID].Value = null;
|
||
worksheet.Cells[row, COL_ITEMS].Value = null;
|
||
worksheet.Cells[row, COL_PROB].Value = null;
|
||
}
|
||
|
||
package.Save();
|
||
}
|
||
|
||
EditorUtility.DisplayDialog("成功", "宝箱奖励及概率已保存到 Chest Sheet!", "确定");
|
||
Debug.Log("宝箱奖励及概率已保存");
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
EditorUtility.DisplayDialog("错误", $"保存失败: {e.Message}", "确定");
|
||
Debug.LogError($"保存宝箱奖励及概率失败: {e}");
|
||
}
|
||
}
|
||
|
||
private bool ValidateBeforeSave(out string errorMessage)
|
||
{
|
||
if (chestRewardList.Count == 0)
|
||
{
|
||
errorMessage = "至少需要保留一条宝箱奖励数据。";
|
||
return false;
|
||
}
|
||
|
||
for (int i = 0; i < chestRewardList.Count; i++)
|
||
{
|
||
FriendTreasureChestRowData rowData = chestRewardList[i];
|
||
if (!itemDict.ContainsKey(rowData.RewardItemId))
|
||
{
|
||
errorMessage = $"第 {i + 1} 行选择的 ItemId 不存在于 Item.xlsx 中。";
|
||
return false;
|
||
}
|
||
|
||
if (rowData.Num < 1)
|
||
{
|
||
errorMessage = $"第 {i + 1} 行的数量必须大于等于 1。";
|
||
return false;
|
||
}
|
||
|
||
if (rowData.Prob < 0)
|
||
{
|
||
errorMessage = $"第 {i + 1} 行的概率不能小于 0。";
|
||
return false;
|
||
}
|
||
}
|
||
|
||
int totalProb = chestRewardList.Sum(x => x.Prob);
|
||
if (totalProb != PROB_TOTAL)
|
||
{
|
||
errorMessage = $"所有概率之和必须等于 {PROB_TOTAL},当前为 {totalProb}。";
|
||
return false;
|
||
}
|
||
|
||
errorMessage = string.Empty;
|
||
return true;
|
||
}
|
||
|
||
private bool TryParseItems(string itemsText, out int itemId, out int num)
|
||
{
|
||
itemId = 0;
|
||
num = 0;
|
||
|
||
if (string.IsNullOrWhiteSpace(itemsText))
|
||
{
|
||
return false;
|
||
}
|
||
|
||
Match idMatch = Regex.Match(itemsText, @"""Id""\s*:\s*(\d+)");
|
||
Match numMatch = Regex.Match(itemsText, @"""Num""\s*:\s*(-?\d+)");
|
||
if (!idMatch.Success || !numMatch.Success)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
return int.TryParse(idMatch.Groups[1].Value, out itemId) &&
|
||
int.TryParse(numMatch.Groups[1].Value, out num);
|
||
}
|
||
|
||
private string BuildItemsJson(int itemId, int num)
|
||
{
|
||
return $"[{{\"Id\":{itemId},\"Num\":{num}}}]";
|
||
}
|
||
|
||
private int ParseInt(string text)
|
||
{
|
||
return int.TryParse(text, out int value) ? value : 0;
|
||
}
|
||
|
||
private string GetPercentText(int prob)
|
||
{
|
||
return $"{prob / 10f:F1}%";
|
||
}
|
||
|
||
private int GetCurrentItemType(int itemId)
|
||
{
|
||
return itemDict.TryGetValue(itemId, out FriendTreasureItemData itemData) ? itemData.IType : -1;
|
||
}
|
||
|
||
private string GetItemTypeDisplayName(int iType)
|
||
{
|
||
return ITEM_TYPE_NAMES.TryGetValue(iType, out string typeName)
|
||
? $"{typeName} ({iType})"
|
||
: $"类型 {iType}";
|
||
}
|
||
|
||
private void DrawItemPreview(int itemId)
|
||
{
|
||
if (!itemDict.TryGetValue(itemId, out FriendTreasureItemData itemData) || string.IsNullOrEmpty(itemData.Res))
|
||
{
|
||
EditorGUILayout.LabelField("无图", GUILayout.Width(70));
|
||
return;
|
||
}
|
||
|
||
string[] parts = itemData.Res.Split(',');
|
||
if (parts.Length != 2)
|
||
{
|
||
EditorGUILayout.LabelField("无图", GUILayout.Width(70));
|
||
return;
|
||
}
|
||
|
||
string tableName = parts[0];
|
||
string artItemName = parts[1];
|
||
|
||
if (string.IsNullOrEmpty(tableName) || string.IsNullOrEmpty(artItemName))
|
||
{
|
||
EditorGUILayout.LabelField("无图", GUILayout.Width(70));
|
||
return;
|
||
}
|
||
|
||
ArtTableSO artTable = allArtTables.FirstOrDefault(x => x.TableName == tableName);
|
||
if (artTable == null)
|
||
{
|
||
EditorGUILayout.LabelField("无图", GUILayout.Width(70));
|
||
return;
|
||
}
|
||
|
||
var artItem = artTable.Items.FirstOrDefault(x => x.Name == artItemName);
|
||
if (artItem == null || artItem.Sprite == null)
|
||
{
|
||
EditorGUILayout.LabelField("无图", GUILayout.Width(70));
|
||
return;
|
||
}
|
||
|
||
Rect rect = GUILayoutUtility.GetRect(50, 50, GUILayout.Width(50), GUILayout.Height(50));
|
||
GUI.DrawTexture(rect, artItem.Sprite.texture, ScaleMode.ScaleToFit);
|
||
}
|
||
|
||
private static readonly Dictionary<int, string> ITEM_TYPE_NAMES = new Dictionary<int, string>
|
||
{
|
||
{ 1, "能量" },
|
||
{ 2, "星星" },
|
||
{ 3, "钻石" },
|
||
{ 97, "Playroom宠物道具" },
|
||
{ 98, "卡牌" },
|
||
{ 99, "背包道具" },
|
||
{ 100, "棋子" },
|
||
{ 101, "卡包" },
|
||
{ 102, "限时事件" },
|
||
{ 103, "小猪存钱罐" },
|
||
{ 104, "万能卡" },
|
||
{ 105, "头像框" },
|
||
{ 106, "活动代币" },
|
||
{ 107, "竞赛游戏代币" },
|
||
{ 108, "Pet Playroom拜访道具" },
|
||
{ 109, "表情" },
|
||
{ 110, "头像" },
|
||
{ 111, "Playroom装饰" },
|
||
{ 112, "Playroom服装" },
|
||
{ 113, "Playroom装饰套装" },
|
||
{ 114, "Playroom服装套装" },
|
||
{ 115, "Playroom道具宝箱" },
|
||
{ 116, "活动通行证代币道具" }
|
||
};
|
||
}
|
||
|
||
[Serializable]
|
||
public class FriendTreasureChestRowData
|
||
{
|
||
public int Id;
|
||
public int RewardItemId;
|
||
public int InputItemId;
|
||
public int Num;
|
||
public int Prob;
|
||
public int RowIndex;
|
||
}
|
||
|
||
[Serializable]
|
||
public class FriendTreasureItemData
|
||
{
|
||
public int Id;
|
||
public string Name;
|
||
public int IType;
|
||
public string Res;
|
||
}
|
||
}
|