Remove ImGui Widget Testing Guide and update documentation structure
- Deleted the ImGui Widget Testing Guide as it is no longer needed. - Updated the main documentation index to reflect the new Dungeon Editor Guide location. - Revised z3ed README to clarify core capabilities and quick start instructions. - Removed the developer guide for z3ed as its content is now integrated into other documentation. - Enhanced the architecture section to provide a clearer overview of the z3ed system components. - Updated command references and added details on agent commands and workflows.
This commit is contained in:
@@ -480,210 +480,31 @@ All Windows CI/CD builds include automatic fallback mechanisms:
|
||||
**Linux:**
|
||||
- x64 (64-bit)
|
||||
|
||||
## Troubleshooting
|
||||
## Contributing
|
||||
|
||||
### Build Environment Issues
|
||||
### Code Style
|
||||
|
||||
**CMake Configuration Fails:**
|
||||
```bash
|
||||
# Run verification script to diagnose
|
||||
./scripts/verify-build-environment.sh --verbose
|
||||
- **C++23**: Use modern language features
|
||||
- **Google C++ Style**: Follow Google C++ style guide
|
||||
- **Naming**: Use descriptive names, avoid abbreviations
|
||||
|
||||
### Error Handling
|
||||
|
||||
- **Use absl::Status** for error handling
|
||||
- **Use absl::StatusOr** for operations that return values
|
||||
|
||||
### Pull Request Process
|
||||
|
||||
1. **Run tests**: Ensure all stable tests pass (`ctest --preset stable`)
|
||||
2. **Check formatting**: Use `clang-format`
|
||||
3. **Update documentation**: If your changes affect behavior or APIs
|
||||
|
||||
### Commit Messages
|
||||
|
||||
# Common fixes
|
||||
git submodule update --init --recursive
|
||||
./scripts/verify-build-environment.sh --clean --fix
|
||||
```
|
||||
type(scope): brief description
|
||||
|
||||
**Git Submodules Missing or Out of Sync:**
|
||||
```bash
|
||||
# Sync and update all submodules
|
||||
git submodule sync --recursive
|
||||
git submodule update --init --recursive
|
||||
Detailed explanation of changes.
|
||||
|
||||
# Verify submodules are present
|
||||
./scripts/verify-build-environment.sh
|
||||
```
|
||||
|
||||
**Old CMake Cache Causing Issues:**
|
||||
```bash
|
||||
# Clean cache with verification script
|
||||
./scripts/verify-build-environment.sh --clean
|
||||
|
||||
# Or manually
|
||||
rm -rf build build_test build-grpc-test
|
||||
cmake -B build -DCMAKE_BUILD_TYPE=Debug
|
||||
```
|
||||
|
||||
### Dependency Conflicts
|
||||
|
||||
**gRPC Conflicts with System Packages:**
|
||||
The project automatically isolates gRPC (when enabled) from system packages:
|
||||
- `CMAKE_DISABLE_FIND_PACKAGE_Protobuf=TRUE`
|
||||
- `CMAKE_DISABLE_FIND_PACKAGE_absl=TRUE`
|
||||
- gRPC builds its own protobuf and abseil
|
||||
|
||||
**If you see protobuf/abseil version conflicts:**
|
||||
```bash
|
||||
# Verify isolation is configured
|
||||
grep CMAKE_DISABLE_FIND_PACKAGE cmake/grpc.cmake
|
||||
|
||||
# Clean and reconfigure
|
||||
./scripts/verify-build-environment.sh --clean --fix
|
||||
```
|
||||
|
||||
**httplib or nlohmann/json Missing:**
|
||||
These are header-only libraries in git submodules:
|
||||
```bash
|
||||
# Update submodules
|
||||
git submodule update --init third_party/json third_party/httplib
|
||||
|
||||
# Verify
|
||||
ls -la third_party/json/include/
|
||||
ls -la third_party/httplib/httplib.h
|
||||
```
|
||||
|
||||
### Windows CMake Issues
|
||||
|
||||
**CMake Not Found:**
|
||||
```powershell
|
||||
# Run the setup script
|
||||
.\scripts\setup-windows-dev.ps1
|
||||
|
||||
# Or install manually via Chocolatey
|
||||
choco install cmake
|
||||
```
|
||||
|
||||
**Submodule Compatibility Errors:**
|
||||
```powershell
|
||||
# Test CMake configuration
|
||||
.\scripts\test-cmake-config.ps1
|
||||
|
||||
# Clean build with compatibility flags
|
||||
Remove-Item -Recurse -Force build
|
||||
cmake -B build -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -DCMAKE_WARN_DEPRECATED=OFF
|
||||
```
|
||||
|
||||
**Visual Studio CMake Issues:**
|
||||
```powershell
|
||||
# Clean CMake cache
|
||||
Remove-Item -Recurse -Force build
|
||||
|
||||
# Rebuild CMake configuration
|
||||
cmake -B build -DCMAKE_BUILD_TYPE=Debug
|
||||
cmake --build build --config Debug
|
||||
```
|
||||
|
||||
### vcpkg Issues
|
||||
|
||||
**Dependencies Not Installing:**
|
||||
```cmd
|
||||
# Check vcpkg installation
|
||||
vcpkg version
|
||||
|
||||
# Reinstall dependencies
|
||||
vcpkg install --triplet x64-windows sdl2
|
||||
|
||||
# Check installed packages
|
||||
vcpkg list
|
||||
```
|
||||
|
||||
**Network/Download Failures:**
|
||||
- The CI/CD workflows automatically fall back to minimal builds
|
||||
- For local development, ensure stable internet connection
|
||||
- If vcpkg consistently fails, use minimal build mode:
|
||||
```bash
|
||||
cmake -B build -DYAZE_MINIMAL_BUILD=ON
|
||||
```
|
||||
|
||||
**Visual Studio Integration:**
|
||||
```cmd
|
||||
# Re-integrate vcpkg
|
||||
cd C:\vcpkg
|
||||
.\vcpkg.exe integrate install
|
||||
```
|
||||
|
||||
**Dependencies Not Found:**
|
||||
```powershell
|
||||
# Ensure vcpkg is properly set up (if using vcpkg)
|
||||
.\scripts\setup-vcpkg-windows.ps1
|
||||
|
||||
# Or use bundled dependencies (default)
|
||||
cmake -B build -DCMAKE_BUILD_TYPE=Debug
|
||||
```
|
||||
|
||||
### Test Issues
|
||||
|
||||
**Test Discovery Failures:**
|
||||
```bash
|
||||
# Use CI test executable for minimal builds
|
||||
cmake -B build -DYAZE_MINIMAL_BUILD=ON
|
||||
cmake --build build
|
||||
|
||||
# Check test executable
|
||||
./build/test/yaze_test --help
|
||||
```
|
||||
|
||||
**ROM Test Failures:**
|
||||
```bash
|
||||
# Ensure ROM file exists
|
||||
ls -la zelda3.sfc
|
||||
|
||||
# Run with explicit ROM path
|
||||
./build/test/yaze_test --e2e --rom-path zelda3.sfc
|
||||
```
|
||||
|
||||
**SDL Initialization Errors:**
|
||||
- These are expected in CI builds
|
||||
- Use minimal build configuration for CI compatibility
|
||||
- For local development, ensure SDL2 is properly installed
|
||||
|
||||
### Architecture Errors (macOS)
|
||||
```bash
|
||||
# Clean and use ARM64-only preset
|
||||
rm -rf build
|
||||
cmake --preset debug # Uses arm64 only
|
||||
```
|
||||
|
||||
### Missing Headers (Language Server)
|
||||
```bash
|
||||
# Regenerate compile commands
|
||||
cmake --preset debug
|
||||
cp build/compile_commands.json .
|
||||
# Restart VS Code
|
||||
```
|
||||
|
||||
### CI Build Failures
|
||||
Use minimal build configuration that matches CI:
|
||||
```bash
|
||||
cmake -B build -DYAZE_MINIMAL_BUILD=ON -DYAZE_ENABLE_UI_TESTS=OFF
|
||||
cmake --build build
|
||||
```
|
||||
|
||||
### Common Error Solutions
|
||||
|
||||
**"CMake Deprecation Warning" from submodules:**
|
||||
- This is automatically handled by the project's CMake configuration
|
||||
- If you see these warnings, they can be safely ignored
|
||||
|
||||
**"pthread_create not found" on Windows:**
|
||||
- The project automatically sets `THREADS_PREFER_PTHREAD_FLAG=OFF`
|
||||
- This is normal for Windows builds
|
||||
|
||||
**"Abseil C++ std propagation" warnings:**
|
||||
- Automatically handled with `ABSL_PROPAGATE_CXX_STD=ON`
|
||||
- Ensures proper C++ standard handling
|
||||
|
||||
**Visual Studio "file not found" errors:**
|
||||
- Close and reopen the folder in Visual Studio
|
||||
- Delete the `build/` directory and let Visual Studio regenerate CMake cache
|
||||
- Ensure all git submodules are initialized: `git submodule update --init --recursive`
|
||||
|
||||
**CI/CD Build Failures:**
|
||||
- Check if vcpkg download failed (network issues)
|
||||
- The workflows automatically fall back to minimal builds
|
||||
- For persistent issues, check the workflow logs for specific error messages
|
||||
|
||||
**Test Executable Issues:**
|
||||
- Ensure the correct test executable is being used (CI vs development)
|
||||
- Check that test filters are properly configured
|
||||
- Verify that ROM-dependent tests are excluded in CI builds
|
||||
Fixes #issue_number
|
||||
```
|
||||
@@ -160,8 +160,6 @@ TEST(CpuTest, InstructionExecution) {
|
||||
|
||||
## E2E GUI Testing Framework
|
||||
|
||||
### Overview
|
||||
|
||||
An agent-friendly, end-to-end testing framework built on `ImGuiTestEngine` to automate UI interaction testing for the YAZE editor.
|
||||
|
||||
### Architecture
|
||||
@@ -204,14 +202,6 @@ void RegisterCanvasSelectionTest() {
|
||||
}
|
||||
```
|
||||
|
||||
### Helper Functions
|
||||
|
||||
**test/test_utils.h** provides high-level wrappers:
|
||||
- `LoadRomInTest(ctx, rom_path)` - Load ROM file in test context
|
||||
- `OpenEditorInTest(ctx, editor_name)` - Open specific editor
|
||||
- `VerifyTileData(ctx, expected)` - Assert tile data correctness
|
||||
- `WaitForRender(ctx)` - Wait for rendering to complete
|
||||
|
||||
### Running GUI Tests
|
||||
|
||||
```bash
|
||||
@@ -224,47 +214,3 @@ z3ed test-gui --rom zelda3.sfc --test canvas_selection
|
||||
# Run in headless mode (CI)
|
||||
z3ed test-gui --rom zelda3.sfc --test all --headless
|
||||
```
|
||||
|
||||
### Test Categories for E2E
|
||||
|
||||
- **Smoke Tests**: Basic functionality verification (window opens, ROM loads)
|
||||
- **Canvas Tests**: Drawing, selection, copy/paste operations
|
||||
- **Editor Tests**: Specific editor workflows (Overworld, Dungeon, Graphics)
|
||||
- **Integration Tests**: Multi-editor workflows and data persistence
|
||||
|
||||
### Development Status
|
||||
|
||||
- ✅ **Phase 1**: Core infrastructure & test execution flow
|
||||
- ✅ **Phase 2**: Agent-friendly test definition & interaction
|
||||
- ✅ **Phase 3**: Initial test case - Canvas rectangle selection
|
||||
- ✅ **Phase 4**: Build and verify infrastructure
|
||||
- ⏳ **Phase 5**: Expand test coverage and fix identified bugs
|
||||
- ⏳ **Phase 6**: CI/CD integration with headless mode
|
||||
|
||||
### Best Practices
|
||||
|
||||
1. **Keep tests deterministic** - Use fixed delays and wait for specific states
|
||||
2. **Use high-level helpers** - Abstract ImGuiTestEngine complexity
|
||||
3. **Test user workflows** - Focus on real user interactions, not internal state
|
||||
4. **Verify visually** - Check rendered output, not just data structures
|
||||
5. **Clean up state** - Reset between tests to prevent interference
|
||||
|
||||
## Performance and Maintenance
|
||||
|
||||
### Regular Review
|
||||
- **Monthly review** of experimental test failures
|
||||
- **Promote stable experimental tests** to stable category
|
||||
- **Deprecate obsolete tests** that no longer provide value
|
||||
- **Update test categorization** as features mature
|
||||
|
||||
### Performance Monitoring
|
||||
- **Track test execution times** for CI efficiency
|
||||
- **Identify slow tests** for optimization or recategorization
|
||||
- **Monitor CI resource usage** and adjust parallelism
|
||||
- **Benchmark critical path tests** for performance regression
|
||||
|
||||
### E2E Test Maintenance
|
||||
- **Update test helpers** as UI components change
|
||||
- **Maintain test ROM files** for consistent test data
|
||||
- **Review failed tests** for UI changes vs. actual bugs
|
||||
- **Expand coverage** for new features and bug fixes
|
||||
|
||||
@@ -1,239 +0,0 @@
|
||||
# Contributing
|
||||
|
||||
Guidelines for contributing to the YAZE project.
|
||||
|
||||
## Development Setup
|
||||
|
||||
### Prerequisites
|
||||
- **CMake 3.16+**: Modern build system
|
||||
- **C++23 Compiler**: GCC 13+, Clang 16+, MSVC 2022 17.8+
|
||||
- **Git**: Version control with submodules
|
||||
|
||||
### Quick Start
|
||||
```bash
|
||||
# Clone with submodules
|
||||
git clone --recursive https://github.com/scawful/yaze.git
|
||||
cd yaze
|
||||
|
||||
# Build with presets
|
||||
cmake --preset dev
|
||||
cmake --build --preset dev
|
||||
|
||||
# Run tests
|
||||
ctest --preset stable
|
||||
```
|
||||
|
||||
## Code Style
|
||||
|
||||
### C++ Standards
|
||||
- **C++23**: Use modern language features
|
||||
- **Google C++ Style**: Follow Google C++ style guide
|
||||
- **Naming**: Use descriptive names, avoid abbreviations
|
||||
|
||||
### File Organization
|
||||
```cpp
|
||||
// Header guards
|
||||
#pragma once
|
||||
|
||||
// Includes (system, third-party, local)
|
||||
#include <vector>
|
||||
#include "absl/status/status.h"
|
||||
#include "app/core/asar_wrapper.h"
|
||||
|
||||
// Namespace usage
|
||||
namespace yaze::editor {
|
||||
|
||||
class ExampleClass {
|
||||
public:
|
||||
// Public interface
|
||||
absl::Status Initialize();
|
||||
|
||||
private:
|
||||
// Private implementation
|
||||
std::vector<uint8_t> data_;
|
||||
};
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
```cpp
|
||||
// Use absl::Status for error handling
|
||||
absl::Status LoadRom(const std::string& filename) {
|
||||
if (filename.empty()) {
|
||||
return absl::InvalidArgumentError("Filename cannot be empty");
|
||||
}
|
||||
|
||||
// ... implementation
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// Use absl::StatusOr for operations that return values
|
||||
absl::StatusOr<std::vector<uint8_t>> ReadFile(const std::string& filename);
|
||||
```
|
||||
|
||||
## Testing Requirements
|
||||
|
||||
### Test Categories
|
||||
- **Stable Tests**: Fast, reliable, no external dependencies
|
||||
- **ROM-Dependent Tests**: Require ROM files, skip in CI
|
||||
- **Experimental Tests**: Complex, may be unstable
|
||||
|
||||
### Writing Tests
|
||||
```cpp
|
||||
// Stable test example
|
||||
TEST(SnesTileTest, UnpackBppTile) {
|
||||
std::vector<uint8_t> tile_data = {0xAA, 0x55};
|
||||
auto result = UnpackBppTile(tile_data, 2);
|
||||
EXPECT_TRUE(result.ok());
|
||||
EXPECT_EQ(result->size(), 64);
|
||||
}
|
||||
|
||||
// ROM-dependent test example
|
||||
YAZE_ROM_TEST(AsarIntegration, RealRomPatching) {
|
||||
auto rom_data = TestRomManager::LoadTestRom();
|
||||
if (!rom_data.has_value()) {
|
||||
GTEST_SKIP() << "ROM file not available";
|
||||
}
|
||||
// ... test implementation
|
||||
}
|
||||
```
|
||||
|
||||
### Test Execution
|
||||
```bash
|
||||
# Run stable tests (required)
|
||||
ctest --label-regex "STABLE"
|
||||
|
||||
# Run experimental tests (optional)
|
||||
ctest --label-regex "EXPERIMENTAL"
|
||||
|
||||
# Run specific test
|
||||
ctest -R "AsarWrapperTest"
|
||||
```
|
||||
|
||||
## Pull Request Process
|
||||
|
||||
### Before Submitting
|
||||
1. **Run tests**: Ensure all stable tests pass
|
||||
2. **Check formatting**: Use clang-format
|
||||
3. **Update documentation**: Update relevant docs if needed
|
||||
4. **Test on multiple platforms**: Verify cross-platform compatibility
|
||||
|
||||
### Pull Request Template
|
||||
```markdown
|
||||
## Description
|
||||
Brief description of changes
|
||||
|
||||
## Type of Change
|
||||
- [ ] Bug fix
|
||||
- [ ] New feature
|
||||
- [ ] Breaking change
|
||||
- [ ] Documentation update
|
||||
|
||||
## Testing
|
||||
- [ ] Stable tests pass
|
||||
- [ ] Manual testing completed
|
||||
- [ ] Cross-platform testing (if applicable)
|
||||
|
||||
## Checklist
|
||||
- [ ] Code follows project style guidelines
|
||||
- [ ] Self-review completed
|
||||
- [ ] Documentation updated
|
||||
- [ ] Tests added/updated
|
||||
```
|
||||
|
||||
## Development Workflow
|
||||
|
||||
### Branch Strategy
|
||||
- **main**: Stable, release-ready code
|
||||
- **feature/**: New features and enhancements
|
||||
- **fix/**: Bug fixes
|
||||
- **docs/**: Documentation updates
|
||||
|
||||
### Commit Messages
|
||||
```
|
||||
type(scope): brief description
|
||||
|
||||
Detailed explanation of changes, including:
|
||||
- What was changed
|
||||
- Why it was changed
|
||||
- Any breaking changes
|
||||
|
||||
Fixes #issue_number
|
||||
```
|
||||
|
||||
### Types
|
||||
- **feat**: New features
|
||||
- **fix**: Bug fixes
|
||||
- **docs**: Documentation changes
|
||||
- **style**: Code style changes
|
||||
- **refactor**: Code refactoring
|
||||
- **test**: Test additions/changes
|
||||
- **chore**: Build/tooling changes
|
||||
|
||||
## Architecture Guidelines
|
||||
|
||||
### Component Design
|
||||
- **Single Responsibility**: Each class should have one clear purpose
|
||||
- **Dependency Injection**: Use dependency injection for testability
|
||||
- **Interface Segregation**: Keep interfaces focused and minimal
|
||||
|
||||
### Memory Management
|
||||
- **RAII**: Use RAII for resource management
|
||||
- **Smart Pointers**: Prefer unique_ptr and shared_ptr
|
||||
- **Avoid Raw Pointers**: Use smart pointers or references
|
||||
|
||||
### Performance
|
||||
- **Profile Before Optimizing**: Measure before optimizing
|
||||
- **Use Modern C++**: Leverage C++23 features for performance
|
||||
- **Avoid Premature Optimization**: Focus on correctness first
|
||||
|
||||
## Documentation
|
||||
|
||||
### Code Documentation
|
||||
- **Doxygen Comments**: Use Doxygen format for public APIs
|
||||
- **Inline Comments**: Explain complex logic
|
||||
- **README Updates**: Update relevant README files
|
||||
|
||||
### API Documentation
|
||||
```cpp
|
||||
/**
|
||||
* @brief Applies an assembly patch to ROM data
|
||||
* @param patch_path Path to the assembly patch file
|
||||
* @param rom_data ROM data to patch (modified in place)
|
||||
* @param include_paths Optional include paths for assembly
|
||||
* @return Result containing success status and extracted symbols
|
||||
* @throws std::invalid_argument if patch_path is empty
|
||||
*/
|
||||
absl::StatusOr<AsarPatchResult> ApplyPatch(
|
||||
const std::string& patch_path,
|
||||
std::vector<uint8_t>& rom_data,
|
||||
const std::vector<std::string>& include_paths = {});
|
||||
```
|
||||
|
||||
## Community Guidelines
|
||||
|
||||
### Communication
|
||||
- **Be Respectful**: Treat all contributors with respect
|
||||
- **Be Constructive**: Provide helpful feedback
|
||||
- **Be Patient**: Remember that everyone is learning
|
||||
|
||||
### Getting Help
|
||||
- **GitHub Issues**: Report bugs and request features
|
||||
- **Discussions**: Ask questions and discuss ideas
|
||||
- **Discord**: [Oracle of Secrets Discord](https://discord.gg/MBFkMTPEmk)
|
||||
|
||||
## Release Process
|
||||
|
||||
### Version Numbering
|
||||
- **Semantic Versioning**: MAJOR.MINOR.PATCH
|
||||
- **v0.3.1**: Current stable release
|
||||
- **Pre-release**: v0.4.0-alpha, v0.4.0-beta
|
||||
|
||||
### Release Checklist
|
||||
- [ ] All stable tests pass
|
||||
- [ ] Documentation updated
|
||||
- [ ] Changelog updated
|
||||
- [ ] Cross-platform builds verified
|
||||
- [ ] Release notes prepared
|
||||
@@ -1,248 +0,0 @@
|
||||
# DungeonEditor Refactoring Plan
|
||||
|
||||
## Overview
|
||||
This document outlines the comprehensive refactoring of the 1444-line `dungeon_editor.cc` file into focused, single-responsibility components.
|
||||
|
||||
## Component Structure
|
||||
|
||||
### ✅ Created Components
|
||||
|
||||
#### 1. DungeonToolset (`dungeon_toolset.h/cc`)
|
||||
**Responsibility**: Toolbar UI management
|
||||
- Background layer selection (All/BG1/BG2/BG3)
|
||||
- Placement mode selection (Object/Sprite/Item/etc.)
|
||||
- Undo/Redo buttons with callbacks
|
||||
- **Replaces**: `DrawToolset()` method (~70 lines)
|
||||
|
||||
#### 2. DungeonObjectInteraction (`dungeon_object_interaction.h/cc`)
|
||||
**Responsibility**: Object selection and placement
|
||||
- Mouse interaction handling
|
||||
- Object selection rectangle (like OverworldEditor)
|
||||
- Drag and drop operations
|
||||
- Coordinate conversion utilities
|
||||
- **Replaces**: All mouse/selection methods (~400 lines)
|
||||
|
||||
#### 3. DungeonRenderer (`dungeon_renderer.h/cc`)
|
||||
**Responsibility**: All rendering operations
|
||||
- Object rendering with caching
|
||||
- Background layer composition
|
||||
- Layout object visualization
|
||||
- Render cache management
|
||||
- **Replaces**: All rendering methods (~200 lines)
|
||||
|
||||
#### 4. DungeonRoomLoader (`dungeon_room_loader.h/cc`)
|
||||
**Responsibility**: ROM data loading
|
||||
- Room loading from ROM
|
||||
- Room size calculation
|
||||
- Entrance loading
|
||||
- Graphics loading coordination
|
||||
- **Replaces**: Room loading methods (~150 lines)
|
||||
|
||||
#### 5. DungeonUsageTracker (`dungeon_usage_tracker.h/cc`)
|
||||
**Responsibility**: Resource usage analysis
|
||||
- Blockset/spriteset/palette usage tracking
|
||||
- Usage statistics display
|
||||
- Resource optimization insights
|
||||
- **Replaces**: Usage statistics methods (~100 lines)
|
||||
|
||||
## Refactored DungeonEditor Structure
|
||||
|
||||
### Before Refactoring: 1444 lines
|
||||
```cpp
|
||||
class DungeonEditor {
|
||||
// 30+ methods handling everything
|
||||
// Mixed responsibilities
|
||||
// Large data structures
|
||||
// Complex dependencies
|
||||
};
|
||||
```
|
||||
|
||||
### After Refactoring: ~400 lines
|
||||
```cpp
|
||||
class DungeonEditor {
|
||||
// Core editor interface (unchanged)
|
||||
void Initialize() override;
|
||||
absl::Status Load() override;
|
||||
absl::Status Update() override;
|
||||
absl::Status Save() override;
|
||||
|
||||
// High-level UI orchestration
|
||||
absl::Status UpdateDungeonRoomView();
|
||||
void DrawCanvasAndPropertiesPanel();
|
||||
void DrawRoomPropertiesDebugPopup();
|
||||
|
||||
// Component coordination
|
||||
void OnRoomSelected(int room_id);
|
||||
|
||||
private:
|
||||
// Focused components
|
||||
DungeonToolset toolset_;
|
||||
DungeonObjectInteraction object_interaction_;
|
||||
DungeonRenderer renderer_;
|
||||
DungeonRoomLoader room_loader_;
|
||||
DungeonUsageTracker usage_tracker_;
|
||||
|
||||
// Existing UI components
|
||||
DungeonRoomSelector room_selector_;
|
||||
DungeonCanvasViewer canvas_viewer_;
|
||||
DungeonObjectSelector object_selector_;
|
||||
|
||||
// Core data and state
|
||||
std::array<zelda3::Room, 0x128> rooms_;
|
||||
bool is_loaded_ = false;
|
||||
// etc.
|
||||
};
|
||||
```
|
||||
|
||||
## Method Migration Map
|
||||
|
||||
### Core Editor Methods (Keep in main file)
|
||||
- ✅ `Initialize()` - Component initialization
|
||||
- ✅ `Load()` - Delegates to room_loader_
|
||||
- ✅ `Update()` - High-level update coordination
|
||||
- ✅ `Save()`, `Undo()`, `Redo()` - Editor interface
|
||||
- ✅ `UpdateDungeonRoomView()` - UI orchestration
|
||||
|
||||
### UI Methods (Keep for coordination)
|
||||
- ✅ `DrawCanvasAndPropertiesPanel()` - Tab management
|
||||
- ✅ `DrawRoomPropertiesDebugPopup()` - Debug popup
|
||||
- ✅ `DrawDungeonTabView()` - Room tab management
|
||||
- ✅ `DrawDungeonCanvas()` - Canvas coordination
|
||||
- ✅ `OnRoomSelected()` - Room selection handling
|
||||
|
||||
### Methods Moved to Components
|
||||
|
||||
#### → DungeonToolset
|
||||
- ❌ `DrawToolset()` - Toolbar rendering
|
||||
|
||||
#### → DungeonObjectInteraction
|
||||
- ❌ `HandleCanvasMouseInput()` - Mouse handling
|
||||
- ❌ `CheckForObjectSelection()` - Selection rectangle
|
||||
- ❌ `DrawObjectSelectRect()` - Selection drawing
|
||||
- ❌ `SelectObjectsInRect()` - Selection logic
|
||||
- ❌ `PlaceObjectAtPosition()` - Object placement
|
||||
- ❌ `DrawSelectBox()` - Selection visualization
|
||||
- ❌ `DrawDragPreview()` - Drag preview
|
||||
- ❌ `UpdateSelectedObjects()` - Selection updates
|
||||
- ❌ `IsObjectInSelectBox()` - Selection testing
|
||||
- ❌ Coordinate conversion helpers
|
||||
|
||||
#### → DungeonRenderer
|
||||
- ❌ `RenderObjectInCanvas()` - Object rendering
|
||||
- ❌ `DisplayObjectInfo()` - Object info overlay
|
||||
- ❌ `RenderLayoutObjects()` - Layout rendering
|
||||
- ❌ `RenderRoomBackgroundLayers()` - Background rendering
|
||||
- ❌ `RefreshGraphics()` - Graphics refresh
|
||||
- ❌ Object cache management
|
||||
|
||||
#### → DungeonRoomLoader
|
||||
- ❌ `LoadDungeonRoomSize()` - Room size calculation
|
||||
- ❌ `LoadAndRenderRoomGraphics()` - Graphics loading
|
||||
- ❌ `ReloadAllRoomGraphics()` - Bulk reload
|
||||
- ❌ Room size and address management
|
||||
|
||||
#### → DungeonUsageTracker
|
||||
- ❌ `CalculateUsageStats()` - Usage calculation
|
||||
- ❌ `DrawUsageStats()` - Usage display
|
||||
- ❌ `DrawUsageGrid()` - Usage visualization
|
||||
- ❌ `RenderSetUsage()` - Set usage rendering
|
||||
|
||||
## Component Communication
|
||||
|
||||
### Callback System
|
||||
```cpp
|
||||
// Object placement callback
|
||||
object_interaction_.SetObjectPlacedCallback([this](const auto& object) {
|
||||
renderer_.ClearObjectCache();
|
||||
});
|
||||
|
||||
// Toolset callbacks
|
||||
toolset_.SetUndoCallback([this]() { Undo(); });
|
||||
toolset_.SetPaletteToggleCallback([this]() { palette_showing_ = !palette_showing_; });
|
||||
|
||||
// Object selection callback
|
||||
object_selector_.SetObjectSelectedCallback([this](const auto& object) {
|
||||
object_interaction_.SetPreviewObject(object, true);
|
||||
toolset_.set_placement_type(DungeonToolset::kObject);
|
||||
});
|
||||
```
|
||||
|
||||
### Data Sharing
|
||||
```cpp
|
||||
// Update components with current room
|
||||
void OnRoomSelected(int room_id) {
|
||||
current_room_id_ = room_id;
|
||||
object_interaction_.SetCurrentRoom(&rooms_, room_id);
|
||||
// etc.
|
||||
}
|
||||
```
|
||||
|
||||
## Benefits of Refactoring
|
||||
|
||||
### 1. **Reduced Complexity**
|
||||
- Main file: 1444 → ~400 lines (72% reduction)
|
||||
- Single responsibility per component
|
||||
- Clear separation of concerns
|
||||
|
||||
### 2. **Improved Testability**
|
||||
- Individual components can be unit tested
|
||||
- Mocking becomes easier
|
||||
- Isolated functionality testing
|
||||
|
||||
### 3. **Better Maintainability**
|
||||
- Changes isolated to relevant components
|
||||
- Easier to locate and fix bugs
|
||||
- Cleaner code reviews
|
||||
|
||||
### 4. **Enhanced Extensibility**
|
||||
- New features added to appropriate components
|
||||
- Component interfaces allow easy replacement
|
||||
- Plugin-style architecture possible
|
||||
|
||||
### 5. **Cleaner Dependencies**
|
||||
- UI separate from data manipulation
|
||||
- Rendering separate from business logic
|
||||
- Clear component boundaries
|
||||
|
||||
## Implementation Status
|
||||
|
||||
### ✅ Completed
|
||||
- Created all component header files
|
||||
- Created component implementation stubs
|
||||
- Updated DungeonEditor header with components
|
||||
- Basic component integration
|
||||
|
||||
### 🔄 In Progress
|
||||
- Method migration from main file to components
|
||||
- Component callback setup
|
||||
- Legacy method removal
|
||||
|
||||
### ⏳ Pending
|
||||
- Full method implementation in components
|
||||
- Complete integration testing
|
||||
- Documentation updates
|
||||
- Build system updates
|
||||
|
||||
## Migration Strategy
|
||||
|
||||
### Phase 1: Create Components ✅
|
||||
- Define component interfaces
|
||||
- Create header and implementation files
|
||||
- Set up basic structure
|
||||
|
||||
### Phase 2: Integrate Components 🔄
|
||||
- Add components to DungeonEditor
|
||||
- Set up callback systems
|
||||
- Begin method delegation
|
||||
|
||||
### Phase 3: Move Methods
|
||||
- Systematically move methods to components
|
||||
- Update method calls to use components
|
||||
- Remove old implementations
|
||||
|
||||
### Phase 4: Cleanup
|
||||
- Remove unused member variables
|
||||
- Clean up includes
|
||||
- Update documentation
|
||||
|
||||
This refactoring transforms the monolithic DungeonEditor into a well-organized, component-based architecture that's easier to maintain, test, and extend.
|
||||
@@ -1,271 +0,0 @@
|
||||
# Dungeon Object System
|
||||
|
||||
## Overview
|
||||
|
||||
The Dungeon Object System provides a comprehensive framework for editing and managing dungeon rooms, objects, and layouts in The Legend of Zelda: A Link to the Past. This system combines real-time visual editing with precise data manipulation to create a powerful dungeon creation and modification toolkit.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Core Components
|
||||
|
||||
The dungeon system is built around several key components that work together to provide a seamless editing experience:
|
||||
|
||||
#### 1. DungeonEditor (`src/app/editor/dungeon/dungeon_editor.h`)
|
||||
The main interface that orchestrates all dungeon editing functionality. It provides:
|
||||
- **Windowed Canvas System**: Fixed-size canvas that prevents UI layout disruption
|
||||
- **Tabbed Room Interface**: Multiple rooms can be open simultaneously for easy comparison and editing
|
||||
- **Integrated Object Placement**: Direct object placement from selector to canvas
|
||||
- **Real-time Preview**: Live object preview follows mouse cursor during placement
|
||||
|
||||
#### 2. DungeonObjectSelector (`src/app/editor/dungeon/dungeon_object_selector.h`)
|
||||
Combines object browsing and editing in a unified interface:
|
||||
- **Object Browser**: Visual grid of all available objects with real-time previews
|
||||
- **Object Editor**: Integrated editing panels for sprites, items, entrances, doors, and chests
|
||||
- **Callback System**: Notifies main editor when objects are selected for placement
|
||||
|
||||
#### 3. DungeonCanvasViewer (`src/app/editor/dungeon/dungeon_canvas_viewer.h`)
|
||||
Specialized canvas for rendering dungeon rooms:
|
||||
- **Background Layer Rendering**: Proper BG1/BG2 layer composition
|
||||
- **Object Rendering**: Cached object rendering with palette support
|
||||
- **Coordinate System**: Seamless translation between room and canvas coordinates
|
||||
|
||||
#### 4. Room Management System (`src/app/zelda3/dungeon/room.h`)
|
||||
Core data structures for room representation:
|
||||
- **Room Objects**: Tile-based objects (walls, floors, decorations)
|
||||
- **Room Layout**: Structural elements and collision data
|
||||
- **Sprites**: Enemy and NPC placement
|
||||
- **Entrances/Exits**: Room connections and transitions
|
||||
|
||||
## Object Types and Hierarchies
|
||||
|
||||
### Room Objects
|
||||
Room objects are the fundamental building blocks of dungeon rooms. They follow a hierarchical structure:
|
||||
|
||||
#### Type 1 Objects (0x00-0xFF)
|
||||
Basic structural elements:
|
||||
- **0x10-0x1F**: Wall objects (various types and orientations)
|
||||
- **0x20-0x2F**: Floor tiles (stone, wood, carpet, etc.)
|
||||
- **0x30-0x3F**: Decorative elements (torches, statues, pillars)
|
||||
- **0x40-0x4F**: Interactive elements (switches, blocks)
|
||||
|
||||
#### Type 2 Objects (0x100-0x1FF)
|
||||
Complex multi-tile objects:
|
||||
- **0x100-0x10F**: Large wall sections
|
||||
- **0x110-0x11F**: Complex floor patterns
|
||||
- **0x120-0x12F**: Multi-tile decorations
|
||||
|
||||
#### Type 3 Objects (0x200+)
|
||||
Special dungeon-specific objects:
|
||||
- **0x200-0x20F**: Boss room elements
|
||||
- **0x210-0x21F**: Puzzle-specific objects
|
||||
- **0xF9-0xFA**: Chests (small and large)
|
||||
|
||||
### Object Properties
|
||||
Each object has several key properties:
|
||||
|
||||
```cpp
|
||||
class RoomObject {
|
||||
int id_; // Object type identifier
|
||||
int x_, y_; // Position in room (16x16 tile units)
|
||||
int size_; // Size modifier (affects rendering)
|
||||
LayerType layer_; // Rendering layer (0=BG, 1=MID, 2=FG)
|
||||
// ... additional properties
|
||||
};
|
||||
```
|
||||
|
||||
## How Object Placement Works
|
||||
|
||||
### Selection Process
|
||||
1. **Object Browser**: User selects an object from the visual grid
|
||||
2. **Preview Generation**: Object is rendered with current room palette
|
||||
3. **Callback Trigger**: Selection notifies main editor via callback
|
||||
4. **Preview Update**: Main editor receives object and enables placement mode
|
||||
|
||||
### Placement Process
|
||||
1. **Mouse Tracking**: Preview object follows mouse cursor on canvas
|
||||
2. **Coordinate Translation**: Mouse position converted to room coordinates
|
||||
3. **Visual Feedback**: Semi-transparent preview shows placement position
|
||||
4. **Click Placement**: Left-click places object at current position
|
||||
5. **Room Update**: Object added to room data and cache cleared for redraw
|
||||
|
||||
### Code Flow
|
||||
```cpp
|
||||
// Object selection in DungeonObjectSelector
|
||||
if (ImGui::Selectable("", is_selected)) {
|
||||
preview_object_ = selected_object;
|
||||
object_loaded_ = true;
|
||||
|
||||
// Notify main editor
|
||||
if (object_selected_callback_) {
|
||||
object_selected_callback_(preview_object_);
|
||||
}
|
||||
}
|
||||
|
||||
// Object placement in DungeonEditor
|
||||
void PlaceObjectAtPosition(int room_x, int room_y) {
|
||||
auto new_object = preview_object_;
|
||||
new_object.x_ = room_x;
|
||||
new_object.y_ = room_y;
|
||||
new_object.set_rom(rom_);
|
||||
new_object.EnsureTilesLoaded();
|
||||
|
||||
room.AddTileObject(new_object);
|
||||
object_render_cache_.clear(); // Force redraw
|
||||
}
|
||||
```
|
||||
|
||||
## Rendering Pipeline
|
||||
|
||||
### Object Rendering
|
||||
The system uses a sophisticated rendering pipeline:
|
||||
|
||||
1. **Tile Loading**: Object tiles loaded from ROM based on object ID
|
||||
2. **Palette Application**: Room-specific palette applied to object
|
||||
3. **Bitmap Generation**: Object rendered to bitmap with proper composition
|
||||
4. **Caching**: Rendered objects cached for performance
|
||||
5. **Canvas Drawing**: Bitmap drawn to canvas at correct position
|
||||
|
||||
### Performance Optimizations
|
||||
- **Render Caching**: Objects cached based on ID, position, size, and palette hash
|
||||
- **Bounds Checking**: Only objects within canvas bounds are rendered
|
||||
- **Lazy Loading**: Graphics and objects loaded on-demand
|
||||
- **Palette Hashing**: Efficient cache invalidation when palettes change
|
||||
|
||||
## User Interface Components
|
||||
|
||||
### Three-Column Layout
|
||||
The dungeon editor uses a carefully designed three-column layout:
|
||||
|
||||
#### Column 1: Room Control Panel (280px fixed)
|
||||
- **Room Selector**: Browse and select rooms
|
||||
- **Debug Controls**: Room properties in table format
|
||||
- **Object Statistics**: Live object counts and cache status
|
||||
|
||||
#### Column 2: Windowed Canvas (800px fixed)
|
||||
- **Tabbed Interface**: Multiple rooms open simultaneously
|
||||
- **Fixed Dimensions**: Prevents UI layout disruption
|
||||
- **Real-time Preview**: Object placement preview follows cursor
|
||||
- **Layer Visualization**: Proper background/foreground rendering
|
||||
|
||||
#### Column 3: Object Selector/Editor (stretch)
|
||||
- **Object Browser Tab**: Visual grid of available objects
|
||||
- **Object Editor Tab**: Integrated editing for sprites, items, etc.
|
||||
- **Placement Tools**: Object property editing and placement controls
|
||||
|
||||
### Debug and Control Features
|
||||
|
||||
#### Room Properties Table
|
||||
Real-time editing of room attributes:
|
||||
```
|
||||
Property | Value
|
||||
------------|--------
|
||||
Room ID | 0x001 (1)
|
||||
Layout | [Hex Input]
|
||||
Blockset | [Hex Input]
|
||||
Spriteset | [Hex Input]
|
||||
Palette | [Hex Input]
|
||||
Floor 1 | [Hex Input]
|
||||
Floor 2 | [Hex Input]
|
||||
Message ID | [Hex Input]
|
||||
```
|
||||
|
||||
#### Object Statistics
|
||||
Live feedback on room contents:
|
||||
- Total objects count
|
||||
- Layout objects count
|
||||
- Sprites count
|
||||
- Chests count
|
||||
- Cache status and controls
|
||||
|
||||
## Integration with ROM Data
|
||||
|
||||
### Data Sources
|
||||
The system integrates with multiple ROM data sources:
|
||||
|
||||
#### Room Headers (`0x1F8000`)
|
||||
- Room layout index
|
||||
- Blockset and spriteset references
|
||||
- Palette assignments
|
||||
- Floor type definitions
|
||||
|
||||
#### Object Data
|
||||
- Object definitions and tile mappings
|
||||
- Size and layer information
|
||||
- Interaction properties
|
||||
|
||||
#### Graphics Data
|
||||
- Tile graphics (4bpp SNES format)
|
||||
- Palette data (15-color palettes)
|
||||
- Blockset compositions
|
||||
|
||||
### Assembly Integration
|
||||
The system references the US disassembly (`assets/asm/usdasm/`) for:
|
||||
- Room data structure validation
|
||||
- Object type definitions
|
||||
- Memory layout verification
|
||||
- Data pointer validation
|
||||
|
||||
## Comparison with ZScream
|
||||
|
||||
### Architectural Differences
|
||||
YAZE's approach differs from ZScream in several key ways:
|
||||
|
||||
#### Component-Based Architecture
|
||||
- **YAZE**: Modular components with clear separation of concerns
|
||||
- **ZScream**: More monolithic approach with integrated functionality
|
||||
|
||||
#### Real-time Rendering
|
||||
- **YAZE**: Live object preview with mouse tracking
|
||||
- **ZScream**: Static preview with separate placement step
|
||||
|
||||
#### UI Organization
|
||||
- **YAZE**: Fixed-width columns prevent layout disruption
|
||||
- **ZScream**: Resizable panels that can affect overall layout
|
||||
|
||||
#### Caching Strategy
|
||||
- **YAZE**: Sophisticated object render caching with hash-based invalidation
|
||||
- **ZScream**: Simpler caching approach
|
||||
|
||||
### Shared Concepts
|
||||
Both systems share fundamental concepts:
|
||||
- Object-based room construction
|
||||
- Layer-based rendering
|
||||
- ROM data integration
|
||||
- Visual object browsing
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Performance
|
||||
1. **Use Render Caching**: Don't clear cache unnecessarily
|
||||
2. **Bounds Checking**: Only render visible objects
|
||||
3. **Lazy Loading**: Load graphics and objects on-demand
|
||||
4. **Efficient Callbacks**: Minimize callback frequency
|
||||
|
||||
### Code Organization
|
||||
1. **Separation of Concerns**: Keep UI, data, and rendering separate
|
||||
2. **Clear Interfaces**: Use callbacks for component communication
|
||||
3. **Error Handling**: Validate ROM data and handle errors gracefully
|
||||
4. **Memory Management**: Clean up resources properly
|
||||
|
||||
### User Experience
|
||||
1. **Visual Feedback**: Provide clear object placement preview
|
||||
2. **Consistent Layout**: Use fixed dimensions for stable UI
|
||||
3. **Contextual Information**: Show relevant object properties
|
||||
4. **Efficient Workflow**: Minimize clicks for common operations
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
### Planned Features
|
||||
1. **Drag and Drop**: Direct object dragging from selector to canvas
|
||||
2. **Multi-Selection**: Select and manipulate multiple objects
|
||||
3. **Copy/Paste**: Copy object configurations between rooms
|
||||
4. **Undo/Redo**: Full edit history management
|
||||
5. **Template System**: Save and load room templates
|
||||
|
||||
### Technical Improvements
|
||||
1. **GPU Acceleration**: Move rendering to GPU for better performance
|
||||
2. **Advanced Caching**: Predictive loading and intelligent cache management
|
||||
3. **Background Processing**: Asynchronous ROM data loading
|
||||
4. **Memory Optimization**: Reduce memory footprint for large dungeons
|
||||
|
||||
This documentation provides a comprehensive understanding of how the YAZE dungeon object system works, from high-level architecture to low-level implementation details. The system is designed to be both powerful for advanced users and accessible for newcomers to dungeon editing.
|
||||
@@ -1,61 +0,0 @@
|
||||
# yaze Performance Optimization Summary
|
||||
|
||||
## 🎉 **Massive Performance Improvements Achieved!**
|
||||
|
||||
### 📊 **Overall Performance Results**
|
||||
|
||||
| Component | Before | After | Improvement |
|
||||
|-----------|--------|-------|-------------|
|
||||
| **DungeonEditor::Load** | **17,967ms** | **3,747ms** | **🚀 79% faster!** |
|
||||
| **Total ROM Loading** | **~18.6s** | **~4.7s** | **🚀 75% faster!** |
|
||||
| **User Experience** | 18-second freeze | Near-instant | **Dramatic improvement** |
|
||||
|
||||
## 🚀 **Optimizations Implemented**
|
||||
|
||||
### 1. **Performance Monitoring System with Feature Flag**
|
||||
|
||||
- **Feature Flag Control**: `kEnablePerformanceMonitoring` in FeatureFlags allows enabling/disabling the system.
|
||||
- **Zero-Overhead When Disabled**: `ScopedTimer` becomes a no-op when monitoring is off.
|
||||
- **UI Toggle**: Performance monitoring can be toggled in the Settings UI.
|
||||
|
||||
### 2. **DungeonEditor Parallel Loading (79% Speedup)**
|
||||
|
||||
- **Problem Solved**: Loading 296 rooms sequentially was the primary bottleneck, taking ~18 seconds.
|
||||
- **Solution**: Implemented multi-threaded room loading, using up to 8 threads to process rooms in parallel. This includes thread-safe collection of results and hardware-aware concurrency.
|
||||
|
||||
### 3. **Incremental Overworld Map Loading**
|
||||
|
||||
- **Problem Solved**: UI would block and show blank maps while all 160 overworld maps were loaded upfront.
|
||||
- **Solution**: Implemented a priority-based incremental loading system. It creates textures for the current world's maps first, at a 4x faster rate (8 per frame), while showing "Loading..." placeholders for the rest.
|
||||
|
||||
### 4. **On-Demand Map Reloading**
|
||||
|
||||
- **Problem Solved**: Any property change would trigger an expensive full map refresh, even for non-visible maps.
|
||||
- **Solution**: An intelligent refresh system now only reloads maps that are currently visible. Changes to non-visible maps are deferred until they are viewed.
|
||||
|
||||
---
|
||||
|
||||
## Appendix A: Dungeon Editor Parallel Optimization
|
||||
|
||||
- **Problem Identified**: `DungeonEditor::LoadAllRooms` took **17.97 seconds**, accounting for 99.9% of loading time.
|
||||
- **Strategy**: The 296 independent rooms were loaded in parallel across up to 8 threads (~37 rooms per thread).
|
||||
- **Implementation**: Used `std::async` to launch tasks and `std::mutex` to safely collect results (like room size and palette data). Results are sorted on the main thread for consistency.
|
||||
- **Result**: Loading time for the dungeon editor was reduced by **79%** to ~3.7 seconds.
|
||||
|
||||
---
|
||||
|
||||
## Appendix B: Overworld Load Optimization
|
||||
|
||||
- **Problem Identified**: `Overworld::Load` took **2.9 seconds**, with the main bottleneck being the sequential decompression of 160 map tiles (`DecompressAllMapTiles`).
|
||||
- **Strategy**: Parallelize the decompression operations and implement lazy loading for maps that are not immediately visible.
|
||||
- **Implementation**: The plan involves using `std::async` to decompress map batches concurrently and creating a system to only load essential maps on startup, deferring the rest to a background process.
|
||||
- **Expected Result**: A 70-80% reduction in initial overworld loading time.
|
||||
|
||||
---
|
||||
|
||||
## Appendix C: Renderer Optimization
|
||||
|
||||
- **Problem Identified**: The original renderer created GPU textures synchronously on the main thread for all 160 overworld maps, blocking the UI for several seconds.
|
||||
- **Strategy**: Defer texture creation. Bitmaps and surface data are prepared first (a CPU-bound task that can be backgrounded), while the actual GPU texture creation (a main-thread-only task) is done progressively or on-demand.
|
||||
- **Implementation**: A `CreateBitmapWithoutTexture` method was introduced. A lazy loading system (`ProcessDeferredTextures`) processes a few textures per frame to avoid blocking, and `EnsureMapTexture` creates a texture immediately if a map becomes visible.
|
||||
- **Result**: A much more responsive UI during ROM loading, with an initial load time of only ~200-500ms.
|
||||
@@ -1,421 +0,0 @@
|
||||
# YAZE Graphics System Optimization Recommendations
|
||||
|
||||
## Overview
|
||||
This document provides comprehensive analysis and optimization recommendations for the YAZE graphics system, specifically targeting improvements for Link to the Past ROM hacking workflows.
|
||||
|
||||
## Current Architecture Analysis
|
||||
|
||||
### Strengths
|
||||
1. **Arena-based Resource Management**: Efficient SDL resource pooling
|
||||
2. **SNES-specific Format Support**: Proper handling of 4BPP/8BPP graphics
|
||||
3. **Palette Management**: Integrated SNES palette system
|
||||
4. **Tile-based Editing**: Support for 8x8 and 16x16 tiles
|
||||
|
||||
### Performance Bottlenecks Identified
|
||||
|
||||
#### 1. Bitmap Class Issues
|
||||
- **Linear Palette Search**: `SetPixel()` uses O(n) palette lookup
|
||||
- **Redundant Data Copies**: Multiple copies of pixel data
|
||||
- **Inefficient Texture Updates**: Full texture updates for single pixel changes
|
||||
- **Missing Bounds Optimization**: No early exit for out-of-bounds operations
|
||||
|
||||
#### 2. Arena Resource Management
|
||||
- **Hash Map Overhead**: O(1) lookup but memory overhead for small collections
|
||||
- **No Resource Pooling**: Each allocation creates new SDL resources
|
||||
- **Missing Batch Operations**: No bulk texture/surface operations
|
||||
|
||||
#### 3. Tilemap Performance
|
||||
- **Lazy Loading Inefficiency**: Tiles created on-demand without batching
|
||||
- **Memory Fragmentation**: Individual tile bitmaps cause memory fragmentation
|
||||
- **No Tile Caching Strategy**: No LRU or smart caching for frequently used tiles
|
||||
|
||||
## Optimization Recommendations
|
||||
|
||||
### 1. Bitmap Class Optimizations
|
||||
|
||||
#### A. Palette Lookup Optimization
|
||||
```cpp
|
||||
// Current: O(n) linear search
|
||||
uint8_t color_index = 0;
|
||||
for (size_t i = 0; i < palette_.size(); i++) {
|
||||
if (palette_[i].rgb().x == color.rgb().x && ...) {
|
||||
color_index = static_cast<uint8_t>(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Optimized: O(1) hash map lookup
|
||||
class Bitmap {
|
||||
private:
|
||||
std::unordered_map<uint32_t, uint8_t> color_to_index_cache_;
|
||||
|
||||
public:
|
||||
void InvalidatePaletteCache() {
|
||||
color_to_index_cache_.clear();
|
||||
for (size_t i = 0; i < palette_.size(); i++) {
|
||||
uint32_t color_hash = HashColor(palette_[i].rgb());
|
||||
color_to_index_cache_[color_hash] = static_cast<uint8_t>(i);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t FindColorIndex(const SnesColor& color) {
|
||||
uint32_t hash = HashColor(color.rgb());
|
||||
auto it = color_to_index_cache_.find(hash);
|
||||
return (it != color_to_index_cache_.end()) ? it->second : 0;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
#### B. Dirty Region Tracking
|
||||
```cpp
|
||||
class Bitmap {
|
||||
private:
|
||||
struct DirtyRegion {
|
||||
int min_x, min_y, max_x, max_y;
|
||||
bool is_dirty = false;
|
||||
} dirty_region_;
|
||||
|
||||
public:
|
||||
void SetPixel(int x, int y, const SnesColor& color) {
|
||||
// ... existing code ...
|
||||
|
||||
// Update dirty region instead of marking entire bitmap
|
||||
if (!dirty_region_.is_dirty) {
|
||||
dirty_region_.min_x = dirty_region_.max_x = x;
|
||||
dirty_region_.min_y = dirty_region_.max_y = y;
|
||||
dirty_region_.is_dirty = true;
|
||||
} else {
|
||||
dirty_region_.min_x = std::min(dirty_region_.min_x, x);
|
||||
dirty_region_.min_y = std::min(dirty_region_.min_y, y);
|
||||
dirty_region_.max_x = std::max(dirty_region_.max_x, x);
|
||||
dirty_region_.max_y = std::max(dirty_region_.max_y, y);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateTexture(SDL_Renderer* renderer) {
|
||||
if (!dirty_region_.is_dirty) return;
|
||||
|
||||
// Only update the dirty region
|
||||
SDL_Rect dirty_rect = {
|
||||
dirty_region_.min_x, dirty_region_.min_y,
|
||||
dirty_region_.max_x - dirty_region_.min_x + 1,
|
||||
dirty_region_.max_y - dirty_region_.min_y + 1
|
||||
};
|
||||
|
||||
// Update only the dirty region
|
||||
Arena::Get().UpdateTextureRegion(texture_, surface_, &dirty_rect);
|
||||
dirty_region_.is_dirty = false;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### 2. Arena Resource Management Improvements
|
||||
|
||||
#### A. Resource Pooling
|
||||
```cpp
|
||||
class Arena {
|
||||
private:
|
||||
struct TexturePool {
|
||||
std::vector<SDL_Texture*> available_textures_;
|
||||
std::unordered_map<SDL_Texture*, std::pair<int, int>> texture_sizes_;
|
||||
} texture_pool_;
|
||||
|
||||
struct SurfacePool {
|
||||
std::vector<SDL_Surface*> available_surfaces_;
|
||||
std::unordered_map<SDL_Surface*, std::tuple<int, int, int, int>> surface_info_;
|
||||
} surface_pool_;
|
||||
|
||||
public:
|
||||
SDL_Texture* AllocateTexture(SDL_Renderer* renderer, int width, int height) {
|
||||
// Try to reuse existing texture of same size
|
||||
for (auto it = texture_pool_.available_textures_.begin();
|
||||
it != texture_pool_.available_textures_.end(); ++it) {
|
||||
auto& size = texture_pool_.texture_sizes_[*it];
|
||||
if (size.first == width && size.second == height) {
|
||||
SDL_Texture* texture = *it;
|
||||
texture_pool_.available_textures_.erase(it);
|
||||
return texture;
|
||||
}
|
||||
}
|
||||
|
||||
// Create new texture if none available
|
||||
return CreateNewTexture(renderer, width, height);
|
||||
}
|
||||
|
||||
void FreeTexture(SDL_Texture* texture) {
|
||||
// Return to pool instead of destroying
|
||||
texture_pool_.available_textures_.push_back(texture);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
#### B. Batch Operations
|
||||
```cpp
|
||||
class Arena {
|
||||
public:
|
||||
struct BatchUpdate {
|
||||
std::vector<std::pair<SDL_Texture*, SDL_Surface*>> updates_;
|
||||
|
||||
void AddUpdate(SDL_Texture* texture, SDL_Surface* surface) {
|
||||
updates_.emplace_back(texture, surface);
|
||||
}
|
||||
|
||||
void Execute() {
|
||||
// Batch all texture updates for efficiency
|
||||
for (auto& update : updates_) {
|
||||
UpdateTexture(update.first, update.second);
|
||||
}
|
||||
updates_.clear();
|
||||
}
|
||||
};
|
||||
|
||||
BatchUpdate CreateBatch() { return BatchUpdate{}; }
|
||||
};
|
||||
```
|
||||
|
||||
### 3. Tilemap Performance Enhancements
|
||||
|
||||
#### A. Smart Tile Caching
|
||||
```cpp
|
||||
class Tilemap {
|
||||
private:
|
||||
struct TileCache {
|
||||
static constexpr size_t MAX_CACHE_SIZE = 1024;
|
||||
std::unordered_map<int, Bitmap> cache_;
|
||||
std::list<int> access_order_;
|
||||
|
||||
Bitmap* GetTile(int tile_id) {
|
||||
auto it = cache_.find(tile_id);
|
||||
if (it != cache_.end()) {
|
||||
// Move to front of access order
|
||||
access_order_.remove(tile_id);
|
||||
access_order_.push_front(tile_id);
|
||||
return &it->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CacheTile(int tile_id, Bitmap&& bitmap) {
|
||||
if (cache_.size() >= MAX_CACHE_SIZE) {
|
||||
// Remove least recently used tile
|
||||
int lru_tile = access_order_.back();
|
||||
access_order_.pop_back();
|
||||
cache_.erase(lru_tile);
|
||||
}
|
||||
|
||||
cache_[tile_id] = std::move(bitmap);
|
||||
access_order_.push_front(tile_id);
|
||||
}
|
||||
} tile_cache_;
|
||||
|
||||
public:
|
||||
void RenderTile(int tile_id) {
|
||||
Bitmap* cached_tile = tile_cache_.GetTile(tile_id);
|
||||
if (cached_tile) {
|
||||
core::Renderer::Get().UpdateBitmap(cached_tile);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create new tile and cache it
|
||||
Bitmap new_tile = CreateTileFromAtlas(tile_id);
|
||||
tile_cache_.CacheTile(tile_id, std::move(new_tile));
|
||||
core::Renderer::Get().RenderBitmap(&tile_cache_.cache_[tile_id]);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
#### B. Atlas-based Rendering
|
||||
```cpp
|
||||
class Tilemap {
|
||||
public:
|
||||
void RenderTilemap(const std::vector<int>& tile_ids,
|
||||
const std::vector<SDL_Rect>& positions) {
|
||||
// Batch render multiple tiles from atlas
|
||||
std::vector<SDL_Rect> src_rects;
|
||||
std::vector<SDL_Rect> dst_rects;
|
||||
|
||||
for (size_t i = 0; i < tile_ids.size(); ++i) {
|
||||
SDL_Rect src_rect = GetTileRect(tile_ids[i]);
|
||||
src_rects.push_back(src_rect);
|
||||
dst_rects.push_back(positions[i]);
|
||||
}
|
||||
|
||||
// Single draw call for all tiles
|
||||
core::Renderer::Get().RenderAtlas(atlas.texture(), src_rects, dst_rects);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### 4. Editor-Specific Optimizations
|
||||
|
||||
#### A. Graphics Editor Improvements
|
||||
```cpp
|
||||
class GraphicsEditor {
|
||||
private:
|
||||
struct EditingState {
|
||||
bool is_drawing = false;
|
||||
std::vector<PixelChange> undo_stack_;
|
||||
std::vector<PixelChange> redo_stack_;
|
||||
DirtyRegion current_edit_region_;
|
||||
} editing_state_;
|
||||
|
||||
public:
|
||||
void StartDrawing() {
|
||||
editing_state_.is_drawing = true;
|
||||
editing_state_.current_edit_region_.Reset();
|
||||
}
|
||||
|
||||
void EndDrawing() {
|
||||
if (editing_state_.is_drawing) {
|
||||
// Batch update only the edited region
|
||||
UpdateDirtyRegion(editing_state_.current_edit_region_);
|
||||
editing_state_.is_drawing = false;
|
||||
}
|
||||
}
|
||||
|
||||
void SetPixel(int x, int y, const SnesColor& color) {
|
||||
// Record change for undo/redo
|
||||
editing_state_.undo_stack_.emplace_back(x, y, GetPixel(x, y), color);
|
||||
|
||||
// Update pixel
|
||||
current_bitmap_->SetPixel(x, y, color);
|
||||
|
||||
// Update edit region
|
||||
editing_state_.current_edit_region_.AddPoint(x, y);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
#### B. Palette Editor Optimizations
|
||||
```cpp
|
||||
class PaletteEditor {
|
||||
private:
|
||||
struct PaletteCache {
|
||||
std::unordered_map<uint32_t, ImVec4> snes_to_rgba_cache_;
|
||||
std::unordered_map<uint32_t, uint16_t> rgba_to_snes_cache_;
|
||||
|
||||
void Invalidate() {
|
||||
snes_to_rgba_cache_.clear();
|
||||
rgba_to_snes_cache_.clear();
|
||||
}
|
||||
} palette_cache_;
|
||||
|
||||
public:
|
||||
ImVec4 ConvertSnesToRgba(uint16_t snes_color) {
|
||||
uint32_t key = snes_color;
|
||||
auto it = palette_cache_.snes_to_rgba_cache_.find(key);
|
||||
if (it != palette_cache_.snes_to_rgba_cache_.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
ImVec4 rgba = ConvertSnesColorToImVec4(SnesColor(snes_color));
|
||||
palette_cache_.snes_to_rgba_cache_[key] = rgba;
|
||||
return rgba;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### 5. Memory Management Improvements
|
||||
|
||||
#### A. Custom Allocator for Graphics Data
|
||||
```cpp
|
||||
class GraphicsAllocator {
|
||||
private:
|
||||
static constexpr size_t POOL_SIZE = 16 * 1024 * 1024; // 16MB
|
||||
char* pool_;
|
||||
size_t offset_;
|
||||
|
||||
public:
|
||||
GraphicsAllocator() : pool_(new char[POOL_SIZE]), offset_(0) {}
|
||||
|
||||
void* Allocate(size_t size) {
|
||||
if (offset_ + size > POOL_SIZE) {
|
||||
return nullptr; // Pool exhausted
|
||||
}
|
||||
|
||||
void* ptr = pool_ + offset_;
|
||||
offset_ += size;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void Reset() { offset_ = 0; }
|
||||
};
|
||||
```
|
||||
|
||||
#### B. Smart Pointer Management
|
||||
```cpp
|
||||
template<typename T>
|
||||
class GraphicsPtr {
|
||||
private:
|
||||
T* ptr_;
|
||||
std::function<void(T*)> deleter_;
|
||||
|
||||
public:
|
||||
GraphicsPtr(T* ptr, std::function<void(T*)> deleter)
|
||||
: ptr_(ptr), deleter_(deleter) {}
|
||||
|
||||
~GraphicsPtr() {
|
||||
if (ptr_ && deleter_) {
|
||||
deleter_(ptr_);
|
||||
}
|
||||
}
|
||||
|
||||
T* get() const { return ptr_; }
|
||||
T& operator*() const { return *ptr_; }
|
||||
T* operator->() const { return ptr_; }
|
||||
};
|
||||
```
|
||||
|
||||
## Implementation Priority
|
||||
|
||||
### Phase 1 (High Impact, Low Risk)
|
||||
1. **Palette Lookup Optimization**: Hash map for O(1) color lookups
|
||||
2. **Dirty Region Tracking**: Only update changed areas
|
||||
3. **Resource Pooling**: Reuse SDL textures and surfaces
|
||||
|
||||
### Phase 2 (Medium Impact, Medium Risk)
|
||||
1. **Tile Caching System**: LRU cache for frequently used tiles
|
||||
2. **Batch Operations**: Group texture updates
|
||||
3. **Memory Pool Allocator**: Custom allocator for graphics data
|
||||
|
||||
### Phase 3 (High Impact, High Risk)
|
||||
1. **Atlas-based Rendering**: Single draw calls for multiple tiles
|
||||
2. **Multi-threaded Updates**: Background texture processing
|
||||
3. **GPU-based Operations**: Move some operations to GPU
|
||||
|
||||
## Performance Metrics
|
||||
|
||||
### Target Improvements
|
||||
- **Palette Lookup**: 100x faster (O(n) → O(1))
|
||||
- **Texture Updates**: 10x faster (dirty regions)
|
||||
- **Memory Usage**: 30% reduction (resource pooling)
|
||||
- **Frame Rate**: 2x improvement (batch operations)
|
||||
|
||||
### Measurement Tools
|
||||
```cpp
|
||||
class PerformanceProfiler {
|
||||
public:
|
||||
void StartTimer(const std::string& operation) {
|
||||
timers_[operation] = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
|
||||
void EndTimer(const std::string& operation) {
|
||||
auto end = std::chrono::high_resolution_clock::now();
|
||||
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
end - timers_[operation]).count();
|
||||
|
||||
operation_times_[operation].push_back(duration);
|
||||
}
|
||||
|
||||
void Report() {
|
||||
for (auto& [operation, times] : operation_times_) {
|
||||
double avg_time = std::accumulate(times.begin(), times.end(), 0.0) / times.size();
|
||||
SDL_Log("Operation %s: %.2f μs average", operation.c_str(), avg_time);
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Conclusion
|
||||
|
||||
These optimizations will significantly improve the performance and responsiveness of the YAZE graphics system, particularly for ROM hacking workflows that involve frequent pixel manipulation, palette editing, and tile-based graphics editing. The phased approach ensures minimal risk while delivering substantial performance improvements.
|
||||
@@ -1,51 +0,0 @@
|
||||
# YAZE Graphics System Optimizations
|
||||
|
||||
## Overview
|
||||
This document provides a comprehensive summary of all graphics optimizations implemented in the YAZE ROM hacking editor. These optimizations provide significant performance improvements for Link to the Past graphics editing workflows, with expected gains of 100x faster palette lookups, 10x faster texture updates, and 30% memory reduction.
|
||||
|
||||
## Implemented Optimizations
|
||||
|
||||
### 1. Palette Lookup Optimization
|
||||
- **Impact**: 100x faster palette lookups (O(n) → O(1)).
|
||||
- **Implementation**: A `std::unordered_map` now caches color-to-index lookups within the `Bitmap` class, eliminating a linear search through the palette for each pixel operation.
|
||||
|
||||
### 2. Dirty Region Tracking
|
||||
- **Impact**: 10x faster texture updates.
|
||||
- **Implementation**: The `Bitmap` class now tracks modified regions (`DirtyRegion`). Instead of re-uploading the entire texture to the GPU for minor edits, only the changed portion is updated, significantly reducing GPU bandwidth usage.
|
||||
|
||||
### 3. Resource Pooling
|
||||
- **Impact**: ~30% reduction in texture memory usage.
|
||||
- **Implementation**: The central `Arena` manager now pools and reuses `SDL_Texture` and `SDL_Surface` objects of common sizes, which reduces memory fragmentation and eliminates the overhead of frequent resource creation and destruction.
|
||||
|
||||
### 4. LRU Tile Caching
|
||||
- **Impact**: 5x faster rendering of frequently used tiles.
|
||||
- **Implementation**: The `Tilemap` class now uses a Least Recently Used (LRU) cache. This avoids redundant creation of `Bitmap` objects for tiles that are already in memory, speeding up map rendering.
|
||||
|
||||
### 5. Batch Operations
|
||||
- **Impact**: 5x faster for multiple simultaneous texture updates.
|
||||
- **Implementation**: A batch update system was added to the `Arena`. Multiple texture update requests can be queued and then processed in a single, efficient batch, reducing SDL context switching overhead.
|
||||
|
||||
### 6. Memory Pool Allocator
|
||||
- **Impact**: 10x faster memory allocation for graphics data.
|
||||
- **Implementation**: A custom `MemoryPool` class provides pre-allocated memory blocks for common graphics sizes (e.g., 8x8 and 16x16 tiles), bypassing `malloc`/`free` overhead and reducing fragmentation.
|
||||
|
||||
### 7. Atlas-Based Rendering
|
||||
- **Impact**: Reduces draw calls from N to 1 for multiple elements.
|
||||
- **Implementation**: A new `AtlasRenderer` class dynamically packs multiple smaller bitmaps into a single large texture atlas. This allows many elements to be drawn in a single batch, minimizing GPU state changes and draw call overhead.
|
||||
|
||||
### 8. Performance Monitoring & Validation
|
||||
- **Implementation**: A comprehensive `PerformanceProfiler` and `PerformanceDashboard` were created to measure the impact of these optimizations and detect regressions. A full benchmark suite (`test/gfx_optimization_benchmarks.cc`) validates the performance gains.
|
||||
|
||||
## Future Optimization Recommendations
|
||||
|
||||
### High Priority
|
||||
1. **Multi-threaded Updates**: Move texture processing to a background thread to further reduce main thread workload.
|
||||
2. **GPU-based Operations**: Offload more graphics operations, like palette lookups or tile composition, to the GPU using shaders.
|
||||
|
||||
### Medium Priority
|
||||
1. **Advanced Caching**: Implement predictive tile preloading based on camera movement or user interaction.
|
||||
2. **Advanced Memory Management**: Use custom allocators for more specific use cases to further optimize memory usage.
|
||||
|
||||
## Conclusion
|
||||
|
||||
These completed optimizations have significantly improved the performance and responsiveness of the YAZE graphics system. They provide a faster, more efficient experience for ROM hackers, especially when working with large graphics sheets and complex edits, while maintaining full backward compatibility.
|
||||
@@ -1,407 +0,0 @@
|
||||
# ImGui Widget Testing Guide
|
||||
|
||||
## Overview
|
||||
|
||||
This guide explains how to use YAZE's ImGui testing infrastructure for automated GUI testing and AI agent interaction.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Components
|
||||
|
||||
1. **WidgetIdRegistry**: Centralized registry of all GUI widgets with hierarchical paths
|
||||
2. **AutoWidgetScope**: RAII helper for automatic widget registration
|
||||
3. **Auto* Wrappers**: Drop-in replacements for ImGui functions that auto-register widgets
|
||||
4. **ImGui Test Engine**: Automated testing framework
|
||||
5. **ImGuiTestHarness**: gRPC service for remote test control
|
||||
|
||||
### Widget Hierarchy
|
||||
|
||||
Widgets are identified by hierarchical paths:
|
||||
```
|
||||
Dungeon/Canvas/canvas:DungeonCanvas
|
||||
Dungeon/RoomSelector/selectable:Room_5
|
||||
Dungeon/ObjectEditor/input_int:ObjectID
|
||||
Overworld/Toolset/button:DrawTile
|
||||
```
|
||||
|
||||
Format: `Editor/Section/type:name`
|
||||
|
||||
## Integration Guide
|
||||
|
||||
### 1. Add Auto-Registration to Your Editor
|
||||
|
||||
**Before**:
|
||||
```cpp
|
||||
// dungeon_editor.cc
|
||||
void DungeonEditor::DrawCanvasPanel() {
|
||||
if (ImGui::Button("Save")) {
|
||||
SaveRoom();
|
||||
}
|
||||
ImGui::InputInt("Room ID", &room_id_);
|
||||
}
|
||||
```
|
||||
|
||||
**After**:
|
||||
```cpp
|
||||
#include "app/gui/widget_auto_register.h"
|
||||
|
||||
void DungeonEditor::DrawCanvasPanel() {
|
||||
gui::AutoWidgetScope scope("Dungeon/Canvas");
|
||||
|
||||
if (gui::AutoButton("Save##RoomSave")) {
|
||||
SaveRoom();
|
||||
}
|
||||
gui::AutoInputInt("Room ID", &room_id_);
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Register Canvas and Tables
|
||||
|
||||
```cpp
|
||||
void DungeonEditor::DrawDungeonCanvas() {
|
||||
gui::AutoWidgetScope scope("Dungeon/Canvas");
|
||||
|
||||
ImGui::BeginChild("DungeonCanvas", ImVec2(512, 512));
|
||||
gui::RegisterCanvas("DungeonCanvas", "Main dungeon editing canvas");
|
||||
|
||||
// ... canvas drawing code ...
|
||||
|
||||
ImGui::EndChild();
|
||||
}
|
||||
|
||||
void DungeonEditor::DrawRoomSelector() {
|
||||
gui::AutoWidgetScope scope("Dungeon/RoomSelector");
|
||||
|
||||
if (ImGui::BeginTable("RoomList", 3, table_flags)) {
|
||||
gui::RegisterTable("RoomList", "List of dungeon rooms");
|
||||
|
||||
for (int i = 0; i < rooms_.size(); i++) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
std::string label = absl::StrFormat("Room_%d##room%d", i, i);
|
||||
if (gui::AutoSelectable(label.c_str(), selected_room_ == i)) {
|
||||
OnRoomSelected(i);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Hierarchical Scoping
|
||||
|
||||
Use nested scopes for complex UIs:
|
||||
|
||||
```cpp
|
||||
void DungeonEditor::Update() {
|
||||
gui::AutoWidgetScope editor_scope("Dungeon");
|
||||
|
||||
if (ImGui::BeginTable("DungeonEditTable", 3)) {
|
||||
gui::RegisterTable("DungeonEditTable");
|
||||
|
||||
// Column 1: Room Selector
|
||||
ImGui::TableNextColumn();
|
||||
{
|
||||
gui::AutoWidgetScope selector_scope("RoomSelector");
|
||||
DrawRoomSelector();
|
||||
}
|
||||
|
||||
// Column 2: Canvas
|
||||
ImGui::TableNextColumn();
|
||||
{
|
||||
gui::AutoWidgetScope canvas_scope("Canvas");
|
||||
DrawCanvas();
|
||||
}
|
||||
|
||||
// Column 3: Object Editor
|
||||
ImGui::TableNextColumn();
|
||||
{
|
||||
gui::AutoWidgetScope editor_scope("ObjectEditor");
|
||||
DrawObjectEditor();
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Register Custom Widgets
|
||||
|
||||
For widgets not covered by Auto* wrappers:
|
||||
|
||||
```cpp
|
||||
void DrawCustomWidget() {
|
||||
ImGui::PushID("MyCustomWidget");
|
||||
|
||||
// ... custom drawing ...
|
||||
|
||||
// Get the item ID after drawing
|
||||
ImGuiID custom_id = ImGui::GetItemID();
|
||||
|
||||
// Register manually
|
||||
gui::AutoRegisterLastItem("custom", "MyCustomWidget",
|
||||
"Custom widget description");
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
```
|
||||
|
||||
## Writing Tests
|
||||
|
||||
### Basic Test Structure
|
||||
|
||||
```cpp
|
||||
#include "imgui_test_engine/imgui_te_engine.h"
|
||||
#include "imgui_test_engine/imgui_te_context.h"
|
||||
|
||||
ImGuiTest* t = IM_REGISTER_TEST(engine, "dungeon_editor", "canvas_visible");
|
||||
t->TestFunc = [](ImGuiTestContext* ctx) {
|
||||
ctx->SetRef("Dungeon Editor");
|
||||
|
||||
// Verify canvas exists
|
||||
IM_CHECK(ctx->ItemExists("Dungeon/Canvas/canvas:DungeonCanvas"));
|
||||
|
||||
// Check visibility
|
||||
auto canvas_info = ctx->ItemInfo("Dungeon/Canvas/canvas:DungeonCanvas");
|
||||
IM_CHECK(canvas_info != nullptr);
|
||||
IM_CHECK(canvas_info->RectFull.GetWidth() > 0);
|
||||
};
|
||||
```
|
||||
|
||||
### Test Actions
|
||||
|
||||
```cpp
|
||||
// Click a button
|
||||
ctx->ItemClick("Dungeon/Toolset/button:Save");
|
||||
|
||||
// Type into an input
|
||||
ctx->ItemInputValue("Dungeon/ObjectEditor/input_int:ObjectID", 42);
|
||||
|
||||
// Check a checkbox
|
||||
ctx->ItemCheck("Dungeon/ObjectEditor/checkbox:ShowBG1");
|
||||
|
||||
// Select from combo
|
||||
ctx->ComboClick("Dungeon/Settings/combo:PaletteGroup", "Palette 2");
|
||||
|
||||
// Wait for condition
|
||||
ctx->ItemWaitForVisible("Dungeon/Canvas/canvas:DungeonCanvas", 2.0f);
|
||||
```
|
||||
|
||||
### Test with Variables
|
||||
|
||||
```cpp
|
||||
struct MyTestVars {
|
||||
int room_id = 0;
|
||||
bool canvas_loaded = false;
|
||||
};
|
||||
|
||||
ImGuiTest* t = IM_REGISTER_TEST(engine, "my_test", "test_name");
|
||||
t->SetVarsDataType<MyTestVars>();
|
||||
|
||||
t->TestFunc = [](ImGuiTestContext* ctx) {
|
||||
MyTestVars& vars = ctx->GetVars<MyTestVars>();
|
||||
|
||||
// Use vars for test state
|
||||
vars.room_id = 5;
|
||||
ctx->ItemClick(absl::StrFormat("Room_%d", vars.room_id).c_str());
|
||||
};
|
||||
```
|
||||
|
||||
## Agent Integration
|
||||
|
||||
### Widget Discovery
|
||||
|
||||
The z3ed agent can discover available widgets:
|
||||
|
||||
```bash
|
||||
z3ed describe --widget-catalog
|
||||
```
|
||||
|
||||
Output (YAML):
|
||||
```yaml
|
||||
widgets:
|
||||
- path: "Dungeon/Canvas/canvas:DungeonCanvas"
|
||||
type: canvas
|
||||
label: "DungeonCanvas"
|
||||
window: "Dungeon Editor"
|
||||
visible: true
|
||||
enabled: true
|
||||
bounds:
|
||||
min: [100.0, 50.0]
|
||||
max: [612.0, 562.0]
|
||||
actions: [click, drag, scroll]
|
||||
description: "Main dungeon editing canvas"
|
||||
```
|
||||
|
||||
### Remote Testing via gRPC
|
||||
|
||||
```bash
|
||||
# Click a button
|
||||
z3ed test click "Dungeon/Toolset/button:Save"
|
||||
|
||||
# Type text
|
||||
z3ed test type "Dungeon/Search/input:RoomName" "Hyrule Castle"
|
||||
|
||||
# Wait for element
|
||||
z3ed test wait "Dungeon/Canvas/canvas:DungeonCanvas" --timeout 5s
|
||||
|
||||
# Take screenshot
|
||||
z3ed test screenshot --window "Dungeon Editor" --output dungeon.png
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Use Stable IDs
|
||||
|
||||
```cpp
|
||||
// GOOD: Stable ID that won't change with label
|
||||
gui::AutoButton("Save##DungeonSave");
|
||||
|
||||
// BAD: Label might change in translations
|
||||
gui::AutoButton("Save");
|
||||
```
|
||||
|
||||
### 2. Hierarchical Naming
|
||||
|
||||
```cpp
|
||||
// GOOD: Clear hierarchy
|
||||
{
|
||||
gui::AutoWidgetScope("Dungeon");
|
||||
{
|
||||
gui::AutoWidgetScope("Canvas");
|
||||
// Widgets here: Dungeon/Canvas/...
|
||||
}
|
||||
}
|
||||
|
||||
// BAD: Flat structure, name collisions
|
||||
gui::AutoButton("Save"); // Which editor's save?
|
||||
```
|
||||
|
||||
### 3. Descriptive Names
|
||||
|
||||
```cpp
|
||||
// GOOD: Self-documenting
|
||||
gui::RegisterCanvas("DungeonCanvas", "Main editing canvas for dungeon rooms");
|
||||
|
||||
// BAD: Generic
|
||||
gui::RegisterCanvas("Canvas");
|
||||
```
|
||||
|
||||
### 4. Frame Lifecycle
|
||||
|
||||
```cpp
|
||||
void Editor::Update() {
|
||||
// Begin frame for widget registry
|
||||
gui::WidgetIdRegistry::Instance().BeginFrame();
|
||||
|
||||
// ... draw all your widgets ...
|
||||
|
||||
// End frame to prune stale widgets
|
||||
gui::WidgetIdRegistry::Instance().EndFrame();
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Test Organization
|
||||
|
||||
```cpp
|
||||
// Group related tests
|
||||
RegisterCanvasTests(engine); // Canvas rendering tests
|
||||
RegisterRoomSelectorTests(engine); // Room selection tests
|
||||
RegisterObjectEditorTests(engine); // Object editing tests
|
||||
```
|
||||
|
||||
## Debugging
|
||||
|
||||
### View Widget Registry
|
||||
|
||||
```cpp
|
||||
// Export current registry to file
|
||||
gui::WidgetIdRegistry::Instance().ExportCatalogToFile("widgets.yaml", "yaml");
|
||||
```
|
||||
|
||||
### Check if Widget Registered
|
||||
|
||||
```cpp
|
||||
auto& registry = gui::WidgetIdRegistry::Instance();
|
||||
ImGuiID widget_id = registry.GetWidgetId("Dungeon/Canvas/canvas:DungeonCanvas");
|
||||
if (widget_id == 0) {
|
||||
// Widget not registered!
|
||||
}
|
||||
```
|
||||
|
||||
### Test Engine Debug UI
|
||||
|
||||
```cpp
|
||||
#ifdef IMGUI_ENABLE_TEST_ENGINE
|
||||
ImGuiTestEngine_ShowTestEngineWindows(engine, &show_test_engine);
|
||||
#endif
|
||||
```
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
1. **Auto-registration overhead**: Minimal (~1-2μs per widget per frame)
|
||||
2. **Registry size**: Automatically prunes stale widgets after 600 frames
|
||||
3. **gRPC latency**: 1-5ms for local connections
|
||||
|
||||
## Common Issues
|
||||
|
||||
### Widget Not Found
|
||||
|
||||
**Problem**: Test can't find widget path
|
||||
**Solution**: Check widget is registered and path is correct
|
||||
|
||||
```cpp
|
||||
// List all widgets
|
||||
auto& registry = gui::WidgetIdRegistry::Instance();
|
||||
for (const auto& [path, info] : registry.GetAllWidgets()) {
|
||||
std::cout << path << std::endl;
|
||||
}
|
||||
```
|
||||
|
||||
### ID Collisions
|
||||
|
||||
**Problem**: Multiple widgets with same ID
|
||||
**Solution**: Use unique IDs with `##`
|
||||
|
||||
```cpp
|
||||
// GOOD
|
||||
gui::AutoButton("Save##DungeonSave");
|
||||
gui::AutoButton("Save##OverworldSave");
|
||||
|
||||
// BAD
|
||||
gui::AutoButton("Save"); // Multiple Save buttons collide!
|
||||
gui::AutoButton("Save");
|
||||
```
|
||||
|
||||
### Scope Issues
|
||||
|
||||
**Problem**: Widgets disappearing after scope exit
|
||||
**Solution**: Ensure scopes match widget lifetime
|
||||
|
||||
```cpp
|
||||
// GOOD
|
||||
{
|
||||
gui::AutoWidgetScope scope("Dungeon");
|
||||
gui::AutoButton("Save"); // Registered as Dungeon/button:Save
|
||||
}
|
||||
|
||||
// BAD
|
||||
gui::AutoWidgetScope("Dungeon"); // Scope ends immediately!
|
||||
gui::AutoButton("Save"); // No scope active
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
See:
|
||||
- `test/imgui/dungeon_editor_tests.cc` - Comprehensive dungeon editor tests
|
||||
- `src/app/editor/dungeon/dungeon_editor.cc` - Integration example
|
||||
- `docs/z3ed/E6-z3ed-cli-design.md` - Agent interaction design
|
||||
|
||||
## References
|
||||
|
||||
- [ImGui Test Engine Documentation](https://github.com/ocornut/imgui_test_engine)
|
||||
- [Dear ImGui Documentation](https://github.com/ocornut/imgui)
|
||||
- [z3ed CLI Design](../docs/z3ed/E6-z3ed-cli-design.md)
|
||||
|
||||
@@ -12,7 +12,6 @@ Yet Another Zelda3 Editor - A comprehensive ROM editor for The Legend of Zelda:
|
||||
## Development
|
||||
|
||||
- [Testing Guide](A1-testing-guide.md) - Testing framework and best practices
|
||||
- [Contributing](B1-contributing.md) - Development guidelines and standards
|
||||
- [Platform Compatibility](B2-platform-compatibility.md) - Cross-platform support details
|
||||
- [Build Presets](B3-build-presets.md) - CMake preset usage guide
|
||||
- [Release Workflows](B4-release-workflows.md) - GitHub Actions release pipeline documentation
|
||||
@@ -24,10 +23,7 @@ Yet Another Zelda3 Editor - A comprehensive ROM editor for The Legend of Zelda:
|
||||
- [Assembly Style Guide](E1-asm-style-guide.md) - 65816 assembly coding standards
|
||||
|
||||
### Editor Systems
|
||||
- [Dungeon Editor Guide](E2-dungeon-editor-guide.md) - Complete dungeon editing guide
|
||||
- [Dungeon Editor Design](E3-dungeon-editor-design.md) - Architecture and development guide
|
||||
- [Dungeon Editor Refactoring](E4-dungeon-editor-refactoring.md) - Component-based architecture plan
|
||||
- [Dungeon Object System](E5-dungeon-object-system.md) - Object management framework
|
||||
- [Dungeon Editor Guide](dungeon_editor_master_guide.md) - Complete dungeon editing guide
|
||||
|
||||
### Overworld System
|
||||
- [Overworld Loading](F1-overworld-loading.md) - ZSCustomOverworld v3 implementation
|
||||
@@ -43,5 +39,3 @@ Yet Another Zelda3 Editor - A comprehensive ROM editor for The Legend of Zelda:
|
||||
- **CMake Compatibility**: Automatic handling of submodule compatibility issues (abseil-cpp, SDL)
|
||||
|
||||
---
|
||||
|
||||
*Last updated: December 2025 - Version 0.3.2*
|
||||
@@ -1,27 +1,33 @@
|
||||
# z3ed: AI-Powered CLI for YAZE
|
||||
|
||||
**Status**: Production Ready (AI Integration)
|
||||
**Latest Update**: October 3, 2025
|
||||
**Version**: 0.1.0-alpha
|
||||
**Last Updated**: October 4, 2025
|
||||
|
||||
## Overview
|
||||
## 1. Overview
|
||||
|
||||
`z3ed` is a command-line interface for YAZE enabling AI-driven ROM modifications through a conversational interface. It provides natural language interaction for ROM inspection and editing with a safe proposal-based workflow.
|
||||
This document is the **source of truth** for the z3ed CLI architecture, design, and roadmap. It outlines the evolution of `z3ed` into a powerful, scriptable, and extensible tool for both manual and AI-driven ROM hacking.
|
||||
|
||||
**Core Capabilities**:
|
||||
1. **Conversational Agent**: Chat with AI to explore ROM contents and plan changes
|
||||
2. **GUI Test Automation**: Widget discovery, recording/replay, introspection
|
||||
3. **Proposal System**: Sandbox editing with review workflow
|
||||
4. **Multiple AI Backends**: Ollama (local), Gemini (cloud)
|
||||
`z3ed` has successfully implemented its core infrastructure and is **production-ready on macOS**.
|
||||
|
||||
## Quick Start
|
||||
### Core Capabilities
|
||||
|
||||
1. **Conversational Agent**: Chat with an AI (Ollama or Gemini) to explore ROM contents and plan changes using natural language.
|
||||
2. **GUI Test Automation**: A gRPC-based test harness allows for widget discovery, test recording/replay, and introspection for debugging and AI-driven validation.
|
||||
3. **Proposal System**: A safe, sandboxed editing workflow where all changes are tracked as "proposals" that require human review and acceptance.
|
||||
4. **Resource-Oriented CLI**: A clean `z3ed <resource> <action>` command structure that is both human-readable and machine-parsable.
|
||||
|
||||
## 2. Quick Start
|
||||
|
||||
### Build
|
||||
|
||||
A single `Z3ED_AI=ON` CMake flag enables all AI features, including JSON, YAML, and httplib dependencies. This simplifies the build process.
|
||||
|
||||
```bash
|
||||
# Full AI features (RECOMMENDED)
|
||||
# Build with AI features (RECOMMENDED)
|
||||
cmake -B build -DZ3ED_AI=ON
|
||||
cmake --build build --target z3ed
|
||||
|
||||
# With GUI automation
|
||||
# For GUI automation features, also include gRPC
|
||||
cmake -B build -DZ3ED_AI=ON -DYAZE_WITH_GRPC=ON
|
||||
cmake --build build --target z3ed
|
||||
```
|
||||
@@ -31,14 +37,14 @@ cmake --build build --target z3ed
|
||||
**Ollama (Recommended for Development)**:
|
||||
```bash
|
||||
brew install ollama # macOS
|
||||
ollama pull qwen2.5-coder:7b # Pull model
|
||||
ollama pull qwen2.5-coder:7b # Pull recommended model
|
||||
ollama serve # Start server
|
||||
```
|
||||
|
||||
**Gemini (Cloud API)**:
|
||||
```bash
|
||||
# Get API key from https://aistudio.google.com/apikey
|
||||
export GEMINI_API_KEY="your-key-here"
|
||||
# Get key from https://aistudio.google.com/apikey
|
||||
```
|
||||
|
||||
### Example Commands
|
||||
@@ -55,18 +61,6 @@ z3ed agent simple-chat --rom zelda3.sfc
|
||||
z3ed agent simple-chat --file queries.txt --rom zelda3.sfc
|
||||
```
|
||||
|
||||
**Direct Tool Usage**:
|
||||
```bash
|
||||
# List dungeons
|
||||
z3ed agent resource-list --type dungeon --format json
|
||||
|
||||
# Find tiles
|
||||
z3ed agent overworld-find-tile --tile 0x02E --map 0x05
|
||||
|
||||
# Inspect sprites
|
||||
z3ed agent dungeon-list-sprites --room 0x012
|
||||
```
|
||||
|
||||
**Proposal Workflow**:
|
||||
```bash
|
||||
# Generate from prompt
|
||||
@@ -82,392 +76,113 @@ z3ed agent diff --proposal-id <id>
|
||||
z3ed agent accept --proposal-id <id>
|
||||
```
|
||||
|
||||
## Chat Modes
|
||||
## 3. Architecture
|
||||
|
||||
### 1. FTXUI Chat (`agent chat`)
|
||||
Full-screen interactive terminal with:
|
||||
- Table rendering for JSON results
|
||||
- Syntax highlighting
|
||||
- Scrollable history
|
||||
- Best for manual exploration
|
||||
The z3ed system is composed of several layers, from the high-level AI agent down to the YAZE GUI and test harness.
|
||||
|
||||
### 2. Simple Chat (`agent simple-chat`)
|
||||
Text-based REPL without FTXUI:
|
||||
- Lightweight, no dependencies
|
||||
- Scriptable and automatable
|
||||
- Batch mode support
|
||||
- Better for AI agent testing
|
||||
- Commands: `quit`, `exit`, `reset`
|
||||
### System Components Diagram
|
||||
|
||||
### 3. GUI Chat Widget (In Progress)
|
||||
ImGui widget in YAZE editor:
|
||||
- Same backend as CLI
|
||||
- Dockable interface
|
||||
- History persistence
|
||||
- Visual proposal review
|
||||
|
||||
## Available Tools
|
||||
|
||||
The agent can call these tools autonomously:
|
||||
|
||||
| Tool | Purpose | Example |
|
||||
|------|---------|---------|
|
||||
| `resource-list` | List labeled resources | "What dungeons exist?" |
|
||||
| `resource-search` | Fuzzy search across labels | "Search for soldier labels" |
|
||||
| `dungeon-list-sprites` | Sprites in room | "Show soldiers in room 0x12" |
|
||||
| `dungeon-describe-room` | Room metadata summary | "Describe room 0x012" |
|
||||
| `overworld-find-tile` | Find tile locations | "Where is tile 0x2E used?" |
|
||||
| `overworld-describe-map` | Map metadata | "Describe map 0x05" |
|
||||
| `overworld-list-warps` | List entrances/exits | "Show all cave entrances" |
|
||||
|
||||
|
||||
### 🎯 Next Steps
|
||||
2. **GUI Integration** (4-6h): Wire chat widget into main app
|
||||
3. **Proposal Integration** (6-8h): Connect chat to ROM modification
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Chat mode freezes
|
||||
**Solution**: Use `agent simple-chat` instead of `agent chat`
|
||||
|
||||
## Example Workflows
|
||||
|
||||
### Explore ROM
|
||||
```bash
|
||||
$ z3ed agent simple-chat --rom zelda3.sfc
|
||||
You: What dungeons are defined?
|
||||
Agent: <calls resource-list --type dungeon>
|
||||
ID Label
|
||||
---- ------------------------
|
||||
0x00 eastern_palace
|
||||
0x01 desert_palace
|
||||
...
|
||||
|
||||
You: Show me sprites in the first dungeon room 0x012
|
||||
Agent: <calls dungeon-list-sprites --room 0x012>
|
||||
...
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ AI Agent Layer (LLM: Ollama, Gemini) │
|
||||
└────────────────────┬────────────────────────────────────┘
|
||||
│
|
||||
┌────────────────────▼────────────────────────────────────┐
|
||||
│ z3ed CLI (Command-Line Interface) │
|
||||
│ ├─ agent run/plan/diff/test/list/describe │
|
||||
│ └─ rom/palette/overworld/dungeon commands │
|
||||
└────────────────────┬────────────────────────────────────┘
|
||||
│
|
||||
┌────────────────────▼────────────────────────────────────┐
|
||||
│ Service Layer (Singleton Services) │
|
||||
│ ├─ ProposalRegistry (Proposal Tracking) │
|
||||
│ ├─ RomSandboxManager (Isolated ROM Copies) │
|
||||
│ ├─ ResourceCatalog (Machine-Readable API Specs) │
|
||||
│ └─ ConversationalAgentService (Chat & Tool Dispatch) │
|
||||
└────────────────────┬────────────────────────────────────┘
|
||||
│
|
||||
┌────────────────────▼────────────────────────────────────┐
|
||||
│ ImGuiTestHarness (gRPC Server in YAZE) │
|
||||
│ ├─ Ping, Click, Type, Wait, Assert, Screenshot │
|
||||
│ └─ Introspection & Discovery RPCs │
|
||||
└────────────────────┬────────────────────────────────────┘
|
||||
│
|
||||
┌────────────────────▼────────────────────────────────────┐
|
||||
│ YAZE GUI (ImGui Application) │
|
||||
│ └─ ProposalDrawer & Editor Windows │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Make Changes
|
||||
```bash
|
||||
$ z3ed agent run --prompt "Add a tree at position 10,10 on map 0" --sandbox
|
||||
Proposal created: abc123
|
||||
## 4. Agentic & Generative Workflow (MCP)
|
||||
|
||||
$ z3ed agent diff --proposal-id abc123
|
||||
Commands:
|
||||
overworld set-tile --map 0 --x 10 --y 10 --tile 0x02E
|
||||
The `z3ed` CLI is the foundation for an AI-driven Model-Code-Program (MCP) loop, where the AI agent's "program" is a script of `z3ed` commands.
|
||||
|
||||
$ z3ed agent accept --proposal-id abc123
|
||||
✅ Proposal accepted
|
||||
```
|
||||
1. **Model (Planner)**: The agent receives a natural language prompt and leverages an LLM to create a plan, which is a sequence of `z3ed` commands.
|
||||
2. **Code (Generation)**: The LLM returns the plan as a structured JSON object containing actions.
|
||||
3. **Program (Execution)**: The `z3ed agent` parses the plan and executes each command sequentially in a sandboxed ROM environment.
|
||||
4. **Verification (Tester)**: The `ImGuiTestHarness` is used to run automated GUI tests to verify that the changes were applied correctly.
|
||||
|
||||
## Overview
|
||||
## 5. Command Reference
|
||||
|
||||
`z3ed` is a command-line interface for YAZE that enables AI-driven ROM modifications through a proposal-based workflow. It provides both human-accessible commands for developers and machine-readable APIs for LLM integration.
|
||||
### Agent Commands
|
||||
|
||||
**Core Capabilities**:
|
||||
1. **AI-Driven Editing**: Natural language prompts → ROM modifications (overworld tile16, dungeon objects, sprites, palettes)
|
||||
2. **GUI Test Automation**: Widget discovery, test recording/replay, introspection for debugging
|
||||
3. **Proposal System**: Safe sandbox editing with accept/reject workflow
|
||||
4. **Multiple AI Backends**: Ollama (local), Gemini (cloud), Claude (planned)
|
||||
- `agent run --prompt "..."`: Executes an AI-driven ROM modification in a sandbox.
|
||||
- `agent plan --prompt "..."`: Shows the sequence of commands the AI plans to execute.
|
||||
- `agent list`: Shows all proposals and their status.
|
||||
- `agent diff [--proposal-id <id>]`: Shows the changes, logs, and metadata for a proposal.
|
||||
- `agent describe [--resource <name>]`: Exports machine-readable API specifications for AI consumption.
|
||||
- `agent chat`: Opens an interactive terminal chat (TUI) with the AI agent.
|
||||
- `agent simple-chat`: A lightweight, non-TUI chat mode for scripting and automation.
|
||||
- `agent test ...`: Commands for running and managing automated GUI tests.
|
||||
|
||||
## Quick Start
|
||||
### Resource Commands
|
||||
|
||||
### Build Options
|
||||
- `rom info|validate|diff`: Commands for ROM file inspection and comparison.
|
||||
- `palette export|import|list`: Commands for palette manipulation.
|
||||
- `overworld get-tile|find-tile|set-tile`: Commands for overworld editing.
|
||||
- `dungeon list-sprites|list-rooms`: Commands for dungeon inspection.
|
||||
|
||||
```bash
|
||||
# Basic z3ed (CLI only, no AI/testing features)
|
||||
cmake --build build --target z3ed
|
||||
## 6. Chat Modes
|
||||
|
||||
# Full build with AI agent (RECOMMENDED - uses consolidated flag)
|
||||
cmake -B build -DZ3ED_AI=ON
|
||||
cmake --build build --target z3ed
|
||||
### FTXUI Chat (`agent chat`)
|
||||
Full-screen interactive terminal with table rendering, syntax highlighting, and scrollable history. Best for manual exploration.
|
||||
|
||||
# use macos-dev-z3ed-ai cmake preset
|
||||
### Simple Chat (`agent simple-chat`)
|
||||
Lightweight, scriptable text-based REPL that supports single messages, interactive sessions, piped input, and batch files.
|
||||
|
||||
# Full build with AI agent AND testing suite
|
||||
cmake -B build -DZ3ED_AI=ON -DYAZE_WITH_GRPC=ON
|
||||
cmake --build build --target z3ed
|
||||
```
|
||||
### GUI Chat Widget (In Progress)
|
||||
An ImGui widget in the main YAZE editor that will provide the same functionality with a graphical interface.
|
||||
|
||||
**Build Flags Explained**:
|
||||
- `Z3ED_AI=ON` - **Master flag** for AI features (enables JSON, YAML, httplib for Ollama + Gemini)
|
||||
- `YAZE_WITH_GRPC=ON` - Optional GUI automation and test harness (also enables JSON)
|
||||
- `YAZE_WITH_JSON=ON` - Lower-level flag (auto-enabled by Z3ED_AI or GRPC)
|
||||
## 7. AI Provider Configuration
|
||||
|
||||
**Dependencies for AI Features** (auto-managed by Z3ED_AI):
|
||||
- nlohmann/json (JSON parsing for AI responses)
|
||||
- yaml-cpp (Config file loading)
|
||||
- httplib (HTTP/HTTPS API calls)
|
||||
- OpenSSL (optional, for Gemini HTTPS - auto-detected on macOS/Linux)
|
||||
Z3ED supports multiple AI providers. Configuration is resolved with command-line flags taking precedence over environment variables.
|
||||
|
||||
### AI Agent Commands
|
||||
- `--ai_provider=<provider>`: Selects the AI provider (`mock`, `ollama`, `gemini`).
|
||||
- `--ai_model=<model>`: Specifies the model name (e.g., `qwen2.5-coder:7b`, `gemini-1.5-flash`).
|
||||
- `--gemini_api_key=<key>`: Your Gemini API key.
|
||||
- `--ollama_host=<url>`: The URL for your Ollama server (default: `http://localhost:11434`).
|
||||
|
||||
```bash
|
||||
# Generate commands from natural language prompt
|
||||
z3ed agent plan --prompt "Place a tree at position 10, 10 on map 0"
|
||||
## 8. Roadmap & Implementation Status
|
||||
|
||||
# Execute in sandbox with auto-approval
|
||||
z3ed agent run --prompt "Create a 3x3 water pond at 15, 20" --rom zelda3.sfc --sandbox
|
||||
**Last Updated**: October 4, 2025
|
||||
|
||||
# Chat with the agent in the terminal (FTXUI prototype)
|
||||
z3ed agent chat
|
||||
### ✅ Completed
|
||||
|
||||
# List all proposals
|
||||
z3ed agent list
|
||||
- **Core Infrastructure**: Resource-oriented CLI, proposal workflow, sandbox manager, and resource catalog are all production-ready.
|
||||
- **AI Backends**: Both Ollama (local) and Gemini (cloud) are operational.
|
||||
- **Conversational Agent**: The agent service, tool dispatcher (with 5 read-only tools), and TUI/simple chat interfaces are complete.
|
||||
- **GUI Test Harness**: A comprehensive GUI testing platform with introspection, widget discovery, recording/replay, and CI integration support.
|
||||
|
||||
# View proposal details
|
||||
z3ed agent diff --proposal <id>
|
||||
### 🚧 Active & Next Steps
|
||||
|
||||
# Inspect project metadata for the LLM toolchain
|
||||
z3ed agent resource-list --type dungeon --format json
|
||||
1. **Live LLM Testing (1-2h)**: Verify function calling with real models (Ollama/Gemini).
|
||||
2. **GUI Chat Integration (6-8h)**: Wire the `AgentChatWidget` into the main YAZE editor.
|
||||
3. **Expand Tool Coverage (8-10h)**: Add new read-only tools for inspecting dialogue, sprites, and regions.
|
||||
4. **Windows Cross-Platform Testing (8-10h)**: Validate `z3ed` and the test harness on Windows.
|
||||
|
||||
# Dump sprite placements for a dungeon room
|
||||
z3ed agent dungeon-list-sprites --room 0x012
|
||||
## 9. Troubleshooting
|
||||
|
||||
# Search overworld maps for a tile ID using shared agent tooling
|
||||
z3ed agent overworld-find-tile --tile 0x02E --map 0x05
|
||||
```
|
||||
|
||||
### GUI Testing Commands
|
||||
|
||||
```bash
|
||||
# Run automated test
|
||||
z3ed agent test --prompt "Open Overworld editor and verify it loads"
|
||||
|
||||
# Query test status
|
||||
z3ed agent test status --test-id <id> --follow
|
||||
|
||||
# Record manual workflow
|
||||
z3ed agent test record start --output tests/my_test.json
|
||||
# ... perform actions in GUI ...
|
||||
z3ed agent test record stop
|
||||
|
||||
# Replay recorded test
|
||||
z3ed agent test replay tests/my_test.json
|
||||
|
||||
# Test conversational agent (batch mode, no TUI required)
|
||||
z3ed agent test-conversation
|
||||
|
||||
# Test with custom conversation file
|
||||
z3ed agent test-conversation --file my_tests.json
|
||||
```
|
||||
|
||||
## AI Service Setup
|
||||
|
||||
### Ollama (Local LLM - Recommended for Development)
|
||||
|
||||
```bash
|
||||
# Install Ollama
|
||||
brew install ollama # macOS
|
||||
# or download from https://ollama.com
|
||||
|
||||
# Pull recommended model
|
||||
ollama pull qwen2.5-coder:7b
|
||||
|
||||
# Start server
|
||||
ollama serve
|
||||
|
||||
# z3ed will auto-detect Ollama at localhost:11434
|
||||
z3ed agent plan --prompt "test"
|
||||
```
|
||||
|
||||
### Gemini (Google Cloud API)
|
||||
|
||||
```bash
|
||||
# Get API key from https://aistudio.google.com/apikey
|
||||
export GEMINI_API_KEY="your-key-here"
|
||||
|
||||
# z3ed will auto-select Gemini when key is set
|
||||
z3ed agent plan --prompt "test"
|
||||
```
|
||||
|
||||
**Note**: Gemini requires OpenSSL (HTTPS). Build with `-DYAZE_WITH_GRPC=ON -DYAZE_WITH_JSON=ON` to enable SSL support. OpenSSL is auto-detected on macOS/Linux. Windows users can use Ollama instead.
|
||||
|
||||
### Example Prompts
|
||||
Here are some example prompts you can try with either Ollama or Gemini:
|
||||
|
||||
**Overworld Tile16 Editing**:
|
||||
- `"Place a tree at position 10, 20 on map 0"`
|
||||
- `"Create a 3x3 water pond at coordinates 15, 10"`
|
||||
- `"Add a dirt path from position 5,5 to 5,15"`
|
||||
- `"Plant a row of trees horizontally at y=8 from x=20 to x=25"`
|
||||
|
||||
**Dungeon Editing (Label-Aware)**:
|
||||
- `"Add 3 soldiers to the Eastern Palace entrance room"`
|
||||
- `"Place a chest in Hyrule Castle treasure room"`
|
||||
|
||||
## Core Documentation
|
||||
|
||||
## Current Status (October 3, 2025)
|
||||
|
||||
### ✅ Production Ready
|
||||
- **Build System**: ✅ Z3ED_AI flag consolidation complete
|
||||
- Single flag for all AI features
|
||||
- Graceful degradation when dependencies missing
|
||||
- Clear error messages and build status
|
||||
- Backward compatible with old flags
|
||||
- **AI Backends**: ✅ Both Ollama and Gemini operational
|
||||
- Auto-detection based on environment
|
||||
- Health checks and error handling
|
||||
- Tested with real API calls
|
||||
- **Conversational Agent**: ✅ Multi-step tool execution loop
|
||||
- Chat history management
|
||||
- Tool result replay without recursion
|
||||
- JSON/table rendering in TUI
|
||||
- **Tool Dispatcher**: ✅ 5 read-only tools operational
|
||||
- Resource listing, sprite inspection, tile search
|
||||
- Map descriptions, warp enumeration
|
||||
- Machine-readable JSON output
|
||||
|
||||
### <20> In Progress (Priority Order)
|
||||
1. **Live LLM Testing** (1-2h): Verify function calling with real models
|
||||
2. **GUI Chat Widget** (6-8h): ImGui integration (TUI exists as reference)
|
||||
3. **Tool Coverage Expansion** (8-10h): Dialogue, sprites, regions
|
||||
|
||||
## AI Editing Focus Areas
|
||||
|
||||
z3ed is optimized for practical ROM editing workflows:
|
||||
|
||||
### Overworld Tile16 Editing ⭐ PRIMARY FOCUS
|
||||
**Why**: Simple data model (uint16 IDs), visual feedback, reversible, safe
|
||||
- Single tile placement (trees, rocks, bushes)
|
||||
- Area creation (water ponds, dirt patches)
|
||||
- Path creation (connecting points with tiles)
|
||||
- Pattern generation (tree rows, forests, boundaries)
|
||||
|
||||
### Dungeon Editing
|
||||
- Sprite placement with label awareness ("eastern palace entrance")
|
||||
- Object placement (chests, doors, switches)
|
||||
- Entrance configuration
|
||||
- Room property editing
|
||||
|
||||
### Palette Editing
|
||||
- Color modification by index
|
||||
- Sprite palette adjustments
|
||||
- Export/import workflows
|
||||
|
||||
### Additional Capabilities
|
||||
- Sprite data editing
|
||||
- Compression/decompression
|
||||
- ROM validation
|
||||
- Patch application
|
||||
|
||||
## Example Workflows
|
||||
|
||||
### Basic Tile16 Edit
|
||||
```bash
|
||||
# AI generates command
|
||||
z3ed agent plan --prompt "Place a tree at 10, 10"
|
||||
# Output: overworld set-tile --map 0 --x 10 --y 10 --tile 0x02E
|
||||
|
||||
# Execute manually
|
||||
z3ed overworld set-tile --map 0 --x 10 --y 10 --tile 0x02E
|
||||
|
||||
# Or auto-execute with sandbox
|
||||
z3ed agent run --prompt "Place a tree at 10, 10" --rom zelda3.sfc --sandbox
|
||||
```
|
||||
|
||||
### Complex Multi-Step Edit
|
||||
```bash
|
||||
# AI generates multiple commands
|
||||
z3ed agent plan --prompt "Create a 3x3 water pond at 15, 20"
|
||||
|
||||
# Review proposal
|
||||
z3ed agent diff --latest
|
||||
|
||||
# Accept and apply
|
||||
z3ed agent accept --latest
|
||||
```
|
||||
|
||||
### Locate Existing Tiles
|
||||
```bash
|
||||
# Find every instance of tile 0x02E across the overworld
|
||||
z3ed overworld find-tile --tile 0x02E --format json
|
||||
|
||||
# Narrow search to Light World map 0x05
|
||||
z3ed overworld find-tile --tile 0x02E --map 0x05
|
||||
|
||||
# Ask the agent to perform the same lookup (returns JSON by default)
|
||||
z3ed agent overworld-find-tile --tile 0x02E --map 0x05
|
||||
```
|
||||
|
||||
### Label-Aware Dungeon Edit
|
||||
```bash
|
||||
# AI uses ResourceLabels from your project
|
||||
z3ed agent plan --prompt "Add 3 soldiers to my custom fortress entrance"
|
||||
# AI explains: "Using label 'custom_fortress' for dungeon 0x04"
|
||||
```
|
||||
|
||||
## Dependencies Guard
|
||||
|
||||
AI agent features require:
|
||||
- `YAZE_WITH_GRPC=ON` - GUI automation and test harness
|
||||
- `YAZE_WITH_JSON=ON` - AI service communication
|
||||
- OpenSSL (optional) - Gemini HTTPS support (auto-detected)
|
||||
|
||||
**Windows Compatibility**: Build without gRPC/JSON for basic z3ed functionality. Use Ollama (localhost) instead of Gemini for AI features without SSL dependency.
|
||||
|
||||
## Recent Changes (Oct 3, 2025)
|
||||
|
||||
### Z3ED_AI Build Flag (Major Improvement)
|
||||
- ✅ **Consolidated Build Flags**: New `-DZ3ED_AI=ON` replaces multiple flags
|
||||
- Old: `-DYAZE_WITH_GRPC=ON -DYAZE_WITH_JSON=ON`
|
||||
- New: `-DZ3ED_AI=ON` (simpler, clearer intent)
|
||||
- ✅ **Fixed Gemini Crash**: Graceful degradation when dependencies missing
|
||||
- ✅ **Better Error Messages**: Clear guidance on missing dependencies
|
||||
- ✅ **Production Ready**: Both backends tested and operational
|
||||
|
||||
### Build System
|
||||
- ✅ Auto-manages dependencies (JSON, YAML, httplib, OpenSSL)
|
||||
- ✅ Backward compatible with old flags
|
||||
- ✅ Ready for build modularization (optional `libyaze_agent.a`)
|
||||
|
||||
### Documentation
|
||||
- ✅ Updated build instructions with Z3ED_AI flag
|
||||
- ✅ Added migration guide: [Z3ED_AI_FLAG_MIGRATION.md](Z3ED_AI_FLAG_MIGRATION.md)
|
||||
- ✅ Clear troubleshooting section with common issues
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Build with -DZ3ED_AI=ON" warning
|
||||
**Impact**: AI agent features disabled (no Ollama or Gemini)
|
||||
**Solution**: Rebuild with AI support:
|
||||
```bash
|
||||
cmake -B build -DZ3ED_AI=ON
|
||||
cmake --build build --target z3ed
|
||||
```
|
||||
|
||||
### "gRPC not available" error
|
||||
**Impact**: GUI testing and automation disabled
|
||||
**Solution**: Rebuild with `-DYAZE_WITH_GRPC=ON` (also requires Z3ED_AI)
|
||||
|
||||
### AI generates invalid commands
|
||||
**Causes**: Vague prompt, unfamiliar tile IDs, missing context
|
||||
**Solutions**:
|
||||
- Use specific coordinates and tile types
|
||||
- Reference tile16 IDs from documentation
|
||||
- Provide map context ("Light World", "map 0")
|
||||
- Check ResourceLabels are loaded for your project
|
||||
|
||||
### Testing the conversational agent
|
||||
**Problem**: TUI chat requires interactive input
|
||||
**Solution**: Use the new batch testing mode:
|
||||
```bash
|
||||
# Run with default test cases (no interaction required)
|
||||
z3ed agent test-conversation --rom zelda3.sfc
|
||||
|
||||
# Or use the automated test script
|
||||
./scripts/test_agent_conversation_live.sh
|
||||
```
|
||||
|
||||
### Verifying ImGui test harness
|
||||
**Problem**: Unsure if GUI automation is working
|
||||
**Solution**: Run the verification script:
|
||||
```bash
|
||||
./scripts/test_imgui_harness.sh
|
||||
```
|
||||
|
||||
#### Gemini-Specific Issues
|
||||
- **"Cannot reach Gemini API"**: Check your internet connection, API key, and that you've built with SSL support.
|
||||
- **"Invalid Gemini API key"**: Regenerate your key at `aistudio.google.com/apikey`.
|
||||
- **"Build with -DZ3ED_AI=ON" warning**: AI features are disabled. Rebuild with the flag to enable them.
|
||||
- **"gRPC not available" error**: GUI testing is disabled. Rebuild with `-DYAZE_WITH_GRPC=ON`.
|
||||
- **AI generates invalid commands**: The prompt may be vague. Use specific coordinates, tile IDs, and map context.
|
||||
- **Chat mode freezes**: Use `agent simple-chat` instead of the FTXUI-based `agent chat` for better stability, especially in scripts.
|
||||
@@ -1,182 +0,0 @@
|
||||
# z3ed Developer Guide
|
||||
|
||||
**Version**: 0.1.0-alpha
|
||||
**Last Updated**: October 4, 2025
|
||||
|
||||
## 1. Overview
|
||||
|
||||
This document is the **source of truth** for the z3ed CLI architecture, design, and roadmap. It outlines the evolution of `z3ed` into a powerful, scriptable, and extensible tool for both manual and AI-driven ROM hacking.
|
||||
|
||||
`z3ed` has successfully implemented its core infrastructure and is **production-ready on macOS**.
|
||||
|
||||
### Core Capabilities
|
||||
|
||||
1. **Conversational Agent**: Chat with an AI (Ollama or Gemini) to explore ROM contents and plan changes using natural language.
|
||||
2. **GUI Test Automation**: A gRPC-based test harness allows for widget discovery, test recording/replay, and introspection for debugging and AI-driven validation.
|
||||
3. **Proposal System**: A safe, sandboxed editing workflow where all changes are tracked as "proposals" that require human review and acceptance.
|
||||
4. **Resource-Oriented CLI**: A clean `z3ed <resource> <action>` command structure that is both human-readable and machine-parsable.
|
||||
|
||||
## 2. Architecture
|
||||
|
||||
The z3ed system is composed of several layers, from the high-level AI agent down to the YAZE GUI and test harness.
|
||||
|
||||
### System Components Diagram
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ AI Agent Layer (LLM: Ollama, Gemini) │
|
||||
└────────────────────┬────────────────────────────────────┘
|
||||
│
|
||||
┌────────────────────▼────────────────────────────────────┐
|
||||
│ z3ed CLI (Command-Line Interface) │
|
||||
│ ├─ agent run/plan/diff/test/list/describe │
|
||||
│ └─ rom/palette/overworld/dungeon commands │
|
||||
└────────────────────┬────────────────────────────────────┘
|
||||
│
|
||||
┌────────────────────▼────────────────────────────────────┐
|
||||
│ Service Layer (Singleton Services) │
|
||||
│ ├─ ProposalRegistry (Proposal Tracking) │
|
||||
│ ├─ RomSandboxManager (Isolated ROM Copies) │
|
||||
│ ├─ ResourceCatalog (Machine-Readable API Specs) │
|
||||
│ └─ ConversationalAgentService (Chat & Tool Dispatch) │
|
||||
└────────────────────┬────────────────────────────────────┘
|
||||
│
|
||||
┌────────────────────▼────────────────────────────────────┐
|
||||
│ ImGuiTestHarness (gRPC Server in YAZE) │
|
||||
│ ├─ Ping, Click, Type, Wait, Assert, Screenshot │
|
||||
│ └─ Introspection & Discovery RPCs │
|
||||
└────────────────────┬────────────────────────────────────┘
|
||||
│
|
||||
┌────────────────────▼────────────────────────────────────┐
|
||||
│ YAZE GUI (ImGui Application) │
|
||||
│ └─ ProposalDrawer & Editor Windows │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Key Architectural Decisions
|
||||
|
||||
- **Resource-Oriented Command Structure**: `z3ed <resource> <action>` for clarity and extensibility.
|
||||
- **Machine-Readable API**: All commands are documented in `docs/api/z3ed-resources.yaml` with structured schemas for AI consumption.
|
||||
- **Proposal-Based Workflow**: AI-generated changes are sandboxed as "proposals" requiring human review.
|
||||
- **gRPC Test Harness**: An embedded gRPC server in YAZE enables remote GUI automation.
|
||||
|
||||
## 3. Command Reference
|
||||
|
||||
This section provides a reference for the core `z3ed` commands.
|
||||
|
||||
### Agent Commands
|
||||
|
||||
- `agent run --prompt "..."`: Executes an AI-driven ROM modification in a sandbox.
|
||||
- `agent plan --prompt "..."`: Shows the sequence of commands the AI plans to execute.
|
||||
- `agent list`: Shows all proposals and their status.
|
||||
- `agent diff [--proposal-id <id>]`: Shows the changes, logs, and metadata for a proposal.
|
||||
- `agent describe [--resource <name>]`: Exports machine-readable API specifications for AI consumption.
|
||||
- `agent chat`: Opens an interactive terminal chat (TUI) with the AI agent.
|
||||
- `agent simple-chat`: A lightweight, non-TUI chat mode for scripting and automation.
|
||||
- `agent test ...`: Commands for running and managing automated GUI tests.
|
||||
|
||||
### Resource Commands
|
||||
|
||||
- `rom info|validate|diff`: Commands for ROM file inspection and comparison.
|
||||
- `palette export|import|list`: Commands for palette manipulation.
|
||||
- `overworld get-tile|find-tile|set-tile`: Commands for overworld editing.
|
||||
- `dungeon list-sprites|list-rooms`: Commands for dungeon inspection.
|
||||
|
||||
## 4. Agentic & Generative Workflow (MCP)
|
||||
|
||||
The `z3ed` CLI is the foundation for an AI-driven Model-Code-Program (MCP) loop, where the AI agent's "program" is a script of `z3ed` commands.
|
||||
|
||||
1. **Model (Planner)**: The agent receives a natural language prompt and leverages an LLM to create a plan, which is a sequence of `z3ed` commands.
|
||||
2. **Code (Generation)**: The LLM returns the plan as a structured JSON object containing actions.
|
||||
3. **Program (Execution)**: The `z3ed agent` parses the plan and executes each command sequentially in a sandboxed ROM environment.
|
||||
4. **Verification (Tester)**: The `ImGuiTestHarness` is used to run automated GUI tests to verify that the changes were applied correctly.
|
||||
|
||||
## 5. Roadmap & Implementation Status
|
||||
|
||||
**Last Updated**: October 4, 2025
|
||||
|
||||
### ✅ Completed
|
||||
|
||||
- **Core Infrastructure**: Resource-oriented CLI, proposal workflow, sandbox manager, and resource catalog are all production-ready.
|
||||
- **AI Backends**: Both Ollama (local) and Gemini (cloud) are operational.
|
||||
- **Conversational Agent**: The agent service, tool dispatcher (with 5 read-only tools), and TUI/simple chat interfaces are complete.
|
||||
- **GUI Test Harness (IT-01 to IT-09)**: A comprehensive GUI testing platform with introspection, widget discovery, recording/replay, enhanced error reporting, and CI integration support.
|
||||
|
||||
### 🚧 Active & Next Steps
|
||||
|
||||
1. **Live LLM Testing (1-2h)**: Verify function calling with real models (Ollama/Gemini).
|
||||
2. **GUI Chat Integration (6-8h)**: Wire the `AgentChatWidget` into the main YAZE editor.
|
||||
3. **Expand Tool Coverage (8-10h)**: Add new read-only tools for inspecting dialogue, sprites, and regions.
|
||||
4. **Windows Cross-Platform Testing (8-10h)**: Validate `z3ed` and the test harness on Windows.
|
||||
|
||||
## 6. Technical Implementation Details
|
||||
|
||||
### Build System
|
||||
|
||||
A single `Z3ED_AI=ON` CMake flag enables all AI features, including JSON, YAML, and httplib dependencies. This simplifies the build process and is designed for the upcoming build modularization.
|
||||
|
||||
**Build Command (with AI features):**
|
||||
```bash
|
||||
cmake -B build -DZ3ED_AI=ON
|
||||
cmake --build build --target z3ed
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. AI Provider Configuration
|
||||
|
||||
Z3ED supports multiple AI providers for conversational agent features. You can configure the AI service using command-line flags, making it easy to switch between providers without modifying environment variables.
|
||||
|
||||
### Supported Providers
|
||||
|
||||
- **Mock (Default)**: For testing and development. Returns placeholder responses. Use `--ai_provider=mock`.
|
||||
- **Ollama (Local)**: For local LLM inference. Requires an Ollama server and a downloaded model. Use `--ai_provider=ollama`.
|
||||
- **Gemini (Cloud)**: Google's cloud-based AI. Requires a Gemini API key. Use `--ai_provider=gemini`.
|
||||
|
||||
### Core Flags
|
||||
|
||||
- `--ai_provider=<provider>`: Selects the AI provider (`mock`, `ollama`, `gemini`).
|
||||
- `--ai_model=<model>`: Specifies the model name (e.g., `qwen2.5-coder:7b`, `gemini-1.5-flash`).
|
||||
- `--gemini_api_key=<key>`: Your Gemini API key.
|
||||
- `--ollama_host=<url>`: The URL for your Ollama server (default: `http://localhost:11434`).
|
||||
|
||||
Configuration is resolved with flags taking precedence over environment variables, which take precedence over defaults.
|
||||
|
||||
---
|
||||
|
||||
## 8. Agent Chat Input Methods
|
||||
|
||||
The `z3ed agent simple-chat` command supports multiple input methods for flexibility.
|
||||
|
||||
1. **Single Message Mode**: `z3ed agent simple-chat "<message>" --rom=<path>`
|
||||
* **Use Case**: Quick, one-off scripted queries.
|
||||
|
||||
2. **Interactive Mode**: `z3ed agent simple-chat --rom=<path>`
|
||||
* **Use Case**: Multi-turn conversations and interactive exploration.
|
||||
* **Commands**: `quit`, `exit`, `reset`.
|
||||
|
||||
3. **Piped Input Mode**: `echo "<message>" | z3ed agent simple-chat --rom=<path>`
|
||||
* **Use Case**: Integrating with shell scripts and Unix pipelines.
|
||||
|
||||
4. **Batch File Mode**: `z3ed agent simple-chat --file=<input.txt> --rom=<path>`
|
||||
* **Use Case**: Running documented test suites and performing repeatable validation.
|
||||
|
||||
---
|
||||
|
||||
## 9. Test Harness (gRPC)
|
||||
|
||||
The test harness is a gRPC server embedded in the YAZE application, enabling remote control for automated testing. It exposes RPCs for actions like `Click`, `Type`, and `Wait`, as well as advanced introspection and test management.
|
||||
|
||||
**Start Test Harness:**
|
||||
```bash
|
||||
./build-grpc-test/bin/yaze.app/Contents/MacOS/yaze \
|
||||
--enable_test_harness \
|
||||
--test_harness_port=50052 \
|
||||
--rom_file=assets/zelda3.sfc &
|
||||
```
|
||||
|
||||
**Key RPCs:**
|
||||
- **Automation**: `Ping`, `Click`, `Type`, `Wait`, `Assert`, `Screenshot`
|
||||
- **Introspection**: `GetTestStatus`, `ListTests`, `GetTestResults`
|
||||
- **Discovery**: `DiscoverWidgets`
|
||||
- **Recording**: `StartRecording`, `StopRecording`, `ReplayTest`
|
||||
Reference in New Issue
Block a user