resolution example

Guide for resolution example

Complete Resolution Example: SelectSpellEvent Type Mismatch

Overview

This document provides a complete, real-world example of resolving the duplicate SelectSpellEvent compilation error and related issues. It demonstrates the systematic debugging workflow that successfully fixed all compilation errors in the magic system.

Initial Error Report

error[E0308]: mismatched types
  --> src/systems/ui/mod.rs:402:46
   |
395 |                   spell_book_ui::render_magic_tab(
    |                   ------------------------------- arguments to this function are incorrect
...
402 |                       &mut select_spell_writer,
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^ expected `systems::magic::SelectSpellEvent`, 
    |                                                    found `systems::skills::magic::SelectSpellEvent`
Additional errors:
  • Unused import ItemId in interactions.rs
  • Unnecessary parentheses in ui/mod.rs system registration
  • Missing spell_db argument in render_magic_tab call
  • Corrupted ui_main_layout function signature

Resolution Steps

Step 1: Identify Root Cause

Analysis: Two SelectSpellEvent structs exist in different modules:
  • src/systems/magic/mod.rs (line 64) - NEW magic system
  • src/systems/skills/magic.rs (line 83) - OLD skill-based magic
Decision: Use systems::magic::SelectSpellEvent as the canonical version since it's part of the new dedicated magic module.

Step 2: Fix Type Mismatch in UI

File: src/systems/ui/mod.rs
Change (line 245):
// Before
mut select_spell_writer: EventWriter<crate::systems::skills::magic::SelectSpellEvent>,

// After
mut select_spell_writer: EventWriter<crate::systems::magic::SelectSpellEvent>,
Rationale: UI should use the new magic system's event type.

Step 3: Implement Missing Event Handler

Problem: The new systems::magic module defined SelectSpellEvent but didn't have a handler for it.
File: src/systems/magic/cast_system.rs
Added imports (line 2):
use crate::systems::magic::{
    SpellDatabase, CastSpellEvent, SpawnProjectileEvent, MantrasJson, 
    ActiveSpell, SelectSpellEvent  // Added these two
};
Added handler (appended to end of file):
pub fn handle_spell_selection(
    mut commands: Commands,
    mut events: EventReader<SelectSpellEvent>,
) {
    for event in events.read() {
        if let Some(spell_id) = &event.spell_id {
            commands.entity(event.caster).insert(ActiveSpell {
                spell_id: spell_id.clone(),
                autocast: true, 
                last_cast_time: 0.0,
            });
            info!("Selected spell: {}", spell_id);
        } else {
            commands.entity(event.caster).remove::<ActiveSpell>();
            info!("Cleared active spell");
        }
    }
}

Step 4: Register New System

File: src/systems/magic/mod.rs
Change (line 105-106):
// Before
            .add_systems(Update, (
                cast_system::cast_spell_system,
                projectile::magic_projectile_movement,
                projectile::projectile_collision,
            ));

// After
            .add_systems(Update, (
                cast_system::cast_spell_system,
                projectile::magic_projectile_movement,
                projectile::projectile_collision,
                cast_system::handle_spell_selection,  // Added
            ));

Step 5: Fix Lint Warnings

File: src/systems/ui/mod.rs
Change (line 84):
// Before
.add_systems(Update, (ui_main_layout))

// After
.add_systems(Update, ui_main_layout)
File: src/systems/player/interactions.rs
Change (line 4):
// Before
use crate::systems::player::inventory::{UseItemEvent, ItemId};

// After
use crate::systems::player::inventory::{UseItemEvent};

Step 6: Restore Corrupted Code

Problem: During editing, ui_main_layout function signature was corrupted.
File: src/systems/ui/mod.rs
Restored UiParams struct (line 223):
pub struct UiParams<'w, 's> {
    pub ui_assets: Res<'w, UiAssets>,
    pub interactables: Query<'w, 's, &'static crate::systems::api::Interactable>,
    pub player_q: Query<'w, 's, (Entity, &'static crate::systems::player::skills::Skills, Option<&'static crate::systems::skills::magic::ActiveSpell>), With<crate::systems::player::Player>>,
    pub skills_q: Query<'w, 's, &'static crate::systems::player::skills::Skills>,
    pub inventory_q: Query<'w, 's, &'static crate::systems::player::inventory::Inventory>,
    pub equipment_q: Query<'w, 's, &'static crate::systems::player::inventory::Equipment>,
    pub skills_data: Res<'w, crate::systems::data::SkillsData>,
    pub spell_db: Res<'w, crate::systems::magic::SpellDatabase>,  // Added missing field
}
Restored function signature (lines 238-247):
fn ui_main_layout(
    mut contexts: EguiContexts,
    mut ui_state: ResMut<UiState>,
    mut combat_style_writer: EventWriter<CombatStyleEvent>,
    editor_state: Option<Res<crate::systems::editor::EditorState>>,
    mut last_interaction: Local<String>,
    mut interaction_reader: EventReader<InteractionEvent>,
    
    params: UiParams,
    
    mut plugin_ui_state: ResMut<PluginUiState>,
    mut use_item_writer: EventWriter<crate::systems::player::inventory::UseItemEvent>,
    mut unequip_writer: EventWriter<crate::systems::player::equipment::UnequipItemEvent>,

    // Magic UI params
    mut spell_book_state: ResMut<spell_book_ui::SpellBookState>,
    mut select_spell_writer: EventWriter<crate::systems::magic::SelectSpellEvent>,
    mut cast_spell_writer: EventWriter<crate::systems::magic::CastSpellEvent>,
    mut coconut_ui_state: ResMut<coconut_stacking_ui::CoconutUIState>,
) {
    let ui_assets = params.ui_assets;
    let interactables = params.interactables;
    let player_q = params.player_q;
    let skills_q = params.skills_q;
    let inventory_q = params.inventory_q;
    let equipment_q = params.equipment_q;
    let skills_data = params.skills_data;
    // ... rest of function

Step 7: Add Missing Argument

File: src/systems/ui/mod.rs
Change (lines 394-405):
// Before
spell_book_ui::render_magic_tab(
    ui,
    &mut spell_book_state,
    &skills_data,
    player_entity,
    skills,
    active_spell,
    &mut select_spell_writer,
    &mut cast_spell_writer,
    &mut coconut_ui_state
);

// After
spell_book_ui::render_magic_tab(
    ui,
    &mut spell_book_state,
    &skills_data,
    player_entity,
    skills,
    active_spell,
    &mut select_spell_writer,
    &mut cast_spell_writer,
    &mut coconut_ui_state,
    &params.spell_db  // Added missing argument
);

Verification

After all fixes:
cargo check
Result: Compilation successful (with only minor warnings about unused variables, which are non-blocking).

Key Lessons

1. Systematic Approach

  • Read error messages carefully
  • Fix one error at a time
  • Run cargo check after each fix
  • Don't assume errors are independent

2. Type System Strictness

  • Rust treats identically-named structs in different modules as completely different types
  • Always verify import paths match the intended module

3. Event Handler Completeness

  • Defining an event is not enough - you must also:
    1. Implement a handler system
    2. Register the system in the plugin
    3. Ensure the event writer uses the correct type

4. Code Corruption Recovery

  • When function signatures get corrupted, check:
    1. All parameters are present
    2. Opening and closing braces match
    3. SystemParam structs have all required fields

5. Missing Arguments

  • When adding new fields to structs, update ALL call sites
  • Use compiler error messages to find missing arguments
  • The compiler's "help:" suggestions are usually correct

Files Modified

  1. src/systems/ui/mod.rs - Fixed event type, removed lint warnings, restored signature, added argument
  2. src/systems/magic/cast_system.rs - Added imports and handle_spell_selection function
  3. src/systems/magic/mod.rs - Registered new system
  4. src/systems/player/interactions.rs - Removed unused import

Time to Resolution

  • Initial error identification: ~5 minutes
  • Root cause analysis: ~10 minutes
  • Implementing fixes: ~15 minutes
  • Debugging corrupted code: ~10 minutes
  • Final verification: ~5 minutes
Total: ~45 minutes

Prevention for Future

  1. Before creating new events: Search for existing definitions
    grep -r "struct SelectSpellEvent" src/
  2. When refactoring modules: Delete old definitions immediately after moving code
  3. When adding struct fields: Use IDE "Find Usages" to locate all call sites
  4. Before committing: Run cargo check to catch issues early
  • compilation_errors.md: Error patterns and solutions
  • duplicate_event_definitions.md: Deep dive into module conflicts
  • lessons_learned.md: General implementation insights