mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Retrieves added + New ECS memory layout for plugins
This commit is contained in:
parent
1597fcc79e
commit
06aa7ab70c
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -5699,6 +5699,7 @@ name = "veloren-plugin-api"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
|
"veloren-common",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
BIN
assets/plugins/hello.wasm
Normal file
BIN
assets/plugins/hello.wasm
Normal file
Binary file not shown.
BIN
assets/plugins/plugin1.plugin.tar
(Stored with Git LFS)
BIN
assets/plugins/plugin1.plugin.tar
(Stored with Git LFS)
Binary file not shown.
@ -13,6 +13,11 @@ bin_csv = ["csv", "structopt"]
|
|||||||
default = ["simd"]
|
default = ["simd"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
||||||
|
# Serde
|
||||||
|
serde = { version = "1.0.110", features = ["derive", "rc"] }
|
||||||
|
|
||||||
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
approx = "0.4.0"
|
approx = "0.4.0"
|
||||||
arraygen = "0.1.13"
|
arraygen = "0.1.13"
|
||||||
crossbeam-utils = "0.8.1"
|
crossbeam-utils = "0.8.1"
|
||||||
@ -22,20 +27,34 @@ lazy_static = "1.4.0"
|
|||||||
num-derive = "0.3"
|
num-derive = "0.3"
|
||||||
num-traits = "0.2"
|
num-traits = "0.2"
|
||||||
ordered-float = { version = "2.0.1", default-features = false }
|
ordered-float = { version = "2.0.1", default-features = false }
|
||||||
rand = "0.8"
|
|
||||||
rayon = "1.5"
|
rayon = "1.5"
|
||||||
roots = "0.0.6"
|
roots = "0.0.6"
|
||||||
spin_sleep = "1.0"
|
spin_sleep = "1.0"
|
||||||
tracing = { version = "0.1", default-features = false }
|
tracing = { version = "0.1", default-features = false }
|
||||||
vek = { version = "=0.12.0", features = ["serde"] }
|
vek = { version = "=0.12.0", features = ["serde"] }
|
||||||
uuid = { version = "0.8.1", default-features = false, features = ["serde", "v4"] }
|
uuid = { version = "0.8.1", default-features = false, features = ["serde", "v4"] }
|
||||||
|
rand = "0.8"
|
||||||
|
|
||||||
# Assets
|
# Assets
|
||||||
assets_manager = {version = "0.4.2", features = ["bincode", "ron", "json", "hot-reloading"]}
|
|
||||||
directories-next = "2.0"
|
directories-next = "2.0"
|
||||||
dot_vox = "4.0"
|
dot_vox = "4.0"
|
||||||
image = { version = "0.23.12", default-features = false, features = ["png"] }
|
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
|
# Data structures
|
||||||
hashbrown = { version = "0.9", features = ["rayon", "serde", "nightly"] }
|
hashbrown = { version = "0.9", features = ["rayon", "serde", "nightly"] }
|
||||||
slotmap = { version = "1.0", features = ["serde"] }
|
slotmap = { version = "1.0", features = ["serde"] }
|
||||||
@ -45,18 +64,6 @@ slab = "0.4.2"
|
|||||||
# ECS
|
# ECS
|
||||||
specs = { git = "https://github.com/amethyst/specs.git", features = ["serde", "storage-event-control", "nightly"], rev = "d4435bdf496cf322c74886ca09dd8795984919b4" }
|
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" }
|
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]
|
[dev-dependencies]
|
||||||
#bench
|
#bench
|
||||||
|
@ -18,45 +18,66 @@
|
|||||||
trait_alias,
|
trait_alias,
|
||||||
type_alias_impl_trait
|
type_alias_impl_trait
|
||||||
)]
|
)]
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub mod assets;
|
pub mod assets;
|
||||||
pub mod astar;
|
#[cfg(not(target_arch = "wasm32"))] pub mod astar;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub mod character;
|
pub mod character;
|
||||||
pub mod clock;
|
#[cfg(not(target_arch = "wasm32"))] pub mod clock;
|
||||||
pub mod cmd;
|
#[cfg(not(target_arch = "wasm32"))] pub mod cmd;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub mod combat;
|
pub mod combat;
|
||||||
pub mod comp;
|
#[cfg(not(target_arch = "wasm32"))] pub mod comp;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub mod consts;
|
pub mod consts;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub mod effect;
|
pub mod effect;
|
||||||
pub mod event;
|
#[cfg(not(target_arch = "wasm32"))] pub mod event;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub mod explosion;
|
pub mod explosion;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub mod figure;
|
pub mod figure;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub mod generation;
|
pub mod generation;
|
||||||
pub mod grid;
|
#[cfg(not(target_arch = "wasm32"))] pub mod grid;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub mod lottery;
|
pub mod lottery;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub mod metrics;
|
pub mod metrics;
|
||||||
pub mod npc;
|
#[cfg(not(target_arch = "wasm32"))] pub mod npc;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub mod outcome;
|
pub mod outcome;
|
||||||
pub mod path;
|
#[cfg(not(target_arch = "wasm32"))] pub mod path;
|
||||||
pub mod ray;
|
#[cfg(not(target_arch = "wasm32"))] pub mod ray;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub mod recipe;
|
pub mod recipe;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub mod region;
|
pub mod region;
|
||||||
pub mod resources;
|
pub mod resources;
|
||||||
pub mod rtsim;
|
#[cfg(not(target_arch = "wasm32"))] pub mod rtsim;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub mod skillset_builder;
|
pub mod skillset_builder;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub mod spiral;
|
pub mod spiral;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub mod states;
|
pub mod states;
|
||||||
pub mod store;
|
#[cfg(not(target_arch = "wasm32"))] pub mod store;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub mod terrain;
|
pub mod terrain;
|
||||||
pub mod time;
|
#[cfg(not(target_arch = "wasm32"))] pub mod time;
|
||||||
pub mod trade;
|
#[cfg(not(target_arch = "wasm32"))] pub mod trade;
|
||||||
pub mod typed;
|
#[cfg(not(target_arch = "wasm32"))] pub mod typed;
|
||||||
pub mod uid;
|
pub mod uid;
|
||||||
pub mod util;
|
#[cfg(not(target_arch = "wasm32"))] pub mod util;
|
||||||
pub mod vol;
|
#[cfg(not(target_arch = "wasm32"))] pub mod vol;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub mod volumes;
|
pub mod volumes;
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub use combat::{Damage, DamageSource, GroupTarget, Knockback, KnockbackDir};
|
pub use combat::{Damage, DamageSource, GroupTarget, Knockback, KnockbackDir};
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub use comp::inventory::loadout_builder::LoadoutBuilder;
|
pub use comp::inventory::loadout_builder::LoadoutBuilder;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub use explosion::{Explosion, RadiusEffect};
|
pub use explosion::{Explosion, RadiusEffect};
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub use skillset_builder::SkillSetBuilder;
|
pub use skillset_builder::SkillSetBuilder;
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
use specs::{
|
use specs::{
|
||||||
saveload::{Marker, MarkerAllocator},
|
saveload::{Marker, MarkerAllocator},
|
||||||
world::EntitiesRes,
|
world::EntitiesRes,
|
||||||
@ -22,10 +24,12 @@ impl fmt::Display for Uid {
|
|||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.0) }
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
impl Component for Uid {
|
impl Component for Uid {
|
||||||
type Storage = FlaggedStorage<Self, VecStorage<Self>>;
|
type Storage = FlaggedStorage<Self, VecStorage<Self>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
impl Marker for Uid {
|
impl Marker for Uid {
|
||||||
type Allocator = UidAllocator;
|
type Allocator = UidAllocator;
|
||||||
type Identifier = u64;
|
type Identifier = u64;
|
||||||
@ -37,11 +41,14 @@ impl Marker for Uid {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct UidAllocator {
|
pub struct UidAllocator {
|
||||||
index: u64,
|
index: u64,
|
||||||
mapping: HashMap<u64, Entity>,
|
mapping: HashMap<u64, Entity>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
impl UidAllocator {
|
impl UidAllocator {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -55,10 +62,12 @@ impl UidAllocator {
|
|||||||
pub fn remove_entity(&mut self, id: u64) -> Option<Entity> { self.mapping.remove(&id) }
|
pub fn remove_entity(&mut self, id: u64) -> Option<Entity> { self.mapping.remove(&id) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
impl Default for UidAllocator {
|
impl Default for UidAllocator {
|
||||||
fn default() -> Self { Self::new() }
|
fn default() -> Self { Self::new() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
impl MarkerAllocator<Uid> for UidAllocator {
|
impl MarkerAllocator<Uid> for UidAllocator {
|
||||||
fn allocate(&mut self, entity: Entity, id: Option<u64>) -> Uid {
|
fn allocate(&mut self, entity: Entity, id: Option<u64>) -> Uid {
|
||||||
let id = id.unwrap_or_else(|| {
|
let id = id.unwrap_or_else(|| {
|
||||||
|
@ -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 wasmer::{Function, Memory, Value};
|
||||||
|
|
||||||
use super::errors::{MemoryAllocationError, PluginModuleError};
|
use super::errors::{MemoryAllocationError, PluginModuleError};
|
||||||
|
|
||||||
|
// This structure wraps the ECS pointer to ensure safety
|
||||||
|
pub struct EcsAccessManager {
|
||||||
|
ecs_pointer: AtomicPtr<World>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for EcsAccessManager {
|
||||||
|
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
ecs_pointer: AtomicPtr::new(std::ptr::null_mut::<_>())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EcsAccessManager {
|
||||||
|
|
||||||
|
pub fn execute_with<T>(&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 struct MemoryManager {
|
||||||
pub pointer: AtomicI32,
|
pub pointer: AtomicI32,
|
||||||
pub length: AtomicU32
|
pub length: AtomicU32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MemoryManager {
|
impl Default for MemoryManager {
|
||||||
|
fn default() -> Self {
|
||||||
pub fn new() -> Self{
|
|
||||||
Self {
|
Self {
|
||||||
pointer: AtomicI32::new(0),
|
pointer: AtomicI32::new(0),
|
||||||
length: AtomicU32::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
|
impl MemoryManager {
|
||||||
// Note: There is probably optimizations that can be done using less restrictive ordering
|
|
||||||
pub fn get_pointer(&self, object_length: u32, allocator: &Function) -> Result<i32,MemoryAllocationError> {
|
// 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<i32, MemoryAllocationError> {
|
||||||
if self.length.load(Ordering::SeqCst) >= object_length {
|
if self.length.load(Ordering::SeqCst) >= object_length {
|
||||||
return Ok(self.pointer.load(Ordering::SeqCst));
|
return Ok(self.pointer.load(Ordering::SeqCst));
|
||||||
}
|
}
|
||||||
let pointer = allocator
|
let pointer = allocator
|
||||||
.call(&[Value::I32(object_length as i32)])
|
.call(&[Value::I32(object_length as i32)])
|
||||||
.map_err(MemoryAllocationError::CantAllocate)?;
|
.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.length.store(object_length, Ordering::SeqCst);
|
||||||
self.pointer.store(pointer, Ordering::SeqCst);
|
self.pointer.store(pointer, Ordering::SeqCst);
|
||||||
Ok(pointer)
|
Ok(pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function writes an object to WASM memory returning a pointer and a length. Will realloc the buffer is not wide enough
|
// This function writes an object to WASM memory returning a pointer and a
|
||||||
pub fn write_data<T: Serialize>(&self, memory: &Memory, allocator: &Function ,object: &T) -> Result<(i32,u32),PluginModuleError> {
|
// length. Will realloc the buffer is not wide enough
|
||||||
self.write_bytes(memory,allocator,&bincode::serialize(object).map_err(PluginModuleError::Encoding)?)
|
pub fn write_data<T: Serialize>(
|
||||||
|
&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
|
// This function writes an raw bytes to WASM memory returning a pointer and a
|
||||||
pub fn write_bytes(&self, memory: &Memory, allocator: &Function ,array: &[u8]) -> Result<(i32,u32),PluginModuleError> {
|
// 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 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]
|
memory.view()[mem_position..mem_position + len]
|
||||||
.iter()
|
.iter()
|
||||||
.zip(array.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
|
// This function read data from memory at a position with the array length and
|
||||||
pub fn read_data<T: DeserializeOwned>(memory: &Memory, position: i32, length: u32) -> Result<T, bincode::Error> {
|
// converts it to an object using bincode
|
||||||
bincode::deserialize(&read_bytes(memory,position,length))
|
pub fn read_data<T: DeserializeOwned>(
|
||||||
|
memory: &Memory,
|
||||||
|
position: i32,
|
||||||
|
length: u32,
|
||||||
|
) -> Result<T, bincode::Error> {
|
||||||
|
bincode::deserialize(&read_bytes(memory, position, length))
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function read raw bytes from memory at a position with the array 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<u8> {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|x| x.get())
|
.map(|x| x.get())
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
pub mod errors;
|
pub mod errors;
|
||||||
|
pub mod memory_manager;
|
||||||
pub mod module;
|
pub mod module;
|
||||||
pub mod wasm_env;
|
pub mod wasm_env;
|
||||||
pub mod memory_manager;
|
|
||||||
|
|
||||||
use common::assets::ASSETS_PATH;
|
use common::assets::ASSETS_PATH;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
use std::{collections::HashSet, convert::TryInto, marker::PhantomData, sync::{Arc, Mutex, atomic::AtomicI32}};
|
|
||||||
|
|
||||||
use specs::World;
|
use std::{collections::HashSet, convert::TryInto, marker::PhantomData, sync::{Arc, Mutex}};
|
||||||
use wasmer::{
|
|
||||||
imports, Cranelift, Function, Instance, Memory, Module,
|
|
||||||
Store, Value, JIT,
|
|
||||||
};
|
|
||||||
|
|
||||||
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)]
|
#[derive(Clone)]
|
||||||
// This structure represent the WASM State of the plugin.
|
// This structure represent the WASM State of the plugin.
|
||||||
pub struct PluginModule {
|
pub struct PluginModule {
|
||||||
ecs: Arc<AtomicI32>,
|
ecs: Arc<EcsAccessManager>,
|
||||||
wasm_state: Arc<Mutex<Instance>>,
|
wasm_state: Arc<Mutex<Instance>>,
|
||||||
memory_manager: Arc<MemoryManager>,
|
memory_manager: Arc<MemoryManager>,
|
||||||
events: HashSet<String>,
|
events: HashSet<String>,
|
||||||
@ -43,13 +43,42 @@ impl PluginModule {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let ecs = Arc::new(AtomicI32::new(i32::MAX));
|
fn raw_retreive_action(env: &HostFunctionEnvironement, ptr: u32, len: u32) -> i64 {
|
||||||
let memory_manager = Arc::new(MemoryManager::new());
|
|
||||||
|
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::<UidAllocator>());
|
||||||
|
println!("HOST DEBUG 5 {:?}",&*world.read_resource::<UidAllocator>());
|
||||||
|
let player = world.read_resource::<UidAllocator>().retrieve_entity_internal(e.0).expect("Invalid uid");
|
||||||
|
println!("HOST DEBUG 6");
|
||||||
|
format!("{:?}",world.read_component::<Player>().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.
|
// Create an import object.
|
||||||
let import_object = imports! {
|
let import_object = imports! {
|
||||||
"env" => {
|
"env" => {
|
||||||
"raw_emit_actions" => Function::new_native_with_env(&store, HostFunctionEnvironement::new(name.clone(), ecs.clone(),memory_manager.clone()), raw_emit_actions),
|
"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 {
|
Ok(Self {
|
||||||
memory_manager,
|
memory_manager,
|
||||||
ecs,
|
ecs,
|
||||||
memory: instance.exports.get_memory("memory").map_err(PluginModuleError::MemoryUninit)?.clone(),
|
memory: instance
|
||||||
allocator: instance.exports.get_function("wasm_prepare_buffer").map_err(PluginModuleError::MemoryUninit)?.clone(),
|
.exports
|
||||||
|
.get_memory("memory")
|
||||||
|
.map_err(PluginModuleError::MemoryUninit)?
|
||||||
|
.clone(),
|
||||||
|
allocator: instance
|
||||||
|
.exports
|
||||||
|
.get_function("wasm_prepare_buffer")
|
||||||
|
.map_err(PluginModuleError::MemoryUninit)?
|
||||||
|
.clone(),
|
||||||
events: instance
|
events: instance
|
||||||
.exports
|
.exports
|
||||||
.iter()
|
.iter()
|
||||||
@ -86,21 +123,17 @@ impl PluginModule {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
// Store the ECS Pointer for later use in `retreives`
|
// Store the ECS Pointer for later use in `retreives`
|
||||||
self.ecs.store((&ecs) as *const _ as i32, std::sync::atomic::Ordering::SeqCst);
|
let bytes = match self.ecs.execute_with(ecs, || {
|
||||||
let bytes = {
|
|
||||||
let mut state = self.wasm_state.lock().unwrap();
|
let mut state = self.wasm_state.lock().unwrap();
|
||||||
match execute_raw(self,&mut state,event_name,&request.bytes) {
|
execute_raw(self, &mut state, event_name, &request.bytes)
|
||||||
Ok(e) => e,
|
}) {
|
||||||
Err(e) => return Some(Err(e)),
|
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))
|
Some(bincode::deserialize(&bytes).map_err(PluginModuleError::Encoding))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// This structure represent a Pre-encoded event object (Useful to avoid
|
// This structure represent a Pre-encoded event object (Useful to avoid
|
||||||
// reencoding for each module in every plugin)
|
// reencoding for each module in every plugin)
|
||||||
pub struct PreparedEventQuery<T> {
|
pub struct PreparedEventQuery<T> {
|
||||||
@ -122,9 +155,18 @@ impl<T: Event> PreparedEventQuery<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_i64(i: i64) -> (i32,i32) {
|
fn from_i64(i: i64) -> (i32, i32) {
|
||||||
let i = i.to_le_bytes();
|
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
|
// This function is not public because this function should not be used without
|
||||||
@ -136,10 +178,13 @@ fn execute_raw(
|
|||||||
event_name: &str,
|
event_name: &str,
|
||||||
bytes: &[u8],
|
bytes: &[u8],
|
||||||
) -> Result<Vec<u8>, PluginModuleError> {
|
) -> Result<Vec<u8>, 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
|
||||||
let (mem_position,len) = module.memory_manager.write_bytes(&module.memory, &module.allocator, bytes)?;
|
.memory_manager
|
||||||
|
.write_bytes(&module.memory, &module.allocator, bytes)?;
|
||||||
|
|
||||||
// This gets the event function from module exports
|
// This gets the event function from module exports
|
||||||
|
|
||||||
@ -153,16 +198,23 @@ fn execute_raw(
|
|||||||
let function_result = func
|
let function_result = func
|
||||||
.call(&[Value::I32(mem_position as i32), Value::I32(len as i32)])
|
.call(&[Value::I32(mem_position as i32), Value::I32(len as i32)])
|
||||||
.map_err(PluginModuleError::RunFunction)?;
|
.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]
|
// Waiting for `multi-value` to be added to LLVM. So we encode the two i32 as an
|
||||||
.i64()
|
// i64
|
||||||
.ok_or_else(PluginModuleError::InvalidArgumentType)?);
|
|
||||||
|
let (pointer, length) = from_i64(
|
||||||
|
function_result[0]
|
||||||
|
.i64()
|
||||||
|
.ok_or_else(PluginModuleError::InvalidArgumentType)?,
|
||||||
|
);
|
||||||
|
|
||||||
// We read the return object and deserialize it
|
// 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<Action>) {
|
fn handle_actions(actions: Vec<Action>) {
|
||||||
|
@ -1,22 +1,23 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::{atomic::AtomicI32, Arc};
|
||||||
use std::sync::atomic::AtomicI32;
|
|
||||||
|
|
||||||
use serde::{Serialize, de::DeserializeOwned};
|
use serde::{de::DeserializeOwned, Serialize};
|
||||||
use wasmer::{Function, HostEnvInitError, Instance, LazyInit, Memory, WasmerEnv};
|
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)]
|
#[derive(Clone)]
|
||||||
pub struct HostFunctionEnvironement {
|
pub struct HostFunctionEnvironement {
|
||||||
pub ecs: Arc<AtomicI32>, // This represent the pointer to the ECS object (set to i32::MAX if to ECS is availible)
|
pub ecs: Arc<EcsAccessManager>, /* This represent the pointer to the ECS object (set to i32::MAX if
|
||||||
|
* to ECS is availible) */
|
||||||
pub memory: LazyInit<Memory>, // This object represent the WASM Memory
|
pub memory: LazyInit<Memory>, // This object represent the WASM Memory
|
||||||
pub allocator: LazyInit<Function>, // Linked to: wasm_prepare_buffer
|
pub allocator: LazyInit<Function>, // Linked to: wasm_prepare_buffer
|
||||||
pub memory_manager: Arc<MemoryManager>, // This object represent the current buffer size and pointer
|
pub memory_manager: Arc<MemoryManager>, /* This object represent the current buffer size and
|
||||||
|
* pointer */
|
||||||
pub name: String, // This represent the plugin name
|
pub name: String, // This represent the plugin name
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HostFunctionEnvironement {
|
impl HostFunctionEnvironement {
|
||||||
pub fn new(name: String,ecs: Arc<AtomicI32>,memory_manager: Arc<MemoryManager>) -> Self {
|
pub fn new(name: String, ecs: Arc<EcsAccessManager>, memory_manager: Arc<MemoryManager>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
memory_manager,
|
memory_manager,
|
||||||
ecs,
|
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
|
// This function is a safe interface to WASM memory that writes data to the
|
||||||
pub fn write_data<T: Serialize>(&self, object: &T) -> Result<(i32,u32),PluginModuleError> {
|
// memory returning a pointer and length
|
||||||
self.memory_manager.write_data(self.memory.get_ref().unwrap(), self.allocator.get_ref().unwrap(), object)
|
pub fn write_data<T: Serialize>(&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
|
// This function is a safe interface to WASM memory that reads memory from
|
||||||
pub fn read_data<T: DeserializeOwned>(&self, position: i32, length: u32) -> Result<T, bincode::Error> {
|
// pointer and length returning an object
|
||||||
|
pub fn read_data<T: DeserializeOwned>(
|
||||||
|
&self,
|
||||||
|
position: i32,
|
||||||
|
length: u32,
|
||||||
|
) -> Result<T, bincode::Error> {
|
||||||
memory_manager::read_data(self.memory.get_ref().unwrap(), position, length)
|
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> {
|
fn init_with_instance(&mut self, instance: &Instance) -> Result<(), HostEnvInitError> {
|
||||||
let memory = instance.exports.get_memory("memory").unwrap();
|
let memory = instance.exports.get_memory("memory").unwrap();
|
||||||
self.memory.initialize(memory.clone());
|
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());
|
self.allocator.initialize(allocator.clone());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -208,12 +208,14 @@ impl State {
|
|||||||
#[cfg(feature = "plugins")]
|
#[cfg(feature = "plugins")]
|
||||||
ecs.insert(match PluginMgr::from_assets() {
|
ecs.insert(match PluginMgr::from_assets() {
|
||||||
Ok(plugin_mgr) => {
|
Ok(plugin_mgr) => {
|
||||||
if let Err(e) = plugin_mgr
|
if let Err(e) =
|
||||||
.execute_event(&ecs,"on_load", &plugin_api::event::PluginLoadEvent { game_mode: match game_mode {
|
plugin_mgr.execute_event(&ecs, "on_load", &plugin_api::event::PluginLoadEvent {
|
||||||
resources::GameMode::Server => plugin_api::GameMode::Server,
|
game_mode: match game_mode {
|
||||||
resources::GameMode::Client => plugin_api::GameMode::Client,
|
resources::GameMode::Server => plugin_api::GameMode::Server,
|
||||||
resources::GameMode::Singleplayer => plugin_api::GameMode::Singleplayer,
|
resources::GameMode::Client => plugin_api::GameMode::Client,
|
||||||
} })
|
resources::GameMode::Singleplayer => plugin_api::GameMode::Singleplayer,
|
||||||
|
},
|
||||||
|
})
|
||||||
{
|
{
|
||||||
tracing::error!(?e, "Failed to run plugin init");
|
tracing::error!(?e, "Failed to run plugin init");
|
||||||
tracing::info!(
|
tracing::info!(
|
||||||
|
@ -6,3 +6,4 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde = { version = "1.0.118", features = ["derive"] }
|
serde = { version = "1.0.118", features = ["derive"] }
|
||||||
|
common = { package = "veloren-common", path = "../../common", features = ["no-assets"] }
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
|
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||||
|
|
||||||
|
pub use common::{resources::GameMode, uid::Uid};
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Debug)]
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
pub enum Action {
|
pub enum Action {
|
||||||
ServerClose,
|
ServerClose,
|
||||||
@ -20,35 +19,6 @@ pub trait Event: Serialize + DeserializeOwned + Send + Sync {
|
|||||||
type Response: 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<u64> for Uid {
|
|
||||||
fn into(self) -> u64 { self.0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<u64> 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 {
|
pub mod event {
|
||||||
use super::*;
|
use super::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -3,7 +3,7 @@ use veloren_plugin_rt::{
|
|||||||
*,
|
*,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[veloren_plugin_rt::event_handler]
|
#[event_handler]
|
||||||
pub fn on_load(load: PluginLoadEvent) {
|
pub fn on_load(load: PluginLoadEvent) {
|
||||||
match load.game_mode {
|
match load.game_mode {
|
||||||
GameMode::Server => emit_action(Action::Print("Hello, server!".to_owned())),
|
GameMode::Server => emit_action(Action::Print("Hello, server!".to_owned())),
|
||||||
@ -15,13 +15,11 @@ pub fn on_load(load: PluginLoadEvent) {
|
|||||||
#[event_handler]
|
#[event_handler]
|
||||||
pub fn on_command_testplugin(command: ChatCommandEvent) -> Result<Vec<String>, String> {
|
pub fn on_command_testplugin(command: ChatCommandEvent) -> Result<Vec<String>, String> {
|
||||||
Ok(vec![format!(
|
Ok(vec![format!(
|
||||||
"Player of id {:?} sended command with args {:?}",
|
"Player of id {:?} named {} sended command with args {:?}",
|
||||||
command.player, command.command_args
|
command.player, command.player.get_entity_name(), command.command_args
|
||||||
)])
|
)])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[event_handler]
|
#[event_handler]
|
||||||
pub fn on_player_join(input: PlayerJoinEvent) -> PlayerJoinResult {
|
pub fn on_player_join(input: PlayerJoinEvent) -> PlayerJoinResult {
|
||||||
emit_action(Action::PlayerSendMessage(
|
emit_action(Action::PlayerSendMessage(
|
||||||
|
@ -4,6 +4,8 @@ pub extern crate plugin_derive;
|
|||||||
|
|
||||||
pub mod retreive;
|
pub mod retreive;
|
||||||
|
|
||||||
|
pub use retreive::*;
|
||||||
|
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
|
||||||
pub use retreive::*;
|
pub use retreive::*;
|
||||||
@ -16,22 +18,28 @@ use serde::{de::DeserializeOwned, Serialize};
|
|||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn raw_emit_actions(ptr: *const u8, len: usize);
|
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<T: DeserializeOwned>(_actions: &api::Retreive) -> Result<T,bincode::Error> {
|
pub fn retreive_action<T: DeserializeOwned>(_actions: &api::Retreive) -> Result<T,bincode::Error> {
|
||||||
// #[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
// {
|
{
|
||||||
// let ret = bincode::serialize(&_actions).expect("Can't serialize action in emit");
|
unsafe{dbg(0);}
|
||||||
// unsafe {
|
let ret = bincode::serialize(&_actions).expect("Can't serialize action in emit");
|
||||||
// let (ptr,len) = raw_retreive_action(ret.as_ptr(), ret.len());
|
unsafe{dbg(1);}
|
||||||
// let a = ::std::slice::from_raw_parts(ptr as _, len as _);
|
unsafe {
|
||||||
// bincode::deserialize(&a)
|
dbg(2);
|
||||||
// }
|
let (ptr,len) = from_i64(raw_retreive_action(ret.as_ptr(), ret.len()));
|
||||||
// }
|
dbg(3);
|
||||||
// #[cfg(not(target_arch = "wasm32"))]
|
let a = ::std::slice::from_raw_parts(ptr as _, len as _);
|
||||||
// unreachable!()
|
dbg(4);
|
||||||
// }
|
bincode::deserialize(&a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn emit_action(action: api::Action) { emit_actions(vec![action]) }
|
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")
|
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 {
|
pub fn to_i64(a: i32, b: i32) -> i64 {
|
||||||
let a = a.to_le_bytes();
|
let a = a.to_le_bytes();
|
||||||
let b = b.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 {
|
pub fn write_output(value: impl Serialize) -> i64 {
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
use crate::api::Retreive;
|
use crate::api::Retreive;
|
||||||
|
|
||||||
trait GetEntityName {
|
pub trait GetEntityName {
|
||||||
fn get_entity_name(&self) -> String;
|
fn get_entity_name(&self) -> String;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GetEntityName for crate::api::event::Player {
|
impl GetEntityName for crate::api::event::Player {
|
||||||
|
|
||||||
fn get_entity_name(&self) -> String {
|
fn get_entity_name(&self) -> String {
|
||||||
// crate::retreive_action(&Retreive::GetEntityName(self.id)).expect("Can't get entity name")
|
#[cfg(target_arch = "wasm32")]
|
||||||
String::new()
|
unsafe {
|
||||||
|
crate::dbg(-1);
|
||||||
|
}
|
||||||
|
crate::retreive_action(&Retreive::GetEntityName(self.id)).expect("Can't get entity name")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1037,12 +1037,15 @@ impl Server {
|
|||||||
command: kwd.clone(),
|
command: kwd.clone(),
|
||||||
command_args: args.split(' ').map(|x| x.to_owned()).collect(),
|
command_args: args.split(' ').map(|x| x.to_owned()).collect(),
|
||||||
player: plugin_api::event::Player {
|
player: plugin_api::event::Player {
|
||||||
id: plugin_api::Uid((self
|
id: plugin_api::Uid(
|
||||||
.state
|
(self
|
||||||
.ecs()
|
.state
|
||||||
.read_storage::<Uid>()
|
.ecs()
|
||||||
.get(entity)
|
.read_storage::<Uid>()
|
||||||
.expect("Can't get player UUID [This should never appen]")).0),
|
.get(entity)
|
||||||
|
.expect("Can't get player UUID [This should never appen]"))
|
||||||
|
.0,
|
||||||
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user