978 lines
29 KiB
C#
978 lines
29 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 idolEquipments : 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("objects")]
|
|
public GameObject eqpmtItemPrefab;
|
|
public Transform eqpmtToPut;
|
|
|
|
[Header("INFO")]
|
|
public Text this_eqpmtName;
|
|
public Text this_eqpmtType;
|
|
public Text this_eqpmtLevel;
|
|
public Text this_eqpmtID;
|
|
|
|
[Header("waitingList")]
|
|
public int i_batch = 16;
|
|
public Transform eqpmtBagParent;
|
|
|
|
[Header("filter")]
|
|
public Toggle onlyCanEquip;
|
|
public Dropdown orderFilter;
|
|
public Dropdown typeFilter;
|
|
|
|
[Header("emptyText")]
|
|
public Text emptyText;
|
|
public Scrollbar eqpmtBagScrollbar;
|
|
|
|
[Header("source paths")]
|
|
public string runtimeEquipmentFolder = "so/uEquip";
|
|
public string editorEquipmentFolder = "Assets/Resources/so/uEquip";
|
|
|
|
private readonly List<GameObject> spawnedBagItems = new List<GameObject>();
|
|
private Coroutine rebuildRoutine;
|
|
private equipmentSO equippedEquipment;
|
|
private GameObject equippedItemInstance;
|
|
private AllyHero_SO currentHero;
|
|
private float pendingScrollbarValue = 1f;
|
|
private Coroutine restoreScrollbarRoutine;
|
|
private bool suppressDropdownCallbacks;
|
|
private bool hasStarted;
|
|
private bool equipmentOwnershipCacheReady;
|
|
private readonly Dictionary<equipmentSO, AllyHero_SO> ownershipByReference = new Dictionary<equipmentSO, AllyHero_SO>();
|
|
private readonly Dictionary<string, AllyHero_SO> ownershipByName = new Dictionary<string, AllyHero_SO>(StringComparer.Ordinal);
|
|
|
|
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 Start()
|
|
{
|
|
hasStarted = true;
|
|
InitializeDropdowns();
|
|
InitializeOnlyCanEquipToggle();
|
|
BindControls();
|
|
RestoreEquippedFromHero();
|
|
RebuildBag();
|
|
RefreshEquippedSlot();
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
InitializeDropdowns();
|
|
InitializeOnlyCanEquipToggle();
|
|
BindControls();
|
|
RestoreEquippedFromHero();
|
|
if (hasStarted)
|
|
{
|
|
RebuildBag();
|
|
RefreshEquippedSlot();
|
|
}
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
UnbindControls();
|
|
if (rebuildRoutine != null)
|
|
{
|
|
StopCoroutine(rebuildRoutine);
|
|
rebuildRoutine = null;
|
|
}
|
|
|
|
if (restoreScrollbarRoutine != null)
|
|
{
|
|
StopCoroutine(restoreScrollbarRoutine);
|
|
restoreScrollbarRoutine = null;
|
|
}
|
|
}
|
|
|
|
private void BindControls()
|
|
{
|
|
if (onlyCanEquip != null)
|
|
{
|
|
onlyCanEquip.onValueChanged.RemoveListener(HandleFilterChanged);
|
|
onlyCanEquip.onValueChanged.AddListener(HandleFilterChanged);
|
|
}
|
|
|
|
if (orderFilter != null)
|
|
{
|
|
orderFilter.onValueChanged.RemoveListener(HandleOrderChanged);
|
|
orderFilter.onValueChanged.AddListener(HandleOrderChanged);
|
|
}
|
|
|
|
if (typeFilter != null)
|
|
{
|
|
typeFilter.onValueChanged.RemoveListener(HandleTypeChanged);
|
|
typeFilter.onValueChanged.AddListener(HandleTypeChanged);
|
|
}
|
|
}
|
|
|
|
private void UnbindControls()
|
|
{
|
|
if (onlyCanEquip != null)
|
|
{
|
|
onlyCanEquip.onValueChanged.RemoveListener(HandleFilterChanged);
|
|
}
|
|
|
|
if (orderFilter != null)
|
|
{
|
|
orderFilter.onValueChanged.RemoveListener(HandleOrderChanged);
|
|
}
|
|
|
|
if (typeFilter != null)
|
|
{
|
|
typeFilter.onValueChanged.RemoveListener(HandleTypeChanged);
|
|
}
|
|
}
|
|
|
|
private void HandleFilterChanged(bool _)
|
|
{
|
|
if (!suppressDropdownCallbacks)
|
|
{
|
|
RebuildBag();
|
|
}
|
|
}
|
|
|
|
private void HandleOrderChanged(int _)
|
|
{
|
|
if (!suppressDropdownCallbacks)
|
|
{
|
|
RebuildBag();
|
|
}
|
|
}
|
|
|
|
private void HandleTypeChanged(int _)
|
|
{
|
|
if (!suppressDropdownCallbacks)
|
|
{
|
|
RebuildBag();
|
|
}
|
|
}
|
|
|
|
private void InitializeDropdowns()
|
|
{
|
|
InitializeTypeFilterDropdown();
|
|
InitializeOrderDropdown();
|
|
}
|
|
|
|
private void InitializeTypeFilterDropdown()
|
|
{
|
|
if (typeFilter == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
suppressDropdownCallbacks = true;
|
|
typeFilter.onValueChanged.RemoveListener(HandleTypeChanged);
|
|
typeFilter.ClearOptions();
|
|
typeFilter.AddOptions(FilterOptions.Select(option => new Dropdown.OptionData(option.label)).ToList());
|
|
typeFilter.value = 0;
|
|
typeFilter.RefreshShownValue();
|
|
typeFilter.onValueChanged.AddListener(HandleTypeChanged);
|
|
suppressDropdownCallbacks = false;
|
|
}
|
|
|
|
private void InitializeOrderDropdown()
|
|
{
|
|
if (orderFilter == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
suppressDropdownCallbacks = true;
|
|
orderFilter.onValueChanged.RemoveListener(HandleOrderChanged);
|
|
orderFilter.ClearOptions();
|
|
orderFilter.AddOptions(OrderOptions.Select(option => new Dropdown.OptionData(option.label)).ToList());
|
|
orderFilter.value = 3;
|
|
orderFilter.RefreshShownValue();
|
|
orderFilter.onValueChanged.AddListener(HandleOrderChanged);
|
|
suppressDropdownCallbacks = false;
|
|
}
|
|
|
|
private void InitializeOnlyCanEquipToggle()
|
|
{
|
|
if (onlyCanEquip == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
onlyCanEquip.SetIsOnWithoutNotify(true);
|
|
}
|
|
|
|
public void RebuildBag()
|
|
{
|
|
CacheScrollbarValue();
|
|
|
|
if (rebuildRoutine != null)
|
|
{
|
|
StopCoroutine(rebuildRoutine);
|
|
rebuildRoutine = null;
|
|
}
|
|
|
|
ClearBagItems();
|
|
|
|
if (eqpmtItemPrefab == null || eqpmtBagParent == null)
|
|
{
|
|
RefreshEmptyState(0);
|
|
return;
|
|
}
|
|
|
|
RefreshEquipmentOwnershipCache();
|
|
|
|
List<equipmentSO> equipments = LoadEquipments()
|
|
.Where(e => e != null)
|
|
.Where(e => !equipSmelt.IsEquipmentAssignedToSmeltPool(e) && !equipSmelt.ShouldHideConsumedEquipment(e))
|
|
.Where(e => equippedEquipment == null || e != equippedEquipment)
|
|
.Where(MatchesCurrentFilters)
|
|
.ToList();
|
|
|
|
SortEquipments(equipments);
|
|
RefreshEmptyState(equipments.Count);
|
|
|
|
if (Application.isPlaying && isActiveAndEnabled && gameObject.activeInHierarchy)
|
|
{
|
|
rebuildRoutine = StartCoroutine(RebuildBagAsync(equipments));
|
|
return;
|
|
}
|
|
|
|
SpawnBagItemsImmediate(equipments);
|
|
RestoreScrollbarValueImmediate();
|
|
}
|
|
|
|
private IEnumerator RebuildBagAsync(List<equipmentSO> equipments)
|
|
{
|
|
int batchSize = Mathf.Max(1, i_batch);
|
|
for (int i = 0; i < equipments.Count; i++)
|
|
{
|
|
SpawnBagItem(equipments[i], i);
|
|
if ((i + 1) % batchSize == 0)
|
|
{
|
|
yield return null;
|
|
}
|
|
}
|
|
|
|
rebuildRoutine = null;
|
|
BeginRestoreScrollbarValue();
|
|
}
|
|
|
|
private void SpawnBagItemsImmediate(List<equipmentSO> equipments)
|
|
{
|
|
for (int i = 0; i < equipments.Count; i++)
|
|
{
|
|
SpawnBagItem(equipments[i], i);
|
|
}
|
|
}
|
|
|
|
private void SpawnBagItem(equipmentSO equipment, int index)
|
|
{
|
|
if (equipment == null || eqpmtItemPrefab == null || eqpmtBagParent == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
GameObject instance = GetOrCreateBagItem(index);
|
|
instance.name = string.IsNullOrWhiteSpace(equipment.GetDisplayTierName()) ? equipment.name : equipment.GetDisplayTierName();
|
|
|
|
equipItemPrefab item = instance.GetComponent<equipItemPrefab>();
|
|
if (item != null)
|
|
{
|
|
item.Bind(equipment, null, HandleBagItemRightClicked);
|
|
item.allowDrag = false;
|
|
item.allowQuickTransfer = false;
|
|
if (item.itemButton != null)
|
|
{
|
|
item.itemButton.interactable = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool HandleBagItemRightClicked(equipmentSO equipment)
|
|
{
|
|
if (equipment == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (IsEquippedByOtherHero(equipment, out AllyHero_SO occupiedHero))
|
|
{
|
|
string heroName = occupiedHero != null ? occupiedHero.ally_heroName : "其他角色";
|
|
gNotice.warning.display($"该记忆已被{heroName}装备");
|
|
return true;
|
|
}
|
|
|
|
EquipEquipment(equipment);
|
|
return true;
|
|
}
|
|
|
|
private bool HandleEquippedItemRightClicked(equipmentSO equipment)
|
|
{
|
|
if (equipment == null || equippedEquipment == null || equipment != equippedEquipment)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
UnequipEquipment();
|
|
return true;
|
|
}
|
|
|
|
private void EquipEquipment(equipmentSO equipment)
|
|
{
|
|
equippedEquipment = equipment;
|
|
if (currentHero != null)
|
|
{
|
|
currentHero.SetEquippedEquipment(equipment);
|
|
}
|
|
equipmentOwnershipCacheReady = false;
|
|
RefreshAllIdolPanels(GetComponentInParent<UI_Idols>(true));
|
|
RefreshEquippedSlot();
|
|
RebuildBag();
|
|
}
|
|
|
|
private void UnequipEquipment()
|
|
{
|
|
equippedEquipment = null;
|
|
if (currentHero != null)
|
|
{
|
|
currentHero.ClearEquippedEquipment();
|
|
}
|
|
equipmentOwnershipCacheReady = false;
|
|
RefreshAllIdolPanels(GetComponentInParent<UI_Idols>(true));
|
|
RefreshEquippedSlot();
|
|
RebuildBag();
|
|
}
|
|
|
|
public void SetHero(AllyHero_SO hero)
|
|
{
|
|
currentHero = hero;
|
|
equipmentOwnershipCacheReady = false;
|
|
RestoreEquippedFromHero();
|
|
RefreshEquippedSlot();
|
|
RebuildBag();
|
|
}
|
|
|
|
public void RefreshCurrentHeroEquipmentState()
|
|
{
|
|
equipmentOwnershipCacheReady = false;
|
|
RestoreEquippedFromHero();
|
|
RefreshEquippedSlot();
|
|
RebuildBag();
|
|
}
|
|
|
|
private void RestoreEquippedFromHero()
|
|
{
|
|
if (currentHero == null)
|
|
{
|
|
equippedEquipment = null;
|
|
return;
|
|
}
|
|
|
|
currentHero.LoadEquippedEquipmentFromLocal();
|
|
equippedEquipment = currentHero.GetEquippedEquipmentResolved();
|
|
}
|
|
|
|
private void RefreshEquippedSlot()
|
|
{
|
|
if (equippedItemInstance != null)
|
|
{
|
|
Destroy(equippedItemInstance);
|
|
equippedItemInstance = null;
|
|
}
|
|
|
|
if (equippedEquipment != null && eqpmtItemPrefab != null && eqpmtToPut != null)
|
|
{
|
|
equippedItemInstance = Instantiate(eqpmtItemPrefab, eqpmtToPut);
|
|
equippedItemInstance.name = string.IsNullOrWhiteSpace(equippedEquipment.GetDisplayTierName()) ? equippedEquipment.name : equippedEquipment.GetDisplayTierName();
|
|
UI_OrderedEntryAnimator.PlayFadeOnly(equippedItemInstance, 0, 0.14f, 0f, true);
|
|
|
|
equipItemPrefab item = equippedItemInstance.GetComponent<equipItemPrefab>();
|
|
if (item != null)
|
|
{
|
|
item.Bind(equippedEquipment, null, HandleEquippedItemRightClicked);
|
|
item.allowDrag = false;
|
|
item.allowQuickTransfer = false;
|
|
if (item.itemButton != null)
|
|
{
|
|
item.itemButton.interactable = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
RefreshInfoPanel();
|
|
}
|
|
|
|
private void HandleEquipmentClicked(equipmentSO equipment)
|
|
{
|
|
if (equipment == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (this_eqpmtName != null)
|
|
{
|
|
this_eqpmtName.text = equipment.GetDisplayTierName();
|
|
this_eqpmtName.color = ResolveEquipmentColor(equipment.GetVisualQualityColorIndex());
|
|
}
|
|
|
|
if (this_eqpmtType != null)
|
|
{
|
|
this_eqpmtType.text = $"<b>{equipment.skillType}</b> 类装备";
|
|
}
|
|
|
|
if (this_eqpmtLevel != null)
|
|
{
|
|
this_eqpmtLevel.text = $"{equipment.level}追忆等阶";
|
|
}
|
|
|
|
if (this_eqpmtID != null)
|
|
{
|
|
this_eqpmtID.text = $"记忆编号{BuildDisplayEquipmentId(equipment)}";
|
|
}
|
|
}
|
|
|
|
private void RefreshInfoPanel()
|
|
{
|
|
if (equippedEquipment == null)
|
|
{
|
|
if (this_eqpmtName != null)
|
|
{
|
|
this_eqpmtName.text = "可装配一个记忆";
|
|
this_eqpmtName.color = new Color32(0x32, 0x32, 0x32, 0xFF);
|
|
}
|
|
if (this_eqpmtType != null) this_eqpmtType.text = "请选择记忆";
|
|
if (this_eqpmtLevel != null) this_eqpmtLevel.text = string.Empty;
|
|
if (this_eqpmtID != null) this_eqpmtID.text = "请选择记忆";
|
|
return;
|
|
}
|
|
|
|
HandleEquipmentClicked(equippedEquipment);
|
|
}
|
|
|
|
private bool IsEquippedByOtherHero(equipmentSO equipment, out AllyHero_SO occupiedHero)
|
|
{
|
|
occupiedHero = null;
|
|
if (equipment == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!equipmentOwnershipCacheReady)
|
|
{
|
|
RefreshEquipmentOwnershipCache();
|
|
}
|
|
|
|
if (ownershipByReference.TryGetValue(equipment, out occupiedHero) && occupiedHero != null)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(equipment.name) &&
|
|
ownershipByName.TryGetValue(equipment.name, out occupiedHero) &&
|
|
occupiedHero != null)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private AllyHero_SO[] LoadHeroAssetsForOwnershipCheck()
|
|
{
|
|
#if UNITY_EDITOR
|
|
if (!Application.isPlaying)
|
|
{
|
|
if (string.IsNullOrWhiteSpace("Assets/Resources/so/ally") || !AssetDatabase.IsValidFolder("Assets/Resources/so/ally"))
|
|
{
|
|
return Array.Empty<AllyHero_SO>();
|
|
}
|
|
|
|
string[] guids = AssetDatabase.FindAssets("t:AllyHero_SO", new[] { "Assets/Resources/so/ally" });
|
|
var result = new List<AllyHero_SO>(guids.Length);
|
|
for (int i = 0; i < guids.Length; i++)
|
|
{
|
|
string path = AssetDatabase.GUIDToAssetPath(guids[i]);
|
|
AllyHero_SO hero = AssetDatabase.LoadAssetAtPath<AllyHero_SO>(path);
|
|
if (hero != null)
|
|
{
|
|
result.Add(hero);
|
|
}
|
|
}
|
|
|
|
return result.ToArray();
|
|
}
|
|
#endif
|
|
|
|
return RuntimeResourcesCache.LoadAllAllyHeroes();
|
|
}
|
|
|
|
private Color ResolveEquipmentColor(int colorIndex)
|
|
{
|
|
if (eqpmtItemPrefab == null)
|
|
{
|
|
return Color.white;
|
|
}
|
|
|
|
equipItemPrefab prefab = eqpmtItemPrefab.GetComponent<equipItemPrefab>();
|
|
if (prefab == null)
|
|
{
|
|
return Color.white;
|
|
}
|
|
|
|
return prefab.GetAccentColorByVisualIndex(colorIndex);
|
|
}
|
|
|
|
private void RefreshEmptyState(int count)
|
|
{
|
|
if (emptyText != null)
|
|
{
|
|
emptyText.text = count > 0 ? string.Empty : "暂无装备";
|
|
}
|
|
}
|
|
|
|
private void RefreshAllIdolPanels(UI_Idols skipPanel = null)
|
|
{
|
|
UI_Idols[] panels = FindObjectsByType<UI_Idols>(FindObjectsInactive.Include, FindObjectsSortMode.None);
|
|
for (int i = 0; i < panels.Length; i++)
|
|
{
|
|
UI_Idols panel = panels[i];
|
|
if (panel != null && panel != skipPanel)
|
|
{
|
|
panel.RefreshCurrentHeroDetails();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ClearBagItems()
|
|
{
|
|
for (int i = spawnedBagItems.Count - 1; i >= 0; i--)
|
|
{
|
|
GameObject item = spawnedBagItems[i];
|
|
if (item != null && item.activeSelf)
|
|
{
|
|
item.SetActive(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CacheScrollbarValue()
|
|
{
|
|
if (eqpmtBagScrollbar == null)
|
|
{
|
|
pendingScrollbarValue = 1f;
|
|
return;
|
|
}
|
|
|
|
pendingScrollbarValue = eqpmtBagScrollbar.value;
|
|
}
|
|
|
|
private void BeginRestoreScrollbarValue()
|
|
{
|
|
if (!Application.isPlaying || !isActiveAndEnabled || !gameObject.activeInHierarchy)
|
|
{
|
|
RestoreScrollbarValueImmediate();
|
|
return;
|
|
}
|
|
|
|
if (restoreScrollbarRoutine != null)
|
|
{
|
|
StopCoroutine(restoreScrollbarRoutine);
|
|
}
|
|
|
|
restoreScrollbarRoutine = StartCoroutine(RestoreScrollbarValueNextFrame());
|
|
}
|
|
|
|
private IEnumerator RestoreScrollbarValueNextFrame()
|
|
{
|
|
yield return null;
|
|
Canvas.ForceUpdateCanvases();
|
|
yield return null;
|
|
Canvas.ForceUpdateCanvases();
|
|
RestoreScrollbarValueImmediate();
|
|
restoreScrollbarRoutine = null;
|
|
}
|
|
|
|
private void RestoreScrollbarValueImmediate()
|
|
{
|
|
if (eqpmtBagScrollbar == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ScrollRect scrollRect = eqpmtBagScrollbar.GetComponentInParent<ScrollRect>();
|
|
if (scrollRect != null && scrollRect.verticalScrollbar == eqpmtBagScrollbar)
|
|
{
|
|
scrollRect.verticalNormalizedPosition = pendingScrollbarValue;
|
|
}
|
|
|
|
eqpmtBagScrollbar.value = pendingScrollbarValue;
|
|
}
|
|
|
|
private bool MatchesCurrentFilters(equipmentSO equipment)
|
|
{
|
|
if (equipment == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (onlyCanEquip != null && onlyCanEquip.isOn && !IsEquipmentUsableByCurrentHero(equipment))
|
|
{
|
|
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 bool IsEquipmentUsableByCurrentHero(equipmentSO equipment)
|
|
{
|
|
if (equipment == null || currentHero == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (equipment.GetVisualTierPresentation() == null || string.IsNullOrWhiteSpace(equipment.GetDisplayTierName()))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return !IsEquippedByOtherHero(equipment, out _);
|
|
}
|
|
|
|
private void SortEquipments(List<equipmentSO> equipments)
|
|
{
|
|
if (equipments == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
EquipOrderMode mode = GetSelectedOrderMode();
|
|
switch (mode)
|
|
{
|
|
case EquipOrderMode.AcquireAsc:
|
|
equipments.Sort((a, b) => CompareAcquire(a, b, false));
|
|
break;
|
|
case EquipOrderMode.AcquireDesc:
|
|
equipments.Sort((a, b) => CompareAcquire(a, b, true));
|
|
break;
|
|
case EquipOrderMode.QualityAsc:
|
|
equipments.Sort((a, b) => CompareQuality(a, b, false));
|
|
break;
|
|
case EquipOrderMode.QualityDesc:
|
|
equipments.Sort((a, b) => CompareQuality(a, b, true));
|
|
break;
|
|
default:
|
|
equipments.Sort((a, b) => CompareAcquire(a, b, false));
|
|
break;
|
|
}
|
|
}
|
|
|
|
private EquipFilterMode GetSelectedFilterMode()
|
|
{
|
|
int index = typeFilter != null ? Mathf.Clamp(typeFilter.value, 0, FilterOptions.Length - 1) : 0;
|
|
return FilterOptions[index].mode;
|
|
}
|
|
|
|
private EquipOrderMode GetSelectedOrderMode()
|
|
{
|
|
int index = orderFilter != null ? Mathf.Clamp(orderFilter.value, 0, OrderOptions.Length - 1) : 0;
|
|
return OrderOptions[index].mode;
|
|
}
|
|
|
|
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(RuntimeResourcesCache.LoadAll<equipmentSO>(runtimeEquipmentFolder).Where(e => e != 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.ToArray();
|
|
}
|
|
|
|
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 != null ? left.GetDisplayTierName() : string.Empty;
|
|
string rightName = right != null ? right.GetDisplayTierName() : string.Empty;
|
|
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);
|
|
}
|
|
}
|
|
|
|
#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 static string BuildDisplayEquipmentId(equipmentSO equipment)
|
|
{
|
|
if (equipment == null || string.IsNullOrWhiteSpace(equipment.name))
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
string raw = equipment.name.Replace("(Clone)", string.Empty).Replace("(Preview)", string.Empty).Replace("(TourPreview)", string.Empty);
|
|
return raw.StartsWith("type", StringComparison.OrdinalIgnoreCase) && raw.Length > 4 ? raw.Substring(4) : raw;
|
|
}
|
|
|
|
private GameObject GetOrCreateBagItem(int index)
|
|
{
|
|
while (spawnedBagItems.Count <= index)
|
|
{
|
|
GameObject instance = Instantiate(eqpmtItemPrefab, eqpmtBagParent);
|
|
spawnedBagItems.Add(instance);
|
|
}
|
|
|
|
GameObject item = spawnedBagItems[index];
|
|
if (item != null)
|
|
{
|
|
item.transform.SetParent(eqpmtBagParent, false);
|
|
item.transform.SetSiblingIndex(index);
|
|
if (!item.activeSelf)
|
|
{
|
|
item.SetActive(true);
|
|
}
|
|
UI_OrderedEntryAnimator.PlaySingle(item, index, 0.16f, 0.012f, -10f, 0.97f, true);
|
|
}
|
|
|
|
return item;
|
|
}
|
|
|
|
private void RefreshEquipmentOwnershipCache()
|
|
{
|
|
ownershipByReference.Clear();
|
|
ownershipByName.Clear();
|
|
|
|
AllyHero_SO[] heroes = LoadHeroAssetsForOwnershipCheck();
|
|
for (int i = 0; i < heroes.Length; i++)
|
|
{
|
|
AllyHero_SO hero = heroes[i];
|
|
if (hero == null || hero == currentHero)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
hero.LoadEquippedEquipmentFromLocal();
|
|
equipmentSO equipped = hero.GetEquippedEquipmentResolved();
|
|
if (equipped == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
ownershipByReference[equipped] = hero;
|
|
if (!string.IsNullOrWhiteSpace(equipped.name))
|
|
{
|
|
ownershipByName[equipped.name] = hero;
|
|
}
|
|
}
|
|
|
|
equipmentOwnershipCacheReady = true;
|
|
}
|
|
}
|