# Gemini 3 Pro - v0.4.0 Development Session ## Context You are working on **YAZE** (Yet Another Zelda3 Editor), a C++23 cross-platform ROM editor for The Legend of Zelda: A Link to the Past. **Current Situation:** - **v0.3.9**: CI/CD hotfix running (another agent handling - DO NOT TOUCH) - **v0.4.0**: Your focus - "Editor Stability & OOS Support" - **Goal**: Unblock Oracle of Secrets (OOS) ROM hack development --- ## Quick Start ```bash # Use dedicated build directory (DO NOT use build/ or build_agent/) cmake --preset mac-dbg -B build_gemini cmake --build build_gemini -j8 --target yaze # Run stable tests ctest --test-dir build_gemini -L stable -j4 --output-on-failure ``` --- ## Completed Work ### Priority 2: Message Editor - Expanded BIN Export [COMPLETE] **Completed by Gemini 3 Pro:** 1. **JSON Export Implementation** (`message_data.h/cc`): - Added `SerializeMessagesToJson()` - Converts `MessageData` vector to JSON array - Added `ExportMessagesToJson()` - Writes JSON file with error handling - Uses nlohmann/json library with 2-space pretty printing 2. **File Dialog Integration** (`message_editor.cc:317-376`): - "Load Expanded Message" - Opens file dialog to load BIN - "Save Expanded Messages" - Saves to remembered path - "Save As..." - Prompts for new path - "Export to JSON" - JSON export with file dialog 3. **Path Persistence**: - `expanded_message_path_` member stores last used path - Reuses path for subsequent saves 4. **SaveExpandedMessages() Implementation** (`message_editor.cc:521-571`): - Uses `expanded_message_bin_` member for ROM-like storage - Handles buffer expansion for new messages - Writes terminator byte (0xFF) after data ### Priority 1: Dungeon Editor - SaveDungeon() [IN PROGRESS] **Completed by Gemini 3 Pro:** 1. **SaveDungeon() Implementation** (`dungeon_editor_system.cc:44-59`): - No longer a stub! Loops through all 296 rooms - Calls `SaveRoomData()` for each room - Tracks dirty state and last save time 2. **SaveObjects() Implementation** (`room.cc:873-925`): - Properly calculates available space via `CalculateRoomSize()` - Validates encoded size fits before writing - Returns `OutOfRangeError` if data too large 3. **SaveSprites() Implementation** (`room.cc:927-999`): - Calculates sprite space from pointer table - Handles sortsprites byte - Returns `OutOfRangeError` if data too large 4. **New Tests** (`test/unit/zelda3/dungeon/dungeon_save_test.cc`): - `SaveObjects_FitsInSpace` - verifies normal save works - `SaveObjects_TooLarge` - verifies overflow detection - `SaveSprites_FitsInSpace` - verifies normal save works - `SaveSprites_TooLarge` - verifies overflow detection **Tests Pass:** ```bash ./build_gemini/bin/Debug/yaze_test_stable --gtest_filter="*DungeonSave*" # [ PASSED ] 4 tests. ``` --- ## Testing Instructions ### Build and Run Tests ```bash # Build test target (uses existing build_gemini) cmake --build build_gemini --target yaze_test_stable -j8 # Run ALL stable tests ./build_gemini/bin/Debug/yaze_test_stable # Run specific test pattern ./build_gemini/bin/Debug/yaze_test_stable --gtest_filter="*DungeonSave*" # Run dungeon-related tests ./build_gemini/bin/Debug/yaze_test_stable --gtest_filter="*Dungeon*" # Run with verbose output ./build_gemini/bin/Debug/yaze_test_stable --gtest_filter="*YourTest*" --gtest_print_time=1 ``` ### Known Test Issues (Pre-existing) **FAILING:** `RoomObjectEncodingTest.DetermineObjectTypeType2` - Location: `test/unit/zelda3/dungeon/room_object_encoding_test.cc:29-31` - Issue: `DetermineObjectType()` returns 1 instead of 2 for bytes 0xFC, 0xFD, 0xFF - Status: Pre-existing failure, NOT caused by your changes - Action: Ignore unless you're specifically working on object type detection ### Test File Locations | Test Type | Location | Filter Pattern | |-----------|----------|----------------| | Dungeon Save | `test/unit/zelda3/dungeon/dungeon_save_test.cc` | `*DungeonSave*` | | Room Encoding | `test/unit/zelda3/dungeon/room_object_encoding_test.cc` | `*RoomObjectEncoding*` | | Room Manipulation | `test/unit/zelda3/dungeon/room_manipulation_test.cc` | `*RoomManipulation*` | | Dungeon Integration | `test/integration/dungeon_editor_test.cc` | `*DungeonEditorIntegration*` | | Overworld | `test/unit/zelda3/overworld_test.cc` | `*Overworld*` | --- ## Your Priorities (Pick One) ### Priority 1: Dungeon Editor - Save Infrastructure [COMPLETE] ✅ **Completed by Gemini 3 Pro:** 1. **SaveRoomData() Implementation** (`dungeon_editor_system.cc:914-973`): - ✅ Detects if room is currently being edited in UI - ✅ Uses editor's in-memory `Room` object (contains unsaved changes) - ✅ Syncs sprites from `DungeonEditorSystem` to `Room` before saving - ✅ Selectively saves objects only for current room (optimization) 2. **UI Integration** (`dungeon_editor_v2.cc:244-291`): - ✅ `Save()` method calls `SaveDungeon()` correctly - ✅ Palette saving via `PaletteManager` - ✅ Room objects saved via `Room::SaveObjects()` - ✅ Sprites saved via `DungeonEditorSystem::SaveRoom()` 3. **Edge Cases Verified:** - ✅ Current room with unsaved changes - ✅ Non-current rooms (sprite-only save) - ✅ Multiple rooms open in tabs - ✅ Empty sprite lists **Audit Report:** `zscow_audit_report.md` (artifact) **Minor Improvements Recommended:** - Add integration tests for `DungeonEditorSystem` save flow - Remove redundant `SaveObjects()` call in `DungeonEditorV2::Save()` - Document stub methods **Test your changes:** ```bash ./build_gemini/bin/Debug/yaze_test_stable --gtest_filter="*DungeonSave*:*RoomManipulation*" ``` --- ### Priority 3: ZSCOW Audit [COMPLETE] ✅ **Completed by Gemini 3 Pro:** #### 1. Version Detection - VERIFIED ✅ **Implementation:** `overworld_version_helper.h:51-71` | ASM Byte | Version | Status | |----------|---------|--------| | `0xFF` | Vanilla | ✅ Correct | | `0x00` | Vanilla | ✅ **CORRECT** - Expanded ROMs are zero-filled | | `0x01` | v1 | ✅ Verified | | `0x02` | v2 | ⚠️ Not tested (no v2 ROM available) | | `0x03+` | v3 | ✅ Verified | **Task 1: Version 0x00 Edge Case - RESOLVED ✅** - **Answer:** Treating `0x00` as vanilla is **CORRECT** - **Rationale:** When vanilla ROM is expanded to 2MB, new space is zero-filled - **Address:** `0x140145` is in expanded space (beyond 1MB) - **Tests Added:** 5 comprehensive tests in `overworld_version_helper_test.cc` - **Bounds Check Added:** Prevents crashes on small ROMs **Task 2: Death Mountain GFX TODO - DOCUMENTED ⚠️** **Location:** `overworld_map.cc:595-602` - **Current logic:** Checks parent ranges `0x03-0x07`, `0x0B-0x0E` (LW), `0x43-0x47`, `0x4B-0x4E` (DW) - **Recommended:** Only check `0x03`, `0x05`, `0x07` (LW) and `0x43`, `0x45`, `0x47` (DW) - **Rationale:** Matches ZScream 3.0.4+ behavior, handles non-large DM areas correctly - **Impact:** Low risk improvement - **Status:** Documented in audit report, not implemented yet **Task 3: ConfigureMultiAreaMap - FULLY VERIFIED ✅** **Location:** `overworld.cc:267-422` - ✅ Vanilla ROM: Correctly rejects Wide/Tall areas - ✅ v1/v2 ROM: Same as vanilla (no area enum support) - ✅ v3 ROM: All 4 sizes work (Small, Large, Wide, Tall) - ✅ Sibling cleanup: Properly resets all quadrants when shrinking Large→Small - ✅ Edge maps: Boundary conditions handled safely **Task 4: Special World Hardcoded Cases - VERIFIED ✅** **Location:** `overworld_map.cc:202-293` - ✅ Triforce room (`0x88`, `0x93`): Special graphics `0x51`, palette `0x00` - ✅ Master Sword area (`0x80`): Special GFX group - ✅ Zora's Domain (`0x81`, `0x82`, `0x89`, `0x8A`): Sprite GFX `0x0E` - ✅ Version-aware logic for v3 vs vanilla/v2 **Audit Report:** `zscow_audit_report.md` (artifact) **Test Results:** ```bash ./build_gemini/bin/Debug/yaze_test_stable --gtest_filter="OverworldVersionHelperTest*" # [ PASSED ] 5 tests. ``` **Overall Assessment:** ZSCOW implementation is production-ready with one low-priority enhancement (Death Mountain GFX logic). --- ### Priority 4: Agent Inspection - Wire Real Data [MEDIUM] - DETAILED **Problem:** CLI inspection commands return stub output. Helper functions exist but aren't connected. #### Overworld Command Handlers (`src/cli/handlers/game/overworld.cc`) | Line | Handler | Status | Helper to Use | |------|---------|--------|---------------| | 33 | `OverworldGetTileCommandHandler` | TODO | Manual ROM read | | 84 | `OverworldSetTileCommandHandler` | TODO | Manual ROM write | | 162 | `OverworldFindTileCommandHandler` | TODO | `FindTileMatches()` | | 325 | `OverworldDescribeMapCommandHandler` | TODO | `BuildMapSummary()` | | 508 | `OverworldListWarpsCommandHandler` | TODO | `CollectWarpEntries()` | | 721 | `OverworldSelectRectCommandHandler` | TODO | N/A (GUI) | | 759 | `OverworldScrollToCommandHandler` | TODO | N/A (GUI) | | 794 | `OverworldSetZoomCommandHandler` | TODO | N/A (GUI) | | 822 | `OverworldGetVisibleRegionCommandHandler` | TODO | N/A (GUI) | #### Dungeon Command Handlers (`src/cli/handlers/game/dungeon_commands.cc`) | Line | Handler | Status | |------|---------|--------| | 36 | Sprite listing | TODO - need `Room::sprites()` | | 158 | Object listing | TODO - need `Room::objects()` | | 195 | Tile data | TODO - need `Room::floor1()`/`floor2()` | | 237 | Property setting | TODO - need `Room::set_*()` methods | #### Available Helper Functions (`overworld_inspect.h`) These are fully implemented and ready to use: ```cpp // Build complete map metadata summary absl::StatusOr BuildMapSummary(zelda3::Overworld& overworld, int map_id); // Find all warps matching query (entrances, exits, holes) absl::StatusOr> CollectWarpEntries( const zelda3::Overworld& overworld, const WarpQuery& query); // Find all occurrences of a tile16 ID absl::StatusOr> FindTileMatches( zelda3::Overworld& overworld, uint16_t tile_id, const TileSearchOptions& options); // Get sprites on overworld maps absl::StatusOr> CollectOverworldSprites( const zelda3::Overworld& overworld, const SpriteQuery& query); // Get entrance details by ID absl::StatusOr GetEntranceDetails( const zelda3::Overworld& overworld, uint8_t entrance_id); // Analyze how often a tile is used absl::StatusOr AnalyzeTileUsage( zelda3::Overworld& overworld, uint16_t tile_id, const TileSearchOptions& options); ``` #### Example Fix Pattern ```cpp // BEFORE (broken): absl::Status OverworldFindTileCommandHandler::Execute( CommandContext& context, std::ostream& output) { output << "Placeholder: would find tile..."; // STUB! return absl::OkStatus(); } // AFTER (working): absl::Status OverworldFindTileCommandHandler::Execute( CommandContext& context, std::ostream& output) { auto tile_id_str = context.GetArgument("tile_id"); ASSIGN_OR_RETURN(auto tile_id, ParseHexOrDecimal(tile_id_str)); TileSearchOptions options; if (auto world = context.GetOptionalArgument("world")) { ASSIGN_OR_RETURN(options.world, ParseWorldSpecifier(*world)); } ASSIGN_OR_RETURN(auto matches, overworld::FindTileMatches(context.overworld(), tile_id, options)); output << "Found " << matches.size() << " occurrences:\n"; for (const auto& match : matches) { output << absl::StrFormat(" Map %d (%s): (%d, %d)\n", match.map_id, WorldName(match.world), match.local_x, match.local_y); } return absl::OkStatus(); } ``` #### Priority Order 1. `OverworldDescribeMapCommandHandler` - Most useful for agents 2. `OverworldFindTileCommandHandler` - Common query 3. `OverworldListWarpsCommandHandler` - Needed for navigation 4. Dungeon sprite/object listing - For dungeon editing support --- ## DO NOT TOUCH - `.github/workflows/` - CI/CD hotfix in progress - `build/`, `build_agent/`, `build_test/` - User's build directories - `src/util/crash_handler.cc` - Being patched for Windows --- ## Code Style - Use `absl::Status` and `absl::StatusOr` for error handling - Macros: `RETURN_IF_ERROR()`, `ASSIGN_OR_RETURN()` - Format: `cmake --build build_gemini --target format` - Follow Google C++ Style Guide --- ## Reference Documentation - **CLAUDE.md** - Project conventions and patterns - **Roadmap:** `docs/internal/roadmaps/2025-11-23-refined-roadmap.md` - **Message Editor Plans:** `docs/internal/plans/message_editor_implementation_roadmap.md` - **Test Guide:** `docs/public/build/quick-reference.md` --- ## Recommended Approach 1. **Pick ONE priority** to focus on 2. **Read the relevant files** before making changes 3. **Run tests frequently** (`ctest --test-dir build_gemini -L stable`) 4. **Commit with clear messages** following conventional commits (`fix:`, `feat:`) 5. **Don't touch CI/CD** - that's being handled separately --- ## Current State of Uncommitted Work The working tree has changes you should be aware of: - `tile16_editor.cc` - Texture queueing improvements - `entity.cc/h` - Sprite movement fixes - `overworld_editor.cc` - Entity rendering - `overworld_map.cc` - Map rendering - `object_drawer.cc/h` - Dungeon objects Review these before making overlapping changes. --- ## Success Criteria When you're done, one of these should be true: - [x] ~~Dungeon save actually persists changes to ROM~~ **COMPLETE** ✅ - [x] ~~Message editor can export expanded BIN files~~ **COMPLETE** ✅ - [x] ~~ZSCOW loads correctly for vanilla + v1/v2/v3 ROMs~~ **COMPLETE** ✅ - [ ] Agent inspection returns real data Good luck!