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}