Pumpkin/crates/pumpkin-plugin-api/src/commands.rs
2026-08-08 13:44:51 +02:00

78 lines
2.4 KiB
Rust

use std::{
collections::BTreeMap,
sync::{
Mutex,
atomic::{AtomicU32, Ordering},
},
};
pub use crate::wit::pumpkin::plugin::command::Command;
use crate::{
Result, Server,
command::CommandNode,
wit::pumpkin::plugin::command::{CommandError, CommandSender, ConsumedArgs},
};
pub(crate) static NEXT_COMMAND_ID: AtomicU32 = AtomicU32::new(0);
pub(crate) static COMMAND_HANDLERS: Mutex<BTreeMap<u32, Box<dyn CommandHandler>>> =
Mutex::new(BTreeMap::new());
/// Handles the execution of a registered command.
///
/// Implement this trait to define the logic that runs when a command is invoked.
/// The return value is the exit code passed back to the server; return `Ok(0)` for
/// success or an [`Err`] variant to report a failure message to the sender.
pub trait CommandHandler: Send + Sync {
/// Executes the command.
///
/// # Arguments
/// - `sender` — who invoked the command (player or console).
/// - `server` — handle to the server.
/// - `args` — the parsed argument map for this command invocation.
fn handle(
&self,
sender: CommandSender,
server: Server,
args: ConsumedArgs,
) -> Result<i32, CommandError>;
}
impl Command {
/// Attaches an execution handler to this command.
///
/// Registers `handler` so that it is called whenever this command is invoked.
/// Returns `self` to allow builder-style chaining.
pub fn execute<H: CommandHandler + Send + Sync + 'static>(self, handler: H) -> Self {
let id = NEXT_COMMAND_ID.fetch_add(1, Ordering::Relaxed);
COMMAND_HANDLERS
.lock()
.unwrap_or_else(|e| e.into_inner())
.insert(id, Box::new(handler));
self.execute_with_handler_id(id);
self
}
}
impl CommandNode {
/// Attaches an execution handler to this command node.
///
/// Registers `handler` so that it is called when this specific node (subcommand
/// or argument branch) is the final node matched during command dispatch.
/// Returns `self` to allow builder-style chaining.
pub fn execute<H: CommandHandler + Send + Sync + 'static>(self, handler: H) -> Self {
let id = NEXT_COMMAND_ID.fetch_add(1, Ordering::Relaxed);
COMMAND_HANDLERS
.lock()
.unwrap_or_else(|e| e.into_inner())
.insert(id, Box::new(handler));
self.execute_with_handler_id(id);
self
}
}