build fixes and api evolution

Guide for build fixes and api evolution

Build Fixes and API Evolution

Overview

This document captures the evolution of the interaction bridge pattern and related systems, including breaking changes that required fixes during game launch attempts.

Breaking Changes Fixed (January 2026)

1. EatFoodEvent Structure Change

Old Structure (documented in interaction_bridge_pattern.md):
EatFoodEvent {
    entity: event.entity,
    item_id: event.item,
}
New Structure (current):
EatFoodEvent {
    player: event.entity,
    food_item: event.item,
}
Location: src/systems/skills/cooking.rs (lines 73-76)
Impact: Direct field name changes require updating all event construction sites.

2. Consumable Item Detection

Old Approach:
// Check item definition for consumable field
else if item_def.consumable.is_some() {
    eat_events.send(EatFoodEvent { ... });
}
New Approach:
// Check SkillsData for food items registry
else if skills_data.food_items.contains_key(&event.item.0) {
    eat_events.send(EatFoodEvent { ... });
}
Rationale:
  • ItemDefinition struct removed the consumable field
  • Food items are now centrally managed in SkillsData.food_items HashMap
  • More data-driven: food properties (heal amount) stored separately from item definitions
Required Changes:
  1. Add skills_data: Res<SkillsData> to handle_use_item_events system parameters
  2. Import SkillsData from crate::systems::data
  3. Replace consumable check with food_items lookup

3. Equipment Type Location

Issue: Equipment component moved from equipment module to inventory module.
Old Import:
use crate::systems::player::equipment::Equipment;
New Import:
use crate::systems::player::inventory::Equipment;
Location: src/systems/player/inventory.rs (lines 37-51)
Impact: All queries and imports referencing Equipment needed updating.

4. UI System Parameter Updates

Issue: render_inventory_tab function signature expanded to support equipment interaction.
Old Signature:
pub fn render_inventory_tab(
    ui: &mut egui::Ui,
    player_entity: Entity,
    inventory_query: &Query<&Inventory>,
    use_events: &mut EventWriter<UseItemEvent>,
)
New Signature:
pub fn render_inventory_tab(
    ui: &mut egui::Ui,
    player_entity: Entity,
    inventory_query: &Query<&Inventory>,
    equipment_query: &Query<&Equipment>,
    use_events: &mut EventWriter<UseItemEvent>,
    unequip_events: &mut EventWriter<UnequipItemEvent>,
)
Required UI System Changes (src/systems/ui/mod.rs):
  1. Add equipment_q to UiParams struct
  2. Add unequip_writer to ui_main_layout system parameters
  3. Pass both to render_inventory_tab call
  4. Make render_slot closure mutable to allow event sending

Updated Interaction Bridge Pattern

Current Implementation

File: src/systems/player/interactions.rs
use bevy::prelude::*;
use crate::systems::data::GameData;
use crate::systems::data::SkillsData; // [NEW]
use crate::systems::player::inventory::{UseItemEvent, ItemId};
use crate::systems::player::equipment::EquipItemEvent;
use crate::systems::skills::cooking::EatFoodEvent;

pub struct InteractionPlugin;

impl Plugin for InteractionPlugin {
    fn build(&self, app: &mut App) {
        app.add_systems(Update, handle_use_item_events);
    }
}

pub fn handle_use_item_events(
    mut use_events: EventReader<UseItemEvent>,
    mut equip_events: EventWriter<EquipItemEvent>,
    mut eat_events: EventWriter<EatFoodEvent>,
    game_data: Res<GameData>,
    skills_data: Res<SkillsData>, // [NEW]
) {
    for event in use_events.read() {
        if let Some(item_def) = game_data.items.get(&event.item.0) {
            // Check if equippable
            if item_def.equip_slot.is_some() {
                equip_events.send(EquipItemEvent {
                    entity: event.entity,
                    item_id: event.item,
                });
                info!("Requesting equip for {}", item_def.name);
            } 
            // Check if edible (using SkillsData for verification)
            else if skills_data.food_items.contains_key(&event.item.0) {
                 eat_events.send(EatFoodEvent {
                     player: event.entity,      // [CHANGED] was: entity
                     food_item: event.item,     // [CHANGED] was: item_id
                 });
                 info!("Requesting consumption for {}", item_def.name);
            }
            else {
                info!("Used {} (No action defined)", item_def.name);
            }
        }
    }
}

Architecture Insights

Data-Driven Design Evolution

The codebase demonstrates a clear evolution toward more data-driven architecture:
  1. Separation of Concerns: Item metadata (GameData.items) vs. skill-specific data (SkillsData.food_items)
  2. Centralized Resources: SkillsData consolidates fishing spots, cooking recipes, food items, smelting recipes, smithing recipes, seeds, and magic spells
  3. String-to-ID Hashing: Consistent use of string_to_id() for data-driven item references

Resource Dependencies

Systems now commonly depend on multiple data resources:
  • GameData: Core item/NPC/loot definitions
  • SkillsData: Skill-specific recipes and configurations
  • Both loaded at startup via DataPlugin

Debugging Patterns

Common Build Error Categories

  1. Event Structure Mismatches: Field renames require careful tracking
  2. Module Reorganization: Component moves between modules break imports
  3. Function Signature Evolution: Parameter additions require call site updates
  4. Closure Mutability: Rust's borrow checker requires mut for closures that send events

Verification Strategy

  1. Fix compilation errors in dependency order (data structures → systems → UI)
  2. Check event definitions in their source modules before constructing
  3. Verify component locations using grep_search or IDE navigation
  4. Test incrementally with cargo check before full cargo run

References

  • Conversation: 98916264-d3c6-415d-9626-69d448f17901
  • Files Modified:
    • src/systems/player/interactions.rs
    • src/systems/ui/mod.rs
    • src/systems/ui/inventory_ui.rs
    • src/systems/data/editor_ui.rs