using System; using System.Collections.Generic; using System.Linq; using BriarQueen.Data.IO.Saves; using BriarQueen.Framework.Managers.IO; using BriarQueen.Framework.Services.Puzzles.Base; using Cysharp.Threading.Tasks; using UnityEngine; using VContainer; namespace BriarQueen.Framework.Services.Puzzles { public class PuzzleService : IDisposable { private readonly SaveManager _saveManager; private BasePuzzle _currentBasePuzzle; private bool _isWritingState; [Inject] public PuzzleService(SaveManager saveManager) { _saveManager = saveManager; _saveManager.OnBeforeSaveRequestedAsync += OnBeforeSaveRequestedAsync; } public void Dispose() { _saveManager.OnBeforeSaveRequestedAsync -= OnBeforeSaveRequestedAsync; } public async UniTask LoadPuzzle(BasePuzzle basePuzzle) { _currentBasePuzzle = basePuzzle; if (_currentBasePuzzle == null) return; await TryRestorePuzzleState(_currentBasePuzzle); } public async UniTask SavePuzzle(BasePuzzle basePuzzle) { if (basePuzzle == null) return; if (_currentBasePuzzle != null && basePuzzle != _currentBasePuzzle) return; await SavePuzzleState(basePuzzle, flushToDisk: true); _currentBasePuzzle = null; } private async UniTask OnBeforeSaveRequestedAsync() { if (_currentBasePuzzle == null) return; await SavePuzzleState(_currentBasePuzzle, flushToDisk: false); } private async UniTask TryRestorePuzzleState(BasePuzzle basePuzzle) { if (basePuzzle == null || _saveManager.CurrentSave == null) return; if (basePuzzle is not IPuzzleStateful stateful) return; var save = _saveManager.CurrentSave; var entry = save.PuzzleStates?.FirstOrDefault(x => x != null && x.PuzzleID == basePuzzle.PuzzleID); var stateBlob = entry?.State; try { await stateful.RestoreState(stateBlob); } catch (Exception ex) { Debug.LogWarning($"[PuzzleService] Failed to restore state for '{basePuzzle.PuzzleID}': {ex}"); } } private async UniTask SavePuzzleState(BasePuzzle basePuzzle, bool flushToDisk) { if (basePuzzle == null || _saveManager.CurrentSave == null) return; if (basePuzzle is not IPuzzleStateful stateful) return; if (_isWritingState) return; _isWritingState = true; try { if (basePuzzle is IPuzzleWorldStateSync worldStateSync) worldStateSync.SyncWorldStateToSave(); var save = _saveManager.CurrentSave; save.PuzzleStates ??= new List(); byte[] blob; try { blob = await stateful.CaptureState() ?? Array.Empty(); } catch (Exception ex) { Debug.LogWarning($"[PuzzleService] Failed to capture state for '{basePuzzle.PuzzleID}': {ex}"); return; } var existing = save.PuzzleStates.FirstOrDefault(x => x != null && x.PuzzleID == basePuzzle.PuzzleID); if (existing == null) { existing = new PuzzleStateSaveData { PuzzleID = basePuzzle.PuzzleID }; save.PuzzleStates.Add(existing); } existing.State = blob; existing.Completed = stateful.IsCompleted; if (flushToDisk) await _saveManager.SaveGameDataLatest(); } finally { _isWritingState = false; } } } }