mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added safety section to the EcsAccessManager
This commit is contained in:
parent
f85e79af07
commit
74ec5c652a
@ -635,7 +635,7 @@ impl CombatBuff {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
fn equipped_item_and_tool(inv: &Inventory, slot: EquipSlot) -> Option<&Tool> {
|
fn equipped_item_and_tool(inv: &Inventory, slot: EquipSlot) -> Option<(&Item, &Tool)> {
|
||||||
inv.equipped(slot).and_then(|i| {
|
inv.equipped(slot).and_then(|i| {
|
||||||
if let ItemKind::Tool(tool) = &i.kind() {
|
if let ItemKind::Tool(tool) = &i.kind() {
|
||||||
Some((i, tool))
|
Some((i, tool))
|
||||||
|
@ -76,7 +76,7 @@ pub use self::{
|
|||||||
misc::Object,
|
misc::Object,
|
||||||
ori::Ori,
|
ori::Ori,
|
||||||
phys::{
|
phys::{
|
||||||
Collider, ForceUpdate, Gravity, Mass, PhysicsState, Pos, PreviousVelDtCache, Scale, Sticky,
|
Collider, ForceUpdate, Gravity, Mass, PhysicsState, Pos, PreviousPhysCache, Scale, Sticky,
|
||||||
Vel,
|
Vel,
|
||||||
},
|
},
|
||||||
player::Player,
|
player::Player,
|
||||||
@ -86,4 +86,6 @@ pub use self::{
|
|||||||
skills::{Skill, SkillGroup, SkillGroupKind, SkillSet},
|
skills::{Skill, SkillGroup, SkillGroupKind, SkillSet},
|
||||||
stats::Stats,
|
stats::Stats,
|
||||||
visual::{LightAnimation, LightEmitter},
|
visual::{LightAnimation, LightEmitter},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub use health::{Health, HealthChange, HealthSource};
|
||||||
|
@ -6,7 +6,7 @@ use wasmer::{Function, Memory, Value};
|
|||||||
|
|
||||||
use super::errors::{MemoryAllocationError, PluginModuleError};
|
use super::errors::{MemoryAllocationError, PluginModuleError};
|
||||||
|
|
||||||
// This structure wraps the ECS pointer to ensure safety
|
/// This structure wraps the ECS pointer to ensure safety
|
||||||
pub struct EcsAccessManager {
|
pub struct EcsAccessManager {
|
||||||
ecs_pointer: AtomicPtr<World>,
|
ecs_pointer: AtomicPtr<World>,
|
||||||
}
|
}
|
||||||
@ -31,9 +31,21 @@ impl EcsAccessManager {
|
|||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self) -> Option<&World> {
|
/// This unsafe function returns a reference to the Ecs World
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// This function is safe to use if it matches the following requirements
|
||||||
|
/// - The reference and subreferences like Entities, Components ... aren't
|
||||||
|
/// leaked out the thread
|
||||||
|
/// - The reference and subreferences lifetime doesn't exceed the source
|
||||||
|
/// function lifetime
|
||||||
|
/// - Always safe when called from `retrieve_action` if you don't pass a
|
||||||
|
/// reference somewhere else
|
||||||
|
/// - All that ensure that the reference doesn't exceed the execute_with
|
||||||
|
/// function scope
|
||||||
|
pub unsafe fn get(&self) -> Option<&World> {
|
||||||
// ptr::as_ref will automatically check for null
|
// ptr::as_ref will automatically check for null
|
||||||
unsafe { self.ecs_pointer.load(Ordering::Relaxed).as_ref() }
|
self.ecs_pointer.load(Ordering::Relaxed).as_ref()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,9 +64,10 @@ impl Default for MemoryManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl MemoryManager {
|
impl MemoryManager {
|
||||||
// This function check if the buffer is wide enough if not it realloc the buffer
|
/// This function check if the buffer is wide enough if not it realloc the
|
||||||
// calling the `wasm_prepare_buffer` function Note: There is probably
|
/// buffer calling the `wasm_prepare_buffer` function Note: There is
|
||||||
// optimizations that can be done using less restrictive ordering
|
/// probably optimizations that can be done using less restrictive
|
||||||
|
/// ordering
|
||||||
pub fn get_pointer(
|
pub fn get_pointer(
|
||||||
&self,
|
&self,
|
||||||
object_length: u32,
|
object_length: u32,
|
||||||
@ -74,8 +87,8 @@ impl MemoryManager {
|
|||||||
Ok(pointer)
|
Ok(pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function writes an object to WASM memory returning a pointer and a
|
/// This function writes an object to WASM memory returning a pointer and a
|
||||||
// length. Will realloc the buffer is not wide enough
|
/// length. Will realloc the buffer is not wide enough
|
||||||
pub fn write_data<T: Serialize>(
|
pub fn write_data<T: Serialize>(
|
||||||
&self,
|
&self,
|
||||||
memory: &Memory,
|
memory: &Memory,
|
||||||
@ -89,8 +102,8 @@ impl MemoryManager {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function writes an raw bytes to WASM memory returning a pointer and a
|
/// This function writes an raw bytes to WASM memory returning a pointer and
|
||||||
// length. Will realloc the buffer is not wide enough
|
/// a length. Will realloc the buffer is not wide enough
|
||||||
pub fn write_bytes(
|
pub fn write_bytes(
|
||||||
&self,
|
&self,
|
||||||
memory: &Memory,
|
memory: &Memory,
|
||||||
@ -109,8 +122,8 @@ impl MemoryManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function read data from memory at a position with the array length and
|
/// This function read data from memory at a position with the array length and
|
||||||
// converts it to an object using bincode
|
/// converts it to an object using bincode
|
||||||
pub fn read_data<T: DeserializeOwned>(
|
pub fn read_data<T: DeserializeOwned>(
|
||||||
memory: &Memory,
|
memory: &Memory,
|
||||||
position: i32,
|
position: i32,
|
||||||
@ -119,7 +132,7 @@ pub fn read_data<T: DeserializeOwned>(
|
|||||||
bincode::deserialize(&read_bytes(memory, position, length))
|
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
|
||||||
pub fn read_bytes(memory: &Memory, position: i32, length: u32) -> Vec<u8> {
|
pub fn read_bytes(memory: &Memory, position: i32, length: u32) -> Vec<u8> {
|
||||||
memory.view()[(position as usize)..(position as usize) + length as usize]
|
memory.view()[(position as usize)..(position as usize) + length as usize]
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -21,7 +21,7 @@ use super::{
|
|||||||
use plugin_api::{Action, EcsAccessError, Event, Retrieve, RetrieveError, RetrieveResult};
|
use plugin_api::{Action, EcsAccessError, Event, Retrieve, RetrieveError, RetrieveResult};
|
||||||
|
|
||||||
#[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<EcsAccessManager>,
|
ecs: Arc<EcsAccessManager>,
|
||||||
wasm_state: Arc<Mutex<Instance>>,
|
wasm_state: Arc<Mutex<Instance>>,
|
||||||
@ -33,7 +33,7 @@ pub struct PluginModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PluginModule {
|
impl PluginModule {
|
||||||
// This function takes bytes from a WASM File and compile them
|
/// This function takes bytes from a WASM File and compile them
|
||||||
pub fn new(name: String, wasm_data: &[u8]) -> Result<Self, PluginModuleError> {
|
pub fn new(name: String, wasm_data: &[u8]) -> Result<Self, PluginModuleError> {
|
||||||
// This is creating the engine is this case a JIT based on Cranelift
|
// This is creating the engine is this case a JIT based on Cranelift
|
||||||
let engine = JIT::new(Cranelift::default()).engine();
|
let engine = JIT::new(Cranelift::default()).engine();
|
||||||
@ -107,8 +107,8 @@ impl PluginModule {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function tries to execute an event for the current module. Will return
|
/// This function tries to execute an event for the current module. Will
|
||||||
// None if the event doesn't exists
|
/// return None if the event doesn't exists
|
||||||
pub fn try_execute<T>(
|
pub fn try_execute<T>(
|
||||||
&self,
|
&self,
|
||||||
ecs: &World,
|
ecs: &World,
|
||||||
@ -133,16 +133,17 @@ impl PluginModule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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> {
|
||||||
bytes: Vec<u8>,
|
bytes: Vec<u8>,
|
||||||
_phantom: PhantomData<T>,
|
_phantom: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Event> PreparedEventQuery<T> {
|
impl<T: Event> PreparedEventQuery<T> {
|
||||||
// Create a prepared query from an event reference (Encode to bytes the struct)
|
/// Create a prepared query from an event reference (Encode to bytes the
|
||||||
// This Prepared Query is used by the `try_execute` method in `PluginModule`
|
/// struct) This Prepared Query is used by the `try_execute` method in
|
||||||
|
/// `PluginModule`
|
||||||
pub fn new(event: &T) -> Result<Self, PluginError>
|
pub fn new(event: &T) -> Result<Self, PluginError>
|
||||||
where
|
where
|
||||||
T: Event,
|
T: Event,
|
||||||
@ -222,9 +223,12 @@ fn retrieve_action(
|
|||||||
) -> Result<RetrieveResult, RetrieveError> {
|
) -> Result<RetrieveResult, RetrieveError> {
|
||||||
match action {
|
match action {
|
||||||
Retrieve::GetPlayerName(e) => {
|
Retrieve::GetPlayerName(e) => {
|
||||||
let world = ecs.get().ok_or(RetrieveError::EcsAccessError(
|
// Safety: No reference is leaked out the function so it is safe.
|
||||||
EcsAccessError::EcsPointerNotAvailable,
|
let world = unsafe {
|
||||||
))?;
|
ecs.get().ok_or(RetrieveError::EcsAccessError(
|
||||||
|
EcsAccessError::EcsPointerNotAvailable,
|
||||||
|
))?
|
||||||
|
};
|
||||||
let player = world
|
let player = world
|
||||||
.read_resource::<UidAllocator>()
|
.read_resource::<UidAllocator>()
|
||||||
.retrieve_entity_internal(e.0)
|
.retrieve_entity_internal(e.0)
|
||||||
@ -246,9 +250,12 @@ fn retrieve_action(
|
|||||||
))
|
))
|
||||||
},
|
},
|
||||||
Retrieve::GetEntityHealth(e) => {
|
Retrieve::GetEntityHealth(e) => {
|
||||||
let world = ecs.get().ok_or(RetrieveError::EcsAccessError(
|
// Safety: No reference is leaked out the function so it is safe.
|
||||||
EcsAccessError::EcsPointerNotAvailable,
|
let world = unsafe {
|
||||||
))?;
|
ecs.get().ok_or(RetrieveError::EcsAccessError(
|
||||||
|
EcsAccessError::EcsPointerNotAvailable,
|
||||||
|
))?
|
||||||
|
};
|
||||||
let player = world
|
let player = world
|
||||||
.read_resource::<UidAllocator>()
|
.read_resource::<UidAllocator>()
|
||||||
.retrieve_entity_internal(e.0)
|
.retrieve_entity_internal(e.0)
|
||||||
|
@ -35,8 +35,8 @@ impl HostFunctionEnvironement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function is a safe interface to WASM memory that writes data to the
|
/// This function is a safe interface to WASM memory that writes data to the
|
||||||
// memory returning a pointer and length
|
/// memory returning a pointer and length
|
||||||
pub fn write_data<T: Serialize>(&self, object: &T) -> Result<(i32, u32), PluginModuleError> {
|
pub fn write_data<T: Serialize>(&self, object: &T) -> Result<(i32, u32), PluginModuleError> {
|
||||||
self.memory_manager.write_data(
|
self.memory_manager.write_data(
|
||||||
self.memory.get_ref().unwrap(),
|
self.memory.get_ref().unwrap(),
|
||||||
@ -45,8 +45,8 @@ impl HostFunctionEnvironement {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function is a safe interface to WASM memory that reads memory from
|
/// This function is a safe interface to WASM memory that reads memory from
|
||||||
// pointer and length returning an object
|
/// pointer and length returning an object
|
||||||
pub fn read_data<T: DeserializeOwned>(
|
pub fn read_data<T: DeserializeOwned>(
|
||||||
&self,
|
&self,
|
||||||
position: i32,
|
position: i32,
|
||||||
|
@ -210,11 +210,7 @@ impl State {
|
|||||||
Ok(plugin_mgr) => {
|
Ok(plugin_mgr) => {
|
||||||
if let Err(e) =
|
if let Err(e) =
|
||||||
plugin_mgr.execute_event(&ecs, "on_load", &plugin_api::event::PluginLoadEvent {
|
plugin_mgr.execute_event(&ecs, "on_load", &plugin_api::event::PluginLoadEvent {
|
||||||
game_mode: match game_mode {
|
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::error!(?e, "Failed to run plugin init");
|
||||||
|
Loading…
Reference in New Issue
Block a user