using System; using AppleHills.Core.Settings; using Core; using Input; using Interactions; using System.Threading.Tasks; using Bootstrap; using PuzzleS; using UnityEngine; using Core.SaveLoad; // Added for IInteractionSettings namespace Levels { /// /// Saveable data for MinigameSwitch state /// [System.Serializable] public class MinigameSwitchSaveData { public bool isUnlocked; } /// /// Handles switching into minigame levels when interacted with. Applies switch data and triggers scene transitions. /// public class MinigameSwitch : SaveableInteractable { /// /// Data for this level switch (target scene, icon, etc). /// public LevelSwitchData switchData; /// /// If true, skip save/load logic and start the game active (unlocked by default) /// [SerializeField] private bool startUnlocked = false; private SpriteRenderer iconRenderer; // Settings reference private IInteractionSettings interactionSettings; private bool switchActive = true; private bool isUnlocked; /// /// Unity Awake callback. Sets up icon, interactable, and event handlers. /// protected override void Awake() { base.Awake(); // Register with save system BootCompletionService.RegisterInitAction(InitializePostBoot); switchActive = true; if (iconRenderer == null) iconRenderer = GetComponent(); // If startUnlocked is true, set isUnlocked and skip save/load logic if (startUnlocked) { isUnlocked = true; } // Initialize settings reference interactionSettings = GameManager.GetSettingsObject(); ApplySwitchData(); } protected override void Start() { base.Start(); // Register with save system // If startUnlocked is true, always start active if (startUnlocked) { gameObject.SetActive(true); return; } // Otherwise, if not restoring from save, start inactive if (!IsRestoringFromSave && !isUnlocked) { gameObject.SetActive(false); } } protected override void OnDestroy() { base.OnDestroy(); // Unregister from save system } private void HandleAllPuzzlesComplete(PuzzleS.PuzzleLevelDataSO _) { // Unlock the minigame isUnlocked = true; gameObject.SetActive(true); // Save will happen automatically on next save cycle via ISaveParticipant } #if UNITY_EDITOR /// /// Unity OnValidate callback. Ensures icon and data are up to date in editor. /// void OnValidate() { if (iconRenderer == null) iconRenderer = GetComponent(); ApplySwitchData(); } #endif /// /// Applies the switch data to the level switch (icon, name, etc). /// public void ApplySwitchData() { if (switchData != null) { if (iconRenderer != null) iconRenderer.sprite = switchData.mapSprite; gameObject.name = switchData.targetLevelSceneName; // Optionally update other fields, e.g. description } } /// /// Handles the start of an interaction (shows confirmation menu and switches the level if confirmed). /// protected override void OnCharacterArrived() { if (switchData == null || string.IsNullOrEmpty(switchData.targetLevelSceneName) || !switchActive) return; var menuPrefab = interactionSettings?.MinigameSwitchMenuPrefab; if (menuPrefab == null) { Debug.LogError("MinigameSwitchMenu prefab not assigned in InteractionSettings!"); return; } // Spawn the menu overlay (assume Canvas parent is handled in prefab setup) var menuGo = Instantiate(menuPrefab); var menu = menuGo.GetComponent(); if (menu == null) { Debug.LogError("MinigameSwitchMenu component missing on prefab!"); Destroy(menuGo); return; } // Setup menu with data and callbacks menu.Setup(switchData, OnLevelSelectedWrapper, OnMenuCancel); switchActive = false; // Prevent re-triggering until menu is closed // Switch input mode to UI only InputManager.Instance.SetInputMode(InputMode.UI); } private void OnLevelSelectedWrapper() { _ = OnLevelSelected(); } private async Task OnLevelSelected() { var progress = new Progress(p => Logging.Debug($"Loading progress: {p * 100:F0}%")); await SceneManagerService.Instance.SwitchSceneAsync(switchData.targetLevelSceneName, progress); } private void OnMenuCancel() { switchActive = true; // Allow interaction again if cancelled InputManager.Instance.SetInputMode(InputMode.GameAndUI); } private void InitializePostBoot() { PuzzleManager.Instance.OnAllPuzzlesComplete += HandleAllPuzzlesComplete; } #region Save/Load Implementation protected override object GetSerializableState() { // Skip saving if startUnlocked is true if (startUnlocked) return null; return new MinigameSwitchSaveData { isUnlocked = isUnlocked }; } protected override void ApplySerializableState(string serializedData) { // Skip loading if startUnlocked is true if (startUnlocked) return; MinigameSwitchSaveData data = JsonUtility.FromJson(serializedData); if (data == null) { Debug.LogWarning($"[MinigameSwitch] Failed to deserialize save data for {gameObject.name}"); return; } isUnlocked = data.isUnlocked; // Show/hide based on unlock state gameObject.SetActive(isUnlocked); } #endregion } }