723 lines
22 KiB
C#
723 lines
22 KiB
C#
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
using UnityEngine.EventSystems;
|
|
using System.Collections.Generic;
|
|
using System.Collections;
|
|
using System.IO;
|
|
using DG.Tweening;
|
|
|
|
public class dlcButton : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
|
|
{
|
|
private static readonly bool VerboseLogs = false;
|
|
[Header("Inspector")]
|
|
public Image dlc_profileImgae;
|
|
public Text dlcName;
|
|
public Text dlcID;
|
|
public Text dlcProducer;
|
|
public Text dlcPubliushDate;
|
|
public Text dlcSongsAmount;
|
|
public Image dlc_nowSelectedImageBoarder;
|
|
[Header("Inspector")]
|
|
public GameObject dlcDetailParent;
|
|
public Text dlcDescription;
|
|
|
|
[Header("Inspector")]
|
|
public dlcData dlcDataSO;
|
|
|
|
[Header("Inspector")]
|
|
public List<SongData> dlcContent = new List<SongData>();
|
|
|
|
[Header("Inspector")]
|
|
public string editorSearchFolder = "Assets/Resources/dlc_dlcIndex";
|
|
public string runtimeResourcesFolder = "Resources/dlc_dlcIndex";
|
|
|
|
private Button _btn;
|
|
public bool Resolved { get; private set; }
|
|
|
|
// Shared cache to avoid repeated Resources.LoadAll scans
|
|
private static Dictionary<int, dlcData> cachedById = new Dictionary<int, dlcData>();
|
|
private static List<dlcData> cachedAll = new List<dlcData>();
|
|
private static bool cacheBuilt = false;
|
|
private static bool cacheBuilding = false;
|
|
// Selection management (shared across all dlcButton instances)
|
|
private static List<dlcButton> allButtons = new List<dlcButton>();
|
|
private static int selectedIndex = -1;
|
|
private const string PlayerPrefsKey = "dlc_selected_index";
|
|
private const string SelectedDlcIdPrefsKey = "dlc_selected_id";
|
|
// When true, Select() applies visual selection but does NOT persist to
|
|
// PlayerPrefs. Used during restore so re-selecting (including fallback)
|
|
// never overwrites the user's genuine last choice.
|
|
public static bool SuppressSelectionPersist = false;
|
|
|
|
private int instanceIndex = -1;
|
|
private Coroutine hoverCoroutine;
|
|
|
|
private void UpdateSongsAmountText()
|
|
{
|
|
if (dlcSongsAmount != null)
|
|
{
|
|
dlcSongsAmount.text = dlcContent != null ? dlcContent.Count.ToString() : "0";
|
|
}
|
|
}
|
|
|
|
public static void ResetSelectionState()
|
|
{
|
|
allButtons.Clear();
|
|
selectedIndex = -1;
|
|
}
|
|
|
|
public void OnPointerEnter(PointerEventData eventData)
|
|
{
|
|
if (hoverCoroutine != null) StopCoroutine(hoverCoroutine);
|
|
hoverCoroutine = StartCoroutine(HandleHover());
|
|
}
|
|
|
|
public void OnPointerExit(PointerEventData eventData)
|
|
{
|
|
if (hoverCoroutine != null) StopCoroutine(hoverCoroutine);
|
|
HideDlcDetail();
|
|
}
|
|
|
|
public void SetDlcData(dlcData so)
|
|
{
|
|
dlcDataSO = so;
|
|
ApplyDlcData(so);
|
|
}
|
|
|
|
private IEnumerator HandleHover()
|
|
{
|
|
yield return new WaitForSecondsRealtime(0.5f);
|
|
|
|
// 灏濊瘯浠庡満鏅腑鏌ユ壘 dlcDetailParent (濡傛灉鑷韩寮曠敤鐨勪负绌?
|
|
if (dlcDetailParent == null)
|
|
{
|
|
var details = GameObject.FindObjectsByType<dlcButton>(FindObjectsInactive.Include, FindObjectsSortMode.None);
|
|
foreach (var b in details)
|
|
{
|
|
if (b != this && b.dlcDetailParent != null)
|
|
{
|
|
dlcDetailParent = b.dlcDetailParent;
|
|
dlcDescription = b.dlcDescription;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (dlcDetailParent != null)
|
|
{
|
|
dlcDetailParent.SetActive(true);
|
|
UI_OrderedEntryAnimator.PlayFadeOnly(dlcDetailParent, 0, 0.12f, 0f, true);
|
|
// 鏇存柊绠€浠嬩俊鎭?
|
|
if (dlcDescription != null)
|
|
{
|
|
if (dlcDataSO != null)
|
|
{
|
|
dlcDescription.text = string.IsNullOrEmpty(dlcDataSO.dlcDescription)
|
|
? LocalizationService.Get("dlc.no_description", "暂无DLC简介信息。")
|
|
: dlcDataSO.dlcDescription;
|
|
}
|
|
else
|
|
{
|
|
dlcDescription.text = LocalizationService.Get("dlc.no_description", "暂无DLC简介信息。");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void HideDlcDetail()
|
|
{
|
|
if (dlcDetailParent == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
CanvasGroup group = dlcDetailParent.GetComponent<CanvasGroup>();
|
|
if (group == null)
|
|
{
|
|
group = dlcDetailParent.AddComponent<CanvasGroup>();
|
|
}
|
|
|
|
group.DOKill();
|
|
group.DOFade(0f, 0.1f)
|
|
.SetEase(Ease.OutQuad)
|
|
.SetUpdate(true)
|
|
.SetTarget(dlcDetailParent)
|
|
.OnComplete(() =>
|
|
{
|
|
if (dlcDetailParent != null)
|
|
{
|
|
dlcDetailParent.SetActive(false);
|
|
group.alpha = 1f;
|
|
}
|
|
});
|
|
}
|
|
|
|
void Awake()
|
|
{
|
|
_btn = GetComponent<Button>();
|
|
if (_btn != null)
|
|
{
|
|
_btn.onClick.RemoveAllListeners();
|
|
_btn.onClick.AddListener(OnButtonClicked_ShowSongs);
|
|
}
|
|
|
|
// ensure border initial state
|
|
if (dlc_nowSelectedImageBoarder != null)
|
|
{
|
|
if (!dlc_nowSelectedImageBoarder.gameObject.activeSelf)
|
|
{
|
|
dlc_nowSelectedImageBoarder.gameObject.SetActive(true);
|
|
}
|
|
var c = dlc_nowSelectedImageBoarder.color;
|
|
c.a = 0f;
|
|
dlc_nowSelectedImageBoarder.color = c;
|
|
}
|
|
|
|
// register this button for centralized selection handling
|
|
RegisterInstance();
|
|
|
|
if (VerboseLogs) Debug.Log($"dlcButton.Awake: registered '{gameObject.name}' as index {instanceIndex}");
|
|
}
|
|
|
|
private void RegisterInstance()
|
|
{
|
|
if (!allButtons.Contains(this))
|
|
{
|
|
instanceIndex = allButtons.Count;
|
|
allButtons.Add(this);
|
|
|
|
// If no selectedIndex loaded yet, load from PlayerPrefs default 0
|
|
if (selectedIndex == -1)
|
|
{
|
|
selectedIndex = PlayerPrefs.GetInt(PlayerPrefsKey, 0);
|
|
}
|
|
|
|
// If this instance matches the persisted selection, apply selection
|
|
if (instanceIndex == selectedIndex)
|
|
{
|
|
// ensure other buttons are deselected
|
|
ApplySelectionToAll(instanceIndex);
|
|
}
|
|
else
|
|
{
|
|
// ensure unselected visual
|
|
SetSelectedVisual(false, immediate: true);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
instanceIndex = allButtons.IndexOf(this);
|
|
}
|
|
}
|
|
|
|
private void UnregisterInstance()
|
|
{
|
|
int idx = allButtons.IndexOf(this);
|
|
if (idx >= 0)
|
|
{
|
|
allButtons.Remove(this);
|
|
if (selectedIndex == idx)
|
|
{
|
|
selectedIndex = -1;
|
|
}
|
|
else if (selectedIndex > idx)
|
|
{
|
|
selectedIndex--;
|
|
}
|
|
}
|
|
}
|
|
|
|
void OnDestroy()
|
|
{
|
|
UnregisterInstance();
|
|
}
|
|
|
|
// Ensure only one button is selected and persist the index
|
|
public void Select()
|
|
{
|
|
ApplySelectionToAll(instanceIndex);
|
|
selectedIndex = instanceIndex;
|
|
if (SuppressSelectionPersist)
|
|
{
|
|
if (VerboseLogs) Debug.Log($"dlcButton.Select: '{gameObject.name}' selected (index {instanceIndex}) without persisting (restore in progress)");
|
|
return;
|
|
}
|
|
PlayerPrefs.SetInt(PlayerPrefsKey, selectedIndex);
|
|
int dlcId = ResolveOwnDlcId();
|
|
if (dlcId > 0)
|
|
{
|
|
PlayerPrefs.SetInt(SelectedDlcIdPrefsKey, dlcId);
|
|
}
|
|
PlayerPrefs.Save();
|
|
if (VerboseLogs) Debug.Log($"dlcButton.Select: '{gameObject.name}' selected (index {instanceIndex}) and saved to PlayerPrefs");
|
|
}
|
|
|
|
public static string SelectedDlcIdKey => SelectedDlcIdPrefsKey;
|
|
|
|
public int ResolveOwnDlcId()
|
|
{
|
|
if (dlcDataSO != null && dlcDataSO.dlcID > 0)
|
|
{
|
|
return dlcDataSO.dlcID;
|
|
}
|
|
|
|
if (dlcID != null && int.TryParse(dlcID.text, out int parsedId))
|
|
{
|
|
return parsedId;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
private static void ApplySelectionToAll(int selectIdx)
|
|
{
|
|
for (int i = 0; i < allButtons.Count; i++)
|
|
{
|
|
var btn = allButtons[i];
|
|
if (btn == null) continue;
|
|
bool shouldSelect = (i == selectIdx);
|
|
btn.SetSelectedVisual(shouldSelect);
|
|
}
|
|
}
|
|
|
|
// fades the border in or out; if immediate, set without coroutine
|
|
private Coroutine borderFadeCoroutine = null;
|
|
private Coroutine showSongsRetryCoroutine = null;
|
|
private void SetSelectedVisual(bool selected, bool immediate = false)
|
|
{
|
|
if (dlc_nowSelectedImageBoarder == null) return;
|
|
|
|
if (borderFadeCoroutine != null)
|
|
{
|
|
StopCoroutine(borderFadeCoroutine);
|
|
borderFadeCoroutine = null;
|
|
}
|
|
|
|
if (immediate)
|
|
{
|
|
if (!dlc_nowSelectedImageBoarder.gameObject.activeSelf)
|
|
{
|
|
dlc_nowSelectedImageBoarder.gameObject.SetActive(true);
|
|
}
|
|
var c = dlc_nowSelectedImageBoarder.color;
|
|
c.a = selected ? 1f : 0f;
|
|
dlc_nowSelectedImageBoarder.color = c;
|
|
}
|
|
else
|
|
{
|
|
dlc_nowSelectedImageBoarder.gameObject.SetActive(true);
|
|
borderFadeCoroutine = StartCoroutine(FadeBorder(dlc_nowSelectedImageBoarder, selected ? 1f : 0f, 0.25f));
|
|
}
|
|
}
|
|
|
|
private IEnumerator<YieldInstruction> FadeBorder(Image img, float targetAlpha, float duration)
|
|
{
|
|
if (img == null) yield break;
|
|
float startAlpha = img.color.a;
|
|
float t = 0f;
|
|
// if fading out, ensure we start from current alpha
|
|
while (t < duration)
|
|
{
|
|
t += Time.unscaledDeltaTime;
|
|
float a = Mathf.Lerp(startAlpha, targetAlpha, Mathf.Clamp01(t / duration));
|
|
var c = img.color;
|
|
c.a = a;
|
|
img.color = c;
|
|
yield return null;
|
|
}
|
|
var final = img.color;
|
|
final.a = targetAlpha;
|
|
img.color = final;
|
|
borderFadeCoroutine = null;
|
|
}
|
|
|
|
void Start()
|
|
{
|
|
// Do not auto-resolve here anymore. Resolution will be triggered externally after instantiation of all buttons.
|
|
}
|
|
|
|
public void OnButtonClicked_ShowSongs()
|
|
{
|
|
// set current DLC key for SongSelectUI to allow per-DLC song selection restore
|
|
string dlcKey = null;
|
|
if (dlcDataSO != null)
|
|
{
|
|
dlcKey = "dlc_" + dlcDataSO.dlcID;
|
|
}
|
|
else if (dlcID != null && int.TryParse(dlcID.text, out int parsedId))
|
|
{
|
|
dlcKey = "dlc_" + parsedId;
|
|
}
|
|
else
|
|
{
|
|
dlcKey = "dlc_instance_" + instanceIndex;
|
|
}
|
|
|
|
// assign to SongSelectUI static key
|
|
try { SongSelectUI.CurrentDlcKey = dlcKey; } catch { }
|
|
|
|
// mark selection first
|
|
Select();
|
|
|
|
if (TryDisplaySongsNow())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (showSongsRetryCoroutine != null)
|
|
{
|
|
StopCoroutine(showSongsRetryCoroutine);
|
|
}
|
|
showSongsRetryCoroutine = StartCoroutine(RetryDisplaySongsWhenUIReady());
|
|
}
|
|
|
|
private SongSelectUI FindSongSelectUI()
|
|
{
|
|
var ui = SceneObjectLookupCache.FindAny<SongSelectUI>();
|
|
if (ui != null)
|
|
{
|
|
return ui;
|
|
}
|
|
|
|
var all = Object.FindObjectsByType<SongSelectUI>(FindObjectsInactive.Include, FindObjectsSortMode.None);
|
|
if (all != null && all.Length > 0)
|
|
{
|
|
return all[0];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private bool TryDisplaySongsNow()
|
|
{
|
|
var ui = FindSongSelectUI();
|
|
if (ui == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (SongSelectUI.ForceFirstSongOnNextRestore)
|
|
{
|
|
SongDataHolder.SelectedSongData = null;
|
|
}
|
|
|
|
ui.DisplaySongsFromList(GetAccessibleDlcContent());
|
|
return true;
|
|
}
|
|
|
|
private List<SongData> GetAccessibleDlcContent()
|
|
{
|
|
List<SongData> accessible = new List<SongData>();
|
|
if (dlcContent == null)
|
|
{
|
|
return accessible;
|
|
}
|
|
|
|
for (int i = 0; i < dlcContent.Count; i++)
|
|
{
|
|
SongData song = dlcContent[i];
|
|
if (song != null && DlcContentAccess.IsSongAccessible(song))
|
|
{
|
|
accessible.Add(song);
|
|
}
|
|
}
|
|
|
|
return accessible;
|
|
}
|
|
|
|
private IEnumerator RetryDisplaySongsWhenUIReady()
|
|
{
|
|
const int maxRetryFrames = 8;
|
|
for (int i = 0; i < maxRetryFrames; i++)
|
|
{
|
|
yield return null;
|
|
if (TryDisplaySongsNow())
|
|
{
|
|
showSongsRetryCoroutine = null;
|
|
yield break;
|
|
}
|
|
}
|
|
|
|
showSongsRetryCoroutine = null;
|
|
Debug.LogWarning("dlcButton: SongSelectUI not found in scene to display songs");
|
|
}
|
|
|
|
// Try to find a dlcData SO by id and apply its songList to dlcContent
|
|
public void LoadDlcDataById(int id)
|
|
{
|
|
if (VerboseLogs) Debug.Log($"dlcButton.LoadDlcDataById: searching for id={id} (editorFolder='{editorSearchFolder}', runtimeFolder='{runtimeResourcesFolder}') on '{gameObject.name}'");
|
|
#if UNITY_EDITOR
|
|
// Editor search: search recursively for asset files under editorSearchFolder
|
|
if (!string.IsNullOrEmpty(editorSearchFolder) && Directory.Exists(editorSearchFolder))
|
|
{
|
|
try
|
|
{
|
|
var files = Directory.GetFiles(editorSearchFolder, "*.asset", SearchOption.AllDirectories);
|
|
if (VerboseLogs) Debug.Log($"dlcButton.LoadDlcDataById: found {files.Length} asset files under {editorSearchFolder}");
|
|
foreach (var path in files)
|
|
{
|
|
string fileName = Path.GetFileNameWithoutExtension(path);
|
|
if (fileName.StartsWith(id.ToString()))
|
|
{
|
|
string assetPath = path.Replace("\\", "/");
|
|
if (VerboseLogs) Debug.Log($"dlcButton.LoadDlcDataById: candidate assetPath={assetPath}");
|
|
var so = UnityEditor.AssetDatabase.LoadAssetAtPath<dlcData>(assetPath);
|
|
if (so != null)
|
|
{
|
|
if (VerboseLogs) Debug.Log($"dlcButton.LoadDlcDataById: loaded dlcData SO '{so.name}' for id={id}");
|
|
dlcDataSO = so;
|
|
ApplyDlcData(so);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (System.Exception e)
|
|
{
|
|
Debug.LogWarning("dlcButton LoadDlcDataById (Editor) failed: " + e.Message);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (VerboseLogs) Debug.Log($"dlcButton.LoadDlcDataById: editorSearchFolder '{editorSearchFolder}' does not exist or not set");
|
|
}
|
|
#endif
|
|
// Runtime: search Resources (load all dlcData then filter by name prefix)
|
|
try
|
|
{
|
|
var all = RuntimeResourcesCache.LoadAllDlcs();
|
|
if (VerboseLogs) Debug.Log($"dlcButton.LoadDlcDataById: runtime cache returned {(all != null ? all.Length : 0)} items");
|
|
if (all != null)
|
|
{
|
|
foreach (var so in all)
|
|
{
|
|
if (so == null) continue;
|
|
if (so.dlcID == id || so.name.StartsWith(id.ToString()))
|
|
{
|
|
if (VerboseLogs) Debug.Log($"dlcButton.LoadDlcDataById: found runtime dlcData '{so.name}' for id={id}");
|
|
dlcDataSO = so;
|
|
ApplyDlcData(so);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (System.Exception e)
|
|
{
|
|
Debug.LogWarning($"dlcButton.LoadDlcDataById: runtime cache search failed: {e.Message}");
|
|
}
|
|
|
|
// if no dlcData found, keep dlcContent empty but attempt old behavior: search SongData by id prefix
|
|
if (VerboseLogs) Debug.Log($"dlcButton.LoadDlcDataById: no dlcData found for id={id}, falling back to song prefix search");
|
|
LoadContentBySongIdPrefix(id);
|
|
}
|
|
|
|
// Populate dlcContent from dlcData SO and update UI texts/images
|
|
private void ApplyDlcData(dlcData so)
|
|
{
|
|
if (so == null) return;
|
|
dlcContent = new List<SongData>();
|
|
if (so.songList != null)
|
|
{
|
|
foreach (var s in so.songList)
|
|
if (s != null) dlcContent.Add(s);
|
|
}
|
|
|
|
UpdateSongsAmountText();
|
|
|
|
if (dlcName != null) dlcName.text = so.dlcName ?? dlcName.text;
|
|
if (dlcProducer != null) dlcProducer.text = so.dlcProducer ?? dlcProducer.text;
|
|
if (dlcDescription != null) dlcDescription.text = so.dlcDescription ?? dlcDescription.text;
|
|
if (dlcPubliushDate != null) dlcPubliushDate.text = so.dlcPublishDate ?? dlcPubliushDate.text;
|
|
if (dlc_profileImgae != null)
|
|
{
|
|
dlc_profileImgae.sprite = so.dlc_image;
|
|
dlc_profileImgae.enabled = so.dlc_image != null;
|
|
}
|
|
|
|
if (VerboseLogs) Debug.Log($"dlcButton.ApplyDlcData: applied dlcData '{so.name}' with {dlcContent.Count} songs to button '{gameObject.name}'");
|
|
}
|
|
|
|
// Legacy: if no dlcData SO, search SongData assets by id prefix and fill dlcContent
|
|
public void LoadContentBySongIdPrefix(int id)
|
|
{
|
|
dlcContent.Clear();
|
|
#if UNITY_EDITOR
|
|
if (!string.IsNullOrEmpty(editorSearchFolder) && Directory.Exists(editorSearchFolder))
|
|
{
|
|
try
|
|
{
|
|
var files = Directory.GetFiles(editorSearchFolder, "*.asset", SearchOption.AllDirectories);
|
|
foreach (var path in files)
|
|
{
|
|
var fileName = Path.GetFileNameWithoutExtension(path);
|
|
if (fileName.StartsWith(id.ToString()))
|
|
{
|
|
var assetPath = path.Replace("\\", "/");
|
|
var so = UnityEditor.AssetDatabase.LoadAssetAtPath<SongData>(assetPath);
|
|
if (so != null) dlcContent.Add(so);
|
|
}
|
|
}
|
|
}
|
|
catch (System.Exception e)
|
|
{
|
|
Debug.LogWarning("dlcButton LoadContentBySongIdPrefix (Editor) failed: " + e.Message);
|
|
}
|
|
}
|
|
#endif
|
|
SongData[] allSongs = RuntimeResourcesCache.LoadAllSongs();
|
|
if (allSongs != null)
|
|
{
|
|
foreach (var so in allSongs)
|
|
{
|
|
if (so == null) continue;
|
|
if (so.name.StartsWith(id.ToString())) dlcContent.Add(so);
|
|
}
|
|
}
|
|
|
|
UpdateSongsAmountText();
|
|
|
|
if (VerboseLogs) Debug.Log($"dlcButton: Loaded {dlcContent.Count} SongData entries for DLC id={id} (fallback search)");
|
|
}
|
|
|
|
// Resolve dlcData after all buttons have been instantiated
|
|
public void ResolveDlcData()
|
|
{
|
|
if (Resolved)
|
|
{
|
|
return;
|
|
}
|
|
StartCoroutine(ResolveDlcDataAsync());
|
|
}
|
|
|
|
public IEnumerator ResolveDlcDataAsync()
|
|
{
|
|
if (Resolved)
|
|
{
|
|
yield break;
|
|
}
|
|
|
|
if (VerboseLogs) Debug.Log($"dlcButton.ResolveDlcData called on '{gameObject.name}'");
|
|
|
|
if (dlcDataSO != null)
|
|
{
|
|
if (VerboseLogs) Debug.Log($"dlcButton: dlcDataSO already assigned on '{gameObject.name}' -> {dlcDataSO.name}");
|
|
ApplyDlcData(dlcDataSO);
|
|
Resolved = true;
|
|
yield break;
|
|
}
|
|
|
|
int id;
|
|
if (!TryGetResolveId(out id))
|
|
{
|
|
Debug.LogWarning($"dlcButton.ResolveDlcData: no dlcID text and no name to parse for '{gameObject.name}'");
|
|
Resolved = true;
|
|
yield break;
|
|
}
|
|
|
|
yield return BuildCacheIfNeeded(runtimeResourcesFolder);
|
|
|
|
if (TryResolveFromCache(id))
|
|
{
|
|
Resolved = true;
|
|
yield break;
|
|
}
|
|
|
|
LoadContentBySongIdPrefix(id);
|
|
Resolved = true;
|
|
}
|
|
|
|
private bool TryGetResolveId(out int id)
|
|
{
|
|
id = 0;
|
|
if (dlcID != null && int.TryParse(dlcID.text, out id))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
string goName = gameObject.name;
|
|
if (!string.IsNullOrEmpty(goName))
|
|
{
|
|
var parts = goName.Split('_');
|
|
if (parts.Length > 0 && int.TryParse(parts[0], out id))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private bool TryResolveFromCache(int id)
|
|
{
|
|
if (!cacheBuilt)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
dlcData so;
|
|
if (cachedById.TryGetValue(id, out so) && so != null)
|
|
{
|
|
dlcDataSO = so;
|
|
ApplyDlcData(so);
|
|
return true;
|
|
}
|
|
|
|
string prefix = id.ToString();
|
|
for (int i = 0; i < cachedAll.Count; i++)
|
|
{
|
|
var item = cachedAll[i];
|
|
if (item == null) continue;
|
|
if (item.name.StartsWith(prefix))
|
|
{
|
|
dlcDataSO = item;
|
|
ApplyDlcData(item);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private static IEnumerator BuildCacheIfNeeded(string runtimeFolder)
|
|
{
|
|
if (cacheBuilt)
|
|
{
|
|
yield break;
|
|
}
|
|
if (cacheBuilding)
|
|
{
|
|
while (!cacheBuilt)
|
|
{
|
|
yield return null;
|
|
}
|
|
yield break;
|
|
}
|
|
|
|
cacheBuilding = true;
|
|
cachedById.Clear();
|
|
cachedAll.Clear();
|
|
|
|
// allow one frame before heavy load
|
|
yield return null;
|
|
|
|
dlcData[] arr = RuntimeResourcesCache.LoadAllDlcs();
|
|
|
|
if (arr != null)
|
|
{
|
|
for (int i = 0; i < arr.Length; i++)
|
|
{
|
|
var so = arr[i];
|
|
if (so == null) continue;
|
|
cachedAll.Add(so);
|
|
if (!cachedById.ContainsKey(so.dlcID))
|
|
{
|
|
cachedById.Add(so.dlcID, so);
|
|
}
|
|
}
|
|
}
|
|
|
|
cacheBuilt = true;
|
|
cacheBuilding = false;
|
|
}
|
|
}
|