chore: swap permissions_manger to dashmap

i need this also PatchBukkit
This commit is contained in:
Alexander Medvedev 2026-08-19 19:50:20 +02:00
parent 489403c58b
commit 61bd8f77b6
43 changed files with 245 additions and 220 deletions

2
Cargo.lock generated
View File

@ -3595,6 +3595,7 @@ dependencies = [
"colored", "colored",
"criterion", "criterion",
"crypto-bigint 0.7.5", "crypto-bigint 0.7.5",
"dashmap",
"ecdsa 0.17.0", "ecdsa 0.17.0",
"md5", "md5",
"num-derive", "num-derive",
@ -3610,7 +3611,6 @@ dependencies = [
"sha2 0.11.0", "sha2 0.11.0",
"syn 3.0.3", "syn 3.0.3",
"thiserror 2.0.20", "thiserror 2.0.20",
"tokio",
"ureq", "ureq",
"uuid", "uuid",
] ]

View File

@ -22,7 +22,7 @@ syn = { workspace = true, optional = true }
proc-macro2 = { workspace = true, optional = true } proc-macro2 = { workspace = true, optional = true }
uuid.workspace = true uuid.workspace = true
tokio = { workspace = true, features = ["sync"] } dashmap.workspace = true
base64.workspace = true base64.workspace = true
p384 = { workspace = true, features = ["ecdsa"] } p384 = { workspace = true, features = ["ecdsa"] }
thiserror.workspace = true thiserror.workspace = true

View File

