yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
dungeon_editor_v2_room_edits.cc
Go to the documentation of this file.
2
3#include <functional>
4#include <map>
5#include <memory>
6#include <utility>
7#include <vector>
8
11#include "util/macro.h"
13
14namespace yaze::editor {
15namespace {
16
17class RoomMetadataAction final : public UndoAction {
18 public:
20 using States = std::vector<std::pair<int, Snapshot>>;
21 using Restore = std::function<absl::Status(const States&)>;
22 RoomMetadataAction(States before, States after, Restore restore)
23 : before_(std::move(before)),
24 after_(std::move(after)),
25 restore_(std::move(restore)) {}
26 absl::Status Undo() override { return restore_(before_); }
27 absl::Status Redo() override { return restore_(after_); }
28 std::string Description() const override {
29 if (before_.size() == 1) {
30 return absl::StrFormat("Edit room %03X properties",
31 before_.front().first);
32 }
33 return absl::StrFormat("Edit properties in %zu rooms", before_.size());
34 }
35 size_t MemoryUsage() const override {
36 size_t bytes =
37 (before_.size() + after_.size()) * sizeof(States::value_type);
38 for (const auto* states : {&before_, &after_}) {
39 for (const auto& [id, snapshot] : *states) {
40 bytes += snapshot.layer_merging.Name.capacity();
41 }
42 }
43 return bytes;
44 }
45
46 private:
47 States before_, after_;
49};
50
51} // namespace
52
53absl::Status DungeonEditorV2::EditRoomMetadata(int room_id,
54 const RoomMetadataEdit& edit) {
55 return EditRoomMetadataBatch({{room_id, edit}});
56}
57
59 const std::vector<RoomMetadataRequest>& requests) {
60 std::map<int, std::vector<RoomMetadataEdit>> room_edits;
61 for (const auto& request : requests) {
63 const auto* room = rooms_.GetIfLoaded(request.room_id);
64 if (!room || room->rom() != rom_) {
65 return absl::FailedPreconditionError("Room properties are not loaded");
66 }
67 room_edits[request.room_id].push_back(request.edit);
68 }
69
70 RoomMetadataAction::States before;
71 RoomMetadataAction::States after;
72 // Reuse the same model setters for planning, with no ROM or render resources.
73 // In particular, a batch may change a field and then restore its original
74 // value. Plan the final state before dirtying any real room or its history.
75 zelda3::Room staged;
76 for (const auto& [room_id, edits] : room_edits) {
77 const auto original =
79 staged.RestoreMetadataSnapshot(original);
80 for (const auto& edit : edits) {
82 }
83 auto planned = staged.CaptureMetadataSnapshot();
84 if (original != planned) {
85 before.emplace_back(room_id, original);
86 after.emplace_back(room_id, std::move(planned));
87 }
88 }
89 if (before.empty()) {
90 return absl::OkStatus();
91 }
94 undo_manager_.Push(std::make_unique<RoomMetadataAction>(
95 std::move(before), std::move(after),
96 [this](const RoomMetadataAction::States& states) {
97 return RestoreRoomMetadataBatch(states);
98 }));
99 return absl::OkStatus();
100}
101
103 const std::vector<std::pair<int, zelda3::Room::MetadataSnapshot>>& states) {
104 for (const auto& [room_id, snapshot] : states) {
105 const auto* room = rooms_.GetIfLoaded(room_id);
106 if (!room || room->rom() != rom_) {
107 return absl::FailedPreconditionError("Room properties are not loaded");
108 }
109 }
110 for (const auto& [room_id, snapshot] : states) {
111 rooms_.GetIfLoaded(room_id)->RestoreMetadataSnapshot(snapshot);
112 }
113 for (const auto& [room_id, snapshot] : states) {
115 }
116 // Refresh only the edited room, even when undo targets an offscreen room.
118 return absl::OkStatus();
119}
120
122 auto* room = rooms_.GetIfLoaded(room_id);
123 if (!room) {
124 return;
125 }
128 }
129
130 // A destination edit can change a graph centered on any neighboring room.
131 // Update existing viewers only: undo must not create a viewer or navigate.
132 auto refresh_viewer = [&](DungeonCanvasViewer* viewer, bool is_target) {
133 if (!viewer) {
134 return;
135 }
137 if (!is_target) {
138 return;
139 }
140 const int palette_id = room->ResolveDungeonPaletteId();
141 viewer->SetCurrentPaletteId(palette_id);
142 if (game_data_ && palette_id >= 0 &&
143 palette_id <
144 static_cast<int>(game_data_->palette_groups.dungeon_main.size())) {
148 /*force_refresh=*/true);
149 }
150 viewer->TriggerChangePing();
151 };
152 room_viewers_.ForEach(
153 [&](int id, std::unique_ptr<DungeonCanvasViewer>& viewer) {
154 refresh_viewer(viewer.get(), id == room_id);
155 });
156 for (auto* viewer :
158 const auto* ctx = viewer ? viewer->object_interaction()
160 .tile_handler()
161 .context()
162 : nullptr;
163 refresh_viewer(viewer, ctx && ctx->current_room_id == room_id);
164 }
165
166 if (current_room_id_ != room_id) {
167 return;
168 }
169 current_palette_id_ = room->ResolveDungeonPaletteId();
172 if (!game_data_ ||
174 return;
175 }
182 }
185 }
188 room_id, current_palette_group_);
189 }
190}
191
192} // namespace yaze::editor
InteractionContext * context() const
Get the interaction context.
DungeonObjectInteraction & object_interaction()
void SetCurrentPaletteGroup(const gfx::PaletteGroup &group, bool force_refresh=false)
util::LruCache< int, std::unique_ptr< DungeonCanvasViewer > > room_viewers_
gfx::PaletteGroup current_palette_group_
absl::Status EditRoomMetadataBatch(const std::vector< RoomMetadataRequest > &requests)
ObjectTileEditorPanel * object_tile_editor_panel_
ObjectSelectorContent * object_selector_panel_
absl::Status EditRoomMetadata(int room_id, const RoomMetadataEdit &edit)
std::unique_ptr< DungeonCanvasViewer > workbench_compare_viewer_
gui::PaletteEditorWidget palette_editor_
RoomGraphicsContent * room_graphics_panel_
class RoomTagEditorPanel * room_tag_editor_panel_
absl::Status RestoreRoomMetadataBatch(const std::vector< std::pair< int, zelda3::Room::MetadataSnapshot > > &states)
std::unique_ptr< DungeonCanvasViewer > workbench_viewer_
InteractionCoordinator & entity_coordinator()
Get the interaction coordinator for entity handling.
zelda3::Room * GetIfLoaded(int room_id)
UndoManager undo_manager_
Definition editor.h:371
void SetCurrentPaletteGroup(const gfx::PaletteGroup &group)
void SetCurrentPaletteGroupForRoom(int room_id, const gfx::PaletteGroup &group)
void SetCurrentPaletteGroup(const gfx::PaletteGroup &group)
Set the current palette group for graphics rendering.
Abstract base for all undoable actions (Command pattern)
Definition undo_action.h:20
void Push(std::unique_ptr< UndoAction > action)
size_t MemoryUsage() const override
Approximate memory footprint for budget enforcement.
std::string Description() const override
Human-readable description (e.g., "Paint 12 tiles on map 5")
void RestoreMetadataSnapshot(const MetadataSnapshot &snapshot)
Definition room.cc:886
MetadataSnapshot CaptureMetadataSnapshot() const
Definition room.cc:861
Editors are the view controllers for the application.
absl::Status ValidateRoomMetadataEdit(const RoomMetadataEdit &edit)
absl::Status ApplyRoomMetadataEdit(zelda3::Room &room, const RoomMetadataEdit &edit)
gfx::PaletteGroup BuildDungeonRenderPaletteGroupFromGameData(const gfx::SnesPalette &dungeon_palette, const GameData *game_data)
Definition room.cc:191
#define RETURN_IF_ERROR(expr)
Definition snes.cc:22
gfx::PaletteGroupMap palette_groups
Definition game_data.h:95