deepslate 0.1.0

A high-performance Minecraft server proxy written in Rust.
Documentation
//! Type-safe event system for the Deepslate proxy.
//!
//! Inspired by [Velocity's event system](https://docs.papermc.io/velocity/dev/event-system),
//! this module provides a type-safe publish-subscribe event system where:
//!
//! - **Events are plain structs** — no required base trait or common ancestor.
//! - **Result-based outcomes** — events that can be cancelled or modified implement
//!   [`ResultedEvent`] with domain-specific result enums (e.g., `Allow`/`Deny`).
//! - **Priority ordering** — handlers execute in priority order ([`PostOrder`]),
//!   so multiple plugins can cooperate on the same event.
//! - **Compile-time type safety** — the [`EventManager::subscribe`] API is fully
//!   generic; internal storage uses type-erased trait objects keyed by [`TypeId`].
//!
//! # Plugin Model
//!
//! Rather than implementing a monolithic trait with one method per event, plugins
//! implement the [`Plugin`] trait and register individual event handlers during
//! startup:
//!
//! ```rust,no_run
//! use deepslate::event::*;
//! use deepslate::event::events::*;
//!
//! struct MyPlugin;
//!
//! impl Plugin for MyPlugin {
//!     fn register(&self, events: &mut EventManager) {
//!         events.subscribe::<LoginEvent>(PostOrder::NORMAL, |event| {
//!             if event.player.profile.name == "griefer" {
//!                 event.set_result(LoginResult::Deny("Not allowed".into()));
//!             }
//!         });
//!
//!         events.subscribe::<DisconnectEvent>(PostOrder::NORMAL, |event| {
//!             println!("Player left: {}", event.player.profile.name);
//!         });
//!     }
//! }
//! ```

pub mod events;
pub mod handler;
pub mod priority;
pub mod result;

use std::any::TypeId;
use std::collections::HashMap;

use deepslate_protocol::types::GameProfile;

pub use events::*;
pub use priority::PostOrder;
pub use result::{EventResult, ResultedEvent};

use handler::{sort_handlers, HandlerRegistration, TypedHandler};

/// Information about a connected player, passed to event handlers.
#[derive(Debug, Clone)]
pub struct PlayerInfo {
    /// The player's authenticated game profile.
    pub profile: GameProfile,
    /// The player's remote IP address as a string.
    pub remote_addr: String,
    /// The protocol version the player connected with.
    pub protocol_version: i32,
}

/// Central event dispatcher.
///
/// Stores type-erased handlers keyed by event [`TypeId`]. Handlers are sorted
/// by priority at registration time and dispatched sequentially when an event
/// is fired.
///
/// The `EventManager` is built during proxy startup (plugins register handlers
/// via [`Plugin::register`]), then wrapped in an `Arc` and shared across async
/// tasks as an immutable reference.
pub struct EventManager {
    handlers: HashMap<TypeId, Vec<HandlerRegistration>>,
}

impl EventManager {
    /// Create a new, empty event manager.
    #[must_use]
    pub fn new() -> Self {
        Self {
            handlers: HashMap::new(),
        }
    }

    /// Register a handler for a specific event type at the given priority.
    ///
    /// Handlers are called in priority order (highest first). Handlers at the
    /// same priority execute in registration order.
    ///
    /// # Type Safety
    ///
    /// The handler closure receives a `&mut E`, so it can read and modify the
    /// event (including setting results on [`ResultedEvent`] types). The
    /// `EventManager` guarantees that the handler is only called with events of
    /// the correct type.
    pub fn subscribe<E: 'static + Send>(
        &mut self,
        priority: PostOrder,
        handler: impl Fn(&mut E) + Send + Sync + 'static,
    ) {
        let type_id = TypeId::of::<E>();
        let registration = HandlerRegistration {
            priority,
            handler: Box::new(TypedHandler::new(handler)),
        };

        let handlers = self.handlers.entry(type_id).or_default();
        handlers.push(registration);
        sort_handlers(handlers);
    }

    /// Fire an event through all registered handlers in priority order.
    ///
    /// Returns the (potentially modified) event so callers can inspect the
    /// final result.
    pub fn fire<E: 'static + Send>(&self, mut event: E) -> E {
        if let Some(handlers) = self.handlers.get(&TypeId::of::<E>()) {
            for handler in handlers {
                handler.handler.call(&mut event);
            }
        }
        event
    }
}

impl Default for EventManager {
    fn default() -> Self {
        Self::new()
    }
}

/// Trait that plugins implement to hook into the proxy lifecycle.
///
/// Instead of overriding hardcoded event methods, plugins register individual
/// event handlers with the [`EventManager`] during the [`register`](Plugin::register)
/// call. This allows multiple plugins to subscribe to the same events with
/// independent priority ordering.
///
/// The trait requires `Send + Sync + 'static` because plugin references are
/// shared during the registration phase.
///
/// # Example
///
/// ```rust,no_run
/// use deepslate::event::*;
/// use deepslate::event::events::*;
///
/// struct LobbyPlugin;
///
/// impl Plugin for LobbyPlugin {
///     fn register(&self, events: &mut EventManager) {
///         events.subscribe::<ChooseServerEvent>(PostOrder::NORMAL, |event| {
///             event.set_result(ChooseServerResult::Override("lobby".into()));
///         });
///     }
/// }
/// ```
pub trait Plugin: Send + Sync + 'static {
    /// Called once during proxy startup to register event handlers.
    ///
    /// Implementations should call [`EventManager::subscribe`] to register
    /// handlers for the events they care about.
    fn register(&self, events: &mut EventManager);
}