Merge branch 'ccgauche/move-back-register-to-system' into 'master'

Moved back register to a system

See merge request veloren/veloren!1868
This commit is contained in:
Marcel 2021-03-10 00:56:33 +00:00
commit 81959c0a89
7 changed files with 187 additions and 184 deletions

View File

@ -1,7 +1,7 @@
use std::sync::atomic::{AtomicPtr, AtomicU32, AtomicU64, Ordering};
use serde::{de::DeserializeOwned, Serialize};
use specs::{shred::Fetch, Entities, ReadStorage};
use specs::{Entities, Read, ReadStorage};
use wasmer::{Function, Memory, Value};
use common::{
@ -11,17 +11,17 @@ use common::{
use super::errors::{MemoryAllocationError, PluginModuleError};
pub struct EcsWorld<'a> {
pub entities: Entities<'a>,
pub health: ReadStorage<'a, Health>,
pub uid: ReadStorage<'a, Uid>,
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 uid_allocator: Fetch<'a, UidAllocator>,
pub uid_allocator: &'b Read<'a, UidAllocator>,
}
/// This structure wraps the ECS pointer to ensure safety
pub struct EcsAccessManager {
ecs_pointer: AtomicPtr<EcsWorld<'static>>,
ecs_pointer: AtomicPtr<EcsWorld<'static, 'static>>,
}
impl Default for EcsAccessManager {

View File

@ -10,6 +10,7 @@ use common::{
terrain::{Block, TerrainChunk, TerrainGrid},
time::DayPeriod,
trade::Trades,
uid::UidAllocator,
vol::{ReadVol, WriteVol},
};
use common_base::span;
@ -212,10 +213,10 @@ impl State {
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(),
entities: &ecs.entities(),
health: &ecs.read_component(),
uid: &ecs.read_component(),
uid_allocator: &ecs.read_resource::<UidAllocator>().into(),
//player: Either::First(ecs.read_component()),
};
if let Err(e) = plugin_mgr

View File

@ -24,7 +24,6 @@ pub mod login_provider;
pub mod metrics;
pub mod persistence;
pub mod presence;
mod register;
pub mod rtsim;
pub mod settings;
pub mod state_ext;
@ -59,27 +58,26 @@ use common::{
assets::AssetExt,
cmd::ChatCommand,
comp,
comp::{item::MaterialStatManifest, Admin, CharacterAbility, Player, Stats},
comp::{item::MaterialStatManifest, CharacterAbility},
event::{EventBus, ServerEvent},
recipe::default_recipe_book,
resources::TimeOfDay,
rtsim::RtSimEntity,
terrain::TerrainChunkSize,
uid::UidAllocator,
vol::{ReadVol, RectVolSize},
};
use common_ecs::run_now;
use common_net::{
msg::{
CharacterInfo, ClientType, DisconnectReason, PlayerInfo, PlayerListUpdate, ServerGeneral,
ServerInfo, ServerInit, ServerMsg, WorldMapMsg,
ClientType, DisconnectReason, ServerGeneral, ServerInfo, ServerInit, ServerMsg, WorldMapMsg,
},
sync::WorldSyncExt,
};
#[cfg(feature = "plugins")]
use common_sys::plugin::PluginMgr;
use common_sys::{plugin::memory_manager::EcsWorld, state::State};
use hashbrown::HashMap;
use metrics::{EcsSystemMetrics, PhysicsMetrics, PlayerMetrics, TickMetrics};
use metrics::{EcsSystemMetrics, PhysicsMetrics, TickMetrics};
use network::{Network, Pid, ProtocolAddr};
use persistence::{
character_loader::{CharacterLoader, CharacterLoaderResponseKind},
@ -498,7 +496,7 @@ impl Server {
// (e.g. run before controller system)
//TODO: run in parallel
run_now::<sys::msg::general::Sys>(&self.state.ecs());
self.register_run();
run_now::<sys::msg::register::Sys>(&self.state.ecs());
run_now::<sys::msg::character_screen::Sys>(&self.state.ecs());
run_now::<sys::msg::in_game::Sys>(&self.state.ecs());
run_now::<sys::msg::ping::Sys>(&self.state.ecs());
@ -725,75 +723,6 @@ impl Server {
self.state.cleanup();
}
pub fn register_run(&mut self) {
let world = self.state_mut().ecs_mut();
let entities = world.entities();
let player_metrics = world.read_resource::<PlayerMetrics>();
let uids = world.read_storage::<Uid>();
let clients = world.read_storage::<Client>();
let mut players = world.write_storage::<Player>();
let stats = world.read_storage::<Stats>();
let mut login_provider = world.write_resource::<LoginProvider>();
let mut admins = world.write_storage::<Admin>();
let editable_settings = world.read_resource::<EditableSettings>();
// Player list to send new players.
let player_list = (&uids, &players, stats.maybe(), admins.maybe())
.join()
.map(|(uid, player, stats, admin)| {
(*uid, PlayerInfo {
is_online: true,
is_admin: admin.is_some(),
player_alias: player.alias.clone(),
character: stats.map(|stats| CharacterInfo {
name: stats.name.clone(),
}),
})
})
.collect::<HashMap<_, _>>();
// List of new players to update player lists of all clients.
let mut new_players = Vec::new();
for (entity, client) in (&entities, &clients).join() {
let _ = sys::msg::try_recv_all(client, 0, |client, msg| {
register::handle_register_msg(
&world,
&player_list,
&mut new_players,
entity,
client,
&player_metrics,
&mut login_provider,
&mut admins,
&mut players,
&editable_settings,
msg,
)
});
}
// Handle new players.
// Tell all clients to add them to the player list.
for entity in new_players {
if let (Some(uid), Some(player)) = (uids.get(entity), players.get(entity)) {
let mut lazy_msg = None;
for (_, client) in (&players, &clients).join() {
if lazy_msg.is_none() {
lazy_msg = Some(client.prepare(ServerGeneral::PlayerListUpdate(
PlayerListUpdate::Add(*uid, PlayerInfo {
player_alias: player.alias.clone(),
is_online: true,
is_admin: admins.get(entity).is_some(),
character: None, // new players will be on character select.
}),
)));
}
lazy_msg.as_ref().map(|ref msg| client.send_prepared(&msg));
}
}
}
}
fn initialize_client(
&mut self,
client: crate::connection_handler::IncomingClient,
@ -912,10 +841,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(),
uid_allocator: self.state.ecs().read_resource(),
entities: &self.state.ecs().entities(),
health: &self.state.ecs().read_component(),
uid: &self.state.ecs().read_component(),
uid_allocator: &self.state.ecs().read_resource::<UidAllocator>().into(),
};
let rs = plugin_manager.execute_event(
&ecs_world,

View File

@ -57,7 +57,7 @@ impl LoginProvider {
pub fn try_login(
&mut self,
username_or_token: &str,
world: &EcsWorld,
#[cfg(feature = "plugins")] world: &EcsWorld,
#[cfg(feature = "plugins")] plugin_manager: &PluginMgr,
admins: &HashSet<Uuid>,
whitelist: &HashSet<Uuid>,

View File

@ -1,92 +0,0 @@
use common::comp::{Admin, Player};
use common_net::msg::{
ClientRegister, PlayerInfo, PlayerListUpdate, RegisterError, ServerGeneral,
ServerRegisterAnswer,
};
use common_sys::plugin::memory_manager::EcsWorld;
#[cfg(feature = "plugins")]
use common_sys::plugin::PluginMgr;
use hashbrown::HashMap;
use plugin_api::Uid;
use specs::{
shred::{Fetch, FetchMut},
Entity, World, WorldExt, WriteStorage,
};
use crate::{
client::Client, login_provider::LoginProvider, metrics::PlayerMetrics, EditableSettings,
};
#[allow(clippy::too_many_arguments)]
pub(crate) fn handle_register_msg(
world: &World,
player_list: &HashMap<Uid, PlayerInfo>,
new_players: &mut Vec<Entity>,
entity: Entity,
client: &Client,
player_metrics: &Fetch<'_, PlayerMetrics>,
login_provider: &mut FetchMut<'_, LoginProvider>,
admins: &mut WriteStorage<'_, Admin>,
players: &mut WriteStorage<'_, Player>,
editable_settings: &Fetch<'_, EditableSettings>,
msg: ClientRegister,
) -> Result<(), crate::error::Error> {
#[cfg(feature = "plugins")]
let plugin_mgr = world.read_resource::<PluginMgr>();
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,
&ecs_world,
#[cfg(feature = "plugins")]
&plugin_mgr,
&*editable_settings.admins,
&*editable_settings.whitelist,
&*editable_settings.banlist,
) {
Err(err) => {
client.send(ServerRegisterAnswer::Err(err))?;
return Ok(());
},
Ok((username, uuid)) => (username, uuid),
};
let player = Player::new(username, uuid);
let is_admin = editable_settings.admins.contains(&uuid);
if !player.is_valid() {
// Invalid player
client.send(ServerRegisterAnswer::Err(RegisterError::InvalidCharacter))?;
return Ok(());
}
if !players.contains(entity) {
// Add Player component to this client
let _ = players.insert(entity, player);
player_metrics.players_connected.inc();
// Give the Admin component to the player if their name exists in
// admin list
if is_admin {
let _ = admins.insert(entity, Admin);
}
// Tell the client its request was successful.
client.send(ServerRegisterAnswer::Ok(()))?;
// Send initial player list
client.send(ServerGeneral::PlayerListUpdate(PlayerListUpdate::Init(
player_list.clone(),
)))?;
// Add to list to notify all clients of the new player
new_players.push(entity);
}
Ok(())
}

View File

@ -2,6 +2,7 @@ pub mod character_screen;
pub mod general;
pub mod in_game;
pub mod ping;
pub mod register;
use crate::client::Client;
use serde::de::DeserializeOwned;

View File

@ -0,0 +1,164 @@
use crate::{
client::Client, login_provider::LoginProvider, metrics::PlayerMetrics, EditableSettings,
};
use common::{
comp::{Admin, Player, Stats},
uid::{Uid, UidAllocator},
};
use common_ecs::{Job, Origin, Phase, System};
use common_net::msg::{
CharacterInfo, ClientRegister, PlayerInfo, PlayerListUpdate, RegisterError, ServerGeneral,
ServerRegisterAnswer,
};
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;
/// This system will handle new messages from clients
#[derive(Default)]
pub struct Sys;
impl<'a> System<'a> for Sys {
#[allow(clippy::type_complexity)]
type SystemData = (
Entities<'a>,
ReadExpect<'a, PlayerMetrics>,
ReadStorage<'a, Health>,
ReadStorage<'a, Uid>,
ReadStorage<'a, Client>,
WriteStorage<'a, Player>,
Read<'a, UidAllocator>,
Read<'a, PluginMgr>,
ReadStorage<'a, Stats>,
WriteExpect<'a, LoginProvider>,
WriteStorage<'a, Admin>,
ReadExpect<'a, EditableSettings>,
);
const NAME: &'static str = "msg::register";
const ORIGIN: Origin = Origin::Server;
const PHASE: Phase = Phase::Create;
fn run(
_job: &mut Job<Self>,
(
entities,
player_metrics,
health_comp,
uids,
clients,
mut players,
uid_allocator,
plugin_mgr,
stats,
mut login_provider,
mut admins,
editable_settings,
): Self::SystemData,
) {
// Player list to send new players.
let player_list = (&uids, &players, stats.maybe(), admins.maybe())
.join()
.map(|(uid, player, stats, admin)| {
(*uid, PlayerInfo {
is_online: true,
is_admin: admin.is_some(),
player_alias: player.alias.clone(),
character: stats.map(|stats| CharacterInfo {
name: stats.name.clone(),
}),
})
})
.collect::<HashMap<_, _>>();
// 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,
#[cfg(feature = "plugins")]
&plugin_mgr,
&*editable_settings.admins,
&*editable_settings.whitelist,
&*editable_settings.banlist,
) {
Err(err) => {
client.send(ServerRegisterAnswer::Err(err))?;
return Ok(());
},
Ok((username, uuid)) => (username, uuid),
};
let player = Player::new(username, uuid);
let is_admin = editable_settings.admins.contains(&uuid);
if !player.is_valid() {
// Invalid player
client.send(ServerRegisterAnswer::Err(RegisterError::InvalidCharacter))?;
return Ok(());
}
if !players.contains(entity) {
// Add Player component to this client
let _ = players.insert(entity, player);
player_metrics.players_connected.inc();
// Give the Admin component to the player if their name exists in
// admin list
if is_admin {
let _ = admins.insert(entity, Admin);
}
// Tell the client its request was successful.
client.send(ServerRegisterAnswer::Ok(()))?;
// Send initial player list
client.send(ServerGeneral::PlayerListUpdate(PlayerListUpdate::Init(
player_list.clone(),
)))?;
// Add to list to notify all clients of the new player
new_players.push(entity);
}
Ok(())
});
}
// Handle new players.
// Tell all clients to add them to the player list.
for entity in new_players {
if let (Some(uid), Some(player)) = (uids.get(entity), players.get(entity)) {
let mut lazy_msg = None;
for (_, client) in (&players, &clients).join() {
if lazy_msg.is_none() {
lazy_msg = Some(client.prepare(ServerGeneral::PlayerListUpdate(
PlayerListUpdate::Add(*uid, PlayerInfo {
player_alias: player.alias.clone(),
is_online: true,
is_admin: admins.get(entity).is_some(),
character: None, // new players will be on character select.
}),
)));
}
lazy_msg.as_ref().map(|ref msg| client.send_prepared(&msg));
}
}
}
}
}