Chessistics/chessistics-engine/Simulation/GameSim.cs
Samuel Bouchet 2537bfe828 Add QuickSave/QuickLoad with full state restore and visual rebuild
BoardState.CaptureSave/RestoreFromSave deep-copy every mutable field
(grid, pieces, demands, transformers, buffers, stock, campaign progress)
into a WorldSave slot. GameSim.QuickSave/QuickLoad expose slotted saves
and emit StateSavedEvent / StateRestoredEvent — the latter carries a
fresh BoardSnapshot so the presentation can rebuild board, pieces,
trajectories, objectives, stock, camera, and control bar in one pass.

F5/F9 trigger it in Main; harness gains quick_save/quick_load commands so
UI tests can checkpoint a scenario and resume without replaying from
scratch. Seven xUnit tests cover the roundtrip (including independence
from post-save mutations, campaign state, and multi-slot isolation).
2026-04-17 22:10:06 +02:00

64 lines
1.9 KiB
C#

using Chessistics.Engine.Commands;
using Chessistics.Engine.Events;
using Chessistics.Engine.Model;
namespace Chessistics.Engine.Simulation;
public class GameSim
{
private readonly BoardState _state;
private readonly Dictionary<int, WorldSave> _saveSlots = new();
private const int DefaultSlot = 0;
public GameSim(LevelDef level)
{
_state = BoardState.FromLevel(level);
}
public GameSim(CampaignDef campaign)
{
_state = BoardState.FromCampaign(campaign);
}
public IReadOnlyList<IWorldEvent> ProcessCommand(IWorldCommand command)
{
var changeList = new List<IWorldEvent>();
try
{
command.Apply(_state, changeList);
}
catch (CommandRejectedException ex)
{
return [ex.RejectionEvent];
}
return changeList;
}
public BoardSnapshot GetSnapshot() => new(_state);
/// <summary>
/// Capture a full deep-copy of the world into an in-memory slot.
/// Returns a single StateSavedEvent — no state mutation.
/// </summary>
public IReadOnlyList<IWorldEvent> QuickSave(int slot = DefaultSlot)
{
_saveSlots[slot] = _state.CaptureSave();
return [new StateSavedEvent(_state.TurnNumber, slot)];
}
/// <summary>
/// Restore the world from a saved slot. Emits StateRestoredEvent with a
/// fresh snapshot — the presentation layer must rebuild all visuals.
/// Returns an empty list (no event) if the slot is empty.
/// </summary>
public IReadOnlyList<IWorldEvent> QuickLoad(int slot = DefaultSlot)
{
if (!_saveSlots.TryGetValue(slot, out var save))
return [];
_state.RestoreFromSave(save);
return [new StateRestoredEvent(new BoardSnapshot(_state), slot)];
}
public bool HasSave(int slot = DefaultSlot) => _saveSlots.ContainsKey(slot);
}