diff --git a/Assets/Scripts/Core/SaveLoad/SaveLoadManager.cs b/Assets/Scripts/Core/SaveLoad/SaveLoadManager.cs index a5c4da76..ecbeb0ca 100644 --- a/Assets/Scripts/Core/SaveLoad/SaveLoadManager.cs +++ b/Assets/Scripts/Core/SaveLoad/SaveLoadManager.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using System.IO; @@ -242,6 +242,35 @@ namespace Core.SaveLoad return currentSaveData.unlockedMinigames.AsReadOnly(); } + /// + /// Clears all save data for a specific level/scene. + /// Removes all participant states that belong to the specified scene. + /// Useful for "restart level" functionality to wipe progress. + /// + /// The name of the scene to clear data for + public void ClearLevelData(string sceneName) + { + if (string.IsNullOrEmpty(sceneName)) + { + Logging.Warning("[SaveLoadManager] Cannot clear level data - scene name is null or empty"); + return; + } + + if (currentSaveData == null || currentSaveData.participantStates == null) + { + Logging.Warning("[SaveLoadManager] Cannot clear level data - no save data loaded"); + return; + } + + // SaveId format is "SceneName/ObjectName/ComponentType" + // Remove all entries that start with "sceneName/" + string scenePrefix = $"{sceneName}/"; + int removedCount = currentSaveData.participantStates.RemoveAll(entry => + entry.saveId.StartsWith(scenePrefix)); + + Logging.Debug($"[SaveLoadManager] Cleared {removedCount} save entries for level: {sceneName}"); + } + #endregion #region State Restoration diff --git a/Assets/Scripts/Core/SceneManagerService.cs b/Assets/Scripts/Core/SceneManagerService.cs index e19aee5a..70c9c4df 100644 --- a/Assets/Scripts/Core/SceneManagerService.cs +++ b/Assets/Scripts/Core/SceneManagerService.cs @@ -283,9 +283,9 @@ namespace Core // Tracks the currently loaded gameplay scene (not persistent/bootstrapper) public string CurrentGameplayScene { get; set; } = "AppleHillsOverworld"; - public async Task ReloadCurrentScene(IProgress progress = null, bool autoHideLoadingScreen = true) + public async Task ReloadCurrentScene(IProgress progress = null, bool autoHideLoadingScreen = true, bool skipSave = false) { - await SwitchSceneAsync(CurrentGameplayScene, progress, autoHideLoadingScreen); + await SwitchSceneAsync(CurrentGameplayScene, progress, autoHideLoadingScreen, skipSave); } /// @@ -294,7 +294,8 @@ namespace Core /// Name of the scene to load /// Optional progress reporter /// Whether to automatically hide the loading screen when complete. If false, caller must hide it manually. - public async Task SwitchSceneAsync(string newSceneName, IProgress progress = null, bool autoHideLoadingScreen = true) + /// If true, skips saving scene data during transition. Useful for level restart to prevent re-saving cleared data. + public async Task SwitchSceneAsync(string newSceneName, IProgress progress = null, bool autoHideLoadingScreen = true, bool skipSave = false) { string oldSceneName = CurrentGameplayScene; @@ -309,8 +310,8 @@ namespace Core LogDebugMessage($"Broadcasting OnSceneUnloading for: {oldSceneName}"); LifecycleManager.Instance?.BroadcastSceneUnloading(oldSceneName); - // PHASE 3: Save scene-specific data via SaveLoadManager - if (SaveLoadManager.Instance != null) + // PHASE 3: Save scene-specific data via SaveLoadManager (unless skipSave is true) + if (!skipSave && SaveLoadManager.Instance != null) { var debugSettings = DeveloperSettingsProvider.Instance.GetSettings(); if (debugSettings.useSaveLoadSystem) @@ -319,6 +320,10 @@ namespace Core SaveLoadManager.Instance.SaveSceneData(); } } + else if (skipSave) + { + LogDebugMessage($"Skipping save for: {oldSceneName} (skipSave=true)"); + } // PHASE 5: Remove all AstarPath (A* Pathfinder) singletons before loading the new scene var astarPaths = FindObjectsByType(FindObjectsSortMode.None); @@ -364,7 +369,7 @@ namespace Core LifecycleManager.Instance?.BroadcastSceneReady(newSceneName); // PHASE 11: Restore scene-specific data via SaveLoadManager - if (SaveLoadManager.Instance != null) + if (!skipSave && SaveLoadManager.Instance != null) { var debugSettings = DeveloperSettingsProvider.Instance.GetSettings(); if (debugSettings.useSaveLoadSystem) @@ -373,6 +378,10 @@ namespace Core SaveLoadManager.Instance.RestoreSceneData(); } } + else if (skipSave) + { + LogDebugMessage($"Skipping restore for: {newSceneName} (skipSave=true)"); + } // PHASE 12: Only hide the loading screen if autoHideLoadingScreen is true if (autoHideLoadingScreen && _loadingScreen != null) diff --git a/Assets/Scripts/Levels/LevelSwitch.cs b/Assets/Scripts/Levels/LevelSwitch.cs index 1e8dfe02..2bffef35 100644 --- a/Assets/Scripts/Levels/LevelSwitch.cs +++ b/Assets/Scripts/Levels/LevelSwitch.cs @@ -128,8 +128,16 @@ namespace Levels private async void OnRestartSelected() { - // TODO: Restart level here - await OnLevelSelected(); + // Clear all save data for the target level before reloading + if (Core.SaveLoad.SaveLoadManager.Instance != null && !string.IsNullOrEmpty(switchData?.targetLevelSceneName)) + { + Core.SaveLoad.SaveLoadManager.Instance.ClearLevelData(switchData.targetLevelSceneName); + Logging.Debug($"[LevelSwitch] Cleared save data for level: {switchData.targetLevelSceneName}"); + } + + // Now reload the level with fresh state - skipSave=true prevents re-saving cleared data + var progress = new Progress(p => Logging.Debug($"Loading progress: {p * 100:F0}%")); + await SceneManagerService.Instance.SwitchSceneAsync(switchData.targetLevelSceneName, progress, autoHideLoadingScreen: true, skipSave: true); } private void OnMenuCancel() diff --git a/Assets/Scripts/UI/PauseMenu.cs b/Assets/Scripts/UI/PauseMenu.cs index 71b3ba0d..a6aef1f3 100644 --- a/Assets/Scripts/UI/PauseMenu.cs +++ b/Assets/Scripts/UI/PauseMenu.cs @@ -1,5 +1,6 @@ using System; using Core; +using Core.SaveLoad; using UnityEngine; using UnityEngine.SceneManagement; using UI.Core; @@ -294,8 +295,20 @@ namespace UI public async void ReloadLevel() { + // Clear all save data for the current gameplay level before reloading + if (SaveLoadManager.Instance != null && SceneManagerService.Instance != null) + { + string currentLevel = SceneManagerService.Instance.CurrentGameplayScene; + if (!string.IsNullOrEmpty(currentLevel)) + { + SaveLoadManager.Instance.ClearLevelData(currentLevel); + Logging.Debug($"[PauseMenu] Cleared save data for current level: {currentLevel}"); + } + } + + // Now reload the current scene with fresh state - skipSave=true prevents re-saving cleared data var progress = new Progress(p => Logging.Debug($"Loading progress: {p * 100:F0}%")); - await SceneManagerService.Instance.ReloadCurrentScene(progress); + await SceneManagerService.Instance.ReloadCurrentScene(progress, autoHideLoadingScreen: true, skipSave: true); } ///