Files
bansonic_beta_main/Assets/scripts/gamePlay_gameplay/JudgeManager.cs
T

305 lines
10 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class JudgeManager : MonoBehaviour
{
[Header("settlement go")]
public GameObject settlement_go;
public settlementController sc;
public NoteSpawner ns;
public static JudgeManager Instance { get; private set; }
// total/remaining notes tracking for end-of-song detection
private int totalNotes = 0;
private int remainingNotes = 0;
// ===== ԭ =====
private Dictionary<KeyCode, Queue<Note>> judgeQueues = new Dictionary<KeyCode, Queue<Note>>();
private Dictionary<string, bool> startJudgedNotes = new Dictionary<string, bool>();
private Dictionary<string, bool> releasedNotes = new Dictionary<string, bool>();
private Dictionary<string, float> noteEndTimes = new Dictionary<string, float>();
private Dictionary<string, int> middlePassedCounts = new Dictionary<string, int>();
// ===== ȫֻ״̬ =====
private class HoldJudgeState
{
public bool startResolved; // Start ǷѾжɹ or ʧܣ
public bool endResolved; // End ǷѾж
public bool skillTriggered; // ǷѴ
}
private Dictionary<string, HoldJudgeState> holdStates = new Dictionary<string, HoldJudgeState>();
private HoldJudgeState GetHoldState(string noteID)
{
if (!holdStates.ContainsKey(noteID))
holdStates[noteID] = new HoldJudgeState();
return holdStates[noteID];
}
// Public event and hook invoked when the entire beatmap's last note has been judged.
// The method is intentionally empty so you can override or call it via the singleton.
public event Action AllNotesJudged;
/// <summary>
/// Public empty hook called when all notes have been judged. Implement your end-of-song logic here
/// or subscribe to the AllNotesJudged event. This method is intentionally left empty.
/// </summary>
public void OnAllNotesJudged()
{
if (settlement_go == null)
{
Debug.LogError("结算页面不存在!");
return;
}
// Activate settlement UI so components run their lifecycle, then call update next frame
try
{
settlement_go.SetActive(true);
}
catch (Exception ex)
{
Debug.LogWarning($"[JudgeManager] Failed to activate settlement_go: {ex}");
}
// Try to resolve settlementController reference if missing
if (sc == null && settlement_go != null)
{
sc = settlement_go.GetComponent<settlementController>() ?? settlement_go.GetComponentInChildren<settlementController>(true);
}
// Invoke the settlement update on next frame to ensure UI initialization finished
StartCoroutine(InvokeSettlementUpdateNextFrame());
}
private IEnumerator InvokeSettlementUpdateNextFrame()
{
yield return null; // wait one frame to allow Awake/Start/OnEnable
if (sc != null)
{
try
{
sc.startSettlement_uiUpdate();
}
catch (Exception ex)
{
Debug.LogWarning($"[JudgeManager] Exception calling startSettlement_uiUpdate: {ex}");
}
}
else
{
Debug.LogWarning("[JudgeManager] settlementController (sc) not found on settlement_go; cannot call startSettlement_uiUpdate().");
}
}
/// <summary>
/// Helper to invoke the AllNotesJudged event and call the public hook.
/// Call this when you detect the last note was judged.
/// </summary>
public void TriggerAllNotesJudged()
{
try
{
AllNotesJudged?.Invoke();
}
catch (Exception ex)
{
Debug.LogWarning($"[JudgeManager] Exception while invoking AllNotesJudged event: {ex}");
}
try
{
OnAllNotesJudged();
}
catch (Exception ex)
{
Debug.LogWarning($"[JudgeManager] Exception in OnAllNotesJudged hook: {ex}");
}
}
private void Awake()
{
if (Instance == null) Instance = this;
else Destroy(gameObject);
if (settlement_go != null) settlement_go.SetActive(false);
}
/// <summary>
/// Set the total number of notes in the current beatmap. Remaining notes will be initialized
/// to this value. Call before playback/spawning starts.
/// </summary>
public void SetTotalNotes(int total)
{
totalNotes = Mathf.Max(0, total);
remainingNotes = totalNotes;
Debug.Log($"[JudgeManager] SetTotalNotes: total={totalNotes}");
}
/// <summary>
/// Notify that one note has been finally judged (hit or miss). When remaining reaches zero,
/// TriggerAllNotesJudged will be invoked.
/// </summary>
public void NotifyNoteJudged()
{
if (remainingNotes <= 0) return;
remainingNotes = Mathf.Max(0, remainingNotes - 1);
Debug.Log($"[JudgeManager] NotifyNoteJudged: remaining={remainingNotes}");
if (remainingNotes == 0)
{
Debug.Log("[JudgeManager] All notes judged -> Triggering AllNotesJudged");
TriggerAllNotesJudged();
}
}
// ===== жխ =====
public bool TryResolveStart(string noteID)
{
var s = GetHoldState(noteID);
if (s.startResolved)
{
Debug.LogWarning($"[JudgeManager] TryResolveStart: already resolved start for {noteID}");
return false;
}
s.startResolved = true;
Debug.Log($"[JudgeManager] TryResolveStart: start resolved for {noteID} at time={Time.time:F3}");
return true;
}
public bool TryResolveEnd(string noteID)
{
var s = GetHoldState(noteID);
if (s.endResolved)
{
Debug.LogWarning($"[JudgeManager] TryResolveEnd: already resolved end for {noteID}");
return false;
}
s.endResolved = true;
Debug.Log($"[JudgeManager] TryResolveEnd: end resolved for {noteID} at time={Time.time:F3}");
return true;
}
public bool TryTriggerSkill(string noteID)
{
var s = GetHoldState(noteID);
if (s.skillTriggered)
{
Debug.LogWarning($"[JudgeManager] TryTriggerSkill: already triggered for {noteID}");
return false;
}
s.skillTriggered = true;
Debug.Log($"[JudgeManager] TryTriggerSkill: skill triggered for {noteID} at time={Time.time:F3}");
return true;
}
public void ClearHoldState(string noteID)
{
if (holdStates.ContainsKey(noteID))
{
holdStates.Remove(noteID);
Debug.Log($"[JudgeManager] ClearHoldState: cleared state for {noteID}");
}
}
// ===== ԭнӿڣֲ䣩 =====
public void RegisterScheduledEndTime(string noteID, float endTime)
{
noteEndTimes[noteID] = endTime;
Debug.Log($"[JudgeManager] RegisterScheduledEndTime: {noteID} -> {endTime:F3}");
}
public float GetScheduledEndTime(string noteID)
{
return noteEndTimes.ContainsKey(noteID) ? noteEndTimes[noteID] : 0f;
}
public void RegisterStartJudged(string noteID, bool state)
{
startJudgedNotes[noteID] = state;
Debug.Log($"[JudgeManager] RegisterStartJudged: {noteID} = {state} at time={Time.time:F3}");
}
public bool IsStartJudged(string noteID)
{
return startJudgedNotes.ContainsKey(noteID) && startJudgedNotes[noteID];
}
public void RegisterNoteReleased(string noteID, bool state)
{
releasedNotes[noteID] = state;
Debug.Log($"[JudgeManager] RegisterNoteReleased: {noteID} = {state}");
}
public bool HasNoteReleased(string noteID)
{
return releasedNotes.ContainsKey(noteID) && releasedNotes[noteID];
}
public void RegisterNote(KeyCode key, Note note)
{
if (!judgeQueues.ContainsKey(key))
judgeQueues[key] = new Queue<Note>();
if (!judgeQueues[key].Contains(note))
judgeQueues[key].Enqueue(note);
Debug.Log($"[JudgeManager] RegisterNote: key={key} note={note.name} time={Time.time:F3} queueSize={judgeQueues[key].Count}");
}
public void UnregisterNote(KeyCode key, Note note)
{
if (!judgeQueues.ContainsKey(key)) return;
Queue<Note> newQueue = new Queue<Note>();
while (judgeQueues[key].Count > 0)
{
Note n = judgeQueues[key].Dequeue();
if (n != note)
newQueue.Enqueue(n);
else if (!n.IsJudged())
n.JudgeMiss();
}
judgeQueues[key] = newQueue;
Debug.Log($"[JudgeManager] UnregisterNote: key={key} removed {note.name}, newQueueSize={judgeQueues[key].Count}");
}
public void JudgeEarliestNote(KeyCode key)
{
if (judgeQueues.ContainsKey(key) && judgeQueues[key].Count > 0)
{
Note note = judgeQueues[key].Dequeue();
if (note != null && !note.IsJudged())
{
Debug.Log($"[JudgeManager] JudgeEarliestNote: judging {note.name} for key={key} at time={Time.time:F3}");
note.Judge();
}
}
}
public void RegisterMiddlePassed(string noteID)
{
if (!middlePassedCounts.ContainsKey(noteID))
middlePassedCounts[noteID] = 0;
middlePassedCounts[noteID]++;
Debug.Log($"[JudgeManager] Middle passed for {noteID}, total={middlePassedCounts[noteID]}");
}
public int GetMiddlePassedCount(string noteID)
{
return middlePassedCounts.ContainsKey(noteID) ? middlePassedCounts[noteID] : 0;
}
public void ClearNoteRecord(string noteID)
{
startJudgedNotes.Remove(noteID);
releasedNotes.Remove(noteID);
noteEndTimes.Remove(noteID);
middlePassedCounts.Remove(noteID);
ClearHoldState(noteID);
Debug.Log($"[JudgeManager] ClearNoteRecord: cleared records for {noteID}");
}
}