From a256b589ac1e7d71b91f363dc5684649177af280 Mon Sep 17 00:00:00 2001 From: scawful Date: Sun, 28 Dec 2025 09:50:46 -0600 Subject: [PATCH] imgui-frontend-engineer: fix merge blockers in graphics/dungeon map --- src/app/editor/graphics/graphics_editor.cc | 25 ++++++++++++++++++- .../editor/graphics/graphics_editor_state.h | 9 +++++++ src/core/asar_wrapper.cc | 1 + src/zelda3/screen/dungeon_map.cc | 18 +++++++------ 4 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/app/editor/graphics/graphics_editor.cc b/src/app/editor/graphics/graphics_editor.cc index c604f85d..932297f3 100644 --- a/src/app/editor/graphics/graphics_editor.cc +++ b/src/app/editor/graphics/graphics_editor.cc @@ -4,6 +4,7 @@ // C++ standard library headers #include #include +#include // Third-party library headers #include "absl/status/status.h" @@ -209,6 +210,8 @@ absl::Status GraphicsEditor::Save() { state_.modified_sheets.size()); auto& sheets = gfx::Arena::Get().gfx_sheets(); + std::set saved_sheets; + std::vector skipped_sheets; for (uint16_t sheet_id : state_.modified_sheets) { if (sheet_id >= zelda3::kNumGfxSheets) continue; @@ -230,6 +233,20 @@ absl::Status GraphicsEditor::Save() { compressed = false; } + if (bpp == 2) { + const size_t expected_size = + gfx::kTilesheetWidth * gfx::kTilesheetHeight * 2; + const size_t actual_size = sheet.vector().size(); + if (actual_size < expected_size) { + LOG_WARN( + "GraphicsEditor", + "Skipping 2BPP sheet %02X save (expected %zu bytes, got %zu)", + sheet_id, expected_size, actual_size); + skipped_sheets.push_back(sheet_id); + continue; + } + } + // Calculate ROM offset for this sheet // Get version constants from game_data auto version_constants = zelda3::kVersionConstantsMap.at(game_data()->version); @@ -288,10 +305,16 @@ absl::Status GraphicsEditor::Save() { LOG_INFO("GraphicsEditor", "Saved sheet %02X (%zu bytes, %s) at offset %06X", sheet_id, final_data.size(), compressed ? "compressed" : "raw", offset); + saved_sheets.insert(sheet_id); } // Clear modified tracking after successful save - state_.ClearModifiedSheets(); + state_.ClearModifiedSheets(saved_sheets); + if (!skipped_sheets.empty()) { + return absl::FailedPreconditionError( + absl::StrCat("Skipped ", skipped_sheets.size(), + " 2BPP sheet(s); full data unavailable.")); + } return absl::OkStatus(); } diff --git a/src/app/editor/graphics/graphics_editor_state.h b/src/app/editor/graphics/graphics_editor_state.h index 2d29f111..eca9e8fe 100644 --- a/src/app/editor/graphics/graphics_editor_state.h +++ b/src/app/editor/graphics/graphics_editor_state.h @@ -139,6 +139,15 @@ class GraphicsEditorState { */ void ClearModifiedSheets() { modified_sheets.clear(); } + /** + * @brief Clear specific sheets from modification tracking + */ + void ClearModifiedSheets(const std::set& sheet_ids) { + for (auto sheet_id : sheet_ids) { + modified_sheets.erase(sheet_id); + } + } + /** * @brief Check if any sheets have unsaved changes */ diff --git a/src/core/asar_wrapper.cc b/src/core/asar_wrapper.cc index 311dcf84..8cce86fc 100644 --- a/src/core/asar_wrapper.cc +++ b/src/core/asar_wrapper.cc @@ -414,6 +414,7 @@ absl::StatusOr AsarWrapper::ApplyPatchWithBinary( FILE* pipe = popen(cmd.str().c_str(), "r"); if (!pipe) { fs::remove(temp_rom, ec); + fs::remove(temp_symbols, ec); if (!patch_dir.empty()) fs::current_path(original_cwd, ec); return absl::InternalError("popen() failed for Asar CLI"); } diff --git a/src/zelda3/screen/dungeon_map.cc b/src/zelda3/screen/dungeon_map.cc index 10923ca7..42cd800a 100644 --- a/src/zelda3/screen/dungeon_map.cc +++ b/src/zelda3/screen/dungeon_map.cc @@ -93,8 +93,10 @@ absl::Status SaveDungeonMaps(Rom& rom, std::vector& dungeon_maps) { RETURN_IF_ERROR(rom.WriteWord(kDungeonMapBossRooms + (d * 2), map.boss_room)); - bool search_boss = map.boss_room != 0x000F; - if (!search_boss) { + const bool has_boss = + map.boss_room != 0x000F && map.boss_room != 0xFFFF; + bool search_boss = has_boss; + if (!has_boss) { RETURN_IF_ERROR( rom.WriteWord(kDungeonMapBossFloors + (d * 2), 0xFFFF)); } @@ -111,15 +113,15 @@ absl::Status SaveDungeonMaps(Rom& rom, std::vector& dungeon_maps) { search_boss = false; } - RETURN_IF_ERROR(rom.WriteByte(pos, map.floor_rooms[f][r])); - pos++; - if (pos >= kDungeonMapDataReservedStart && pos <= kDungeonMapDataReservedEnd) { pos = kDungeonMapDataReservedEnd + 1; restart = true; break; } + + RETURN_IF_ERROR(rom.WriteByte(pos, map.floor_rooms[f][r])); + pos++; } if (restart) break; } @@ -134,9 +136,6 @@ absl::Status SaveDungeonMaps(Rom& rom, std::vector& dungeon_maps) { for (int f = 0; f < total_floors; f++) { for (int r = 0; r < kNumRooms; r++) { if (map.floor_rooms[f][r] != 0x0F) { - RETURN_IF_ERROR(rom.WriteByte(pos, map.floor_gfx[f][r])); - pos++; - if (pos >= kDungeonMapDataReservedStart && pos <= kDungeonMapDataReservedEnd) { pos = kDungeonMapDataReservedEnd + 1; @@ -145,6 +144,9 @@ absl::Status SaveDungeonMaps(Rom& rom, std::vector& dungeon_maps) { restart = true; break; } + + RETURN_IF_ERROR(rom.WriteByte(pos, map.floor_gfx[f][r])); + pos++; } } if (restart) break;