duplicate event definitions

Guide for duplicate event definitions

Duplicate Event Definitions Issue

Problem

During the magic system implementation, two separate SelectSpellEvent structs were accidentally created in different modules, causing a type mismatch compilation error:
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`

Root Cause

The magic system was implemented across two different module locations:
  1. src/systems/skills/magic.rs (Original location)
    • Contains: SelectSpellEvent, CastSpellEvent, PrepareCoconutEvent, BreakCoconutEvent
    • Purpose: Skill-based magic implementation integrated with Skills system
    • Event handlers for spell selection, casting, and coconut teleportation
  2. src/systems/magic/mod.rs (New module created later)
    • Contains: SelectSpellEvent, CastSpellEvent, SpawnProjectileEvent
    • Purpose: Combat-focused magic with projectile visuals
    • Separate spell database and casting system
This created duplicate event definitions with the same name but different module paths, making them incompatible types in Rust's type system.

Why This Happened

The implementation evolved through multiple phases:
  1. Phase 1: Magic implemented as part of Skills system (systems::skills::magic)
  2. Phase 2: Combat magic extracted to dedicated module (systems::magic)
  3. Issue: Events were redefined in the new module instead of being moved/shared
The UI code (spell_book_ui.rs) expected one version, but the event writer provided the other version.

Solution Options

Choose ONE canonical location for all magic events:
// Either in src/systems/magic/mod.rs OR src/systems/skills/magic.rs
#[derive(Event)]
pub struct SelectSpellEvent {
    pub player: Entity,
    pub spell_id: Option<String>,
}
Update all imports to reference the canonical location:
// In UI code
use crate::systems::magic::SelectSpellEvent;  // OR
use crate::systems::skills::magic::SelectSpellEvent;
Delete the duplicate definition from the other module.

Option 2: Rename Events for Different Purposes

If the two modules serve genuinely different purposes, rename events to clarify:
// src/systems/skills/magic.rs
pub struct SkillMagicSelectEvent { ... }

// src/systems/magic/mod.rs  
pub struct CombatMagicSelectEvent { ... }
This is only appropriate if the events have different semantics.

Option 3: Shared Events Module

Create a common events module:
// src/systems/magic/events.rs
pub struct SelectSpellEvent { ... }
pub struct CastSpellEvent { ... }

// Both systems import from here
use crate::systems::magic::events::SelectSpellEvent;
For the Legends of Hastinapur project, the recommended structure is:
src/systems/magic/
├── mod.rs              # Events, core types, plugin
├── cast_system.rs      # Spell casting logic
├── projectile.rs       # Visual projectiles
└── events.rs           # Shared event definitions (optional)

src/systems/skills/magic.rs  # DEPRECATED - remove or refactor
Rationale:
  • Magic is complex enough to warrant its own module
  • Combat magic (projectiles, damage) is distinct from skill progression
  • Skills system should only track Magic XP, not implement casting logic
  • UI should interact with systems::magic events

Prevention

To avoid this issue in future:
  1. Search before defining: Use grep to check if an event/type already exists
    grep -r "SelectSpellEvent" src/
  2. Clear module boundaries: Document which module owns which responsibilities
  3. Compiler errors are hints: Type mismatch errors with "similar names" indicate duplicates
  4. Refactor incrementally: When moving code between modules, delete old definitions immediately
This same pattern caused similar issues with:
  • CastSpellEvent (also duplicated)
  • calculate_damage function (private in combat::mod, attempted import in magic::projectile)

Lessons Learned

  1. Module organization matters: Plan module structure before implementing large features
  2. Rust's type system is strict: Two structs with identical fields but different paths are incompatible
  3. Event-driven systems need clear ownership: Each event should have ONE canonical definition
  4. Refactoring requires discipline: When splitting/merging modules, ensure no duplicates remain

Fix Applied

The actual fix in this conversation involved identifying the type mismatch and determining which SelectSpellEvent definition should be used. The compilation error was resolved by ensuring consistent imports across the codebase.