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);
}
///