Skip to main content

pumpkinplus/modules/mechanics/
mechanic.rs

1//! Mechanic system for PumpkinPlus.
2//!
3//! Each gameplay feature is implemented as a module implementing the [`Mechanic`] trait.
4//! Mechanics can register event handlers, commands, and permission nodes.
5
6use pumpkin_plugin_api::Context;
7use pumpkin_plugin_api::command::Command;
8use std::collections::HashSet;
9
10/// A trait representing a plugin mechanic that can be enabled or disabled.
11///
12/// Mechanics may optionally expose commands, permission nodes, and event handlers,
13/// all registered with the server via [`Mechanic::register`].
14pub trait Mechanic {
15    /// Returns `true` if the module is enabled, `false` otherwise.
16    fn enabled(&self) -> bool;
17
18    /// Returns the commands provided by this mechanic.
19    ///
20    /// Each [`Command`] returned here will be registered with the server when
21    /// [`Mechanic::register`] is called. Returns an empty vec by default.
22    fn cmds(&self) -> Vec<Command> {
23        vec![]
24    }
25
26    /// Returns the permission nodes required by this mechanic.
27    ///
28    /// Permissions are paired with commands by index when registering. If there
29    /// are fewer permissions than commands, remaining commands are registered
30    /// without a permission requirement. Returns an empty set by default.
31    fn perms(&self) -> HashSet<String> {
32        HashSet::new()
33    }
34
35    /// Registers event handlers for this mechanic.
36    ///
37    /// Override this to call [`Context::register_event_handler`] for each event
38    /// this mechanic handles. No-op by default.
39    fn events(&self, _context: &Context) {}
40
41    /// Registers this mechanic's event handlers and commands with the server.
42    ///
43    /// Calls [`Mechanic::events`](Mechanic::events), then registers each command from
44    /// [`Mechanic::cmds`] paired with its corresponding permission from [`Mechanic::perms`]
45    /// by index. Commands without a paired permission use an empty permission string.
46    fn register(&self, context: &Context) {
47        if !self.enabled() {
48            return;
49        }
50        self.events(context);
51        let perms: Vec<String> = self.perms().into_iter().collect();
52        for (i, cmd) in self.cmds().into_iter().enumerate() {
53            let perm = perms.get(i).cloned().unwrap_or_default();
54            context.register_command(cmd, &perm);
55        }
56    }
57}