Design_SubModule/Scripts/Editor/Design_Tools/LimitedTimeEvent/LimitedEventSeriesEditor.cs
2026-04-16 15:20:46 +08:00

784 lines
29 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using OfficeOpenXml;
using ArtResource;
using UnityEditor;
using UnityEngine;
using Debug = UnityEngine.Debug;
namespace DesignTools.LimitedTimeEvent
{
/// <summary>
/// 限时事件投放配置工具
/// 读取 Docs/config/LimitedTimeEvent.xlsx 的 Series Sheet
/// Items字段通过读取 Item.xlsx 中 IType=102 的条目进行选择
/// </summary>
public class LimitedEventSeriesEditor : BaseDesignToolEditor
{
private const string LIMITED_TIME_EVENT_EXCEL_NAME = "LimitedTimeEvent.xlsx";
private const string ITEM_EXCEL_NAME = "Item.xlsx";
private const string SERIES_SHEET_NAME = "Jackpot";
private const string ITEM_SHEET_NAME = "Item";
private const string ART_SO_PATH = "Assets/Art_SubModule/Art_SO";
private const int HEADER_ROW = 1;
private const int DATA_START_ROW = 3;
// 列索引
private int colId = -1;
private int colBonusLv = -1;
private int colItems = -1;
private int colType = -1;
private int colProb = -1;
private int colNote = -1;
private readonly List<SeriesRowData> seriesDataList = new List<SeriesRowData>();
private readonly List<LimitedEventItemInfo> limitedEventItems = new List<LimitedEventItemInfo>();
private readonly Dictionary<int, LimitedEventItemInfo> limitedEventItemById = new Dictionary<int, LimitedEventItemInfo>();
private readonly Dictionary<string, ArtTableSO> artTableByName = new Dictionary<string, ArtTableSO>(StringComparer.OrdinalIgnoreCase);
[MenuItem("策划工具/限时事件/限时事件投放")]
public static void ShowWindow()
{
var window = GetWindow<LimitedEventSeriesEditor>("限时事件投放");
window.minSize = window.GetMinWindowSize();
window.Show();
}
protected override string GetDocsPathPrefKey()
{
return "LimitedEventSeriesEditor_DocsPath";
}
protected override string GetWindowTitle()
{
return "限时事件投放配置工具";
}
protected override Vector2 GetMinWindowSize()
{
return new Vector2(1100, 600);
}
protected override void LoadConfigData()
{
LoadAllArtTableSO();
LoadLimitedEventItems();
LoadSeriesSheet();
}
protected override void DrawDataEditor()
{
DrawTableHeader();
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
for (int i = 0; i < seriesDataList.Count; i++)
{
DrawSeriesRow(seriesDataList[i]);
}
EditorGUILayout.EndScrollView();
EditorGUILayout.Space(4);
DrawAddRemoveButtons();
}
protected override void SaveDataToExcel()
{
SaveSeriesSheet();
}
#region
/// <summary>
/// 加载所有ArtTableSO资源
/// </summary>
private void LoadAllArtTableSO()
{
artTableByName.Clear();
string[] guids = AssetDatabase.FindAssets("t:ArtTableSO", new[] { ART_SO_PATH });
foreach (string guid in guids)
{
string path = AssetDatabase.GUIDToAssetPath(guid);
ArtTableSO tableSO = AssetDatabase.LoadAssetAtPath<ArtTableSO>(path);
if (tableSO == null || string.IsNullOrEmpty(tableSO.TableName))
{
continue;
}
artTableByName[tableSO.TableName] = tableSO;
}
Debug.Log($"加载了 {artTableByName.Count} 个 ArtTableSO 资源表");
}
/// <summary>
/// 从Item.xlsx加载IType=102的道具
/// </summary>
private void LoadLimitedEventItems()
{
limitedEventItems.Clear();
limitedEventItemById.Clear();
string excelPath = GetDocsConfigFilePath(ITEM_EXCEL_NAME);
if (!File.Exists(excelPath))
{
Debug.LogWarning($"未找到 {ITEM_EXCEL_NAME}: {excelPath}");
return;
}
using (var package = new ExcelPackage(new FileInfo(excelPath)))
{
var worksheet = package.Workbook.Worksheets[ITEM_SHEET_NAME];
if (worksheet == null || worksheet.Dimension == null)
{
Debug.LogWarning($"{ITEM_EXCEL_NAME} 中未找到 Sheet: {ITEM_SHEET_NAME}");
return;
}
int idCol = -1, nameCol = -1, iTypeCol = -1, resCol = -1;
int columnCount = worksheet.Dimension.End.Column;
for (int col = 1; col <= columnCount; col++)
{
string header = worksheet.Cells[HEADER_ROW, col].Text.Trim();
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.End.Row;
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 iTypeText = worksheet.Cells[row, iTypeCol].Text.Trim();
if (!int.TryParse(iTypeText, out int iType)) continue;
if (iType == 102)
{
string name = worksheet.Cells[row, nameCol].Text.Trim();
string res = resCol > 0 ? worksheet.Cells[row, resCol].Text.Trim() : "";
LimitedEventItemInfo itemInfo = new LimitedEventItemInfo
{
Id = id,
Name = name,
Res = res,
PreviewSprite = GetPreviewSpriteByRes(res)
};
limitedEventItems.Add(itemInfo);
limitedEventItemById[id] = itemInfo;
}
}
}
limitedEventItems.Sort((left, right) => left.Id.CompareTo(right.Id));
Debug.Log($"从Item.xlsx加载了 {limitedEventItems.Count} 个限时事件道具(IType=102)");
}
/// <summary>
/// 加载Series Sheet数据
/// </summary>
private void LoadSeriesSheet()
{
seriesDataList.Clear();
string excelPath = GetDocsConfigFilePath(LIMITED_TIME_EVENT_EXCEL_NAME);
if (!File.Exists(excelPath))
{
throw new FileNotFoundException($"未找到 {LIMITED_TIME_EVENT_EXCEL_NAME}", excelPath);
}
using (var package = new ExcelPackage(new FileInfo(excelPath)))
{
var worksheet = package.Workbook.Worksheets[SERIES_SHEET_NAME];
if (worksheet == null)
{
throw new Exception($"{LIMITED_TIME_EVENT_EXCEL_NAME} 中未找到 Sheet: {SERIES_SHEET_NAME}");
}
if (worksheet.Dimension == null)
{
throw new Exception($"{LIMITED_TIME_EVENT_EXCEL_NAME}/{SERIES_SHEET_NAME} 没有可读取的数据");
}
colId = FindColumnIndex(worksheet, "Id");
colBonusLv = FindColumnIndex(worksheet, "BonusLv");
colItems = FindColumnIndex(worksheet, "Items");
colType = FindColumnIndex(worksheet, "Type");
colProb = FindColumnIndex(worksheet, "Prob");
colNote = FindColumnIndex(worksheet, "备注");
if (colId < 0 || colBonusLv < 0 || colItems < 0 || colType < 0 || colProb < 0)
{
throw new Exception($"{SERIES_SHEET_NAME} 表结构不正确缺少必要列Id/BonusLv/Items/Type/Prob");
}
int rowCount = worksheet.Dimension.End.Row;
for (int row = DATA_START_ROW; row <= rowCount; row++)
{
string idText = worksheet.Cells[row, colId].Text.Trim();
if (string.IsNullOrEmpty(idText)) continue;
if (!int.TryParse(idText, out int id)) continue;
var data = new SeriesRowData
{
RowIndex = row,
Id = id,
BonusLv = ParseInt(worksheet.Cells[row, colBonusLv].Text),
ItemsJson = worksheet.Cells[row, colItems].Text.Trim(),
Type = ParseInt(worksheet.Cells[row, colType].Text),
Prob = ParseInt(worksheet.Cells[row, colProb].Text),
Note = colNote > 0 ? worksheet.Cells[row, colNote].Text.Trim() : ""
};
// 解析Items JSON中的第一个Id
data.ParsedItemId = ParseItemIdFromJson(data.ItemsJson);
seriesDataList.Add(data);
}
}
Debug.Log($"限时事件投放配置读取完成,共加载 {seriesDataList.Count} 条数据");
}
#endregion
#region UI绘制
private void DrawTableHeader()
{
EditorGUILayout.BeginVertical("box");
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Id", EditorStyles.boldLabel, GUILayout.Width(50));
EditorGUILayout.LabelField("BonusLv", EditorStyles.boldLabel, GUILayout.Width(70));
EditorGUILayout.LabelField("Items (限时事件道具)", EditorStyles.boldLabel, GUILayout.Width(350));
EditorGUILayout.LabelField("Type", EditorStyles.boldLabel, GUILayout.Width(60));
EditorGUILayout.LabelField("Prob", EditorStyles.boldLabel, GUILayout.Width(60));
EditorGUILayout.LabelField("备注", EditorStyles.boldLabel, GUILayout.MinWidth(120));
EditorGUILayout.LabelField("", GUILayout.Width(20)); // 删除按钮占位
EditorGUILayout.EndHorizontal();
EditorGUILayout.EndVertical();
}
private void DrawSeriesRow(SeriesRowData data)
{
EditorGUILayout.BeginHorizontal("box");
// Id
data.Id = EditorGUILayout.IntField(data.Id, GUILayout.Width(50));
// BonusLv
data.BonusLv = EditorGUILayout.IntField(data.BonusLv, GUILayout.Width(70));
// Items - 使用下拉选择IType=102的道具
DrawItemsField(data);
// Type
data.Type = EditorGUILayout.IntField(data.Type, GUILayout.Width(60));
// Prob
data.Prob = EditorGUILayout.IntField(data.Prob, GUILayout.Width(60));
// 备注
data.Note = EditorGUILayout.TextField(data.Note, GUILayout.MinWidth(120));
// 删除按钮
if (GUILayout.Button("×", GUILayout.Width(20)))
{
if (EditorUtility.DisplayDialog("确认删除", $"确定删除 Id={data.Id} 的行吗?", "确定", "取消"))
{
seriesDataList.Remove(data);
GUIUtility.ExitGUI();
}
}
EditorGUILayout.EndHorizontal();
}
private void DrawItemsField(SeriesRowData data)
{
LimitedEventItemInfo itemInfo = GetLimitedEventItemInfo(data.ParsedItemId);
bool hasPreview = itemInfo?.PreviewSprite != null && itemInfo.PreviewSprite.texture != null;
EditorGUILayout.BeginHorizontal(
"box",
GUILayout.Width(350),
GUILayout.MinHeight(hasPreview ? 68f : 42f));
if (hasPreview)
{
DrawSpritePreview(itemInfo.PreviewSprite, 48f, string.Empty);
}
EditorGUILayout.BeginVertical();
if (limitedEventItems.Count > 0)
{
string buttonText = itemInfo != null
? $"{itemInfo.Id} - {itemInfo.Name}"
: data.ParsedItemId > 0
? $"未找到道具 {data.ParsedItemId}"
: "选择限时事件道具";
if (GUILayout.Button(buttonText, GUILayout.Height(22)))
{
SeriesRowData capturedData = data;
LimitedEventItemPickerWindow.Show(limitedEventItems, position, data.ParsedItemId, selectedItem =>
{
capturedData.ParsedItemId = selectedItem.Id;
capturedData.ItemsJson = BuildItemsJson(selectedItem.Id);
Repaint();
});
}
if (itemInfo != null && !string.IsNullOrEmpty(itemInfo.Res))
{
EditorGUILayout.LabelField(itemInfo.Res, EditorStyles.miniLabel);
}
}
else
{
EditorGUILayout.LabelField("未加载到IType=102的道具", EditorStyles.miniLabel);
data.ItemsJson = EditorGUILayout.TextField(data.ItemsJson);
}
EditorGUILayout.LabelField(data.ItemsJson, EditorStyles.miniLabel);
EditorGUILayout.EndVertical();
EditorGUILayout.EndHorizontal();
}
private void DrawAddRemoveButtons()
{
EditorGUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (GUILayout.Button("+ 添加行", GUILayout.Width(100), GUILayout.Height(25)))
{
int newId = seriesDataList.Count > 0 ? seriesDataList.Max(x => x.Id) + 1 : 1;
int defaultItemId = limitedEventItems.Count > 0 ? limitedEventItems[0].Id : 0;
seriesDataList.Add(new SeriesRowData
{
RowIndex = -1,
Id = newId,
BonusLv = 1,
ItemsJson = defaultItemId > 0 ? $"[{{\"Id\":{defaultItemId},\"Num\":1}}]" : "[]",
Type = 0,
Prob = 0,
Note = "",
ParsedItemId = defaultItemId
});
}
EditorGUILayout.EndHorizontal();
}
#endregion
#region
private void SaveSeriesSheet()
{
if (seriesDataList.Count == 0)
{
EditorUtility.DisplayDialog("提示", "当前没有可保存的数据,请先加载配置。", "确定");
return;
}
string excelPath = GetDocsConfigFilePath(LIMITED_TIME_EVENT_EXCEL_NAME);
if (!File.Exists(excelPath))
{
EditorUtility.DisplayDialog("错误", $"未找到文件:{excelPath}", "确定");
return;
}
try
{
using (var package = new ExcelPackage(new FileInfo(excelPath)))
{
var worksheet = package.Workbook.Worksheets[SERIES_SHEET_NAME];
if (worksheet == null)
{
EditorUtility.DisplayDialog("错误", $"未找到 Sheet: {SERIES_SHEET_NAME}", "确定");
return;
}
// 清除旧数据行从DATA_START_ROW开始
int oldRowCount = worksheet.Dimension?.End.Row ?? 0;
for (int row = DATA_START_ROW; row <= oldRowCount; row++)
{
for (int col = 1; col <= worksheet.Dimension.End.Column; col++)
{
worksheet.Cells[row, col].Value = null;
}
}
// 写入新数据
for (int i = 0; i < seriesDataList.Count; i++)
{
int row = DATA_START_ROW + i;
var data = seriesDataList[i];
worksheet.Cells[row, colId].Value = data.Id;
worksheet.Cells[row, colBonusLv].Value = data.BonusLv;
worksheet.Cells[row, colItems].Value = data.ItemsJson;
worksheet.Cells[row, colType].Value = data.Type;
worksheet.Cells[row, colProb].Value = data.Prob;
if (colNote > 0)
{
worksheet.Cells[row, colNote].Value = data.Note;
}
}
package.Save();
}
EditorUtility.DisplayDialog("成功", "限时事件投放配置已保存到 Excel", "确定");
Debug.Log("限时事件投放配置保存成功");
}
catch (Exception e)
{
EditorUtility.DisplayDialog("错误", $"保存失败: {e.Message}", "确定");
Debug.LogError($"保存限时事件投放配置失败: {e}");
}
}
#endregion
#region
private LimitedEventItemInfo GetLimitedEventItemInfo(int itemId)
{
if (itemId <= 0)
{
return null;
}
limitedEventItemById.TryGetValue(itemId, out LimitedEventItemInfo itemInfo);
return itemInfo;
}
private string BuildItemsJson(int itemId)
{
return itemId > 0 ? $"[{{\"Id\":{itemId},\"Num\":1}}]" : "[]";
}
private Sprite GetPreviewSpriteByRes(string res)
{
if (!TryParseRes(res, out string tableName, out string artItemName))
{
return null;
}
if (!artTableByName.TryGetValue(tableName, out ArtTableSO table) || table == null)
{
return null;
}
ArtItemData item = table.Items.FirstOrDefault(x => x.Name == artItemName);
return item?.Sprite;
}
private static bool TryParseRes(string res, out string tableName, out string artItemName)
{
tableName = string.Empty;
artItemName = string.Empty;
if (string.IsNullOrWhiteSpace(res))
{
return false;
}
string[] parts = res.Split(new[] { ',' }, 2, StringSplitOptions.None);
if (parts.Length < 2)
{
return false;
}
tableName = parts[0].Trim();
artItemName = parts[1].Trim();
return !string.IsNullOrEmpty(tableName) && !string.IsNullOrEmpty(artItemName);
}
private static void DrawSpritePreview(Sprite sprite, float size, string emptyText)
{
Rect previewRect = GUILayoutUtility.GetRect(size, size, GUILayout.Width(size), GUILayout.Height(size));
DrawSpritePreview(previewRect, sprite, emptyText);
}
private static void DrawSpritePreview(Rect previewRect, Sprite sprite, string emptyText)
{
if (sprite != null && sprite.texture != null)
{
Rect texCoords = sprite.textureRect;
Texture2D tex = sprite.texture;
Rect normalizedCoords = new Rect(
texCoords.x / tex.width,
texCoords.y / tex.height,
texCoords.width / tex.width,
texCoords.height / tex.height
);
EditorGUI.DrawRect(previewRect, new Color(0.4f, 0.4f, 0.4f, 1f));
float aspect = texCoords.height <= 0f ? 1f : texCoords.width / texCoords.height;
Rect drawRect = previewRect;
if (aspect > 1f)
{
float newHeight = previewRect.height / aspect;
drawRect.y += (previewRect.height - newHeight) * 0.5f;
drawRect.height = newHeight;
}
else
{
float newWidth = previewRect.width * aspect;
drawRect.x += (previewRect.width - newWidth) * 0.5f;
drawRect.width = newWidth;
}
GUI.DrawTextureWithTexCoords(drawRect, tex, normalizedCoords);
return;
}
EditorGUI.DrawRect(previewRect, new Color(0.3f, 0.3f, 0.3f, 1f));
GUIStyle emptyStyle = new GUIStyle(EditorStyles.centeredGreyMiniLabel)
{
wordWrap = true,
alignment = TextAnchor.MiddleCenter
};
GUI.Label(previewRect, emptyText, emptyStyle);
}
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 static int ParseInt(string text)
{
if (int.TryParse(text?.Trim(), out int value))
return value;
return 0;
}
/// <summary>
/// 从Items的JSON中解析出第一个Id
/// 输入格式: [{"Id":100011,"Num":1}]
/// </summary>
private static int ParseItemIdFromJson(string json)
{
if (string.IsNullOrEmpty(json)) return 0;
int idIndex = json.IndexOf("\"Id\"", StringComparison.OrdinalIgnoreCase);
if (idIndex < 0) return 0;
int colonIndex = json.IndexOf(':', idIndex);
if (colonIndex < 0) return 0;
int start = colonIndex + 1;
while (start < json.Length && char.IsWhiteSpace(json[start]))
{
start++;
}
int end = start;
while (end < json.Length && (char.IsDigit(json[end]) || json[end] == '-'))
{
end++;
}
if (end > start && int.TryParse(json.Substring(start, end - start), out int id))
return id;
return 0;
}
#endregion
[Serializable]
private class LimitedEventItemInfo
{
public int Id;
public string Name;
public string Res;
public Sprite PreviewSprite;
}
private class LimitedEventItemPickerWindow : EditorWindow
{
private readonly List<LimitedEventItemInfo> allItems = new List<LimitedEventItemInfo>();
private Action<LimitedEventItemInfo> onSelect;
private string searchText = string.Empty;
private Vector2 scrollPosition;
private int currentItemId;
private const float IMAGE_SIZE = 84f;
private const float ROW_HEIGHT_WITH_PREVIEW = 108f;
private const float ROW_HEIGHT_NO_PREVIEW = 54f;
public static void Show(List<LimitedEventItemInfo> items, Rect ownerWindowRect, int currentItemId, Action<LimitedEventItemInfo> onSelect)
{
if (items == null || items.Count == 0)
{
EditorUtility.DisplayDialog("提示", "未加载到 IType=102 的道具", "确定");
return;
}
LimitedEventItemPickerWindow window = CreateInstance<LimitedEventItemPickerWindow>();
window.titleContent = new GUIContent("选择限时事件道具");
window.minSize = new Vector2(620, 520);
window.allItems.Clear();
window.allItems.AddRange(items.OrderBy(x => x.Id));
window.currentItemId = currentItemId;
window.onSelect = onSelect;
window.position = GetCenteredRect(ownerWindowRect, window.minSize);
window.ShowUtility();
}
private static Rect GetCenteredRect(Rect ownerWindowRect, Vector2 windowSize)
{
float x = ownerWindowRect.x + (ownerWindowRect.width - windowSize.x) * 0.5f;
float y = ownerWindowRect.y + (ownerWindowRect.height - windowSize.y) * 0.5f;
return new Rect(x, y, windowSize.x, windowSize.y);
}
private void OnGUI()
{
DrawToolbar();
EditorGUILayout.Space(4f);
DrawItemList();
}
private void DrawToolbar()
{
EditorGUILayout.BeginVertical("box");
EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
EditorGUILayout.LabelField("搜索", GUILayout.Width(40));
searchText = EditorGUILayout.TextField(searchText, EditorStyles.toolbarSearchField);
if (GUILayout.Button("×", EditorStyles.miniButton, GUILayout.Width(20)))
{
searchText = string.Empty;
GUI.FocusControl(null);
}
EditorGUILayout.EndHorizontal();
int filteredCount = allItems.Count(MatchSearch);
EditorGUILayout.LabelField($"共 {filteredCount} 个限时事件道具,点击即可选择", EditorStyles.miniLabel);
EditorGUILayout.EndVertical();
}
private void DrawItemList()
{
List<LimitedEventItemInfo> filteredItems = allItems.Where(MatchSearch).ToList();
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
foreach (LimitedEventItemInfo item in filteredItems)
{
DrawItemRow(item);
}
EditorGUILayout.EndScrollView();
}
private void DrawItemRow(LimitedEventItemInfo item)
{
bool isCurrent = item.Id == currentItemId;
bool hasPreview = item.PreviewSprite != null && item.PreviewSprite.texture != null;
float rowHeight = hasPreview ? ROW_HEIGHT_WITH_PREVIEW : ROW_HEIGHT_NO_PREVIEW;
GUI.backgroundColor = isCurrent ? new Color(0.8f, 1f, 0.8f) : Color.white;
EditorGUILayout.BeginHorizontal("box", GUILayout.ExpandWidth(true), GUILayout.MinHeight(rowHeight));
if (hasPreview)
{
Rect imageRect = GUILayoutUtility.GetRect(IMAGE_SIZE, IMAGE_SIZE, GUILayout.Width(IMAGE_SIZE), GUILayout.Height(IMAGE_SIZE));
DrawSpritePreview(imageRect, item.PreviewSprite, string.Empty);
}
EditorGUILayout.BeginVertical();
GUIStyle nameStyle = new GUIStyle(EditorStyles.boldLabel)
{
wordWrap = true,
alignment = TextAnchor.UpperLeft
};
GUILayout.Label($"{item.Id} - {item.Name}", nameStyle);
if (!string.IsNullOrEmpty(item.Res))
{
GUIStyle resStyle = new GUIStyle(EditorStyles.centeredGreyMiniLabel)
{
wordWrap = true,
alignment = TextAnchor.UpperLeft
};
GUILayout.Label(item.Res, resStyle);
}
EditorGUILayout.EndVertical();
GUILayout.FlexibleSpace();
if (GUILayout.Button("选择", EditorStyles.miniButton))
{
onSelect?.Invoke(item);
Close();
}
EditorGUILayout.EndHorizontal();
GUI.backgroundColor = Color.white;
}
private bool MatchSearch(LimitedEventItemInfo item)
{
if (string.IsNullOrWhiteSpace(searchText))
{
return true;
}
return item.Id.ToString().Contains(searchText, StringComparison.OrdinalIgnoreCase)
|| (!string.IsNullOrEmpty(item.Name) && item.Name.Contains(searchText, StringComparison.OrdinalIgnoreCase))
|| (!string.IsNullOrEmpty(item.Res) && item.Res.Contains(searchText, StringComparison.OrdinalIgnoreCase));
}
}
[Serializable]
private class SeriesRowData
{
public int RowIndex;
public int Id;
public int BonusLv;
public string ItemsJson;
public int Type;
public int Prob;
public string Note;
/// <summary>
/// 从ItemsJson解析出的道具Id用于下拉选择
/// </summary>
public int ParsedItemId;
}
}
}