backend-infra-engineer: Post v0.3.9-hotfix7 snapshot (build cleanup)
This commit is contained in:
@@ -0,0 +1,482 @@
|
||||
# YAZE Dungeon System - Complete Technical Reference
|
||||
|
||||
Comprehensive reference for AI agents working on the YAZE Dungeon editing system.
|
||||
|
||||
---
|
||||
|
||||
## 1. Architecture Overview
|
||||
|
||||
### File Structure
|
||||
```
|
||||
src/zelda3/dungeon/
|
||||
├── dungeon.h/cc # Main Dungeon class
|
||||
├── room.h/cc # Room class (1,337 lines)
|
||||
├── room_object.h/cc # RoomObject encoding (633+249 lines)
|
||||
├── object_drawer.h/cc # Object rendering (210+972 lines)
|
||||
├── object_parser.h/cc # ROM tile parsing (172+387 lines)
|
||||
├── room_entrance.h # Entrance data (367 lines)
|
||||
├── dungeon_rom_addresses.h # ROM address constants (108 lines)
|
||||
|
||||
src/app/editor/dungeon/
|
||||
├── dungeon_editor_v2.h/cc # Main editor (card-based)
|
||||
├── dungeon_room_loader.h/cc # ROM data loading
|
||||
├── dungeon_room_selector.h/cc # Room selection UI
|
||||
├── dungeon_canvas_viewer.h/cc # Canvas rendering
|
||||
├── dungeon_object_selector.h/cc # Object palette
|
||||
├── dungeon_object_interaction.h/cc # Mouse interactions
|
||||
```
|
||||
|
||||
### Data Model
|
||||
```
|
||||
Dungeon
|
||||
└── rooms_[296]
|
||||
└── Room
|
||||
├── tile_objects_[] (RoomObject instances)
|
||||
├── sprites_[]
|
||||
├── chests_in_room_[]
|
||||
├── z3_staircases_[]
|
||||
├── bg1_buffer_ (512x512 pixels)
|
||||
├── bg2_buffer_ (512x512 pixels)
|
||||
└── current_gfx16_[] (16KB graphics)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Room Structure
|
||||
|
||||
### Room Count & Organization
|
||||
- **Total Rooms:** 296 (indices 0x00-0x127)
|
||||
- **Canvas Size:** 512x512 pixels (64x64 tiles)
|
||||
- **Layers:** BG1, BG2, BG3
|
||||
|
||||
### Room Properties
|
||||
```cpp
|
||||
// room.h
|
||||
int room_id_; // Room index (0-295)
|
||||
uint8_t blockset; // Graphics blockset ID
|
||||
uint8_t spriteset; // Sprite set ID
|
||||
uint8_t palette; // Palette ID (0-63)
|
||||
uint8_t layout; // Layout template (0-7)
|
||||
uint8_t floor1, floor2; // Floor graphics (nibbles)
|
||||
uint16_t message_id_; // Associated message
|
||||
|
||||
// Behavioral
|
||||
CollisionKey collision_type; // Collision enum
|
||||
EffectKey effect_type; // Visual effect enum
|
||||
TagKey tag1, tag2; // Special condition tags
|
||||
LayerMergeType layer_merge; // BG1/BG2 blend mode
|
||||
```
|
||||
|
||||
### Layer Merge Types
|
||||
```cpp
|
||||
enum LayerMergeType {
|
||||
LayerMerge00 = 0x00, // Off - Layer 2 invisible
|
||||
LayerMerge01 = 0x01, // Parallax scrolling
|
||||
LayerMerge02 = 0x02, // Dark overlay
|
||||
LayerMerge03 = 0x03, // On top (translucent)
|
||||
LayerMerge04 = 0x04, // Translucent blend
|
||||
LayerMerge05 = 0x05, // Addition blend
|
||||
LayerMerge06 = 0x06, // Normal overlay
|
||||
LayerMerge07 = 0x07, // Transparent
|
||||
LayerMerge08 = 0x08, // Dark room effect
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Object Encoding System
|
||||
|
||||
### 3-Byte Object Format
|
||||
|
||||
Objects are stored as 3 bytes in ROM with three distinct encoding types:
|
||||
|
||||
#### Type 1: Standard Objects (ID 0x00-0xFF)
|
||||
```
|
||||
Byte format: xxxxxxss | yyyyyyss | iiiiiiii
|
||||
b1 b2 b3
|
||||
|
||||
Decoding:
|
||||
x = (b1 & 0xFC) >> 2 // 6 bits (0-63)
|
||||
y = (b2 & 0xFC) >> 2 // 6 bits (0-63)
|
||||
size = ((b1 & 0x03) << 2) | (b2 & 0x03) // 4 bits (0-15)
|
||||
id = b3 // 8 bits
|
||||
```
|
||||
|
||||
#### Type 2: Extended Objects (ID 0x100-0x1FF)
|
||||
```
|
||||
Indicator: b1 >= 0xFC
|
||||
|
||||
Byte format: 111111xx | xxxxyyyy | yyiiiiii
|
||||
b1 b2 b3
|
||||
|
||||
Decoding:
|
||||
id = (b3 & 0x3F) | 0x100
|
||||
x = ((b2 & 0xF0) >> 4) | ((b1 & 0x03) << 4)
|
||||
y = ((b2 & 0x0F) << 2) | ((b3 & 0xC0) >> 6)
|
||||
size = 0 // No size parameter
|
||||
```
|
||||
|
||||
#### Type 3: Rare Objects (ID 0xF00-0xFFF)
|
||||
```
|
||||
Indicator: b3 >= 0xF8
|
||||
|
||||
Byte format: xxxxxxii | yyyyyyii | 11111iii
|
||||
b1 b2 b3
|
||||
|
||||
Decoding:
|
||||
id = (b3 << 4) | 0x80 | ((b2 & 0x03) << 2) | (b1 & 0x03)
|
||||
x = (b1 & 0xFC) >> 2
|
||||
y = (b2 & 0xFC) >> 2
|
||||
size = ((b1 & 0x03) << 2) | (b2 & 0x03)
|
||||
```
|
||||
|
||||
### Object Categories
|
||||
|
||||
| Type | ID Range | Examples |
|
||||
|------|----------|----------|
|
||||
| Type 1 | 0x00-0xFF | Walls, floors, decorations |
|
||||
| Type 2 | 0x100-0x1FF | Corners, stairs, furniture |
|
||||
| Type 3 | 0xF00-0xFFF | Chests, pipes, special objects |
|
||||
|
||||
---
|
||||
|
||||
## 4. ObjectDrawer Rendering System
|
||||
|
||||
### Class Structure
|
||||
```cpp
|
||||
// object_drawer.h
|
||||
class ObjectDrawer {
|
||||
// Entry point
|
||||
absl::Status DrawObject(const RoomObject& object,
|
||||
gfx::BackgroundBuffer& bg1,
|
||||
gfx::BackgroundBuffer& bg2,
|
||||
const gfx::PaletteGroup& palette_group);
|
||||
|
||||
// Data
|
||||
Rom* rom_;
|
||||
const uint8_t* room_gfx_buffer_; // current_gfx16_
|
||||
std::unordered_map<int16_t, int> object_to_routine_map_;
|
||||
std::vector<DrawRoutine> draw_routines_;
|
||||
};
|
||||
```
|
||||
|
||||
### Draw Routine Status
|
||||
|
||||
| # | Routine Name | Status | Lines |
|
||||
|---|--------------|--------|-------|
|
||||
| 0 | DrawRightwards2x2_1to15or32 | COMPLETE | 302-321 |
|
||||
| 1 | DrawRightwards2x4_1to15or26 | COMPLETE | 323-348 |
|
||||
| 2 | DrawRightwards2x4spaced4_1to16 | COMPLETE | 350-373 |
|
||||
| 3 | DrawRightwards2x4spaced4_BothBG | **STUB** | 375-381 |
|
||||
| 4 | DrawRightwards2x2_1to16 | COMPLETE | 383-399 |
|
||||
| 5 | DrawDiagonalAcute_1to16 | **UNCLEAR** | 401-417 |
|
||||
| 6 | DrawDiagonalGrave_1to16 | **UNCLEAR** | 419-435 |
|
||||
| 7 | DrawDownwards2x2_1to15or32 | COMPLETE | 689-708 |
|
||||
| 8 | DrawDownwards4x2_1to15or26 | COMPLETE | 710-753 |
|
||||
| 9 | DrawDownwards4x2_BothBG | **STUB** | 755-761 |
|
||||
| 10 | DrawDownwardsDecor4x2spaced4 | COMPLETE | 763-782 |
|
||||
| 11 | DrawDownwards2x2_1to16 | COMPLETE | 784-799 |
|
||||
| 12 | DrawDownwardsHasEdge1x1 | COMPLETE | 801-813 |
|
||||
| 13 | DrawDownwardsEdge1x1 | COMPLETE | 815-827 |
|
||||
| 14 | DrawDownwardsLeftCorners | COMPLETE | 829-842 |
|
||||
| 15 | DrawDownwardsRightCorners | COMPLETE | 844-857 |
|
||||
| 16 | DrawRightwards4x4_1to16 | COMPLETE | 534-550 |
|
||||
| - | CustomDraw | **STUB** | 524-532 |
|
||||
| - | DrawDoorSwitcherer | **STUB** | 566-575 |
|
||||
|
||||
### INCOMPLETE: BothBG Routines (4 locations)
|
||||
|
||||
These routines should draw to BOTH BG1 and BG2 but currently only call single-layer version:
|
||||
|
||||
```cpp
|
||||
// Line 375-381: DrawRightwards2x4spaced4_1to16_BothBG
|
||||
// Line 437-442: DrawDiagonalAcute_1to16_BothBG
|
||||
// Line 444-449: DrawDiagonalGrave_1to16_BothBG
|
||||
// Line 755-761: DrawDownwards4x2_1to16_BothBG
|
||||
|
||||
// Current (WRONG):
|
||||
void DrawRightwards2x4spaced4_1to16_BothBG(
|
||||
const RoomObject& obj, gfx::BackgroundBuffer& bg, // Only 1 buffer!
|
||||
std::span<const gfx::TileInfo> tiles) {
|
||||
// Just calls single-layer version - misses BG2
|
||||
DrawRightwards2x4spaced4_1to16(obj, bg, tiles);
|
||||
}
|
||||
|
||||
// Should be:
|
||||
void DrawRightwards2x4spaced4_1to16_BothBG(
|
||||
const RoomObject& obj,
|
||||
gfx::BackgroundBuffer& bg1, // Both buffers
|
||||
gfx::BackgroundBuffer& bg2,
|
||||
std::span<const gfx::TileInfo> tiles) {
|
||||
DrawRightwards2x4spaced4_1to16(obj, bg1, tiles);
|
||||
DrawRightwards2x4spaced4_1to16(obj, bg2, tiles);
|
||||
}
|
||||
```
|
||||
|
||||
### UNCLEAR: Diagonal Routines
|
||||
|
||||
```cpp
|
||||
// Lines 401-417, 419-435
|
||||
// Issues:
|
||||
// - Hardcoded +6 and 5 iterations (why?)
|
||||
// - Coordinate formula may produce negative Y
|
||||
// - Only uses 4 tiles from larger span
|
||||
// - No bounds checking
|
||||
|
||||
for (int s = 0; s < size + 6; s++) { // Why +6?
|
||||
for (int i = 0; i < 5; i++) { // Why 5?
|
||||
WriteTile8(bg, obj.x_ + s, obj.y_ + (i - s), tiles[i % 4]);
|
||||
// ^^ (i - s) can be negative when s > i
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Tile Rendering Pipeline
|
||||
|
||||
### WriteTile8() - Tile to Pixel Conversion
|
||||
```cpp
|
||||
// object_drawer.cc lines 863-883
|
||||
void WriteTile8(gfx::BackgroundBuffer& bg, int tile_x, int tile_y,
|
||||
const gfx::TileInfo& tile_info) {
|
||||
// tile coords → pixel coords: tile_x * 8, tile_y * 8
|
||||
DrawTileToBitmap(bitmap, tile_info, tile_x * 8, tile_y * 8, room_gfx_buffer_);
|
||||
}
|
||||
```
|
||||
|
||||
### DrawTileToBitmap() - Pixel Rendering
|
||||
```cpp
|
||||
// object_drawer.cc lines 890-970
|
||||
// Key steps:
|
||||
// 1. Graphics sheet lookup: tile_info.id_ → (sheet_x, sheet_y)
|
||||
// 2. Palette offset: (palette & 0x0F) * 8
|
||||
// 3. Per-pixel with mirroring support
|
||||
// 4. Color 0 = transparent (skipped)
|
||||
|
||||
int tile_sheet_x = (tile_info.id_ % 16) * 8; // 0-127 pixels
|
||||
int tile_sheet_y = (tile_info.id_ / 16) * 8; // 0-127 pixels
|
||||
uint8_t palette_offset = (tile_info.palette_ & 0x0F) * 8;
|
||||
|
||||
for (int py = 0; py < 8; py++) {
|
||||
for (int px = 0; px < 8; px++) {
|
||||
int src_x = tile_info.horizontal_mirror_ ? (7 - px) : px;
|
||||
int src_y = tile_info.vertical_mirror_ ? (7 - py) : py;
|
||||
// Read pixel, apply palette, write to bitmap
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Palette Application (CRITICAL)
|
||||
```cpp
|
||||
// object_drawer.cc lines 71-115
|
||||
// Palette must be applied AFTER drawing, BEFORE SDL sync
|
||||
|
||||
// 1. Draw all objects (writes palette indices 0-255)
|
||||
for (auto& obj : objects) {
|
||||
DrawObject(obj, bg1, bg2, palette_group);
|
||||
}
|
||||
|
||||
// 2. Apply dungeon palette to convert indices → RGB
|
||||
bg1_bmp.SetPalette(dungeon_palette);
|
||||
bg2_bmp.SetPalette(dungeon_palette);
|
||||
|
||||
// 3. Sync to SDL surfaces
|
||||
SDL_LockSurface(bg1_bmp.surface());
|
||||
memcpy(bg1_bmp.surface()->pixels, bg1_bmp.mutable_data().data(), ...);
|
||||
SDL_UnlockSurface(bg1_bmp.surface());
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. ROM Addresses
|
||||
|
||||
### Room Data
|
||||
```cpp
|
||||
kRoomObjectLayoutPointer = 0x882D // Layout pointer table
|
||||
kRoomObjectPointer = 0x874C // Object data pointer
|
||||
kRoomHeaderPointer = 0xB5DD // Room headers (3-byte long)
|
||||
kRoomHeaderPointerBank = 0xB5E7 // Bank byte
|
||||
```
|
||||
|
||||
### Palette & Graphics
|
||||
```cpp
|
||||
kDungeonsMainBgPalettePointers = 0xDEC4B
|
||||
kDungeonsPalettes = 0xDD734
|
||||
kGfxGroupsPointer = 0x6237
|
||||
kTileAddress = 0x1B52 // Main tile graphics
|
||||
kTileAddressFloor = 0x1B5A // Floor tile graphics
|
||||
```
|
||||
|
||||
### Object Subtypes
|
||||
```cpp
|
||||
kRoomObjectSubtype1 = 0x0F8000 // Standard objects
|
||||
kRoomObjectSubtype2 = 0x0F83F0 // Extended objects
|
||||
kRoomObjectSubtype3 = 0x0F84F0 // Rare objects
|
||||
kRoomObjectTileAddress = 0x091B52 // Tile data
|
||||
```
|
||||
|
||||
### Special Objects
|
||||
```cpp
|
||||
kBlocksPointer[1-4] = 0x15AFA-0x15B0F
|
||||
kChestsDataPointer1 = 0xEBFB
|
||||
kTorchData = 0x2736A
|
||||
kPitPointer = 0x394AB
|
||||
kDoorPointers = 0xF83C0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. TODOs in room_object.h (30+ items)
|
||||
|
||||
### Unknown Objects Needing Verification
|
||||
|
||||
| Line | ID | Description |
|
||||
|------|-----|-------------|
|
||||
| 234 | 0x35 | "WEIRD DOOR" - needs investigation |
|
||||
| 252-255 | 0x49-0x4C | "Unknown" Type 1 objects |
|
||||
| 350-353 | 0xC4-0xC7 | "Diagonal layer 2 mask B" - needs verify |
|
||||
| 392-395 | 0xDE-0xE1 | "Moving wall flag" - WTF IS THIS? |
|
||||
| 466-476 | Type 2 | Multiple "Unknown" objects |
|
||||
| 480 | 0x30 | "Intraroom stairs north B" - verify layer |
|
||||
| 486 | 0x36 | "Water ladder (south)" - needs verify |
|
||||
| 512-584 | Type 3 | Multiple "Unknown" objects |
|
||||
|
||||
---
|
||||
|
||||
## 8. DungeonEditorV2 Architecture
|
||||
|
||||
### Card-Based Component System
|
||||
```cpp
|
||||
DungeonEditorV2 (Coordinator)
|
||||
├── DungeonRoomLoader // ROM data loading
|
||||
├── DungeonRoomSelector // Room list/selection
|
||||
├── DungeonCanvasViewer // 512x512 canvas
|
||||
├── DungeonObjectSelector // Object palette
|
||||
├── DungeonObjectInteraction // Mouse handling
|
||||
├── ObjectEditorCard // Property editing
|
||||
└── PaletteEditorWidget // Color editing
|
||||
```
|
||||
|
||||
### Card Types
|
||||
```cpp
|
||||
show_control_panel_ // Room/entrance selection
|
||||
show_room_selector_ // Room list
|
||||
show_room_matrix_ // 16x19 visual layout
|
||||
show_entrances_list_ // Entrance/spawn list
|
||||
show_room_graphics_ // Blockset/palette
|
||||
show_object_editor_ // Object placement
|
||||
show_palette_editor_ // Palette colors
|
||||
show_debug_controls_ // Debug options
|
||||
```
|
||||
|
||||
### Undo/Redo System
|
||||
```cpp
|
||||
// Per-room object snapshots
|
||||
std::unordered_map<int, std::vector<std::vector<RoomObject>>> undo_history_;
|
||||
std::unordered_map<int, std::vector<std::vector<RoomObject>>> redo_history_;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Room Loading Flow
|
||||
|
||||
```
|
||||
LoadRoomFromRom(room_id)
|
||||
│
|
||||
├── Resolve room header pointer (0xB5DD + room_id * 3)
|
||||
│
|
||||
├── Parse header bytes:
|
||||
│ ├── BG2 type, collision, light flag
|
||||
│ ├── Palette, blockset, spriteset
|
||||
│ ├── Effect type, tags
|
||||
│ └── Staircase data
|
||||
│
|
||||
├── Load graphics sheets (16 blocks)
|
||||
│
|
||||
└── LoadObjects()
|
||||
│
|
||||
├── Read floor/layout header (2 bytes)
|
||||
│
|
||||
├── Parse object stream:
|
||||
│ ├── 3 bytes per object
|
||||
│ ├── 0xFF 0xFF = layer boundary
|
||||
│ └── 0xF0 0xFF = door section
|
||||
│
|
||||
└── Handle special objects:
|
||||
├── Staircases
|
||||
├── Chests
|
||||
├── Doors
|
||||
├── Torches
|
||||
└── Blocks
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. Rendering Pipeline
|
||||
|
||||
```
|
||||
1. LoadRoomGraphics()
|
||||
└── Build graphics sheet list from blockset
|
||||
|
||||
2. CopyRoomGraphicsToBuffer()
|
||||
└── Copy ROM sheets → current_gfx16_[]
|
||||
|
||||
3. RenderRoomGraphics()
|
||||
├── Check dirty flags
|
||||
├── LoadLayoutTilesToBuffer()
|
||||
├── Draw floor to bg1/bg2 buffers
|
||||
└── RenderObjectsToBackground()
|
||||
└── ObjectDrawer::DrawObjectList()
|
||||
|
||||
4. Present (Canvas Viewer)
|
||||
├── Process deferred texture queue
|
||||
├── Create/update GPU textures
|
||||
└── Render to ImGui canvas
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. Known Issues Summary
|
||||
|
||||
### BothBG Support (4 stubs)
|
||||
- Line 380: `DrawRightwards2x4spaced4_1to16_BothBG`
|
||||
- Line 441: `DrawDiagonalAcute_1to16_BothBG`
|
||||
- Line 448: `DrawDiagonalGrave_1to16_BothBG`
|
||||
- Line 760: `DrawDownwards4x2_1to16_BothBG`
|
||||
|
||||
**Fix:** Change signature to accept both `bg1` and `bg2` buffers.
|
||||
|
||||
### Diagonal Logic (2 routines)
|
||||
- Lines 401-435: Hardcoded constants, potential negative coords
|
||||
- **Needs:** Game verification or ZScream reference
|
||||
|
||||
### Custom/Door Stubs (2 routines)
|
||||
- Line 524-532: `CustomDraw` - only draws first tile
|
||||
- Line 566-575: `DrawDoorSwitcherer` - only draws first tile
|
||||
|
||||
### Object Names (30+ unknowns)
|
||||
- Multiple objects need in-game verification
|
||||
- See section 7 for full list
|
||||
|
||||
---
|
||||
|
||||
## 12. Testing
|
||||
|
||||
### Run Dungeon Tests
|
||||
```bash
|
||||
# Unit tests
|
||||
ctest --test-dir build -R "dungeon\|Dungeon" -V
|
||||
|
||||
# E2E tests
|
||||
ctest --test-dir build -R "DungeonEditor" -V
|
||||
```
|
||||
|
||||
### E2E Test Files
|
||||
- `test/e2e/dungeon_editor_smoke_test.cc`
|
||||
- `test/e2e/dungeon_canvas_interaction_test.cc`
|
||||
- `test/e2e/dungeon_layer_rendering_test.cc`
|
||||
- `test/e2e/dungeon_object_drawing_test.cc`
|
||||
|
||||
### Test Design Doc
|
||||
`docs/internal/testing/dungeon-gui-test-design.md` (1000+ lines)
|
||||
File diff suppressed because it is too large
Load Diff
1275
docs/internal/agents/archive/large-ref-docs/gemini-zsow-ref.md
Normal file
1275
docs/internal/agents/archive/large-ref-docs/gemini-zsow-ref.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,45 @@
|
||||
# AI Initiative Template
|
||||
|
||||
Use this template when kicking off a sizable AI-driven effort (infrastructure, editor refactor,
|
||||
automation tooling, etc.). Keep the filled-out document alongside other planning notes and reference
|
||||
it from the coordination board.
|
||||
|
||||
```
|
||||
# <Initiative Title>
|
||||
|
||||
## Summary
|
||||
- Lead agent/persona:
|
||||
- Supporting agents:
|
||||
- Problem statement:
|
||||
- Success metrics:
|
||||
|
||||
## Scope
|
||||
- In scope:
|
||||
- Out of scope:
|
||||
- Dependencies / upstream projects:
|
||||
|
||||
## Risks & Mitigations
|
||||
- Risk 1 – mitigation
|
||||
- Risk 2 – mitigation
|
||||
|
||||
## Testing & Validation
|
||||
- Required test targets:
|
||||
- ROM/test data requirements:
|
||||
- Manual validation steps (if any):
|
||||
|
||||
## Documentation Impact
|
||||
- Public docs to update:
|
||||
- Internal docs/templates to update:
|
||||
- Coordination board entry link:
|
||||
- Helper scripts to use/log: `scripts/agents/smoke-build.sh`, `scripts/agents/run-tests.sh`, `scripts/agents/run-gh-workflow.sh`
|
||||
|
||||
## Timeline / Checkpoints
|
||||
- Milestone 1 (description, ETA)
|
||||
- Milestone 2 (description, ETA)
|
||||
```
|
||||
|
||||
After filling in the template:
|
||||
1. Check the coordination board for conflicts before starting work.
|
||||
2. Link the initiative file from your board entries so other agents can find details without copying
|
||||
sections into multiple docs.
|
||||
3. Archive or mark the initiative as complete when the success metrics are met.
|
||||
@@ -0,0 +1,44 @@
|
||||
# Initiative: Test Suite Slimdown & Gating
|
||||
|
||||
## Goal
|
||||
Reduce test bloat, keep high-signal coverage, and gate optional AI/ROM/bench suites. Deliver lean default CI (stable + smokes) with optional nightly heavy suites.
|
||||
|
||||
## Scope & Owners
|
||||
- **test-infrastructure-expert**: Owns harness/labels/CTests; flake triage and duplication removal.
|
||||
- **ai-infra-architect**: Owns AI/experimental/ROM gating logic (skip when keys/runtime missing).
|
||||
- **docs-janitor**: Updates docs (test/README, CI docs) for default vs optional suites.
|
||||
- **backend-infra-engineer**: CI pipeline changes (default vs nightly matrices).
|
||||
- **imgui-frontend-engineer**: Rendering/UI test pruning, keep one rendering suite.
|
||||
- **snes-emulator-expert**: Consult if emulator tests are affected.
|
||||
- **GEMINI_AUTOM**: Quick TODO fixes in tests (small, low-risk).
|
||||
|
||||
## Deliverables
|
||||
1) Default test set: stable + e2e smokes (framework, dungeon editor, canvas); one rendering suite only.
|
||||
2) Optional suites gated: ROM-dependent, AI experimental, benchmarks (off by default); skip cleanly when missing ROM/keys.
|
||||
3) Prune duplicates: drop legacy rendering/e2e duplicates and legacy dungeon_editor_test if v2 covers it.
|
||||
4) Docs: Updated test/README and CI docs with clear run commands and labels.
|
||||
5) CI: PR/commit matrix runs lean set; nightly matrix runs optional suites.
|
||||
|
||||
## Tasks
|
||||
- Inventory and prune
|
||||
- Keep integration/dungeon_object_rendering_tests_new.cc; drop older rendering integration + e2e variants.
|
||||
- Drop/retire dungeon_editor_test.cc (v1) if v2 covers current UI.
|
||||
- Gating
|
||||
- Ensure yaze_test_experimental and rom_dependent suites are off by default; add labels/presets for nightly.
|
||||
- AI tests skip gracefully if AI runtime/key missing.
|
||||
- CI changes
|
||||
- PR: stable + smokes only; Nightly: add ROM + AI + bench.
|
||||
- Docs
|
||||
- Update test/README.md and CI docs to reflect default vs optional suites and commands/labels.
|
||||
- Quick fixes
|
||||
- Triage TODOs: compression header off-by-one, test_editor window/controller handling; fix or mark skipped with reason.
|
||||
|
||||
## Success Criteria
|
||||
- CTest/CI default runs execute only stable + smokes and one rendering suite.
|
||||
- Optional suites runnable via label/preset; fail early if pre-reqs missing.
|
||||
- Documentation matches actual behavior.
|
||||
- No regressions in core stable tests.
|
||||
|
||||
## Coordination
|
||||
- Post progress/hand-offs to coordination-board.md.
|
||||
- Use designated agent IDs above when claiming work.
|
||||
@@ -0,0 +1,224 @@
|
||||
# Gemini Pro 3 Overworld Architecture Reference
|
||||
|
||||
Compact reference for YAZE Overworld/Dungeon systems. Use this to quickly locate code and understand patterns.
|
||||
|
||||
---
|
||||
|
||||
## 1. Overworld Editor Architecture (~8,900 lines across 7 modules)
|
||||
|
||||
### Main Editor
|
||||
| File | Lines | Purpose |
|
||||
|------|-------|---------|
|
||||
| `src/app/editor/overworld/overworld_editor.cc` | 3,204 | Main coordinator, canvas, menus |
|
||||
| `src/app/editor/overworld/overworld_editor.h` | 350 | Class definition |
|
||||
|
||||
### Sub-Modules
|
||||
| File | Lines | Purpose |
|
||||
|------|-------|---------|
|
||||
| `map_properties.cc` | 1,759 | `MapPropertiesSystem` - property panels |
|
||||
| `tile16_editor.cc` | 2,584 | `Tile16Editor` - tile editing popup |
|
||||
| `entity.cc` | 491 | `OverworldEntity` - entity containers |
|
||||
| `entity_operations.cc` | 239 | Entity CRUD helpers |
|
||||
| `overworld_entity_renderer.cc` | 151 | Entity drawing |
|
||||
| `scratch_space.cc` | 444 | Tile16 storage utilities |
|
||||
|
||||
### Data Models
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `src/zelda3/overworld/overworld.cc` | Main overworld class, loading logic |
|
||||
| `src/zelda3/overworld/overworld_map.cc` | Individual map data |
|
||||
| `src/zelda3/overworld/overworld_item.cc` | Item entities |
|
||||
| `src/zelda3/overworld/overworld_version_helper.h` | Version detection API |
|
||||
|
||||
---
|
||||
|
||||
## 2. Completed Work (Gemini's Previous Session)
|
||||
|
||||
### ASM Version Check Standardization
|
||||
- Replaced raw `asm_version >= 3` with `OverworldVersionHelper::SupportsAreaEnum()`
|
||||
- Fixed critical bug: vanilla ROMs (0xFF) incorrectly treated as v3+
|
||||
- Applied consistently across: `overworld.cc`, `overworld_item.cc`, `overworld_map.cc`
|
||||
|
||||
### Tile16Editor Texture Queueing
|
||||
- Fixed `tile16_editor.cc` lines 37-38, 44-45, 56-57
|
||||
- Pattern: `QueueTextureCommand()` instead of `RenderBitmap()` during init
|
||||
|
||||
### Test Infrastructure
|
||||
- Created `test/unit/zelda3/overworld_regression_test.cc`
|
||||
- Tests `OverworldVersionHelper` logic (passing)
|
||||
|
||||
---
|
||||
|
||||
## 3. Remaining Work Checklist
|
||||
|
||||
### P0 - Must Complete
|
||||
|
||||
#### Texture Queueing TODOs in overworld_editor.cc
|
||||
6 locations still use inline rendering instead of deferred queueing:
|
||||
|
||||
| Line | Current Code | Fix Pattern |
|
||||
|------|--------------|-------------|
|
||||
| 1392 | `// TODO: Queue texture` | Use `QueueTextureCommand()` |
|
||||
| 1397 | `// TODO: Queue texture` | Use `QueueTextureCommand()` |
|
||||
| 1740 | `// TODO: Queue texture` | Use `QueueTextureCommand()` |
|
||||
| 1809 | `// TODO: Queue texture` | Use `QueueTextureCommand()` |
|
||||
| 1819 | `// TODO: Queue texture` | Use `QueueTextureCommand()` |
|
||||
| 1962 | `// TODO: Queue texture` | Use `QueueTextureCommand()` |
|
||||
|
||||
**Pattern to follow** (from tile16_editor.cc):
|
||||
```cpp
|
||||
// BEFORE (blocking)
|
||||
Renderer::Get().RenderBitmap(&some_bitmap_);
|
||||
|
||||
// AFTER (non-blocking)
|
||||
gfx::Arena::Get().QueueTextureCommand(gfx::TextureCommand{
|
||||
.operation = gfx::TextureOperation::kCreate,
|
||||
.bitmap = &some_bitmap_,
|
||||
.priority = gfx::TexturePriority::kHigh
|
||||
});
|
||||
```
|
||||
|
||||
#### Entity Deletion Pattern (entity.cc:319) - WORKING CORRECTLY
|
||||
- **Note:** The TODO comment is misleading. The `deleted` flag pattern IS CORRECT for ROM editors
|
||||
- Entities live at fixed ROM offsets, so marking `deleted = true` is the proper approach
|
||||
- Renderer correctly skips deleted entities (see `overworld_entity_renderer.cc`)
|
||||
- `entity_operations.cc` reuses deleted slots when creating new entities
|
||||
- **No fix needed** - just a cleanup of the misleading TODO comment
|
||||
|
||||
### P1 - Should Complete
|
||||
|
||||
#### Tile16Editor Undo/Redo - ALREADY COMPLETE
|
||||
- Location: `tile16_editor.cc:1681-1760`
|
||||
- `SaveUndoState()` called before all edit operations
|
||||
- `Undo()` and `Redo()` fully implemented with `absl::Status` returns
|
||||
- Ctrl+Z/Ctrl+Y handling at lines 224-231
|
||||
- Stack management with `kMaxUndoStates_` limit
|
||||
- **No additional work needed**
|
||||
|
||||
#### Overworld Regression Test Completion
|
||||
- Location: `test/unit/zelda3/overworld_regression_test.cc`
|
||||
- Current: Only tests version helper
|
||||
- Need: Add more comprehensive mock ROM data
|
||||
|
||||
### P2 - Stretch Goals
|
||||
|
||||
#### Dungeon Downwards Draw Routines
|
||||
- Location: `src/zelda3/dungeon/object_drawer.cc` lines 160-185
|
||||
- Missing implementations marked with stubs
|
||||
- Need: Implement based on game ROM patterns
|
||||
|
||||
#### E2E Cinematic Tests
|
||||
- Design doc: `docs/internal/testing/dungeon-gui-test-design.md`
|
||||
- Framework: ImGuiTestEngine integration ready
|
||||
- Need: Screenshot capture, visual verification
|
||||
|
||||
---
|
||||
|
||||
## 4. Key Patterns
|
||||
|
||||
### Bitmap/Surface Synchronization
|
||||
```cpp
|
||||
// CORRECT: Use set_data() for bulk replacement
|
||||
bitmap.set_data(new_data); // Syncs both data_ and surface_->pixels
|
||||
|
||||
// WRONG: Direct assignment breaks sync
|
||||
bitmap.mutable_data() = new_data; // NEVER DO THIS
|
||||
```
|
||||
|
||||
### Graphics Refresh Order
|
||||
```cpp
|
||||
// 1. Update model
|
||||
map.SetProperty(new_value);
|
||||
|
||||
// 2. Reload from ROM
|
||||
map.LoadAreaGraphics();
|
||||
|
||||
// 3. Force render
|
||||
Renderer::Get().RenderBitmap(&map_bitmap_); // Immediate
|
||||
// OR
|
||||
gfx::Arena::Get().QueueTextureCommand(...); // Deferred (preferred)
|
||||
```
|
||||
|
||||
### Version Helper Usage
|
||||
```cpp
|
||||
#include "zelda3/overworld/overworld_version_helper.h"
|
||||
|
||||
auto version = OverworldVersionHelper::GetVersion(*rom_);
|
||||
|
||||
// Feature gates
|
||||
if (OverworldVersionHelper::SupportsAreaEnum(version)) {
|
||||
// v3+ only features
|
||||
}
|
||||
if (OverworldVersionHelper::SupportsExpandedSpace(version)) {
|
||||
// v1+ features
|
||||
}
|
||||
```
|
||||
|
||||
### Entity Rendering Colors (0.85f alpha)
|
||||
```cpp
|
||||
ImVec4 entrance_color(1.0f, 0.85f, 0.0f, 0.85f); // Bright yellow-gold
|
||||
ImVec4 exit_color(0.0f, 1.0f, 1.0f, 0.85f); // Cyan
|
||||
ImVec4 item_color(1.0f, 0.0f, 0.0f, 0.85f); // Bright red
|
||||
ImVec4 sprite_color(1.0f, 0.0f, 1.0f, 0.85f); // Bright magenta
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. File Quick Reference
|
||||
|
||||
### Overworld Editor Entry Points
|
||||
- `Initialize()` → overworld_editor.cc:64
|
||||
- `Load()` → overworld_editor.cc:150
|
||||
- `Update()` → overworld_editor.cc:203
|
||||
- `DrawFullscreenCanvas()` → overworld_editor.cc:472
|
||||
- `ProcessDeferredTextures()` → overworld_editor.cc:899
|
||||
|
||||
### Tile16Editor Entry Points
|
||||
- `Initialize()` → tile16_editor.cc:30
|
||||
- `Update()` → tile16_editor.cc:100
|
||||
- `DrawTile16Editor()` → tile16_editor.cc:200
|
||||
|
||||
### Entity System Entry Points
|
||||
- `OverworldEntity::Draw()` → entity.cc:50
|
||||
- `DeleteSelectedEntity()` → entity.cc:319
|
||||
- Entity containers: `entrances_`, `exits_`, `items_`, `sprites_`
|
||||
|
||||
### Dungeon System Entry Points
|
||||
- `ObjectDrawer::DrawObject()` → object_drawer.cc:50
|
||||
- Draw routines: lines 100-300
|
||||
- Downwards stubs: lines 160-185
|
||||
|
||||
---
|
||||
|
||||
## 6. Test Commands
|
||||
|
||||
```bash
|
||||
# Run overworld regression test specifically
|
||||
ctest --test-dir build_gemini -R "OverworldRegression" -V
|
||||
|
||||
# Run all zelda3 unit tests
|
||||
ctest --test-dir build_gemini -R "zelda3" -L unit
|
||||
|
||||
# Run GUI E2E tests
|
||||
ctest --test-dir build_gemini -L gui -V
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Validation Criteria
|
||||
|
||||
### For Texture Queueing Fix
|
||||
- [ ] No `// TODO` comments remain at specified lines
|
||||
- [ ] `QueueTextureCommand()` used consistently
|
||||
- [ ] UI doesn't freeze when loading maps
|
||||
- [ ] `ctest -L stable` passes
|
||||
|
||||
### For Entity Deletion Fix
|
||||
- [ ] Items actually removed from vector
|
||||
- [ ] No memory leaks (items properly destroyed)
|
||||
- [ ] Undo can restore deleted items (if implementing undo)
|
||||
|
||||
### For Dungeon Draw Routines
|
||||
- [ ] Downwards objects render correctly
|
||||
- [ ] Layer ordering maintained (BG1 → BG2 → BG3)
|
||||
- [ ] Palette applied correctly after render
|
||||
@@ -0,0 +1,859 @@
|
||||
# Z3ED CLI & Agent API Enhancement Design
|
||||
|
||||
## Executive Summary
|
||||
|
||||
This document outlines comprehensive enhancements to the z3ed CLI and agent APIs to significantly improve AI agent interaction with YAZE. The design focuses on enabling better automation, testing, and feature development through a robust command interface, programmatic editor access, and enhanced collaboration features.
|
||||
|
||||
## Current Architecture Analysis
|
||||
|
||||
### Existing Components
|
||||
- **CLI Framework**: ModernCLI with CommandRegistry pattern
|
||||
- **Command Handlers**: 70+ specialized handlers (hex, palette, sprite, music, dialogue, dungeon, overworld, gui, emulator)
|
||||
- **Canvas Automation API**: Programmatic interface for tile operations, selection, and view control
|
||||
- **Network Client**: WebSocket/HTTP fallback for collaborative editing
|
||||
- **HTTP API**: REST endpoints for health, models, and basic operations
|
||||
- **Model Integration**: Ollama and Gemini support through ModelRegistry
|
||||
|
||||
### Key Strengths
|
||||
- Clean command handler abstraction with consistent execution pattern
|
||||
- Canvas automation already supports tile operations and coordinate conversion
|
||||
- Network infrastructure in place for collaboration
|
||||
- Extensible model registry for multiple AI providers
|
||||
|
||||
### Gaps to Address
|
||||
- Limited ROM direct manipulation commands
|
||||
- No session persistence or REPL mode
|
||||
- Minimal test generation capabilities
|
||||
- Limited agent coordination features
|
||||
- No batch operation support for complex workflows
|
||||
- Missing introspection and discovery APIs
|
||||
|
||||
## 1. Z3ED CLI Enhancements
|
||||
|
||||
### 1.1 ROM Operations Commands
|
||||
|
||||
```bash
|
||||
# Direct ROM manipulation
|
||||
z3ed rom read --address <hex> [--length <bytes>] [--format hex|ascii|binary]
|
||||
z3ed rom write --address <hex> --data <hex_string> [--verify]
|
||||
z3ed rom validate [--checksums] [--headers] [--regions]
|
||||
z3ed rom diff --base <rom1> --compare <rom2> [--output patch]
|
||||
z3ed rom patch --input <rom> --patch <ips|bps> --output <patched_rom>
|
||||
z3ed rom export --region <name> --start <hex> --end <hex> --output <file>
|
||||
z3ed rom import --region <name> --address <hex> --input <file>
|
||||
|
||||
# ROM state management
|
||||
z3ed rom snapshot --name <snapshot_name> [--compress]
|
||||
z3ed rom restore --snapshot <name> [--verify]
|
||||
z3ed rom list-snapshots [--details]
|
||||
z3ed rom compare-snapshot --current --snapshot <name>
|
||||
```
|
||||
|
||||
#### Implementation Details
|
||||
```cpp
|
||||
class RomReadCommandHandler : public CommandHandler {
|
||||
protected:
|
||||
absl::Status ValidateArgs(const ArgumentParser& parser) override {
|
||||
RETURN_IF_ERROR(parser.RequireArgs({"address"}));
|
||||
if (auto len = parser.GetInt("length")) {
|
||||
if (*len <= 0 || *len > 0x10000) {
|
||||
return absl::InvalidArgumentError("Length must be 1-65536 bytes");
|
||||
}
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status Execute(Rom* rom, const ArgumentParser& parser,
|
||||
OutputFormatter& formatter) override {
|
||||
uint32_t address = parser.GetHex("address").value();
|
||||
int length = parser.GetInt("length").value_or(16);
|
||||
std::string format = parser.GetString("format").value_or("hex");
|
||||
|
||||
std::vector<uint8_t> data;
|
||||
for (int i = 0; i < length; i++) {
|
||||
data.push_back(rom->ReadByte(address + i));
|
||||
}
|
||||
|
||||
formatter.AddField("address", absl::StrFormat("0x%06X", address));
|
||||
formatter.AddField("data", FormatData(data, format));
|
||||
return absl::OkStatus();
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### 1.2 Editor Automation Commands
|
||||
|
||||
```bash
|
||||
# Dungeon editor automation
|
||||
z3ed editor dungeon place-object --room <id> --type <object_id> --x <x> --y <y>
|
||||
z3ed editor dungeon remove-object --room <id> --object-index <idx>
|
||||
z3ed editor dungeon set-property --room <id> --property <name> --value <val>
|
||||
z3ed editor dungeon list-objects --room <id> [--filter-type <type>]
|
||||
z3ed editor dungeon validate-room --room <id> [--fix-issues]
|
||||
|
||||
# Overworld editor automation
|
||||
z3ed editor overworld set-tile --map <id> --x <x> --y <y> --tile <tile_id>
|
||||
z3ed editor overworld place-entrance --map <id> --x <x> --y <y> --target <room>
|
||||
z3ed editor overworld modify-sprite --map <id> --sprite-index <idx> --property <prop> --value <val>
|
||||
z3ed editor overworld generate-minimap --map <id> --output <file>
|
||||
|
||||
# Graphics editor automation
|
||||
z3ed editor graphics import-sheet --sheet <id> --file <png> [--palette <id>]
|
||||
z3ed editor graphics export-sheet --sheet <id> --output <png>
|
||||
z3ed editor graphics modify-palette --palette <id> --color <idx> --rgb <#RRGGBB>
|
||||
|
||||
# Batch operations
|
||||
z3ed editor batch --script <file> [--dry-run] [--parallel]
|
||||
```
|
||||
|
||||
#### Batch Script Format (JSON)
|
||||
```json
|
||||
{
|
||||
"operations": [
|
||||
{
|
||||
"editor": "dungeon",
|
||||
"action": "place-object",
|
||||
"params": {
|
||||
"room": 1,
|
||||
"type": 0x22,
|
||||
"x": 10,
|
||||
"y": 15
|
||||
}
|
||||
},
|
||||
{
|
||||
"editor": "overworld",
|
||||
"action": "set-tile",
|
||||
"params": {
|
||||
"map": 0x00,
|
||||
"x": 20,
|
||||
"y": 30,
|
||||
"tile": 0x142
|
||||
}
|
||||
}
|
||||
],
|
||||
"options": {
|
||||
"stop_on_error": false,
|
||||
"validate_after": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 1.3 Testing Commands
|
||||
|
||||
```bash
|
||||
# Test execution
|
||||
z3ed test run --category <unit|integration|e2e> [--filter <pattern>]
|
||||
z3ed test validate-feature --feature <name> [--rom <file>]
|
||||
z3ed test generate --target <class|file> --output <test_file>
|
||||
z3ed test coverage --report <html|json|text>
|
||||
|
||||
# Test recording
|
||||
z3ed test record --name <test_name> --start
|
||||
z3ed test record --stop [--save-as <file>]
|
||||
z3ed test playback --file <test_file> [--speed <1-10>]
|
||||
|
||||
# Regression testing
|
||||
z3ed test baseline --create --name <baseline>
|
||||
z3ed test baseline --compare --name <baseline> [--threshold <percent>]
|
||||
```
|
||||
|
||||
### 1.4 Build & Deploy Commands
|
||||
|
||||
```bash
|
||||
# Build management
|
||||
z3ed build --preset <preset> [--verbose] [--parallel <jobs>]
|
||||
z3ed build clean [--all]
|
||||
z3ed build test [--preset <preset>]
|
||||
z3ed build package --platform <win|mac|linux> --output <dir>
|
||||
|
||||
# CI/CD integration
|
||||
z3ed ci status [--workflow <name>]
|
||||
z3ed ci trigger --workflow <name> [--branch <branch>]
|
||||
z3ed ci logs --run-id <id> [--follow]
|
||||
z3ed ci artifacts --run-id <id> --download <path>
|
||||
```
|
||||
|
||||
### 1.5 Query & Introspection Interface
|
||||
|
||||
```bash
|
||||
# System queries
|
||||
z3ed query rom-info [--detailed]
|
||||
z3ed query test-status [--failures-only]
|
||||
z3ed query build-status [--preset <preset>]
|
||||
z3ed query available-commands [--category <cat>] [--format tree|list|json]
|
||||
|
||||
# Data queries
|
||||
z3ed query find-tiles --pattern <hex> [--context <bytes>]
|
||||
z3ed query find-sprites --type <id> [--map <id>]
|
||||
z3ed query find-text --search <string> [--case-sensitive]
|
||||
z3ed query dependencies --entity <type:id>
|
||||
|
||||
# Statistics
|
||||
z3ed query stats --type <rom|dungeon|overworld|sprites>
|
||||
z3ed query usage --command <name> [--since <date>]
|
||||
```
|
||||
|
||||
### 1.6 Interactive REPL Mode
|
||||
|
||||
```bash
|
||||
# Start REPL
|
||||
z3ed repl [--rom <file>] [--history <file>]
|
||||
|
||||
# REPL Features:
|
||||
# - Persistent ROM state across commands
|
||||
# - Command history with arrow keys
|
||||
# - Tab completion for commands and parameters
|
||||
# - Context-aware suggestions
|
||||
# - Session recording/playback
|
||||
# - Variable assignment ($var = command output)
|
||||
# - Pipes and filters (command1 | command2)
|
||||
```
|
||||
|
||||
#### REPL Implementation
|
||||
```cpp
|
||||
class ReplSession {
|
||||
Rom* rom_;
|
||||
std::map<std::string, json> variables_;
|
||||
std::vector<std::string> history_;
|
||||
|
||||
public:
|
||||
absl::Status ProcessLine(const std::string& line) {
|
||||
// Parse for variable assignment
|
||||
if (auto var_match = ParseVariableAssignment(line)) {
|
||||
auto result = ExecuteCommand(var_match->command);
|
||||
variables_[var_match->var_name] = result;
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// Parse for pipes
|
||||
if (auto pipe_commands = ParsePipe(line)) {
|
||||
json previous_output;
|
||||
for (const auto& cmd : *pipe_commands) {
|
||||
auto expanded = ExpandVariables(cmd, previous_output);
|
||||
previous_output = ExecuteCommand(expanded);
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// Simple command
|
||||
return ExecuteCommand(line);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## 2. Agent API Improvements
|
||||
|
||||
### 2.1 Enhanced Canvas Automation API
|
||||
|
||||
```cpp
|
||||
namespace yaze {
|
||||
namespace gui {
|
||||
|
||||
class EnhancedCanvasAutomationAPI : public CanvasAutomationAPI {
|
||||
public:
|
||||
// Object selection by properties
|
||||
struct ObjectQuery {
|
||||
std::optional<int> type_id;
|
||||
std::optional<ImVec2> position_min;
|
||||
std::optional<ImVec2> position_max;
|
||||
std::optional<std::string> name_pattern;
|
||||
std::map<std::string, std::any> properties;
|
||||
};
|
||||
|
||||
std::vector<ObjectHandle> FindObjects(const ObjectQuery& query) const;
|
||||
|
||||
// Batch operations
|
||||
struct BatchOperation {
|
||||
enum Type { MOVE, MODIFY, DELETE, DUPLICATE };
|
||||
Type type;
|
||||
std::vector<ObjectHandle> objects;
|
||||
std::map<std::string, std::any> parameters;
|
||||
};
|
||||
|
||||
absl::Status ExecuteBatch(const std::vector<BatchOperation>& ops);
|
||||
|
||||
// Validation queries
|
||||
bool IsValidPlacement(ObjectHandle obj, ImVec2 position) const;
|
||||
std::vector<std::string> GetPlacementErrors(ObjectHandle obj, ImVec2 pos) const;
|
||||
|
||||
// Event simulation
|
||||
void SimulateClick(ImVec2 position, int button = 0);
|
||||
void SimulateDrag(ImVec2 from, ImVec2 to);
|
||||
void SimulateKeyPress(ImGuiKey key, bool shift = false, bool ctrl = false);
|
||||
void SimulateContextMenu(ImVec2 position);
|
||||
|
||||
// Advanced queries
|
||||
struct CanvasStatistics {
|
||||
int total_objects;
|
||||
std::map<int, int> objects_by_type;
|
||||
float canvas_coverage_percent;
|
||||
ImVec2 bounding_box_min;
|
||||
ImVec2 bounding_box_max;
|
||||
};
|
||||
|
||||
CanvasStatistics GetStatistics() const;
|
||||
|
||||
// Undo/Redo support
|
||||
bool CanUndo() const;
|
||||
bool CanRedo() const;
|
||||
void Undo();
|
||||
void Redo();
|
||||
std::vector<std::string> GetUndoHistory(int count = 10) const;
|
||||
};
|
||||
|
||||
} // namespace gui
|
||||
} // namespace yaze
|
||||
```
|
||||
|
||||
### 2.2 Programmatic Editor Access
|
||||
|
||||
```cpp
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
|
||||
class EditorAutomationAPI {
|
||||
public:
|
||||
// Editor lifecycle
|
||||
absl::Status OpenEditor(EditorType type, const std::string& params = "");
|
||||
absl::Status CloseEditor(EditorHandle handle);
|
||||
std::vector<EditorHandle> GetOpenEditors() const;
|
||||
|
||||
// State snapshots
|
||||
absl::StatusOr<EditorSnapshot> CaptureState(EditorHandle editor);
|
||||
absl::Status RestoreState(EditorHandle editor, const EditorSnapshot& snapshot);
|
||||
absl::Status CompareStates(const EditorSnapshot& s1, const EditorSnapshot& s2);
|
||||
|
||||
// Query current state
|
||||
struct EditorState {
|
||||
EditorType type;
|
||||
std::string name;
|
||||
bool has_unsaved_changes;
|
||||
std::map<std::string, std::any> properties;
|
||||
std::vector<std::string> available_actions;
|
||||
};
|
||||
|
||||
EditorState GetState(EditorHandle editor) const;
|
||||
|
||||
// Execute operations
|
||||
absl::Status ExecuteAction(EditorHandle editor,
|
||||
const std::string& action,
|
||||
const json& parameters);
|
||||
|
||||
// Event subscription
|
||||
using EventCallback = std::function<void(const EditorEvent&)>;
|
||||
|
||||
void Subscribe(EditorHandle editor, EventType type, EventCallback cb);
|
||||
void Unsubscribe(EditorHandle editor, EventType type);
|
||||
|
||||
// Validation
|
||||
absl::Status ValidateEditor(EditorHandle editor);
|
||||
std::vector<ValidationIssue> GetValidationIssues(EditorHandle editor);
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
```
|
||||
|
||||
### 2.3 Test Generation API
|
||||
|
||||
```cpp
|
||||
namespace yaze {
|
||||
namespace test {
|
||||
|
||||
class TestGenerationAPI {
|
||||
public:
|
||||
// Record interactions
|
||||
void StartRecording(const std::string& test_name);
|
||||
void StopRecording();
|
||||
void PauseRecording();
|
||||
void ResumeRecording();
|
||||
|
||||
// Generate tests from recordings
|
||||
absl::StatusOr<std::string> GenerateTestCode(
|
||||
const std::string& test_name,
|
||||
TestFramework framework = TestFramework::GTEST);
|
||||
|
||||
// Generate tests from specifications
|
||||
struct TestSpecification {
|
||||
std::string class_under_test;
|
||||
std::vector<std::string> methods_to_test;
|
||||
bool include_edge_cases = true;
|
||||
bool include_error_cases = true;
|
||||
bool generate_mocks = true;
|
||||
};
|
||||
|
||||
absl::StatusOr<std::string> GenerateTests(const TestSpecification& spec);
|
||||
|
||||
// Test fixtures from state
|
||||
absl::StatusOr<std::string> GenerateFixture(EditorHandle editor);
|
||||
|
||||
// Regression test generation
|
||||
absl::StatusOr<std::string> GenerateRegressionTest(
|
||||
const std::string& bug_description,
|
||||
const std::vector<std::string>& repro_steps);
|
||||
|
||||
// Test execution
|
||||
struct TestResult {
|
||||
bool passed;
|
||||
std::string output;
|
||||
double execution_time_ms;
|
||||
std::vector<std::string> failures;
|
||||
};
|
||||
|
||||
absl::StatusOr<TestResult> RunGeneratedTest(const std::string& test_code);
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
} // namespace yaze
|
||||
```
|
||||
|
||||
## 3. Agent UI Enhancements
|
||||
|
||||
### 3.1 Status Dashboard
|
||||
|
||||
```cpp
|
||||
class AgentStatusDashboard : public Panel {
|
||||
public:
|
||||
void Draw() override {
|
||||
// Real-time agent activity
|
||||
DrawAgentActivity();
|
||||
|
||||
// Test execution progress
|
||||
DrawTestProgress();
|
||||
|
||||
// Build/CI status
|
||||
DrawBuildStatus();
|
||||
|
||||
// Recent changes
|
||||
DrawRecentChanges();
|
||||
|
||||
// Performance metrics
|
||||
DrawPerformanceMetrics();
|
||||
}
|
||||
|
||||
private:
|
||||
struct AgentActivity {
|
||||
std::string agent_name;
|
||||
std::string current_task;
|
||||
float progress_percent;
|
||||
std::chrono::steady_clock::time_point started_at;
|
||||
};
|
||||
|
||||
std::vector<AgentActivity> active_agents_;
|
||||
|
||||
void DrawAgentActivity() {
|
||||
ImGui::Text("Active Agents");
|
||||
for (const auto& agent : active_agents_) {
|
||||
ImGui::ProgressBar(agent.progress_percent / 100.0f,
|
||||
ImVec2(-1, 0),
|
||||
agent.current_task.c_str());
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### 3.2 Agent Control Panel
|
||||
|
||||
```cpp
|
||||
class AgentControlPanel : public Panel {
|
||||
public:
|
||||
void Draw() override {
|
||||
// Agent task management
|
||||
if (ImGui::Button("Start New Task")) {
|
||||
ShowTaskDialog();
|
||||
}
|
||||
|
||||
// Active tasks
|
||||
DrawActiveTasks();
|
||||
|
||||
// Agent logs
|
||||
DrawAgentLogs();
|
||||
|
||||
// Manual intervention
|
||||
DrawInterventionControls();
|
||||
|
||||
// Collaboration coordination
|
||||
DrawCollaborationStatus();
|
||||
}
|
||||
|
||||
private:
|
||||
void ShowTaskDialog() {
|
||||
ImGui::OpenPopup("New Agent Task");
|
||||
if (ImGui::BeginPopupModal("New Agent Task")) {
|
||||
static char task_name[256];
|
||||
ImGui::InputText("Task Name", task_name, sizeof(task_name));
|
||||
|
||||
static int selected_agent = 0;
|
||||
ImGui::Combo("Agent", &selected_agent, available_agents_);
|
||||
|
||||
if (ImGui::Button("Start")) {
|
||||
StartAgentTask(task_name, selected_agent);
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## 4. Network/Collaboration Features
|
||||
|
||||
### 4.1 Multi-Agent Coordination
|
||||
|
||||
```cpp
|
||||
namespace yaze {
|
||||
namespace agent {
|
||||
|
||||
class MultiAgentCoordinator {
|
||||
public:
|
||||
// Agent registration
|
||||
absl::Status RegisterAgent(const AgentInfo& info);
|
||||
absl::Status UnregisterAgent(const std::string& agent_id);
|
||||
|
||||
// Work queue management
|
||||
absl::Status QueueTask(const Task& task);
|
||||
absl::StatusOr<Task> ClaimTask(const std::string& agent_id);
|
||||
absl::Status CompleteTask(const std::string& task_id, const TaskResult& result);
|
||||
|
||||
// Shared state
|
||||
absl::Status UpdateSharedState(const std::string& key, const json& value);
|
||||
absl::StatusOr<json> GetSharedState(const std::string& key);
|
||||
absl::Status SubscribeToState(const std::string& key, StateCallback cb);
|
||||
|
||||
// Conflict resolution
|
||||
enum ConflictStrategy {
|
||||
LAST_WRITE_WINS,
|
||||
MERGE,
|
||||
MANUAL_RESOLUTION,
|
||||
QUEUE_SEQUENTIAL
|
||||
};
|
||||
|
||||
absl::Status SetConflictStrategy(ConflictStrategy strategy);
|
||||
absl::StatusOr<Resolution> ResolveConflict(const Conflict& conflict);
|
||||
|
||||
// Agent discovery
|
||||
std::vector<AgentInfo> DiscoverAgents(const AgentQuery& query);
|
||||
absl::StatusOr<AgentCapabilities> GetCapabilities(const std::string& agent_id);
|
||||
};
|
||||
|
||||
} // namespace agent
|
||||
} // namespace yaze
|
||||
```
|
||||
|
||||
### 4.2 Remote z3ed Access
|
||||
|
||||
```yaml
|
||||
# OpenAPI 3.0 Specification
|
||||
openapi: 3.0.0
|
||||
info:
|
||||
title: Z3ED Remote API
|
||||
version: 1.0.0
|
||||
|
||||
paths:
|
||||
/api/v1/command:
|
||||
post:
|
||||
summary: Execute z3ed command
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
example: "rom read --address 0x1000 --length 16"
|
||||
session_id:
|
||||
type: string
|
||||
timeout_ms:
|
||||
type: integer
|
||||
default: 30000
|
||||
responses:
|
||||
200:
|
||||
description: Command executed successfully
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
result:
|
||||
type: object
|
||||
execution_time_ms:
|
||||
type: number
|
||||
|
||||
/api/v1/session:
|
||||
post:
|
||||
summary: Create new z3ed session
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
rom_path:
|
||||
type: string
|
||||
persist:
|
||||
type: boolean
|
||||
default: false
|
||||
responses:
|
||||
200:
|
||||
description: Session created
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
session_id:
|
||||
type: string
|
||||
expires_at:
|
||||
type: string
|
||||
format: date-time
|
||||
|
||||
/api/v1/websocket:
|
||||
get:
|
||||
summary: WebSocket endpoint for real-time updates
|
||||
responses:
|
||||
101:
|
||||
description: Switching Protocols
|
||||
```
|
||||
|
||||
### 4.3 WebSocket Protocol
|
||||
|
||||
```typescript
|
||||
// WebSocket message types
|
||||
interface Z3edWebSocketMessage {
|
||||
type: 'command' | 'event' | 'subscribe' | 'unsubscribe';
|
||||
id: string;
|
||||
payload: any;
|
||||
}
|
||||
|
||||
// Command execution
|
||||
interface CommandMessage {
|
||||
type: 'command';
|
||||
id: string;
|
||||
payload: {
|
||||
command: string;
|
||||
args: string[];
|
||||
stream: boolean; // Stream output as it's generated
|
||||
};
|
||||
}
|
||||
|
||||
// Event subscription
|
||||
interface SubscribeMessage {
|
||||
type: 'subscribe';
|
||||
id: string;
|
||||
payload: {
|
||||
events: Array<'editor.changed' | 'test.completed' | 'build.status'>;
|
||||
};
|
||||
}
|
||||
|
||||
// Server events
|
||||
interface EventMessage {
|
||||
type: 'event';
|
||||
id: string;
|
||||
payload: {
|
||||
event: string;
|
||||
data: any;
|
||||
timestamp: string;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## 5. Implementation Plan
|
||||
|
||||
### Phase 1: Foundation (Weeks 1-2)
|
||||
1. Implement core ROM operations commands
|
||||
2. Add REPL infrastructure
|
||||
3. Enhance Canvas Automation API with batch operations
|
||||
4. Create command discovery/introspection system
|
||||
|
||||
### Phase 2: Editor Integration (Weeks 3-4)
|
||||
1. Implement editor automation commands
|
||||
2. Add programmatic editor access API
|
||||
3. Create test recording infrastructure
|
||||
4. Build event subscription system
|
||||
|
||||
### Phase 3: Testing & CI (Weeks 5-6)
|
||||
1. Implement test generation API
|
||||
2. Add test execution commands
|
||||
3. Create CI/CD integration commands
|
||||
4. Build regression test framework
|
||||
|
||||
### Phase 4: Collaboration (Weeks 7-8)
|
||||
1. Implement multi-agent coordinator
|
||||
2. Add REST API endpoints
|
||||
3. Create WebSocket real-time protocol
|
||||
4. Build conflict resolution system
|
||||
|
||||
### Phase 5: UI & Polish (Weeks 9-10)
|
||||
1. Create Agent Status Dashboard
|
||||
2. Build Agent Control Panel
|
||||
3. Add comprehensive documentation
|
||||
4. Create example workflows
|
||||
|
||||
## 6. Example Workflows
|
||||
|
||||
### Workflow 1: Automated Dungeon Testing
|
||||
```bash
|
||||
# Start REPL session
|
||||
z3ed repl --rom zelda3.sfc
|
||||
|
||||
# Record baseline
|
||||
> rom snapshot --name baseline
|
||||
> editor dungeon --room 0
|
||||
|
||||
# Start test recording
|
||||
> test record --name dungeon_placement_test --start
|
||||
|
||||
# Perform operations
|
||||
> editor dungeon place-object --room 0 --type 0x22 --x 10 --y 15
|
||||
> editor dungeon place-object --room 0 --type 0x23 --x 20 --y 15
|
||||
> query stats --type dungeon
|
||||
|
||||
# Stop and generate test
|
||||
> test record --stop
|
||||
> test generate --from-recording dungeon_placement_test --output test_dungeon.cc
|
||||
```
|
||||
|
||||
### Workflow 2: Multi-Agent ROM Editing
|
||||
```python
|
||||
import z3ed_client
|
||||
|
||||
# Agent 1: Overworld specialist
|
||||
agent1 = z3ed_client.Agent("overworld_agent")
|
||||
agent1.connect("localhost:8080")
|
||||
|
||||
# Agent 2: Dungeon specialist
|
||||
agent2 = z3ed_client.Agent("dungeon_agent")
|
||||
agent2.connect("localhost:8080")
|
||||
|
||||
# Coordinator assigns tasks
|
||||
coordinator = z3ed_client.Coordinator()
|
||||
coordinator.queue_task({
|
||||
"type": "overworld",
|
||||
"action": "optimize_tilemap",
|
||||
"map_id": 0x00
|
||||
})
|
||||
coordinator.queue_task({
|
||||
"type": "dungeon",
|
||||
"action": "validate_rooms",
|
||||
"rooms": range(0, 296)
|
||||
})
|
||||
|
||||
# Agents work in parallel
|
||||
results = coordinator.wait_for_completion()
|
||||
```
|
||||
|
||||
### Workflow 3: AI-Powered Test Generation
|
||||
```bash
|
||||
# Analyze class for test generation
|
||||
z3ed test analyze --class OverworldEditor
|
||||
|
||||
# Generate comprehensive tests
|
||||
z3ed test generate \
|
||||
--target OverworldEditor \
|
||||
--include-edge-cases \
|
||||
--include-mocks \
|
||||
--framework gtest \
|
||||
--output overworld_editor_test.cc
|
||||
|
||||
# Run generated tests
|
||||
z3ed test run --file overworld_editor_test.cc --verbose
|
||||
|
||||
# Create regression test from bug
|
||||
z3ed test regression \
|
||||
--bug "Tiles corrupt when placing entrance at map boundary" \
|
||||
--repro-steps "1. Open map 0x00" "2. Place entrance at x=511,y=511" \
|
||||
--output regression_boundary_test.cc
|
||||
```
|
||||
|
||||
## 7. Security Considerations
|
||||
|
||||
### Authentication & Authorization
|
||||
- API key authentication for remote access
|
||||
- Role-based permissions (read-only, editor, admin)
|
||||
- Session management with expiration
|
||||
- Rate limiting per API key
|
||||
|
||||
### Input Validation
|
||||
- Command injection prevention
|
||||
- Path traversal protection
|
||||
- Memory address validation
|
||||
- File size limits for imports
|
||||
|
||||
### Audit Logging
|
||||
- All commands logged with timestamp and user
|
||||
- ROM modifications tracked
|
||||
- Rollback capability for destructive operations
|
||||
- Export audit trail for compliance
|
||||
|
||||
## 8. Performance Optimizations
|
||||
|
||||
### Caching
|
||||
- Command result caching for repeated queries
|
||||
- ROM state caching for snapshots
|
||||
- Compiled test cache
|
||||
- WebSocket connection pooling
|
||||
|
||||
### Batch Processing
|
||||
- Aggregate multiple operations into transactions
|
||||
- Parallel execution for independent commands
|
||||
- Lazy loading for large data sets
|
||||
- Progressive streaming for long operations
|
||||
|
||||
### Resource Management
|
||||
- Connection limits per client
|
||||
- Memory quotas for sessions
|
||||
- CPU throttling for intensive operations
|
||||
- Graceful degradation under load
|
||||
|
||||
## 9. Documentation Requirements
|
||||
|
||||
### API Reference
|
||||
- Complete command reference with examples
|
||||
- REST API OpenAPI specification
|
||||
- WebSocket protocol documentation
|
||||
- Error code reference
|
||||
|
||||
### Tutorials
|
||||
- "Getting Started with z3ed REPL"
|
||||
- "Automating ROM Testing"
|
||||
- "Multi-Agent Collaboration"
|
||||
- "Building Custom Commands"
|
||||
|
||||
### Integration Guides
|
||||
- Python client library
|
||||
- JavaScript/TypeScript SDK
|
||||
- CI/CD integration examples
|
||||
- VS Code extension
|
||||
|
||||
### Best Practices
|
||||
- Command naming conventions
|
||||
- Error handling patterns
|
||||
- Performance optimization tips
|
||||
- Security guidelines
|
||||
|
||||
## 10. Success Metrics
|
||||
|
||||
### Functionality
|
||||
- 100% coverage of editor operations via CLI
|
||||
- < 100ms command execution for simple operations
|
||||
- < 1s for complex batch operations
|
||||
- 99.9% API availability
|
||||
|
||||
### Developer Experience
|
||||
- Tab completion for all commands
|
||||
- Comprehensive error messages
|
||||
- Interactive help system
|
||||
- Example for every command
|
||||
|
||||
### Testing
|
||||
- 90% code coverage for new components
|
||||
- Automated regression tests for all commands
|
||||
- Performance benchmarks for critical paths
|
||||
- Integration tests for multi-agent scenarios
|
||||
|
||||
## Conclusion
|
||||
|
||||
These enhancements will transform z3ed from a basic CLI tool into a comprehensive automation platform for YAZE. The design prioritizes developer experience, AI agent capabilities, and robust testing infrastructure while maintaining backwards compatibility and performance.
|
||||
|
||||
The modular implementation plan allows for incremental delivery of value, with each phase providing immediately useful functionality. The foundation laid here will enable future innovations in ROM hacking automation and collaborative editing.
|
||||
Reference in New Issue
Block a user