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 java.util.UUID;
|
||||||
|
|
||||||
import org.bukkit.Server;
|
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.Permission;
|
||||||
import org.bukkit.permissions.PermissionAttachment;
|
import org.bukkit.permissions.PermissionAttachment;
|
||||||
import org.bukkit.permissions.PermissionAttachmentInfo;
|
import org.bukkit.permissions.PermissionAttachmentInfo;
|
||||||
@ -14,7 +15,12 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
|
|
||||||
import net.kyori.adventure.text.Component;
|
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
|
@Override
|
||||||
public boolean isPermissionSet(@NotNull String name) {
|
public boolean isPermissionSet(@NotNull String name) {
|
||||||
@ -44,6 +44,9 @@ public class PatchBukkitWorld
|
|||||||
return instances.computeIfAbsent(uuid, PatchBukkitWorld::new);
|
return instances.computeIfAbsent(uuid, PatchBukkitWorld::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static PatchBukkitWorld getOrCreate(String uuid) {
|
||||||
|
return getOrCreate(UUID.fromString(uuid));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isVoidDamageEnabled() {
|
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::{
|
use std::{path::PathBuf, sync::Arc};
|
||||||
path::PathBuf,
|
|
||||||
sync::{Arc, Mutex},
|
|
||||||
};
|
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use j4rs::Instance;
|
use pumpkin::{command::dispatcher::CommandError, plugin::Context};
|
||||||
use pumpkin::plugin::Context;
|
use pumpkin_protocol::java::client::play::CommandSuggestion;
|
||||||
use tokio::sync::{mpsc, oneshot};
|
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 {
|
pub enum LoadPluginResult {
|
||||||
SuccessfullyLoadedSpigot,
|
SuccessfullyLoadedSpigot,
|
||||||
@ -50,7 +48,45 @@ pub enum JvmCommand {
|
|||||||
TriggerCommand {
|
TriggerCommand {
|
||||||
cmd_name: String,
|
cmd_name: String,
|
||||||
command_sender: SimpleCommandSender,
|
command_sender: SimpleCommandSender,
|
||||||
respond_to: oneshot::Sender<Result<Event>>,
|
respond_to: oneshot::Sender<Result<()>>,
|
||||||
command: Arc<Mutex<Instance>>,
|
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 commands;
|
||||||
pub mod worker;
|
pub mod worker;
|
||||||
|
|||||||
@ -10,14 +10,17 @@ use crate::{
|
|||||||
jar::read_configs_from_jar,
|
jar::read_configs_from_jar,
|
||||||
jvm::commands::{JvmCommand, LoadPluginResult},
|
jvm::commands::{JvmCommand, LoadPluginResult},
|
||||||
native_callbacks::{init_callback_context, initialize_callbacks},
|
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 {
|
pub struct JvmWorker {
|
||||||
command_rx: mpsc::Receiver<JvmCommand>,
|
command_rx: mpsc::Receiver<JvmCommand>,
|
||||||
pub plugin_manager: PluginManager,
|
pub plugin_manager: PluginManager,
|
||||||
pub event_manager: EventManager,
|
pub event_manager: EventManager,
|
||||||
|
pub command_manager: CommandManager,
|
||||||
jvm: Option<j4rs::Jvm>,
|
jvm: Option<j4rs::Jvm>,
|
||||||
context: Option<Arc<Context>>,
|
context: Option<Arc<Context>>,
|
||||||
}
|
}
|
||||||
@ -28,6 +31,7 @@ impl JvmWorker {
|
|||||||
command_rx,
|
command_rx,
|
||||||
plugin_manager: PluginManager::new(),
|
plugin_manager: PluginManager::new(),
|
||||||
event_manager: EventManager::new(),
|
event_manager: EventManager::new(),
|
||||||
|
command_manager: CommandManager::new(),
|
||||||
jvm: None,
|
jvm: None,
|
||||||
context: None,
|
context: None,
|
||||||
}
|
}
|
||||||
@ -99,7 +103,12 @@ impl JvmWorker {
|
|||||||
|
|
||||||
let _ = respond_to.send(
|
let _ = respond_to.send(
|
||||||
self.plugin_manager
|
self.plugin_manager
|
||||||
.instantiate_all_plugins(jvm, &server, command_tx)
|
.instantiate_all_plugins(
|
||||||
|
jvm,
|
||||||
|
&server,
|
||||||
|
command_tx,
|
||||||
|
&mut self.command_manager,
|
||||||
|
)
|
||||||
.await,
|
.await,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -123,7 +132,10 @@ impl JvmWorker {
|
|||||||
let _ = respond_to.send(self.plugin_manager.unload_all_plugins());
|
let _ = respond_to.send(self.plugin_manager.unload_all_plugins());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
JvmCommand::TriggerEvent { event, respond_to } => {
|
JvmCommand::TriggerEvent {
|
||||||
|
event,
|
||||||
|
respond_to: _,
|
||||||
|
} => {
|
||||||
let jvm = match self.jvm {
|
let jvm = match self.jvm {
|
||||||
Some(ref jvm) => jvm,
|
Some(ref jvm) => jvm,
|
||||||
None => &Jvm::attach_thread().unwrap(),
|
None => &Jvm::attach_thread().unwrap(),
|
||||||
@ -221,21 +233,40 @@ impl JvmWorker {
|
|||||||
cmd_name,
|
cmd_name,
|
||||||
command_sender,
|
command_sender,
|
||||||
respond_to,
|
respond_to,
|
||||||
command,
|
args,
|
||||||
} => {
|
} => {
|
||||||
let jvm = match self.jvm {
|
let jvm = match self.jvm {
|
||||||
Some(ref jvm) => jvm,
|
Some(ref jvm) => jvm,
|
||||||
None => &Jvm::attach_thread().unwrap(),
|
None => &Jvm::attach_thread().unwrap(),
|
||||||
};
|
};
|
||||||
self.plugin_manager
|
|
||||||
.trigger_command(
|
let result =
|
||||||
jvm,
|
self.command_manager
|
||||||
&cmd_name,
|
.trigger_command(jvm, &cmd_name, command_sender, args);
|
||||||
command,
|
|
||||||
|
let _ = respond_to.send(result);
|
||||||
|
}
|
||||||
|
JvmCommand::GetCommandTabComplete {
|
||||||
command_sender,
|
command_sender,
|
||||||
vec![cmd_name.clone()],
|
cmd_name,
|
||||||
)
|
respond_to,
|
||||||
.unwrap();
|
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 jar;
|
||||||
pub mod jvm;
|
pub mod jvm;
|
||||||
pub mod native_callbacks;
|
pub mod native_callbacks;
|
||||||
|
pub mod plugin;
|
||||||
pub mod resources;
|
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::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
sync::{Arc, Mutex},
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use j4rs::{Instance, InvocationArg, Jvm};
|
use j4rs::{Instance, InvocationArg, Jvm};
|
||||||
use pumpkin::{
|
use pumpkin::plugin::Context;
|
||||||
command::tree::{CommandTree, builder::literal},
|
|
||||||
plugin::Context,
|
|
||||||
};
|
|
||||||
use pumpkin_util::permission::{Permission, PermissionDefault};
|
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -18,10 +14,7 @@ use crate::{
|
|||||||
paper::PaperPluginYml,
|
paper::PaperPluginYml,
|
||||||
spigot::{Command, SpigotPluginYml},
|
spigot::{Command, SpigotPluginYml},
|
||||||
},
|
},
|
||||||
java::jvm::{
|
java::{jvm::commands::JvmCommand, plugin::command_manager::CommandManager},
|
||||||
command_executor::{JavaCommandExecutor, SimpleCommandSender},
|
|
||||||
commands::JvmCommand,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
@ -219,84 +212,13 @@ impl PluginManager {
|
|||||||
Ok(())
|
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(
|
pub async fn instantiate_all_plugins(
|
||||||
&mut self,
|
&mut self,
|
||||||
jvm: &Jvm,
|
jvm: &Jvm,
|
||||||
server: &Arc<Context>,
|
server: &Arc<Context>,
|
||||||
command_tx: mpsc::Sender<JvmCommand>,
|
command_tx: mpsc::Sender<JvmCommand>,
|
||||||
|
command_manager: &mut CommandManager,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let server_instance =
|
|
||||||
jvm.invoke_static("org.bukkit.Bukkit", "getServer", InvocationArg::empty())?;
|
|
||||||
|
|
||||||
for (_plugin_name, plugin) in &mut self.plugins {
|
for (_plugin_name, plugin) in &mut self.plugins {
|
||||||
let plugin_instance = jvm.invoke_static(
|
let plugin_instance = jvm.invoke_static(
|
||||||
"org.patchbukkit.loader.PatchBukkitPluginLoader",
|
"org.patchbukkit.loader.PatchBukkitPluginLoader",
|
||||||
@ -308,88 +230,29 @@ impl PluginManager {
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
plugin.instance = Some(plugin_instance);
|
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 {
|
for (cmd_name, cmd_data) in &plugin.commands {
|
||||||
let cloned_plugin_instance = jvm.clone_instance(instance_ref)?;
|
match command_manager
|
||||||
let j_plugin_arg = InvocationArg::from(cloned_plugin_instance);
|
.register_command(
|
||||||
|
&jvm,
|
||||||
let j_plugin_cmd = Arc::new(Mutex::new(jvm.invoke_static(
|
server,
|
||||||
"org.patchbukkit.command.CommandFactory",
|
&plugin,
|
||||||
"create",
|
cmd_name.clone(),
|
||||||
&[InvocationArg::try_from(cmd_name)?, j_plugin_arg],
|
cmd_data,
|
||||||
)?));
|
command_tx.clone(),
|
||||||
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(),
|
|
||||||
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
|
.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;
|
plugin.state = PluginState::Loaded;
|
||||||
@ -1,2 +1,3 @@
|
|||||||
|
pub mod command_manager;
|
||||||
pub mod event_manager;
|
pub mod event_manager;
|
||||||
pub mod manager;
|
pub mod manager;
|
||||||
@ -3,11 +3,11 @@ use std::sync::Arc;
|
|||||||
use pumpkin::plugin::Context;
|
use pumpkin::plugin::Context;
|
||||||
use pumpkin_api_macros::{plugin_impl, plugin_method};
|
use pumpkin_api_macros::{plugin_impl, plugin_method};
|
||||||
|
|
||||||
|
pub mod commands;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod directories;
|
pub mod directories;
|
||||||
pub mod events;
|
pub mod events;
|
||||||
pub mod java;
|
pub mod java;
|
||||||
pub mod plugin;
|
|
||||||
|
|
||||||
use directories::setup_directories;
|
use directories::setup_directories;
|
||||||
use java::{
|
use java::{
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user