mirror of
https://github.com/Pumpkin-MC/Pumpkin.git
synced 2026-08-30 20:14:23 +00:00
feat(plugin-api): Initial inter-plugin communication (#2788)
* feat(plugin-api): Initial inter-plugin communication * Update wit submodule commit ref --------- Co-authored-by: Jakub Palacky <kubik.palacky@gmail.com>
This commit is contained in:
@@ -99,8 +99,8 @@ pub use wit::pumpkin::plugin::{
|
||||
data_components, entity,
|
||||
entity_types::EntityType,
|
||||
event::{self as events_wit, EventType},
|
||||
gui, i18n, item_stack, java_dialogs, java_packets, particles, permission, player, scoreboard,
|
||||
server, text, uuid, world,
|
||||
gui, i18n, ipc, item_stack, java_dialogs, java_packets, particles, permission, player,
|
||||
scoreboard, server, text, uuid, world,
|
||||
};
|
||||
|
||||
// Convenience re-exports of commonly-used plugin types so plugin authors can
|
||||
@@ -263,6 +263,13 @@ impl wit::Guest for Component {
|
||||
goal.stop(server, entity);
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_ipc_message(
|
||||
sender: wit::PluginId,
|
||||
message: wit::IpcMessage,
|
||||
) -> Result<wit::IpcMessage, String> {
|
||||
plugin().handle_ipc_message(sender, message)
|
||||
}
|
||||
}
|
||||
|
||||
/// Convenience alias for `core::result::Result<T, String>` used throughout the plugin API.
|
||||
@@ -295,6 +302,15 @@ pub trait Plugin: Send + Sync {
|
||||
fn on_unload(&mut self, _context: Context) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Called when the plugin receives a message from another plugin.
|
||||
fn handle_ipc_message(
|
||||
&mut self,
|
||||
_sender: wit::PluginId,
|
||||
_message: wit::IpcMessage,
|
||||
) -> Result<wit::IpcMessage, String> {
|
||||
Err("This plugin cannot receive messages.".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
|
||||
Submodule crates/pumpkin-plugin-wit updated: 97c0281c8e...160251fb0b
@@ -55,4 +55,16 @@ pub trait Plugin: Send + Sync + 'static {
|
||||
fn on_unload(&self, server: Arc<Context>) -> PluginFuture<'_, Result<(), String>> {
|
||||
Box::pin(async move { Ok(()) })
|
||||
}
|
||||
|
||||
/// Asynchronous method called when the plugin receives an IPC message.
|
||||
///
|
||||
/// This processes the message, and optionally returns a response
|
||||
#[expect(unused)]
|
||||
fn on_ipc_message(
|
||||
&self,
|
||||
sender: &str,
|
||||
message: &[u8],
|
||||
) -> PluginFuture<'_, Result<Vec<u8>, String>> {
|
||||
Box::pin(async move { Err("This plugin cannot receive messages.".to_string()) })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,21 @@ impl Plugin for WasmPlugin {
|
||||
.flatten()
|
||||
})
|
||||
}
|
||||
|
||||
fn on_ipc_message(
|
||||
&self,
|
||||
sender: &str,
|
||||
message: &[u8],
|
||||
) -> PluginFuture<'_, Result<Vec<u8>, String>> {
|
||||
let sender_own = sender.to_owned();
|
||||
let message_own = message.to_owned();
|
||||
Box::pin(async move {
|
||||
self.handle_ipc_message(&sender_own, &message_own)
|
||||
.await
|
||||
.map_err(|err| err.to_string())
|
||||
.flatten()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WasmPluginLoader;
|
||||
|
||||
@@ -266,6 +266,8 @@ impl WasmPlugin {
|
||||
|
||||
store.data_mut().server = Some(context.server.clone());
|
||||
|
||||
store.data_mut().name = Some(metadata.name.clone());
|
||||
|
||||
match self.plugin_instance {
|
||||
PluginInstance::V0_1(ref plugin) => {
|
||||
let context = store.data_mut().add_context(context)?;
|
||||
@@ -297,6 +299,22 @@ impl WasmPlugin {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn handle_ipc_message(
|
||||
&self,
|
||||
sender: &String,
|
||||
message: &Vec<u8>,
|
||||
) -> Result<Result<Vec<u8>, String>, wasmtime::Error> {
|
||||
let mut store = self.store.lock().await;
|
||||
|
||||
match self.plugin_instance {
|
||||
PluginInstance::V0_1(ref plugin) => {
|
||||
plugin
|
||||
.call_handle_ipc_message(&mut *store, sender, message)
|
||||
.await
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait DowncastResourceExt<E> {
|
||||
|
||||
@@ -69,6 +69,7 @@ pub struct PluginHostState {
|
||||
pub plugin: Option<Weak<WasmPlugin>>,
|
||||
pub server: Option<Arc<Server>>,
|
||||
pub permissions: Vec<String>,
|
||||
pub name: Option<String>,
|
||||
}
|
||||
|
||||
impl Default for PluginHostState {
|
||||
@@ -92,6 +93,7 @@ impl PluginHostState {
|
||||
plugin: None,
|
||||
server: None,
|
||||
permissions: Vec::new(),
|
||||
name: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
use crate::plugin::loader::wasm::wasm_host::{
|
||||
state::PluginHostState,
|
||||
wit::v0_1::pumpkin::{
|
||||
self,
|
||||
plugin::ipc::{IpcMessage, PluginId},
|
||||
},
|
||||
};
|
||||
|
||||
impl pumpkin::plugin::ipc::Host for PluginHostState {
|
||||
async fn send_ipc_message(
|
||||
&mut self,
|
||||
recipient: PluginId,
|
||||
message: IpcMessage,
|
||||
) -> wasmtime::Result<Result<Result<IpcMessage, String>, ()>> {
|
||||
Ok(self
|
||||
.server
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.plugin_manager
|
||||
.send_message(self.name.as_ref().unwrap(), &recipient, &message)
|
||||
.await)
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ pub mod forms;
|
||||
pub mod generated_packets;
|
||||
pub mod gui;
|
||||
pub mod i18n;
|
||||
pub mod ipc;
|
||||
pub mod item_stack;
|
||||
pub mod java_dialogs;
|
||||
pub mod logging;
|
||||
|
||||
@@ -1032,6 +1032,28 @@ impl PluginManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn send_message(
|
||||
&self,
|
||||
sender: &str,
|
||||
recipient: &str,
|
||||
message: &[u8],
|
||||
) -> Result<Result<Vec<u8>, String>, ()> {
|
||||
if sender == recipient {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
let plugins = self.plugins.read().await;
|
||||
let target_plugin = &plugins
|
||||
.iter()
|
||||
.find(|p| p.metadata.name == recipient)
|
||||
.ok_or(())?;
|
||||
if let Some(instance) = &target_plugin.instance {
|
||||
Ok(instance.on_ipc_message(sender, message).await)
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
Reference in New Issue
Block a user