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:
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
- Contains:
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
- Contains:
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:
- Phase 1: Magic implemented as part of Skills system (
systems::skills::magic) - Phase 2: Combat magic extracted to dedicated module (
systems::magic) - 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
Option 1: Consolidate to Single Module (Recommended)
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;Recommended Architecture
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 refactorRationale:
- 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::magicevents
Prevention
To avoid this issue in future:
- Search before defining: Use
grepto check if an event/type already existsgrep -r "SelectSpellEvent" src/ - Clear module boundaries: Document which module owns which responsibilities
- Compiler errors are hints: Type mismatch errors with "similar names" indicate duplicates
- Refactor incrementally: When moving code between modules, delete old definitions immediately
Related Errors
This same pattern caused similar issues with:
CastSpellEvent(also duplicated)calculate_damagefunction (private incombat::mod, attempted import inmagic::projectile)
Lessons Learned
- Module organization matters: Plan module structure before implementing large features
- Rust's type system is strict: Two structs with identical fields but different paths are incompatible
- Event-driven systems need clear ownership: Each event should have ONE canonical definition
- 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.