From e60cca78305c3d6ed020442e3b2b167bf1d468af Mon Sep 17 00:00:00 2001 From: Michal Pikulski Date: Thu, 16 Oct 2025 19:40:11 +0200 Subject: [PATCH] FINALIZE THIS SHIEEEEEET --- Assets/Prefabs/UI/LoadingScreen.prefab | 4 +- Assets/Scenes/StartingScene.unity | 2 +- .../Scripts/PuzzleS/ObjectiveStepBehaviour.cs | 19 +++- Assets/Scripts/PuzzleS/PuzzleManager.cs | 95 ++++++++++++++----- Assets/Scripts/PuzzleS/PuzzleStepSO.cs | 55 +++++++++++ 5 files changed, 145 insertions(+), 30 deletions(-) diff --git a/Assets/Prefabs/UI/LoadingScreen.prefab b/Assets/Prefabs/UI/LoadingScreen.prefab index ddbfae6f..cfd531d9 100644 --- a/Assets/Prefabs/UI/LoadingScreen.prefab +++ b/Assets/Prefabs/UI/LoadingScreen.prefab @@ -229,9 +229,7 @@ MonoBehaviour: m_EditorClassIdentifier: AppleHillsScripts::UI.LoadingScreenController loadingScreenContainer: {fileID: 7270617579256400696} progressBarImage: {fileID: 1674678211233966532} - minimumDisplayTime: 2 - animateProgressBar: 1 - progressBarSmoothTime: 0.1 + minimumDisplayTime: 1 progressUpdateInterval: 0.1 --- !u!1 &6888795583318782279 GameObject: diff --git a/Assets/Scenes/StartingScene.unity b/Assets/Scenes/StartingScene.unity index da88ad34..fd4cd910 100644 --- a/Assets/Scenes/StartingScene.unity +++ b/Assets/Scenes/StartingScene.unity @@ -255,7 +255,7 @@ MonoBehaviour: m_EditorClassIdentifier: AppleHillsScripts::Bootstrap.InitialLoadingScreen loadingScreenContainer: {fileID: 180679697} progressBarImage: {fileID: 180679696} - minimumDisplayTime: 2 + minimumDisplayTime: 1 progressUpdateInterval: 0.1 --- !u!1 &400217123 GameObject: diff --git a/Assets/Scripts/PuzzleS/ObjectiveStepBehaviour.cs b/Assets/Scripts/PuzzleS/ObjectiveStepBehaviour.cs index a86b69b2..91937df3 100644 --- a/Assets/Scripts/PuzzleS/ObjectiveStepBehaviour.cs +++ b/Assets/Scripts/PuzzleS/ObjectiveStepBehaviour.cs @@ -71,9 +71,16 @@ namespace PuzzleS void Start() { - // Register with PuzzleManager, regardless of enabled/disabled state - // PuzzleManager will call UnlockStep or LockStep based on current puzzle state - PuzzleManager.Instance?.RegisterStepBehaviour(this); + // Simply register with the PuzzleManager + // The manager will handle state updates appropriately based on whether data is loaded + if (stepData != null && PuzzleManager.Instance != null) + { + PuzzleManager.Instance.RegisterStepBehaviour(this); + } + else if (stepData == null) + { + Logging.Warning($"[Puzzles] Cannot register step on {gameObject.name}: stepData is null"); + } } void OnDestroy() @@ -83,7 +90,11 @@ namespace PuzzleS _interactable.interactionStarted.RemoveListener(OnInteractionStarted); _interactable.interactionComplete.RemoveListener(OnInteractionComplete); } - PuzzleManager.Instance?.UnregisterStepBehaviour(this); + + if (PuzzleManager.Instance != null && stepData != null) + { + PuzzleManager.Instance.UnregisterStepBehaviour(this); + } } /// diff --git a/Assets/Scripts/PuzzleS/PuzzleManager.cs b/Assets/Scripts/PuzzleS/PuzzleManager.cs index 59957bd0..1c8f522f 100644 --- a/Assets/Scripts/PuzzleS/PuzzleManager.cs +++ b/Assets/Scripts/PuzzleS/PuzzleManager.cs @@ -33,10 +33,13 @@ namespace PuzzleS // Current level puzzle data private PuzzleLevelDataSO _currentLevelData; private AsyncOperationHandle _levelDataLoadOperation; - private bool _isLoadingLevelData = false; + private bool _isDataLoaded = false; + + // Store registered behaviors that are waiting for data to be loaded + private List _registeredBehaviours = new List(); /// - /// Singleton instance of the PuzzleManager. No longer creates an instance if one doesn't exist. + /// Singleton instance of the PuzzleManager. /// public static PuzzleManager Instance => _instance; @@ -66,6 +69,7 @@ namespace PuzzleS { // Subscribe to SceneManagerService events after boot is complete SceneManagerService.Instance.SceneLoadCompleted += OnSceneLoadCompleted; + SceneManagerService.Instance.SceneLoadStarted += OnSceneLoadStarted; // Find player transform _playerTransform = GameObject.FindGameObjectWithTag("Player")?.transform; @@ -74,7 +78,7 @@ namespace PuzzleS StartProximityChecks(); // Load puzzle data for the current scene if not already loading - if (_currentLevelData == null && !_isLoadingLevelData) + if (_currentLevelData == null && !_isDataLoaded) { LoadPuzzleDataForCurrentScene(); } @@ -90,6 +94,7 @@ namespace PuzzleS if (SceneManagerService.Instance != null) { SceneManagerService.Instance.SceneLoadCompleted -= OnSceneLoadCompleted; + SceneManagerService.Instance.SceneLoadStarted -= OnSceneLoadStarted; } // Release addressable handle if needed @@ -99,6 +104,16 @@ namespace PuzzleS } } + /// + /// Called when a scene is starting to load + /// + public void OnSceneLoadStarted(string sceneName) + { + // Reset data loaded state when changing scenes to avoid using stale data + _isDataLoaded = false; + Logging.Debug($"[Puzzles] Scene load started: {sceneName}, marked puzzle data as not loaded"); + } + /// /// Called when a scene is loaded /// @@ -132,7 +147,7 @@ namespace PuzzleS return; } - _isLoadingLevelData = true; + _isDataLoaded = false; string addressablePath = $"Puzzles/{currentScene}"; Logging.Debug($"[Puzzles] Loading puzzle data from addressable: {addressablePath}"); @@ -143,9 +158,12 @@ namespace PuzzleS Addressables.Release(_levelDataLoadOperation); } + // Check if the addressable exists before trying to load it if (!AppleHillsUtils.AddressableKeyExists(addressablePath)) { - Logging.Warning($"[Puzzles] Puzzle key does not exist in Addressables: {addressablePath}. Returning early!"); + Logging.Warning($"[Puzzles] Puzzle data does not exist for scene: {currentScene}"); + _isDataLoaded = true; // Mark as loaded but with no data + _currentLevelData = null; return; } @@ -153,8 +171,6 @@ namespace PuzzleS _levelDataLoadOperation = Addressables.LoadAssetAsync(addressablePath); _levelDataLoadOperation.Completed += handle => { - _isLoadingLevelData = false; - if (handle.Status == AsyncOperationStatus.Succeeded) { _currentLevelData = handle.Result; @@ -167,8 +183,11 @@ namespace PuzzleS // Unlock initial steps UnlockInitialSteps(); - // Update existing ObjectiveStepBehaviours with the current state - UpdateRegisteredStepStates(); + // Update all registered behaviors now that data is loaded + UpdateAllRegisteredBehaviors(); + + // Mark data as loaded + _isDataLoaded = true; // Notify listeners OnLevelDataLoaded?.Invoke(_currentLevelData); @@ -176,6 +195,8 @@ namespace PuzzleS else { Logging.Warning($"[Puzzles] Failed to load puzzle data for {currentScene}: {handle.OperationException?.Message}"); + _isDataLoaded = true; // Mark as loaded but with error + _currentLevelData = null; } }; } @@ -238,6 +259,24 @@ namespace PuzzleS } } + /// + /// Update all registered behaviors with their current state + /// + private void UpdateAllRegisteredBehaviors() + { + foreach (var behaviour in _registeredBehaviours) + { + if (behaviour == null) continue; + + // Only update if the step is in our dictionary + bool stepUnlocked = IsStepUnlocked(behaviour.stepData); + if (stepUnlocked) + { + UpdateStepState(behaviour); + } + } + } + /// /// Registers a step behaviour with the manager. /// @@ -246,13 +285,24 @@ namespace PuzzleS { if (behaviour?.stepData == null) return; + // Always add to our registered behaviors list + if (!_registeredBehaviours.Contains(behaviour)) + { + _registeredBehaviours.Add(behaviour); + } + + // Add to the step behaviours dictionary if not already there if (!_stepBehaviours.ContainsKey(behaviour.stepData)) { _stepBehaviours.Add(behaviour.stepData, behaviour); Logging.Debug($"[Puzzles] Registered step: {behaviour.stepData.stepId} on {behaviour.gameObject.name}"); - // Immediately set the correct state based on current puzzle state - UpdateStepState(behaviour); + // Only update state if data is already loaded + if (_isDataLoaded && _currentLevelData != null) + { + UpdateStepState(behaviour); + } + // Otherwise, the state will be updated when data loads in UpdateAllRegisteredBehaviors } } @@ -279,17 +329,6 @@ namespace PuzzleS } } - /// - /// Updates the states of all registered step behaviours based on current puzzle state. - /// - private void UpdateRegisteredStepStates() - { - foreach (var kvp in _stepBehaviours) - { - UpdateStepState(kvp.Value); - } - } - /// /// Unregisters a step behaviour from the manager. /// @@ -297,7 +336,10 @@ namespace PuzzleS public void UnregisterStepBehaviour(ObjectiveStepBehaviour behaviour) { if (behaviour?.stepData == null) return; + _stepBehaviours.Remove(behaviour.stepData); + _registeredBehaviours.Remove(behaviour); + Logging.Debug($"[Puzzles] Unregistered step: {behaviour.stepData.stepId} on {behaviour.gameObject.name}"); } @@ -446,6 +488,15 @@ namespace PuzzleS return _currentLevelData; } + /// + /// Checks if puzzle data is loaded + /// + /// True if data loading has completed (whether successful or not) + public bool IsDataLoaded() + { + return _isDataLoaded; + } + void OnApplicationQuit() { _isQuitting = true; diff --git a/Assets/Scripts/PuzzleS/PuzzleStepSO.cs b/Assets/Scripts/PuzzleS/PuzzleStepSO.cs index 7a2bd299..8de0850c 100644 --- a/Assets/Scripts/PuzzleS/PuzzleStepSO.cs +++ b/Assets/Scripts/PuzzleS/PuzzleStepSO.cs @@ -1,5 +1,6 @@ using UnityEngine; using System.Collections.Generic; +using System; /// /// ScriptableObject representing a single puzzle step, its display info, and which steps it unlocks. @@ -29,4 +30,58 @@ public class PuzzleStepSO : ScriptableObject /// [Header("Unlocks")] public List unlocks = new List(); + + /// + /// Override Equals to compare by stepId rather than reference equality. + /// This ensures consistent behavior across different platforms (Editor vs Mobile). + /// + /// Object to compare to + /// True if the objects represent the same puzzle step + public override bool Equals(object obj) + { + if (obj == null) return false; + + // Check if the object is actually a PuzzleStepSO + PuzzleStepSO other = obj as PuzzleStepSO; + if (other == null) return false; + + // Compare by stepId instead of reference + return string.Equals(stepId, other.stepId, StringComparison.Ordinal); + } + + /// + /// Override GetHashCode to be consistent with the Equals method. + /// This is crucial for HashSet and Dictionary to work properly. + /// + /// Hash code based on stepId + public override int GetHashCode() + { + // Generate hash code from stepId to ensure consistent hashing + return stepId != null ? stepId.GetHashCode() : 0; + } + + /// + /// Override == operator to use our custom equality logic + /// + public static bool operator ==(PuzzleStepSO a, PuzzleStepSO b) + { + // Check if both are null or if they're the same instance + if (ReferenceEquals(a, b)) + return true; + + // Check if either is null (but not both, as that's handled above) + if (((object)a == null) || ((object)b == null)) + return false; + + // Use our custom Equals method + return a.Equals(b); + } + + /// + /// Override != operator to be consistent with == operator + /// + public static bool operator !=(PuzzleStepSO a, PuzzleStepSO b) + { + return !(a == b); + } }