Change Ecs access system to allow write accesses to be used + reintroduced get_player_name

This commit is contained in:
ccgauche 2021-03-10 19:36:53 +01:00
parent cf46ce70cf
commit 67b24294d6
7 changed files with 117 additions and 58 deletions

BIN
assets/plugins/veloren_plugin_template.plugin.tar (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -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<ReadStorage<'a, T>> 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<WriteStorage<'a, T>> 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<EcsWorld<'static, 'static>>,

View File

@ -232,29 +232,29 @@ fn retrieve_action(
action: Retrieve,
) -> Result<RetrieveResult, RetrieveError> {
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(
"<TODO>".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) => {

View File

@ -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::<UidAllocator>().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 {

View File

@ -842,9 +842,10 @@ impl Server {
let plugin_manager = self.state.ecs().read_resource::<PluginMgr>();
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::<UidAllocator>().into(),
player: self.state.ecs().read_component().into(),
};
let rs = plugin_manager.execute_event(
&ecs_world,

View File

@ -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<Uuid>,
whitelist: &HashSet<Uuid>,
@ -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

View File

@ -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,