mirror of
https://github.com/Pumpkin-MC/Pumpkin.git
synced 2026-08-30 20:14:23 +00:00
chore: switch command_dispatcher to ArcSwap
i need this for patchbukkit, but this is also safer in terms of deadlocks
This commit is contained in:
@@ -141,8 +141,7 @@ impl CommandBlock {
|
||||
|
||||
server
|
||||
.command_dispatcher
|
||||
.read()
|
||||
.await
|
||||
.load()
|
||||
.handle_command(&source, command)
|
||||
.await;
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ impl ArgumentConsumer for CommandTreeArgumentConsumer {
|
||||
};
|
||||
|
||||
Box::pin(async move {
|
||||
let dispatcher = server.command_dispatcher.read().await;
|
||||
let dispatcher = server.command_dispatcher.load();
|
||||
|
||||
dispatcher
|
||||
.fallback_dispatcher
|
||||
@@ -61,7 +61,7 @@ impl ArgumentConsumer for CommandTreeArgumentConsumer {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let dispatcher = server.command_dispatcher.read().await;
|
||||
let dispatcher = server.command_dispatcher.load();
|
||||
let suggestions = dispatcher
|
||||
.fallback_dispatcher
|
||||
.commands
|
||||
|
||||
@@ -41,7 +41,7 @@ impl CommandExecutor for Executor {
|
||||
succeeded_deops += 1;
|
||||
|
||||
if let Some(player) = server.get_player_by_uuid(profile.id) {
|
||||
let command_dispatcher = server.command_dispatcher.read().await;
|
||||
let command_dispatcher = server.command_dispatcher.load();
|
||||
player
|
||||
.set_permission_lvl(
|
||||
server,
|
||||
|
||||
@@ -116,7 +116,7 @@ impl HelpCommandExecutor {
|
||||
Box::pin(async move {
|
||||
let server = context.server();
|
||||
|
||||
let dispatcher = server.command_dispatcher.read().await;
|
||||
let dispatcher = server.command_dispatcher.load();
|
||||
let commands = dispatcher
|
||||
.get_all_permitted_commands_usage(&context.source)
|
||||
.await;
|
||||
@@ -206,7 +206,7 @@ impl HelpCommandExecutor {
|
||||
|
||||
fn command<'a>(context: &'a CommandContext, command: &'a str) -> CommandExecutorResult<'a> {
|
||||
Box::pin(async move {
|
||||
let dispatcher = context.server().command_dispatcher.read().await;
|
||||
let dispatcher = context.server().command_dispatcher.load();
|
||||
|
||||
let Some((description, usage)) = dispatcher
|
||||
.get_permitted_command_usage(&context.source, command)
|
||||
@@ -274,7 +274,7 @@ impl HelpCommandExecutor {
|
||||
fn plugin<'a>(context: &'a CommandContext, plugin_name: &'a str) -> CommandExecutorResult<'a> {
|
||||
Box::pin(async move {
|
||||
let server = context.server();
|
||||
let dispatcher = server.command_dispatcher.read().await;
|
||||
let dispatcher = server.command_dispatcher.load();
|
||||
let commands = dispatcher
|
||||
.get_all_permitted_commands_usage_by_plugin(&context.source, plugin_name)
|
||||
.await;
|
||||
@@ -335,7 +335,7 @@ impl HelpCommandExecutor {
|
||||
Box::pin(async move {
|
||||
// Prioritize commands ig
|
||||
{
|
||||
let dispatcher = context.server().command_dispatcher.read().await;
|
||||
let dispatcher = context.server().command_dispatcher.load();
|
||||
if dispatcher
|
||||
.get_permitted_command_usage(&context.source, input)
|
||||
.await
|
||||
@@ -346,7 +346,7 @@ impl HelpCommandExecutor {
|
||||
}
|
||||
|
||||
{
|
||||
let dispatcher = context.server().command_dispatcher.read().await;
|
||||
let dispatcher = context.server().command_dispatcher.load();
|
||||
let plugin_commands = dispatcher
|
||||
.get_all_permitted_commands_usage_by_plugin(&context.source, input)
|
||||
.await;
|
||||
|
||||
@@ -50,7 +50,7 @@ impl CommandExecutor for OpCommandExecutor {
|
||||
}
|
||||
|
||||
if let Some(player) = server.get_player_by_uuid(profile.id) {
|
||||
let command_dispatcher = server.command_dispatcher.read().await;
|
||||
let command_dispatcher = server.command_dispatcher.load();
|
||||
player
|
||||
.set_permission_lvl(server, new_level, &command_dispatcher)
|
||||
.await;
|
||||
|
||||
@@ -228,7 +228,7 @@ fn path_failure(
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Default, Clone)]
|
||||
pub struct CommandDispatcher {
|
||||
pub commands: FxHashMap<String, Command>,
|
||||
pub permissions: FxHashMap<String, String>,
|
||||
|
||||
@@ -95,6 +95,7 @@ pub static RESULT_DEFERRER: LazyLock<Arc<ResultDeferrer>> =
|
||||
///
|
||||
/// Internally, this dispatcher stores a [`Tree`]. Refer to its documentation
|
||||
/// for more information about nodes.
|
||||
#[derive(Clone)]
|
||||
pub struct CommandDispatcher {
|
||||
pub tree: Tree,
|
||||
pub consumer: Arc<dyn ResultConsumer>,
|
||||
|
||||
@@ -67,6 +67,7 @@ impl Debug for NodeType {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Command {
|
||||
Tree(CommandTree),
|
||||
Alias(String),
|
||||
|
||||
@@ -722,8 +722,7 @@ fn setup_stdin_console(server: Arc<Server>) {
|
||||
if !event.cancelled {
|
||||
server
|
||||
.command_dispatcher
|
||||
.read()
|
||||
.await
|
||||
.load()
|
||||
.handle_command(
|
||||
&command::CommandSender::Console.into_source(&server).await,
|
||||
command.as_str(),
|
||||
@@ -795,8 +794,7 @@ fn setup_console(mut rl: Editor<PumpkinCommandCompleter, FileHistory>, server: A
|
||||
if !event.cancelled {
|
||||
server
|
||||
.command_dispatcher
|
||||
.read()
|
||||
.await
|
||||
.load()
|
||||
.handle_command(
|
||||
&command::CommandSender::Console.into_source(&server).await,
|
||||
&line,
|
||||
|
||||
@@ -476,7 +476,7 @@ impl Completer for PumpkinCommandCompleter {
|
||||
let ends_with_space = cmd.ends_with(' ');
|
||||
|
||||
handle.block_on(async {
|
||||
let dispatcher = server.command_dispatcher.read().await;
|
||||
let dispatcher = server.command_dispatcher.load();
|
||||
let source = CommandSender::Console.into_source(server).await;
|
||||
|
||||
// Temporary setups to unify both dispatchers for now:
|
||||
|
||||
@@ -31,7 +31,7 @@ impl BedrockClient {
|
||||
// Some commands can take a long time to execute. If they do, they block packet processing for the player.
|
||||
// That's why we will spawn a task instead.
|
||||
server.spawn_task(async move {
|
||||
let dispatcher = server_clone.command_dispatcher.read().await;
|
||||
let dispatcher = server_clone.command_dispatcher.load();
|
||||
dispatcher.handle_command(
|
||||
&player_clone.get_command_source(&server_clone).await,
|
||||
&command_clone
|
||||
|
||||
@@ -28,7 +28,7 @@ impl JavaClient {
|
||||
// Some commands can take a long time to execute. If they do, they block packet processing for the player.
|
||||
// That's why we will spawn a task instead.
|
||||
server.spawn_task(async move {
|
||||
let dispatcher = server_clone.command_dispatcher.read().await;
|
||||
let dispatcher = server_clone.command_dispatcher.load();
|
||||
dispatcher.handle_command(
|
||||
&player_clone.get_command_source(&server_clone).await,
|
||||
&command_clone
|
||||
|
||||
@@ -19,8 +19,7 @@ impl JavaClient {
|
||||
|
||||
let suggestions = server
|
||||
.command_dispatcher
|
||||
.read()
|
||||
.await
|
||||
.load()
|
||||
.suggest(cmd, &player.get_command_source(server).await)
|
||||
.await;
|
||||
|
||||
|
||||
@@ -146,8 +146,7 @@ impl RCONClient {
|
||||
let _ = tokio::spawn(async move {
|
||||
server_clone
|
||||
.command_dispatcher
|
||||
.read()
|
||||
.await
|
||||
.load()
|
||||
.handle_command(&command_source, &packet_body)
|
||||
.await;
|
||||
})
|
||||
|
||||
@@ -175,12 +175,13 @@ impl Context {
|
||||
format!("{}:{permission}", self.metadata.name)
|
||||
};
|
||||
|
||||
{
|
||||
let mut dispatcher_lock = self.server.command_dispatcher.write().await;
|
||||
dispatcher_lock
|
||||
self.server.command_dispatcher.rcu(|dispatcher| {
|
||||
let mut new_dispatcher = (**dispatcher).clone();
|
||||
new_dispatcher
|
||||
.fallback_dispatcher
|
||||
.register(tree, full_permission_node);
|
||||
};
|
||||
.register(tree.clone(), full_permission_node.clone());
|
||||
Arc::new(new_dispatcher)
|
||||
});
|
||||
|
||||
self.reload_commands_for_everyone().await;
|
||||
}
|
||||
@@ -190,10 +191,11 @@ impl Context {
|
||||
/// # Arguments
|
||||
/// - `name`: The name of the command to unregister.
|
||||
pub async fn unregister_command(&self, name: &str) {
|
||||
{
|
||||
let mut dispatcher_lock = self.server.command_dispatcher.write().await;
|
||||
dispatcher_lock.fallback_dispatcher.unregister(name);
|
||||
};
|
||||
self.server.command_dispatcher.rcu(|dispatcher| {
|
||||
let mut new_dispatcher = (**dispatcher).clone();
|
||||
new_dispatcher.fallback_dispatcher.unregister(name);
|
||||
Arc::new(new_dispatcher)
|
||||
});
|
||||
|
||||
self.reload_commands_for_everyone().await;
|
||||
}
|
||||
@@ -212,7 +214,7 @@ impl Context {
|
||||
/// # Arguments
|
||||
/// - `player`: The player for which the commands will be reloaded.
|
||||
pub async fn reload_commands_for(&self, player: &Arc<Player>) {
|
||||
let command_dispatcher = self.server.command_dispatcher.read().await;
|
||||
let command_dispatcher = self.server.command_dispatcher.load();
|
||||
if let ClientPlatform::Bedrock(_) = player.client.as_ref() {
|
||||
client_suggestions::send_bedrock_commands_packet(
|
||||
player,
|
||||
|
||||
@@ -1349,7 +1349,7 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
|
||||
let player = player_from_resource(self, &player)?;
|
||||
let server = self.server.as_ref().expect("server not available");
|
||||
let level = from_wit_permission_level(level);
|
||||
let command_dispatcher = server.command_dispatcher.read().await;
|
||||
let command_dispatcher = server.command_dispatcher.load();
|
||||
player
|
||||
.set_permission_lvl(server, level, &command_dispatcher)
|
||||
.await;
|
||||
|
||||
@@ -348,7 +348,7 @@ impl pumpkin::plugin::server::HostServer for PluginHostState {
|
||||
}
|
||||
};
|
||||
|
||||
let dispatcher = server.command_dispatcher.read().await;
|
||||
let dispatcher = server.command_dispatcher.load();
|
||||
dispatcher
|
||||
.handle_command(&native_sender.into_source(server).await, &command)
|
||||
.await;
|
||||
@@ -700,7 +700,7 @@ impl pumpkin::plugin::server::HostOpManager for PluginHostState {
|
||||
drop(config);
|
||||
|
||||
if let Some(player) = server.get_player_by_uuid(uuid) {
|
||||
let command_dispatcher = server.command_dispatcher.read().await;
|
||||
let command_dispatcher = server.command_dispatcher.load();
|
||||
player
|
||||
.set_permission_lvl(server, internal_level, &command_dispatcher)
|
||||
.await;
|
||||
@@ -727,7 +727,7 @@ impl pumpkin::plugin::server::HostOpManager for PluginHostState {
|
||||
drop(config);
|
||||
|
||||
if let Some(player) = server.get_player_by_uuid(uuid) {
|
||||
let command_dispatcher = server.command_dispatcher.read().await;
|
||||
let command_dispatcher = server.command_dispatcher.load();
|
||||
player
|
||||
.set_permission_lvl(
|
||||
server,
|
||||
|
||||
@@ -94,7 +94,7 @@ pub struct Server {
|
||||
/// Saves server branding information.
|
||||
branding: CachedBranding,
|
||||
/// Saves and dispatches commands to appropriate handlers.
|
||||
pub command_dispatcher: RwLock<CommandDispatcher>,
|
||||
pub command_dispatcher: ArcSwap<CommandDispatcher>,
|
||||
/// Block behaviour.
|
||||
pub block_registry: Arc<BlockRegistry>,
|
||||
/// Item behaviour.
|
||||
@@ -156,7 +156,7 @@ impl Server {
|
||||
) -> Arc<Self> {
|
||||
let permission_registry = Arc::new(RwLock::new(PermissionRegistry::new()));
|
||||
// First register the default commands. After that, plugins can put in their own.
|
||||
let command_dispatcher = RwLock::new(
|
||||
let command_dispatcher = ArcSwap::from_pointee(
|
||||
default_dispatcher(
|
||||
&permission_registry,
|
||||
&basic_config,
|
||||
|
||||
@@ -2714,7 +2714,7 @@ impl World {
|
||||
player.send_abilities_update().await;
|
||||
|
||||
{
|
||||
let command_dispatcher = server.command_dispatcher.read().await;
|
||||
let command_dispatcher = server.command_dispatcher.load();
|
||||
client_suggestions::send_bedrock_commands_packet(&player, server, &command_dispatcher)
|
||||
.await;
|
||||
};
|
||||
@@ -3092,7 +3092,7 @@ impl World {
|
||||
// Difficulty of the world
|
||||
player.send_difficulty_update().await;
|
||||
{
|
||||
let command_dispatcher = server.command_dispatcher.read().await;
|
||||
let command_dispatcher = server.command_dispatcher.load();
|
||||
|
||||
client_suggestions::send_c_commands_packet(player, server, &command_dispatcher).await;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user