mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added raw_print API, log macro to plugin API
This commit is contained in:
parent
47b522e156
commit
51e5b39f5c
1
assets/.gitignore
vendored
Normal file
1
assets/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
plugins/*
|
@ -228,13 +228,19 @@ pub fn read_data<T: DeserializeOwned>(
|
||||
position: u64,
|
||||
length: u64,
|
||||
) -> Result<T, bincode::Error> {
|
||||
bincode::deserialize(&read_bytes(memory, position, length))
|
||||
bincode::deserialize(
|
||||
&read_bytes(memory, position, length).ok_or(bincode::ErrorKind::SizeLimit)?,
|
||||
)
|
||||
}
|
||||
|
||||
/// This function read raw bytes from memory at a position with the array length
|
||||
pub fn read_bytes(memory: &Memory, position: u64, length: u64) -> Vec<u8> {
|
||||
memory.view()[(position as usize)..(position as usize) + length as usize]
|
||||
.iter()
|
||||
.map(|x| x.get())
|
||||
.collect()
|
||||
pub fn read_bytes(memory: &Memory, position: u64, length: u64) -> Option<Vec<u8>> {
|
||||
Some(
|
||||
memory
|
||||
.view()
|
||||
.get((position as usize)..(position as usize) + length as usize)?
|
||||
.iter()
|
||||
.map(|x| x.get())
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
use hashbrown::HashSet;
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
borrow::Cow,
|
||||
convert::TryInto,
|
||||
marker::PhantomData,
|
||||
sync::{Arc, Mutex},
|
||||
@ -11,7 +12,7 @@ use wasmer::{imports, Cranelift, Function, Instance, Memory, Module, Store, Valu
|
||||
use super::{
|
||||
errors::{PluginError, PluginModuleError},
|
||||
memory_manager::{self, EcsAccessManager, EcsWorld, MemoryManager},
|
||||
wasm_env::HostFunctionEnvironement,
|
||||
wasm_env::HostFunctionEnvironment,
|
||||
};
|
||||
|
||||
use plugin_api::{Action, EcsAccessError, Event, Retrieve, RetrieveError, RetrieveResult};
|
||||
@ -39,7 +40,7 @@ impl PluginModule {
|
||||
let module = Module::new(&store, &wasm_data).expect("Can't compile");
|
||||
|
||||
// This is the function imported into the wasm environement
|
||||
fn raw_emit_actions(env: &HostFunctionEnvironement, ptr: i64, len: i64) {
|
||||
fn raw_emit_actions(env: &HostFunctionEnvironment, ptr: i64, len: i64) {
|
||||
handle_actions(match env.read_data(from_i64(ptr), from_i64(len)) {
|
||||
Ok(e) => e,
|
||||
Err(e) => {
|
||||
@ -49,7 +50,7 @@ impl PluginModule {
|
||||
});
|
||||
}
|
||||
|
||||
fn raw_retrieve_action(env: &HostFunctionEnvironement, ptr: i64, len: i64) -> i64 {
|
||||
fn raw_retrieve_action(env: &HostFunctionEnvironment, ptr: i64, len: i64) -> i64 {
|
||||
let out = match env.read_data(from_i64(ptr), from_i64(len)) {
|
||||
Ok(data) => retrieve_action(&env.ecs, data),
|
||||
Err(e) => Err(RetrieveError::BincodeError(e.to_string())),
|
||||
@ -60,8 +61,15 @@ impl PluginModule {
|
||||
to_i64(env.write_data_as_pointer(&out).unwrap())
|
||||
}
|
||||
|
||||
fn dbg(a: i32) {
|
||||
println!("WASM DEBUG: {}", a);
|
||||
fn raw_print(env: &HostFunctionEnvironment, ptr: i64, len: i64) {
|
||||
if let Some(msg) = env
|
||||
.read_bytes(from_i64(ptr), from_i64(len))
|
||||
.and_then(|bytes| String::from_utf8(bytes).ok())
|
||||
{
|
||||
tracing::info!("[{}] {}", env.name, msg);
|
||||
} else {
|
||||
tracing::error!("Logging message from plugin {} failed!", env.name);
|
||||
}
|
||||
}
|
||||
|
||||
let ecs = Arc::new(EcsAccessManager::default());
|
||||
@ -70,9 +78,9 @@ impl PluginModule {
|
||||
// Create an import object.
|
||||
let import_object = imports! {
|
||||
"env" => {
|
||||
"raw_emit_actions" => Function::new_native_with_env(&store, HostFunctionEnvironement::new(name.clone(), ecs.clone(),memory_manager.clone()), raw_emit_actions),
|
||||
"raw_retrieve_action" => Function::new_native_with_env(&store, HostFunctionEnvironement::new(name.clone(), ecs.clone(),memory_manager.clone()), raw_retrieve_action),
|
||||
"dbg" => Function::new_native(&store, dbg),
|
||||
"raw_emit_actions" => Function::new_native_with_env(&store, HostFunctionEnvironment::new(name.clone(), ecs.clone(), memory_manager.clone()), raw_emit_actions),
|
||||
"raw_retrieve_action" => Function::new_native_with_env(&store, HostFunctionEnvironment::new(name.clone(), ecs.clone(), memory_manager.clone()), raw_retrieve_action),
|
||||
"raw_print" => Function::new_native_with_env(&store, HostFunctionEnvironment::new(name.clone(), ecs.clone(), memory_manager.clone()), raw_print),
|
||||
}
|
||||
};
|
||||
|
||||
@ -112,7 +120,7 @@ impl PluginModule {
|
||||
where
|
||||
T: Event,
|
||||
{
|
||||
if !self.events.contains(&request.function_name) {
|
||||
if !self.events.contains(request.function_name.as_ref()) {
|
||||
return None;
|
||||
}
|
||||
// Store the ECS Pointer for later use in `retreives`
|
||||
@ -131,7 +139,7 @@ impl PluginModule {
|
||||
/// reencoding for each module in every plugin)
|
||||
pub struct PreparedEventQuery<T> {
|
||||
bytes: Vec<u8>,
|
||||
function_name: String,
|
||||
function_name: Cow<'static, str>,
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
@ -214,17 +222,20 @@ fn execute_raw(
|
||||
.ok_or_else(PluginModuleError::InvalidArgumentType)?,
|
||||
);
|
||||
|
||||
let bytes = memory_manager::read_bytes(&module.memory, u128_pointer, 16);
|
||||
// TODO: Codify error
|
||||
let bytes = memory_manager::read_bytes(&module.memory, u128_pointer, 16).unwrap();
|
||||
|
||||
// We read the return object and deserialize it
|
||||
|
||||
// The first 8 bytes are encoded as le and represent the pointer to the data
|
||||
// The next 8 bytes are encoded as le and represent the length of the data
|
||||
// TODO: Codify error
|
||||
Ok(memory_manager::read_bytes(
|
||||
&module.memory,
|
||||
u64::from_le_bytes(bytes[0..8].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[8..16].try_into().unwrap()),
|
||||
))
|
||||
)
|
||||
.unwrap())
|
||||
}
|
||||
|
||||
fn retrieve_action(
|
||||
|
@ -9,7 +9,7 @@ use super::{
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct HostFunctionEnvironement {
|
||||
pub struct HostFunctionEnvironment {
|
||||
pub ecs: Arc<EcsAccessManager>, /* This represent the pointer to the ECS object (set to
|
||||
* i32::MAX if to ECS is
|
||||
* availible) */
|
||||
@ -20,7 +20,7 @@ pub struct HostFunctionEnvironement {
|
||||
pub name: String, // This represent the plugin name
|
||||
}
|
||||
|
||||
impl HostFunctionEnvironement {
|
||||
impl HostFunctionEnvironment {
|
||||
pub fn new(
|
||||
name: String,
|
||||
ecs: Arc<EcsAccessManager>,
|
||||
@ -67,9 +67,15 @@ impl HostFunctionEnvironement {
|
||||
) -> Result<T, bincode::Error> {
|
||||
memory_manager::read_data(self.memory.get_ref().unwrap(), position, length)
|
||||
}
|
||||
|
||||
/// This function is a safe interface to WASM memory that reads memory from
|
||||
/// pointer and length returning an object
|
||||
pub fn read_bytes(&self, position: u64, length: u64) -> Option<Vec<u8>> {
|
||||
memory_manager::read_bytes(self.memory.get_ref().unwrap(), position, length)
|
||||
}
|
||||
}
|
||||
|
||||
impl WasmerEnv for HostFunctionEnvironement {
|
||||
impl WasmerEnv for HostFunctionEnvironment {
|
||||
fn init_with_instance(&mut self, instance: &Instance) -> Result<(), HostEnvInitError> {
|
||||
let memory = instance.exports.get_memory("memory").unwrap();
|
||||
self.memory.initialize(memory.clone());
|
||||
|
@ -1,9 +1,8 @@
|
||||
pub extern crate common;
|
||||
//#![deny(missing_docs)]
|
||||
|
||||
pub use common::comp::Health;
|
||||
pub use common::{comp::Health, resources::GameMode, uid::Uid};
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
|
||||
pub use common::{resources::GameMode, uid::Uid};
|
||||
use std::borrow::Cow;
|
||||
|
||||
mod errors;
|
||||
|
||||
@ -97,7 +96,7 @@ pub enum RetrieveResult {
|
||||
pub trait Event: Serialize + DeserializeOwned + Send + Sync {
|
||||
type Response: Serialize + DeserializeOwned + Send + Sync;
|
||||
|
||||
fn get_event_name(&self) -> String;
|
||||
fn get_event_name(&self) -> Cow<'static, str>;
|
||||
}
|
||||
|
||||
/// This module contains all events from the api
|
||||
@ -141,7 +140,9 @@ pub mod event {
|
||||
impl Event for ChatCommandEvent {
|
||||
type Response = Result<Vec<String>, String>;
|
||||
|
||||
fn get_event_name(&self) -> String { format!("on_command_{}", self.command) }
|
||||
fn get_event_name(&self) -> Cow<'static, str> {
|
||||
Cow::Owned(format!("on_command_{}", self.command))
|
||||
}
|
||||
}
|
||||
|
||||
/// This struct represent a player
|
||||
@ -172,7 +173,7 @@ pub mod event {
|
||||
impl Event for PlayerJoinEvent {
|
||||
type Response = PlayerJoinResult;
|
||||
|
||||
fn get_event_name(&self) -> String { "on_join".to_owned() }
|
||||
fn get_event_name(&self) -> Cow<'static, str> { Cow::Borrowed("on_join") }
|
||||
}
|
||||
|
||||
/// This is the return type of an `on_join` event. See [`PlayerJoinEvent`]
|
||||
@ -213,7 +214,7 @@ pub mod event {
|
||||
impl Event for PluginLoadEvent {
|
||||
type Response = ();
|
||||
|
||||
fn get_event_name(&self) -> String { "on_load".to_owned() }
|
||||
fn get_event_name(&self) -> Cow<'static, str> { Cow::Borrowed("on_load") }
|
||||
}
|
||||
|
||||
// impl Default for PlayerJoinResult {
|
||||
|
@ -1,24 +1,35 @@
|
||||
pub extern crate plugin_derive;
|
||||
extern crate plugin_derive;
|
||||
|
||||
pub mod retrieve;
|
||||
|
||||
use api::RetrieveError;
|
||||
pub use retrieve::*;
|
||||
|
||||
use std::convert::TryInto;
|
||||
|
||||
pub use retrieve::*;
|
||||
|
||||
pub use plugin_api as api;
|
||||
pub use plugin_derive::*;
|
||||
pub use plugin_derive::{event_handler, global_state};
|
||||
pub use retrieve::*;
|
||||
|
||||
use api::RetrieveError;
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
use std::{convert::TryInto, marker::PhantomData};
|
||||
|
||||
pub struct Game {
|
||||
phantom: PhantomData<()>,
|
||||
}
|
||||
|
||||
impl Game {
|
||||
/// This is not strictly unsafe today, but it may become unsafe in the
|
||||
/// future. No safety guarantees are listed because we don't intend this
|
||||
/// to ever be manually called. Do not use this function!
|
||||
pub unsafe fn __new() -> Self {
|
||||
Self {
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
extern "C" {
|
||||
fn raw_emit_actions(ptr: i64, len: i64);
|
||||
fn raw_retrieve_action(ptr: i64, len: i64) -> i64;
|
||||
pub fn dbg(i: i32);
|
||||
fn raw_print(ptr: i64, len: i64);
|
||||
}
|
||||
|
||||
pub fn retrieve_action<T: DeserializeOwned>(_actions: &api::Retrieve) -> Result<T, RetrieveError> {
|
||||
@ -51,6 +62,19 @@ pub fn emit_actions(_actions: Vec<api::Action>) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_str(s: &str) {
|
||||
let bytes = s.as_bytes();
|
||||
unsafe {
|
||||
// Safety: ptr and len are valid for byte slice
|
||||
raw_print(to_i64(bytes.as_ptr() as _), to_i64(bytes.len() as _));
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! log {
|
||||
($($x:tt)*) => { $crate::print_str(&format!($($x)*)) };
|
||||
}
|
||||
|
||||
pub fn read_input<T>(ptr: i64, len: i64) -> Result<T, &'static str>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
|
Loading…
Reference in New Issue
Block a user