Files
bansonic_beta_main/Assets/songsDatabase/dlcData/dlcButton.cs
T

429 lines
15 KiB
C#

using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
using System.IO;
public class dlcButton : MonoBehaviour
{
[Header("基本套件")]
public Image dlc_profileImgae;
public Text dlcName;
public Text dlcID;
public Text dlcProducer;
public Text dlcPubliushDate;
public Image dlc_nowSelectedImageBoarder;
[Header("介绍")]
public Text dlcDescription;
[Header("DLC SO (可在 Inspector 指定)")]
public dlcData dlcDataSO;
[Header("DLC 内容 (运行时会由脚本填充)")]
public List<SongData> dlcContent = new List<SongData>();
[Header("搜索路径 (编辑器/运行时)")]
public string editorSearchFolder = "Assets/Resources/dlc_dlcIndex";
public string runtimeResourcesFolder = "Resources/dlc_dlcIndex";
private Button _btn;
// 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";
// instance index in registration order
private int instanceIndex = -1;
void Awake()
{
_btn = GetComponent<Button>();
if (_btn != null)
{
_btn.onClick.RemoveAllListeners();
_btn.onClick.AddListener(OnButtonClicked_ShowSongs);
}
// register this button for centralized selection handling
RegisterInstance();
// ensure border initial state
if (dlc_nowSelectedImageBoarder != null)
{
var c = dlc_nowSelectedImageBoarder.color;
c.a = 0f;
dlc_nowSelectedImageBoarder.color = c;
dlc_nowSelectedImageBoarder.gameObject.SetActive(false);
}
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);
}
}
}
private void UnregisterInstance()
{
if (allButtons.Contains(this))
{
int idx = allButtons.IndexOf(this);
allButtons.Remove(this);
// if removed index was before selectedIndex, adjust saved index
if (idx >= 0 && idx < instanceIndex)
{
// nothing: instanceIndex only used at registration time
}
}
}
void OnDestroy()
{
UnregisterInstance();
}
// Ensure only one button is selected and persist the index
public void Select()
{
ApplySelectionToAll(instanceIndex);
selectedIndex = instanceIndex;
PlayerPrefs.SetInt(PlayerPrefsKey, selectedIndex);
PlayerPrefs.Save();
Debug.Log($"dlcButton.Select: '{gameObject.name}' selected (index {instanceIndex}) and saved to PlayerPrefs");
}
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 void SetSelectedVisual(bool selected, bool immediate = false)
{
if (dlc_nowSelectedImageBoarder == null) return;
if (borderFadeCoroutine != null)
{
StopCoroutine(borderFadeCoroutine);
borderFadeCoroutine = null;
}
if (immediate)
{
dlc_nowSelectedImageBoarder.gameObject.SetActive(selected);
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;
if (Mathf.Approximately(targetAlpha, 0f))
{
img.gameObject.SetActive(false);
}
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();
var s = GameObject.FindObjectOfType<SongSelectUI>();
if (s != null)
{
s.DisplaySongsFromList(dlcContent);
}
else
{
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)
{
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);
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("\\", "/");
Debug.Log($"dlcButton.LoadDlcDataById: candidate assetPath={assetPath}");
var so = UnityEditor.AssetDatabase.LoadAssetAtPath<dlcData>(assetPath);
if (so != null)
{
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
{
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 arr = Resources.LoadAll<dlcData>(runtimeResourcesFolder);
Debug.Log($"dlcButton.LoadDlcDataById: Resources.LoadAll('{runtimeResourcesFolder}') returned {(arr != null ? arr.Length : 0)} items");
if (arr != null)
{
foreach (var so in arr)
{
if (so == null) continue;
if (so.name.StartsWith(id.ToString()))
{
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: Resources search failed: {e.Message}");
}
// fallback: search all Resources
var all = Resources.LoadAll<dlcData>("");
Debug.Log("dlcButton.LoadDlcDataById: Resources.LoadAll(\"\") returned " + (all != null ? all.Length : 0) + " items");
if (all != null)
{
foreach (var so in all)
{
if (so == null) continue;
if (so.name.StartsWith(id.ToString()))
{
Debug.Log($"dlcButton.LoadDlcDataById: found fallback dlcData '{so.name}' for id={id}");
dlcDataSO = so;
ApplyDlcData(so);
return;
}
}
}
// if no dlcData found, keep dlcContent empty but attempt old behavior: search SongData by id prefix
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);
}
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;
}
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
if (!string.IsNullOrEmpty(runtimeResourcesFolder))
{
var arr = Resources.LoadAll<SongData>(runtimeResourcesFolder);
if (arr != null)
{
foreach (var so in arr)
{
if (so == null) continue;
if (so.name.StartsWith(id.ToString())) dlcContent.Add(so);
}
}
}
if (dlcContent.Count == 0)
{
var arr2 = Resources.LoadAll<SongData>("");
if (arr2 != null)
{
foreach (var so in arr2)
{
if (so == null) continue;
if (so.name.StartsWith(id.ToString())) dlcContent.Add(so);
}
}
}
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()
{
Debug.Log($"dlcButton.ResolveDlcData called on '{gameObject.name}'");
if (dlcDataSO != null)
{
Debug.Log($"dlcButton: dlcDataSO already assigned on '{gameObject.name}' -> {dlcDataSO.name}");
ApplyDlcData(dlcDataSO);
return;
}
int id = 0;
if (dlcID != null && int.TryParse(dlcID.text, out id))
{
Debug.Log($"dlcButton: Resolving by dlcID text {id} for '{gameObject.name}'");
LoadDlcDataById(id);
return;
}
string goName = gameObject.name;
if (!string.IsNullOrEmpty(goName))
{
var parts = goName.Split('_');
int parsed = 0;
if (parts.Length > 0 && int.TryParse(parts[0], out parsed))
{
Debug.Log($"dlcButton: Resolving by GameObject name prefix {parsed} for '{gameObject.name}'");
LoadDlcDataById(parsed);
}
else
{
Debug.LogWarning($"dlcButton.ResolveDlcData: could not parse id from GameObject name '{goName}'");
}
}
else
{
Debug.LogWarning($"dlcButton.ResolveDlcData: no dlcID text and no name to parse for '{gameObject.name}'");
}
}
}