Fix issues with puzzle loading order and add saving state when using Menu
This commit is contained in:
committed by
Michal Pikulski
parent
c527ba334d
commit
717deee0cd
@@ -122,6 +122,32 @@ TextureImporter:
|
|||||||
ignorePlatformSupport: 0
|
ignorePlatformSupport: 0
|
||||||
androidETC2FallbackOverride: 0
|
androidETC2FallbackOverride: 0
|
||||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
|
- serializedVersion: 4
|
||||||
|
buildTarget: WebGL
|
||||||
|
maxTextureSize: 2048
|
||||||
|
resizeAlgorithm: 0
|
||||||
|
textureFormat: -1
|
||||||
|
textureCompression: 1
|
||||||
|
compressionQuality: 50
|
||||||
|
crunchedCompression: 0
|
||||||
|
allowsAlphaSplitting: 0
|
||||||
|
overridden: 0
|
||||||
|
ignorePlatformSupport: 0
|
||||||
|
androidETC2FallbackOverride: 0
|
||||||
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
|
- serializedVersion: 4
|
||||||
|
buildTarget: WindowsStoreApps
|
||||||
|
maxTextureSize: 2048
|
||||||
|
resizeAlgorithm: 0
|
||||||
|
textureFormat: -1
|
||||||
|
textureCompression: 1
|
||||||
|
compressionQuality: 50
|
||||||
|
crunchedCompression: 0
|
||||||
|
allowsAlphaSplitting: 0
|
||||||
|
overridden: 0
|
||||||
|
ignorePlatformSupport: 0
|
||||||
|
androidETC2FallbackOverride: 0
|
||||||
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
spriteSheet:
|
spriteSheet:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
sprites:
|
sprites:
|
||||||
|
|||||||
@@ -122,6 +122,32 @@ TextureImporter:
|
|||||||
ignorePlatformSupport: 0
|
ignorePlatformSupport: 0
|
||||||
androidETC2FallbackOverride: 0
|
androidETC2FallbackOverride: 0
|
||||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
|
- serializedVersion: 4
|
||||||
|
buildTarget: WebGL
|
||||||
|
maxTextureSize: 2048
|
||||||
|
resizeAlgorithm: 0
|
||||||
|
textureFormat: -1
|
||||||
|
textureCompression: 1
|
||||||
|
compressionQuality: 50
|
||||||
|
crunchedCompression: 0
|
||||||
|
allowsAlphaSplitting: 0
|
||||||
|
overridden: 0
|
||||||
|
ignorePlatformSupport: 0
|
||||||
|
androidETC2FallbackOverride: 0
|
||||||
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
|
- serializedVersion: 4
|
||||||
|
buildTarget: WindowsStoreApps
|
||||||
|
maxTextureSize: 2048
|
||||||
|
resizeAlgorithm: 0
|
||||||
|
textureFormat: -1
|
||||||
|
textureCompression: 1
|
||||||
|
compressionQuality: 50
|
||||||
|
crunchedCompression: 0
|
||||||
|
allowsAlphaSplitting: 0
|
||||||
|
overridden: 0
|
||||||
|
ignorePlatformSupport: 0
|
||||||
|
androidETC2FallbackOverride: 0
|
||||||
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
spriteSheet:
|
spriteSheet:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
sprites:
|
sprites:
|
||||||
|
|||||||
@@ -180,6 +180,67 @@ namespace Core.SaveLoad
|
|||||||
return participant;
|
return participant;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Unlocked Minigames Management
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Marks a minigame as unlocked in the global save data.
|
||||||
|
/// This is separate from scene-specific participant states and persists across all saves.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="minigameName">The name/identifier of the minigame (typically scene name)</param>
|
||||||
|
public void UnlockMinigame(string minigameName)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(minigameName))
|
||||||
|
{
|
||||||
|
Logging.Warning("[SaveLoadManager] Attempted to unlock minigame with null or empty name");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentSaveData == null)
|
||||||
|
{
|
||||||
|
Logging.Warning("[SaveLoadManager] Cannot unlock minigame - no save data loaded");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentSaveData.unlockedMinigames == null)
|
||||||
|
{
|
||||||
|
currentSaveData.unlockedMinigames = new System.Collections.Generic.List<string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!currentSaveData.unlockedMinigames.Contains(minigameName))
|
||||||
|
{
|
||||||
|
currentSaveData.unlockedMinigames.Add(minigameName);
|
||||||
|
Logging.Debug($"[SaveLoadManager] Unlocked minigame: {minigameName}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if a minigame has been unlocked.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="minigameName">The name/identifier of the minigame</param>
|
||||||
|
/// <returns>True if the minigame is unlocked, false otherwise</returns>
|
||||||
|
public bool IsMinigameUnlocked(string minigameName)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(minigameName))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (currentSaveData == null || currentSaveData.unlockedMinigames == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return currentSaveData.unlockedMinigames.Contains(minigameName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a read-only list of all unlocked minigames.
|
||||||
|
/// </summary>
|
||||||
|
public System.Collections.Generic.IReadOnlyList<string> GetUnlockedMinigames()
|
||||||
|
{
|
||||||
|
if (currentSaveData == null || currentSaveData.unlockedMinigames == null)
|
||||||
|
return new System.Collections.Generic.List<string>();
|
||||||
|
|
||||||
|
return currentSaveData.unlockedMinigames.AsReadOnly();
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -343,29 +404,68 @@ namespace Core.SaveLoad
|
|||||||
|
|
||||||
Logging.Debug("[SaveLoadManager] Saving scene-specific data...");
|
Logging.Debug("[SaveLoadManager] Saving scene-specific data...");
|
||||||
|
|
||||||
// Collect scene data from LifecycleManager
|
// Build a dictionary of all data to save
|
||||||
|
var allSceneData = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
// Collect scene data from ManagedBehaviours via LifecycleManager
|
||||||
if (Lifecycle.LifecycleManager.Instance != null)
|
if (Lifecycle.LifecycleManager.Instance != null)
|
||||||
{
|
{
|
||||||
var sceneData = Lifecycle.LifecycleManager.Instance.BroadcastSceneSaveRequested();
|
var sceneData = Lifecycle.LifecycleManager.Instance.BroadcastSceneSaveRequested();
|
||||||
|
|
||||||
// Remove old scene data and add new
|
|
||||||
if (currentSaveData.participantStates != null)
|
|
||||||
{
|
|
||||||
// Remove existing entries for these SaveIds (to avoid duplicates)
|
|
||||||
currentSaveData.participantStates.RemoveAll(entry => sceneData.ContainsKey(entry.saveId));
|
|
||||||
|
|
||||||
// Add new scene data
|
|
||||||
foreach (var kvp in sceneData)
|
foreach (var kvp in sceneData)
|
||||||
{
|
{
|
||||||
|
allSceneData[kvp.Key] = kvp.Value;
|
||||||
|
}
|
||||||
|
Logging.Debug($"[SaveLoadManager] Collected {sceneData.Count} ManagedBehaviour scene states");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect data from ISaveParticipants (all currently registered, identified by SaveId)
|
||||||
|
foreach (var kvp in participants.ToList())
|
||||||
|
{
|
||||||
|
string saveId = kvp.Key;
|
||||||
|
ISaveParticipant participant = kvp.Value;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string serializedState = participant.SerializeState();
|
||||||
|
allSceneData[saveId] = serializedState;
|
||||||
|
Logging.Debug($"[SaveLoadManager] Captured state for ISaveParticipant: {saveId}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.Warning($"[SaveLoadManager] Exception while serializing ISaveParticipant '{saveId}': {ex}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update existing entries or add new ones (matches SaveAsync() pattern)
|
||||||
|
if (currentSaveData.participantStates != null)
|
||||||
|
{
|
||||||
|
int updatedCount = 0;
|
||||||
|
|
||||||
|
foreach (var kvp in allSceneData)
|
||||||
|
{
|
||||||
|
var existingEntry = currentSaveData.participantStates.Find(e => e.saveId == kvp.Key);
|
||||||
|
if (existingEntry != null)
|
||||||
|
{
|
||||||
|
// Update existing entry in place
|
||||||
|
existingEntry.serializedState = kvp.Value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Add new entry
|
||||||
currentSaveData.participantStates.Add(new ParticipantStateEntry
|
currentSaveData.participantStates.Add(new ParticipantStateEntry
|
||||||
{
|
{
|
||||||
saveId = kvp.Key,
|
saveId = kvp.Key,
|
||||||
serializedState = kvp.Value
|
serializedState = kvp.Value
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
updatedCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logging.Debug($"[SaveLoadManager] Updated {sceneData.Count} scene data entries in memory");
|
Logging.Debug($"[SaveLoadManager] Updated {updatedCount} scene data entries in memory");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logging.Warning("[SaveLoadManager] participantStates list is null, cannot save scene data");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -255,9 +255,9 @@ namespace Levels
|
|||||||
if (_switchData == null)
|
if (_switchData == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var data = SaveLoadManager.Instance?.currentSaveData;
|
// Use the new public API to check unlock status
|
||||||
string minigameName = _switchData.targetMinigameSceneName;
|
string minigameName = _switchData.targetMinigameSceneName;
|
||||||
bool unlocked = data?.unlockedMinigames != null && !string.IsNullOrEmpty(minigameName) && data.unlockedMinigames.Contains(minigameName);
|
bool unlocked = SaveLoadManager.Instance != null && SaveLoadManager.Instance.IsMinigameUnlocked(minigameName);
|
||||||
|
|
||||||
// Show/hide padlock
|
// Show/hide padlock
|
||||||
if (padlockImage) padlockImage.gameObject.SetActive(!unlocked);
|
if (padlockImage) padlockImage.gameObject.SetActive(!unlocked);
|
||||||
|
|||||||
@@ -102,7 +102,13 @@ namespace Levels
|
|||||||
isUnlocked = true;
|
isUnlocked = true;
|
||||||
gameObject.SetActive(true);
|
gameObject.SetActive(true);
|
||||||
|
|
||||||
// Save will happen automatically on next save cycle via ISaveParticipant
|
// Add to global unlocked minigames list
|
||||||
|
if (switchData != null && !string.IsNullOrEmpty(switchData.targetLevelSceneName))
|
||||||
|
{
|
||||||
|
Core.SaveLoad.SaveLoadManager.Instance?.UnlockMinigame(switchData.targetLevelSceneName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save will happen automatically on next save cycle via SaveableInteractable
|
||||||
}
|
}
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
@@ -231,6 +237,12 @@ namespace Levels
|
|||||||
|
|
||||||
isUnlocked = data.isUnlocked;
|
isUnlocked = data.isUnlocked;
|
||||||
|
|
||||||
|
// Sync with global unlocked minigames list
|
||||||
|
if (isUnlocked && switchData != null && !string.IsNullOrEmpty(switchData.targetLevelSceneName))
|
||||||
|
{
|
||||||
|
Core.SaveLoad.SaveLoadManager.Instance?.UnlockMinigame(switchData.targetLevelSceneName);
|
||||||
|
}
|
||||||
|
|
||||||
// Show/hide based on unlock state
|
// Show/hide based on unlock state
|
||||||
gameObject.SetActive(isUnlocked);
|
gameObject.SetActive(isUnlocked);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,8 +34,6 @@ namespace PuzzleS
|
|||||||
|
|
||||||
protected override void Awake()
|
protected override void Awake()
|
||||||
{
|
{
|
||||||
base.Awake();
|
|
||||||
|
|
||||||
_interactable = GetComponent<InteractableBase>();
|
_interactable = GetComponent<InteractableBase>();
|
||||||
|
|
||||||
// Initialize the indicator if it exists, but ensure it's hidden initially
|
// Initialize the indicator if it exists, but ensure it's hidden initially
|
||||||
@@ -58,6 +56,8 @@ namespace PuzzleS
|
|||||||
Logging.Warning($"[Puzzles] Indicator prefab for {stepData?.stepId} does not implement IPuzzlePrompt");
|
Logging.Warning($"[Puzzles] Indicator prefab for {stepData?.stepId} does not implement IPuzzlePrompt");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
base.Awake();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnManagedAwake()
|
protected override void OnManagedAwake()
|
||||||
|
|||||||
@@ -50,7 +50,24 @@ namespace PuzzleS
|
|||||||
|
|
||||||
// Save system configuration
|
// Save system configuration
|
||||||
public override bool AutoRegisterForSave => true;
|
public override bool AutoRegisterForSave => true;
|
||||||
public override string SaveId => $"{SceneManager.GetActiveScene().name}/PuzzleManager";
|
|
||||||
|
/// <summary>
|
||||||
|
/// SaveId uses CurrentGameplayScene instead of GetActiveScene() because PuzzleManager
|
||||||
|
/// lives in DontDestroyOnLoad and needs to save/load data per-scene.
|
||||||
|
/// </summary>
|
||||||
|
public override string SaveId
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
string sceneName = SceneManagerService.Instance?.CurrentGameplayScene;
|
||||||
|
if (string.IsNullOrEmpty(sceneName))
|
||||||
|
{
|
||||||
|
// Fallback during early initialization
|
||||||
|
sceneName = SceneManager.GetActiveScene().name;
|
||||||
|
}
|
||||||
|
return $"{sceneName}/PuzzleManager";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Singleton instance of the PuzzleManager.
|
/// Singleton instance of the PuzzleManager.
|
||||||
@@ -602,6 +619,7 @@ namespace PuzzleS
|
|||||||
// Update any behaviors that registered before RestoreState was called
|
// Update any behaviors that registered before RestoreState was called
|
||||||
foreach (var behaviour in _pendingRegistrations)
|
foreach (var behaviour in _pendingRegistrations)
|
||||||
{
|
{
|
||||||
|
if(behaviour != null)
|
||||||
UpdateStepState(behaviour);
|
UpdateStepState(behaviour);
|
||||||
}
|
}
|
||||||
_pendingRegistrations.Clear();
|
_pendingRegistrations.Clear();
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ MonoBehaviour:
|
|||||||
pauseTimeOnPauseGame: 0
|
pauseTimeOnPauseGame: 0
|
||||||
useSaveLoadSystem: 1
|
useSaveLoadSystem: 1
|
||||||
bootstrapLogVerbosity: 0
|
bootstrapLogVerbosity: 0
|
||||||
settingsLogVerbosity: 1
|
settingsLogVerbosity: 0
|
||||||
gameManagerLogVerbosity: 1
|
gameManagerLogVerbosity: 0
|
||||||
sceneLogVerbosity: 0
|
sceneLogVerbosity: 0
|
||||||
saveLoadLogVerbosity: 0
|
saveLoadLogVerbosity: 0
|
||||||
inputLogVerbosity: 0
|
inputLogVerbosity: 0
|
||||||
|
|||||||
Reference in New Issue
Block a user