Files
bansonic_beta_main/Assets/songsDatabase/loadDlcListPrefab.cs
T

352 lines
11 KiB
C#

using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.Collections.Generic;
public class loadDlcListPrefab : MonoBehaviour
{
private static readonly bool VerboseLogs = false;
private const string RuntimeInstalledColumnName = "Installed DLC";
private const int DefaultFallbackDlcId = 66002;
private const string DlcSelectedIndexPrefsKey = "dlc_selected_index";
[System.Serializable]
public class Column
{
public string columnName;
public List<dlcData> dlcList = new List<dlcData>();
}
[Header("Inspector")]
public List<Column> columns = new List<Column>();
[Header("Runtime DLC")]
[SerializeField] bool includeRuntimeInstalledDlcs = true;
[SerializeField] string runtimeInstalledColumnName = RuntimeInstalledColumnName;
[Header("Inspector")]
public GameObject dlc_scContent;
public GameObject columnPrefab;
public GameObject dlcButtonPrefab;
void Start()
{
RefreshUI();
}
public void RefreshUI()
{
if (dlc_scContent == null) return;
dlcButton.ResetSelectionState();
for (int i = dlc_scContent.transform.childCount - 1; i >= 0; i--)
{
var c = dlc_scContent.transform.GetChild(i).gameObject;
#if UNITY_EDITOR
if (!Application.isPlaying) DestroyImmediate(c);
else Destroy(c);
#else
Destroy(c);
#endif
}
List<Column> displayColumns = BuildDisplayColumns();
if (displayColumns == null) return;
for (int colIndex = 0; colIndex < displayColumns.Count; colIndex++)
{
var col = displayColumns[colIndex];
if (columnPrefab != null)
{
var headerGO = Instantiate(columnPrefab, dlc_scContent.transform);
headerGO.name = "Column_" + colIndex;
var card = headerGO.GetComponent<columnCardPrefab>();
if (card != null && card.columnNameText != null)
{
card.columnNameText.text = col.columnName ?? "(Unnamed)";
}
else
{
var txt = headerGO.transform.Find("ColumnNameText")?.GetComponent<Text>();
if (txt != null) txt.text = col.columnName ?? "(Unnamed)";
}
}
if (col.dlcList == null) continue;
for (int entryIndex = 0; entryIndex < col.dlcList.Count; entryIndex++)
{
var dlc = col.dlcList[entryIndex];
if (dlcButtonPrefab == null)
{
Debug.LogWarning("dlcButtonPrefab is not assigned");
break;
}
var itemGO = Instantiate(dlcButtonPrefab, dlc_scContent.transform);
itemGO.name = $"DLC_Col{colIndex}_Item{entryIndex}";
var btn = itemGO.GetComponent<dlcButton>();
if (btn != null)
{
if (dlc != null)
{
btn.SetDlcData(dlc);
}
else
{
if (btn.dlcName != null) btn.dlcName.text = "(None)";
if (btn.dlcID != null) btn.dlcID.text = "";
if (btn.dlc_profileImgae != null) btn.dlc_profileImgae.enabled = false;
if (btn.dlcDescription != null) btn.dlcDescription.text = "";
if (btn.dlcSongsAmount != null) btn.dlcSongsAmount.text = "0";
}
}
}
}
var rt = dlc_scContent.GetComponent<RectTransform>();
if (rt != null) UnityEngine.UI.LayoutRebuilder.ForceRebuildLayoutImmediate(rt);
var allButtons = dlc_scContent.GetComponentsInChildren<dlcButton>(true);
StartCoroutine(ResolveAndRestore(allButtons));
}
private IEnumerator ResolveAndRestore(dlcButton[] allButtons)
{
if (allButtons != null)
{
for (int i = 0; i < allButtons.Length; i++)
{
var b = allButtons[i];
if (b != null)
{
yield return b.ResolveDlcDataAsync();
}
}
}
// Let layout and any fades settle for a frame
yield return null;
if (allButtons == null || allButtons.Length == 0)
{
if (VerboseLogs) Debug.LogWarning("loadDlcListPrefab: no dlc buttons found after RefreshUI");
yield break;
}
dlcButton targetButton = ResolvePreferredRestoreButton(allButtons, out bool forceFirstSong);
if (targetButton == null)
{
targetButton = allButtons[0];
forceFirstSong = true;
}
SongSelectUI.ForceFirstSongOnNextRestore = forceFirstSong;
// Restore is read-only: applying the selection here (including the
// fallback DLC) must not overwrite the user's genuine last choice.
// Select() runs synchronously inside OnButtonClicked_ShowSongs, so the
// suppression window only needs to span this call.
dlcButton.SuppressSelectionPersist = true;
try
{
targetButton.OnButtonClicked_ShowSongs();
}
finally
{
dlcButton.SuppressSelectionPersist = false;
}
if (VerboseLogs)
{
Debug.Log(
$"loadDlcListPrefab: restored dlc button '{targetButton.gameObject.name}', " +
$"dlcId={GetDlcId(targetButton)}, forceFirstSong={forceFirstSong}");
}
}
private dlcButton ResolvePreferredRestoreButton(dlcButton[] allButtons, out bool forceFirstSong)
{
forceFirstSong = true;
if (allButtons == null || allButtons.Length == 0)
{
return null;
}
// Prefer restoring by the saved DLC id, which is stable across
// session-to-session ordering changes (e.g. runtime-installed DLCs).
int savedDlcId = PlayerPrefs.GetInt(dlcButton.SelectedDlcIdKey, 0);
if (savedDlcId > 0)
{
dlcButton savedById = FindButtonByDlcId(allButtons, savedDlcId);
if (savedById != null && HasSavedSongSelection(savedById))
{
forceFirstSong = false;
return savedById;
}
}
// Fall back to the saved positional index for legacy saves.
int savedIndex = PlayerPrefs.GetInt(DlcSelectedIndexPrefsKey, 0);
if (savedIndex >= 0 && savedIndex < allButtons.Length)
{
dlcButton savedButton = allButtons[savedIndex];
if (HasSavedSongSelection(savedButton))
{
forceFirstSong = false;
return savedButton;
}
}
dlcButton fallbackById = FindButtonByDlcId(allButtons, DefaultFallbackDlcId);
if (fallbackById != null)
{
return fallbackById;
}
return allButtons[0];
}
private dlcButton FindButtonByDlcId(dlcButton[] allButtons, int dlcId)
{
if (allButtons == null)
{
return null;
}
for (int i = 0; i < allButtons.Length; i++)
{
dlcButton button = allButtons[i];
if (button == null)
{
continue;
}
if (GetDlcId(button) == dlcId)
{
return button;
}
}
return null;
}
private bool HasSavedSongSelection(dlcButton button)
{
if (button == null)
{
return false;
}
string dlcKey = BuildDlcKey(button);
if (string.IsNullOrEmpty(dlcKey))
{
return false;
}
// Only the songID key proves a genuine user click: SongButton.OnSongButtonClick
// always writes it alongside the index. The index key alone is unreliable because
// RestoreSelectedSongForCurrentDlc auto-writes it to 0 on mere display, so relying
// on it would treat any browsed-but-not-selected DLC as "user selected".
string songIdKey = SongButton.BuildSongSelectedIdPrefsKey(dlcKey);
return PlayerPrefs.HasKey(songIdKey) && PlayerPrefs.GetInt(songIdKey, 0) > 0;
}
private string BuildDlcKey(dlcButton button)
{
int dlcId = GetDlcId(button);
if (dlcId > 0)
{
return "dlc_" + dlcId;
}
return null;
}
private int GetDlcId(dlcButton button)
{
// Delegate to the button's own resolver to keep id resolution in one place.
return button != null ? button.ResolveOwnDlcId() : 0;
}
private List<Column> BuildDisplayColumns()
{
List<Column> result = new List<Column>();
HashSet<dlcData> knownDlcs = new HashSet<dlcData>();
if (columns != null)
{
for (int i = 0; i < columns.Count; i++)
{
Column source = columns[i];
if (source == null)
{
continue;
}
Column copy = new Column
{
columnName = source.columnName,
dlcList = new List<dlcData>()
};
if (source.dlcList != null)
{
for (int j = 0; j < source.dlcList.Count; j++)
{
dlcData item = source.dlcList[j];
if (item == null)
{
continue;
}
copy.dlcList.Add(item);
knownDlcs.Add(item);
}
}
result.Add(copy);
}
}
if (!includeRuntimeInstalledDlcs)
{
return result;
}
dlcData[] runtimeDlcs = DlcRuntimeRegistry.GetAllDlcs();
if (runtimeDlcs == null || runtimeDlcs.Length == 0)
{
return result;
}
Column runtimeColumn = new Column
{
columnName = string.IsNullOrWhiteSpace(runtimeInstalledColumnName) ? RuntimeInstalledColumnName : runtimeInstalledColumnName,
dlcList = new List<dlcData>()
};
for (int i = 0; i < runtimeDlcs.Length; i++)
{
dlcData dlc = runtimeDlcs[i];
if (dlc == null || knownDlcs.Contains(dlc))
{
continue;
}
runtimeColumn.dlcList.Add(dlc);
}
if (runtimeColumn.dlcList.Count > 0)
{
result.Add(runtimeColumn);
}
return result;
}
}