1#ifndef YAZE_APP_EDITOR_OVERWORLD_UNDO_ACTIONS_H_
2#define YAZE_APP_EDITOR_OVERWORLD_UNDO_ACTIONS_H_
9#include <unordered_map>
13#include "absl/status/status.h"
14#include "absl/strings/str_format.h"
60 std::function<
void()> refresh_fn)
66 timestamp_(std::chrono::steady_clock::now()) {}
68 absl::Status
Undo()
override {
70 return absl::InternalError(
"Overworld pointer is null");
74 world_tiles[change.x][change.y] = change.old_tile_id;
79 return absl::OkStatus();
82 absl::Status
Redo()
override {
84 return absl::InternalError(
"Overworld pointer is null");
88 world_tiles[change.x][change.y] = change.new_tile_id;
93 return absl::OkStatus();
97 return absl::StrFormat(
"Paint %d tile%s on map %d",
tile_changes_.size(),
106 const auto* prev_paint =
110 if (prev_paint->map_id_ !=
map_id_)
112 if (prev_paint->world_ !=
world_)
115 auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
126 std::unordered_map<int64_t, size_t> coord_index;
128 int64_t key = (
static_cast<int64_t
>(
tile_changes_[i].x) << 32) |
130 coord_index[key] = i;
133 for (
const auto& prev_change : prev_paint.tile_changes_) {
134 int64_t key = (
static_cast<int64_t
>(prev_change.x) << 32) |
135 static_cast<int64_t
>(prev_change.y);
136 auto it = coord_index.find(key);
137 if (it != coord_index.end()) {
139 tile_changes_[it->second].old_tile_id = prev_change.old_tile_id;
172 std::vector<zelda3::OverworldItem>
items;
188 std::string description)
196 return absl::InternalError(
197 "OverworldItemsEditAction: no restore callback");
200 return absl::OkStatus();
205 return absl::InternalError(
206 "OverworldItemsEditAction: no restore callback");
209 return absl::OkStatus();
215 const size_t before_size =
217 const size_t after_size =
219 return sizeof(*this) + before_size + after_size;
237 std::string description)
245 return absl::InternalError(
246 "OverworldMapPropertyEditAction: no apply callback");
253 return absl::InternalError(
254 "OverworldMapPropertyEditAction: no apply callback");
280 std::vector<OverworldPropertyEdit> after,
281 ApplyFn apply, std::string description)
289 return absl::InternalError(
290 "OverworldMapPropertyBatchEditAction: no apply callback");
295 return absl::OkStatus();
300 return absl::InternalError(
301 "OverworldMapPropertyBatchEditAction: no apply callback");
303 for (
const auto& edit :
after_) {
306 return absl::OkStatus();
313 for (
const auto& edit :
before_) {
314 total +=
sizeof(edit) + edit.description.size();
316 for (
const auto& edit :
after_) {
317 total +=
sizeof(edit) + edit.description.size();
326 std::vector<OverworldPropertyEdit>
after_;
333 using ApplyFn = std::function<absl::Status(
const std::string&)>;
336 ApplyFn apply, std::string description)
344 return absl::InternalError(
345 "OverworldProjectLabelEditAction: no apply callback");
352 return absl::InternalError(
353 "OverworldProjectLabelEditAction: no apply callback");
Undoable action for overworld item mutations.
bool CanMergeWith(const UndoAction &) const override
std::string Description() const override
Human-readable description (e.g., "Paint 12 tiles on map 5")
OverworldItemsEditAction(OverworldItemsSnapshot before, OverworldItemsSnapshot after, RestoreFn restore, std::string description)
absl::Status Redo() override
absl::Status Undo() override
std::function< void(const OverworldItemsSnapshot &)> RestoreFn
OverworldItemsSnapshot before_
OverworldItemsSnapshot after_
size_t MemoryUsage() const override
Approximate memory footprint for budget enforcement.
std::vector< OverworldPropertyEdit > after_
std::vector< OverworldPropertyEdit > before_
std::string Description() const override
Human-readable description (e.g., "Paint 12 tiles on map 5")
absl::Status Undo() override
std::function< absl::Status(const OverworldPropertyEdit &)> ApplyFn
absl::Status Redo() override
size_t MemoryUsage() const override
Approximate memory footprint for budget enforcement.
OverworldMapPropertyBatchEditAction(std::vector< OverworldPropertyEdit > before, std::vector< OverworldPropertyEdit > after, ApplyFn apply, std::string description)
bool CanMergeWith(const UndoAction &) const override
size_t MemoryUsage() const override
Approximate memory footprint for budget enforcement.
bool CanMergeWith(const UndoAction &) const override
OverworldPropertyEdit before_
std::string Description() const override
Human-readable description (e.g., "Paint 12 tiles on map 5")
OverworldPropertyEdit after_
absl::Status Redo() override
OverworldMapPropertyEditAction(OverworldPropertyEdit before, OverworldPropertyEdit after, ApplyFn apply, std::string description)
absl::Status Undo() override
std::function< absl::Status(const OverworldPropertyEdit &)> ApplyFn
OverworldProjectLabelEditAction(std::string before, std::string after, ApplyFn apply, std::string description)
size_t MemoryUsage() const override
Approximate memory footprint for budget enforcement.
std::function< absl::Status(const std::string &)> ApplyFn
absl::Status Redo() override
bool CanMergeWith(const UndoAction &) const override
std::string Description() const override
Human-readable description (e.g., "Paint 12 tiles on map 5")
absl::Status Undo() override
Undoable action for painting tiles on the overworld map.
std::function< void()> refresh_fn_
size_t MemoryUsage() const override
Approximate memory footprint for budget enforcement.
void MergeWith(UndoAction &prev) override
bool CanMergeWith(const UndoAction &prev) const override
static constexpr int kMergeWindowMs
Merge window: consecutive paints within this duration become one step.
OverworldTilePaintAction(int map_id, int world, std::vector< OverworldTileChange > tile_changes, zelda3::Overworld *overworld, std::function< void()> refresh_fn)
std::string Description() const override
Human-readable description (e.g., "Paint 12 tiles on map 5")
std::vector< OverworldTileChange > tile_changes_
const std::vector< OverworldTileChange > & tile_changes() const
absl::Status Redo() override
zelda3::Overworld * overworld_
std::chrono::steady_clock::time_point timestamp_
absl::Status Undo() override
Abstract base for all undoable actions (Command pattern)
Represents the full Overworld data, light and dark world.
OverworldBlockset & GetMapTiles(int world_type)
#define RETURN_IF_ERROR(expr)
Snapshot of overworld item list + current item selection.
std::vector< zelda3::OverworldItem > items
std::optional< zelda3::OverworldItem > selected_item_identity
A single tile coordinate + old/new value pair for undo/redo.