mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Lots of improvement in pointer management (switched from i32 to u64) + New event implemented
This commit is contained in:
parent
b7bd0306e6
commit
dbd4d70b79
@ -4,6 +4,7 @@ use network::{ParticipantError, StreamError};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
KickedByPlugin(String),
|
||||
NetworkErr(NetworkError),
|
||||
ParticipantErr(ParticipantError),
|
||||
StreamErr(StreamError),
|
||||
|
@ -500,6 +500,7 @@ impl Client {
|
||||
Err(RegisterError::AuthError(err)) => Err(Error::AuthErr(err)),
|
||||
Err(RegisterError::InvalidCharacter) => Err(Error::InvalidCharacter),
|
||||
Err(RegisterError::NotOnWhitelist) => Err(Error::NotOnWhitelist),
|
||||
Err(RegisterError::KickedByPlugin(err)) => Err(Error::KickedByPlugin(err)),
|
||||
Err(RegisterError::Banned(reason)) => Err(Error::Banned(reason)),
|
||||
Ok(()) => {
|
||||
self.registered = true;
|
||||
|
@ -191,6 +191,7 @@ pub enum RegisterError {
|
||||
AlreadyLoggedIn,
|
||||
AuthError(String),
|
||||
Banned(String),
|
||||
KickedByPlugin(String),
|
||||
InvalidCharacter,
|
||||
NotOnWhitelist,
|
||||
//TODO: InvalidAlias,
|
||||
|
@ -8,7 +8,7 @@ pub mod buff;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
mod character_state;
|
||||
#[cfg(not(target_arch = "wasm32"))] pub mod chat;
|
||||
pub mod combo;
|
||||
#[cfg(not(target_arch = "wasm32"))] pub mod combo;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
mod controller;
|
||||
#[cfg(not(target_arch = "wasm32"))] mod energy;
|
||||
|
@ -1,4 +1,4 @@
|
||||
use std::sync::atomic::{AtomicI32, AtomicPtr, AtomicU32, Ordering};
|
||||
use std::sync::atomic::{AtomicPtr, AtomicU32, AtomicU64, Ordering};
|
||||
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
use specs::World;
|
||||
@ -52,14 +52,14 @@ impl EcsAccessManager {
|
||||
}
|
||||
|
||||
pub struct MemoryManager {
|
||||
pub pointer: AtomicI32,
|
||||
pub pointer: AtomicU64,
|
||||
pub length: AtomicU32,
|
||||
}
|
||||
|
||||
impl Default for MemoryManager {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
pointer: AtomicI32::new(0),
|
||||
pointer: AtomicU64::new(0),
|
||||
length: AtomicU32::new(0),
|
||||
}
|
||||
}
|
||||
@ -74,16 +74,18 @@ impl MemoryManager {
|
||||
&self,
|
||||
object_length: u32,
|
||||
allocator: &Function,
|
||||
) -> Result<i32, MemoryAllocationError> {
|
||||
) -> Result<u64, MemoryAllocationError> {
|
||||
if self.length.load(Ordering::SeqCst) >= object_length {
|
||||
return Ok(self.pointer.load(Ordering::SeqCst));
|
||||
}
|
||||
let pointer = allocator
|
||||
.call(&[Value::I32(object_length as i32)])
|
||||
.map_err(MemoryAllocationError::CantAllocate)?;
|
||||
let pointer = pointer[0]
|
||||
.i32()
|
||||
.ok_or(MemoryAllocationError::InvalidReturnType)?;
|
||||
let pointer = super::module::from_i64(
|
||||
pointer[0]
|
||||
.i64()
|
||||
.ok_or(MemoryAllocationError::InvalidReturnType)?,
|
||||
);
|
||||
self.length.store(object_length, Ordering::SeqCst);
|
||||
self.pointer.store(pointer, Ordering::SeqCst);
|
||||
Ok(pointer)
|
||||
@ -96,7 +98,7 @@ impl MemoryManager {
|
||||
memory: &Memory,
|
||||
allocator: &Function,
|
||||
object: &T,
|
||||
) -> Result<(i32, u32), PluginModuleError> {
|
||||
) -> Result<(u64, u64), PluginModuleError> {
|
||||
self.write_bytes(
|
||||
memory,
|
||||
allocator,
|
||||
@ -104,6 +106,19 @@ impl MemoryManager {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn write_data_as_pointer<T: Serialize>(
|
||||
&self,
|
||||
memory: &Memory,
|
||||
allocator: &Function,
|
||||
object: &T,
|
||||
) -> Result<u64, PluginModuleError> {
|
||||
self.write_bytes_as_pointer(
|
||||
memory,
|
||||
allocator,
|
||||
&bincode::serialize(object).map_err(PluginModuleError::Encoding)?,
|
||||
)
|
||||
}
|
||||
|
||||
/// This function writes an raw bytes to WASM memory returning a pointer and
|
||||
/// a length. Will realloc the buffer is not wide enough
|
||||
pub fn write_bytes(
|
||||
@ -111,7 +126,7 @@ impl MemoryManager {
|
||||
memory: &Memory,
|
||||
allocator: &Function,
|
||||
array: &[u8],
|
||||
) -> Result<(i32, u32), PluginModuleError> {
|
||||
) -> Result<(u64, u64), PluginModuleError> {
|
||||
let len = array.len();
|
||||
let mem_position = self
|
||||
.get_pointer(len as u32, allocator)
|
||||
@ -120,7 +135,24 @@ impl MemoryManager {
|
||||
.iter()
|
||||
.zip(array.iter())
|
||||
.for_each(|(cell, byte)| cell.set(*byte));
|
||||
Ok((mem_position as i32, len as u32))
|
||||
Ok((mem_position as u64, len as u64))
|
||||
}
|
||||
|
||||
pub fn write_bytes_as_pointer(
|
||||
&self,
|
||||
memory: &Memory,
|
||||
allocator: &Function,
|
||||
array: &[u8],
|
||||
) -> Result<u64, PluginModuleError> {
|
||||
let len = array.len();
|
||||
let mem_position = self
|
||||
.get_pointer(len as u32 + 8, allocator)
|
||||
.map_err(PluginModuleError::MemoryAllocation)? as usize;
|
||||
memory.view()[mem_position..mem_position + len + 8]
|
||||
.iter()
|
||||
.zip((len as u64).to_le_bytes().iter().chain(array.iter()))
|
||||
.for_each(|(cell, byte)| cell.set(*byte));
|
||||
Ok(mem_position as u64)
|
||||
}
|
||||
}
|
||||
|
||||
@ -128,14 +160,14 @@ impl MemoryManager {
|
||||
/// converts it to an object using bincode
|
||||
pub fn read_data<T: DeserializeOwned>(
|
||||
memory: &Memory,
|
||||
position: i32,
|
||||
length: u32,
|
||||
position: u64,
|
||||
length: u64,
|
||||
) -> Result<T, bincode::Error> {
|
||||
bincode::deserialize(&read_bytes(memory, position, 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: u64, length: u64) -> Vec<u8> {
|
||||
memory.view()[(position as usize)..(position as usize) + length as usize]
|
||||
.iter()
|
||||
.map(|x| x.get())
|
||||
|
@ -43,8 +43,8 @@ impl PluginModule {
|
||||
let module = Module::new(&store, &wasm_data).expect("Can't compile");
|
||||
|
||||
// This is the function imported into the wasm environement
|
||||
fn raw_emit_actions(env: &HostFunctionEnvironement, ptr: u32, len: u32) {
|
||||
handle_actions(match env.read_data(ptr as i32, len) {
|
||||
fn raw_emit_actions(env: &HostFunctionEnvironement, ptr: i64, len: i64) {
|
||||
handle_actions(match env.read_data(from_i64(ptr), from_i64(len)) {
|
||||
Ok(e) => e,
|
||||
Err(e) => {
|
||||
tracing::error!(?e, "Can't decode action");
|
||||
@ -53,16 +53,15 @@ impl PluginModule {
|
||||
});
|
||||
}
|
||||
|
||||
fn raw_retrieve_action(env: &HostFunctionEnvironement, ptr: u32, len: u32) -> i64 {
|
||||
let out = match env.read_data(ptr as _, len) {
|
||||
fn raw_retrieve_action(env: &HostFunctionEnvironement, ptr: i64, len: i64) -> i64 {
|
||||
let out = match env.read_data(from_i64(ptr), from_i64(len)) {
|
||||
Ok(data) => retrieve_action(&env.ecs, data),
|
||||
Err(e) => Err(RetrieveError::BincodeError(e.to_string())),
|
||||
};
|
||||
|
||||
// If an error happen set the i64 to 0 so the WASM side can tell an error
|
||||
// occured
|
||||
let (ptr, len) = env.write_data(&out).unwrap();
|
||||
to_i64(ptr, len as _)
|
||||
to_i64(env.write_data_as_pointer(&out).unwrap())
|
||||
}
|
||||
|
||||
fn dbg(a: i32) {
|
||||
@ -155,20 +154,24 @@ impl<T: Event> PreparedEventQuery<T> {
|
||||
}
|
||||
}
|
||||
|
||||
fn from_i64(i: i64) -> (i32, i32) {
|
||||
pub fn from_u128(i: u128) -> (u64, u64) {
|
||||
let i = i.to_le_bytes();
|
||||
(
|
||||
i32::from_le_bytes(i[0..4].try_into().unwrap()),
|
||||
i32::from_le_bytes(i[4..8].try_into().unwrap()),
|
||||
u64::from_le_bytes(i[0..8].try_into().unwrap()),
|
||||
u64::from_le_bytes(i[8..16].try_into().unwrap()),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn to_i64(a: i32, b: i32) -> i64 {
|
||||
pub fn to_u128(a: u64, b: u64) -> u128 {
|
||||
let a = a.to_le_bytes();
|
||||
let b = b.to_le_bytes();
|
||||
i64::from_le_bytes([a[0], a[1], a[2], a[3], b[0], b[1], b[2], b[3]])
|
||||
u128::from_le_bytes([a, b].concat().try_into().unwrap())
|
||||
}
|
||||
|
||||
pub fn to_i64(i: u64) -> i64 { i64::from_le_bytes(i.to_le_bytes()) }
|
||||
|
||||
pub fn from_i64(i: i64) -> u64 { u64::from_le_bytes(i.to_le_bytes()) }
|
||||
|
||||
// This function is not public because this function should not be used without
|
||||
// an interface to limit unsafe behaviours
|
||||
#[allow(clippy::needless_range_loop)]
|
||||
@ -196,24 +199,26 @@ fn execute_raw(
|
||||
// We call the function with the pointer and the length
|
||||
|
||||
let function_result = func
|
||||
.call(&[Value::I32(mem_position as i32), Value::I32(len as i32)])
|
||||
.call(&[Value::I64(to_i64(mem_position)), Value::I64(to_i64(len))])
|
||||
.map_err(PluginModuleError::RunFunction)?;
|
||||
|
||||
// Waiting for `multi-value` to be added to LLVM. So we encode the two i32 as an
|
||||
// i64
|
||||
|
||||
let (pointer, length) = from_i64(
|
||||
let u128_pointer = from_i64(
|
||||
function_result[0]
|
||||
.i64()
|
||||
.ok_or_else(PluginModuleError::InvalidArgumentType)?,
|
||||
);
|
||||
|
||||
let bytes = memory_manager::read_bytes(&module.memory, u128_pointer, 16);
|
||||
|
||||
// We read the return object and deserialize it
|
||||
|
||||
Ok(memory_manager::read_bytes(
|
||||
&module.memory,
|
||||
pointer,
|
||||
length as u32,
|
||||
u64::from_le_bytes(bytes[0..8].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[8..16].try_into().unwrap()),
|
||||
))
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@ impl HostFunctionEnvironement {
|
||||
|
||||
/// This function is a safe interface to WASM memory that writes data to the
|
||||
/// 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<(u64, u64), PluginModuleError> {
|
||||
self.memory_manager.write_data(
|
||||
self.memory.get_ref().unwrap(),
|
||||
self.allocator.get_ref().unwrap(),
|
||||
@ -45,12 +45,25 @@ impl HostFunctionEnvironement {
|
||||
)
|
||||
}
|
||||
|
||||
/// This function is a safe interface to WASM memory that writes data to the
|
||||
/// memory returning a pointer and length
|
||||
pub fn write_data_as_pointer<T: Serialize>(
|
||||
&self,
|
||||
object: &T,
|
||||
) -> Result<u64, PluginModuleError> {
|
||||
self.memory_manager.write_data_as_pointer(
|
||||
self.memory.get_ref().unwrap(),
|
||||
self.allocator.get_ref().unwrap(),
|
||||
object,
|
||||
)
|
||||
}
|
||||
|
||||
/// This function is a safe interface to WASM memory that reads memory from
|
||||
/// pointer and length returning an object
|
||||
pub fn read_data<T: DeserializeOwned>(
|
||||
&self,
|
||||
position: i32,
|
||||
length: u32,
|
||||
position: u64,
|
||||
length: u64,
|
||||
) -> Result<T, bincode::Error> {
|
||||
memory_manager::read_data(self.memory.get_ref().unwrap(), position, length)
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ pub mod event {
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
|
||||
pub struct PlayerJoinEvent {
|
||||
pub player_name: String,
|
||||
pub player_id: Uid,
|
||||
pub player_id: [u8; 16],
|
||||
}
|
||||
|
||||
impl Event for PlayerJoinEvent {
|
||||
@ -64,8 +64,9 @@ pub mod event {
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
|
||||
#[repr(u8)]
|
||||
pub enum PlayerJoinResult {
|
||||
CloseConnection,
|
||||
CloseConnection(String),
|
||||
None,
|
||||
}
|
||||
|
||||
|
@ -16,8 +16,8 @@ pub fn event_handler(_args: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let out: proc_macro2::TokenStream = quote! {
|
||||
#[allow(clippy::unnecessary_wraps)]
|
||||
#[no_mangle]
|
||||
pub fn #fn_name(intern__ptr: i32, intern__len: i32) -> i64 {
|
||||
let input = ::veloren_plugin_rt::read_input(intern__ptr,intern__len as u32).unwrap();
|
||||
pub fn #fn_name(intern__ptr: i64, intern__len: i64) -> i64 {
|
||||
let input = ::veloren_plugin_rt::read_input(intern__ptr as _,intern__len as _).unwrap();
|
||||
#[inline]
|
||||
fn inner(#fn_args) #fn_return {
|
||||
#fn_body
|
||||
|
@ -1,3 +1,5 @@
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
use veloren_plugin_rt::{
|
||||
api::{event::*, Action, GameMode},
|
||||
*,
|
||||
@ -29,14 +31,12 @@ pub fn on_command_testplugin(command: ChatCommandEvent) -> Result<Vec<String>, S
|
||||
)])
|
||||
}
|
||||
|
||||
static COUNTER: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
#[event_handler]
|
||||
pub fn on_player_join(input: PlayerJoinEvent) -> PlayerJoinResult {
|
||||
emit_action(Action::PlayerSendMessage(
|
||||
input.player_id,
|
||||
format!("Welcome {} on our server", input.player_name),
|
||||
));
|
||||
if input.player_name == "Cheater123" {
|
||||
PlayerJoinResult::CloseConnection
|
||||
pub fn on_join(input: PlayerJoinEvent) -> PlayerJoinResult {
|
||||
if COUNTER.swap(!COUNTER.load(Ordering::SeqCst), Ordering::SeqCst) {
|
||||
PlayerJoinResult::CloseConnection(format!("You are a cheater {:?}", input))
|
||||
} else {
|
||||
PlayerJoinResult::None
|
||||
}
|
||||
|
@ -18,8 +18,8 @@ use serde::{de::DeserializeOwned, Serialize};
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
extern "C" {
|
||||
fn raw_emit_actions(ptr: *const u8, len: usize);
|
||||
fn raw_retrieve_action(ptr: *const u8, len: usize) -> i64;
|
||||
fn raw_emit_actions(ptr: i64, len: i64);
|
||||
fn raw_retrieve_action(ptr: i64, len: i64) -> i64;
|
||||
pub fn dbg(i: i32);
|
||||
}
|
||||
|
||||
@ -28,8 +28,11 @@ pub fn retrieve_action<T: DeserializeOwned>(_actions: &api::Retrieve) -> Result<
|
||||
{
|
||||
let ret = bincode::serialize(&_actions).expect("Can't serialize action in emit");
|
||||
unsafe {
|
||||
let (ptr, len) = from_i64(raw_retrieve_action(ret.as_ptr(), ret.len()));
|
||||
let a = ::std::slice::from_raw_parts(ptr as _, len as _);
|
||||
let ptr = raw_retrieve_action(to_i64(ret.as_ptr() as _), to_i64(ret.len() as _));
|
||||
let ptr = from_i64(ptr);
|
||||
let len =
|
||||
u64::from_le_bytes(std::slice::from_raw_parts(ptr as _, 8).try_into().unwrap());
|
||||
let a = ::std::slice::from_raw_parts((ptr + 8) as _, len as _);
|
||||
bincode::deserialize::<Result<T, RetrieveError>>(&a)
|
||||
.map_err(|x| RetrieveError::BincodeError(x.to_string()))?
|
||||
}
|
||||
@ -45,36 +48,50 @@ pub fn emit_actions(_actions: Vec<api::Action>) {
|
||||
{
|
||||
let ret = bincode::serialize(&_actions).expect("Can't serialize action in emit");
|
||||
unsafe {
|
||||
raw_emit_actions(ret.as_ptr(), ret.len());
|
||||
raw_emit_actions(to_i64(ret.as_ptr() as _), to_i64(ret.len() as _));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_input<T>(ptr: i32, len: u32) -> Result<T, &'static str>
|
||||
pub fn read_input<T>(ptr: i64, len: i64) -> Result<T, &'static str>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
let slice = unsafe { ::std::slice::from_raw_parts(ptr as _, len as _) };
|
||||
let slice = unsafe { ::std::slice::from_raw_parts(from_i64(ptr) as _, from_i64(len) as _) };
|
||||
bincode::deserialize(slice).map_err(|_| "Failed to deserialize function input")
|
||||
}
|
||||
|
||||
pub fn from_i64(i: i64) -> (i32, i32) {
|
||||
pub fn from_u128(i: u128) -> (u64, u64) {
|
||||
let i = i.to_le_bytes();
|
||||
(
|
||||
i32::from_le_bytes(i[0..4].try_into().unwrap()),
|
||||
i32::from_le_bytes(i[4..8].try_into().unwrap()),
|
||||
u64::from_le_bytes(i[0..8].try_into().unwrap()),
|
||||
u64::from_le_bytes(i[8..16].try_into().unwrap()),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn to_i64(a: i32, b: i32) -> i64 {
|
||||
pub fn to_u128(a: u64, b: u64) -> u128 {
|
||||
let a = a.to_le_bytes();
|
||||
let b = b.to_le_bytes();
|
||||
i64::from_le_bytes([a[0], a[1], a[2], a[3], b[0], b[1], b[2], b[3]])
|
||||
u128::from_le_bytes([a, b].concat().try_into().unwrap())
|
||||
}
|
||||
|
||||
pub fn to_i64(i: u64) -> i64 { i64::from_le_bytes(i.to_le_bytes()) }
|
||||
|
||||
pub fn from_i64(i: i64) -> u64 { u64::from_le_bytes(i.to_le_bytes()) }
|
||||
|
||||
static mut VEC: Vec<u8> = vec![];
|
||||
static mut DATA: Vec<u8> = vec![];
|
||||
|
||||
pub fn write_output(value: impl Serialize) -> i64 {
|
||||
let ret = bincode::serialize(&value).expect("Can't serialize event output");
|
||||
to_i64(ret.as_ptr() as _, ret.len() as _)
|
||||
unsafe {
|
||||
VEC = bincode::serialize(&value).expect("Can't serialize event output");
|
||||
DATA = [
|
||||
(VEC.as_ptr() as u64).to_le_bytes(),
|
||||
(VEC.len() as u64).to_le_bytes(),
|
||||
]
|
||||
.concat();
|
||||
to_i64(DATA.as_ptr() as u64)
|
||||
}
|
||||
}
|
||||
|
||||
static mut BUFFERS: Vec<u8> = Vec::new();
|
||||
@ -83,7 +100,7 @@ static mut BUFFERS: Vec<u8> = Vec::new();
|
||||
/// # Safety
|
||||
/// This function should never be used only intented to by used by the host
|
||||
#[no_mangle]
|
||||
pub unsafe fn wasm_prepare_buffer(size: i32) -> i32 {
|
||||
pub unsafe fn wasm_prepare_buffer(size: i32) -> i64 {
|
||||
BUFFERS = vec![0u8; size as usize];
|
||||
BUFFERS.as_ptr() as i32
|
||||
BUFFERS.as_ptr() as i64
|
||||
}
|
||||
|
@ -507,7 +507,7 @@ impl Server {
|
||||
// (e.g. run before controller system)
|
||||
//TODO: run in parallel
|
||||
sys::msg::general::Sys.run_now(&self.state.ecs());
|
||||
sys::msg::register::Sys.run_now(&self.state.ecs());
|
||||
sys::msg::register::register_run(self.state_mut().ecs_mut());
|
||||
sys::msg::character_screen::Sys.run_now(&self.state.ecs());
|
||||
sys::msg::in_game::Sys.run_now(&self.state.ecs());
|
||||
sys::msg::ping::Sys.run_now(&self.state.ecs());
|
||||
|
@ -1,7 +1,10 @@
|
||||
use crate::settings::BanRecord;
|
||||
use authc::{AuthClient, AuthClientError, AuthToken, Uuid};
|
||||
use common_net::msg::RegisterError;
|
||||
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};
|
||||
|
||||
@ -53,6 +56,8 @@ impl LoginProvider {
|
||||
pub fn try_login(
|
||||
&mut self,
|
||||
username_or_token: &str,
|
||||
world: &World,
|
||||
plugin_manager: &PluginMgr,
|
||||
admins: &HashSet<Uuid>,
|
||||
whitelist: &HashSet<Uuid>,
|
||||
banlist: &HashMap<Uuid, BanRecord>,
|
||||
@ -74,6 +79,22 @@ impl LoginProvider {
|
||||
return Err(RegisterError::NotOnWhitelist);
|
||||
}
|
||||
|
||||
match plugin_manager.execute_event(&world, "on_join", &PlayerJoinEvent {
|
||||
player_name: username.clone(),
|
||||
player_id: uuid.as_bytes().clone(),
|
||||
}) {
|
||||
Ok(e) => {
|
||||
for i in e.into_iter() {
|
||||
if let PlayerJoinResult::CloseConnection(a) = i {
|
||||
return Err(RegisterError::KickedByPlugin(a));
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
error!("Error occured while executing `on_join`: {:?}",e);
|
||||
},
|
||||
};
|
||||
|
||||
// add the user to self.accounts
|
||||
self.login(uuid, username.clone())?;
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
use super::super::SysTimer;
|
||||
use crate::{
|
||||
client::Client, login_provider::LoginProvider, metrics::PlayerMetrics, EditableSettings,
|
||||
};
|
||||
@ -11,162 +10,151 @@ use common_net::msg::{
|
||||
CharacterInfo, ClientRegister, PlayerInfo, PlayerListUpdate, RegisterError, ServerGeneral,
|
||||
ServerRegisterAnswer,
|
||||
};
|
||||
use common_sys::plugin::PluginMgr;
|
||||
use hashbrown::HashMap;
|
||||
use specs::{Entities, Join, ReadExpect, ReadStorage, System, Write, WriteExpect, WriteStorage};
|
||||
use specs::{
|
||||
shred::{Fetch, FetchMut},
|
||||
Join, World, WorldExt, WriteStorage,
|
||||
};
|
||||
|
||||
impl Sys {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn handle_register_msg(
|
||||
player_list: &HashMap<Uid, PlayerInfo>,
|
||||
new_players: &mut Vec<specs::Entity>,
|
||||
entity: specs::Entity,
|
||||
client: &Client,
|
||||
player_metrics: &ReadExpect<'_, PlayerMetrics>,
|
||||
login_provider: &mut WriteExpect<'_, LoginProvider>,
|
||||
admins: &mut WriteStorage<'_, Admin>,
|
||||
players: &mut WriteStorage<'_, Player>,
|
||||
editable_settings: &ReadExpect<'_, EditableSettings>,
|
||||
msg: ClientRegister,
|
||||
) -> Result<(), crate::error::Error> {
|
||||
let (username, uuid) = match login_provider.try_login(
|
||||
&msg.token_or_username,
|
||||
&*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))?;
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn handle_register_msg(
|
||||
world: &World,
|
||||
player_list: &HashMap<Uid, PlayerInfo>,
|
||||
new_players: &mut Vec<specs::Entity>,
|
||||
entity: specs::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> {
|
||||
let plugin_mgr = world.read_resource::<PluginMgr>();
|
||||
let (username, uuid) = match login_provider.try_login(
|
||||
&msg.token_or_username,
|
||||
world,
|
||||
&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),
|
||||
};
|
||||
|
||||
if !players.contains(entity) {
|
||||
// Add Player component to this client
|
||||
let _ = players.insert(entity, player);
|
||||
player_metrics.players_connected.inc();
|
||||
let player = Player::new(username, uuid);
|
||||
let is_admin = editable_settings.admins.contains(&uuid);
|
||||
|
||||
// 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(())
|
||||
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(())
|
||||
}
|
||||
|
||||
/// This system will handle new messages from clients
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
#[allow(clippy::type_complexity)]
|
||||
type SystemData = (
|
||||
Entities<'a>,
|
||||
ReadExpect<'a, PlayerMetrics>,
|
||||
Write<'a, SysTimer<Self>>,
|
||||
ReadStorage<'a, Uid>,
|
||||
ReadStorage<'a, Client>,
|
||||
WriteStorage<'a, Player>,
|
||||
ReadStorage<'a, Stats>,
|
||||
WriteExpect<'a, LoginProvider>,
|
||||
WriteStorage<'a, Admin>,
|
||||
ReadExpect<'a, EditableSettings>,
|
||||
);
|
||||
|
||||
fn run(
|
||||
&mut self,
|
||||
(
|
||||
entities,
|
||||
player_metrics,
|
||||
mut timer,
|
||||
uids,
|
||||
clients,
|
||||
mut players,
|
||||
stats,
|
||||
mut login_provider,
|
||||
mut admins,
|
||||
editable_settings,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
span!(_guard, "run", "msg::register::Sys::run");
|
||||
timer.start();
|
||||
pub fn register_run(world: &mut World) {
|
||||
let entities = world.entities();
|
||||
let player_metrics = world.read_resource::<PlayerMetrics>();
|
||||
//let mut timer = world.write_resource::<SysTimer<Self>>();
|
||||
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(),
|
||||
}),
|
||||
})
|
||||
span!(_guard, "run", "msg::register::Sys::run");
|
||||
//timer.start();
|
||||
|
||||
// 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();
|
||||
})
|
||||
.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 _ = super::try_recv_all(client, 0, |client, msg| {
|
||||
Self::handle_register_msg(
|
||||
&player_list,
|
||||
&mut new_players,
|
||||
entity,
|
||||
client,
|
||||
&player_metrics,
|
||||
&mut login_provider,
|
||||
&mut admins,
|
||||
&mut players,
|
||||
&editable_settings,
|
||||
msg,
|
||||
)
|
||||
});
|
||||
}
|
||||
for (entity, client) in (&entities, &clients).join() {
|
||||
let _ = super::try_recv_all(client, 0, |client, msg| {
|
||||
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));
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
|
||||
timer.end()
|
||||
}
|
||||
|
||||
//timer.end()
|
||||
}
|
||||
|
@ -134,6 +134,7 @@ impl PlayState for MainMenuState {
|
||||
localized_strings.get("main.login.authentication_error"),
|
||||
e
|
||||
),
|
||||
client::Error::KickedByPlugin(e) => e,
|
||||
client::Error::TooManyPlayers => {
|
||||
localized_strings.get("main.login.server_full").into()
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user