backend-infra-engineer: Release v0.3.3 snapshot
This commit is contained in:
116
docs/public/usage/dungeon-editor.md
Normal file
116
docs/public/usage/dungeon-editor.md
Normal file
@@ -0,0 +1,116 @@
|
||||
# F2: Dungeon Editor v2 Guide
|
||||
|
||||
**Scope**: DungeonEditorV2 (card-based UI), DungeonEditorSystem, dungeon canvases
|
||||
**Related**: [Architecture Overview](../developer/architecture.md), [Canvas System](../developer/canvas-system.md)
|
||||
|
||||
---
|
||||
|
||||
## 1. Overview
|
||||
|
||||
The Dungeon Editor ships with the multi-card workspace introduced in the 0.3.x releases.
|
||||
Self-contained room buffers keep graphics, objects, and palettes isolated so you can switch between
|
||||
rooms without invalidating the entire renderer.
|
||||
|
||||
### Key Features
|
||||
- 512×512 canvas per room with pan/zoom, grid, and collision overlays.
|
||||
- Layer-specific visualization (BG1/BG2 toggles, colored object outlines, slot labels).
|
||||
- Modular cards for rooms, objects, palettes, entrances, and toolsets.
|
||||
- Undo/Redo shared across cards via `DungeonEditorSystem`.
|
||||
- Tight overworld integration: double-click an entrance to open the linked dungeon room.
|
||||
|
||||
---
|
||||
|
||||
## 2. Architecture Snapshot
|
||||
|
||||
```
|
||||
DungeonEditorV2 (UI)
|
||||
├─ Cards & docking
|
||||
├─ Canvas presenter
|
||||
└─ Menu + toolbar actions
|
||||
|
||||
DungeonEditorSystem (Backend)
|
||||
├─ Room/session state
|
||||
├─ Undo/Redo stack
|
||||
├─ Sprite/entrance/item helpers
|
||||
└─ Persistence + ROM writes
|
||||
|
||||
Room Model (Data)
|
||||
├─ bg1_buffer_, bg2_buffer_
|
||||
├─ tile_objects_, door data, metadata
|
||||
└─ Palette + blockset caches
|
||||
```
|
||||
|
||||
### Room Rendering Pipeline
|
||||
1. **Load** – `DungeonRoomLoader` reads the room header, blockset pointers, and door/entrance
|
||||
metadata, producing a `Room` instance with immutable layout info.
|
||||
2. **Decode** – The requested blockset is converted into `current_gfx16_` bitmaps; objects are parsed
|
||||
into `tile_objects_` grouped by layer and palette slot.
|
||||
3. **Draw** – `DungeonCanvasViewer` builds BG1/BG2 bitmaps, then overlays each object layer via
|
||||
`ObjectDrawer`. Palette state comes from the room’s 90-color dungeon palette.
|
||||
4. **Queue** – The finished bitmaps are pushed into the graphics `Arena`, which uploads a bounded
|
||||
number of textures per frame so UI latency stays flat.
|
||||
5. **Present** – When textures become available, the canvas displays the layers, draws interaction
|
||||
widgets (selection rectangles, door gizmos, entity labels), and applies zoom/grid settings.
|
||||
|
||||
Changing tiles, palettes, or objects invalidates the affected room cache so steps 2–5 rerun only for
|
||||
that room.
|
||||
|
||||
---
|
||||
|
||||
## 3. Editing Workflow
|
||||
|
||||
### Opening Rooms
|
||||
1. Launch `yaze` with a ROM (`./build/bin/yaze --rom_file=zelda3.sfc`).
|
||||
2. Use the **Room Matrix** or **Rooms List** card to choose a room. The toolbar “+” button also opens
|
||||
the selector.
|
||||
3. Pin multiple rooms by opening them in separate cards; each card maintains its own canvas state.
|
||||
|
||||
### Working with Cards
|
||||
|
||||
| Card | Purpose |
|
||||
|------|---------|
|
||||
| **Room Graphics** | Primary canvas, BG toggles, collision/grid switches. |
|
||||
| **Object Editor** | Filter by type/layer, edit coordinates, duplicate/delete objects. |
|
||||
| **Palette Editor** | Adjust per-room palette slots and preview results immediately. |
|
||||
| **Entrances List** | Jump between overworld entrances and their mapped rooms. |
|
||||
| **Room Matrix** | Visual grid of all rooms grouped per dungeon for quick navigation. |
|
||||
|
||||
Cards can be docked, detached, or saved as workspace presets; use the sidebar to store favorite
|
||||
layouts (e.g., Room Graphics + Object Editor + Palette).
|
||||
|
||||
### Canvas Interactions
|
||||
- Left-click to select an object; Shift-click to add to the selection.
|
||||
- Drag handles to move objects or use the property grid for precise coordinates.
|
||||
- Right-click to open the context menu, which includes quick inserts for common objects and a “jump
|
||||
to entrance” helper.
|
||||
- Hold Space to pan, use mouse wheel (or trackpad pinch) to zoom. The status footer shows current
|
||||
zoom and cursor coordinates.
|
||||
- Enable **Object Labels** from the toolbar to show layer-colored labels (e.g., `L1 Chest 0x23`).
|
||||
|
||||
### Saving & Undo
|
||||
- The editor queues every change through `DungeonEditorSystem`. Use `Cmd/Ctrl+Z` and `Cmd/Ctrl+Shift+Z`
|
||||
to undo/redo across cards.
|
||||
- Saving writes back the room buffers, door metadata, and palettes for the active session. Keep
|
||||
backups enabled (`File → Options → Experiment Flags`) for safety.
|
||||
|
||||
---
|
||||
|
||||
## 4. Tips & Troubleshooting
|
||||
|
||||
- **Layer sanity**: If objects appear on the wrong layer, check the BG toggles in Room Graphics and
|
||||
the layer filter in Object Editor—they operate independently.
|
||||
- **Palette issues**: Palettes are per room. After editing, ensure `Palette Editor` writes the new
|
||||
values before switching rooms; the status footer confirms pending writes.
|
||||
- **Door alignment**: Use the entrance/door inspector popup (right-click a door marker) to verify
|
||||
leads-to IDs without leaving the canvas.
|
||||
- **Performance**: Large ROMs with many rooms can accumulate textures. If the editor feels sluggish,
|
||||
close unused room cards; each card releases its textures when closed.
|
||||
|
||||
---
|
||||
|
||||
## 5. Related Docs
|
||||
- [Developer Architecture Overview](../developer/architecture.md) – patterns shared across editors.
|
||||
- [Canvas System Guide](../developer/canvas-system.md) – detailed explanation of canvas usage,
|
||||
context menus, and popups.
|
||||
- [Debugging Guide](../developer/debugging-guide.md) – startup flags and logging tips (e.g.,
|
||||
`--editor=Dungeon --cards="Room 0"` for focused debugging).
|
||||
554
docs/public/usage/overworld-loading.md
Normal file
554
docs/public/usage/overworld-loading.md
Normal file
@@ -0,0 +1,554 @@
|
||||
# Overworld Loading Guide
|
||||
|
||||
This document provides a comprehensive guide to understanding how overworld loading works in both ZScream (C#) and yaze (C++), including the differences between vanilla ROMs and ZSCustomOverworld v2/v3 ROMs.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Overview](#overview)
|
||||
2. [ROM Types and Versions](#rom-types-and-versions)
|
||||
3. [Overworld Map Structure](#overworld-map-structure)
|
||||
4. [Loading Process](#loading-process)
|
||||
5. [ZScream Implementation](#zscream-implementation)
|
||||
6. [Yaze Implementation](#yaze-implementation)
|
||||
7. [Key Differences](#key-differences)
|
||||
8. [Common Issues and Solutions](#common-issues-and-solutions)
|
||||
|
||||
## Overview
|
||||
|
||||
Both ZScream and yaze are Zelda 3 ROM editors that support editing overworld maps. They handle three main types of ROMs:
|
||||
|
||||
- **Vanilla ROMs**: Original Zelda 3 ROMs without modifications
|
||||
- **ZSCustomOverworld v2**: ROMs with expanded overworld features
|
||||
- **ZSCustomOverworld v3**: ROMs with additional features like overlays and custom background colors
|
||||
|
||||
## ROM Types and Versions
|
||||
|
||||
### Version Detection
|
||||
|
||||
Both editors detect the ROM version using the same constant:
|
||||
|
||||
```cpp
|
||||
// Address: 0x140145
|
||||
constexpr int OverworldCustomASMHasBeenApplied = 0x140145;
|
||||
|
||||
// Version values:
|
||||
// 0xFF = Vanilla ROM
|
||||
// 0x02 = ZSCustomOverworld v2
|
||||
// 0x03 = ZSCustomOverworld v3
|
||||
```
|
||||
|
||||
### Feature Support by Version
|
||||
|
||||
| Feature | Vanilla | v2 | v3 |
|
||||
|---------|---------|----|----|
|
||||
| Basic Overworld Maps | | | |
|
||||
| Area Size Enum | ❌ | ❌ | |
|
||||
| Main Palette | ❌ | | |
|
||||
| Custom Background Colors | ❌ | | |
|
||||
| Subscreen Overlays | | | |
|
||||
| Animated GFX | ❌ | ❌ | |
|
||||
| Custom Tile Graphics | ❌ | ❌ | |
|
||||
| Vanilla Overlays | | | |
|
||||
|
||||
**Note:** Subscreen overlays are visual effects (fog, rain, backgrounds, etc.) that are shared between vanilla ROMs and ZSCustomOverworld. ZSCustomOverworld v2+ expands on this by adding support for custom overlay configurations and additional overlay types.
|
||||
|
||||
## Overworld Map Structure
|
||||
|
||||
### Core Properties
|
||||
|
||||
Each overworld map contains the following core properties:
|
||||
|
||||
```cpp
|
||||
class OverworldMap {
|
||||
// Basic properties
|
||||
uint8_t index_; // Map index (0-159)
|
||||
uint8_t parent_; // Parent map ID
|
||||
uint8_t world_; // World type (0=LW, 1=DW, 2=SW)
|
||||
uint8_t game_state_; // Game state (0=Beginning, 1=Zelda, 2=Agahnim)
|
||||
|
||||
// Graphics and palettes
|
||||
uint8_t area_graphics_; // Area graphics ID
|
||||
uint8_t area_palette_; // Area palette ID
|
||||
uint8_t main_palette_; // Main palette ID (v2+)
|
||||
std::array<uint8_t, 3> sprite_graphics_; // Sprite graphics IDs
|
||||
std::array<uint8_t, 3> sprite_palette_; // Sprite palette IDs
|
||||
|
||||
// Map properties
|
||||
uint16_t message_id_; // Message ID
|
||||
bool mosaic_; // Mosaic effect enabled
|
||||
bool large_map_; // Is large map (vanilla)
|
||||
AreaSizeEnum area_size_; // Area size (v3)
|
||||
|
||||
// Custom features (v2/v3)
|
||||
uint16_t area_specific_bg_color_; // Custom background color
|
||||
uint16_t subscreen_overlay_; // Subscreen overlay ID (references special area maps)
|
||||
uint8_t animated_gfx_; // Animated graphics ID
|
||||
std::array<uint8_t, 8> custom_gfx_ids_; // Custom tile graphics
|
||||
|
||||
// Overlay support (vanilla and custom)
|
||||
uint16_t vanilla_overlay_id_; // Vanilla overlay ID
|
||||
bool has_vanilla_overlay_; // Has vanilla overlay data
|
||||
std::vector<uint8_t> vanilla_overlay_data_; // Raw overlay data
|
||||
};
|
||||
```
|
||||
|
||||
## Overlays and Special Area Maps
|
||||
|
||||
### Understanding Overlays
|
||||
|
||||
Overlays in Zelda 3 are **visual effects** that are displayed over or behind the main overworld map. They include effects like fog, rain, canopy, backgrounds, and other atmospheric elements. Overlays are collections of tile positions and tile IDs that specify where to place specific graphics on the map.
|
||||
|
||||
### Special Area Maps (0x80-0x9F)
|
||||
|
||||
The special area maps (0x80-0x9F) contain the actual tile data for overlays. These maps store the graphics that overlays reference and use to create visual effects:
|
||||
|
||||
- **0x80-0x8F**: Various special area maps containing overlay graphics
|
||||
- **0x90-0x9F**: Additional special area maps including more overlay graphics
|
||||
|
||||
### Overlay ID Mappings
|
||||
|
||||
Overlay IDs directly correspond to special area map indices. Common overlay mappings:
|
||||
|
||||
| Overlay ID | Special Area Map | Description |
|
||||
|------------|------------------|-------------|
|
||||
| 0x0093 | 0x93 | Triforce Room Curtain |
|
||||
| 0x0094 | 0x94 | Under the Bridge |
|
||||
| 0x0095 | 0x95 | Sky Background (LW Death Mountain) |
|
||||
| 0x0096 | 0x96 | Pyramid Background |
|
||||
| 0x0097 | 0x97 | First Fog Overlay (Master Sword Area) |
|
||||
| 0x009C | 0x9C | Lava Background (DW Death Mountain) |
|
||||
| 0x009D | 0x9D | Second Fog Overlay (Lost Woods/Skull Woods) |
|
||||
| 0x009E | 0x9E | Tree Canopy (Forest) |
|
||||
| 0x009F | 0x9F | Rain Effect (Misery Mire) |
|
||||
|
||||
### Drawing Order
|
||||
|
||||
Overlays are drawn in a specific order based on their type:
|
||||
|
||||
- **Background Overlays** (0x95, 0x96, 0x9C): Drawn behind the main map tiles
|
||||
- **Foreground Overlays** (0x9D, 0x97, 0x93, 0x94, 0x9E, 0x9F): Drawn on top of the main map tiles with transparency
|
||||
|
||||
### Vanilla Overlay Loading
|
||||
|
||||
In vanilla ROMs, overlays are loaded by parsing SNES assembly-like commands that specify tile positions and IDs:
|
||||
|
||||
```cpp
|
||||
absl::Status LoadVanillaOverlay() {
|
||||
uint8_t asm_version = (*rom_)[OverworldCustomASMHasBeenApplied];
|
||||
|
||||
// Only load vanilla overlays for vanilla ROMs
|
||||
if (asm_version != 0xFF) {
|
||||
has_vanilla_overlay_ = false;
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// Load overlay pointer for this map
|
||||
int address = (kOverlayPointersBank << 16) +
|
||||
((*rom_)[kOverlayPointers + (index_ * 2) + 1] << 8) +
|
||||
(*rom_)[kOverlayPointers + (index_ * 2)];
|
||||
|
||||
// Parse overlay commands:
|
||||
// LDA #$xxxx - Load tile ID into accumulator
|
||||
// LDX #$xxxx - Load position into X register
|
||||
// STA $xxxx - Store tile at position
|
||||
// STA $xxxx,x - Store tile at position + X
|
||||
// INC A - Increment accumulator (for sequential tiles)
|
||||
// JMP $xxxx - Jump to another overlay routine
|
||||
// END (0x60) - End of overlay data
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
```
|
||||
|
||||
### Special Area Graphics Loading
|
||||
|
||||
Special area maps require special handling for graphics loading:
|
||||
|
||||
```cpp
|
||||
void LoadAreaInfo() {
|
||||
if (parent_ >= kSpecialWorldMapIdStart) {
|
||||
// Special World (SW) areas
|
||||
if (asm_version >= 3 && asm_version != 0xFF) {
|
||||
// Use expanded sprite tables for v3
|
||||
sprite_graphics_[0] = (*rom_)[kOverworldSpecialSpriteGfxGroupExpandedTemp +
|
||||
parent_ - kSpecialWorldMapIdStart];
|
||||
} else {
|
||||
// Use original sprite tables for v2/vanilla
|
||||
sprite_graphics_[0] = (*rom_)[kOverworldSpecialGfxGroup +
|
||||
parent_ - kSpecialWorldMapIdStart];
|
||||
}
|
||||
|
||||
// Handle special cases for specific maps
|
||||
if (index_ == 0x88 || index_ == 0x93) {
|
||||
area_graphics_ = 0x51;
|
||||
area_palette_ = 0x00;
|
||||
} else if (index_ == 0x95) {
|
||||
// Make this the same GFX as LW death mountain areas
|
||||
area_graphics_ = (*rom_)[kAreaGfxIdPtr + 0x03];
|
||||
area_palette_ = (*rom_)[kOverworldMapPaletteIds + 0x03];
|
||||
} else if (index_ == 0x96) {
|
||||
// Make this the same GFX as pyramid areas
|
||||
area_graphics_ = (*rom_)[kAreaGfxIdPtr + 0x5B];
|
||||
area_palette_ = (*rom_)[kOverworldMapPaletteIds + 0x5B];
|
||||
} else if (index_ == 0x9C) {
|
||||
// Make this the same GFX as DW death mountain areas
|
||||
area_graphics_ = (*rom_)[kAreaGfxIdPtr + 0x43];
|
||||
area_palette_ = (*rom_)[kOverworldMapPaletteIds + 0x43];
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Loading Process
|
||||
|
||||
### 1. Version Detection
|
||||
|
||||
Both editors first detect the ROM version:
|
||||
|
||||
```cpp
|
||||
uint8_t asm_version = rom[OverworldCustomASMHasBeenApplied];
|
||||
```
|
||||
|
||||
### 2. Map Initialization
|
||||
|
||||
For each of the 160 overworld maps (0x00-0x9F):
|
||||
|
||||
```cpp
|
||||
// ZScream
|
||||
var map = new OverworldMap(index, overworld);
|
||||
|
||||
// Yaze
|
||||
OverworldMap map(index, rom);
|
||||
```
|
||||
|
||||
### 3. Property Loading
|
||||
|
||||
The loading process varies by ROM version:
|
||||
|
||||
#### Vanilla ROMs (asm_version == 0xFF)
|
||||
|
||||
```cpp
|
||||
void LoadAreaInfo() {
|
||||
// Load from vanilla tables
|
||||
message_id_ = rom[kOverworldMessageIds + index_ * 2];
|
||||
area_graphics_ = rom[kOverworldMapGfx + index_];
|
||||
area_palette_ = rom[kOverworldMapPaletteIds + index_];
|
||||
|
||||
// Determine large map status
|
||||
large_map_ = (rom[kOverworldMapSize + index_] != 0);
|
||||
|
||||
// Load vanilla overlay
|
||||
LoadVanillaOverlay();
|
||||
}
|
||||
```
|
||||
|
||||
#### ZSCustomOverworld v2/v3
|
||||
|
||||
```cpp
|
||||
void LoadAreaInfo() {
|
||||
// Use expanded tables for v3
|
||||
if (asm_version >= 3) {
|
||||
message_id_ = rom[kOverworldMessagesExpanded + index_ * 2];
|
||||
area_size_ = static_cast<AreaSizeEnum>(rom[kOverworldScreenSize + index_]);
|
||||
} else {
|
||||
message_id_ = rom[kOverworldMessageIds + index_ * 2];
|
||||
area_size_ = large_map_ ? LargeArea : SmallArea;
|
||||
}
|
||||
|
||||
// Load custom overworld data
|
||||
LoadCustomOverworldData();
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Custom Data Loading
|
||||
|
||||
For ZSCustomOverworld ROMs:
|
||||
|
||||
```cpp
|
||||
void LoadCustomOverworldData() {
|
||||
// Load main palette
|
||||
main_palette_ = rom[OverworldCustomMainPaletteArray + index_];
|
||||
|
||||
// Load custom background color
|
||||
if (rom[OverworldCustomAreaSpecificBGEnabled] != 0) {
|
||||
area_specific_bg_color_ = rom[OverworldCustomAreaSpecificBGPalette + index_ * 2];
|
||||
}
|
||||
|
||||
// Load v3 features
|
||||
if (asm_version >= 3) {
|
||||
subscreen_overlay_ = rom[OverworldCustomSubscreenOverlayArray + index_ * 2];
|
||||
animated_gfx_ = rom[OverworldCustomAnimatedGFXArray + index_];
|
||||
|
||||
// Load custom tile graphics (8 sheets)
|
||||
for (int i = 0; i < 8; i++) {
|
||||
custom_gfx_ids_[i] = rom[OverworldCustomTileGFXGroupArray + index_ * 8 + i];
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## ZScream Implementation
|
||||
|
||||
### OverworldMap Constructor
|
||||
|
||||
```csharp
|
||||
public OverworldMap(byte index, Overworld overworld) {
|
||||
Index = index;
|
||||
this.overworld = overworld;
|
||||
|
||||
// Load area info
|
||||
LoadAreaInfo();
|
||||
|
||||
// Load custom data if available
|
||||
if (ROM.DATA[Constants.OverworldCustomASMHasBeenApplied] != 0xFF) {
|
||||
LoadCustomOverworldData();
|
||||
}
|
||||
|
||||
// Build graphics and palette
|
||||
BuildMap();
|
||||
}
|
||||
```
|
||||
|
||||
### Key Methods
|
||||
|
||||
- `LoadAreaInfo()`: Loads basic map properties from ROM
|
||||
- `LoadCustomOverworldData()`: Loads ZSCustomOverworld features
|
||||
- `LoadPalette()`: Loads and processes palette data
|
||||
- `BuildMap()`: Constructs the final map bitmap
|
||||
|
||||
**Note**: ZScream is the original C# implementation that yaze is designed to be compatible with.
|
||||
|
||||
## Yaze Implementation
|
||||
|
||||
### OverworldMap Constructor
|
||||
|
||||
```cpp
|
||||
OverworldMap::OverworldMap(int index, Rom* rom) : index_(index), rom_(rom) {
|
||||
LoadAreaInfo();
|
||||
LoadCustomOverworldData();
|
||||
SetupCustomTileset(asm_version);
|
||||
}
|
||||
```
|
||||
|
||||
### Key Methods
|
||||
|
||||
- `LoadAreaInfo()`: Loads basic map properties
|
||||
- `LoadCustomOverworldData()`: Loads ZSCustomOverworld features
|
||||
- `LoadVanillaOverlay()`: Loads vanilla overlay data
|
||||
- `LoadPalette()`: Loads and processes palette data
|
||||
- `BuildTileset()`: Constructs graphics tileset
|
||||
- `BuildBitmap()`: Creates the final map bitmap
|
||||
|
||||
### Mode 7 Tileset Conversion
|
||||
|
||||
Mode 7 graphics live at PC `0x0C4000` as 0x4000 bytes of tiled 8×8 pixel data.
|
||||
Yaze mirrors ZScream’s tiled-to-linear conversion so SDL can consume it:
|
||||
|
||||
```cpp
|
||||
std::array<uint8_t, 0x4000> mode7_raw = rom_->ReadRange(kMode7Tiles, 0x4000);
|
||||
int pos = 0;
|
||||
for (int sy = 0; sy < 16 * 1024; sy += 1024) {
|
||||
for (int sx = 0; sx < 16 * 8; sx += 8) {
|
||||
for (int y = 0; y < 8 * 128; y += 128) {
|
||||
for (int x = 0; x < 8; ++x) {
|
||||
tileset_[x + sx + y + sy] = mode7_raw[pos++];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The result is a contiguous 128×128 tileset used by both Light and Dark world
|
||||
maps.
|
||||
|
||||
### Interleaved Tilemap Layout
|
||||
|
||||
The 64×64 tilemap (4 096 bytes) is interleaved across four 0x400-byte banks
|
||||
plus a Dark World override. Copying logic mirrors the original IDK/Zarby docs:
|
||||
|
||||
```cpp
|
||||
auto load_quadrant = [&](uint8_t* dest, const uint8_t* left,
|
||||
const uint8_t* right) {
|
||||
for (int count = 0, col = 0; count < 0x800; ++count, ++col) {
|
||||
*dest++ = (col < 32 ? left : right)[count & 0x3FF];
|
||||
if (col == 63) col = -1; // wrap every 64 tiles
|
||||
}
|
||||
};
|
||||
load_quadrant(lw_map_, p1, p2); // top half
|
||||
load_quadrant(lw_map_ + 0x800, p3, p4); // bottom half
|
||||
```
|
||||
|
||||
The Dark World map reuses Light World data except for the final quadrant stored
|
||||
at `+0x1000`.
|
||||
|
||||
### Palette Addresses
|
||||
|
||||
- Light World palette: `0x055B27` (128 colors)
|
||||
- Dark World palette: `0x055C27` (128 colors)
|
||||
- Conversion uses the shared helper discussed in [Palette System Overview](../developer/palette-system-overview.md).
|
||||
|
||||
### Custom Map Import/Export
|
||||
|
||||
The editor ships binary import/export to accelerate iteration:
|
||||
|
||||
```cpp
|
||||
absl::Status OverworldMap::LoadCustomMap(std::string_view path);
|
||||
absl::Status OverworldMap::SaveCustomMap(std::string_view path, bool dark_world);
|
||||
```
|
||||
|
||||
- Load expects a raw 4 096-byte tilemap; it replaces the active Light/Dark world
|
||||
buffer and triggers a redraw.
|
||||
- Save writes either the Light World tilemap or the Dark World override,
|
||||
allowing collaboration with external tooling.
|
||||
|
||||
### Current Status
|
||||
|
||||
**ZSCustomOverworld v2/v3 Support**: Fully implemented and tested
|
||||
**Vanilla ROM Support**: Complete compatibility maintained
|
||||
**Overlay System**: Both vanilla and custom overlays supported
|
||||
**Map Properties System**: Integrated with UI components
|
||||
**Graphics Loading**: Optimized with caching and performance monitoring
|
||||
|
||||
## Key Differences
|
||||
|
||||
### 1. Language and Architecture
|
||||
|
||||
| Aspect | ZScream | Yaze |
|
||||
|--------|---------|------|
|
||||
| Language | C# | C++ |
|
||||
| Memory Management | Garbage Collected | Manual (RAII) |
|
||||
| Graphics | System.Drawing | Custom OpenGL |
|
||||
| UI Framework | WinForms | ImGui |
|
||||
|
||||
### 2. Data Structures
|
||||
|
||||
**ZScream:**
|
||||
```csharp
|
||||
public class OverworldMap {
|
||||
public byte Index { get; set; }
|
||||
public AreaSizeEnum AreaSize { get; set; }
|
||||
public Bitmap GFXBitmap { get; set; }
|
||||
// ... other properties
|
||||
}
|
||||
```
|
||||
|
||||
**Yaze:**
|
||||
```cpp
|
||||
class OverworldMap {
|
||||
uint8_t index_;
|
||||
AreaSizeEnum area_size_;
|
||||
std::vector<uint8_t> bitmap_data_;
|
||||
// ... other member variables
|
||||
};
|
||||
```
|
||||
|
||||
### 3. Error Handling
|
||||
|
||||
**ZScream:** Uses exceptions and try-catch blocks
|
||||
**Yaze:** Uses `absl::Status` return values and `RETURN_IF_ERROR` macros
|
||||
|
||||
### 4. Graphics Processing
|
||||
|
||||
**ZScream:** Uses .NET's `Bitmap` class and GDI+
|
||||
**Yaze:** Uses custom `gfx::Bitmap` class with OpenGL textures
|
||||
|
||||
## Common Issues and Solutions
|
||||
|
||||
### 1. Version Detection Issues
|
||||
|
||||
**Problem:** ROM not recognized as ZSCustomOverworld
|
||||
**Solution:** Check that `OverworldCustomASMHasBeenApplied` is set correctly
|
||||
|
||||
### 2. Palette Loading Errors
|
||||
|
||||
**Problem:** Maps appear with wrong colors
|
||||
**Solution:** Verify palette group addresses and 0xFF fallback handling
|
||||
|
||||
### 3. Graphics Not Loading
|
||||
|
||||
**Problem:** Blank textures or missing graphics
|
||||
**Solution:** Check graphics buffer bounds and ProcessGraphicsBuffer implementation
|
||||
|
||||
### 4. Overlay Issues
|
||||
|
||||
**Problem:** Vanilla overlays not displaying
|
||||
**Solution:**
|
||||
- Verify overlay pointer addresses and SNES-to-PC conversion
|
||||
- Ensure special area maps (0x80-0x9F) are properly loaded with correct graphics
|
||||
- Check that overlay ID mappings are correct (e.g., 0x009D → map 0x9D)
|
||||
- Verify that overlay preview shows the actual bitmap of the referenced special area map
|
||||
|
||||
**Problem:** Overlay preview showing incorrect information
|
||||
**Solution:** Ensure overlay preview correctly maps overlay IDs to special area map indices and displays the appropriate bitmap from the special area maps (0x80-0x9F)
|
||||
|
||||
### 5. Large Map Problems
|
||||
|
||||
**Problem:** Large maps not rendering correctly
|
||||
**Solution:** Check parent-child relationships and large map detection logic
|
||||
|
||||
### 6. Special Area Graphics Issues
|
||||
|
||||
**Problem:** Special area maps (0x80-0x9F) showing blank or incorrect graphics
|
||||
**Solution:**
|
||||
- Verify special area graphics loading in `LoadAreaInfo()`
|
||||
- Check that special cases for maps like 0x88, 0x93, 0x95, 0x96, 0x9C are handled correctly
|
||||
- Ensure proper sprite graphics table selection for v2 vs v3 ROMs
|
||||
- Verify that special area maps use the correct graphics from referenced LW/DW maps
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Version-Specific Code
|
||||
|
||||
Always check the ASM version before accessing version-specific features:
|
||||
|
||||
```cpp
|
||||
uint8_t asm_version = (*rom_)[OverworldCustomASMHasBeenApplied];
|
||||
if (asm_version >= 3) {
|
||||
// v3 features
|
||||
} else if (asm_version == 0xFF) {
|
||||
// Vanilla features
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Error Handling
|
||||
|
||||
Use proper error handling for ROM operations:
|
||||
|
||||
```cpp
|
||||
absl::Status LoadPalette() {
|
||||
RETURN_IF_ERROR(LoadPaletteData());
|
||||
RETURN_IF_ERROR(ProcessPalette());
|
||||
return absl::OkStatus();
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Memory Management
|
||||
|
||||
Be careful with memory management in C++:
|
||||
|
||||
```cpp
|
||||
// Good: RAII and smart pointers
|
||||
std::vector<uint8_t> data;
|
||||
std::unique_ptr<OverworldMap> map;
|
||||
|
||||
// Bad: Raw pointers without cleanup
|
||||
uint8_t* raw_data = new uint8_t[size];
|
||||
OverworldMap* map = new OverworldMap();
|
||||
```
|
||||
|
||||
### 4. Thread Safety
|
||||
|
||||
Both editors use threading for performance:
|
||||
|
||||
```cpp
|
||||
// Yaze: Use std::async for parallel processing
|
||||
auto future = std::async(std::launch::async, [this](int map_index) {
|
||||
RefreshChildMap(map_index);
|
||||
}, map_index);
|
||||
```
|
||||
|
||||
## Conclusion
|
||||
|
||||
Understanding the differences between ZScream and yaze implementations is crucial for maintaining compatibility and adding new features. Both editors follow similar patterns but use different approaches due to their respective languages and architectures.
|
||||
|
||||
The key is to maintain the same ROM data structure understanding while adapting to each editor's specific implementation patterns.
|
||||
107
docs/public/usage/z3ed-cli.md
Normal file
107
docs/public/usage/z3ed-cli.md
Normal file
@@ -0,0 +1,107 @@
|
||||
# z3ed CLI Guide
|
||||
|
||||
_Last reviewed: November 2025. `z3ed` ships alongside the main editor in every `*-ai` preset and
|
||||
runs on Windows, macOS, and Linux._
|
||||
|
||||
`z3ed` exposes the same ROM-editing capabilities as the GUI but in a scriptable form. Use it to
|
||||
apply patches, inspect resources, run batch conversions, or drive the AI-assisted workflows that
|
||||
feed the in-editor proposals.
|
||||
|
||||
## 1. Building & Configuration
|
||||
|
||||
```bash
|
||||
# Enable the agent/CLI toolchain
|
||||
cmake --preset mac-ai
|
||||
cmake --build --preset mac-ai --target z3ed
|
||||
|
||||
# Run the text UI (FTXUI)
|
||||
./build/bin/z3ed --tui
|
||||
```
|
||||
|
||||
The AI features require at least one provider:
|
||||
- **Ollama (local)** – install via `brew install ollama`, run `ollama serve`, then set
|
||||
`OLLAMA_MODEL=qwen2.5-coder:0.5b` (the lightweight default used in CI) or any other supported
|
||||
model. Pass `--ai_model "$OLLAMA_MODEL"` on the CLI to override per-run.
|
||||
- **Gemini (cloud)** – export `GEMINI_API_KEY` before launching `z3ed`.
|
||||
|
||||
If no provider is configured the CLI still works, but agent subcommands will fall back to manual
|
||||
plans.
|
||||
|
||||
## 2. Everyday Commands
|
||||
|
||||
| Task | Example |
|
||||
| --- | --- |
|
||||
| Apply an Asar patch | `z3ed asar patch.asm --rom zelda3.sfc` |
|
||||
| Export all sprites from a dungeon | `z3ed dungeon list-sprites --dungeon 2 --rom zelda3.sfc --format json` |
|
||||
| Inspect an overworld map | `z3ed overworld describe-map --map 80 --rom zelda3.sfc` |
|
||||
| Dump palette data | `z3ed palette export --rom zelda3.sfc --output palettes.json` |
|
||||
| Validate ROM headers | `z3ed rom info --rom zelda3.sfc` |
|
||||
|
||||
Pass `--help` after any command to see its flags. Most resource commands follow the
|
||||
`<noun> <verb>` convention (`overworld set-tile`, `dungeon import-room`, etc.).
|
||||
|
||||
## 3. Agent & Proposal Workflow
|
||||
|
||||
### 3.1 Interactive Chat
|
||||
```bash
|
||||
z3ed agent chat --rom zelda3.sfc --theme overworld
|
||||
```
|
||||
- Maintains conversation history on disk so you can pause/resume.
|
||||
- Supports tool-calling: the agent invokes subcommands (e.g., `overworld describe-map`) and
|
||||
returns structured diffs.
|
||||
|
||||
### 3.2 Plans & Batches
|
||||
```bash
|
||||
# Generate a proposal but do not apply it
|
||||
z3ed agent plan --prompt "Move the eastern palace entrance 3 tiles east" --rom zelda3.sfc
|
||||
|
||||
# List pending plans
|
||||
z3ed agent list
|
||||
|
||||
# Apply a plan after review
|
||||
z3ed agent accept --proposal-id <id> --rom zelda3.sfc
|
||||
```
|
||||
Plans store the command transcript, diffs, and metadata inside
|
||||
`$XDG_DATA_HOME/yaze/proposals/` (or `%APPDATA%\yaze\proposals\`). Review them before applying to
|
||||
non-sandbox ROMs.
|
||||
|
||||
### 3.3 Non-interactive Scripts
|
||||
```bash
|
||||
# Run prompts from a file
|
||||
z3ed agent simple-chat --file scripts/queries.txt --rom zelda3.sfc --stdout
|
||||
|
||||
# Feed stdin (useful in CI)
|
||||
cat <<'PROMPTS' | z3ed agent simple-chat --rom zelda3.sfc --stdout
|
||||
Describe tile 0x3A in map 0x80.
|
||||
Suggest palette swaps for dungeon 2.
|
||||
PROMPTS
|
||||
```
|
||||
|
||||
## 4. Automation Tips
|
||||
|
||||
1. **Sandbox first** – point the agent at a copy of your ROM (`--sandbox` flag) so you can review
|
||||
patches safely.
|
||||
2. **Log everything** – `--log-file agent.log` captures the provider transcript for auditing.
|
||||
3. **Structure output** – most list/describe commands support `--format json` or `--format yaml`
|
||||
for downstream tooling.
|
||||
4. **Combine with `yaze_test`** – run `./build_ai/bin/yaze_test --unit` after batch patches to
|
||||
confirm nothing regressed.
|
||||
5. **Use TUI filters** – in `--tui`, press `:` to open the command palette, type part of a command,
|
||||
hit Enter, and the tool auto-fills the available flags.
|
||||
|
||||
## 5. Troubleshooting
|
||||
|
||||
| Symptom | Fix |
|
||||
| --- | --- |
|
||||
| `agent chat` hangs after a prompt | Ensure `ollama serve` or the Gemini API key is configured. |
|
||||
| `libgrpc` or `absl` missing | Re-run the `*-ai` preset; plain debug presets do not pull the agent stack. |
|
||||
| CLI cannot find the ROM | Use absolute paths or set `YAZE_DEFAULT_ROM=/path/to/zelda3.sfc`. |
|
||||
| Tool reports "command not found" | Run `z3ed --help` to refresh the command index; stale binaries from older builds lack new verbs. |
|
||||
| Proposal diffs are empty | Provide `--rom` plus either `--sandbox` or `--workspace` so the agent knows where to stage files. |
|
||||
|
||||
## 6. Related Documentation
|
||||
- `docs/public/developer/testing-without-roms.md` – ROM-less fixtures for CI.
|
||||
- `docs/public/developer/debugging-guide.md` – logging and instrumentation tips shared between the
|
||||
GUI and CLI.
|
||||
- `docs/internal/agents/` – deep dives into the agent architecture and refactor plans (internal
|
||||
audience only).
|
||||
Reference in New Issue
Block a user