From 67b24294d6fbd41cacaa183180b59fe0d52ddb40 Mon Sep 17 00:00:00 2001 From: ccgauche Date: Wed, 10 Mar 2021 19:36:53 +0100 Subject: [PATCH] Change Ecs access system to allow write accesses to be used + reintroduced get_player_name --- .../veloren_plugin_template.plugin.tar | 3 ++ common/sys/src/plugin/memory_manager.rs | 50 ++++++++++++++++-- common/sys/src/plugin/module.rs | 40 +++++++-------- common/sys/src/state.rs | 6 +-- server/src/lib.rs | 5 +- server/src/login_provider.rs | 51 ++++++++++++------- server/src/sys/msg/register.rs | 20 ++++---- 7 files changed, 117 insertions(+), 58 deletions(-) create mode 100644 assets/plugins/veloren_plugin_template.plugin.tar diff --git a/assets/plugins/veloren_plugin_template.plugin.tar b/assets/plugins/veloren_plugin_template.plugin.tar new file mode 100644 index 0000000000..177af9b958 --- /dev/null +++ b/assets/plugins/veloren_plugin_template.plugin.tar @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6460e779520be3580320a695832b81161dd48d2199a6f91ba5ed64a1734d95a1 +size 1697792 diff --git a/common/sys/src/plugin/memory_manager.rs b/common/sys/src/plugin/memory_manager.rs index b13f2843fd..a76ba45382 100644 --- a/common/sys/src/plugin/memory_manager.rs +++ b/common/sys/src/plugin/memory_manager.rs @@ -1,11 +1,13 @@ use std::sync::atomic::{AtomicPtr, AtomicU32, AtomicU64, Ordering}; use serde::{de::DeserializeOwned, Serialize}; -use specs::{Entities, Read, ReadStorage}; +use specs::{ + storage::GenericReadStorage, Component, Entities, Entity, Read, ReadStorage, WriteStorage, +}; use wasmer::{Function, Memory, Value}; use common::{ - comp::Health, + comp::{Health, Player}, uid::{Uid, UidAllocator}, }; @@ -13,12 +15,50 @@ use super::errors::{MemoryAllocationError, PluginModuleError}; pub struct EcsWorld<'a, 'b> { pub entities: &'b Entities<'a>, - pub health: &'b ReadStorage<'a, Health>, - pub uid: &'b ReadStorage<'a, Uid>, - //pub player: ReadStorage<'a, Player>, + pub health: EcsComponentAccess<'a, 'b, Health>, + pub uid: EcsComponentAccess<'a, 'b, Uid>, + pub player: EcsComponentAccess<'a, 'b, Player>, pub uid_allocator: &'b Read<'a, UidAllocator>, } +pub enum EcsComponentAccess<'a, 'b, T: Component> { + Read(&'b ReadStorage<'a, T>), + ReadOwned(ReadStorage<'a, T>), + Write(&'b WriteStorage<'a, T>), + WriteOwned(WriteStorage<'a, T>), +} + +impl<'a, 'b, T: Component> EcsComponentAccess<'a, 'b, T> { + pub fn get(&self, entity: Entity) -> Option<&T> { + match self { + EcsComponentAccess::Read(e) => e.get(entity), + EcsComponentAccess::Write(e) => e.get(entity), + EcsComponentAccess::ReadOwned(e) => e.get(entity), + EcsComponentAccess::WriteOwned(e) => e.get(entity), + } + } +} + +impl<'a, 'b, T: Component> From<&'b ReadStorage<'a, T>> for EcsComponentAccess<'a, 'b, T> { + fn from(a: &'b ReadStorage<'a, T>) -> Self { Self::Read(a) } +} + +impl<'a, 'b, T: Component> From> for EcsComponentAccess<'a, 'b, T> { + fn from(a: ReadStorage<'a, T>) -> Self { Self::ReadOwned(a) } +} + +impl<'a, 'b, T: Component> From<&'b WriteStorage<'a, T>> for EcsComponentAccess<'a, 'b, T> { + fn from(a: &'b WriteStorage<'a, T>) -> Self { Self::Write(a) } +} + +impl<'a, 'b, T: Component> From> for EcsComponentAccess<'a, 'b, T> { + fn from(a: WriteStorage<'a, T>) -> Self { Self::WriteOwned(a) } +} + +// pub enum EcsResourceAccess<'a, T> { +// Read(Read<'a, T>), +// } + /// This structure wraps the ECS pointer to ensure safety pub struct EcsAccessManager { ecs_pointer: AtomicPtr>, diff --git a/common/sys/src/plugin/module.rs b/common/sys/src/plugin/module.rs index 0cd53048e5..4adba15e63 100644 --- a/common/sys/src/plugin/module.rs +++ b/common/sys/src/plugin/module.rs @@ -232,29 +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.uid_allocator.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( - "".to_owned(), /* world - * .player.get(player).ok_or_else(|| { - * - * RetrieveError::EcsAccessError(EcsAccessError:: - * EcsComponentNotFound( - * e, - * "Player".to_owned(), - * )) - * })? - * .alias - * .to_owned() */ + world + .player + .get(player) + .ok_or_else(|| { + RetrieveError::EcsAccessError(EcsAccessError::EcsComponentNotFound( + e, + "Player".to_owned(), + )) + })? + .alias + .to_owned(), )) }, Retrieve::GetEntityHealth(e) => { diff --git a/common/sys/src/state.rs b/common/sys/src/state.rs index bc256766c5..3d15d4e3ff 100644 --- a/common/sys/src/state.rs +++ b/common/sys/src/state.rs @@ -214,10 +214,10 @@ impl State { Ok(plugin_mgr) => { let ecs_world = EcsWorld { entities: &ecs.entities(), - health: &ecs.read_component(), - uid: &ecs.read_component(), + health: ecs.read_component().into(), + uid: ecs.read_component().into(), uid_allocator: &ecs.read_resource::().into(), - //player: Either::First(ecs.read_component()), + player: ecs.read_component().into(), }; if let Err(e) = plugin_mgr .execute_event(&ecs_world, &plugin_api::event::PluginLoadEvent { diff --git a/server/src/lib.rs b/server/src/lib.rs index 4ccb17dccb..8bc0ea8aab 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -842,9 +842,10 @@ impl Server { 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(), + health: self.state.ecs().read_component().into(), + uid: self.state.ecs().read_component().into(), uid_allocator: &self.state.ecs().read_resource::().into(), + player: self.state.ecs().read_component().into(), }; let rs = plugin_manager.execute_event( &ecs_world, diff --git a/server/src/login_provider.rs b/server/src/login_provider.rs index 2c2e84ed88..a163c68279 100644 --- a/server/src/login_provider.rs +++ b/server/src/login_provider.rs @@ -1,11 +1,16 @@ use crate::settings::BanRecord; use authc::{AuthClient, AuthClientError, AuthToken, Uuid}; +use common::{comp::Player, uid::UidAllocator}; 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 plugin_api::{ + event::{PlayerJoinEvent, PlayerJoinResult}, + Health, +}; +use specs::{Entities, Read, ReadStorage, WriteStorage}; use std::str::FromStr; use tracing::{error, info}; @@ -54,10 +59,14 @@ impl LoginProvider { }; } - pub fn try_login( + pub fn try_login<'a, 'b>( &mut self, username_or_token: &str, - #[cfg(feature = "plugins")] world: &EcsWorld, + #[cfg(feature = "plugins")] entities: &Entities<'a>, + #[cfg(feature = "plugins")] health_comp: &ReadStorage<'a, Health>, + #[cfg(feature = "plugins")] uid_comp: &ReadStorage<'a, common::uid::Uid>, + #[cfg(feature = "plugins")] player_comp: &WriteStorage<'a, Player>, + #[cfg(feature = "plugins")] uids_res: &Read<'a, UidAllocator>, #[cfg(feature = "plugins")] plugin_manager: &PluginMgr, admins: &HashSet, whitelist: &HashSet, @@ -81,21 +90,29 @@ impl LoginProvider { } #[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)); - } - } - }, - Err(e) => { - error!("Error occured while executing `on_join`: {:?}",e); - }, + + let ecs_world = EcsWorld { + entities: &entities, + health: health_comp.into(), + uid: uid_comp.into(), + player: player_comp.into(), + uid_allocator: uids_res, }; + match plugin_manager.execute_event(&ecs_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); + }, + }; } // add the user to self.accounts diff --git a/server/src/sys/msg/register.rs b/server/src/sys/msg/register.rs index ceb640267f..0b6a34bdc0 100644 --- a/server/src/sys/msg/register.rs +++ b/server/src/sys/msg/register.rs @@ -14,8 +14,6 @@ use hashbrown::HashMap; use plugin_api::Health; use specs::{Entities, Join, Read, ReadExpect, ReadStorage, WriteExpect, WriteStorage}; -use common_sys::plugin::memory_manager::EcsWorld; - #[cfg(feature = "plugins")] use common_sys::plugin::PluginMgr; @@ -77,20 +75,20 @@ impl<'a> System<'a> for Sys { // List of new players to update player lists of all clients. let mut new_players = Vec::new(); - #[cfg(feature = "plugins")] - let ecs_world = EcsWorld { - entities: &entities, - health: &health_comp, - uid: &uids, - uid_allocator: &uid_allocator, - }; - for (entity, client) in (&entities, &clients).join() { let _ = super::try_recv_all(client, 0, |client, msg: ClientRegister| { let (username, uuid) = match login_provider.try_login( &msg.token_or_username, #[cfg(feature = "plugins")] - &ecs_world, + &entities, + #[cfg(feature = "plugins")] + &health_comp, + #[cfg(feature = "plugins")] + &uids, + #[cfg(feature = "plugins")] + &players, + #[cfg(feature = "plugins")] + &uid_allocator, #[cfg(feature = "plugins")] &plugin_mgr, &*editable_settings.admins,