diff --git a/common/sys/src/plugin/memory_manager.rs b/common/sys/src/plugin/memory_manager.rs index b69834c74e..d62f7bfb83 100644 --- a/common/sys/src/plugin/memory_manager.rs +++ b/common/sys/src/plugin/memory_manager.rs @@ -1,14 +1,27 @@ use std::sync::atomic::{AtomicPtr, AtomicU32, AtomicU64, Ordering}; use serde::{de::DeserializeOwned, Serialize}; -use specs::World; +use specs::{shred::Fetch, Entities, ReadStorage}; use wasmer::{Function, Memory, Value}; +use common::{ + comp::Health, + uid::{Uid, UidAllocator}, +}; + use super::errors::{MemoryAllocationError, PluginModuleError}; +pub struct EcsWorld<'a> { + pub entities: Entities<'a>, + pub health: ReadStorage<'a, Health>, + pub uid: ReadStorage<'a, Uid>, + //pub player: ReadStorage<'a, Player>, + pub uid_allocator: Fetch<'a, UidAllocator>, +} + /// This structure wraps the ECS pointer to ensure safety pub struct EcsAccessManager { - ecs_pointer: AtomicPtr, + ecs_pointer: AtomicPtr>, } impl Default for EcsAccessManager { @@ -22,7 +35,7 @@ impl Default for EcsAccessManager { impl EcsAccessManager { // This function take a World reference and a function to execute ensuring the // pointer will never be corrupted during the execution of the function! - pub fn execute_with(&self, world: &World, func: impl FnOnce() -> T) -> T { + pub fn execute_with(&self, world: &EcsWorld, func: impl FnOnce() -> T) -> T { let _guard = scopeguard::guard((), |_| { // ensure the pointer is cleared in any case self.ecs_pointer @@ -45,7 +58,7 @@ impl EcsAccessManager { /// reference somewhere else /// - All that ensure that the reference doesn't exceed the execute_with /// function scope - pub unsafe fn get(&self) -> Option<&World> { + pub unsafe fn get(&self) -> Option<&EcsWorld> { // ptr::as_ref will automatically check for null self.ecs_pointer.load(Ordering::Relaxed).as_ref() } diff --git a/common/sys/src/plugin/mod.rs b/common/sys/src/plugin/mod.rs index df1b733457..f79aa4a344 100644 --- a/common/sys/src/plugin/mod.rs +++ b/common/sys/src/plugin/mod.rs @@ -5,7 +5,6 @@ pub mod wasm_env; use common::assets::ASSETS_PATH; use serde::{Deserialize, Serialize}; -use specs::World; use std::{ collections::{HashMap, HashSet}, fs, @@ -18,6 +17,7 @@ use plugin_api::Event; use self::{ errors::PluginError, + memory_manager::EcsWorld, module::{PluginModule, PreparedEventQuery}, }; @@ -83,7 +83,7 @@ impl Plugin { pub fn execute_prepared( &self, - ecs: &World, + ecs: &EcsWorld, event: &PreparedEventQuery, ) -> Result, PluginError> where @@ -121,7 +121,7 @@ impl PluginMgr { pub fn execute_prepared( &self, - ecs: &World, + ecs: &EcsWorld, event: &PreparedEventQuery, ) -> Result, PluginError> where @@ -137,7 +137,11 @@ impl PluginMgr { .collect()) } - pub fn execute_event(&self, ecs: &World, event: &T) -> Result, PluginError> + pub fn execute_event( + &self, + ecs: &EcsWorld, + event: &T, + ) -> Result, PluginError> where T: Event, { diff --git a/common/sys/src/plugin/module.rs b/common/sys/src/plugin/module.rs index 2bf7ca3dec..0cd53048e5 100644 --- a/common/sys/src/plugin/module.rs +++ b/common/sys/src/plugin/module.rs @@ -5,16 +5,12 @@ use std::{ sync::{Arc, Mutex}, }; -use common::{ - comp::{Health, Player}, - uid::UidAllocator, -}; -use specs::{saveload::MarkerAllocator, World, WorldExt}; +use specs::saveload::MarkerAllocator; use wasmer::{imports, Cranelift, Function, Instance, Memory, Module, Store, Value, JIT}; use super::{ errors::{PluginError, PluginModuleError}, - memory_manager::{self, EcsAccessManager, MemoryManager}, + memory_manager::{self, EcsAccessManager, EcsWorld, MemoryManager}, wasm_env::HostFunctionEnvironement, }; @@ -110,7 +106,7 @@ impl PluginModule { /// return None if the event doesn't exists pub fn try_execute( &self, - ecs: &World, + ecs: &EcsWorld, request: &PreparedEventQuery, ) -> Option> where @@ -236,31 +232,29 @@ fn retrieve_action( action: Retrieve, ) -> Result { match action { - Retrieve::GetPlayerName(e) => { + Retrieve::GetPlayerName(_e) => { // Safety: No reference is leaked out the function so it is safe. - let world = unsafe { - ecs.get().ok_or(RetrieveError::EcsAccessError( - EcsAccessError::EcsPointerNotAvailable, - ))? - }; - let player = world - .read_resource::() - .retrieve_entity_internal(e.0) - .ok_or(RetrieveError::EcsAccessError( - EcsAccessError::EcsEntityNotFound(e), - ))?; + // let world = unsafe { + // ecs.get().ok_or(RetrieveError::EcsAccessError( + // EcsAccessError::EcsPointerNotAvailable, + // ))? + // }; + // let player = world.uid_allocator.retrieve_entity_internal(e.0).ok_or( + // RetrieveError::EcsAccessError(EcsAccessError::EcsEntityNotFound(e)), + // )?; + Ok(RetrieveResult::GetPlayerName( - world - .read_component::() - .get(player) - .ok_or_else(|| { - RetrieveError::EcsAccessError(EcsAccessError::EcsComponentNotFound( - e, - "Player".to_owned(), - )) - })? - .alias - .to_owned(), + "".to_owned(), /* world + * .player.get(player).ok_or_else(|| { + * + * RetrieveError::EcsAccessError(EcsAccessError:: + * EcsComponentNotFound( + * e, + * "Player".to_owned(), + * )) + * })? + * .alias + * .to_owned() */ )) }, Retrieve::GetEntityHealth(e) => { @@ -270,22 +264,16 @@ fn retrieve_action( EcsAccessError::EcsPointerNotAvailable, ))? }; - let player = world - .read_resource::() - .retrieve_entity_internal(e.0) - .ok_or(RetrieveError::EcsAccessError( - EcsAccessError::EcsEntityNotFound(e), - ))?; + let player = world.uid_allocator.retrieve_entity_internal(e.0).ok_or( + RetrieveError::EcsAccessError(EcsAccessError::EcsEntityNotFound(e)), + )?; Ok(RetrieveResult::GetEntityHealth( - *world - .read_component::() - .get(player) - .ok_or_else(|| { - RetrieveError::EcsAccessError(EcsAccessError::EcsComponentNotFound( - e, - "Health".to_owned(), - )) - })?, + *world.health.get(player).ok_or_else(|| { + RetrieveError::EcsAccessError(EcsAccessError::EcsComponentNotFound( + e, + "Health".to_owned(), + )) + })?, )) }, } diff --git a/common/sys/src/state.rs b/common/sys/src/state.rs index d53ad1e1e0..f62434eddf 100644 --- a/common/sys/src/state.rs +++ b/common/sys/src/state.rs @@ -1,4 +1,6 @@ #[cfg(feature = "plugins")] +use crate::plugin::memory_manager::EcsWorld; +#[cfg(feature = "plugins")] use crate::plugin::PluginMgr; use common::{ comp, @@ -209,8 +211,17 @@ impl State { #[cfg(feature = "plugins")] ecs.insert(match PluginMgr::from_assets() { Ok(plugin_mgr) => { + let ecs_world = EcsWorld { + entities: ecs.entities(), + health: ecs.read_component(), + uid: ecs.read_component(), + uid_allocator: ecs.read_resource(), + //player: Either::First(ecs.read_component()), + }; if let Err(e) = plugin_mgr - .execute_event(&ecs, &plugin_api::event::PluginLoadEvent { game_mode }) + .execute_event(&ecs_world, &plugin_api::event::PluginLoadEvent { + game_mode, + }) { tracing::error!(?e, "Failed to run plugin init"); tracing::info!( @@ -221,7 +232,8 @@ impl State { plugin_mgr } }, - Err(_) => { + Err(e) => { + tracing::error!(?e, "Failed to read plugins from assets"); tracing::info!( "Error occurred when loading plugins. Running without plugins instead." ); diff --git a/server/src/lib.rs b/server/src/lib.rs index 7c01bac517..8215c01e48 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -76,7 +76,7 @@ use common_net::{ }; #[cfg(feature = "plugins")] use common_sys::plugin::PluginMgr; -use common_sys::state::State; +use common_sys::{plugin::memory_manager::EcsWorld, state::State}; use hashbrown::HashMap; use metrics::{PhysicsMetrics, PlayerMetrics, StateTickMetrics, TickMetrics}; use network::{Network, Pid, ProtocolAddr}; @@ -1106,8 +1106,14 @@ impl Server { #[cfg(feature = "plugins")] { let plugin_manager = self.state.ecs().read_resource::(); + let ecs_world = EcsWorld { + entities: self.state.ecs().entities(), + health: self.state.ecs().read_component(), + uid: self.state.ecs().read_component(), + uid_allocator: self.state.ecs().read_resource(), + }; let rs = plugin_manager.execute_event( - self.state.ecs(), + &ecs_world, &plugin_api::event::ChatCommandEvent { command: kwd.clone(), command_args: args.split(' ').map(|x| x.to_owned()).collect(), diff --git a/server/src/login_provider.rs b/server/src/login_provider.rs index 2c53a6bd34..616d0c33da 100644 --- a/server/src/login_provider.rs +++ b/server/src/login_provider.rs @@ -1,11 +1,11 @@ use crate::settings::BanRecord; use authc::{AuthClient, AuthClientError, AuthToken, Uuid}; use common_net::msg::RegisterError; +use common_sys::plugin::memory_manager::EcsWorld; #[cfg(feature = "plugins")] use common_sys::plugin::PluginMgr; use hashbrown::{HashMap, HashSet}; use plugin_api::event::{PlayerJoinEvent, PlayerJoinResult}; -use specs::World; use std::str::FromStr; use tracing::{error, info}; @@ -57,7 +57,7 @@ impl LoginProvider { pub fn try_login( &mut self, username_or_token: &str, - world: &World, + world: &EcsWorld, #[cfg(feature = "plugins")] plugin_manager: &PluginMgr, admins: &HashSet, whitelist: &HashSet, @@ -80,21 +80,23 @@ impl LoginProvider { return Err(RegisterError::NotOnWhitelist); } #[cfg(feature = "plugins")] - match plugin_manager.execute_event(&world, &PlayerJoinEvent { - player_name: username.clone(), - player_id: *uuid.as_bytes(), - }) { - Ok(e) => { - for i in e.into_iter() { - if let PlayerJoinResult::Kick(a) = i { - return Err(RegisterError::Kicked(a)); + { + match plugin_manager.execute_event(&world, &PlayerJoinEvent { + player_name: username.clone(), + player_id: *uuid.as_bytes(), + }) { + Ok(e) => { + for i in e.into_iter() { + if let PlayerJoinResult::Kick(a) = i { + return Err(RegisterError::Kicked(a)); + } } - } - }, - Err(e) => { - error!("Error occured while executing `on_join`: {:?}",e); - }, - }; + }, + Err(e) => { + error!("Error occured while executing `on_join`: {:?}",e); + }, + }; + } // add the user to self.accounts self.login(uuid, username.clone())?; diff --git a/server/src/register.rs b/server/src/register.rs index 73fa04356d..f7837354a5 100644 --- a/server/src/register.rs +++ b/server/src/register.rs @@ -4,6 +4,7 @@ use common_net::msg::{ ServerRegisterAnswer, }; +use common_sys::plugin::memory_manager::EcsWorld; #[cfg(feature = "plugins")] use common_sys::plugin::PluginMgr; use hashbrown::HashMap; @@ -33,9 +34,15 @@ pub(crate) fn handle_register_msg( ) -> Result<(), crate::error::Error> { #[cfg(feature = "plugins")] let plugin_mgr = world.read_resource::(); + let ecs_world = EcsWorld { + entities: world.entities(), + health: world.read_component(), + uid: world.read_component(), + uid_allocator: world.read_resource(), + }; let (username, uuid) = match login_provider.try_login( &msg.token_or_username, - world, + &ecs_world, #[cfg(feature = "plugins")] &plugin_mgr, &*editable_settings.admins,