PatchBukkit/rust/src/java/jvm/worker.rs
2026-02-02 16:44:57 -07:00

231 lines
8.3 KiB
Rust

use std::{path::PathBuf, sync::Arc};
use j4rs::{InvocationArg, Jvm, JvmBuilder};
use pumpkin::plugin::Context;
use tokio::sync::mpsc;
use crate::java::{
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,
},
};
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>>,
}
impl JvmWorker {
pub fn new(command_rx: mpsc::Receiver<JvmCommand>) -> Self {
Self {
command_rx,
plugin_manager: PluginManager::new(),
event_manager: EventManager::new(),
command_manager: CommandManager::new(),
jvm: None,
context: None,
}
}
pub async fn attach_thread(mut self) {
log::info!("JVM worker thread started");
while let Some(command) = self.command_rx.recv().await {
match command {
JvmCommand::Initialize {
j4rs_path,
respond_to,
context,
command_tx,
} => {
init_callback_context(
context.clone(),
tokio::runtime::Handle::current(),
command_tx.clone(),
)
.unwrap();
self.context = Some(context);
let result = self.initialize_jvm(&j4rs_path);
let _ = respond_to.send(result);
}
JvmCommand::LoadPlugin {
plugin_path,
respond_to,
} => {
let _ = match read_configs_from_jar(&plugin_path) {
Ok(configs) => match configs {
(Some(paper_plugin_config), spigot @ _) => {
match self.plugin_manager.load_paper_plugin(
&plugin_path,
&paper_plugin_config,
&spigot,
) {
Ok(_) => {
respond_to.send(LoadPluginResult::SuccessfullyLoadedPaper)
}
Err(err) => respond_to
.send(LoadPluginResult::FailedToLoadPaperPlugin(err)),
}
}
(None, Some(spigot)) => {
match self
.plugin_manager
.load_spigot_plugin(&plugin_path, &spigot)
{
Ok(_) => {
respond_to.send(LoadPluginResult::SuccessfullyLoadedSpigot)
}
Err(err) => respond_to
.send(LoadPluginResult::FailedToLoadSpigotPlugin(err)),
}
}
(None, None) => respond_to.send(LoadPluginResult::NoConfigurationFile),
},
Err(err) => {
respond_to.send(LoadPluginResult::FailedToReadConfigurationFile(err))
}
};
}
JvmCommand::InstantiateAllPlugins {
respond_to,
server,
command_tx,
} => {
let jvm = match self.jvm {
Some(ref jvm) => jvm,
None => &Jvm::attach_thread().unwrap(),
};
let _ = respond_to.send(
self.plugin_manager
.instantiate_all_plugins(
jvm,
&server,
command_tx,
&mut self.command_manager,
)
.await,
);
}
JvmCommand::EnableAllPlugins { respond_to } => {
let jvm = match self.jvm {
Some(ref jvm) => jvm,
None => &Jvm::attach_thread().unwrap(),
};
let _ = respond_to.send(self.plugin_manager.enable_all_plugins(jvm));
}
JvmCommand::DisableAllPlugins { respond_to } => {
let jvm = match self.jvm {
Some(ref jvm) => jvm,
None => &Jvm::attach_thread().unwrap(),
};
let _ = respond_to.send(self.plugin_manager.disable_all_plugins(jvm));
}
JvmCommand::Shutdown { respond_to } => {
let _ = respond_to.send(self.plugin_manager.unload_all_plugins());
break;
}
JvmCommand::FireEvent {
respond_to,
plugin,
patchbukkit_event,
} => {
let jvm = match self.jvm {
Some(ref jvm) => jvm,
None => &Jvm::attach_thread().unwrap(),
};
let cancelled =
match self
.event_manager
.fire_event(jvm, patchbukkit_event, plugin)
{
Ok(c) => c,
Err(e) => {
log::error!("Failed to fire event: {}", e);
false
}
};
let _ = respond_to.send(cancelled);
}
JvmCommand::TriggerCommand {
full_command,
command_sender,
respond_to,
} => {
let jvm = match self.jvm {
Some(ref jvm) => jvm,
None => &Jvm::attach_thread().unwrap(),
};
let result =
self.command_manager
.trigger_command(jvm, full_command, command_sender);
let _ = respond_to.send(result);
}
JvmCommand::GetCommandTabComplete {
command_sender,
full_command,
respond_to,
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,
full_command,
location,
);
let _ = respond_to.send(result);
}
}
}
log::info!("JVM worker thread exited");
}
fn initialize_jvm(&mut self, j4rs_path: &PathBuf) -> anyhow::Result<()> {
log::info!("Initializing JVM with path: {:?}", j4rs_path);
let jvm = JvmBuilder::new().with_base_path(j4rs_path).build()?;
initialize_callbacks(&jvm)?;
setup_patchbukkit_server(&jvm)?;
self.jvm = Some(jvm);
log::info!("JVM initialized successfully");
Ok(())
}
}
pub fn setup_patchbukkit_server(jvm: &Jvm) -> anyhow::Result<()> {
let patchbukkit_server =
jvm.create_instance("org.patchbukkit.PatchBukkitServer", InvocationArg::empty())?;
jvm.invoke_static(
"org.bukkit.Bukkit",
"setServer",
&[InvocationArg::from(patchbukkit_server)],
)?;
Ok(())
}