6.0 KiB
Overworld Entity System
This document provides a technical overview of the overworld entity system, including critical bug fixes that enable its functionality and the ongoing plan to refactor it for modularity and ZScream feature parity.
1. System Overview
The overworld entity system manages all interactive objects on the overworld map, such as entrances, exits, items, and sprites. The system is undergoing a refactor to move from a monolithic architecture within the Overworld class to a modular design where each entity's save/load logic is handled in dedicated files.
Key Goals of the Refactor:
- Modularity: Isolate entity logic into testable, self-contained units.
- ZScream Parity: Achieve feature compatibility with ZScream's entity management, including support for expanded ROM formats.
- Maintainability: Simplify the
Overworldclass by delegating I/O responsibilities.
2. Core Components & Bug Fixes
Several critical bugs were fixed to make the entity system functional. Understanding these fixes is key to understanding the system's design.
2.1. Entity Interaction and Hover Detection
File: src/app/editor/overworld/overworld_entity_renderer.cc
- Problem: Exit entities were not responding to mouse interactions because the hover state was being improperly reset.
- Fix: The hover state (
hovered_entity_) is now reset only once at the beginning of the entity rendering cycle, specifically inDrawExits(), which is the first rendering function called. Subsequent functions (DrawEntrances(),DrawItems(), etc.) can set the hover state without it being cleared, preserving the correct hover priority (last-drawn entity wins).
// In DrawExits(), which is called first:
hovered_entity_ = nullptr; // Reset hover state at the start of the cycle.
// In DrawEntrances() and other subsequent renderers:
// The reset is removed to allow hover state to persist.
2.2. Entity Property Popup Save/Cancel Logic
File: src/app/editor/overworld/entity.cc
- Problem: The "Done" and "Cancel" buttons in entity property popups had inverted logic, causing changes to be saved on "Cancel" and discarded on "Done".
- Fix: The
set_doneflag, which controls the popup's return value, is now correctly managed. The "Done" and "Delete" buttons setset_done = trueto signal a save action, while the "Cancel" button does not, correctly discarding changes.
// Corrected logic for the "Done" button in popups
if (ImGui::Button(ICON_MD_DONE)) {
set_done = true; // Save changes
ImGui::CloseCurrentPopup();
}
// Corrected logic for the "Cancel" button
if (ImGui::Button(ICON_MD_CANCEL)) {
// Discard changes (do not set set_done)
ImGui::CloseCurrentPopup();
}
2.3. Exit Entity Coordinate System
File: src/zelda3/overworld/overworld_exit.h
- Problem: Saving a vanilla ROM would corrupt exit positions, causing them to load at (0,0). This was because the
OverworldExitclass useduint8_tfor player coordinates, truncating 16-bit values. - Fix: The coordinate-related members of
OverworldExitwere changed touint16_tto match the full 0-4088 coordinate range, achieving parity with ZScream's data structures.
// In OverworldExit class definition:
class OverworldExit : public GameEntity {
public:
// ...
uint16_t y_player_; // Changed from uint8_t
uint16_t x_player_; // Changed from uint8_t
uint16_t y_camera_; // Changed from uint8_t
uint16_t x_camera_; // Changed from uint8_t
// ...
};
2.4. Coordinate Synchronization on Drag
File: src/zelda3/overworld/overworld_exit.h
- Problem: When dragging an exit, the visual position (
x_,y_) would update, but the underlying data used for saving (x_player_,y_player_) would not, leading to a data desync and incorrect saves. - Fix: The
UpdateMapPropertiesmethod now explicitly syncs the base entity coordinates to the player coordinates before recalculating scroll and camera values. This ensures that drag operations correctly persist.
// In OverworldExit::UpdateMapProperties()
void UpdateMapProperties(uint16_t map_id) override {
// Sync player position from the base entity coordinates updated by the drag system.
x_player_ = static_cast<uint16_t>(x_);
y_player_ = static_cast<uint16_t>(y_);
// Proceed with auto-calculation using the now-correct player coordinates.
// ...
}
3. Entity I/O Refactoring Plan
The next phase of development is to extract all entity save and load logic from the monolithic overworld.cc into dedicated files.
3.1. File Structure
New files will be created to handle I/O for each entity type:
src/zelda3/overworld/overworld_entrance.ccsrc/zelda3/overworld/overworld_exit.ccsrc/zelda3/overworld/overworld_item.ccsrc/zelda3/overworld/overworld_transport.cc(for new transport/whirlpool support)
3.2. Core Functions
Each new file will implement a standard set of flat functions:
LoadAll...(): Reads all entities of a given type from the ROM.SaveAll...(): Writes all entities of a given type to the ROM.- Helper functions for coordinate calculation and data manipulation, mirroring ZScream's logic.
3.3. ZScream Parity Goals
The refactor aims to implement key ZScream features:
- Expanded ROM Support: Correctly read/write from vanilla or expanded ROM addresses for entrances and items.
- Pointer Deduplication: When saving items, reuse pointers for identical item lists on different maps to conserve space.
- Automatic Coordinate Calculation: For exits and transports, automatically calculate camera and scroll values based on player position, matching the
UpdateMapStufflogic in ZScream. - Transport Entity: Add full support for transport entities (whirlpools, birds).
3.4. Overworld Class Role
After the refactor, the Overworld class will act as a coordinator, delegating all entity I/O to the new, modular functions. Its responsibility will be to hold the entity vectors and orchestrate the calls to the LoadAll... and SaveAll... functions.