3.0 KiB
3.0 KiB
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:
- DungeonObjectEditor Stack: Handles granular operations within the Object Editor (insert, move, delete, resize).
- 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 UndoPoints.
Data Structures
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
- Snapshot Creation: Before any operation that modifies the room (Insert, Delete, Move, Resize),
CreateUndoPoint()is called. - Snapshot Storage: The current state (objects list, selection, mode) is copied into an
UndoPointand pushed toundo_history_. - Limit: The history size is capped (currently 50) to limit memory usage.
- Undo:
- The current state is moved to
redo_history_. - The last
UndoPointis popped fromundo_history_. ApplyUndoPoint()restores theobjectsvector and selection state to the room.
- The current state is moved to
- Redo:
- Similar to Undo, but moves from
redo_history_back to active state andundo_history_.
- Similar to Undo, but moves from
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 inkObjectsmode, it forwards the call toDungeonObjectEditor. - 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
UndoPointcaptures enough state to fully restore the context (e.g., selection). If you add new state variables that affect editing, add them toUndoPoint.