use crate::plugin::EngineEvent;
use wasmtime::{Instance, Store, TypedFunc};
pub struct PluginInstance {
pub id: u64,
pub store: Store<PluginState>,
pub instance: Instance,
pub on_init: Option<TypedFunc<(), ()>>,
pub on_frame: Option<TypedFunc<(), ()>>,
}
pub struct PluginState {
pub wasi: wasmtime_wasi::p1::WasiP1Ctx,
pub pending_commands: Vec<crate::plugin::EngineCommand>,
pub pending_custom_commands: Vec<Vec<u8>>,
}
impl PluginState {
pub fn new(wasi: wasmtime_wasi::p1::WasiP1Ctx) -> Self {
Self {
wasi,
pending_commands: Vec::new(),
pending_custom_commands: Vec::new(),
}
}
pub fn push_custom_command(&mut self, bytes: Vec<u8>) {
self.pending_custom_commands.push(bytes);
}
}
pub fn send_engine_event_to_plugin(plugin: &mut PluginInstance, event: &EngineEvent) {
let event_bytes = match event.to_bytes() {
Ok(bytes) => bytes,
Err(error) => {
tracing::error!("Failed to serialize engine event: {}", error);
return;
}
};
send_bytes_to_plugin(plugin, &event_bytes, "plugin_alloc", "plugin_receive_event");
}
pub fn send_bytes_to_plugin(
plugin: &mut PluginInstance,
event_bytes: &[u8],
alloc_fn: &str,
receive_fn: &str,
) {
let plugin_alloc = match plugin
.instance
.get_typed_func::<u32, u32>(&mut plugin.store, alloc_fn)
{
Ok(func) => func,
Err(_) => return,
};
let ptr = match plugin_alloc.call(&mut plugin.store, event_bytes.len() as u32) {
Ok(ptr) => ptr,
Err(error) => {
tracing::error!("Plugin {} alloc failed: {}", plugin.id, error);
return;
}
};
let memory = match plugin.instance.get_memory(&mut plugin.store, "memory") {
Some(mem) => mem,
None => {
tracing::error!("Plugin {} has no memory export", plugin.id);
return;
}
};
if let Err(error) = memory.write(&mut plugin.store, ptr as usize, event_bytes) {
tracing::error!("Plugin {} memory write failed: {}", plugin.id, error);
return;
}
let receive_fn_typed = match plugin
.instance
.get_typed_func::<(u32, u32), ()>(&mut plugin.store, receive_fn)
{
Ok(func) => func,
Err(_) => return,
};
if let Err(error) = receive_fn_typed.call(&mut plugin.store, (ptr, event_bytes.len() as u32)) {
tracing::error!("Plugin {} receive_event failed: {}", plugin.id, error);
}
}