203 lines
5.7 KiB
C#
203 lines
5.7 KiB
C#
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 readonly Dictionary<string, BasePuzzle> _activePuzzles = new();
|
|
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)
|
|
{
|
|
if (basePuzzle == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(basePuzzle.PuzzleID))
|
|
{
|
|
Debug.LogWarning($"[PuzzleService] Cannot load puzzle '{basePuzzle.name}' with null/empty PuzzleID.");
|
|
return;
|
|
}
|
|
|
|
_activePuzzles[basePuzzle.PuzzleID] = basePuzzle;
|
|
|
|
await basePuzzle.PostLoad();
|
|
await TryRestorePuzzleState(basePuzzle);
|
|
}
|
|
|
|
public async UniTask LoadPuzzles(IEnumerable<BasePuzzle> basePuzzles)
|
|
{
|
|
_activePuzzles.Clear();
|
|
|
|
if (basePuzzles == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
foreach (var basePuzzle in basePuzzles)
|
|
{
|
|
await LoadPuzzle(basePuzzle);
|
|
}
|
|
}
|
|
|
|
public async UniTask SavePuzzle(BasePuzzle basePuzzle)
|
|
{
|
|
if (basePuzzle == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(basePuzzle.PuzzleID) &&
|
|
_activePuzzles.TryGetValue(basePuzzle.PuzzleID, out var activePuzzle) &&
|
|
activePuzzle != basePuzzle)
|
|
{
|
|
return;
|
|
}
|
|
|
|
await SavePuzzleState(basePuzzle, flushToDisk: true);
|
|
await basePuzzle.PreUnload();
|
|
|
|
if (!string.IsNullOrWhiteSpace(basePuzzle.PuzzleID))
|
|
{
|
|
_activePuzzles.Remove(basePuzzle.PuzzleID);
|
|
}
|
|
}
|
|
|
|
public async UniTask SavePuzzles(IEnumerable<BasePuzzle> basePuzzles)
|
|
{
|
|
if (basePuzzles != null)
|
|
{
|
|
foreach (var basePuzzle in basePuzzles)
|
|
{
|
|
await SavePuzzle(basePuzzle);
|
|
}
|
|
}
|
|
|
|
_activePuzzles.Clear();
|
|
}
|
|
|
|
private async UniTask OnBeforeSaveRequestedAsync()
|
|
{
|
|
if (_activePuzzles.Count == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
foreach (var basePuzzle in _activePuzzles.Values.ToList())
|
|
{
|
|
await SavePuzzleState(basePuzzle, 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<PuzzleStateSaveData>();
|
|
|
|
byte[] blob;
|
|
try
|
|
{
|
|
blob = await stateful.CaptureState() ?? Array.Empty<byte>();
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|