using System; using System.Collections; using System.Collections.Generic; using System.Linq; using Ichni.RhythmGame; using Ichni.RhythmGame.UI; using Sirenix.OdinInspector; using SLSUtilities.General; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.Serialization; namespace Ichni { public partial class GameManager : Singleton, ISongTimeProvider { [FormerlySerializedAs("audioManager")] public SongPlayer songPlayer; public CameraManager cameraManager; [FormerlySerializedAs("inputManager")] public NoteJudgeManager noteJudgeManager; public BackgroundSetter backgroundSetter; public BackgroundController backgroundController; public VariablesContainer variablesContainer; public ProjectLoader projectLoader; public PlayingRecorder playingRecorder; public BeatmapContainer beatmapContainer; public CommandScripts commandScripts; public ProjectInformation projectInformation; public SongInformation songInformation; public List timeDurations; public AnimationManager animationManager; public TrackManager trackManager; public NoteManager noteManager; public BasePrefabsCollection basePrefabs; public Dictionary customPrefabs; public List activeTransformSubmodules = new List(); public List activeColorSubmodules = new List(); public List activeDirtyMarkSubmodules = new List(); public ElementUpdateScheduler updateScheduler; [Title("UI")] public Canvas judgeHintCanvas; public GameUICanvas gameUICanvas; public GameLoadingCanvas gameLoadingCanvas; public SummaryPageCanvas summaryPageCanvas; public float SongTime => songPlayer.isStarting ? 0 : songPlayer.songTimeSegment - songInformation.offset - (SettingsManager.instance.gameSettings.beatmapOffset / 1000f); public bool IsPlaying => songPlayer != null && songPlayer.isPlaying; public bool isDebugging; protected override void Awake() { base.Awake(); CoreServices.TimeProvider = this; timeDurations = new List(); playingRecorder = new PlayingRecorder(); playingRecorder.Initialize(); updateScheduler = new ElementUpdateScheduler(); CoreServices.UpdateScheduler = updateScheduler; } private void Start() { basePrefabs.PrepareAudios(); projectLoader.TestLoad(); } private void Update() { updateScheduler.TickEarly(SongTime); } private void LateUpdate() { updateScheduler.TickLate(); } } public partial class GameManager { /// /// 将当前演奏结果写入独立的游戏记录存档。 /// 由 SongPlayer 在实际歌曲结束后、打开 Summary 前调用。 /// 剧情树、选项和 Yarn 变量仍由 单独管理。 /// 当前 Difficulty 的 Chart Revision 会一并传入,从而在谱面改版时只清除不可比较的单谱面成绩。 /// public bool SaveCurrentPlayRecord() { if (GameSaveManager.instance == null || GameSaveManager.instance.SongSaveModule == null) { Debug.LogWarning("Cannot save play record because SongSaveModule is not initialized."); return false; } if (InformationTransistor.instance == null || InformationTransistor.instance.song == null || InformationTransistor.instance.difficulty == null) { Debug.LogWarning("Cannot save play record because the selected song or difficulty is missing."); return false; } return GameSaveManager.instance.SongSaveModule.RecordPlayResult( InformationTransistor.instance.song.songName, InformationTransistor.instance.difficulty.saveDifficultyId, InformationTransistor.instance.difficulty.GetChartRevision(), playingRecorder); } public static void RestartGame() { // 保留 InformationTransistor 中的歌曲和返回目标,使教程与普通歌曲的重开都回到正确页面。 SceneManager.LoadScene("GameScene"); Time.timeScale = 1f; // 确保重启时时间缩放恢复正常 } public static void ReturnToMenu() { Time.timeScale = 1f; // 确保返回时时间缩放恢复正常 // 返回目标已在进入 GameScene 时写入 InformationTransistor;这里不再写互斥布尔值。 SceneManager.LoadScene("MenuScene"); } } }