@ -1,7 +1,6 @@
use dashmap::DashMap;
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
/// Describes the default behaviour for permissions. /// Describes the default behaviour for permissions.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
@ -65,7 +64,7 @@ impl Permission {
#[derive(Default)] #[derive(Default)]
pub struct PermissionRegistry { pub struct PermissionRegistry {
/// All registered permissions. /// All registered permissions.
permissions: HashMap<String, Permission>, permissions: DashMap<String, Permission>,
} }
impl PermissionRegistry { impl PermissionRegistry {
@ -76,7 +75,7 @@ impl PermissionRegistry {
#[must_use] #[must_use]
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
permissions: HashMap::new(), permissions: DashMap::new(),
} }
} }
@ -88,7 +87,7 @@ impl PermissionRegistry {
/// # Returns /// # Returns
/// - `Ok(())` if the permission was successfully registered. /// - `Ok(())` if the permission was successfully registered.
/// - `Err(String)` if a permission with the same node already exists. /// - `Err(String)` if a permission with the same node already exists.
pub fn register_permission(&mut self, permission: Permission) -> Result<(), String> { pub fn register_permission(&self, permission: Permission) -> Result<(), String> {
if self.permissions.contains_key(&permission.node) { if self.permissions.contains_key(&permission.node) {
return Err(format!( return Err(format!(
"Permission {} is already registered", "Permission {} is already registered",
@ -108,7 +107,7 @@ impl PermissionRegistry {
/// # Parameters /// # Parameters
/// - `permission`: The `Permission` instance to add. /// - `permission`: The `Permission` instance to add.
#[allow(clippy::expect_used)] #[allow(clippy::expect_used)]
pub fn register_permission_or_panic(&mut self, permission: Permission) { pub fn register_permission_or_panic(&self, permission: Permission) {
self.register_permission(permission) self.register_permission(permission)
.expect("Permission should have been registered successfully"); .expect("Permission should have been registered successfully");
} }
@ -119,9 +118,12 @@ impl PermissionRegistry {
/// - `node`: The full permission node string to look up. /// - `node`: The full permission node string to look up.
/// ///
/// # Returns /// # Returns
/// `Some(&Permission)` if the node exists, or `None` otherwise. /// `Some(Ref<'_, String, Permission>)` if the node exists, or `None` otherwise.
#[must_use] #[must_use]
pub fn get_permission(&self, node: &str) -> Option<&Permission> { pub fn get_permission(
&self,
node: &str,
) -> Option<dashmap::mapref::one::Ref<'_, String, Permission>> {
self.permissions.get(node) self.permissions.get(node)
} }
@ -137,8 +139,9 @@ impl PermissionRegistry {
/// # Returns /// # Returns
/// - `true` if the node existed and its default was updated. /// - `true` if the node existed and its default was updated.
/// - `false` if no permission with that node is registered. /// - `false` if no permission with that node is registered.
pub fn set_default(&mut self, node: &str, default: PermissionDefault) -> bool { #[must_use]
if let Some(permission) = self.permissions.get_mut(node) { pub fn set_default(&self, node: &str, default: PermissionDefault) -> bool {
if let Some(mut permission) = self.permissions.get_mut(node) {
permission.default = default; permission.default = default;
true true
} else { } else {
@ -163,7 +166,7 @@ impl PermissionRegistry {
#[derive(Default, Clone, Debug, Serialize, Deserialize)] #[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct PermissionAttachment { pub struct PermissionAttachment {
/// Directly assigned permissions. /// Directly assigned permissions.
permissions: HashMap<String, bool>, pub permissions: HashMap<String, bool>,
} }
impl PermissionAttachment { impl PermissionAttachment {
@ -217,53 +220,103 @@ impl PermissionAttachment {
} }
} }
/// Manager for player permissions. /// Manager for player and server permissions.
#[derive(Default)] #[derive(Default)]
pub struct PermissionManager { pub struct PermissionManager {
/// Global registry of permissions. /// Global registry of permissions.
pub registry: Arc<RwLock<PermissionRegistry>>, pub registry: PermissionRegistry,
/// Player permission attachments. /// Player permission attachments keyed by player UUID.
pub attachments: HashMap<uuid::Uuid, Arc<RwLock<PermissionAttachment>>>, pub attachments: DashMap<uuid::Uuid, DashMap<String, bool>>,
} }
impl PermissionManager { impl PermissionManager {
/// Creates a new `PermissionManager`. /// Creates a new empty `PermissionManager`.
/// #[must_use]
/// # Parameters pub fn new() -> Self {
/// - `registry`: An `Arc<RwLock<PermissionRegistry>>` containing the global permissions registry.
///
/// # Returns
/// A `PermissionManager` with an empty attachments map.
pub fn new(registry: Arc<RwLock<PermissionRegistry>>) -> Self {
Self { Self {
registry, registry: PermissionRegistry::new(),
attachments: HashMap::new(), attachments: DashMap::new(),
} }
} }
/// Retrieves the `PermissionAttachment` for a given player, creating one if it doesn't exist. /// Creates a new `PermissionManager` with an existing `PermissionRegistry`.
/// #[must_use]
/// # Parameters pub fn with_registry(registry: PermissionRegistry) -> Self {
/// - `player_id`: The UUID of the player. Self {
/// registry,
/// # Returns attachments: DashMap::new(),
/// An `Arc<RwLock<PermissionAttachment>>` representing the player's attachment. }
pub fn get_attachment(&mut self, player_id: uuid::Uuid) -> Arc<RwLock<PermissionAttachment>> {
Arc::clone(
self.attachments
.entry(player_id)
.or_insert_with(|| Arc::new(RwLock::new(PermissionAttachment::new()))),
)
} }
/// Removes the `PermissionAttachment` for a given player. /// Registers a new permission node in the global registry.
/// pub fn register_permission(&self, permission: Permission) -> Result<(), String> {
/// # Parameters self.registry.register_permission(permission)
/// - `player_id`: The UUID of the player. }
pub fn remove_attachment(&mut self, player_id: &uuid::Uuid) {
/// Registers a new permission node in the global registry or panics if already registered.
pub fn register_permission_or_panic(&self, permission: Permission) {
self.registry.register_permission_or_panic(permission);
}
/// Retrieves a permission node by its name from the registry.
#[must_use]
pub fn get_permission(
&self,
node: &str,
) -> Option<dashmap::mapref::one::Ref<'_, String, Permission>> {
self.registry.get_permission(node)
}
/// Overrides the default behaviour of an already-registered permission in the registry.
#[must_use]
pub fn set_default(&self, node: &str, default: PermissionDefault) -> bool {
self.registry.set_default(node, default)
}
/// Checks whether a permission node exists in the registry.
#[must_use]
pub fn has_registered_permission(&self, node: &str) -> bool {
self.registry.has_permission(node)
}
/// Sets a player's explicit permission.
pub fn set_permission(&self, player_id: uuid::Uuid, node: impl Into<String>, value: bool) {
self.attachments
.entry(player_id)
.or_default()
.insert(node.into(), value);
}
/// Unsets a player's explicit permission.
pub fn unset_permission(&self, player_id: &uuid::Uuid, node: &str) {
if let Some(player_perms) = self.attachments.get(player_id) {
player_perms.remove(node);
}
}
/// Checks if a permission is explicitly set for a player.
#[must_use]
pub fn has_permission_set(&self, player_id: &uuid::Uuid, node: &str) -> Option<bool> {
self.attachments
.get(player_id)
.and_then(|p| p.get(node).as_deref().copied())
}
/// Removes all permission attachments for a player.
pub fn remove_attachment(&self, player_id: &uuid::Uuid) {
self.attachments.remove(player_id); self.attachments.remove(player_id);
} }
/// Retrieves all explicitly assigned permissions for a player.
#[must_use]
pub fn get_player_permissions(&self, player_id: &uuid::Uuid) -> Option<HashMap<String, bool>> {
self.attachments.get(player_id).map(|p| {
p.iter()
.map(|item| (item.key().clone(), *item.value()))
.collect()
})
}
/// Checks if a player has a specific permission. /// Checks if a player has a specific permission.
/// ///
/// # Parameters /// # Parameters
@ -273,21 +326,18 @@ impl PermissionManager {
/// ///
/// # Returns /// # Returns
/// `true` if the player has the permission, `false` otherwise. /// `true` if the player has the permission, `false` otherwise.
pub async fn has_permission( #[must_use]
pub fn has_permission(
&self, &self,
player_id: &uuid::Uuid, player_id: &uuid::Uuid,
permission_node: &str, permission_node: &str,
player_op_level: PermissionLvl, player_op_level: PermissionLvl,
) -> bool { ) -> bool {
let reg = self.registry.read().await;
// Check explicitly set permissions // Check explicitly set permissions
if let Some(attachment) = self.attachments.get(player_id) { if let Some(attachment) = self.attachments.get(player_id) {
let attachment = attachment.read().await;
// Check for the exact permission match // Check for the exact permission match
if let Some(value) = attachment.has_permission_set(permission_node) { if let Some(value) = attachment.get(permission_node) {
return value; return *value;
} }
// Check parent nodes (for wildcard permissions) // Check parent nodes (for wildcard permissions)
@ -298,23 +348,21 @@ impl PermissionManager {
// Check wildcard permissions at each level // Check wildcard permissions at each level
let mut current_node = namespace.to_string(); let mut current_node = namespace.to_string();
if let Some(value) = attachment.has_permission_set(&format!("{current_node}:*")) { if let Some(value) = attachment.get(&format!("{current_node}:*")) {
return value; return *value;
} }
current_node.push(':'); current_node.push(':');
for (i, part) in key_parts.iter().enumerate() { for (i, part) in key_parts.iter().enumerate() {
current_node.push_str(part); current_node.push_str(part);
if let Some(value) = attachment.has_permission_set(&current_node) { if let Some(value) = attachment.get(&current_node) {
return value; return *value;
} }
if i < key_parts.len() - 1 { if i < key_parts.len() - 1 {
if let Some(value) = if let Some(value) = attachment.get(&format!("{current_node}.*")) {
attachment.has_permission_set(&format!("{current_node}.*")) return *value;
{
return value;
} }
current_node.push('.'); current_node.push('.');
} }
@ -322,17 +370,20 @@ impl PermissionManager {
} }
// Check for inherited permissions from parent nodes // Check for inherited permissions from parent nodes
for (node, value) in attachment.get_permissions() { for item in attachment.iter() {
if let Some(permission) = reg.get_permission(node) let node = item.key();
let value = *item.value();
if let Some(permission) = self.registry.get_permission(node)
&& let Some(child_val) = permission.children.get(permission_node) && let Some(child_val) = permission.children.get(permission_node)
{ {
return *value && *child_val; return value && *child_val;
} }
} }
} }
// Fall back to the default permission value // Fall back to the default permission value
reg.get_permission(permission_node) self.registry
.get_permission(permission_node)
.is_some_and(|permission| match permission.default { .is_some_and(|permission| match permission.default {
PermissionDefault::Allow => true, PermissionDefault::Allow => true,
PermissionDefault::Deny => false, PermissionDefault::Deny => false,

View File

@ -562,7 +562,7 @@ impl CommandExecutor for EveryAdvancementExecutor {
} }
/// register the advancement command /// register the advancement command
pub fn register(dispatcher: &mut CommandDispatcher, registry: &mut PermissionRegistry) { pub fn register(dispatcher: &mut CommandDispatcher, registry: &PermissionRegistry) {
registry.register_permission_or_panic(Permission::new( registry.register_permission_or_panic(Permission::new(
PERMISSION, PERMISSION,
DESCRIPTION, DESCRIPTION,

View File

@ -450,7 +450,7 @@ impl CommandExecutor for ModifierGetExecutor {
} }
} }
pub fn register(dispatcher: &mut CommandDispatcher, registry: &mut PermissionRegistry) { pub fn register(dispatcher: &mut CommandDispatcher, registry: &PermissionRegistry) {
registry.register_permission_or_panic(Permission::new( registry.register_permission_or_panic(Permission::new(
PERMISSION, PERMISSION,
DESCRIPTION, DESCRIPTION,

View File

@ -106,7 +106,7 @@ impl CommandExecutor for BanListCommandExecutor {
} }
} }
pub fn register(dispatcher: &mut CommandDispatcher, registry: &mut PermissionRegistry) { pub fn register(dispatcher: &mut CommandDispatcher, registry: &PermissionRegistry) {
registry.register_permission_or_panic(Permission::new( registry.register_permission_or_panic(Permission::new(
PERMISSION, PERMISSION,
DESCRIPTION, DESCRIPTION,

View File

@ -264,7 +264,7 @@ impl CommandExecutor for CloneExecutor {
} }
} }
pub fn register(dispatcher: &mut CommandDispatcher, registry: &mut PermissionRegistry) { pub fn register(dispatcher: &mut CommandDispatcher, registry: &PermissionRegistry) {
registry.register_permission_or_panic(Permission::new( registry.register_permission_or_panic(Permission::new(
PERMISSION, PERMISSION,
DESCRIPTION, DESCRIPTION,

View File

@ -86,7 +86,7 @@ impl CommandExecutor for DialogShowExecutor {
} }
} }
pub fn register(dispatcher: &mut CommandDispatcher, registry: &mut PermissionRegistry) { pub fn register(dispatcher: &mut CommandDispatcher, registry: &PermissionRegistry) {
registry.register_permission_or_panic(Permission::new( registry.register_permission_or_panic(Permission::new(
PERMISSION, PERMISSION,
DESCRIPTION, DESCRIPTION,

View File

@ -82,7 +82,7 @@ impl CommandExecutor for DifficultySetExecutor {
} }
} }
pub fn register(dispatcher: &mut CommandDispatcher, registry: &mut PermissionRegistry) { pub fn register(dispatcher: &mut CommandDispatcher, registry: &PermissionRegistry) {
registry.register_permission_or_panic(Permission::new( registry.register_permission_or_panic(Permission::new(
PERMISSION, PERMISSION,
DESCRIPTION, DESCRIPTION,

View File

@ -393,7 +393,7 @@ fn execute_summon_modifier<'a>(
} }
#[allow(clippy::too_many_lines)] #[allow(clippy::too_many_lines)]
pub fn register(dispatcher: &mut CommandDispatcher, registry: &mut PermissionRegistry) { pub fn register(dispatcher: &mut CommandDispatcher, registry: &PermissionRegistry) {
registry.register_permission_or_panic(Permission::new( registry.register_permission_or_panic(Permission::new(
PERMISSION, PERMISSION,
DESCRIPTION, DESCRIPTION,

View File

@ -364,7 +364,7 @@ impl CommandExecutor for PrintForEntityExecutor {
} }
} }
pub fn register(dispatcher: &mut CommandDispatcher, registry: &mut PermissionRegistry) { pub fn register(dispatcher: &mut CommandDispatcher, registry: &PermissionRegistry) {
registry.register_permission_or_panic(Permission::new( registry.register_permission_or_panic(Permission::new(
PERMISSION, PERMISSION,
DESCRIPTION, DESCRIPTION,

View File

@ -158,7 +158,7 @@ impl CommandExecutor for FillBiomeExecutor {
} }
} }
pub fn register(dispatcher: &mut CommandDispatcher, registry: &mut PermissionRegistry) { pub fn register(dispatcher: &mut CommandDispatcher, registry: &PermissionRegistry) {
registry.register_permission_or_panic(Permission::new( registry.register_permission_or_panic(Permission::new(
PERMISSION, PERMISSION,
DESCRIPTION, DESCRIPTION,

View File

@ -347,7 +347,7 @@ impl CommandExecutor for ForceloadQueryExecutor {
} }
} }
pub fn register(dispatcher: &mut CommandDispatcher, registry: &mut PermissionRegistry) { pub fn register(dispatcher: &mut CommandDispatcher, registry: &PermissionRegistry) {
registry.register_permission_or_panic(Permission::new( registry.register_permission_or_panic(Permission::new(
PERMISSION, PERMISSION,
DESCRIPTION, DESCRIPTION,

View File

@ -373,7 +373,7 @@ impl CommandExecutor for HelpCommandExecutor {
} }
} }
pub fn register(dispatcher: &mut CommandDispatcher, registry: &mut PermissionRegistry) { pub fn register(dispatcher: &mut CommandDispatcher, registry: &PermissionRegistry) {
registry.register_permission_or_panic(Permission::new( registry.register_permission_or_panic(Permission::new(
PERMISSION, PERMISSION,
DESCRIPTION, DESCRIPTION,

View File

@ -72,7 +72,7 @@ impl CommandExecutor for SelfExecutor {
} }
} }
pub fn register(dispatcher: &mut CommandDispatcher, registry: &mut PermissionRegistry) { pub fn register(dispatcher: &mut CommandDispatcher, registry: &PermissionRegistry) {
registry.register_permission_or_panic(Permission::new( registry.register_permission_or_panic(Permission::new(
PERMISSION, PERMISSION,
DESCRIPTION, DESCRIPTION,

View File

@ -99,7 +99,7 @@ fn get_player_names_and_ids(players: &[Arc<Player>]) -> TextComponent {
TextComponent::join_with_comma(names_and_ids) TextComponent::join_with_comma(names_and_ids)
} }
pub fn register(dispatcher: &mut CommandDispatcher, registry: &mut PermissionRegistry) { pub fn register(dispatcher: &mut CommandDispatcher, registry: &PermissionRegistry) {
registry.register_permission_or_panic(Permission::new( registry.register_permission_or_panic(Permission::new(
PERMISSION, PERMISSION,
DESCRIPTION, DESCRIPTION,

View File

@ -220,7 +220,7 @@ impl CommandExecutor for LootExecutor {
} }
#[expect(clippy::too_many_lines)] #[expect(clippy::too_many_lines)]
pub fn register(dispatcher: &mut CommandDispatcher, registry: &mut PermissionRegistry) { pub fn register(dispatcher: &mut CommandDispatcher, registry: &PermissionRegistry) {
registry.register_permission_or_panic(Permission::new( registry.register_permission_or_panic(Permission::new(
PERMISSION, PERMISSION,
DESCRIPTION, DESCRIPTION,

View File

@ -3,9 +3,8 @@ use crate::command::tree::Command;
use pumpkin_config::{BasicConfiguration, CommandsConfig}; use pumpkin_config::{BasicConfiguration, CommandsConfig};
use pumpkin_util::{ use pumpkin_util::{
PermissionLvl, PermissionLvl,
permission::{Permission, PermissionDefault, PermissionRegistry}, permission::{Permission, PermissionDefault, PermissionManager, PermissionRegistry},
}; };
use tokio::sync::RwLock;
use tracing::{info, warn}; use tracing::{info, warn};
mod advancement; mod advancement;
@ -87,15 +86,13 @@ mod worldborder;
#[allow(clippy::too_many_lines)] #[allow(clippy::too_many_lines)]
#[must_use] #[must_use]
pub async fn default_dispatcher( pub fn default_dispatcher(
registry: &RwLock<PermissionRegistry>, permission_manager: &PermissionManager,
_basic_config: &BasicConfiguration, _basic_config: &BasicConfiguration,
commands_config: &CommandsConfig, commands_config: &CommandsConfig,
) -> CommandDispatcher { ) -> CommandDispatcher {
let mut dispatcher = crate::command::dispatcher::CommandDispatcher::default(); let mut dispatcher = crate::command::dispatcher::CommandDispatcher::default();
let registry = &permission_manager.registry;
let mut registry_lock = registry.write().await;
let registry = &mut *registry_lock;
register_permissions(registry); register_permissions(registry);
@ -227,7 +224,7 @@ pub async fn default_dispatcher(
/// this affects both the legacy and the node-based dispatchers uniformly. /// this affects both the legacy and the node-based dispatchers uniformly.
fn apply_command_overrides( fn apply_command_overrides(
dispatcher: &mut CommandDispatcher, dispatcher: &mut CommandDispatcher,
registry: &mut PermissionRegistry, registry: &PermissionRegistry,
commands_config: &CommandsConfig, commands_config: &CommandsConfig,
) { ) {
for (raw_name, settings) in &commands_config.overrides { for (raw_name, settings) in &commands_config.overrides {
@ -278,11 +275,16 @@ fn apply_command_overrides(
}; };
if let Some(node) = resolve_permission_node(dispatcher, registry, &name) { if let Some(node) = resolve_permission_node(dispatcher, registry, &name) {
registry.set_default(&node, default); if registry.set_default(&node, default) {
info!( info!(
"The /{name} command now needs permission level {} to use", "The /{name} command now needs permission level {} to use",
level as u8 level as u8
); );
} else {
warn!(
"Command override for /{name} sets a permission level, but matching permission node could not be updated; leaving it unchanged"
);
}
} else { } else {
warn!( warn!(
"Command override for /{name} sets a permission level, but no matching permission node could be found; leaving it unchanged" "Command override for /{name} sets a permission level, but no matching permission node could be found; leaving it unchanged"
@ -316,7 +318,7 @@ fn resolve_permission_node(
None None
} }
fn register_permissions(registry: &mut PermissionRegistry) { fn register_permissions(registry: &PermissionRegistry) {
// Register level 0 permissions (allowed by default) // Register level 0 permissions (allowed by default)
register_level_0_permissions(registry); register_level_0_permissions(registry);
@ -336,7 +338,7 @@ fn register_permissions(registry: &mut PermissionRegistry) {
.unwrap_or_else(|e| tracing::warn!("{e}")); .unwrap_or_else(|e| tracing::warn!("{e}"));
} }
fn register_level_0_permissions(registry: &mut PermissionRegistry) { fn register_level_0_permissions(registry: &PermissionRegistry) {
// Register permissions for builtin commands that are allowed for everyone // Register permissions for builtin commands that are allowed for everyone
registry registry
.register_permission(Permission::new( .register_permission(Permission::new(
@ -362,7 +364,7 @@ fn register_level_0_permissions(registry: &mut PermissionRegistry) {
} }
#[expect(clippy::too_many_lines)] #[expect(clippy::too_many_lines)]
fn register_level_2_permissions(registry: &mut PermissionRegistry) { fn register_level_2_permissions(registry: &PermissionRegistry) {
// Register permissions for commands with PermissionLvl::Two // Register permissions for commands with PermissionLvl::Two
registry registry
.register_permission(Permission::new( .register_permission(Permission::new(
@ -576,7 +578,7 @@ fn register_level_2_permissions(registry: &mut PermissionRegistry) {
.unwrap_or_else(|e| tracing::warn!("{e}")); .unwrap_or_else(|e| tracing::warn!("{e}"));
} }
fn register_level_3_permissions(registry: &mut PermissionRegistry) { fn register_level_3_permissions(registry: &PermissionRegistry) {
// Register permissions for commands with PermissionLvl::Three // Register permissions for commands with PermissionLvl::Three
registry registry
.register_permission(Permission::new( .register_permission(Permission::new(
@ -661,8 +663,7 @@ fn register_level_3_permissions(registry: &mut PermissionRegistry) {
mod override_tests { mod override_tests {
use pumpkin_config::{BasicConfiguration, CommandOverride, CommandsConfig}; use pumpkin_config::{BasicConfiguration, CommandOverride, CommandsConfig};
use pumpkin_util::PermissionLvl; use pumpkin_util::PermissionLvl;
use pumpkin_util::permission::{PermissionDefault, PermissionRegistry}; use pumpkin_util::permission::{PermissionDefault, PermissionManager};
use tokio::sync::RwLock;
use super::default_dispatcher; use super::default_dispatcher;
@ -686,16 +687,16 @@ mod override_tests {
); );
} }
#[tokio::test] #[test]
async fn disabling_a_command_removes_and_hides_it() { fn disabling_a_command_removes_and_hides_it() {
let basic = BasicConfiguration::default(); let basic = BasicConfiguration::default();
let mut commands = CommandsConfig::default(); let mut commands = CommandsConfig::default();
// `gamemode` lives on the legacy dispatcher; disabling it should remove // `gamemode` lives on the legacy dispatcher; disabling it should remove
// it there and flag it on the wrapper. // it there and flag it on the wrapper.
disabled(&mut commands, "gamemode"); disabled(&mut commands, "gamemode");
let registry = RwLock::new(PermissionRegistry::new()); let manager = PermissionManager::new();
let dispatcher = default_dispatcher(&registry, &basic, &commands).await; let dispatcher = default_dispatcher(&manager, &basic, &commands);
assert!(dispatcher.is_disabled("gamemode")); assert!(dispatcher.is_disabled("gamemode"));
assert!( assert!(
@ -708,16 +709,16 @@ mod override_tests {
); );
} }
#[tokio::test] #[test]
async fn disabling_an_alias_turns_off_the_whole_command() { fn disabling_an_alias_turns_off_the_whole_command() {
let basic = BasicConfiguration::default(); let basic = BasicConfiguration::default();
let mut commands = CommandsConfig::default(); let mut commands = CommandsConfig::default();
// `tp` is an alias of `teleport`; disabling it should take the whole // `tp` is an alias of `teleport`; disabling it should take the whole
// command down, including the primary name. // command down, including the primary name.
disabled(&mut commands, "tp"); disabled(&mut commands, "tp");
let registry = RwLock::new(PermissionRegistry::new()); let manager = PermissionManager::new();
let dispatcher = default_dispatcher(&registry, &basic, &commands).await; let dispatcher = default_dispatcher(&manager, &basic, &commands);
assert!(dispatcher.is_disabled("tp")); assert!(dispatcher.is_disabled("tp"));
assert!(dispatcher.is_disabled("teleport")); assert!(dispatcher.is_disabled("teleport"));
@ -725,60 +726,59 @@ mod override_tests {
assert!(dispatcher.fallback_dispatcher.get_tree("teleport").is_err()); assert!(dispatcher.fallback_dispatcher.get_tree("teleport").is_err());
} }
#[tokio::test] #[test]
async fn disabling_a_node_command_also_disables_its_aliases() { fn disabling_a_node_command_also_disables_its_aliases() {
let basic = BasicConfiguration::default(); let basic = BasicConfiguration::default();
let mut commands = CommandsConfig::default(); let mut commands = CommandsConfig::default();
// `help` is a node-based command with the aliases `h` and `?`. // `help` is a node-based command with the aliases `h` and `?`.
disabled(&mut commands, "help"); disabled(&mut commands, "help");
let registry = RwLock::new(PermissionRegistry::new()); let manager = PermissionManager::new();
let dispatcher = default_dispatcher(&registry, &basic, &commands).await; let dispatcher = default_dispatcher(&manager, &basic, &commands);
assert!(dispatcher.is_disabled("help")); assert!(dispatcher.is_disabled("help"));
assert!(dispatcher.is_disabled("h")); assert!(dispatcher.is_disabled("h"));
assert!(dispatcher.is_disabled("?")); assert!(dispatcher.is_disabled("?"));
} }
#[tokio::test] #[test]
async fn override_for_unknown_command_is_ignored() { fn override_for_unknown_command_is_ignored() {
let basic = BasicConfiguration::default(); let basic = BasicConfiguration::default();
let mut commands = CommandsConfig::default(); let mut commands = CommandsConfig::default();
// A command name that does not exist (usually a typo in the config) // A command name that does not exist (usually a typo in the config)
// should be ignored, not silently swallow a real command or panic. // should be ignored, not silently swallow a real command or panic.
disabled(&mut commands, "notacommand"); disabled(&mut commands, "notacommand");
let registry = RwLock::new(PermissionRegistry::new()); let manager = PermissionManager::new();
let dispatcher = default_dispatcher(&registry, &basic, &commands).await; let dispatcher = default_dispatcher(&manager, &basic, &commands);
assert!(!dispatcher.is_disabled("notacommand")); assert!(!dispatcher.is_disabled("notacommand"));
assert!(dispatcher.fallback_dispatcher.get_tree("gamemode").is_ok()); assert!(dispatcher.fallback_dispatcher.get_tree("gamemode").is_ok());
} }
#[tokio::test] #[test]
async fn override_is_case_insensitive() { fn override_is_case_insensitive() {
let basic = BasicConfiguration::default(); let basic = BasicConfiguration::default();
let mut commands = CommandsConfig::default(); let mut commands = CommandsConfig::default();
disabled(&mut commands, "GameMode"); disabled(&mut commands, "GameMode");
let registry = RwLock::new(PermissionRegistry::new()); let manager = PermissionManager::new();
let dispatcher = default_dispatcher(&registry, &basic, &commands).await; let dispatcher = default_dispatcher(&manager, &basic, &commands);
assert!(dispatcher.is_disabled("gamemode")); assert!(dispatcher.is_disabled("gamemode"));
} }
#[tokio::test] #[test]
async fn permission_level_override_rewrites_the_registry_default() { fn permission_level_override_rewrites_the_registry_default() {
let basic = BasicConfiguration::default(); let basic = BasicConfiguration::default();
let mut commands = CommandsConfig::default(); let mut commands = CommandsConfig::default();
// `gamemode` is normally level 2; bump it to owner-only. // `gamemode` is normally level 2; bump it to owner-only.
permission(&mut commands, "gamemode", PermissionLvl::Four); permission(&mut commands, "gamemode", PermissionLvl::Four);
let registry = RwLock::new(PermissionRegistry::new()); let manager = PermissionManager::new();
let _dispatcher = default_dispatcher(&registry, &basic, &commands).await; let _dispatcher = default_dispatcher(&manager, &basic, &commands);
let registry = registry.read().await; let permission = manager
let permission = registry
.get_permission("minecraft:command.gamemode") .get_permission("minecraft:command.gamemode")
.expect("gamemode permission should be registered"); .expect("gamemode permission should be registered");
assert_eq!( assert_eq!(
@ -787,8 +787,8 @@ mod override_tests {
); );
} }
#[tokio::test] #[test]
async fn permission_override_resolves_node_command_by_convention() { fn permission_override_resolves_node_command_by_convention() {
let basic = BasicConfiguration::default(); let basic = BasicConfiguration::default();
let mut commands = CommandsConfig::default(); let mut commands = CommandsConfig::default();
// `kill` is a node-based command whose permission node is not recorded in // `kill` is a node-based command whose permission node is not recorded in
@ -796,11 +796,10 @@ mod override_tests {
// `minecraft:command.kill` naming convention. // `minecraft:command.kill` naming convention.
permission(&mut commands, "kill", PermissionLvl::Four); permission(&mut commands, "kill", PermissionLvl::Four);
let registry = RwLock::new(PermissionRegistry::new()); let manager = PermissionManager::new();
let _dispatcher = default_dispatcher(&registry, &basic, &commands).await; let _dispatcher = default_dispatcher(&manager, &basic, &commands);
let registry = registry.read().await; let permission = manager
let permission = registry
.get_permission("minecraft:command.kill") .get_permission("minecraft:command.kill")
.expect("kill permission should be registered"); .expect("kill permission should be registered");
assert_eq!( assert_eq!(
@ -809,17 +808,16 @@ mod override_tests {
); );
} }
#[tokio::test] #[test]
async fn permission_level_zero_allows_everyone() { fn permission_level_zero_allows_everyone() {
let basic = BasicConfiguration::default(); let basic = BasicConfiguration::default();
let mut commands = CommandsConfig::default(); let mut commands = CommandsConfig::default();
permission(&mut commands, "gamemode", PermissionLvl::Zero); permission(&mut commands, "gamemode", PermissionLvl::Zero);
let registry = RwLock::new(PermissionRegistry::new()); let manager = PermissionManager::new();
let _dispatcher = default_dispatcher(&registry, &basic, &commands).await; let _dispatcher = default_dispatcher(&manager, &basic, &commands);
let registry = registry.read().await; let permission = manager
let permission = registry
.get_permission("minecraft:command.gamemode") .get_permission("minecraft:command.gamemode")
.expect("gamemode permission should be registered"); .expect("gamemode permission should be registered");
assert_eq!(permission.default, PermissionDefault::Allow); assert_eq!(permission.default, PermissionDefault::Allow);

View File

@ -105,7 +105,7 @@ impl SuggestionProvider for OpSuggestionProvider {
} }
} }
pub fn register(dispatcher: &mut CommandDispatcher, registry: &mut PermissionRegistry) { pub fn register(dispatcher: &mut CommandDispatcher, registry: &PermissionRegistry) {
registry.register_permission_or_panic(Permission::new( registry.register_permission_or_panic(Permission::new(
PERMISSION, PERMISSION,
DESCRIPTION, DESCRIPTION,

View File

@ -701,7 +701,7 @@ fn apply_delta(
} }
} }
pub fn register(dispatcher: &mut CommandDispatcher, registry: &mut PermissionRegistry) { pub fn register(dispatcher: &mut CommandDispatcher, registry: &PermissionRegistry) {
registry.register_permission_or_panic(Permission::new( registry.register_permission_or_panic(Permission::new(
PERMISSION, PERMISSION,
DESCRIPTION, DESCRIPTION,

View File

@ -88,7 +88,7 @@ impl CommandExecutor for RandomExecutor {
} }
} }
pub fn register(dispatcher: &mut CommandDispatcher, registry: &mut PermissionRegistry) { pub fn register(dispatcher: &mut CommandDispatcher, registry: &PermissionRegistry) {
registry.register_permission_or_panic(Permission::new( registry.register_permission_or_panic(Permission::new(
PERMISSION, PERMISSION,
DESCRIPTION, DESCRIPTION,

View File

@ -223,7 +223,7 @@ impl CommandExecutor for RecipeTakeExecutor {
} }
} }
pub fn register(dispatcher: &mut CommandDispatcher, registry: &mut PermissionRegistry) { pub fn register(dispatcher: &mut CommandDispatcher, registry: &PermissionRegistry) {
registry.register_permission_or_panic(Permission::new( registry.register_permission_or_panic(Permission::new(
PERMISSION, PERMISSION,
DESCRIPTION, DESCRIPTION,

View File

@ -178,7 +178,7 @@ impl CommandExecutor for RideDismountExecutor {
} }
} }
pub fn register(dispatcher: &mut CommandDispatcher, registry: &mut PermissionRegistry) { pub fn register(dispatcher: &mut CommandDispatcher, registry: &PermissionRegistry) {
registry.register_permission_or_panic(Permission::new( registry.register_permission_or_panic(Permission::new(
PERMISSION, PERMISSION,
DESCRIPTION, DESCRIPTION,

View File

@ -60,7 +60,7 @@ impl CommandExecutor for SaveAllExecutor {
} }
} }
pub fn register(dispatcher: &mut CommandDispatcher, registry: &mut PermissionRegistry) { pub fn register(dispatcher: &mut CommandDispatcher, registry: &PermissionRegistry) {
registry.register_permission_or_panic(Permission::new( registry.register_permission_or_panic(Permission::new(
PERMISSION, PERMISSION,
DESCRIPTION, DESCRIPTION,

View File

@ -53,7 +53,7 @@ impl CommandExecutor for SaveOffExecutor {
} }
} }
pub fn register(dispatcher: &mut CommandDispatcher, registry: &mut PermissionRegistry) { pub fn register(dispatcher: &mut CommandDispatcher, registry: &PermissionRegistry) {
registry.register_permission_or_panic(Permission::new( registry.register_permission_or_panic(Permission::new(
PERMISSION, PERMISSION,
DESCRIPTION, DESCRIPTION,

View File

@ -53,7 +53,7 @@ impl CommandExecutor for SaveOnExecutor {
} }
} }
pub fn register(dispatcher: &mut CommandDispatcher, registry: &mut PermissionRegistry) { pub fn register(dispatcher: &mut CommandDispatcher, registry: &PermissionRegistry) {
registry.register_permission_or_panic(Permission::new( registry.register_permission_or_panic(Permission::new(
PERMISSION, PERMISSION,
DESCRIPTION, DESCRIPTION,

View File

@ -205,7 +205,7 @@ impl CommandExecutor for ObjectivesRemoveExecutor {
} }
} }
pub fn register(dispatcher: &mut CommandDispatcher, registry: &mut PermissionRegistry) { pub fn register(dispatcher: &mut CommandDispatcher, registry: &PermissionRegistry) {
registry.register_permission_or_panic(Permission::new( registry.register_permission_or_panic(Permission::new(
PERMISSION, PERMISSION,
DESCRIPTION, DESCRIPTION,

View File

@ -50,7 +50,7 @@ impl CommandExecutor for SeedCommandExecutor {
} }
} }
pub fn register(dispatcher: &mut CommandDispatcher, registry: &mut PermissionRegistry) { pub fn register(dispatcher: &mut CommandDispatcher, registry: &PermissionRegistry) {
registry.register_permission_or_panic(Permission::new( registry.register_permission_or_panic(Permission::new(
PERMISSION, PERMISSION,
DESCRIPTION, DESCRIPTION,

View File

@ -58,7 +58,7 @@ impl CommandExecutor for SetIdleTimeoutExecutor {
} }
} }
pub fn register(dispatcher: &mut CommandDispatcher, registry: &mut PermissionRegistry) { pub fn register(dispatcher: &mut CommandDispatcher, registry: &PermissionRegistry) {
registry.register_permission_or_panic(Permission::new( registry.register_permission_or_panic(Permission::new(
PERMISSION, PERMISSION,
DESCRIPTION, DESCRIPTION,

View File

@ -320,7 +320,7 @@ impl CommandExecutor for SpreadPlayersExecutor {
} }
} }
pub fn register(dispatcher: &mut CommandDispatcher, registry: &mut PermissionRegistry) { pub fn register(dispatcher: &mut CommandDispatcher, registry: &PermissionRegistry) {
registry.register_permission_or_panic(Permission::new( registry.register_permission_or_panic(Permission::new(
PERMISSION, PERMISSION,
DESCRIPTION, DESCRIPTION,

View File

@ -37,7 +37,7 @@ impl CommandExecutor for StopCommandExecutor {
} }
} }
pub fn register(dispatcher: &mut CommandDispatcher, registry: &mut PermissionRegistry) { pub fn register(dispatcher: &mut CommandDispatcher, registry: &PermissionRegistry) {
registry.register_permission_or_panic(Permission::new( registry.register_permission_or_panic(Permission::new(
PERMISSION, PERMISSION,
DESCRIPTION, DESCRIPTION,

View File

@ -177,7 +177,7 @@ impl CommandExecutor for ListExecutor {
} }
} }
pub fn register(dispatcher: &mut CommandDispatcher, registry: &mut PermissionRegistry) { pub fn register(dispatcher: &mut CommandDispatcher, registry: &PermissionRegistry) {
registry.register_permission_or_panic(Permission::new( registry.register_permission_or_panic(Permission::new(
PERMISSION, PERMISSION,
DESCRIPTION, DESCRIPTION,

View File

@ -1114,7 +1114,7 @@ fn modify_branch() -> LiteralArgumentBuilder {
) )
} }
pub fn register(dispatcher: &mut CommandDispatcher, registry: &mut PermissionRegistry) { pub fn register(dispatcher: &mut CommandDispatcher, registry: &PermissionRegistry) {
registry.register_permission_or_panic(Permission::new( registry.register_permission_or_panic(Permission::new(
PERMISSION, PERMISSION,
DESCRIPTION, DESCRIPTION,

View File

@ -81,7 +81,7 @@ impl CommandExecutor for TeamMsgCommandExecutor {
} }
} }
pub fn register(dispatcher: &mut CommandDispatcher, registry: &mut PermissionRegistry) { pub fn register(dispatcher: &mut CommandDispatcher, registry: &PermissionRegistry) {
registry.register_permission_or_panic(Permission::new( registry.register_permission_or_panic(Permission::new(
PERMISSION, PERMISSION,
DESCRIPTION, DESCRIPTION,

View File

@ -366,7 +366,7 @@ const fn time_argument() -> TimeArgumentType {
TimeArgumentType::new(1) TimeArgumentType::new(1)
} }
pub fn register(dispatcher: &mut CommandDispatcher, registry: &mut PermissionRegistry) { pub fn register(dispatcher: &mut CommandDispatcher, registry: &PermissionRegistry) {
registry.register_permission_or_panic(Permission::new( registry.register_permission_or_panic(Permission::new(
PERMISSION, PERMISSION,
DESCRIPTION, DESCRIPTION,

View File

@ -234,7 +234,7 @@ impl CommandExecutor for SetTriggerExecutor {
} }
} }
pub fn register(dispatcher: &mut CommandDispatcher, registry: &mut PermissionRegistry) { pub fn register(dispatcher: &mut CommandDispatcher, registry: &PermissionRegistry) {
registry.register_permission_or_panic(Permission::new( registry.register_permission_or_panic(Permission::new(
PERMISSION, PERMISSION,
DESCRIPTION, DESCRIPTION,

View File

@ -768,11 +768,10 @@ impl CommandDispatcher {
mod test { mod test {
use pumpkin_config::BasicConfiguration; use pumpkin_config::BasicConfiguration;
use pumpkin_data::translation; use pumpkin_data::translation;
use pumpkin_util::permission::PermissionRegistry; use pumpkin_util::permission::PermissionManager;
use pumpkin_util::text::TextContent; use pumpkin_util::text::TextContent;
use pumpkin_util::text::click::ClickEvent; use pumpkin_util::text::click::ClickEvent;
use pumpkin_util::text::color::{Color, NamedColor}; use pumpkin_util::text::color::{Color, NamedColor};
use tokio::sync::RwLock;
use super::{ use super::{
PathParsingFailure, render_syntax_error_messages, select_parse_error, PathParsingFailure, render_syntax_error_messages, select_parse_error,
@ -789,26 +788,24 @@ mod test {
} }
} }
#[tokio::test] #[test]
async fn dynamic_command() { fn dynamic_command() {
let config = BasicConfiguration::default(); let config = BasicConfiguration::default();
let commands_config = pumpkin_config::CommandsConfig::default(); let commands_config = pumpkin_config::CommandsConfig::default();
let registry = RwLock::new(PermissionRegistry::new()); let manager = PermissionManager::new();
let mut dispatcher = default_dispatcher(&registry, &config, &commands_config) let mut dispatcher =
.await default_dispatcher(&manager, &config, &commands_config).fallback_dispatcher;
.fallback_dispatcher;
let tree = CommandTree::new(["test"], "test_desc"); let tree = CommandTree::new(["test"], "test_desc");
dispatcher.register(tree, "minecraft:test"); dispatcher.register(tree, "minecraft:test");
} }
#[tokio::test] #[test]
async fn pumpkin_command_aliases() { fn pumpkin_command_aliases() {
let config = BasicConfiguration::default(); let config = BasicConfiguration::default();
let commands_config = pumpkin_config::CommandsConfig::default(); let commands_config = pumpkin_config::CommandsConfig::default();
let registry = RwLock::new(PermissionRegistry::new()); let manager = PermissionManager::new();
let dispatcher = default_dispatcher(&registry, &config, &commands_config) let dispatcher =
.await default_dispatcher(&manager, &config, &commands_config).fallback_dispatcher;
.fallback_dispatcher;
let pumpkin_tree = dispatcher.get_tree("pumpkin").unwrap(); let pumpkin_tree = dispatcher.get_tree("pumpkin").unwrap();
let version_tree = dispatcher.get_tree("version").unwrap(); let version_tree = dispatcher.get_tree("version").unwrap();

View File

@ -174,8 +174,7 @@ impl CommandSender {
Self::Console | Self::Rcon(_) => true, // Console and RCON always have all permissions Self::Console | Self::Rcon(_) => true, // Console and RCON always have all permissions
Self::Player(p) => p.has_permission(server, node).await, Self::Player(p) => p.has_permission(server, node).await,
Self::CommandBlock(..) | Self::Dummy => { Self::CommandBlock(..) | Self::Dummy => {
let perm_reg = server.permission_registry.read().await; let Some(p) = server.permission_manager.get_permission(node) else {
let Some(p) = perm_reg.get_permission(node) else {
return false; return false;
}; };
match p.default { match p.default {

View File

@ -5294,11 +5294,11 @@ impl Player {
} }
pub async fn has_permission(self: &Arc<Self>, server: &Server, node: &str) -> bool { pub async fn has_permission(self: &Arc<Self>, server: &Server, node: &str) -> bool {
let perm_manager = server.permission_manager.read().await; let result = server.permission_manager.has_permission(
let result = perm_manager &self.gameprofile.id,
.has_permission(&self.gameprofile.id, node, self.permission_lvl.load()) node,
.await; self.permission_lvl.load(),
drop(perm_manager); );
let mut event = PlayerPermissionCheckEvent::new(self.clone(), node.to_string(), result); let mut event = PlayerPermissionCheckEvent::new(self.clone(), node.to_string(), result);
let server_arc = self.world().server.upgrade(); let server_arc = self.world().server.upgrade();

View File

@ -37,7 +37,7 @@ pub struct Context {
pub server: Arc<Server>, pub server: Arc<Server>,
pub handlers: Arc<RwLock<HandlerMap>>, pub handlers: Arc<RwLock<HandlerMap>>,
pub plugin_manager: Arc<PluginManager>, pub plugin_manager: Arc<PluginManager>,
pub permission_manager: Arc<RwLock<PermissionManager>>, pub permission_manager: Arc<PermissionManager>,
pub logger: Arc<OnceLock<LoggerOption>>, pub logger: Arc<OnceLock<LoggerOption>>,
} }
impl Context { impl Context {
@ -229,7 +229,7 @@ impl Context {
} }
/// Register a permission for this plugin /// Register a permission for this plugin
pub async fn register_permission(&self, permission: Permission) -> Result<(), String> { pub fn register_permission(&self, permission: Permission) -> Result<(), String> {
// Ensure the permission has the correct namespace // Ensure the permission has the correct namespace
if !permission if !permission
.node .node
@ -241,23 +241,20 @@ impl Context {
)); ));
} }
let registry = &self.permission_manager.read().await.registry; self.permission_manager.register_permission(permission)
registry.write().await.register_permission(permission)
} }
/// Check if a player has a permission /// Check if a player has a permission
pub async fn player_has_permission(&self, player_uuid: &uuid::Uuid, permission: &str) -> bool { #[must_use]
let permission_manager = self.permission_manager.read().await; pub fn player_has_permission(&self, player_uuid: &uuid::Uuid, permission: &str) -> bool {
// If the player isn't online, we need to find their op level // If the player isn't online, we need to find their op level
let player_op_level = self let player_op_level = self
.server .server
.get_player_by_uuid(*player_uuid) .get_player_by_uuid(*player_uuid)
.map_or(PermissionLvl::Zero, |player| player.permission_lvl.load()); .map_or(PermissionLvl::Zero, |player| player.permission_lvl.load());
permission_manager self.permission_manager
.has_permission(player_uuid, permission, player_op_level) .has_permission(player_uuid, permission, player_op_level)
.await
} }
/// Asynchronously registers an event handler for a specific event type. /// Asynchronously registers an event handler for a specific event type.

View File

@ -1963,10 +1963,7 @@ impl pumpkin::plugin::context::HostContext for PluginHostState {
let context_res = self let context_res = self
.resource_table .resource_table
.get_mut::<ContextResource>(&Resource::new_own(context.rep()))?; .get_mut::<ContextResource>(&Resource::new_own(context.rep()))?;
Ok(context_res Ok(context_res.provider.register_permission(util_permission))
.provider
.register_permission(util_permission)
.await)
} }
async fn get_data_folder(&mut self, _context: Resource<Context>) -> wasmtime::Result<String> { async fn get_data_folder(&mut self, _context: Resource<Context>) -> wasmtime::Result<String> {

View File

@ -1365,11 +1365,9 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
let player = player_from_resource(self, &player)?; let player = player_from_resource(self, &player)?;
let server = self.server.as_ref().expect("server not available"); let server = self.server.as_ref().expect("server not available");
let mut perm_manager = server.permission_manager.write().await; server
let attachment = perm_manager.get_attachment(player.gameprofile.id); .permission_manager
drop(perm_manager); .set_permission(player.gameprofile.id, node, value);
attachment.write().await.set_permission(&node, value);
Ok(()) Ok(())
} }
@ -1382,11 +1380,9 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
let player = player_from_resource(self, &player)?; let player = player_from_resource(self, &player)?;
let server = self.server.as_ref().expect("server not available"); let server = self.server.as_ref().expect("server not available");
let mut perm_manager = server.permission_manager.write().await; server
let attachment = perm_manager.get_attachment(player.gameprofile.id); .permission_manager
drop(perm_manager); .unset_permission(&player.gameprofile.id, &node);
attachment.write().await.unset_permission(&node);
Ok(()) Ok(())
} }
@ -1399,11 +1395,9 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
let player = player_from_resource(self, &player)?; let player = player_from_resource(self, &player)?;
let server = self.server.as_ref().expect("server not available"); let server = self.server.as_ref().expect("server not available");
let mut perm_manager = server.permission_manager.write().await; Ok(server
let attachment = perm_manager.get_attachment(player.gameprofile.id); .permission_manager
drop(perm_manager); .has_permission_set(&player.gameprofile.id, &node))
Ok(attachment.read().await.has_permission_set(&node))
} }
async fn has_permission( async fn has_permission(

View File

@ -23,7 +23,7 @@ use key_store::KeyStore;
use pumpkin_config::{AdvancedConfiguration, BasicConfiguration}; use pumpkin_config::{AdvancedConfiguration, BasicConfiguration};
use pumpkin_data::dimension::Dimension; use pumpkin_data::dimension::Dimension;
use pumpkin_data::entity::EntityType; use pumpkin_data::entity::EntityType;
use pumpkin_util::permission::{PermissionManager, PermissionRegistry}; use pumpkin_util::permission::PermissionManager;
use pumpkin_util::text::color::NamedColor; use pumpkin_util::text::color::NamedColor;
use pumpkin_world::dimension::into_level; use pumpkin_world::dimension::into_level;
use pumpkin_world::world::WorldPortalExt; use pumpkin_world::world::WorldPortalExt;
@ -47,7 +47,7 @@ use std::net::IpAddr;
use std::sync::Arc; use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicI32, AtomicI64, AtomicU32}; use std::sync::atomic::{AtomicBool, AtomicI32, AtomicI64, AtomicU32};
use std::{future::Future, sync::atomic::Ordering, time::Duration}; use std::{future::Future, sync::atomic::Ordering, time::Duration};
use tokio::sync::{Mutex, OnceCell, RwLock}; use tokio::sync::{Mutex, OnceCell};
use tokio::task::{JoinHandle, JoinSet}; use tokio::task::{JoinHandle, JoinSet};
use tokio_util::task::TaskTracker; use tokio_util::task::TaskTracker;
@ -79,9 +79,7 @@ pub struct Server {
pub plugin_manager: Arc<PluginManager>, pub plugin_manager: Arc<PluginManager>,
/// Permission manager for the server. /// Permission manager for the server.
pub permission_manager: Arc<RwLock<PermissionManager>>, pub permission_manager: Arc<PermissionManager>,
/// Permission registry for the server.
pub permission_registry: Arc<RwLock<PermissionRegistry>>,
/// Handles cryptographic keys for secure communication. /// Handles cryptographic keys for secure communication.
key_store: OnceCell<Arc<KeyStore>>, key_store: OnceCell<Arc<KeyStore>>,
@ -154,16 +152,13 @@ impl Server {
advanced_config: AdvancedConfiguration, advanced_config: AdvancedConfiguration,
vanilla_data: VanillaData, vanilla_data: VanillaData,
) -> Arc<Self> { ) -> Arc<Self> {
let permission_registry = Arc::new(RwLock::new(PermissionRegistry::new())); let permission_manager = Arc::new(PermissionManager::new());
// First register the default commands. After that, plugins can put in their own. // First register the default commands. After that, plugins can put in their own.
let command_dispatcher = ArcSwap::from_pointee( let command_dispatcher = ArcSwap::from_pointee(default_dispatcher(
default_dispatcher( &permission_manager,
&permission_registry, &basic_config,
&basic_config, &advanced_config.commands,
&advanced_config.commands, ));
)
.await,
);
crate::command::set_broadcast_console_to_ops( crate::command::set_broadcast_console_to_ops(
advanced_config.commands.broadcast_console_to_ops, advanced_config.commands.broadcast_console_to_ops,
@ -264,10 +259,7 @@ impl Server {
advanced_config, advanced_config,
data: vanilla_data, data: vanilla_data,
plugin_manager: Arc::new(PluginManager::new()), plugin_manager: Arc::new(PluginManager::new()),
permission_manager: Arc::new(RwLock::new(PermissionManager::new( permission_manager,
permission_registry.clone(),
))),
permission_registry,
container_id: 0.into(), container_id: 0.into(),
recipe_manager: Arc::new(recipe::RecipeManager::new()), recipe_manager: Arc::new(recipe::RecipeManager::new()),
enchantment_manager: Arc::new(enchantment::EnchantmentManager::new()), enchantment_manager: Arc::new(enchantment::EnchantmentManager::new()),