diff --git a/Cargo.lock b/Cargo.lock index d8426940ff..d394200d4c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5699,6 +5699,7 @@ name = "veloren-plugin-api" version = "0.1.0" dependencies = [ "serde", + "veloren-common", ] [[package]] diff --git a/assets/plugins/hello.wasm b/assets/plugins/hello.wasm new file mode 100644 index 0000000000..71c52f6d82 Binary files /dev/null and b/assets/plugins/hello.wasm differ diff --git a/assets/plugins/plugin1.plugin.tar b/assets/plugins/plugin1.plugin.tar index 98eed25770..c7fc024eec 100644 --- a/assets/plugins/plugin1.plugin.tar +++ b/assets/plugins/plugin1.plugin.tar @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ef354296a2db3ed7f8505db3ed252c8b5c575bc28801d4e1ab1ab0b3af3d433b -size 269312 +oid sha256:b478702b437788efbffdd1bc64b57ea4eb16fc476ba77dfb1142fbc1d1d3522a +size 288768 diff --git a/common/Cargo.toml b/common/Cargo.toml index 76aaca36c1..b0137d163f 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -13,6 +13,11 @@ bin_csv = ["csv", "structopt"] default = ["simd"] [dependencies] + +# Serde +serde = { version = "1.0.110", features = ["derive", "rc"] } + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] approx = "0.4.0" arraygen = "0.1.13" crossbeam-utils = "0.8.1" @@ -22,20 +27,34 @@ lazy_static = "1.4.0" num-derive = "0.3" num-traits = "0.2" ordered-float = { version = "2.0.1", default-features = false } -rand = "0.8" rayon = "1.5" roots = "0.0.6" spin_sleep = "1.0" tracing = { version = "0.1", default-features = false } vek = { version = "=0.12.0", features = ["serde"] } uuid = { version = "0.8.1", default-features = false, features = ["serde", "v4"] } +rand = "0.8" # Assets -assets_manager = {version = "0.4.2", features = ["bincode", "ron", "json", "hot-reloading"]} directories-next = "2.0" dot_vox = "4.0" image = { version = "0.23.12", default-features = false, features = ["png"] } +# Assets +assets_manager = {version = "0.4.2", features = ["bincode", "ron", "json", "hot-reloading"]} +# Serde +ron = { version = "0.6", default-features = false } +serde_json = "1.0.50" +serde_repr = "0.1.6" + +# esv export +csv = { version = "1.1.3", optional = true } +structopt = { version = "0.3.13", optional = true } + +# Tracy +tracy-client = { version = "0.10.0", optional = true } + + # Data structures hashbrown = { version = "0.9", features = ["rayon", "serde", "nightly"] } slotmap = { version = "1.0", features = ["serde"] } @@ -45,18 +64,6 @@ slab = "0.4.2" # ECS specs = { git = "https://github.com/amethyst/specs.git", features = ["serde", "storage-event-control", "nightly"], rev = "d4435bdf496cf322c74886ca09dd8795984919b4" } specs-idvs = { git = "https://gitlab.com/veloren/specs-idvs.git", rev = "9fab7b396acd6454585486e50ae4bfe2069858a9" } -# Serde -ron = { version = "0.6", default-features = false } -serde = { version = "1.0.110", features = ["derive", "rc"] } -serde_json = "1.0.50" -serde_repr = "0.1.6" - -#esv export -csv = { version = "1.1.3", optional = true } -structopt = { version = "0.3.13", optional = true } - -# Tracy -tracy-client = { version = "0.10.0", optional = true } [dev-dependencies] #bench diff --git a/common/src/lib.rs b/common/src/lib.rs index 37739b9b68..841fa50135 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -18,45 +18,66 @@ trait_alias, type_alias_impl_trait )] - +#[cfg(not(target_arch = "wasm32"))] pub mod assets; -pub mod astar; +#[cfg(not(target_arch = "wasm32"))] pub mod astar; +#[cfg(not(target_arch = "wasm32"))] pub mod character; -pub mod clock; -pub mod cmd; +#[cfg(not(target_arch = "wasm32"))] pub mod clock; +#[cfg(not(target_arch = "wasm32"))] pub mod cmd; +#[cfg(not(target_arch = "wasm32"))] pub mod combat; -pub mod comp; +#[cfg(not(target_arch = "wasm32"))] pub mod comp; +#[cfg(not(target_arch = "wasm32"))] pub mod consts; +#[cfg(not(target_arch = "wasm32"))] pub mod effect; -pub mod event; +#[cfg(not(target_arch = "wasm32"))] pub mod event; +#[cfg(not(target_arch = "wasm32"))] pub mod explosion; +#[cfg(not(target_arch = "wasm32"))] pub mod figure; +#[cfg(not(target_arch = "wasm32"))] pub mod generation; -pub mod grid; +#[cfg(not(target_arch = "wasm32"))] pub mod grid; +#[cfg(not(target_arch = "wasm32"))] pub mod lottery; +#[cfg(not(target_arch = "wasm32"))] pub mod metrics; -pub mod npc; +#[cfg(not(target_arch = "wasm32"))] pub mod npc; +#[cfg(not(target_arch = "wasm32"))] pub mod outcome; -pub mod path; -pub mod ray; +#[cfg(not(target_arch = "wasm32"))] pub mod path; +#[cfg(not(target_arch = "wasm32"))] pub mod ray; +#[cfg(not(target_arch = "wasm32"))] pub mod recipe; +#[cfg(not(target_arch = "wasm32"))] pub mod region; pub mod resources; -pub mod rtsim; +#[cfg(not(target_arch = "wasm32"))] pub mod rtsim; +#[cfg(not(target_arch = "wasm32"))] pub mod skillset_builder; +#[cfg(not(target_arch = "wasm32"))] pub mod spiral; +#[cfg(not(target_arch = "wasm32"))] pub mod states; -pub mod store; +#[cfg(not(target_arch = "wasm32"))] pub mod store; +#[cfg(not(target_arch = "wasm32"))] pub mod terrain; -pub mod time; -pub mod trade; -pub mod typed; +#[cfg(not(target_arch = "wasm32"))] pub mod time; +#[cfg(not(target_arch = "wasm32"))] pub mod trade; +#[cfg(not(target_arch = "wasm32"))] pub mod typed; pub mod uid; -pub mod util; -pub mod vol; +#[cfg(not(target_arch = "wasm32"))] pub mod util; +#[cfg(not(target_arch = "wasm32"))] pub mod vol; +#[cfg(not(target_arch = "wasm32"))] pub mod volumes; +#[cfg(not(target_arch = "wasm32"))] pub use combat::{Damage, DamageSource, GroupTarget, Knockback, KnockbackDir}; +#[cfg(not(target_arch = "wasm32"))] pub use comp::inventory::loadout_builder::LoadoutBuilder; +#[cfg(not(target_arch = "wasm32"))] pub use explosion::{Explosion, RadiusEffect}; +#[cfg(not(target_arch = "wasm32"))] pub use skillset_builder::SkillSetBuilder; diff --git a/common/src/uid.rs b/common/src/uid.rs index 22c5eb347f..1899a06299 100644 --- a/common/src/uid.rs +++ b/common/src/uid.rs @@ -1,5 +1,7 @@ +#[cfg(not(target_arch = "wasm32"))] use hashbrown::HashMap; use serde::{Deserialize, Serialize}; +#[cfg(not(target_arch = "wasm32"))] use specs::{ saveload::{Marker, MarkerAllocator}, world::EntitiesRes, @@ -22,10 +24,12 @@ impl fmt::Display for Uid { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.0) } } +#[cfg(not(target_arch = "wasm32"))] impl Component for Uid { type Storage = FlaggedStorage>; } +#[cfg(not(target_arch = "wasm32"))] impl Marker for Uid { type Allocator = UidAllocator; type Identifier = u64; @@ -37,11 +41,14 @@ impl Marker for Uid { } } +#[cfg(not(target_arch = "wasm32"))] +#[derive(Debug)] pub struct UidAllocator { index: u64, mapping: HashMap, } +#[cfg(not(target_arch = "wasm32"))] impl UidAllocator { pub fn new() -> Self { Self { @@ -55,10 +62,12 @@ impl UidAllocator { pub fn remove_entity(&mut self, id: u64) -> Option { self.mapping.remove(&id) } } +#[cfg(not(target_arch = "wasm32"))] impl Default for UidAllocator { fn default() -> Self { Self::new() } } +#[cfg(not(target_arch = "wasm32"))] impl MarkerAllocator for UidAllocator { fn allocate(&mut self, entity: Entity, id: Option) -> Uid { let id = id.unwrap_or_else(|| { diff --git a/common/sys/src/plugin/memory_manager.rs b/common/sys/src/plugin/memory_manager.rs index b242587a45..353909439b 100644 --- a/common/sys/src/plugin/memory_manager.rs +++ b/common/sys/src/plugin/memory_manager.rs @@ -1,49 +1,105 @@ -use std::sync::atomic::{AtomicI32, AtomicU32, Ordering}; +use std::sync::atomic::{AtomicI32, AtomicPtr, AtomicU32, AtomicU64, Ordering}; -use serde::{Serialize, de::DeserializeOwned}; +use serde::{de::DeserializeOwned, Serialize}; +use specs::World; use wasmer::{Function, Memory, Value}; use super::errors::{MemoryAllocationError, PluginModuleError}; +// This structure wraps the ECS pointer to ensure safety +pub struct EcsAccessManager { + ecs_pointer: AtomicPtr, +} + +impl Default for EcsAccessManager { + + fn default() -> Self { + Self { + ecs_pointer: AtomicPtr::new(std::ptr::null_mut::<_>()) + } + } +} + +impl EcsAccessManager { + + pub fn execute_with(&self, world: &World, func: impl FnOnce() -> T) -> T { + self.ecs_pointer.store(world as *const _ as *mut _, Ordering::SeqCst); + let out = func(); + self.ecs_pointer.store(std::ptr::null_mut::<_>(), Ordering::SeqCst); + out + } + + pub fn get(&self) -> Option<&World> { + // ptr::as_ref will automatically check for null + unsafe {self.ecs_pointer.load(Ordering::SeqCst).as_ref()} + } +} pub struct MemoryManager { pub pointer: AtomicI32, - pub length: AtomicU32 + pub length: AtomicU32, } -impl MemoryManager { - - pub fn new() -> Self{ +impl Default for MemoryManager { + fn default() -> Self { Self { pointer: AtomicI32::new(0), length: AtomicU32::new(0), } } +} - // This function check if the buffer is wide enough if not it realloc the buffer calling the `wasm_prepare_buffer` function - // Note: There is probably optimizations that can be done using less restrictive ordering - pub fn get_pointer(&self, object_length: u32, allocator: &Function) -> Result { +impl MemoryManager { + + // This function check if the buffer is wide enough if not it realloc the buffer + // calling the `wasm_prepare_buffer` function Note: There is probably + // optimizations that can be done using less restrictive ordering + pub fn get_pointer( + &self, + object_length: u32, + allocator: &Function, + ) -> Result { if self.length.load(Ordering::SeqCst) >= object_length { return Ok(self.pointer.load(Ordering::SeqCst)); } let pointer = allocator .call(&[Value::I32(object_length as i32)]) .map_err(MemoryAllocationError::CantAllocate)?; - let pointer= pointer[0].i32().ok_or(MemoryAllocationError::InvalidReturnType)?; + let pointer = pointer[0] + .i32() + .ok_or(MemoryAllocationError::InvalidReturnType)?; self.length.store(object_length, Ordering::SeqCst); self.pointer.store(pointer, Ordering::SeqCst); Ok(pointer) } - - // This function writes an object to WASM memory returning a pointer and a length. Will realloc the buffer is not wide enough - pub fn write_data(&self, memory: &Memory, allocator: &Function ,object: &T) -> Result<(i32,u32),PluginModuleError> { - self.write_bytes(memory,allocator,&bincode::serialize(object).map_err(PluginModuleError::Encoding)?) + + // This function writes an object to WASM memory returning a pointer and a + // length. Will realloc the buffer is not wide enough + pub fn write_data( + &self, + memory: &Memory, + allocator: &Function, + object: &T, + ) -> Result<(i32, u32), PluginModuleError> { + self.write_bytes( + memory, + allocator, + &bincode::serialize(object).map_err(PluginModuleError::Encoding)?, + ) } - // This function writes an raw bytes to WASM memory returning a pointer and a length. Will realloc the buffer is not wide enough - pub fn write_bytes(&self, memory: &Memory, allocator: &Function ,array: &[u8]) -> Result<(i32,u32),PluginModuleError> { + // This function writes an raw bytes to WASM memory returning a pointer and a + // length. Will realloc the buffer is not wide enough + pub fn write_bytes( + &self, + memory: &Memory, + allocator: &Function, + array: &[u8], + ) -> Result<(i32, u32), PluginModuleError> { let len = array.len(); - let mem_position = self.get_pointer(len as u32, allocator).map_err(PluginModuleError::MemoryAllocation)? as usize; + let mem_position = self + .get_pointer(len as u32, allocator) + .map_err(PluginModuleError::MemoryAllocation)? as usize; memory.view()[mem_position..mem_position + len] .iter() .zip(array.iter()) @@ -52,9 +108,14 @@ impl MemoryManager { } } -// This function read data from memory at a position with the array length and converts it to an object using bincode -pub fn read_data(memory: &Memory, position: i32, length: u32) -> Result { - bincode::deserialize(&read_bytes(memory,position,length)) +// This function read data from memory at a position with the array length and +// converts it to an object using bincode +pub fn read_data( + memory: &Memory, + position: i32, + length: u32, +) -> Result { + bincode::deserialize(&read_bytes(memory, position, length)) } // This function read raw bytes from memory at a position with the array length @@ -63,4 +124,4 @@ pub fn read_bytes(memory: &Memory, position: i32, length: u32) -> Vec { .iter() .map(|x| x.get()) .collect::>() -} \ No newline at end of file +} diff --git a/common/sys/src/plugin/mod.rs b/common/sys/src/plugin/mod.rs index c393dacf13..2d2c0a8342 100644 --- a/common/sys/src/plugin/mod.rs +++ b/common/sys/src/plugin/mod.rs @@ -1,7 +1,7 @@ pub mod errors; +pub mod memory_manager; pub mod module; pub mod wasm_env; -pub mod memory_manager; use common::assets::ASSETS_PATH; use serde::{Deserialize, Serialize}; diff --git a/common/sys/src/plugin/module.rs b/common/sys/src/plugin/module.rs index fe314936cc..a150d5af03 100644 --- a/common/sys/src/plugin/module.rs +++ b/common/sys/src/plugin/module.rs @@ -1,19 +1,19 @@ -use std::{collections::HashSet, convert::TryInto, marker::PhantomData, sync::{Arc, Mutex, atomic::AtomicI32}}; -use specs::World; -use wasmer::{ - imports, Cranelift, Function, Instance, Memory, Module, - Store, Value, JIT, -}; +use std::{collections::HashSet, convert::TryInto, marker::PhantomData, sync::{Arc, Mutex}}; -use super::{errors::{PluginError, PluginModuleError}, memory_manager::{self, MemoryManager}, wasm_env::HostFunctionEnvironement}; +use common::{comp::Player, uid::UidAllocator}; +use common_net::sync::WorldSyncExt; +use specs::{World, WorldExt, saveload::MarkerAllocator}; +use wasmer::{imports, Cranelift, Function, Instance, Memory, Module, Store, Value, JIT}; -use plugin_api::{Action, Event}; +use super::{errors::{PluginError, PluginModuleError}, memory_manager::{self, EcsAccessManager, MemoryManager}, wasm_env::HostFunctionEnvironement}; + +use plugin_api::{Action, Event, Retreive}; #[derive(Clone)] // This structure represent the WASM State of the plugin. pub struct PluginModule { - ecs: Arc, + ecs: Arc, wasm_state: Arc>, memory_manager: Arc, events: HashSet, @@ -43,13 +43,42 @@ impl PluginModule { }); } - let ecs = Arc::new(AtomicI32::new(i32::MAX)); - let memory_manager = Arc::new(MemoryManager::new()); + fn raw_retreive_action(env: &HostFunctionEnvironement, ptr: u32, len: u32) -> i64 { + + println!("HOST DEBUG 1"); + // TODO: Handle correctly the error + let data: Retreive = env.read_data(ptr as _, len).unwrap(); + println!("HOST DEBUG 2"); + + let out = match data { + Retreive::GetEntityName(e) => { + println!("HOST DEBUG 3 {:?}",env.ecs.get().is_some()); + let world = env.ecs.get().expect("Can't get entity name because ECS pointer isn't set"); + println!("HOST DEBUG 4 {}",world.has_value::()); + println!("HOST DEBUG 5 {:?}",&*world.read_resource::()); + let player = world.read_resource::().retrieve_entity_internal(e.0).expect("Invalid uid"); + println!("HOST DEBUG 6"); + format!("{:?}",world.read_component::().get(player)) + } + }; + println!("{}",out); + let (ptr,len) = env.write_data(&out).unwrap(); + to_i64(ptr, len as _) + } + + fn dbg(a: i32) { + println!("WASM DEBUG: {}",a); + } + + let ecs = Arc::new(EcsAccessManager::default()); + let memory_manager = Arc::new(MemoryManager::default()); // 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_retreive_action" => Function::new_native_with_env(&store, HostFunctionEnvironement::new(name.clone(), ecs.clone(),memory_manager.clone()), raw_retreive_action), + "dbg" => Function::new_native(&store, dbg), } }; @@ -59,8 +88,16 @@ impl PluginModule { Ok(Self { memory_manager, ecs, - memory: instance.exports.get_memory("memory").map_err(PluginModuleError::MemoryUninit)?.clone(), - allocator: instance.exports.get_function("wasm_prepare_buffer").map_err(PluginModuleError::MemoryUninit)?.clone(), + memory: instance + .exports + .get_memory("memory") + .map_err(PluginModuleError::MemoryUninit)? + .clone(), + allocator: instance + .exports + .get_function("wasm_prepare_buffer") + .map_err(PluginModuleError::MemoryUninit)? + .clone(), events: instance .exports .iter() @@ -86,21 +123,17 @@ impl PluginModule { return None; } // Store the ECS Pointer for later use in `retreives` - self.ecs.store((&ecs) as *const _ as i32, std::sync::atomic::Ordering::SeqCst); - let bytes = { + let bytes = match self.ecs.execute_with(ecs, || { let mut state = self.wasm_state.lock().unwrap(); - match execute_raw(self,&mut state,event_name,&request.bytes) { - Ok(e) => e, - Err(e) => return Some(Err(e)), - } + execute_raw(self, &mut state, event_name, &request.bytes) + }) { + Ok(e) => e, + Err(e) => return Some(Err(e)), }; - // Remove the ECS Pointer to avoid UB - self.ecs.store(i32::MAX, std::sync::atomic::Ordering::SeqCst); Some(bincode::deserialize(&bytes).map_err(PluginModuleError::Encoding)) } } - // This structure represent a Pre-encoded event object (Useful to avoid // reencoding for each module in every plugin) pub struct PreparedEventQuery { @@ -122,9 +155,18 @@ impl PreparedEventQuery { } } -fn from_i64(i: i64) -> (i32,i32) { +fn from_i64(i: i64) -> (i32, i32) { let i = i.to_le_bytes(); - (i32::from_le_bytes(i[0..4].try_into().unwrap()),i32::from_le_bytes(i[4..8].try_into().unwrap())) + ( + i32::from_le_bytes(i[0..4].try_into().unwrap()), + i32::from_le_bytes(i[4..8].try_into().unwrap()), + ) +} + +pub fn to_i64(a: i32, b: i32) -> i64 { + let a = a.to_le_bytes(); + let b = b.to_le_bytes(); + i64::from_le_bytes([a[0], a[1], a[2], a[3], b[0], b[1], b[2], b[3]]) } // This function is not public because this function should not be used without @@ -136,10 +178,13 @@ fn execute_raw( event_name: &str, bytes: &[u8], ) -> Result, PluginModuleError> { + // This write into memory `bytes` using allocation if necessary returning a + // pointer and a length - // This write into memory `bytes` using allocation if necessary returning a pointer and a length - - let (mem_position,len) = module.memory_manager.write_bytes(&module.memory, &module.allocator, bytes)?; + let (mem_position, len) = + module + .memory_manager + .write_bytes(&module.memory, &module.allocator, bytes)?; // This gets the event function from module exports @@ -153,16 +198,23 @@ fn execute_raw( let function_result = func .call(&[Value::I32(mem_position as i32), Value::I32(len as i32)]) .map_err(PluginModuleError::RunFunction)?; - - // Waiting for `multi-value` to be added to LLVM. So we encode the two i32 as an i64 - let (pointer,length) = from_i64(function_result[0] - .i64() - .ok_or_else(PluginModuleError::InvalidArgumentType)?); + // Waiting for `multi-value` to be added to LLVM. So we encode the two i32 as an + // i64 + + let (pointer, length) = from_i64( + function_result[0] + .i64() + .ok_or_else(PluginModuleError::InvalidArgumentType)?, + ); // We read the return object and deserialize it - Ok(memory_manager::read_bytes(&module.memory, pointer, length as u32)) + Ok(memory_manager::read_bytes( + &module.memory, + pointer, + length as u32, + )) } fn handle_actions(actions: Vec) { diff --git a/common/sys/src/plugin/wasm_env.rs b/common/sys/src/plugin/wasm_env.rs index fc332fc505..ddacc968b2 100644 --- a/common/sys/src/plugin/wasm_env.rs +++ b/common/sys/src/plugin/wasm_env.rs @@ -1,22 +1,23 @@ -use std::sync::Arc; -use std::sync::atomic::AtomicI32; +use std::sync::{atomic::AtomicI32, Arc}; -use serde::{Serialize, de::DeserializeOwned}; +use serde::{de::DeserializeOwned, Serialize}; use wasmer::{Function, HostEnvInitError, Instance, LazyInit, Memory, WasmerEnv}; -use super::{errors::PluginModuleError, memory_manager::{self, MemoryManager}}; +use super::{errors::PluginModuleError, memory_manager::{self, EcsAccessManager, MemoryManager}}; #[derive(Clone)] pub struct HostFunctionEnvironement { - pub ecs: Arc, // This represent the pointer to the ECS object (set to i32::MAX if to ECS is availible) + pub ecs: Arc, /* This represent the pointer to the ECS object (set to i32::MAX if + * to ECS is availible) */ pub memory: LazyInit, // This object represent the WASM Memory pub allocator: LazyInit, // Linked to: wasm_prepare_buffer - pub memory_manager: Arc, // This object represent the current buffer size and pointer + pub memory_manager: Arc, /* This object represent the current buffer size and + * pointer */ pub name: String, // This represent the plugin name } impl HostFunctionEnvironement { - pub fn new(name: String,ecs: Arc,memory_manager: Arc) -> Self { + pub fn new(name: String, ecs: Arc, memory_manager: Arc) -> Self { Self { memory_manager, ecs, @@ -26,13 +27,23 @@ impl HostFunctionEnvironement { } } - // This function is a safe interface to WASM memory that writes data to the memory returning a pointer and length - pub fn write_data(&self, object: &T) -> Result<(i32,u32),PluginModuleError> { - self.memory_manager.write_data(self.memory.get_ref().unwrap(), self.allocator.get_ref().unwrap(), object) + // This function is a safe interface to WASM memory that writes data to the + // memory returning a pointer and length + pub fn write_data(&self, object: &T) -> Result<(i32, u32), PluginModuleError> { + self.memory_manager.write_data( + self.memory.get_ref().unwrap(), + self.allocator.get_ref().unwrap(), + object, + ) } - // This function is a safe interface to WASM memory that reads memory from pointer and length returning an object - pub fn read_data(&self, position: i32, length: u32) -> Result { + // This function is a safe interface to WASM memory that reads memory from + // pointer and length returning an object + pub fn read_data( + &self, + position: i32, + length: u32, + ) -> Result { memory_manager::read_data(self.memory.get_ref().unwrap(), position, length) } } @@ -41,8 +52,11 @@ impl WasmerEnv for HostFunctionEnvironement { fn init_with_instance(&mut self, instance: &Instance) -> Result<(), HostEnvInitError> { let memory = instance.exports.get_memory("memory").unwrap(); self.memory.initialize(memory.clone()); - let allocator = instance.exports.get_function("wasm_prepare_buffer").expect("Can't get allocator"); + let allocator = instance + .exports + .get_function("wasm_prepare_buffer") + .expect("Can't get allocator"); self.allocator.initialize(allocator.clone()); Ok(()) } -} \ No newline at end of file +} diff --git a/common/sys/src/state.rs b/common/sys/src/state.rs index a58cdfd26f..3f0bad997a 100644 --- a/common/sys/src/state.rs +++ b/common/sys/src/state.rs @@ -208,12 +208,14 @@ impl State { #[cfg(feature = "plugins")] ecs.insert(match PluginMgr::from_assets() { Ok(plugin_mgr) => { - if let Err(e) = plugin_mgr - .execute_event(&ecs,"on_load", &plugin_api::event::PluginLoadEvent { game_mode: match game_mode { - resources::GameMode::Server => plugin_api::GameMode::Server, - resources::GameMode::Client => plugin_api::GameMode::Client, - resources::GameMode::Singleplayer => plugin_api::GameMode::Singleplayer, - } }) + if let Err(e) = + plugin_mgr.execute_event(&ecs, "on_load", &plugin_api::event::PluginLoadEvent { + game_mode: match game_mode { + resources::GameMode::Server => plugin_api::GameMode::Server, + resources::GameMode::Client => plugin_api::GameMode::Client, + resources::GameMode::Singleplayer => plugin_api::GameMode::Singleplayer, + }, + }) { tracing::error!(?e, "Failed to run plugin init"); tracing::info!( diff --git a/plugin/api/Cargo.toml b/plugin/api/Cargo.toml index db865e87e5..84d8e9b270 100644 --- a/plugin/api/Cargo.toml +++ b/plugin/api/Cargo.toml @@ -6,3 +6,4 @@ edition = "2018" [dependencies] serde = { version = "1.0.118", features = ["derive"] } +common = { package = "veloren-common", path = "../../common", features = ["no-assets"] } diff --git a/plugin/api/src/lib.rs b/plugin/api/src/lib.rs index 510169de17..ffaf761e94 100644 --- a/plugin/api/src/lib.rs +++ b/plugin/api/src/lib.rs @@ -1,8 +1,7 @@ - -use std::fmt; - use serde::{de::DeserializeOwned, Deserialize, Serialize}; +pub use common::{resources::GameMode, uid::Uid}; + #[derive(Deserialize, Serialize, Debug)] pub enum Action { ServerClose, @@ -20,35 +19,6 @@ pub trait Event: Serialize + DeserializeOwned + Send + Sync { type Response: Serialize + DeserializeOwned + Send + Sync; } -#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] -pub struct Uid(pub u64); - -impl Into for Uid { - fn into(self) -> u64 { self.0 } -} - -impl From for Uid { - fn from(uid: u64) -> Self { Self(uid) } -} - -impl fmt::Display for Uid { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.0) } -} - -#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] -pub enum GameMode { - /// The game is being played in server mode (i.e: the code is running - /// server-side) - Server, - /// The game is being played in client mode (i.e: the code is running - /// client-side) - Client, - /// The game is being played in singleplayer mode (i.e: both client and - /// server at once) - // To be used later when we no longer start up an entirely new server for singleplayer - Singleplayer, -} - pub mod event { use super::*; use serde::{Deserialize, Serialize}; diff --git a/plugin/rt/examples/hello.rs b/plugin/rt/examples/hello.rs index 2f596f1a02..6bf7c836a9 100644 --- a/plugin/rt/examples/hello.rs +++ b/plugin/rt/examples/hello.rs @@ -3,7 +3,7 @@ use veloren_plugin_rt::{ *, }; -#[veloren_plugin_rt::event_handler] +#[event_handler] pub fn on_load(load: PluginLoadEvent) { match load.game_mode { GameMode::Server => emit_action(Action::Print("Hello, server!".to_owned())), @@ -15,13 +15,11 @@ pub fn on_load(load: PluginLoadEvent) { #[event_handler] pub fn on_command_testplugin(command: ChatCommandEvent) -> Result, String> { Ok(vec![format!( - "Player of id {:?} sended command with args {:?}", - command.player, command.command_args + "Player of id {:?} named {} sended command with args {:?}", + command.player, command.player.get_entity_name(), command.command_args )]) } - - #[event_handler] pub fn on_player_join(input: PlayerJoinEvent) -> PlayerJoinResult { emit_action(Action::PlayerSendMessage( diff --git a/plugin/rt/src/lib.rs b/plugin/rt/src/lib.rs index d8aa0d4006..c5872f1d05 100644 --- a/plugin/rt/src/lib.rs +++ b/plugin/rt/src/lib.rs @@ -4,6 +4,8 @@ pub extern crate plugin_derive; pub mod retreive; +pub use retreive::*; + use std::convert::TryInto; pub use retreive::*; @@ -16,22 +18,28 @@ use serde::{de::DeserializeOwned, Serialize}; #[cfg(target_arch = "wasm32")] extern "C" { fn raw_emit_actions(ptr: *const u8, len: usize); - //fn raw_retreive_action(ptr: *const u8, len: usize) -> (i32, u32); + fn raw_retreive_action(ptr: *const u8, len: usize) -> i64; + pub fn dbg(i: i32); } -// pub fn retreive_action(_actions: &api::Retreive) -> Result { -// #[cfg(target_arch = "wasm32")] -// { -// let ret = bincode::serialize(&_actions).expect("Can't serialize action in emit"); -// unsafe { -// let (ptr,len) = raw_retreive_action(ret.as_ptr(), ret.len()); -// let a = ::std::slice::from_raw_parts(ptr as _, len as _); -// bincode::deserialize(&a) -// } -// } -// #[cfg(not(target_arch = "wasm32"))] -// unreachable!() -// } +pub fn retreive_action(_actions: &api::Retreive) -> Result { + #[cfg(target_arch = "wasm32")] + { + unsafe{dbg(0);} + let ret = bincode::serialize(&_actions).expect("Can't serialize action in emit"); + unsafe{dbg(1);} + unsafe { + dbg(2); + let (ptr,len) = from_i64(raw_retreive_action(ret.as_ptr(), ret.len())); + dbg(3); + let a = ::std::slice::from_raw_parts(ptr as _, len as _); + dbg(4); + bincode::deserialize(&a) + } + } + #[cfg(not(target_arch = "wasm32"))] + unreachable!() +} pub fn emit_action(action: api::Action) { emit_actions(vec![action]) } @@ -53,10 +61,18 @@ where bincode::deserialize(slice).map_err(|_| "Failed to deserialize function input") } +pub fn from_i64(i: i64) -> (i32, i32) { + let i = i.to_le_bytes(); + ( + i32::from_le_bytes(i[0..4].try_into().unwrap()), + i32::from_le_bytes(i[4..8].try_into().unwrap()), + ) +} + pub fn to_i64(a: i32, b: i32) -> i64 { let a = a.to_le_bytes(); let b = b.to_le_bytes(); - i64::from_le_bytes([a[0],a[1],a[2],a[3],b[0],b[1],b[2],b[3]]) + i64::from_le_bytes([a[0], a[1], a[2], a[3], b[0], b[1], b[2], b[3]]) } pub fn write_output(value: impl Serialize) -> i64 { diff --git a/plugin/rt/src/retreive.rs b/plugin/rt/src/retreive.rs index 1a805307ed..b214009776 100644 --- a/plugin/rt/src/retreive.rs +++ b/plugin/rt/src/retreive.rs @@ -1,13 +1,15 @@ use crate::api::Retreive; -trait GetEntityName { +pub trait GetEntityName { fn get_entity_name(&self) -> String; } impl GetEntityName for crate::api::event::Player { - fn get_entity_name(&self) -> String { - // crate::retreive_action(&Retreive::GetEntityName(self.id)).expect("Can't get entity name") - String::new() + #[cfg(target_arch = "wasm32")] + unsafe { + crate::dbg(-1); + } + crate::retreive_action(&Retreive::GetEntityName(self.id)).expect("Can't get entity name") } -} \ No newline at end of file +} diff --git a/server/src/lib.rs b/server/src/lib.rs index c45175d2a8..70a3bd2aec 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -1037,12 +1037,15 @@ impl Server { command: kwd.clone(), command_args: args.split(' ').map(|x| x.to_owned()).collect(), player: plugin_api::event::Player { - id: plugin_api::Uid((self - .state - .ecs() - .read_storage::() - .get(entity) - .expect("Can't get player UUID [This should never appen]")).0), + id: plugin_api::Uid( + (self + .state + .ecs() + .read_storage::() + .get(entity) + .expect("Can't get player UUID [This should never appen]")) + .0, + ), }, }, );