feat: Introduce DungeonEditorV2 with component delegation for improved architecture

- Added DungeonEditorV2 to streamline dungeon editing by delegating tasks to specialized components.
- Implemented comprehensive integration tests to validate functionality and ensure proper ROM handling.
- Achieved 100% pass rate for all integration tests, enhancing reliability and performance of the editor.
- Updated test suite to include tests for the new editor, ensuring robust coverage and error handling.
This commit is contained in:
scawful
2025-10-04 14:32:56 -04:00
parent 31154daa71
commit 37e8e77376
8 changed files with 647 additions and 44 deletions

View File

@@ -0,0 +1,174 @@
#include "dungeon_editor_v2.h"
#include <cstdio>
#include "absl/strings/str_format.h"
#include "app/gfx/snes_palette.h"
#include "imgui/imgui.h"
namespace yaze::editor {
using ImGui::BeginTable;
using ImGui::BeginTabBar;
using ImGui::BeginTabItem;
using ImGui::EndTable;
using ImGui::EndTabBar;
using ImGui::EndTabItem;
using ImGui::TableHeadersRow;
using ImGui::TableNextColumn;
using ImGui::TableNextRow;
using ImGui::TableSetupColumn;
void DungeonEditorV2::Initialize() {
// No complex initialization needed - components handle themselves
}
absl::Status DungeonEditorV2::Load() {
if (!rom_ || !rom_->is_loaded()) {
return absl::FailedPreconditionError("ROM not loaded");
}
// Load all rooms using the loader component
RETURN_IF_ERROR(room_loader_.LoadAllRooms(rooms_));
RETURN_IF_ERROR(room_loader_.LoadRoomEntrances(entrances_));
// Load palette group
auto dungeon_main_pal_group = rom_->palette_group().dungeon_main;
current_palette_ = dungeon_main_pal_group[current_palette_group_id_];
ASSIGN_OR_RETURN(current_palette_group_,
gfx::CreatePaletteGroupFromLargePalette(current_palette_));
// Initialize components with loaded data
room_selector_.set_rooms(&rooms_);
room_selector_.set_entrances(&entrances_);
room_selector_.set_active_rooms(active_rooms_);
room_selector_.set_room_selected_callback(
[this](int room_id) { OnRoomSelected(room_id); });
canvas_viewer_.SetRooms(&rooms_);
canvas_viewer_.SetCurrentPaletteGroup(current_palette_group_);
canvas_viewer_.SetCurrentPaletteId(current_palette_id_);
object_selector_.SetCurrentPaletteGroup(current_palette_group_);
object_selector_.SetCurrentPaletteId(current_palette_id_);
object_selector_.set_rooms(&rooms_);
is_loaded_ = true;
return absl::OkStatus();
}
absl::Status DungeonEditorV2::Update() {
if (!is_loaded_) {
ImGui::Text("Loading...");
return absl::OkStatus();
}
DrawLayout();
return absl::OkStatus();
}
absl::Status DungeonEditorV2::Save() {
if (!rom_ || !rom_->is_loaded()) {
return absl::FailedPreconditionError("ROM not loaded");
}
// Save all rooms (SaveObjects will handle which ones need saving)
for (auto& room : rooms_) {
auto status = room.SaveObjects();
if (!status.ok()) {
// Log error but continue with other rooms
std::printf("Failed to save room: %s\n", status.message().data());
}
}
return absl::OkStatus();
}
void DungeonEditorV2::DrawLayout() {
// Simple 3-column layout as designed
if (BeginTable("##DungeonEditTable", 3,
ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersInnerV,
ImVec2(0, 0))) {
TableSetupColumn("Room Selector", ImGuiTableColumnFlags_WidthFixed, 250);
TableSetupColumn("Canvas", ImGuiTableColumnFlags_WidthStretch);
TableSetupColumn("Object Selector", ImGuiTableColumnFlags_WidthFixed, 300);
TableHeadersRow();
TableNextRow();
// Column 1: Room Selector (fully delegated)
TableNextColumn();
room_selector_.Draw();
// Column 2: Canvas (fully delegated)
TableNextColumn();
if (BeginTabBar("##RoomTabs")) {
for (int i = 0; i < active_rooms_.Size; i++) {
int room_id = active_rooms_[i];
bool open = true;
if (BeginTabItem(absl::StrFormat("Room %03X", room_id).c_str(), &open)) {
DrawRoomTab(room_id);
EndTabItem();
}
if (!open) {
active_rooms_.erase(active_rooms_.Data + i);
i--;
}
}
EndTabBar();
}
// Column 3: Object Selector (fully delegated)
TableNextColumn();
object_selector_.Draw();
EndTable();
}
}
void DungeonEditorV2::DrawRoomTab(int room_id) {
if (room_id < 0 || room_id >= static_cast<int>(rooms_.size())) {
ImGui::Text("Invalid room ID: %d", room_id);
return;
}
// Quick controls
ImGui::Text("Room %03X", room_id);
ImGui::SameLine();
if (ImGui::Button("Load Graphics")) {
(void)room_loader_.LoadAndRenderRoomGraphics(room_id, rooms_[room_id]);
}
ImGui::SameLine();
if (ImGui::Button("Save")) {
auto status = rooms_[room_id].SaveObjects();
if (!status.ok()) {
ImGui::TextColored(ImVec4(1, 0, 0, 1), "Save failed: %s",
status.message().data());
}
}
ImGui::Separator();
// Canvas - fully delegated to DungeonCanvasViewer
// DungeonCanvasViewer has DrawDungeonCanvas() method
canvas_viewer_.DrawDungeonCanvas(room_id);
}
void DungeonEditorV2::OnRoomSelected(int room_id) {
current_room_id_ = room_id;
// Check if already open
for (int i = 0; i < active_rooms_.Size; i++) {
if (active_rooms_[i] == room_id) {
return; // Already open
}
}
// Add new tab
active_rooms_.push_back(room_id);
room_selector_.set_active_rooms(active_rooms_);
}
} // namespace yaze::editor