yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
dungeon_editor_v2.h
Go to the documentation of this file.
1#ifndef YAZE_APP_EDITOR_DUNGEON_EDITOR_V2_H
2#define YAZE_APP_EDITOR_DUNGEON_EDITOR_V2_H
3
4#include <array>
5#include <cstdint>
6#include <deque>
7#include <functional>
8#include <future>
9#include <memory>
10#include <optional>
11#include <string>
12#include <unordered_map>
13#include <utility>
14#include <vector>
15
16#include "absl/status/status.h"
17#include "absl/status/statusor.h"
18#include "absl/strings/str_format.h"
19#include "app/editor/editor.h"
29#include "dungeon_room_loader.h"
31#include "dungeon_room_store.h"
33#include "imgui/imgui.h"
35#include "rom/rom.h"
37#include "util/lru_cache.h"
38#include "util/stop_token.h"
41#include "zelda3/dungeon/room.h"
46#include "zelda3/game_data.h"
47
48namespace yaze {
49namespace editor {
50
51class CustomCollisionPanel;
52class DungeonEntrancesPanel;
53struct GraphicsEditContext;
54class DungeonEditorPaletteRefreshTestPeer;
55class DungeonEditorV2MinecartTrackTestPeer;
56class DungeonEditorV2MinecartNodeTestPeer;
57struct MinecartNodeBrush;
58class DungeonEditorV2ObjectTileEditorTestPeer;
59class DungeonEditorV2EntranceCameraTestPeer;
60class DungeonEditorEntrancePropertiesTestPeer;
61class DungeonEditorV2RegularEntranceTestPeer;
62class DungeonEditorV2ReloadTestPeer;
63class DungeonEditorV2ShortcutTestPeer;
64class DungeonEditorV2SpawnPointTestPeer;
65class DungeonEditorV2SpawnRejectionTestPeer;
66class MinecartTrackEditorPanel;
67struct MinecartCollisionStamp;
68struct MinecartTrack;
69class ObjectCoveragePanel;
70class ObjectTileEditorPanel;
71class OverlayManagerPanel;
72class PaletteEditorContent;
73class RoomTagEditorPanel;
74class RoomMatrixContent;
75class WaterFillPanel;
76
78 kUp,
79 kDown,
80 kLeft,
81 kRight,
82};
83
124class DungeonEditorV2 : public Editor {
125 public:
126 explicit DungeonEditorV2(Rom* rom = nullptr);
127
128 ~DungeonEditorV2() override;
129 // Visit loaded models using the dungeon canvas's entrance resolver.
131 const std::function<void(int, zelda3::Room&, const std::string&, bool,
132 int)>& visitor);
133 void PrepareForSessionTeardown() override;
134
137 dependencies_.game_data = game_data; // Also set base class dependency
141 }
143 dungeon_editor_system_->SetGameData(game_data);
144 }
146 // Note: Canvas viewer game data is set lazily in GetViewerForRoom
147 // but we should update existing viewers
148 room_viewers_.ForEach(
149 [game_data](int, std::unique_ptr<DungeonCanvasViewer>& viewer) {
150 if (viewer)
151 viewer->SetGameData(game_data);
152 });
153 if (workbench_viewer_) {
154 workbench_viewer_->SetGameData(game_data);
155 }
158 }
159 }
160
161 // Editor interface
162 void SetDependencies(const EditorDependencies& deps) override;
163 void Initialize() override;
164 absl::Status Load() override;
165 absl::Status Update() override;
166 absl::Status Undo() override;
167 absl::Status Redo() override;
168 absl::Status Cut() override;
169 absl::Status Copy() override;
170 absl::Status Paste() override;
171 absl::Status Find() override { return absl::UnimplementedError("Find"); }
172 // Undo() first finalizes pending gestures into history, so any pending
173 // snapshot makes Undo available even while undo_manager_ is still empty.
174 bool CanUndo() const override {
176 }
177 absl::Status Save() override;
178 // Reject excluded model edits before any writer runs. Apply Room narrows
179 // room-local streams; shared tables still include all pending room records.
180 // Dirty fixed headers in scope must not share storage with another room.
181 absl::Status ValidateSaveScope(int only_room = -1,
182 bool room_data_only = false) const;
183 absl::Status BeginSaveTransaction() override;
184 void RollbackSaveTransaction() override;
185 void CommitSaveTransaction() override;
186 void ContributeStatus(StatusBar* status_bar) override;
188 absl::Status SaveRoom(int room_id);
189 // Discrete room property edits share the dungeon undo history in both views.
190 absl::StatusOr<DungeonConnectionPlan> PreviewDoorConnection(
191 const DungeonConnectionRequest& request);
192 absl::Status ApplyDoorConnection(const DungeonConnectionPlan& plan);
193 absl::StatusOr<std::string> ExportRoomDocument(int room_id);
194 absl::StatusOr<DungeonRoomTransferPlan> PreviewRoomTransfer(
195 int target_room_id, int source_room_id, const std::string& json,
196 const DungeonRoomTransferOptions& options);
197 absl::Status ApplyRoomTransfer(const DungeonRoomTransferPlan& plan);
198 absl::Status EditRoomMetadata(int room_id, const RoomMetadataEdit& edit);
199 // Shared roomset assignment (background slots 3-6); zero inherits main.
200 absl::Status EditRoomGraphicsSheet(int room_id, int slot, int sheet_id);
201 // The owning EditorSet supplies an existing model only; usage queries must
202 // not create another editor or read another ROM session's window context.
204 std::function<const zelda3::Overworld*()> provider) {
205 room_graphics_overworld_provider_ = std::move(provider);
206 }
207 absl::StatusOr<zelda3::RoomsetUsageReport> GetRoomGraphicsUsage(
208 int roomset) const;
209 absl::Status EditRoomMetadataBatch(
210 const std::vector<RoomMetadataRequest>& requests);
211 absl::Status EditChest(int room_id, size_t index, uint8_t item_id,
212 bool big_chest);
213 absl::Status DeleteChest(int room_id, size_t index);
214 int LoadedRoomCount() const;
215 // Room-specific pending state used by room counts and room-level UI.
216 int PendingRoomCount() const;
217 bool HasPendingRoomChanges() const;
218 // All dungeon save domains plus unapplied editor-local work.
219 bool HasPendingDungeonChanges() const;
220 // Track source must be published separately from the ROM save domains.
223 absl::Status PrepareProjectSave();
224 // Rename (label) or reset (nullopt) a room's name in the active project.
225 absl::Status ApplyRoomLabelEdit(int room_id,
226 std::optional<std::string> label);
227 bool CurrentRoomHasPendingChanges() const;
228 int TotalRoomCount() const { return static_cast<int>(rooms_.size()); }
229
230 // Collect PC write ranges for all dirty/loaded rooms (for write conflict
231 // analysis). Returns pairs of (start_pc, end_pc) covering header and object
232 // regions that would be written during save.
233 std::vector<std::pair<uint32_t, uint32_t>> CollectWriteRanges() const;
234
235 // ROM management
236 void SetRom(Rom* rom) {
237 const bool rom_changed = rom_ != rom;
238 rom_ = rom;
242
243 // Propagate ROM to all rooms
245 // Reset viewers and copied room data on ROM change.
246 if (rom_changed) {
251 rooms_.Clear();
252 room_viewers_.Clear();
253 workbench_viewer_.reset();
256 }
257 }
258 // Reloads same-address ROM state in place so rooms, viewers, and workspace
259 // panel bindings retain stable addresses.
260 absl::Status RefreshRomBackedState();
261 Rom* rom() const { return rom_; }
262
263 // Room management
264 void add_room(int room_id);
265 // Opens the room of regular entrance `entrance_id` (0x00-0x84, the overworld
266 // entrance numbering) with that entrance's render context.
267 void OpenRegularEntrance(int entrance_id);
268 void FocusRoom(int room_id);
269 absl::Status LoadProposalForReview(const std::string& path);
270 std::string proposal_review_path() const;
271
272 // Agent/Automation controls
273 void SelectObject(int obj_id);
274 void SetAgentMode(bool enabled);
277 bool CycleRoomSelection(int direction);
278 // Select the next or previous room object in the active editable canvas.
279 bool CycleObjectSelection(int direction);
280
281 // ROM state
282 bool IsRomLoaded() const override { return rom_ && rom_->is_loaded(); }
283 std::string GetRomStatus() const override {
284 if (!rom_)
285 return "No ROM loaded";
286 if (!rom_->is_loaded())
287 return "ROM failed to load";
288 return absl::StrFormat("ROM loaded: %s", rom_->title());
289 }
290
291 // Open a workspace window by its id using WorkspaceWindowManager.
292 void OpenWindow(const std::string& window_id) {
295 }
296 }
297
298 // Create and register the project-only Minecart Tracks surface on demand.
299 // This supports enabling custom objects after the Dungeon editor has loaded.
300 absl::Status EnsureMinecartTrackEditorPanel();
301
302 // Explicit workflow toggle between integrated Workbench and standalone panels.
303 void SetWorkbenchWorkflowMode(bool enabled, bool show_toast = true);
304 // Queue a workflow mode change to run at a safe point in the next update.
305 void QueueWorkbenchWorkflowMode(bool enabled, bool show_toast = true);
306 // Queue a mode flip (Workbench <-> Standalone) for next update.
307 void ToggleWorkbenchWorkflowMode(bool show_toast = true);
308 bool IsWorkbenchWorkflowEnabled() const;
309
310 // ShortcutManager runs before this editor draws. Queue destructive keyboard
311 // actions so the room canvas can establish ownership for the current frame
312 // before the action is evaluated.
314
315 // Panel card IDs for programmatic access
316 static constexpr const char* kRoomSelectorId = "dungeon.room_selector";
317 static constexpr const char* kEntranceListId = "dungeon.entrance_list";
318 static constexpr const char* kRoomMatrixId = "dungeon.room_matrix";
319 static constexpr const char* kRoomGraphicsId = "dungeon.room_graphics";
320 static constexpr const char* kObjectSelectorId = "dungeon.object_selector";
321 static constexpr const char* kObjectToolsId = kObjectSelectorId;
322 static constexpr const char* kDoorEditorId = "dungeon.door_editor";
323 static constexpr const char* kPaletteEditorId = "dungeon.palette_editor";
324 static constexpr const char* kMinecartTrackEditorId =
325 "dungeon.minecart_tracks";
326
327 // Public accessors for WASM API and automation
330 const ImVector<int>& active_rooms() const {
332 }
334 const DungeonRoomStore& rooms() const { return rooms_; }
335 gfx::IRenderer* renderer() const { return renderer_; }
343
348 const std::deque<int>& GetRecentRooms() const { return recent_rooms_; }
349
350 private:
372 friend class
375 friend class
377 friend class
379 friend class
381 friend class
383 friend class
385 friend class
387 friend class
389 friend class
391
393
394 // Draw the Room Panels
395 void DrawRoomPanels();
396 void DrawRoomTab(int room_id);
397
398 // Texture processing (critical for rendering)
401
402 // Room selection callback
403 void OnRoomSelected(int room_id, bool request_focus = true);
404 void OnRoomSelected(int room_id, RoomSelectionIntent intent);
405 // Opens `room_id` and selects its placed object `object_index`. If the room
406 // changed since the index was built, falls back to the first object with
407 // `object_id`.
408 void NavigateToPlacedObject(int room_id, size_t object_index, int object_id);
409 // Object Coverage wiring, in dungeon_editor_v2_object_coverage.cc.
410 std::unique_ptr<ObjectCoveragePanel> CreateObjectCoveragePanel();
411 void FocusObjectCoverage(int room_id, const zelda3::RoomObject& object);
412 void OnEntranceSelected(int entrance_id);
413 void SetGraphicsPreviewEntrance(int entrance_id);
414 int ResolveEntranceRoomId(int entrance_id) const;
415
416 // Sync all sub-panels to the current room configuration
417 void SyncPanelsToRoom(int room_id);
419 void HandleArenaPaletteChanged(const std::string& group_name,
420 int palette_index);
424 uint8_t ResolveSelectedEntranceBlocksetForRoom(int room_id) const;
425 std::vector<DungeonRenderEntranceCandidate>
429 void ApplyEntranceRenderContext(int room_id);
430 void ConfigureViewerRenderContext(DungeonCanvasViewer* viewer, int room_id);
431 std::optional<DungeonEntranceCameraState> GetEntranceCameraState(
432 int slot_index) const;
433 absl::Status RepairEntranceCamera(int slot_index);
434 absl::Status RestoreEntranceCameraState(
435 int slot_index, const DungeonEntranceCameraState& state);
438 void RecordEntrancePropertyEdit(int slot_index,
439 const zelda3::RoomEntrance& before,
440 const zelda3::RoomEntrance& after,
441 std::shared_ptr<const int> gesture);
442 void RecordSpawnPropertyEdit(int slot_index,
443 const zelda3::DungeonSpawnPoint& before,
444 const zelda3::DungeonSpawnPoint& after,
445 std::shared_ptr<const int> gesture);
446 absl::Status RestoreEntranceProperties(int slot_index,
447 const zelda3::RoomEntrance& entrance);
448 absl::Status RestoreSpawnProperties(int slot_index,
449 const zelda3::DungeonSpawnPoint& spawn);
450 void RefreshEntranceDirtyState(int slot_index);
453 absl::Status ApplyMinecartTrackEdit(const MinecartTrack& before,
454 const MinecartTrack& after,
455 bool move_cart);
456 absl::StatusOr<std::unique_ptr<UndoAction>> PairMinecartObjectCollision(
457 int room_id, const std::vector<zelda3::RoomObject>& before,
458 const std::vector<zelda3::RoomObject>& after,
459 std::unique_ptr<UndoAction> object_action);
461 int room_id, const std::vector<zelda3::RoomObject>& objects) const;
462 absl::Status PlaceMinecartNode(int room_id, int tile_x, int tile_y,
463 const MinecartNodeBrush& brush);
465
466 // Show or create a standalone room panel
467 void ShowRoomPanel(int room_id);
468
469 // Convenience action for Settings panel.
470 void SaveAllRooms();
471
472 // Object placement callback
473 void HandleObjectPlaced(const zelda3::RoomObject& obj);
474 void OpenGraphicsEditorForObject(int room_id,
475 const zelda3::RoomObject& object);
476 // Supplies the detached art-candidate preview and its source revision.
478 GraphicsEditContext& context, int room_id,
479 std::function<absl::Status(GraphicsEditContext&)> resolve_live_source);
480 absl::Status OpenObjectTileEditorForObject(int room_id,
481 const zelda3::RoomObject& object);
482
483 // Helper to get or create a viewer for a specific room
485 // An explicitly open room panel keeps its own viewer even while the
486 // Workbench is the active workflow (for example, a pinned room panel).
490 void RefreshViewerRuntimeContext(DungeonCanvasViewer* viewer, int room_id,
491 bool rebind_project = false);
495 void TouchViewerLru(int room_id);
496 void RemoveViewerFromLru(int room_id);
497
498 absl::Status SaveRoomData(int room_id);
499 absl::Status SaveRoomImpl(int room_id, bool room_data_only);
500 // Fixed 14-byte room headers have no copy-on-write allocator. Refuse an
501 // in-place header write that would also change another room's header.
502 static absl::Status ValidateRoomHeaderOwnership(const Rom& rom, int room_id);
503 absl::Status RunWithSaveTransaction(
504 const std::function<absl::Status()>& operation);
505
506 // Data
510 std::array<zelda3::RoomEntrance, zelda3::kNumDungeonEntranceSlots> entrances_;
511 std::array<zelda3::DungeonSpawnPoint, zelda3::kNumDungeonSpawnPoints>
513 mutable std::optional<zelda3::RoomCensus> dungeon_render_context_census_;
514 mutable std::future<absl::StatusOr<zelda3::RoomCensus>>
523
525 std::vector<std::pair<int, zelda3::Room::SaveDirtySnapshot>> room_states;
526 std::array<bool, zelda3::kNumDungeonEntranceSlots> entrance_dirty_states{};
527 std::array<bool, zelda3::kNumDungeonSpawnPoints> spawn_dirty_states{};
529 bool pit_damage_dirty = false;
531 };
532 std::optional<SaveTransactionSnapshot> save_transaction_snapshot_;
534
536
537 // Current selection state
538 // Combined slots begin with spawn points; regular Entrance 00 follows them.
541
542 // Active room tabs and card tracking for jump-to
543 ImVector<int> active_rooms_;
545
546 // Recent rooms history for quick navigation (most recent first, max 10)
547 static constexpr size_t kMaxRecentRooms = 10;
548 std::deque<int> recent_rooms_;
549 std::vector<int> pinned_rooms_;
550
551 // Workbench panel pointer (owned by WorkspaceWindowManager, stored for notifications).
555
556 // Palette management
562
563 // Components - these do all the work
566 static constexpr int kMaxCachedViewers = 20;
567 // Shared by this editor's room panels, never by other ROM sessions.
571 std::unique_ptr<DungeonCanvasViewer> workbench_viewer_;
572 std::unique_ptr<DungeonCanvasViewer> workbench_compare_viewer_;
573
575 // Panel pointers. WorkspaceWindowManager owns these when available; fallback
576 // unique_ptrs keep non-workspace tests and direct embedding paths alive.
577 // Workbench mode embeds room-local utilities in the Tools inspector. Their
578 // standalone entries remain discoverable, but one content instance has only
579 // one active presentation owner at a time.
594
595 // Owned content fields are fallbacks for tests without WorkspaceWindowManager.
596 std::unique_ptr<ObjectSelectorContent> owned_object_selector_panel_;
597 std::unique_ptr<DoorEditorContent> owned_door_editor_panel_;
598 std::unique_ptr<RoomTagEditorPanel> owned_room_tag_editor_panel_;
599 std::unique_ptr<ObjectCoveragePanel> owned_object_coverage_panel_;
600 std::unique_ptr<CustomCollisionPanel> owned_custom_collision_panel_;
601 std::unique_ptr<WaterFillPanel> owned_water_fill_panel_;
602 std::unique_ptr<MinecartTrackEditorPanel> owned_minecart_track_editor_panel_;
603 std::unique_ptr<zelda3::DungeonEditorSystem> dungeon_editor_system_;
604 std::unique_ptr<emu::render::EmulatorRenderService> render_service_;
605
606 bool is_loaded_ = false;
609
610 // Docking class for room windows to dock together
611 ImGuiWindowClass room_window_class_;
612
613 // Shared dock ID for all room panels to auto-dock together
614 ImGuiID room_dock_id_ = 0;
615
616 // Dynamic room cards - created per open room
617 std::unordered_map<int, std::shared_ptr<gui::PanelWindow>> room_cards_;
618
619 // Stable window slot mapping: room_id -> slot_id.
620 // Slot IDs are used in the "###" part of the window title so ImGui treats the
621 // window as the same entity even when its displayed room changes.
623 std::unordered_map<int, int> room_panel_slot_ids_;
624
625 // Pending undo snapshot: captured on mutation callback (before edit),
626 // finalized on cache invalidation callback (after edit) by pushing an undo
627 // action to the inherited undo_manager_.
628 struct PendingUndo {
629 int room_id = -1;
630 std::vector<zelda3::RoomObject> before_objects;
631 std::vector<chest_data> before_chests;
632 std::vector<size_t> before_selection;
634 };
636 // Ownership is deliberately session-local. Imported collision never becomes
637 // disposable merely because its value resembles a generated rail.
638 std::unordered_map<int, zelda3::MinecartTrackCollisionOwnership>
641 bool has_pending_undo_ = false;
643
645 std::optional<DungeonSelectionEditPlan> plan;
647 };
649
654 // Doors, sprites and pot items can be dragged together; keep each domain's
655 // original snapshot until its corresponding completion notification.
656 std::array<PendingEntityUndo, 3> pending_entity_undo_;
657
663
669
670 // True while any gesture snapshot is waiting for FinalizePendingUndoActions.
674 pending_selection_undo_.plan.has_value()) {
675 return true;
676 }
677 for (const auto& pending : pending_entity_undo_) {
678 if (pending.room_id >= 0) {
679 return true;
680 }
681 }
682 return false;
683 }
684
685 // Pending room swap (deferred until after draw phase completes)
686 struct PendingSwap {
687 int old_room_id = -1;
688 int new_room_id = -1;
689 bool pending = false;
690 };
692
694 bool enabled = false;
695 bool show_toast = true;
696 bool pending = false;
697 };
699
700 // Opening or focusing a standalone tool mutates WorkspaceWindowManager and
701 // Dear ImGui focus state. Workbench buttons are drawn inside child windows,
702 // so defer that mutation to the next Update() safe point. Capture the
703 // originating session so a session switch cannot redirect the request.
705 size_t session_id = 0;
706 std::string window_id;
707 bool pending = false;
708 };
710
711 // Unpinned room-navigation panels hidden by the most recent transition into
712 // the integrated Workbench. Standalone editing tools remain user-owned and
713 // are never added to this restoration set.
715
716 // Two-phase undo capture: BeginUndoSnapshot saves state before mutation,
717 // FinalizeUndoAction captures state after mutation and pushes the action.
718 void BeginUndoSnapshot(int room_id);
719 void FinalizeUndoAction(int room_id);
720 absl::Status RestoreRoomObjects(
721 int room_id, const std::vector<zelda3::RoomObject>& objects,
722 const std::vector<size_t>& selected_indices,
723 const std::vector<chest_data>& chests);
724 absl::Status PreflightObjectMutation(
725 int room_id, const std::vector<zelda3::RoomObject>& objects,
726 const std::vector<chest_data>& chests, bool check_streams = true);
727 absl::Status PreflightStreamMutation(
728 int room_id, const DungeonSelectionEditState& candidate, uint8_t domains);
729 absl::Status PreflightSpriteMutation(
730 int room_id, const std::vector<zelda3::Sprite>& sprites);
731 absl::Status PreflightPotItemPlacement(
732 int room_id, const std::vector<zelda3::PotItem>& items);
733 absl::StatusOr<std::vector<std::pair<uint32_t, uint32_t>>>
735 const std::vector<DungeonSelectionEditPlan>& candidates) const;
736 absl::Status PreflightDoorMutation(
737 int room_id, const std::vector<zelda3::Room::Door>& doors);
738 absl::Status ApplyChestObjectEdit(
739 int room_id, const std::vector<zelda3::RoomObject>& objects,
740 const std::vector<chest_data>& chests,
741 const std::vector<size_t>& selection);
742
743 absl::Status CommitSelectionEdit(const DungeonSelectionEditPlan& plan,
744 bool continuous);
746 absl::Status RestoreSelectionEditBatch(
747 const std::vector<DungeonSelectionEditPlan>& plans, bool after);
748 absl::Status EnsureConnectionRoomLoaded(int room_id);
749 absl::Status EnsureRoomTransferLoaded(int room_id);
750 absl::Status PreflightRoomTransfer(const DungeonRoomTransferPlan& plan);
751 absl::Status RestoreRoomTransfer(int room_id,
752 const DungeonRoomDocument& document);
753 void RefreshSelectionEditViews(int room_id,
754 const DungeonSelectionEditState* selection);
756 void PushSelectionUndoBatch(std::vector<DungeonSelectionEditPlan> plans,
757 std::string description);
760 absl::Status RestoreRoomMetadataBatch(
761 const std::vector<std::pair<int, zelda3::Room::MetadataSnapshot>>&
762 states);
763 absl::Status RestoreChest(int room_id, size_t index, chest_data chest);
764 void RefreshRoomMetadataViews(int room_id);
766 void BeginEntityUndoSnapshot(int room_id, MutationDomain domain);
767 void FinalizeEntityUndoAction(int room_id, MutationDomain domain);
769 absl::Status RestoreRoomEntities(int room_id, MutationDomain domain,
770 const DungeonEntitySnapshot& snapshot);
771
773 void BeginCollisionUndoSnapshot(int room_id);
774 void FinalizeCollisionUndoAction(int room_id);
775 void RestoreRoomCustomCollision(int room_id,
776 const zelda3::CustomCollisionMap& map);
777 absl::Status ApplyMinecartCollisionStamp(
778 int room_id, const zelda3::CustomCollisionMap& expected,
779 const MinecartCollisionStamp& stamp);
780 absl::Status ApplyMinecartCollisionBatch(
781 const std::vector<zelda3::TrackCollisionResult>& preview,
782 const zelda3::GeneratorOptions& options);
784 const std::vector<zelda3::CustomCollisionRoomEntry>& entries);
786 const std::vector<DungeonCustomCollisionSnapshot>& snapshots);
787
788 void BeginWaterFillUndoSnapshot(int room_id);
789 void FinalizeWaterFillUndoAction(int room_id);
790 void RestoreRoomWaterFill(int room_id, const WaterFillSnapshot& snap);
791 void SwapRoomInPanel(int old_room_id, int new_room_id);
792 void ProcessPendingSwap(); // Process deferred swap after draw
795
796 // Room panel slot IDs provide stable ImGui window IDs across "swap room in
797 // panel" navigation. This keeps the window position/dock state when the room
798 // changes via the directional arrows.
799 int GetOrCreateRoomPanelSlotId(int room_id);
800 void ReleaseRoomPanelSlotId(int room_id);
801
802 // Defensive guard: returns true iff room_id is within the valid range
803 // [0, kNumberOfRooms). Use this instead of open-coded range checks.
804 static bool IsValidRoomId(int room_id) {
805 return room_id >= 0 && room_id < zelda3::kNumberOfRooms;
806 }
807};
808
809} // namespace editor
810} // namespace yaze
811
812#endif // YAZE_APP_EDITOR_DUNGEON_EDITOR_V2_H
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
Definition rom.h:52
bool is_loaded() const
Definition rom.h:199
auto title() const
Definition rom.h:211
DungeonEditorV2 - Simplified dungeon editor using component delegation.
class MinecartTrackEditorPanel * minecart_track_editor_panel_
EditorContextSnapshot BuildContextSnapshot() const override
std::optional< zelda3::RoomCensus > dungeon_render_context_census_
std::string proposal_review_path() const
DungeonRenderContext ResolveDungeonRenderContextForRoom(int room_id) const
absl::Status ApplyCustomCollisionImportBatch(const std::vector< zelda3::CustomCollisionRoomEntry > &entries)
absl::Status EditRoomGraphicsSheet(int room_id, int slot, int sheet_id)
absl::Status RestoreEntranceCameraState(int slot_index, const DungeonEntranceCameraState &state)
friend class DungeonEditorV2SpawnRejectionTestPeer
friend class DungeonEditorEntrancePropertiesTestPeer
std::unique_ptr< CustomCollisionPanel > owned_custom_collision_panel_
friend class DungeonEditorV2MinecartTrackTestPeer
class CustomCollisionPanel * custom_collision_panel_
void ConfigureViewerUndoHooks(DungeonCanvasViewer *viewer)
std::function< const zelda3::Overworld *()> room_graphics_overworld_provider_
std::optional< int > room_canvas_delete_shortcut_frame_
friend class DungeonEditorV2RegularEntranceTestPeer
friend class DungeonEditorV2RomSafetyTest_SaveAllRoomsRollsBackEarlierWritesOnLateFailure_Test
friend class DungeonEditorPaletteRefreshTest_CachedRoomRefreshesThroughViewerCompositePreparation_Test
absl::Status PreflightObjectMutation(int room_id, const std::vector< zelda3::RoomObject > &objects, const std::vector< chest_data > &chests, bool check_streams=true)
void RefreshViewerRuntimeContext(DungeonCanvasViewer *viewer, int room_id, bool rebind_project=false)
absl::Status PreflightRoomTransfer(const DungeonRoomTransferPlan &plan)
void ToggleWorkbenchWorkflowMode(bool show_toast=true)
friend class DungeonEditorPaletteRefreshTest_SharedHudEditRefreshesRoomUsingDifferentDungeonPalette_Test
void RestoreRoomWaterFill(int room_id, const WaterFillSnapshot &snap)
absl::Status RestoreRoomEntities(int room_id, MutationDomain domain, const DungeonEntitySnapshot &snapshot)
void ContributeStatus(StatusBar *status_bar) override
void OpenGraphicsEditorForObject(int room_id, const zelda3::RoomObject &object)
absl::Status OpenObjectTileEditorForObject(int room_id, const zelda3::RoomObject &object)
class ItemEditorPanel * item_editor_panel_
std::unique_ptr< RoomTagEditorPanel > owned_room_tag_editor_panel_
class ObjectCoveragePanel * object_coverage_panel_
std::unique_ptr< ObjectCoveragePanel > CreateObjectCoveragePanel()
absl::StatusOr< zelda3::RoomsetUsageReport > GetRoomGraphicsUsage(int roomset) const
absl::Status ApplyRoomLabelEdit(int room_id, std::optional< std::string > label)
void SetDependencies(const EditorDependencies &deps) override
void BeginEntityUndoSnapshot(int room_id, MutationDomain domain)
std::unique_ptr< ObjectCoveragePanel > owned_object_coverage_panel_
ObjectSelectorContent * object_selector_panel() const
absl::Status ApplyRoomTransfer(const DungeonRoomTransferPlan &plan)
util::LruCache< int, std::unique_ptr< DungeonCanvasViewer > > room_viewers_
gfx::PaletteGroup current_palette_group_
void OnEntranceSelected(int entrance_id)
static constexpr const char * kEntranceListId
DungeonEntitySnapshot CaptureRoomEntities(int room_id, MutationDomain domain)
absl::Status CommitSelectionEdit(const DungeonSelectionEditPlan &plan, bool continuous)
friend class DungeonEditorV2EntranceCameraTestPeer
PendingStandaloneToolWindow pending_standalone_tool_window_
class SpriteEditorPanel * sprite_editor_panel_
void HandleObjectPlaced(const zelda3::RoomObject &obj)
std::string GetRomStatus() const override
DoorEditorContent * door_editor_panel() const
std::unique_ptr< zelda3::DungeonEditorSystem > dungeon_editor_system_
std::array< zelda3::RoomEntrance, zelda3::kNumDungeonEntranceSlots > entrances_
void OpenWindow(const std::string &window_id)
absl::Status PreflightPotItemPlacement(int room_id, const std::vector< zelda3::PotItem > &items)
friend class DungeonEditorV2ObjectTileEditorTestPeer
DoorEditorContent * door_editor_panel_
absl::Status ApplyDoorConnection(const DungeonConnectionPlan &plan)
absl::Status LoadProposalForReview(const std::string &path)
std::unordered_map< int, int > room_panel_slot_ids_
void OpenRegularEntrance(int entrance_id)
friend class DungeonEditorV2RomSafetyTest_UndoSnapshotLeakDetection_Test
absl::Status EditRoomMetadataBatch(const std::vector< RoomMetadataRequest > &requests)
class DungeonWorkbenchContent * workbench_panel_
int ResolveEntranceRoomId(int entrance_id) const
absl::Status ValidateSaveScope(int only_room=-1, bool room_data_only=false) const
friend class DungeonEditorV2RomSafetyTest_ViewerCacheLRUEviction_Test
void OnRoomSelected(int room_id, bool request_focus=true)
void RefreshSelectionEditViews(int room_id, const DungeonSelectionEditState *selection)
absl::Status ApplyMinecartCollisionStamp(int room_id, const zelda3::CustomCollisionMap &expected, const MinecartCollisionStamp &stamp)
absl::StatusOr< std::vector< std::pair< uint32_t, uint32_t > > > PlanPendingRoomStreamRanges(const std::vector< DungeonSelectionEditPlan > &candidates) const
friend class DungeonEditorV2RomSafetyTest_ViewerCacheNeverEvictsActiveRooms_Test
std::optional< DungeonEntranceCameraState > GetEntranceCameraState(int slot_index) const
absl::Status RestoreEntranceProperties(int slot_index, const zelda3::RoomEntrance &entrance)
void FinalizeEntityUndoAction(int room_id, MutationDomain domain)
PendingCollisionUndo pending_collision_undo_
void FocusObjectCoverage(int room_id, const zelda3::RoomObject &object)
void ConfigureEntrancePropertyEditCallbacks(DungeonEntrancesPanel *panel)
ObjectTileEditorPanel * object_tile_editor_panel_
absl::Status PreflightDoorMutation(int room_id, const std::vector< zelda3::Room::Door > &doors)
ObjectSelectorContent * object_selector_panel_
OverlayManagerPanel * overlay_manager_panel_
static absl::Status ValidateRoomHeaderOwnership(const Rom &rom, int room_id)
absl::Status RestoreRoomObjects(int room_id, const std::vector< zelda3::RoomObject > &objects, const std::vector< size_t > &selected_indices, const std::vector< chest_data > &chests)
uint8_t ResolveSelectedEntranceBlocksetForRoom(int room_id) const
absl::Status PreflightSpriteMutation(int room_id, const std::vector< zelda3::Sprite > &sprites)
DungeonCanvasViewer * GetWorkbenchCompareViewer(int room_id)
void ConfigureStagedGraphicsPreview(GraphicsEditContext &context, int room_id, std::function< absl::Status(GraphicsEditContext &)> resolve_live_source)
bool CycleObjectSelection(int direction)
void WireViewerPanelCallbacks(DungeonCanvasViewer *viewer)
absl::Status RestoreSelectionEditBatch(const std::vector< DungeonSelectionEditPlan > &plans, bool after)
absl::Status EditRoomMetadata(int room_id, const RoomMetadataEdit &edit)
gfx::IRenderer * renderer() const
std::vector< DungeonRenderEntranceCandidate > BuildDungeonRenderEntranceCandidates() const
std::unique_ptr< DungeonCanvasViewer > workbench_compare_viewer_
PendingWaterFillUndo pending_water_fill_undo_
RoomMatrixContent * room_matrix_panel_
std::unique_ptr< MinecartTrackEditorPanel > owned_minecart_track_editor_panel_
absl::Status ApplyMinecartTrackEdit(const MinecartTrack &before, const MinecartTrack &after, bool move_cart)
void SetGraphicsPreviewEntrance(int entrance_id)
std::array< PendingEntityUndo, 3 > pending_entity_undo_
bool IsRomLoaded() const override
gui::PaletteEditorWidget palette_editor_
std::unique_ptr< DoorEditorContent > owned_door_editor_panel_
const std::deque< int > & GetRecentRooms() const
Get the list of recently visited room IDs.
bool ConsumeRoomCanvasDeleteShortcut(DungeonCanvasViewer &viewer)
static bool IsValidRoomId(int room_id)
void VisitGraphicsUsageRooms(const std::function< void(int, zelda3::Room &, const std::string &, bool, int)> &visitor)
void SwapRoomInPanel(int old_room_id, int new_room_id)
void RecordEntrancePropertyEdit(int slot_index, const zelda3::RoomEntrance &before, const zelda3::RoomEntrance &after, std::shared_ptr< const int > gesture)
RoomGraphicsContent * room_graphics_panel_
absl::Status RunWithSaveTransaction(const std::function< absl::Status()> &operation)
const DungeonRoomStore & rooms() const
static constexpr int kMaxCachedViewers
static constexpr size_t kMaxRecentRooms
std::array< zelda3::DungeonSpawnPoint, zelda3::kNumDungeonSpawnPoints > spawn_points_
void SetWorkbenchWorkflowMode(bool enabled, bool show_toast=true)
const zelda3::RoomCensus * GetDungeonRenderContextCensus() const
class RoomTagEditorPanel * room_tag_editor_panel_
std::optional< SaveTransactionSnapshot > save_transaction_snapshot_
std::unique_ptr< ObjectSelectorContent > owned_object_selector_panel_
absl::StatusOr< std::unique_ptr< UndoAction > > PairMinecartObjectCollision(int room_id, const std::vector< zelda3::RoomObject > &before, const std::vector< zelda3::RoomObject > &after, std::unique_ptr< UndoAction > object_action)
friend class DungeonEditorV2RomSafetyTest_ViewerCacheLRUAccessOrderUpdate_Test
friend class DungeonEditorPaletteRefreshTest_CompareViewerScopesEntranceContextToRequestedRoom_Test
static constexpr const char * kDoorEditorId
friend class DungeonEditorV2RomSafetyTest_LateCoordinatorRollbackRestoresEntranceDirtyState_Test
static constexpr const char * kObjectToolsId
DungeonCanvasViewer * GetViewerForRoom(int room_id)
PendingSelectionUndo pending_selection_undo_
void SetRoomGraphicsOverworldProvider(std::function< const zelda3::Overworld *()> provider)
absl::StatusOr< std::string > ExportRoomDocument(int room_id)
class WaterFillPanel * water_fill_panel_
std::future< absl::StatusOr< zelda3::RoomCensus > > dungeon_render_context_census_pending_
absl::Status RestoreRoomCustomCollisionBatch(const std::vector< DungeonCustomCollisionSnapshot > &snapshots)
absl::Status Find() override
bool NavigateToAdjacentRoom(DungeonRoomNavigationDirection direction)
friend class DungeonEditorPaletteRefreshTest_DungeonMainEditRefreshesResolvedAliasesOnly_Test
absl::Status PreflightMinecartObjectCollision(int room_id, const std::vector< zelda3::RoomObject > &objects) const
ObjectSelectorContent * object_editor_panel() const
std::unique_ptr< emu::render::EmulatorRenderService > render_service_
DungeonCanvasViewer * GetWorkbenchViewer()
std::unordered_map< int, std::shared_ptr< gui::PanelWindow > > room_cards_
absl::Status DeleteChest(int room_id, size_t index)
void ApplyEntranceRenderContext(int room_id)
void SetGameData(zelda3::GameData *game_data) override
friend class DungeonEditorV2RomSafetyTest_ObjectStreamUndoRedoRestoresSelectionIdentity_Test
absl::Status RestoreRoomMetadataBatch(const std::vector< std::pair< int, zelda3::Room::MetadataSnapshot > > &states)
static constexpr const char * kObjectSelectorId
absl::StatusOr< DungeonRoomTransferPlan > PreviewRoomTransfer(int target_room_id, int source_room_id, const std::string &json, const DungeonRoomTransferOptions &options)
void ConfigureViewerRenderContext(DungeonCanvasViewer *viewer, int room_id)
static constexpr const char * kRoomGraphicsId
void QueueWorkbenchWorkflowMode(bool enabled, bool show_toast=true)
static constexpr const char * kRoomMatrixId
void HandleDungeonPaletteChanged(gui::DungeonPaletteChange change)
static constexpr const char * kRoomSelectorId
const ImVector< int > & active_rooms() const
void ConfigureEditableViewer(DungeonCanvasViewer *viewer)
PaletteEditorContent * palette_editor_panel_
static constexpr const char * kMinecartTrackEditorId
DungeonSelectionClipboard selection_clipboard_
std::unique_ptr< DungeonCanvasViewer > workbench_viewer_
absl::Status PlaceMinecartNode(int room_id, int tile_x, int tile_y, const MinecartNodeBrush &brush)
void RestoreRoomCustomCollision(int room_id, const zelda3::CustomCollisionMap &map)
absl::Status SaveRoomImpl(int room_id, bool room_data_only)
void RecordSpawnPropertyEdit(int slot_index, const zelda3::DungeonSpawnPoint &before, const zelda3::DungeonSpawnPoint &after, std::shared_ptr< const int > gesture)
util::StopSource dungeon_render_context_census_stop_
absl::Status PreflightStreamMutation(int room_id, const DungeonSelectionEditState &candidate, uint8_t domains)
absl::Status RestoreChest(int room_id, size_t index, chest_data chest)
absl::Status EditChest(int room_id, size_t index, uint8_t item_id, bool big_chest)
absl::Status ApplyChestObjectEdit(int room_id, const std::vector< zelda3::RoomObject > &objects, const std::vector< chest_data > &chests, const std::vector< size_t > &selection)
DungeonCanvasViewer * GetStandaloneViewerForRoom(int room_id)
std::unordered_map< int, zelda3::MinecartTrackCollisionOwnership > minecart_collision_ownership_
absl::Status RestoreSpawnProperties(int slot_index, const zelda3::DungeonSpawnPoint &spawn)
std::vector< std::pair< uint32_t, uint32_t > > CollectWriteRanges() const
std::unique_ptr< WaterFillPanel > owned_water_fill_panel_
absl::Status ApplyMinecartCollisionBatch(const std::vector< zelda3::TrackCollisionResult > &preview, const zelda3::GeneratorOptions &options)
absl::Status RestoreRoomTransfer(int room_id, const DungeonRoomDocument &document)
DungeonEntrancesPanel * entrance_navigator_panel_
absl::StatusOr< DungeonConnectionPlan > PreviewDoorConnection(const DungeonConnectionRequest &request)
static constexpr const char * kPaletteEditorId
void PushSelectionUndoBatch(std::vector< DungeonSelectionEditPlan > plans, std::string description)
void PushSelectionUndoAction(DungeonSelectionEditPlan plan)
PendingWorkflowMode pending_workflow_mode_
void InvalidateDungeonPaletteUsers(gui::DungeonPaletteChange change)
void HandleArenaPaletteChanged(const std::string &group_name, int palette_index)
std::vector< std::string > workbench_suspended_navigation_window_ids_
void NavigateToPlacedObject(int room_id, size_t object_index, int object_id)
WindowContent for displaying and editing dungeon entrances.
Manages loading and saving of dungeon room data.
void SetGameData(zelda3::GameData *game_data)
Handles room and entrance selection UI.
const ImVector< int > & active_rooms() const
void set_current_entrance_id(int entrance_id)
void SetGameData(zelda3::GameData *game_data)
Interface for editor classes.
Definition editor.h:252
EditorContext context() const
Definition editor.h:376
UndoManager undo_manager_
Definition editor.h:383
zelda3::GameData * game_data() const
Definition editor.h:369
EditorDependencies dependencies_
Definition editor.h:382
WindowContent for placing and managing dungeon pot items.
Checklist for proving each dungeon object draws like the game.
Browse and place dungeon objects.
void SetGameData(zelda3::GameData *game_data)
Panel for editing the tile8 composition of dungeon objects.
WindowContent wrapper for PaletteEditorWidget in dungeon context.
WindowContent for displaying room graphics blocks.
WindowContent for displaying a visual 16x19 grid of all dungeon rooms.
WindowContent showing all room tag slots and their usage across rooms.
WindowContent for placing and managing dungeon sprites.
A session-aware status bar displayed at the bottom of the application.
Definition status_bar.h:57
bool OpenWindow(size_t session_id, const std::string &base_window_id)
Defines an abstract interface for all rendering operations.
Definition irenderer.h:60
Represents a palette of colors for the Super Nintendo Entertainment System (SNES).
Dungeon Room Entrance or Spawn Point.
MutationDomain
Domain/type of mutation for undo + invalidation routing.
RoomSelectionIntent
Intent for room selection in the dungeon editor.
constexpr NoStopStateTag kNoStopState
Definition stop_token.h:11
constexpr int kNumDungeonSpawnPoints
constexpr int kNumberOfRooms
Legacy chest data structure.
Definition zelda.h:438
Treasure chest.
Definition zelda.h:425
std::optional< DungeonSelectionEditPlan > plan
zelda3::Room::SaveDirtySnapshot dirty_before
std::vector< zelda3::RoomObject > before_objects
std::vector< std::pair< int, zelda3::Room::SaveDirtySnapshot > > room_states
std::array< bool, zelda3::kNumDungeonSpawnPoints > spawn_dirty_states
std::array< bool, zelda3::kNumDungeonEntranceSlots > entrance_dirty_states
Unified dependency container for all editor types.
Definition editor.h:170
zelda3::GameData * game_data
Definition editor.h:173
WorkspaceWindowManager * window_manager
Definition editor.h:182
Represents a group of palettes.