Files
bansonic_beta_main/Assets/_eqpmtSys/equipBag.cs
T
2026-06-25 11:48:56 +08:00

543 lines
16 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
using Bansonic;
#if UNITY_EDITOR
using UnityEditor;
#endif
public class equipBag : MonoBehaviour
{
private enum EquipFilterMode
{
All,
HasSpecialSkill,
HasIllusionSkill,
HasAnySkill,
HasNoSkill,
HasDualSkill,
Type0,
Type1,
Type2,
Type3,
Type4,
Type5,
Type6,
Type7
}
private enum EquipOrderMode
{
AcquireAsc,
AcquireDesc,
QualityAsc,
QualityDesc
}
[Header("prefab")]
public GameObject eqpmtItemPrefab;
public Transform eqpmtItemParent;
[Header("dropdown")]
public Dropdown orderDropdown;
public Dropdown filterDropdown;
[Header("source paths")]
public string runtimeEquipmentFolder = "so/uEquip";
public string editorEquipmentFolder = "Assets/Resources/so/uEquip";
[Header("async spawn")]
public int spawnBatchSize = 12;
private readonly List<GameObject> spawnedItems = new List<GameObject>();
private Coroutine rebuildCoroutine;
private bool suppressDropdownCallbacks;
private static readonly (EquipFilterMode mode, string label)[] FilterOptions =
{
(EquipFilterMode.All, "全部"),
(EquipFilterMode.HasSpecialSkill, "含特效技能"),
(EquipFilterMode.HasIllusionSkill, "含巡演技能"),
(EquipFilterMode.HasAnySkill, "含技能"),
(EquipFilterMode.HasNoSkill, "不含技能"),
(EquipFilterMode.HasDualSkill, "含双技能"),
(EquipFilterMode.Type0, equipmentSO.EquipmentSkillType.题海战术.ToString()),
(EquipFilterMode.Type1, equipmentSO.EquipmentSkillType.诛锄异己.ToString()),
(EquipFilterMode.Type2, equipmentSO.EquipmentSkillType.逸乐共谋.ToString()),
(EquipFilterMode.Type3, equipmentSO.EquipmentSkillType.完美至上.ToString()),
(EquipFilterMode.Type4, equipmentSO.EquipmentSkillType.涵养心境.ToString()),
(EquipFilterMode.Type5, equipmentSO.EquipmentSkillType.众志成城.ToString()),
(EquipFilterMode.Type6, equipmentSO.EquipmentSkillType.过激行为.ToString()),
(EquipFilterMode.Type7, equipmentSO.EquipmentSkillType.二次形变.ToString())
};
private static readonly (EquipOrderMode mode, string label)[] OrderOptions =
{
(EquipOrderMode.AcquireAsc, "获取时间升序"),
(EquipOrderMode.AcquireDesc, "获取时间降序"),
(EquipOrderMode.QualityAsc, "品质升序"),
(EquipOrderMode.QualityDesc, "品质降序")
};
private void Awake()
{
InitializeDropdowns();
}
private void Start()
{
Rebuild();
}
private void OnEnable()
{
InitializeDropdowns();
Rebuild();
}
private void OnDisable()
{
if (orderDropdown != null)
{
orderDropdown.onValueChanged.RemoveListener(HandleOrderChanged);
}
if (filterDropdown != null)
{
filterDropdown.onValueChanged.RemoveListener(HandleFilterChanged);
}
if (rebuildCoroutine != null)
{
StopCoroutine(rebuildCoroutine);
rebuildCoroutine = null;
}
}
public void Rebuild()
{
if (rebuildCoroutine != null)
{
StopCoroutine(rebuildCoroutine);
rebuildCoroutine = null;
}
ClearSpawnedItems();
if (eqpmtItemPrefab == null || eqpmtItemParent == null)
{
return;
}
List<equipmentSO> equipments = LoadEquipments()
.Where(equipment => equipment != null
&& !equipSmelt.IsEquipmentAssignedToSmeltPool(equipment)
&& !equipSmelt.ShouldHideConsumedEquipment(equipment))
.Where(MatchesCurrentFilter)
.ToList();
SortEquipments(equipments);
if (Application.isPlaying && isActiveAndEnabled && gameObject.activeInHierarchy)
{
rebuildCoroutine = StartCoroutine(RebuildAsync(equipments));
return;
}
SpawnAllImmediate(equipments);
}
private void InitializeDropdowns()
{
InitializeFilterDropdown();
InitializeOrderDropdown();
}
private void InitializeFilterDropdown()
{
if (filterDropdown == null)
{
return;
}
suppressDropdownCallbacks = true;
filterDropdown.onValueChanged.RemoveListener(HandleFilterChanged);
filterDropdown.ClearOptions();
filterDropdown.AddOptions(FilterOptions.Select(option => new Dropdown.OptionData(option.label)).ToList());
filterDropdown.value = 0;
filterDropdown.RefreshShownValue();
filterDropdown.onValueChanged.AddListener(HandleFilterChanged);
suppressDropdownCallbacks = false;
}
private void InitializeOrderDropdown()
{
if (orderDropdown == null)
{
return;
}
suppressDropdownCallbacks = true;
orderDropdown.onValueChanged.RemoveListener(HandleOrderChanged);
orderDropdown.ClearOptions();
orderDropdown.AddOptions(OrderOptions.Select(option => new Dropdown.OptionData(option.label)).ToList());
orderDropdown.value = 0;
orderDropdown.RefreshShownValue();
orderDropdown.onValueChanged.AddListener(HandleOrderChanged);
suppressDropdownCallbacks = false;
}
private void HandleFilterChanged(int _)
{
if (!suppressDropdownCallbacks)
{
Rebuild();
}
}
private void HandleOrderChanged(int _)
{
if (!suppressDropdownCallbacks)
{
Rebuild();
}
}
private IEnumerator RebuildAsync(List<equipmentSO> equipments)
{
if (equipments == null || equipments.Count == 0)
{
rebuildCoroutine = null;
yield break;
}
int batchSize = Mathf.Max(1, spawnBatchSize);
for (int i = 0; i < equipments.Count; i++)
{
SpawnOne(equipments[i]);
if ((i + 1) % batchSize == 0)
{
yield return null;
}
}
rebuildCoroutine = null;
}
private void SpawnAllImmediate(List<equipmentSO> equipments)
{
if (equipments == null)
{
return;
}
for (int i = 0; i < equipments.Count; i++)
{
SpawnOne(equipments[i]);
}
}
private void SpawnOne(equipmentSO equipment)
{
if (equipment == null || eqpmtItemPrefab == null || eqpmtItemParent == null)
{
return;
}
GameObject instance = Instantiate(eqpmtItemPrefab, eqpmtItemParent);
string displayName = equipment.GetDisplayTierName();
instance.name = string.IsNullOrWhiteSpace(displayName) ? equipment.name : displayName;
equipItemPrefab item = instance.GetComponent<equipItemPrefab>();
if (item != null)
{
item.Bind(equipment, HandleEquipmentClicked);
}
spawnedItems.Add(instance);
}
private equipmentSO[] LoadEquipments()
{
var results = new List<equipmentSO>();
var indexedByName = new Dictionary<string, int>(StringComparer.Ordinal);
#if UNITY_EDITOR
if (!Application.isPlaying)
{
results.AddRange(LoadEditorEquipments());
}
else
#endif
{
results.AddRange(Resources.LoadAll<equipmentSO>(runtimeEquipmentFolder)
.Where(equipment => equipment != null));
}
for (int i = 0; i < results.Count; i++)
{
equipmentSO equipment = results[i];
if (equipment == null || string.IsNullOrWhiteSpace(equipment.name))
{
continue;
}
indexedByName[equipment.name] = i;
}
IReadOnlyList<equipmentSO> runtimeGenerated = equipmentGenerator.GetRuntimeGeneratedEquipments();
if (runtimeGenerated != null)
{
for (int i = 0; i < runtimeGenerated.Count; i++)
{
equipmentSO equipment = runtimeGenerated[i];
if (equipment == null)
{
continue;
}
if (!string.IsNullOrWhiteSpace(equipment.name) && indexedByName.TryGetValue(equipment.name, out int existingIndex))
{
results[existingIndex] = equipment;
continue;
}
results.Add(equipment);
if (!string.IsNullOrWhiteSpace(equipment.name))
{
indexedByName[equipment.name] = results.Count - 1;
}
}
}
return results.Where(equipment => equipment != null).ToArray();
}
#if UNITY_EDITOR
private equipmentSO[] LoadEditorEquipments()
{
if (string.IsNullOrWhiteSpace(editorEquipmentFolder) || !AssetDatabase.IsValidFolder(editorEquipmentFolder))
{
return Array.Empty<equipmentSO>();
}
string[] guids = AssetDatabase.FindAssets("t:equipmentSO", new[] { editorEquipmentFolder });
var result = new List<equipmentSO>(guids.Length);
for (int i = 0; i < guids.Length; i++)
{
string path = AssetDatabase.GUIDToAssetPath(guids[i]);
equipmentSO equipment = AssetDatabase.LoadAssetAtPath<equipmentSO>(path);
if (equipment != null)
{
result.Add(equipment);
}
}
return result.ToArray();
}
#endif
private bool MatchesCurrentFilter(equipmentSO equipment)
{
if (equipment == null)
{
return false;
}
EquipFilterMode mode = GetSelectedFilterMode();
bool hasSpecialSkill = equipment.sa_skillID > 0;
bool hasIllusionSkill = equipment.ia_skillID > 0;
switch (mode)
{
case EquipFilterMode.All:
return true;
case EquipFilterMode.HasSpecialSkill:
return hasSpecialSkill;
case EquipFilterMode.HasIllusionSkill:
return hasIllusionSkill;
case EquipFilterMode.HasAnySkill:
return hasSpecialSkill || hasIllusionSkill;
case EquipFilterMode.HasNoSkill:
return !hasSpecialSkill && !hasIllusionSkill;
case EquipFilterMode.HasDualSkill:
return hasSpecialSkill && hasIllusionSkill;
case EquipFilterMode.Type0:
return equipment.skillType == equipmentSO.EquipmentSkillType.题海战术;
case EquipFilterMode.Type1:
return equipment.skillType == equipmentSO.EquipmentSkillType.诛锄异己;
case EquipFilterMode.Type2:
return equipment.skillType == equipmentSO.EquipmentSkillType.逸乐共谋;
case EquipFilterMode.Type3:
return equipment.skillType == equipmentSO.EquipmentSkillType.完美至上;
case EquipFilterMode.Type4:
return equipment.skillType == equipmentSO.EquipmentSkillType.涵养心境;
case EquipFilterMode.Type5:
return equipment.skillType == equipmentSO.EquipmentSkillType.众志成城;
case EquipFilterMode.Type6:
return equipment.skillType == equipmentSO.EquipmentSkillType.过激行为;
case EquipFilterMode.Type7:
return equipment.skillType == equipmentSO.EquipmentSkillType.二次形变;
default:
return true;
}
}
private void SortEquipments(List<equipmentSO> equipments)
{
if (equipments == null)
{
return;
}
EquipOrderMode mode = GetSelectedOrderMode();
equipments.Sort((left, right) => CompareEquipments(left, right, mode));
}
private EquipFilterMode GetSelectedFilterMode()
{
int index = filterDropdown != null ? Mathf.Clamp(filterDropdown.value, 0, FilterOptions.Length - 1) : 0;
return FilterOptions[index].mode;
}
private EquipOrderMode GetSelectedOrderMode()
{
int index = orderDropdown != null ? Mathf.Clamp(orderDropdown.value, 0, OrderOptions.Length - 1) : 0;
return OrderOptions[index].mode;
}
private void HandleEquipmentClicked(equipmentSO equipment)
{
if (equipment == null)
{
return;
}
}
private void ClearSpawnedItems()
{
if (eqpmtItemParent != null)
{
for (int i = eqpmtItemParent.childCount - 1; i >= 0; i--)
{
Transform child = eqpmtItemParent.GetChild(i);
if (child == null)
{
continue;
}
#if UNITY_EDITOR
if (!Application.isPlaying)
{
DestroyImmediate(child.gameObject);
}
else
#endif
{
Destroy(child.gameObject);
}
}
}
spawnedItems.Clear();
}
private static int CompareEquipments(equipmentSO left, equipmentSO right, EquipOrderMode mode)
{
if (left == right)
{
return 0;
}
if (left == null)
{
return 1;
}
if (right == null)
{
return -1;
}
switch (mode)
{
case EquipOrderMode.AcquireAsc:
return CompareAcquire(left, right, false);
case EquipOrderMode.AcquireDesc:
return CompareAcquire(left, right, true);
case EquipOrderMode.QualityAsc:
return CompareQuality(left, right, false);
case EquipOrderMode.QualityDesc:
return CompareQuality(left, right, true);
default:
return CompareAcquire(left, right, false);
}
}
private static int CompareAcquire(equipmentSO left, equipmentSO right, bool descending)
{
ParseEquipmentSortKey(left, out long leftDate, out long leftId);
ParseEquipmentSortKey(right, out long rightDate, out long rightId);
int dateCompare = leftDate.CompareTo(rightDate);
if (dateCompare != 0)
{
return descending ? -dateCompare : dateCompare;
}
int idCompare = leftId.CompareTo(rightId);
if (idCompare != 0)
{
return descending ? -idCompare : idCompare;
}
string leftName = left.GetDisplayTierName();
string rightName = right.GetDisplayTierName();
int nameCompare = string.Compare(leftName, rightName, StringComparison.Ordinal);
return descending ? -nameCompare : nameCompare;
}
private static int CompareQuality(equipmentSO left, equipmentSO right, bool descending)
{
int qualityCompare = left.GetVisualQualityColorIndex().CompareTo(right.GetVisualQualityColorIndex());
if (qualityCompare != 0)
{
return descending ? -qualityCompare : qualityCompare;
}
return CompareAcquire(left, right, true);
}
private static void ParseEquipmentSortKey(equipmentSO equipment, out long datePart, out long idPart)
{
datePart = 0L;
idPart = 0L;
if (equipment == null || string.IsNullOrWhiteSpace(equipment.name))
{
return;
}
string raw = equipment.name;
if (raw.StartsWith("type", StringComparison.OrdinalIgnoreCase))
{
int firstUnderscore = raw.IndexOf('_');
if (firstUnderscore >= 0 && firstUnderscore + 1 < raw.Length)
{
raw = raw.Substring(firstUnderscore + 1);
}
}
string[] parts = raw.Split('_');
if (parts.Length >= 2)
{
long.TryParse(parts[0], out datePart);
long.TryParse(parts[1], out idPart);
}
}
}