Refactor command code
This commit is contained in:
parent
d2ee270e82
commit
196acf8865
@ -4,7 +4,8 @@ import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.command.BlockCommandSender;
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.permissions.PermissionAttachment;
|
||||
import org.bukkit.permissions.PermissionAttachmentInfo;
|
||||
@ -14,7 +15,12 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
public class PatchBukkitCommandSender implements CommandSender {
|
||||
public class PatchBukkitBlockCommandSender implements BlockCommandSender {
|
||||
@NotNull
|
||||
public Block getBlock() {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'getBlock'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPermissionSet(@NotNull String name) {
|
||||
@ -141,5 +147,5 @@ public class PatchBukkitCommandSender implements CommandSender {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'name'");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -44,6 +44,9 @@ public class PatchBukkitWorld
|
||||
return instances.computeIfAbsent(uuid, PatchBukkitWorld::new);
|
||||
}
|
||||
|
||||
public static PatchBukkitWorld getOrCreate(String uuid) {
|
||||
return getOrCreate(UUID.fromString(uuid));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVoidDamageEnabled() {
|
||||
|
||||
144
rust/src/commands/mod.rs
Normal file
144
rust/src/commands/mod.rs
Normal file
@ -0,0 +1,144 @@
|
||||
use pumpkin::{
|
||||
command::{
|
||||
CommandExecutor, CommandSender,
|
||||
args::{Arg, ArgumentConsumer, GetClientSideArgParser, SuggestResult},
|
||||
},
|
||||
entity::EntityBase,
|
||||
};
|
||||
use pumpkin_protocol::java::client::play::{
|
||||
ArgumentType, StringProtoArgBehavior, SuggestionProviders,
|
||||
};
|
||||
use tokio::sync::{mpsc, oneshot};
|
||||
|
||||
use crate::java::jvm::commands::{JvmCommand, Location, Rotation};
|
||||
|
||||
pub struct JavaCommandExecutor {
|
||||
pub cmd_name: String,
|
||||
pub command_tx: mpsc::Sender<JvmCommand>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum SimpleCommandSender {
|
||||
Console,
|
||||
/// UUID
|
||||
Player(String),
|
||||
}
|
||||
|
||||
pub struct AnyCommandNode {
|
||||
command_name: String,
|
||||
command_tx: mpsc::Sender<JvmCommand>,
|
||||
}
|
||||
|
||||
impl GetClientSideArgParser for AnyCommandNode {
|
||||
fn get_client_side_parser(&self) -> ArgumentType<'_> {
|
||||
ArgumentType::String(StringProtoArgBehavior::GreedyPhrase)
|
||||
}
|
||||
|
||||
fn get_client_side_suggestion_type_override(&self) -> Option<SuggestionProviders> {
|
||||
Some(SuggestionProviders::AskServer)
|
||||
}
|
||||
}
|
||||
|
||||
impl ArgumentConsumer for AnyCommandNode {
|
||||
fn consume<'a>(
|
||||
&'a self,
|
||||
_sender: &'a pumpkin::command::CommandSender,
|
||||
_server: &'a pumpkin::server::Server,
|
||||
args: &mut pumpkin::command::tree::RawArgs<'a>,
|
||||
) -> pumpkin::command::args::ConsumeResult<'a> {
|
||||
let first_word_opt = args.pop();
|
||||
|
||||
let mut msg = match first_word_opt {
|
||||
Some(word) => word.to_string(),
|
||||
None => return Box::pin(async { None }),
|
||||
};
|
||||
|
||||
while let Some(word) = args.pop() {
|
||||
msg.push(' ');
|
||||
msg.push_str(word);
|
||||
}
|
||||
|
||||
Box::pin(async move { Some(Arg::Msg(msg)) })
|
||||
}
|
||||
|
||||
fn suggest<'a>(
|
||||
&'a self,
|
||||
sender: &pumpkin::command::CommandSender,
|
||||
_server: &'a pumpkin::server::Server,
|
||||
input: &'a str,
|
||||
) -> SuggestResult<'a> {
|
||||
let location = if let Some(position) = sender.position()
|
||||
&& let Some(world) = sender.world()
|
||||
{
|
||||
let rotation = if let Some(player) = sender.as_player() {
|
||||
let entity = player.get_entity();
|
||||
let yaw = entity.yaw.load();
|
||||
let pitch = entity.pitch.load();
|
||||
Some(Rotation::new(yaw, pitch))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Some(Location::new(
|
||||
world.uuid, position.x, position.y, position.z, rotation,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let command_name = self.command_name.clone();
|
||||
let command_sender: SimpleCommandSender = sender.into();
|
||||
|
||||
Box::pin(async move {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
self.command_tx
|
||||
.send(JvmCommand::GetCommandTabComplete {
|
||||
command_sender,
|
||||
cmd_name: command_name,
|
||||
respond_to: tx,
|
||||
args: input.split(' ').map(|arg| arg.to_string()).collect(),
|
||||
location,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
rx.await.unwrap()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<SimpleCommandSender> for &CommandSender {
|
||||
fn into(self) -> SimpleCommandSender {
|
||||
match self {
|
||||
CommandSender::Rcon(_mutex) => todo!(),
|
||||
CommandSender::Console => SimpleCommandSender::Console,
|
||||
CommandSender::Player(player) => {
|
||||
SimpleCommandSender::Player(player.gameprofile.id.to_string())
|
||||
}
|
||||
CommandSender::CommandBlock(_block_entity, _world) => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CommandExecutor for JavaCommandExecutor {
|
||||
fn execute<'a>(
|
||||
&'a self,
|
||||
sender: &'a pumpkin::command::CommandSender,
|
||||
_server: &'a pumpkin::server::Server,
|
||||
_args: &'a pumpkin::command::args::ConsumedArgs<'a>,
|
||||
) -> pumpkin::command::CommandResult<'a> {
|
||||
Box::pin(async move {
|
||||
let (tx, _rx) = oneshot::channel();
|
||||
self.command_tx
|
||||
.send(JvmCommand::TriggerCommand {
|
||||
cmd_name: self.cmd_name.clone(),
|
||||
respond_to: tx,
|
||||
command_sender: sender.into(),
|
||||
args: vec![self.cmd_name.clone()],
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -1,56 +0,0 @@
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use j4rs::Instance;
|
||||
use pumpkin::command::CommandExecutor;
|
||||
use tokio::sync::{mpsc, oneshot};
|
||||
|
||||
use crate::java::jvm::commands::JvmCommand;
|
||||
|
||||
pub struct JavaCommandExecutor {
|
||||
pub cmd_name: String,
|
||||
pub command_tx: mpsc::Sender<JvmCommand>,
|
||||
pub command: Arc<Mutex<Instance>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum SimpleCommandSender {
|
||||
Console,
|
||||
// UUID
|
||||
Player(String),
|
||||
}
|
||||
|
||||
impl CommandExecutor for JavaCommandExecutor {
|
||||
fn execute<'a>(
|
||||
&'a self,
|
||||
sender: &'a pumpkin::command::CommandSender,
|
||||
_server: &'a pumpkin::server::Server,
|
||||
_args: &'a pumpkin::command::args::ConsumedArgs<'a>,
|
||||
) -> pumpkin::command::CommandResult<'a> {
|
||||
Box::pin(async move {
|
||||
let (tx, _rx) = oneshot::channel();
|
||||
let sender = match sender {
|
||||
pumpkin::command::CommandSender::Rcon(_mutex) => todo!(),
|
||||
pumpkin::command::CommandSender::Console => SimpleCommandSender::Console,
|
||||
pumpkin::command::CommandSender::Player(player) => {
|
||||
SimpleCommandSender::Player(player.gameprofile.id.to_string())
|
||||
}
|
||||
pumpkin::command::CommandSender::CommandBlock(_block_entity, _world) => todo!(),
|
||||
};
|
||||
self.command_tx
|
||||
.send(JvmCommand::TriggerCommand {
|
||||
cmd_name: self.cmd_name.clone(),
|
||||
respond_to: tx,
|
||||
command_sender: sender.clone(),
|
||||
command: self.command.clone(),
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// match rx.await.unwrap().unwrap() {
|
||||
// Event::PlayerJoinEvent(player_join_event) => *event = player_join_event,
|
||||
// _ => unreachable!(),
|
||||
// };
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -1,14 +1,12 @@
|
||||
use std::{
|
||||
path::PathBuf,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
use std::{path::PathBuf, sync::Arc};
|
||||
|
||||
use anyhow::Result;
|
||||
use j4rs::Instance;
|
||||
use pumpkin::plugin::Context;
|
||||
use pumpkin::{command::dispatcher::CommandError, plugin::Context};
|
||||
use pumpkin_protocol::java::client::play::CommandSuggestion;
|
||||
use tokio::sync::{mpsc, oneshot};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{events::Event, java::jvm::command_executor::SimpleCommandSender};
|
||||
use crate::{commands::SimpleCommandSender, events::Event};
|
||||
|
||||
pub enum LoadPluginResult {
|
||||
SuccessfullyLoadedSpigot,
|
||||
@ -50,7 +48,45 @@ pub enum JvmCommand {
|
||||
TriggerCommand {
|
||||
cmd_name: String,
|
||||
command_sender: SimpleCommandSender,
|
||||
respond_to: oneshot::Sender<Result<Event>>,
|
||||
command: Arc<Mutex<Instance>>,
|
||||
respond_to: oneshot::Sender<Result<()>>,
|
||||
args: Vec<String>,
|
||||
},
|
||||
GetCommandTabComplete {
|
||||
command_sender: SimpleCommandSender,
|
||||
cmd_name: String,
|
||||
respond_to: oneshot::Sender<Result<Option<Vec<CommandSuggestion>>, CommandError>>,
|
||||
args: Vec<String>,
|
||||
location: Option<Location>,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct Rotation {
|
||||
pub yaw: f32,
|
||||
pub pitch: f32,
|
||||
}
|
||||
|
||||
impl Rotation {
|
||||
pub fn new(yaw: f32, pitch: f32) -> Self {
|
||||
Rotation { yaw, pitch }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Location {
|
||||
pub world: Uuid,
|
||||
pub x: f64,
|
||||
pub y: f64,
|
||||
pub z: f64,
|
||||
pub rotation: Option<Rotation>,
|
||||
}
|
||||
|
||||
impl Location {
|
||||
pub fn new(world: Uuid, x: f64, y: f64, z: f64, rotation: Option<Rotation>) -> Self {
|
||||
Location {
|
||||
world,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
rotation,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,2 @@
|
||||
pub mod command_executor;
|
||||
pub mod commands;
|
||||
pub mod worker;
|
||||
|
||||
@ -10,14 +10,17 @@ use crate::{
|
||||
jar::read_configs_from_jar,
|
||||
jvm::commands::{JvmCommand, LoadPluginResult},
|
||||
native_callbacks::{init_callback_context, initialize_callbacks},
|
||||
plugin::{
|
||||
command_manager::CommandManager, event_manager::EventManager, manager::PluginManager,
|
||||
},
|
||||
},
|
||||
plugin::{event_manager::EventManager, manager::PluginManager},
|
||||
};
|
||||
|
||||
pub struct JvmWorker {
|
||||
command_rx: mpsc::Receiver<JvmCommand>,
|
||||
pub plugin_manager: PluginManager,
|
||||
pub event_manager: EventManager,
|
||||
pub command_manager: CommandManager,
|
||||
jvm: Option<j4rs::Jvm>,
|
||||
context: Option<Arc<Context>>,
|
||||
}
|
||||
@ -28,6 +31,7 @@ impl JvmWorker {
|
||||
command_rx,
|
||||
plugin_manager: PluginManager::new(),
|
||||
event_manager: EventManager::new(),
|
||||
command_manager: CommandManager::new(),
|
||||
jvm: None,
|
||||
context: None,
|
||||
}
|
||||
@ -99,7 +103,12 @@ impl JvmWorker {
|
||||
|
||||
let _ = respond_to.send(
|
||||
self.plugin_manager
|
||||
.instantiate_all_plugins(jvm, &server, command_tx)
|
||||
.instantiate_all_plugins(
|
||||
jvm,
|
||||
&server,
|
||||
command_tx,
|
||||
&mut self.command_manager,
|
||||
)
|
||||
.await,
|
||||
);
|
||||
}
|
||||
@ -123,7 +132,10 @@ impl JvmWorker {
|
||||
let _ = respond_to.send(self.plugin_manager.unload_all_plugins());
|
||||
break;
|
||||
}
|
||||
JvmCommand::TriggerEvent { event, respond_to } => {
|
||||
JvmCommand::TriggerEvent {
|
||||
event,
|
||||
respond_to: _,
|
||||
} => {
|
||||
let jvm = match self.jvm {
|
||||
Some(ref jvm) => jvm,
|
||||
None => &Jvm::attach_thread().unwrap(),
|
||||
@ -221,21 +233,40 @@ impl JvmWorker {
|
||||
cmd_name,
|
||||
command_sender,
|
||||
respond_to,
|
||||
command,
|
||||
args,
|
||||
} => {
|
||||
let jvm = match self.jvm {
|
||||
Some(ref jvm) => jvm,
|
||||
None => &Jvm::attach_thread().unwrap(),
|
||||
};
|
||||
self.plugin_manager
|
||||
.trigger_command(
|
||||
jvm,
|
||||
&cmd_name,
|
||||
command,
|
||||
command_sender,
|
||||
vec![cmd_name.clone()],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let result =
|
||||
self.command_manager
|
||||
.trigger_command(jvm, &cmd_name, command_sender, args);
|
||||
|
||||
let _ = respond_to.send(result);
|
||||
}
|
||||
JvmCommand::GetCommandTabComplete {
|
||||
command_sender,
|
||||
cmd_name,
|
||||
respond_to,
|
||||
args,
|
||||
location,
|
||||
} => {
|
||||
let jvm = match self.jvm {
|
||||
Some(ref jvm) => jvm,
|
||||
None => &Jvm::attach_thread().unwrap(),
|
||||
};
|
||||
|
||||
let result = self.command_manager.get_tab_complete(
|
||||
jvm,
|
||||
command_sender,
|
||||
&cmd_name,
|
||||
args,
|
||||
location,
|
||||
);
|
||||
|
||||
let _ = respond_to.send(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
pub mod jar;
|
||||
pub mod jvm;
|
||||
pub mod native_callbacks;
|
||||
pub mod plugin;
|
||||
pub mod resources;
|
||||
|
||||
301
rust/src/java/plugin/command_manager/mod.rs
Normal file
301
rust/src/java/plugin/command_manager/mod.rs
Normal file
@ -0,0 +1,301 @@
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use anyhow::Result;
|
||||
use j4rs::{Instance, InvocationArg, JavaClass, Jvm};
|
||||
use pumpkin::{
|
||||
command::{
|
||||
dispatcher::CommandError,
|
||||
tree::{CommandTree, builder::literal},
|
||||
},
|
||||
plugin::Context,
|
||||
};
|
||||
use pumpkin_protocol::java::client::play::CommandSuggestion;
|
||||
use pumpkin_util::permission::{Permission, PermissionDefault};
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
use crate::{
|
||||
commands::{JavaCommandExecutor, SimpleCommandSender},
|
||||
config,
|
||||
java::{
|
||||
jvm::commands::{JvmCommand, Location},
|
||||
plugin::manager::Plugin,
|
||||
},
|
||||
};
|
||||
|
||||
pub struct CommandManager {
|
||||
command_map: Option<Instance>,
|
||||
}
|
||||
|
||||
impl CommandManager {
|
||||
pub fn new() -> Self {
|
||||
Self { command_map: None }
|
||||
}
|
||||
|
||||
pub fn init(&mut self, jvm: &Jvm) -> Result<()> {
|
||||
let server_instance =
|
||||
jvm.invoke_static("org.bukkit.Bukkit", "getServer", InvocationArg::empty())?;
|
||||
|
||||
let command_map = jvm.invoke(&server_instance, "getCommandMap", InvocationArg::empty())?;
|
||||
|
||||
self.command_map = Some(command_map);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_tab_complete(
|
||||
&mut self,
|
||||
jvm: &Jvm,
|
||||
sender: SimpleCommandSender,
|
||||
cmd_name: &str,
|
||||
args: Vec<String>,
|
||||
location: Option<Location>,
|
||||
) -> Result<Option<Vec<CommandSuggestion>>, CommandError> {
|
||||
match self.try_tab_complete(jvm, sender, cmd_name, args, location) {
|
||||
Ok(suggestions) => Ok(suggestions),
|
||||
Err(e) => {
|
||||
log::warn!("Tab completion failed: {e}");
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn try_tab_complete(
|
||||
&mut self,
|
||||
jvm: &Jvm,
|
||||
sender: SimpleCommandSender,
|
||||
cmd_name: &str,
|
||||
args: Vec<String>,
|
||||
location: Option<Location>,
|
||||
) -> Result<Option<Vec<CommandSuggestion>>> {
|
||||
let command_map = match self.command_map {
|
||||
Some(ref command_map) => command_map,
|
||||
None => match self.init(jvm) {
|
||||
Ok(_) => self.command_map.as_ref().unwrap(),
|
||||
Err(_) => return Ok(None),
|
||||
},
|
||||
};
|
||||
|
||||
let sender = Self::sender_to_jsender(jvm, sender)?;
|
||||
|
||||
let completions = if let Some(location) = location {
|
||||
let world = jvm.invoke_static(
|
||||
"org.patchbukkit.world.PatchBukkitWorld",
|
||||
"getOrCreate",
|
||||
&[InvocationArg::try_from(location.world.to_string())?],
|
||||
)?;
|
||||
|
||||
let location = match location.rotation {
|
||||
Some(rotation) => jvm.create_instance(
|
||||
"org.bukkit.Location",
|
||||
&[
|
||||
InvocationArg::try_from(world)?,
|
||||
InvocationArg::try_from(location.x)?.into_primitive()?,
|
||||
InvocationArg::try_from(location.y)?.into_primitive()?,
|
||||
InvocationArg::try_from(location.z)?.into_primitive()?,
|
||||
InvocationArg::try_from(rotation.yaw)?.into_primitive()?,
|
||||
InvocationArg::try_from(rotation.pitch)?.into_primitive()?,
|
||||
],
|
||||
)?,
|
||||
None => jvm.create_instance(
|
||||
"org.bukkit.Location",
|
||||
&[
|
||||
InvocationArg::try_from(world)?,
|
||||
InvocationArg::try_from(location.x)?.into_primitive()?,
|
||||
InvocationArg::try_from(location.y)?.into_primitive()?,
|
||||
InvocationArg::try_from(location.z)?.into_primitive()?,
|
||||
],
|
||||
)?,
|
||||
};
|
||||
|
||||
jvm.invoke(
|
||||
command_map,
|
||||
"tabComplete",
|
||||
&[
|
||||
InvocationArg::try_from(sender)?,
|
||||
InvocationArg::try_from(cmd_name)?,
|
||||
InvocationArg::try_from(jvm.java_list(JavaClass::String, args)?)?,
|
||||
InvocationArg::try_from(location)?,
|
||||
],
|
||||
)?
|
||||
} else {
|
||||
jvm.invoke(
|
||||
command_map,
|
||||
"tabComplete",
|
||||
&[
|
||||
InvocationArg::try_from(sender)?,
|
||||
InvocationArg::try_from(cmd_name)?,
|
||||
InvocationArg::try_from(jvm.java_list(JavaClass::String, args)?)?,
|
||||
],
|
||||
)?
|
||||
};
|
||||
|
||||
let completions: Vec<String> = jvm.to_rust(completions)?;
|
||||
|
||||
Ok(Some(
|
||||
completions
|
||||
.into_iter()
|
||||
.map(|completion| CommandSuggestion::new(completion, None))
|
||||
.collect(),
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn register_command(
|
||||
&mut self,
|
||||
jvm: &Jvm,
|
||||
context: &Arc<Context>,
|
||||
plugin: &Plugin,
|
||||
cmd_name: String,
|
||||
cmd_data: &config::spigot::Command,
|
||||
command_tx: mpsc::Sender<JvmCommand>,
|
||||
) -> Result<()> {
|
||||
let command_map = match self.command_map {
|
||||
Some(ref command_map) => command_map,
|
||||
None => match self.init(jvm) {
|
||||
Ok(_) => self.command_map.as_ref().unwrap(),
|
||||
Err(err) => return Err(err),
|
||||
},
|
||||
};
|
||||
|
||||
let plugin_instance =
|
||||
jvm.clone_instance(plugin.instance.as_ref().expect(
|
||||
"This function should never be called with a plugin that has no instance",
|
||||
))?;
|
||||
let j_plugin_arg = InvocationArg::from(plugin_instance);
|
||||
|
||||
let j_plugin_cmd = Arc::new(Mutex::new(jvm.invoke_static(
|
||||
"org.patchbukkit.command.CommandFactory",
|
||||
"create",
|
||||
&[InvocationArg::try_from(&cmd_name)?, j_plugin_arg],
|
||||
)?));
|
||||
log::info!("Registering Bukkit command: {}", &cmd_name);
|
||||
{
|
||||
let cmd_lock = j_plugin_cmd.lock().unwrap();
|
||||
let j_plugin_cmd_owned = jvm.clone_instance(&*cmd_lock)?;
|
||||
jvm.invoke(
|
||||
command_map,
|
||||
"register",
|
||||
&[
|
||||
InvocationArg::try_from(&cmd_name)?,
|
||||
InvocationArg::try_from(&plugin.name)?,
|
||||
InvocationArg::from(j_plugin_cmd_owned),
|
||||
],
|
||||
)?;
|
||||
}
|
||||
let j_sender = jvm
|
||||
.invoke_static(
|
||||
"org.bukkit.Bukkit",
|
||||
"getConsoleSender",
|
||||
InvocationArg::empty(),
|
||||
)
|
||||
.map_err(|e| e.to_string())
|
||||
.unwrap();
|
||||
|
||||
// Make the tab working, at least the first thingy
|
||||
let dispatch_result = jvm
|
||||
.invoke(
|
||||
command_map,
|
||||
"tabComplete",
|
||||
&[
|
||||
InvocationArg::from(j_sender),
|
||||
InvocationArg::try_from(format!("{} ", &cmd_name)).unwrap(),
|
||||
],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let tab_list: Vec<String> = jvm.to_rust(dispatch_result).unwrap();
|
||||
|
||||
let mut node = CommandTree::new(
|
||||
[&cmd_name],
|
||||
cmd_data.description.clone().unwrap_or_default(),
|
||||
)
|
||||
.execute(JavaCommandExecutor {
|
||||
cmd_name: cmd_name.clone(),
|
||||
command_tx: command_tx.clone(),
|
||||
});
|
||||
for tab in tab_list {
|
||||
node = node.then(literal(tab).execute(JavaCommandExecutor {
|
||||
cmd_name: cmd_name.clone(),
|
||||
command_tx: command_tx.clone(),
|
||||
}));
|
||||
}
|
||||
// TODO
|
||||
// let permission = if let Some(perm) = cmd_data.permission.clone() {
|
||||
// perm
|
||||
// } else {
|
||||
// format!("patchbukkit:{}", cmd_name) // TODO
|
||||
// };
|
||||
let permission = format!("patchbukkit:{}", cmd_name);
|
||||
|
||||
context
|
||||
.register_permission(Permission::new(
|
||||
&permission,
|
||||
&permission,
|
||||
PermissionDefault::Allow,
|
||||
))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
context.register_command(node, permission).await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn trigger_command(
|
||||
&mut self,
|
||||
jvm: &Jvm,
|
||||
cmd_name: &str,
|
||||
sender: SimpleCommandSender,
|
||||
_args: Vec<String>,
|
||||
) -> Result<()> {
|
||||
let command_map = match self.command_map {
|
||||
Some(ref command_map) => command_map,
|
||||
None => match self.init(jvm) {
|
||||
Ok(_) => self.command_map.as_ref().unwrap(),
|
||||
Err(err) => return Err(err),
|
||||
},
|
||||
};
|
||||
|
||||
let j_sender = Self::sender_to_jsender(jvm, sender)?;
|
||||
|
||||
let dispatch_result = jvm.invoke(
|
||||
command_map,
|
||||
"dispatch",
|
||||
&[
|
||||
InvocationArg::from(j_sender),
|
||||
InvocationArg::try_from(cmd_name)?,
|
||||
],
|
||||
)?;
|
||||
|
||||
let handled: bool = jvm.to_rust(dispatch_result)?;
|
||||
|
||||
if !handled {
|
||||
//log::warn!("Command was not handled by any Java plugin: {}", cmd_name);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn sender_to_jsender(jvm: &Jvm, sender: SimpleCommandSender) -> Result<Instance> {
|
||||
match sender {
|
||||
SimpleCommandSender::Console => Ok(jvm.invoke_static(
|
||||
"org.bukkit.Bukkit",
|
||||
"getConsoleSender",
|
||||
InvocationArg::empty(),
|
||||
)?),
|
||||
|
||||
SimpleCommandSender::Player(uuid_str) => {
|
||||
let server =
|
||||
jvm.invoke_static("org.bukkit.Bukkit", "getServer", InvocationArg::empty())?;
|
||||
let patch_server = jvm.cast(&server, "org.patchbukkit.PatchBukkitServer")?;
|
||||
|
||||
let j_uuid = jvm.invoke_static(
|
||||
"java.util.UUID",
|
||||
"fromString",
|
||||
&[InvocationArg::try_from(uuid_str)?],
|
||||
)?;
|
||||
|
||||
Ok(jvm.invoke(&patch_server, "getPlayer", &[InvocationArg::from(j_uuid)])?)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,16 +1,12 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
path::{Path, PathBuf},
|
||||
sync::{Arc, Mutex},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use anyhow::Result;
|
||||
use j4rs::{Instance, InvocationArg, Jvm};
|
||||
use pumpkin::{
|
||||
command::tree::{CommandTree, builder::literal},
|
||||
plugin::Context,
|
||||
};
|
||||
use pumpkin_util::permission::{Permission, PermissionDefault};
|
||||
use pumpkin::plugin::Context;
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
use crate::{
|
||||
@ -18,10 +14,7 @@ use crate::{
|
||||
paper::PaperPluginYml,
|
||||
spigot::{Command, SpigotPluginYml},
|
||||
},
|
||||
java::jvm::{
|
||||
command_executor::{JavaCommandExecutor, SimpleCommandSender},
|
||||
commands::JvmCommand,
|
||||
},
|
||||
java::{jvm::commands::JvmCommand, plugin::command_manager::CommandManager},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
@ -219,84 +212,13 @@ impl PluginManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn trigger_command(
|
||||
&self,
|
||||
jvm: &Jvm,
|
||||
cmd_name: &str,
|
||||
_command: Arc<Mutex<Instance>>,
|
||||
sender: SimpleCommandSender,
|
||||
_args: Vec<String>,
|
||||
) -> Result<(), String> {
|
||||
let j_sender = match sender {
|
||||
SimpleCommandSender::Console => jvm
|
||||
.invoke_static(
|
||||
"org.bukkit.Bukkit",
|
||||
"getConsoleSender",
|
||||
InvocationArg::empty(),
|
||||
)
|
||||
.map_err(|e| e.to_string())?,
|
||||
|
||||
SimpleCommandSender::Player(uuid_str) => {
|
||||
// Get the server and cast it to your implementation
|
||||
let server = jvm
|
||||
.invoke_static("org.bukkit.Bukkit", "getServer", InvocationArg::empty())
|
||||
.map_err(|e| e.to_string())?;
|
||||
let patch_server = jvm
|
||||
.cast(&server, "org.patchbukkit.PatchBukkitServer")
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
// Create Java UUID object
|
||||
let j_uuid = jvm
|
||||
.invoke_static(
|
||||
"java.util.UUID",
|
||||
"fromString",
|
||||
&[InvocationArg::try_from(uuid_str).map_err(|e| e.to_string())?],
|
||||
)
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
// Call your getPlayer(UUID) method on the server
|
||||
jvm.invoke(&patch_server, "getPlayer", &[InvocationArg::from(j_uuid)])
|
||||
.map_err(|e| e.to_string())?
|
||||
}
|
||||
};
|
||||
|
||||
let server_instance = jvm
|
||||
.invoke_static("org.bukkit.Bukkit", "getServer", InvocationArg::empty())
|
||||
.unwrap();
|
||||
|
||||
let command_map = jvm
|
||||
.invoke(&server_instance, "getCommandMap", InvocationArg::empty())
|
||||
.unwrap();
|
||||
|
||||
let dispatch_result = jvm
|
||||
.invoke(
|
||||
&command_map,
|
||||
"dispatch",
|
||||
&[
|
||||
InvocationArg::from(j_sender),
|
||||
InvocationArg::try_from(cmd_name).unwrap(),
|
||||
],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let handled: bool = jvm.to_rust(dispatch_result).unwrap();
|
||||
|
||||
if !handled {
|
||||
//log::warn!("Command was not handled by any Java plugin: {}", cmd_name);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn instantiate_all_plugins(
|
||||
&mut self,
|
||||
jvm: &Jvm,
|
||||
server: &Arc<Context>,
|
||||
command_tx: mpsc::Sender<JvmCommand>,
|
||||
command_manager: &mut CommandManager,
|
||||
) -> Result<()> {
|
||||
let server_instance =
|
||||
jvm.invoke_static("org.bukkit.Bukkit", "getServer", InvocationArg::empty())?;
|
||||
|
||||
for (_plugin_name, plugin) in &mut self.plugins {
|
||||
let plugin_instance = jvm.invoke_static(
|
||||
"org.patchbukkit.loader.PatchBukkitPluginLoader",
|
||||
@ -308,88 +230,29 @@ impl PluginManager {
|
||||
)?;
|
||||
|
||||
plugin.instance = Some(plugin_instance);
|
||||
let instance_ref = plugin.instance.as_ref().unwrap();
|
||||
|
||||
let command_map =
|
||||
jvm.invoke(&server_instance, "getCommandMap", InvocationArg::empty())?;
|
||||
|
||||
for (cmd_name, cmd_data) in &plugin.commands {
|
||||
let cloned_plugin_instance = jvm.clone_instance(instance_ref)?;
|
||||
let j_plugin_arg = InvocationArg::from(cloned_plugin_instance);
|
||||
|
||||
let j_plugin_cmd = Arc::new(Mutex::new(jvm.invoke_static(
|
||||
"org.patchbukkit.command.CommandFactory",
|
||||
"create",
|
||||
&[InvocationArg::try_from(cmd_name)?, j_plugin_arg],
|
||||
)?));
|
||||
log::info!("Registering Bukkit command: {}", cmd_name);
|
||||
{
|
||||
let cmd_lock = j_plugin_cmd.lock().unwrap();
|
||||
let j_plugin_cmd_owned = jvm.clone_instance(&*cmd_lock)?;
|
||||
jvm.invoke(
|
||||
&command_map,
|
||||
"register",
|
||||
&[
|
||||
InvocationArg::try_from(cmd_name)?,
|
||||
InvocationArg::try_from(&plugin.name)?,
|
||||
InvocationArg::from(j_plugin_cmd_owned),
|
||||
],
|
||||
)?;
|
||||
}
|
||||
let j_sender = jvm
|
||||
.invoke_static(
|
||||
"org.bukkit.Bukkit",
|
||||
"getConsoleSender",
|
||||
InvocationArg::empty(),
|
||||
match command_manager
|
||||
.register_command(
|
||||
&jvm,
|
||||
server,
|
||||
&plugin,
|
||||
cmd_name.clone(),
|
||||
cmd_data,
|
||||
command_tx.clone(),
|
||||
)
|
||||
.map_err(|e| e.to_string())
|
||||
.unwrap();
|
||||
|
||||
// Make the tab working, at least the first thingy
|
||||
let dispatch_result = jvm
|
||||
.invoke(
|
||||
&command_map,
|
||||
"tabComplete",
|
||||
&[
|
||||
InvocationArg::from(j_sender),
|
||||
InvocationArg::try_from(format!("{} ", cmd_name)).unwrap(),
|
||||
],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let tab_list: Vec<String> = jvm.to_rust(dispatch_result).unwrap();
|
||||
|
||||
let mut node =
|
||||
CommandTree::new([cmd_name], cmd_data.description.clone().unwrap_or_default())
|
||||
.execute(JavaCommandExecutor {
|
||||
cmd_name: cmd_name.clone(),
|
||||
command_tx: command_tx.clone(),
|
||||
command: j_plugin_cmd.clone(),
|
||||
});
|
||||
for tab in tab_list {
|
||||
node = node.then(literal(tab).execute(JavaCommandExecutor {
|
||||
cmd_name: cmd_name.clone(),
|
||||
command_tx: command_tx.clone(),
|
||||
command: j_plugin_cmd.clone(),
|
||||
}));
|
||||
}
|
||||
// TODO
|
||||
// let permission = if let Some(perm) = cmd_data.permission.clone() {
|
||||
// perm
|
||||
// } else {
|
||||
// format!("patchbukkit:{}", cmd_name) // TODO
|
||||
// };
|
||||
let permission = format!("patchbukkit:{}", cmd_name);
|
||||
|
||||
server
|
||||
.register_permission(Permission::new(
|
||||
&permission,
|
||||
&permission,
|
||||
PermissionDefault::Allow,
|
||||
))
|
||||
.await
|
||||
.unwrap();
|
||||
server.register_command(node, permission).await
|
||||
{
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
log::error!(
|
||||
"Failed to register command {} for plugin {}: {:?}",
|
||||
cmd_name,
|
||||
plugin.name,
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plugin.state = PluginState::Loaded;
|
||||
@ -1,2 +1,3 @@
|
||||
pub mod command_manager;
|
||||
pub mod event_manager;
|
||||
pub mod manager;
|
||||
@ -3,11 +3,11 @@ use std::sync::Arc;
|
||||
use pumpkin::plugin::Context;
|
||||
use pumpkin_api_macros::{plugin_impl, plugin_method};
|
||||
|
||||
pub mod commands;
|
||||
pub mod config;
|
||||
pub mod directories;
|
||||
pub mod events;
|
||||
pub mod java;
|
||||
pub mod plugin;
|
||||
|
||||
use directories::setup_directories;
|
||||
use java::{
|
||||
|
||||
Loading…
Reference in New Issue
Block a user