Files
yaze/docs/internal/architecture/undo_redo_system.md

59 lines
3.0 KiB
Markdown

# Undo/Redo System Architecture
**Status**: Draft
**Last Updated**: 2025-11-21
**Related Code**: `src/zelda3/dungeon/dungeon_object_editor.h`, `src/zelda3/dungeon/dungeon_editor_system.h`
This document outlines the Undo/Redo architecture used in the Dungeon Editor.
## Overview
The system employs a command pattern approach where the state of the editor is snapshotted before destructive operations. Currently, there are two distinct undo stacks:
1. **DungeonObjectEditor Stack**: Handles granular operations within the Object Editor (insert, move, delete, resize).
2. **DungeonEditorSystem Stack**: (Planned/Partial) Intended for high-level operations and other modes (sprites, items), but currently delegates to the Object Editor for object operations.
## DungeonObjectEditor Implementation
The `DungeonObjectEditor` maintains its own local history of `UndoPoint`s.
### Data Structures
```cpp
struct UndoPoint {
std::vector<RoomObject> objects; // Snapshot of all objects in the room
SelectionState selection; // Snapshot of selection (indices, drag state)
EditingState editing; // Snapshot of editing mode/settings
std::chrono::steady_clock::time_point timestamp;
};
```
### Workflow
1. **Snapshot Creation**: Before any operation that modifies the room (Insert, Delete, Move, Resize), `CreateUndoPoint()` is called.
2. **Snapshot Storage**: The current state (objects list, selection, mode) is copied into an `UndoPoint` and pushed to `undo_history_`.
3. **Limit**: The history size is capped (currently 50) to limit memory usage.
4. **Undo**:
* The current state is moved to `redo_history_`.
* The last `UndoPoint` is popped from `undo_history_`.
* `ApplyUndoPoint()` restores the `objects` vector and selection state to the room.
5. **Redo**:
* Similar to Undo, but moves from `redo_history_` back to active state and `undo_history_`.
### Batch Operations
For batch operations (e.g., `BatchMoveObjects`, `PasteObjects`), a single `UndoPoint` is created before the loop that processes all items. This ensures that one "Undo" command reverts the entire batch operation.
## DungeonEditorSystem Role
The `DungeonEditorSystem` acts as a high-level coordinator.
* **Delegation**: When `Undo()`/`Redo()` is called on the system while in `kObjects` mode, it forwards the call to `DungeonObjectEditor`.
* **Future Expansion**: It has its own `undo_history_` structure intended to capture broader state (sprites, chests, entrances), but this is currently a TODO.
## Best Practices for Contributors
* **Always call `CreateUndoPoint()`** before modifying the object list.
* **Snapshot effectively**: The current implementation snapshots the *entire* object list. For very large rooms (which are rare in ALttP), this might be optimized in the future, but it's sufficient for now.
* **State Consistency**: Ensure `UndoPoint` captures enough state to fully restore the context (e.g., selection). If you add new state variables that affect editing, add them to `UndoPoint`.