pack together InGame, CharacterScreen and General variant in a single enum, as requested by zesterer.

His reason to reqeust that is, that there might not be a perfect disctinction in the future.
Now we need to send ServerGeneral over streams and do additional checking at various places to verify that not the wrong variant is send.
This commit is contained in:
Marcel Märtens 2020-10-12 10:18:28 +02:00
parent 55b59fbe07
commit 2a7378b4ae
17 changed files with 331 additions and 243 deletions

View File

@ -25,10 +25,9 @@ use common::{
},
event::{EventBus, LocalEvent},
msg::{
validate_chat_msg, ChatMsgValidationError, ClientCharacterScreen, ClientGeneral,
ClientInGame, ClientIngame, ClientMsg, ClientRegister, ClientType, DisconnectReason,
InviteAnswer, Notification, PingMsg, PlayerInfo, PlayerListUpdate, RegisterError,
ServerCharacterScreen, ServerGeneral, ServerInGame, ServerInfo, ServerInit,
validate_chat_msg, ChatMsgValidationError, ClientGeneral, ClientInGame, ClientMsg,
ClientRegister, ClientType, DisconnectReason, InviteAnswer, Notification, PingMsg,
PlayerInfo, PlayerListUpdate, RegisterError, ServerGeneral, ServerInfo, ServerInit,
ServerRegisterAnswer, MAX_BYTES_CHAT_MSG,
},
outcome::Outcome,
@ -71,7 +70,7 @@ pub enum Event {
pub struct Client {
registered: bool,
in_game: Option<ClientIngame>,
in_game: Option<ClientInGame>,
thread_pool: ThreadPool,
pub server_info: ServerInfo,
/// Just the "base" layer for LOD; currently includes colors and nothing
@ -466,39 +465,46 @@ impl Client {
let msg: ClientMsg = msg.into();
#[cfg(debug_assertions)]
{
// These assertions verify that the state is correct when a message is sent!
match &msg {
ClientMsg::Type(_) | ClientMsg::Register(_) => assert!(
!self.registered,
"must not send msg when already registered"
),
ClientMsg::CharacterScreen(_) => {
assert!(
self.registered,
"must not send character_screen msg when not registered"
);
assert!(
self.in_game.is_none(),
"must not send character_screen msg when not in character screen"
);
},
ClientMsg::InGame(_) => assert!(
self.in_game.is_some(),
"must not send in_game msg when not in game"
),
ClientMsg::General(_) => assert!(
self.registered,
"must not send general msg when not registered"
),
ClientMsg::Ping(_) => (),
}
const C_TYPE: ClientType = ClientType::Game;
let verified = msg.verify(C_TYPE, self.registered, self.in_game);
assert!(
verified,
format!(
"c_type: {:?}, registered: {}, in_game: {:?}, msg: {:?}",
C_TYPE, self.registered, self.in_game, msg
)
);
}
match msg {
ClientMsg::Type(msg) => self.register_stream.send(msg),
ClientMsg::Register(msg) => self.register_stream.send(msg),
ClientMsg::CharacterScreen(msg) => self.character_screen_stream.send(msg),
ClientMsg::InGame(msg) => self.in_game_stream.send(msg),
ClientMsg::General(msg) => self.general_stream.send(msg),
ClientMsg::General(msg) => {
let stream = match msg {
ClientGeneral::RequestCharacterList
| ClientGeneral::CreateCharacter { .. }
| ClientGeneral::DeleteCharacter(_)
| ClientGeneral::Character(_)
| ClientGeneral::Spectate => &mut self.character_screen_stream,
//Only in game
ClientGeneral::ControllerInputs(_)
| ClientGeneral::ControlEvent(_)
| ClientGeneral::ControlAction(_)
| ClientGeneral::SetViewDistance(_)
| ClientGeneral::BreakBlock(_)
| ClientGeneral::PlaceBlock(_, _)
| ClientGeneral::ExitInGame
| ClientGeneral::PlayerPhysics { .. }
| ClientGeneral::TerrainChunkRequest { .. }
| ClientGeneral::UnlockSkill(_)
| ClientGeneral::RefundSkill(_)
| ClientGeneral::UnlockSkillGroup(_) => &mut self.in_game_stream,
//Always possible
ClientGeneral::ChatMsg(_)
| ClientGeneral::Disconnect
| ClientGeneral::Terminate => &mut self.general_stream,
};
stream.send(msg)
},
ClientMsg::Ping(msg) => self.ping_stream.send(msg),
}
}
@ -518,10 +524,10 @@ impl Client {
/// Request a state transition to `ClientState::Character`.
pub fn request_character(&mut self, character_id: CharacterId) {
self.send_msg(ClientCharacterScreen::Character(character_id));
self.send_msg(ClientGeneral::Character(character_id));
//Assume we are in_game unless server tells us otherwise
self.in_game = Some(ClientIngame::Character);
self.in_game = Some(ClientInGame::Character);
self.active_character_id = Some(character_id);
}
@ -529,19 +535,19 @@ impl Client {
/// Load the current players character list
pub fn load_character_list(&mut self) {
self.character_list.loading = true;
self.send_msg(ClientCharacterScreen::RequestCharacterList);
self.send_msg(ClientGeneral::RequestCharacterList);
}
/// New character creation
pub fn create_character(&mut self, alias: String, tool: Option<String>, body: comp::Body) {
self.character_list.loading = true;
self.send_msg(ClientCharacterScreen::CreateCharacter { alias, tool, body });
self.send_msg(ClientGeneral::CreateCharacter { alias, tool, body });
}
/// Character deletion
pub fn delete_character(&mut self, character_id: CharacterId) {
self.character_list.loading = true;
self.send_msg(ClientCharacterScreen::DeleteCharacter(character_id));
self.send_msg(ClientGeneral::DeleteCharacter(character_id));
}
/// Send disconnect message to the server
@ -552,34 +558,34 @@ impl Client {
/// Request a state transition to `ClientState::Registered` from an ingame
/// state.
pub fn request_remove_character(&mut self) { self.send_msg(ClientInGame::ExitInGame); }
pub fn request_remove_character(&mut self) { self.send_msg(ClientGeneral::ExitInGame); }
pub fn set_view_distance(&mut self, view_distance: u32) {
self.view_distance = Some(view_distance.max(1).min(65));
self.send_msg(ClientInGame::SetViewDistance(self.view_distance.unwrap()));
self.send_msg(ClientGeneral::SetViewDistance(self.view_distance.unwrap()));
}
pub fn use_slot(&mut self, slot: comp::slot::Slot) {
self.send_msg(ClientInGame::ControlEvent(ControlEvent::InventoryManip(
self.send_msg(ClientGeneral::ControlEvent(ControlEvent::InventoryManip(
InventoryManip::Use(slot),
)));
}
pub fn swap_slots(&mut self, a: comp::slot::Slot, b: comp::slot::Slot) {
self.send_msg(ClientInGame::ControlEvent(ControlEvent::InventoryManip(
self.send_msg(ClientGeneral::ControlEvent(ControlEvent::InventoryManip(
InventoryManip::Swap(a, b),
)));
}
pub fn drop_slot(&mut self, slot: comp::slot::Slot) {
self.send_msg(ClientInGame::ControlEvent(ControlEvent::InventoryManip(
self.send_msg(ClientGeneral::ControlEvent(ControlEvent::InventoryManip(
InventoryManip::Drop(slot),
)));
}
pub fn pick_up(&mut self, entity: EcsEntity) {
if let Some(uid) = self.state.read_component_copied(entity) {
self.send_msg(ClientInGame::ControlEvent(ControlEvent::InventoryManip(
self.send_msg(ClientGeneral::ControlEvent(ControlEvent::InventoryManip(
InventoryManip::Pickup(uid),
)));
}
@ -599,7 +605,7 @@ impl Client {
pub fn craft_recipe(&mut self, recipe: &str) -> bool {
if self.can_craft_recipe(recipe) {
self.send_msg(ClientInGame::ControlEvent(ControlEvent::InventoryManip(
self.send_msg(ClientGeneral::ControlEvent(ControlEvent::InventoryManip(
InventoryManip::CraftRecipe(recipe.to_string()),
)));
true
@ -618,11 +624,11 @@ impl Client {
}
pub fn enable_lantern(&mut self) {
self.send_msg(ClientInGame::ControlEvent(ControlEvent::EnableLantern));
self.send_msg(ClientGeneral::ControlEvent(ControlEvent::EnableLantern));
}
pub fn disable_lantern(&mut self) {
self.send_msg(ClientInGame::ControlEvent(ControlEvent::DisableLantern));
self.send_msg(ClientGeneral::ControlEvent(ControlEvent::DisableLantern));
}
pub fn max_group_size(&self) -> u32 { self.max_group_size }
@ -640,7 +646,7 @@ impl Client {
pub fn pending_invites(&self) -> &HashSet<Uid> { &self.pending_invites }
pub fn send_group_invite(&mut self, invitee: Uid) {
self.send_msg(ClientInGame::ControlEvent(ControlEvent::GroupManip(
self.send_msg(ClientGeneral::ControlEvent(ControlEvent::GroupManip(
GroupManip::Invite(invitee),
)))
}
@ -648,7 +654,7 @@ impl Client {
pub fn accept_group_invite(&mut self) {
// Clear invite
self.group_invite.take();
self.send_msg(ClientInGame::ControlEvent(ControlEvent::GroupManip(
self.send_msg(ClientGeneral::ControlEvent(ControlEvent::GroupManip(
GroupManip::Accept,
)));
}
@ -656,25 +662,25 @@ impl Client {
pub fn decline_group_invite(&mut self) {
// Clear invite
self.group_invite.take();
self.send_msg(ClientInGame::ControlEvent(ControlEvent::GroupManip(
self.send_msg(ClientGeneral::ControlEvent(ControlEvent::GroupManip(
GroupManip::Decline,
)));
}
pub fn leave_group(&mut self) {
self.send_msg(ClientInGame::ControlEvent(ControlEvent::GroupManip(
self.send_msg(ClientGeneral::ControlEvent(ControlEvent::GroupManip(
GroupManip::Leave,
)));
}
pub fn kick_from_group(&mut self, uid: Uid) {
self.send_msg(ClientInGame::ControlEvent(ControlEvent::GroupManip(
self.send_msg(ClientGeneral::ControlEvent(ControlEvent::GroupManip(
GroupManip::Kick(uid),
)));
}
pub fn assign_group_leader(&mut self, uid: Uid) {
self.send_msg(ClientInGame::ControlEvent(ControlEvent::GroupManip(
self.send_msg(ClientGeneral::ControlEvent(ControlEvent::GroupManip(
GroupManip::AssignLeader(uid),
)));
}
@ -697,11 +703,11 @@ impl Client {
pub fn mount(&mut self, entity: EcsEntity) {
if let Some(uid) = self.state.read_component_copied(entity) {
self.send_msg(ClientInGame::ControlEvent(ControlEvent::Mount(uid)));
self.send_msg(ClientGeneral::ControlEvent(ControlEvent::Mount(uid)));
}
}
pub fn unmount(&mut self) { self.send_msg(ClientInGame::ControlEvent(ControlEvent::Unmount)); }
pub fn unmount(&mut self) { self.send_msg(ClientGeneral::ControlEvent(ControlEvent::Unmount)); }
pub fn respawn(&mut self) {
if self
@ -711,7 +717,7 @@ impl Client {
.get(self.entity)
.map_or(false, |s| s.is_dead)
{
self.send_msg(ClientInGame::ControlEvent(ControlEvent::Respawn));
self.send_msg(ClientGeneral::ControlEvent(ControlEvent::Respawn));
}
}
@ -808,7 +814,7 @@ impl Client {
{
controller.actions.push(control_action);
}
self.send_msg(ClientInGame::ControlAction(control_action));
self.send_msg(ClientGeneral::ControlAction(control_action));
}
pub fn view_distance(&self) -> Option<u32> { self.view_distance }
@ -852,13 +858,15 @@ impl Client {
}
pub fn place_block(&mut self, pos: Vec3<i32>, block: Block) {
self.send_msg(ClientInGame::PlaceBlock(pos, block));
self.send_msg(ClientGeneral::PlaceBlock(pos, block));
}
pub fn remove_block(&mut self, pos: Vec3<i32>) { self.send_msg(ClientInGame::BreakBlock(pos)); }
pub fn remove_block(&mut self, pos: Vec3<i32>) {
self.send_msg(ClientGeneral::BreakBlock(pos));
}
pub fn collect_block(&mut self, pos: Vec3<i32>) {
self.send_msg(ClientInGame::ControlEvent(ControlEvent::InventoryManip(
self.send_msg(ClientGeneral::ControlEvent(ControlEvent::InventoryManip(
InventoryManip::Collect(pos),
)));
}
@ -915,7 +923,7 @@ impl Client {
"Couldn't access controller component on client entity"
);
}
self.send_msg_err(ClientInGame::ControllerInputs(inputs))?;
self.send_msg_err(ClientGeneral::ControllerInputs(inputs))?;
}
// 2) Build up a list of events for this frame, to be passed to the frontend.
@ -1019,7 +1027,7 @@ impl Client {
if self.state.terrain().get_key(*key).is_none() {
if !skip_mode && !self.pending_chunks.contains_key(key) {
if self.pending_chunks.len() < 4 {
self.send_msg_err(ClientInGame::TerrainChunkRequest {
self.send_msg_err(ClientGeneral::TerrainChunkRequest {
key: *key,
})?;
self.pending_chunks.insert(*key, Instant::now());
@ -1065,7 +1073,7 @@ impl Client {
self.state.read_storage().get(self.entity).cloned(),
) {
self.in_game_stream
.send(ClientInGame::PlayerPhysics { pos, vel, ori })?;
.send(ClientGeneral::PlayerPhysics { pos, vel, ori })?;
}
}
@ -1237,6 +1245,7 @@ impl Client {
ServerGeneral::Notification(n) => {
frontend_events.push(Event::Notification(n));
},
_ => unreachable!("Not a general msg"),
}
Ok(())
}
@ -1244,10 +1253,10 @@ impl Client {
fn handle_server_in_game_msg(
&mut self,
frontend_events: &mut Vec<Event>,
msg: ServerInGame,
msg: ServerGeneral,
) -> Result<(), Error> {
match msg {
ServerInGame::GroupUpdate(change_notification) => {
ServerGeneral::GroupUpdate(change_notification) => {
use comp::group::ChangeNotification::*;
// Note: we use a hashmap since this would not work with entities outside
// the view distance
@ -1319,15 +1328,15 @@ impl Client {
},
}
},
ServerInGame::GroupInvite { inviter, timeout } => {
ServerGeneral::GroupInvite { inviter, timeout } => {
self.group_invite = Some((inviter, std::time::Instant::now(), timeout));
},
ServerInGame::InvitePending(uid) => {
ServerGeneral::InvitePending(uid) => {
if !self.pending_invites.insert(uid) {
warn!("Received message about pending invite that was already pending");
}
},
ServerInGame::InviteComplete { target, answer } => {
ServerGeneral::InviteComplete { target, answer } => {
if !self.pending_invites.remove(&target) {
warn!(
"Received completed invite message for invite that was not in the list of \
@ -1345,11 +1354,11 @@ impl Client {
frontend_events.push(Event::Chat(comp::ChatType::Meta.chat_msg(msg)));
},
// Cleanup for when the client goes back to the `in_game = None`
ServerInGame::ExitInGameSuccess => {
ServerGeneral::ExitInGameSuccess => {
self.in_game = None;
self.clean_state();
},
ServerInGame::InventoryUpdate(mut inventory, event) => {
ServerGeneral::InventoryUpdate(mut inventory, event) => {
match event {
InventoryUpdateEvent::CollectFailed => {},
_ => {
@ -1363,25 +1372,25 @@ impl Client {
frontend_events.push(Event::InventoryUpdated(event));
},
ServerInGame::TerrainChunkUpdate { key, chunk } => {
ServerGeneral::TerrainChunkUpdate { key, chunk } => {
if let Ok(chunk) = chunk {
self.state.insert_chunk(key, *chunk);
}
self.pending_chunks.remove(&key);
},
ServerInGame::TerrainBlockUpdates(mut blocks) => {
ServerGeneral::TerrainBlockUpdates(mut blocks) => {
blocks.drain().for_each(|(pos, block)| {
self.state.set_block(pos, block);
});
},
ServerInGame::SetViewDistance(vd) => {
ServerGeneral::SetViewDistance(vd) => {
self.view_distance = Some(vd);
frontend_events.push(Event::SetViewDistance(vd));
},
ServerInGame::Outcomes(outcomes) => {
ServerGeneral::Outcomes(outcomes) => {
frontend_events.extend(outcomes.into_iter().map(Event::Outcome))
},
ServerInGame::Knockback(impulse) => {
ServerGeneral::Knockback(impulse) => {
self.state
.ecs()
.read_resource::<EventBus<LocalEvent>>()
@ -1390,35 +1399,34 @@ impl Client {
impulse,
});
},
_ => unreachable!("Not a in_game message"),
}
Ok(())
}
fn handle_server_character_screen_msg(
&mut self,
msg: ServerCharacterScreen,
) -> Result<(), Error> {
fn handle_server_character_screen_msg(&mut self, msg: ServerGeneral) -> Result<(), Error> {
match msg {
ServerCharacterScreen::CharacterListUpdate(character_list) => {
ServerGeneral::CharacterListUpdate(character_list) => {
self.character_list.characters = character_list;
self.character_list.loading = false;
},
ServerCharacterScreen::CharacterActionError(error) => {
ServerGeneral::CharacterActionError(error) => {
warn!("CharacterActionError: {:?}.", error);
self.character_list.error = Some(error);
},
ServerCharacterScreen::CharacterDataLoadError(error) => {
ServerGeneral::CharacterDataLoadError(error) => {
trace!("Handling join error by server");
self.in_game = None;
self.clean_state();
self.character_list.error = Some(error);
},
ServerCharacterScreen::CharacterSuccess => {
ServerGeneral::CharacterSuccess => {
debug!("client is now in ingame state on server");
if let Some(vd) = self.view_distance {
self.set_view_distance(vd);
}
},
_ => unreachable!("Not a character_screen msg"),
}
Ok(())
}
@ -1518,7 +1526,7 @@ impl Client {
pub fn uid(&self) -> Option<Uid> { self.state.read_component_copied(self.entity) }
pub fn in_game(&self) -> Option<ClientIngame> { self.in_game }
pub fn in_game(&self) -> Option<ClientInGame> { self.in_game }
pub fn registered(&self) -> bool { self.registered }

View File

@ -12,16 +12,13 @@ use vek::*;
/// streams though). It's used to verify the correctness of the state in
/// debug_assertions
#[derive(Debug, Clone)]
#[allow(clippy::clippy::large_enum_variant)]
pub enum ClientMsg {
///Send on the first connection ONCE to identify client intention for
/// server
Type(ClientType),
///Send ONCE to register/auth to the server
Register(ClientRegister),
///Msg only to send while in character screen, e.g. `CreateCharacter`
CharacterScreen(ClientCharacterScreen),
///Msg only to send while playing in game, e.g. `PlayerPositionUpdates`
InGame(ClientInGame),
///Msg that can be send ALWAYS as soon as we are registered, e.g. `Chat`
General(ClientGeneral),
Ping(PingMsg),
@ -47,9 +44,10 @@ pub struct ClientRegister {
pub token_or_username: String,
}
//messages send by clients only valid when in character screen
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ClientCharacterScreen {
/// Messages sent from the client to the server
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ClientGeneral {
//Only in Character Screen
RequestCharacterList,
CreateCharacter {
alias: String,
@ -59,11 +57,7 @@ pub enum ClientCharacterScreen {
DeleteCharacter(CharacterId),
Character(CharacterId),
Spectate,
}
//messages send by clients only valid when in game (with a character)
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ClientInGame {
//Only in game
ControllerInputs(comp::ControllerInputs),
ControlEvent(comp::ControlEvent),
ControlAction(comp::ControlAction),
@ -82,16 +76,59 @@ pub enum ClientInGame {
UnlockSkill(Skill),
RefundSkill(Skill),
UnlockSkillGroup(SkillGroupType),
}
/// Messages sent from the client to the server
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ClientGeneral {
//Always possible
ChatMsg(String),
Disconnect,
Terminate,
}
impl ClientMsg {
pub fn verify(
&self,
c_type: ClientType,
registered: bool,
in_game: Option<super::ClientInGame>,
) -> bool {
match self {
ClientMsg::Type(t) => c_type == *t,
ClientMsg::Register(_) => !registered && in_game.is_none(),
ClientMsg::General(g) => {
registered
&& match g {
ClientGeneral::RequestCharacterList
| ClientGeneral::CreateCharacter { .. }
| ClientGeneral::DeleteCharacter(_) => {
c_type != ClientType::ChatOnly && in_game.is_none()
},
ClientGeneral::Character(_) | ClientGeneral::Spectate => {
c_type == ClientType::Game && in_game.is_none()
},
//Only in game
ClientGeneral::ControllerInputs(_)
| ClientGeneral::ControlEvent(_)
| ClientGeneral::ControlAction(_)
| ClientGeneral::SetViewDistance(_)
| ClientGeneral::BreakBlock(_)
| ClientGeneral::PlaceBlock(_, _)
| ClientGeneral::ExitInGame
| ClientGeneral::PlayerPhysics { .. }
| ClientGeneral::TerrainChunkRequest { .. }
| ClientGeneral::UnlockSkill(_)
| ClientGeneral::RefundSkill(_)
| ClientGeneral::UnlockSkillGroup(_) => {
c_type == ClientType::Game && in_game.is_some()
},
//Always possible
ClientGeneral::ChatMsg(_)
| ClientGeneral::Disconnect
| ClientGeneral::Terminate => true,
}
},
ClientMsg::Ping(_) => true,
}
}
}
/*
end of 2nd level Enums
*/
@ -104,14 +141,6 @@ impl Into<ClientMsg> for ClientRegister {
fn into(self) -> ClientMsg { ClientMsg::Register(self) }
}
impl Into<ClientMsg> for ClientCharacterScreen {
fn into(self) -> ClientMsg { ClientMsg::CharacterScreen(self) }
}
impl Into<ClientMsg> for ClientInGame {
fn into(self) -> ClientMsg { ClientMsg::InGame(self) }
}
impl Into<ClientMsg> for ClientGeneral {
fn into(self) -> ClientMsg { ClientMsg::General(self) }
}

View File

@ -5,21 +5,18 @@ pub mod world_packet;
// Reexports
pub use self::{
client::{
ClientCharacterScreen, ClientGeneral, ClientInGame, ClientMsg, ClientRegister, ClientType,
},
client::{ClientGeneral, ClientMsg, ClientRegister, ClientType},
ecs_packet::EcsCompPacket,
server::{
CharacterInfo, DisconnectReason, InviteAnswer, Notification, PlayerInfo, PlayerListUpdate,
RegisterError, ServerCharacterScreen, ServerGeneral, ServerInGame, ServerInfo, ServerInit,
ServerMsg, ServerRegisterAnswer,
RegisterError, ServerGeneral, ServerInfo, ServerInit, ServerMsg, ServerRegisterAnswer,
},
world_packet::WorldMapMsg,
};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum ClientIngame {
pub enum ClientInGame {
Spectator,
Character,
}

View File

@ -1,4 +1,4 @@
use super::{EcsCompPacket, PingMsg};
use super::{ClientType, EcsCompPacket, PingMsg};
use crate::{
character::CharacterItem,
comp,
@ -24,12 +24,6 @@ pub enum ServerMsg {
Init(ServerInit),
/// Result to `ClientMsg::Register`. send ONCE
RegisterAnswer(ServerRegisterAnswer),
/// Msg only to send when client is on the character screen, e.g.
/// `CharacterListUpdate`
CharacterScreen(ServerCharacterScreen),
/// Msg only to send when client is playing in game, e.g.
/// `TerrainChunkUpdate`
InGame(ServerInGame),
///Msg that can be send ALWAYS as soon as client is registered, e.g. `Chat`
General(ServerGeneral),
Ping(PingMsg),
@ -65,9 +59,10 @@ pub enum ServerInit {
pub type ServerRegisterAnswer = Result<(), RegisterError>;
//Messages only allowed while client in character screen
/// Messages sent from the server to the client
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ServerCharacterScreen {
pub enum ServerGeneral {
//Character Screen related
/// An error occurred while loading character data
CharacterDataLoadError(String),
/// A list of characters belonging to the a authenticated player was sent
@ -75,23 +70,21 @@ pub enum ServerCharacterScreen {
/// An error occurred while creating or deleting a character
CharacterActionError(String),
CharacterSuccess,
}
//Messages only allowed while client is in game (with a character)
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ServerInGame {
//Ingame related
GroupUpdate(comp::group::ChangeNotification<sync::Uid>),
// Indicate to the client that they are invited to join a group
/// Indicate to the client that they are invited to join a group
GroupInvite {
inviter: sync::Uid,
timeout: std::time::Duration,
},
// Indicate to the client that their sent invite was not invalid and is currently pending
/// Indicate to the client that their sent invite was not invalid and is
/// currently pending
InvitePending(sync::Uid),
// Note: this could potentially include all the failure cases such as inviting yourself in
// which case the `InvitePending` message could be removed and the client could consider their
// invite pending until they receive this message
// Indicate to the client the result of their invite
/// Note: this could potentially include all the failure cases such as
/// inviting yourself in which case the `InvitePending` message could be
/// removed and the client could consider their invite pending until
/// they receive this message Indicate to the client the result of their
/// invite
InviteComplete {
target: sync::Uid,
answer: InviteAnswer,
@ -108,11 +101,7 @@ pub enum ServerInGame {
SetViewDistance(u32),
Outcomes(Vec<Outcome>),
Knockback(Vec3<f32>),
}
/// Messages sent from the server to the client
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ServerGeneral {
// Always possible
PlayerListUpdate(PlayerListUpdate),
/// A message to go into the client chat box. The client is responsible for
/// formatting the message and turning it into a speech bubble.
@ -190,6 +179,61 @@ pub enum RegisterError {
//TODO: InvalidAlias,
}
impl ServerMsg {
pub fn verify(
&self,
c_type: ClientType,
registered: bool,
in_game: Option<super::ClientInGame>,
) -> bool {
match self {
ServerMsg::Info(_) | ServerMsg::Init(_) | ServerMsg::RegisterAnswer(_) => {
!registered && in_game.is_none()
},
ServerMsg::General(g) => {
registered
&& match g {
//Character Screen related
ServerGeneral::CharacterDataLoadError(_)
| ServerGeneral::CharacterListUpdate(_)
| ServerGeneral::CharacterActionError(_) => {
c_type != ClientType::ChatOnly && in_game.is_none()
},
ServerGeneral::CharacterSuccess => {
c_type == ClientType::Game && in_game.is_none()
},
//Ingame related
ServerGeneral::GroupUpdate(_)
| ServerGeneral::GroupInvite { .. }
| ServerGeneral::InvitePending(_)
| ServerGeneral::InviteComplete { .. }
| ServerGeneral::ExitInGameSuccess
| ServerGeneral::InventoryUpdate(_, _)
| ServerGeneral::TerrainChunkUpdate { .. }
| ServerGeneral::TerrainBlockUpdates(_)
| ServerGeneral::SetViewDistance(_)
| ServerGeneral::Outcomes(_)
| ServerGeneral::Knockback(_) => {
c_type == ClientType::Game && in_game.is_some()
},
// Always possible
ServerGeneral::PlayerListUpdate(_)
| ServerGeneral::ChatMsg(_)
| ServerGeneral::SetPlayerEntity(_)
| ServerGeneral::TimeOfDay(_)
| ServerGeneral::EntitySync(_)
| ServerGeneral::CompSync(_)
| ServerGeneral::CreateEntity(_)
| ServerGeneral::DeleteEntity(_)
| ServerGeneral::Disconnect(_)
| ServerGeneral::Notification(_) => true,
}
},
ServerMsg::Ping(_) => true,
}
}
}
impl From<AuthClientError> for RegisterError {
fn from(err: AuthClientError) -> Self { Self::AuthError(err.to_string()) }
}
@ -210,14 +254,6 @@ impl Into<ServerMsg> for ServerRegisterAnswer {
fn into(self) -> ServerMsg { ServerMsg::RegisterAnswer(self) }
}
impl Into<ServerMsg> for ServerCharacterScreen {
fn into(self) -> ServerMsg { ServerMsg::CharacterScreen(self) }
}
impl Into<ServerMsg> for ServerInGame {
fn into(self) -> ServerMsg { ServerMsg::InGame(self) }
}
impl Into<ServerMsg> for ServerGeneral {
fn into(self) -> ServerMsg { ServerMsg::General(self) }
}

View File

@ -1,5 +1,5 @@
use crate::error::Error;
use common::msg::{ClientIngame, ClientType, ServerMsg};
use common::msg::{ClientInGame, ClientType, ServerGeneral, ServerMsg};
use hashbrown::HashSet;
use network::{Participant, Stream};
use serde::{de::DeserializeOwned, Serialize};
@ -11,7 +11,7 @@ use vek::*;
pub struct Client {
pub registered: bool,
pub client_type: ClientType,
pub in_game: Option<ClientIngame>,
pub in_game: Option<ClientInGame>,
pub participant: Option<Participant>,
pub general_stream: Stream,
pub ping_stream: Stream,
@ -59,16 +59,38 @@ impl Client {
ServerMsg::RegisterAnswer(msg) => {
Self::internal_send(&mut self.network_error, &mut self.register_stream, &msg)
},
ServerMsg::CharacterScreen(msg) => Self::internal_send(
&mut self.network_error,
&mut self.character_screen_stream,
&msg,
),
ServerMsg::InGame(msg) => {
Self::internal_send(&mut self.network_error, &mut self.in_game_stream, &msg)
},
ServerMsg::General(msg) => {
Self::internal_send(&mut self.network_error, &mut self.general_stream, &msg)
let stream = match &msg {
//Character Screen related
ServerGeneral::CharacterDataLoadError(_)
| ServerGeneral::CharacterListUpdate(_)
| ServerGeneral::CharacterActionError(_)
| ServerGeneral::CharacterSuccess => &mut self.character_screen_stream,
//Ingame related
ServerGeneral::GroupUpdate(_)
| ServerGeneral::GroupInvite { .. }
| ServerGeneral::InvitePending(_)
| ServerGeneral::InviteComplete { .. }
| ServerGeneral::ExitInGameSuccess
| ServerGeneral::InventoryUpdate(_, _)
| ServerGeneral::TerrainChunkUpdate { .. }
| ServerGeneral::TerrainBlockUpdates(_)
| ServerGeneral::SetViewDistance(_)
| ServerGeneral::Outcomes(_)
| ServerGeneral::Knockback(_) => &mut self.in_game_stream,
// Always possible
ServerGeneral::PlayerListUpdate(_)
| ServerGeneral::ChatMsg(_)
| ServerGeneral::SetPlayerEntity(_)
| ServerGeneral::TimeOfDay(_)
| ServerGeneral::EntitySync(_)
| ServerGeneral::CompSync(_)
| ServerGeneral::CreateEntity(_)
| ServerGeneral::DeleteEntity(_)
| ServerGeneral::Disconnect(_)
| ServerGeneral::Notification(_) => &mut self.general_stream,
};
Self::internal_send(&mut self.network_error, stream, &msg)
},
ServerMsg::Ping(msg) => {
Self::internal_send(&mut self.network_error, &mut self.ping_stream, &msg)

View File

@ -12,7 +12,7 @@ use common::{
cmd::{ChatCommand, CHAT_COMMANDS, CHAT_SHORTCUTS},
comp::{self, ChatType, Item, LightEmitter, WaypointArea},
event::{EventBus, ServerEvent},
msg::{DisconnectReason, Notification, PlayerListUpdate, ServerGeneral, ServerInGame},
msg::{DisconnectReason, Notification, PlayerListUpdate, ServerGeneral},
npc::{self, get_npc_name},
state::TimeOfDay,
sync::{Uid, WorldSyncExt},
@ -669,7 +669,9 @@ fn handle_spawn(
.try_map(|e| uids.get(e).copied())
.map(|g| (g, c))
})
.map(|(g, c)| c.send_msg(ServerInGame::GroupUpdate(g)));
.map(|(g, c)| {
c.send_msg(ServerGeneral::GroupUpdate(g))
});
},
);
} else if let Some(group) = match alignment {

View File

@ -12,7 +12,7 @@ use common::{
Player, Pos, Stats,
},
lottery::Lottery,
msg::{PlayerListUpdate, ServerGeneral, ServerInGame},
msg::{PlayerListUpdate, ServerGeneral},
outcome::Outcome,
state::BlockChange,
sync::{Uid, UidAllocator, WorldSyncExt},
@ -44,7 +44,7 @@ pub fn handle_knockback(server: &Server, entity: EcsEntity, impulse: Vec3<f32>)
}
let mut clients = state.ecs().write_storage::<Client>();
if let Some(client) = clients.get_mut(entity) {
client.send_msg(ServerInGame::Knockback(impulse));
client.send_msg(ServerGeneral::Knockback(impulse));
}
}

View File

@ -5,7 +5,7 @@ use common::{
group::{self, Group, GroupManager, Invite, PendingInvites},
ChatType, GroupManip,
},
msg::{InviteAnswer, ServerInGame},
msg::{InviteAnswer, ServerGeneral},
sync,
sync::WorldSyncExt,
};
@ -155,7 +155,7 @@ pub fn handle_group(server: &mut Server, entity: specs::Entity, manip: GroupMani
(clients.get_mut(invitee), uids.get(entity).copied())
{
if send_invite() {
client.send_msg(ServerInGame::GroupInvite {
client.send_msg(ServerGeneral::GroupInvite {
inviter,
timeout: PRESENTED_INVITE_TIMEOUT_DUR,
});
@ -171,7 +171,7 @@ pub fn handle_group(server: &mut Server, entity: specs::Entity, manip: GroupMani
// Notify inviter that the invite is pending
if invite_sent {
if let Some(client) = clients.get_mut(entity) {
client.send_msg(ServerInGame::InvitePending(uid));
client.send_msg(ServerGeneral::InvitePending(uid));
}
}
},
@ -196,7 +196,7 @@ pub fn handle_group(server: &mut Server, entity: specs::Entity, manip: GroupMani
if let (Some(client), Some(target)) =
(clients.get_mut(inviter), uids.get(entity).copied())
{
client.send_msg(ServerInGame::InviteComplete {
client.send_msg(ServerGeneral::InviteComplete {
target,
answer: InviteAnswer::Accepted,
})
@ -217,7 +217,7 @@ pub fn handle_group(server: &mut Server, entity: specs::Entity, manip: GroupMani
.try_map(|e| uids.get(e).copied())
.map(|g| (g, c))
})
.map(|(g, c)| c.send_msg(ServerInGame::GroupUpdate(g)));
.map(|(g, c)| c.send_msg(ServerGeneral::GroupUpdate(g)));
},
);
}
@ -244,7 +244,7 @@ pub fn handle_group(server: &mut Server, entity: specs::Entity, manip: GroupMani
if let (Some(client), Some(target)) =
(clients.get_mut(inviter), uids.get(entity).copied())
{
client.send_msg(ServerInGame::InviteComplete {
client.send_msg(ServerGeneral::InviteComplete {
target,
answer: InviteAnswer::Declined,
})
@ -269,7 +269,7 @@ pub fn handle_group(server: &mut Server, entity: specs::Entity, manip: GroupMani
.try_map(|e| uids.get(e).copied())
.map(|g| (g, c))
})
.map(|(g, c)| c.send_msg(ServerInGame::GroupUpdate(g)));
.map(|(g, c)| c.send_msg(ServerGeneral::GroupUpdate(g)));
},
);
},
@ -336,7 +336,7 @@ pub fn handle_group(server: &mut Server, entity: specs::Entity, manip: GroupMani
.try_map(|e| uids.get(e).copied())
.map(|g| (g, c))
})
.map(|(g, c)| c.send_msg(ServerInGame::GroupUpdate(g)));
.map(|(g, c)| c.send_msg(ServerGeneral::GroupUpdate(g)));
},
);
@ -410,7 +410,7 @@ pub fn handle_group(server: &mut Server, entity: specs::Entity, manip: GroupMani
.try_map(|e| uids.get(e).copied())
.map(|g| (g, c))
})
.map(|(g, c)| c.send_msg(ServerInGame::GroupUpdate(g)));
.map(|(g, c)| c.send_msg(ServerGeneral::GroupUpdate(g)));
},
);
// Tell them they are the leader

View File

@ -5,7 +5,7 @@ use common::{
slot::{self, Slot},
Pos, MAX_PICKUP_RANGE_SQR,
},
msg::ServerInGame,
msg::ServerGeneral,
recipe::default_recipe_book,
sync::{Uid, WorldSyncExt},
vol::ReadVol,
@ -281,7 +281,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
.map(|g| (g, c))
})
.map(|(g, c)| {
c.send_msg(ServerInGame::GroupUpdate(g))
c.send_msg(ServerGeneral::GroupUpdate(g))
});
},
);

View File

@ -5,7 +5,7 @@ use crate::{
use common::{
comp,
comp::{group, Player},
msg::{PlayerListUpdate, ServerGeneral, ServerInGame},
msg::{PlayerListUpdate, ServerGeneral},
span,
sync::{Uid, UidAllocator},
};
@ -34,7 +34,7 @@ pub fn handle_exit_ingame(server: &mut Server, entity: EcsEntity) {
if let (Some(mut client), Some(uid), Some(player)) = (maybe_client, maybe_uid, maybe_player) {
// Tell client its request was successful
client.in_game = None;
client.send_msg(ServerInGame::ExitInGameSuccess);
client.send_msg(ServerGeneral::ExitInGameSuccess);
let entity_builder = state.ecs_mut().create_entity().with(client).with(player);

View File

@ -47,8 +47,7 @@ use common::{
comp::{self, ChatType},
event::{EventBus, ServerEvent},
msg::{
ClientType, DisconnectReason, ServerCharacterScreen, ServerGeneral, ServerInfo, ServerInit,
ServerMsg, WorldMapMsg,
ClientType, DisconnectReason, ServerGeneral, ServerInfo, ServerInit, ServerMsg, WorldMapMsg,
},
outcome::Outcome,
recipe::default_recipe_book,
@ -527,11 +526,11 @@ impl Server {
CharacterLoaderResponseType::CharacterList(result) => match result {
Ok(character_list_data) => self.notify_client(
query_result.entity,
ServerCharacterScreen::CharacterListUpdate(character_list_data),
ServerGeneral::CharacterListUpdate(character_list_data),
),
Err(error) => self.notify_client(
query_result.entity,
ServerCharacterScreen::CharacterActionError(error.to_string()),
ServerGeneral::CharacterActionError(error.to_string()),
),
},
CharacterLoaderResponseType::CharacterData(result) => {
@ -546,7 +545,7 @@ impl Server {
// to display
self.notify_client(
query_result.entity,
ServerCharacterScreen::CharacterDataLoadError(error.to_string()),
ServerGeneral::CharacterDataLoadError(error.to_string()),
);
// Clean up the entity data on the server

View File

@ -5,10 +5,7 @@ use common::{
character::CharacterId,
comp,
effect::Effect,
msg::{
CharacterInfo, ClientIngame, PlayerListUpdate, ServerCharacterScreen, ServerGeneral,
ServerInGame, ServerMsg,
},
msg::{CharacterInfo, ClientInGame, PlayerListUpdate, ServerGeneral, ServerMsg},
state::State,
sync::{Uid, UidAllocator, WorldSyncExt},
util::Dir,
@ -63,7 +60,7 @@ pub trait StateExt {
/// Iterates over registered clients and send each `ServerMsg`
fn send_chat(&self, msg: comp::UnresolvedChatMsg);
fn notify_registered_clients(&self, msg: ServerGeneral);
fn notify_in_game_clients(&self, msg: ServerInGame);
fn notify_in_game_clients(&self, msg: ServerGeneral);
/// Delete an entity, recording the deletion in [`DeletedEntities`]
fn delete_entity_recorded(
&mut self,
@ -220,8 +217,8 @@ impl StateExt for State {
// Tell the client its request was successful.
if let Some(client) = self.ecs().write_storage::<Client>().get_mut(entity) {
client.in_game = Some(ClientIngame::Character);
client.send_msg(ServerCharacterScreen::CharacterSuccess)
client.in_game = Some(ClientInGame::Character);
client.send_msg(ServerGeneral::CharacterSuccess)
}
}
@ -368,7 +365,7 @@ impl StateExt for State {
}
/// Sends the message to all clients playing in game
fn notify_in_game_clients(&self, msg: ServerInGame) {
fn notify_in_game_clients(&self, msg: ServerGeneral) {
let msg: ServerMsg = msg.into();
for client in (&mut self.ecs().write_storage::<Client>())
.join()
@ -401,7 +398,7 @@ impl StateExt for State {
.try_map(|e| uids.get(e).copied())
.map(|g| (g, c))
})
.map(|(g, c)| c.send_msg(ServerInGame::GroupUpdate(g)));
.map(|(g, c)| c.send_msg(ServerGeneral::GroupUpdate(g)));
},
);
}

View File

@ -8,7 +8,7 @@ use crate::{
};
use common::{
comp::{ForceUpdate, Inventory, InventoryUpdate, Last, Ori, Player, Pos, Vel},
msg::{ServerGeneral, ServerInGame},
msg::ServerGeneral,
outcome::Outcome,
region::{Event as RegionEvent, RegionMap},
span,
@ -320,7 +320,7 @@ impl<'a> System<'a> for Sys {
// Sync inventories
for (client, inventory, update) in (&mut clients, &inventories, &inventory_updates).join() {
client.send_msg(ServerInGame::InventoryUpdate(
client.send_msg(ServerGeneral::InventoryUpdate(
inventory.clone(),
update.event(),
));
@ -341,7 +341,7 @@ impl<'a> System<'a> for Sys {
.cloned()
.collect::<Vec<_>>();
if !outcomes.is_empty() {
client.send_msg(ServerInGame::Outcomes(outcomes));
client.send_msg(ServerGeneral::Outcomes(outcomes));
}
}
outcomes.clear();

View File

@ -2,7 +2,7 @@ use super::SysTimer;
use crate::client::Client;
use common::{
comp::group::{Invite, PendingInvites},
msg::{InviteAnswer, ServerInGame},
msg::{InviteAnswer, ServerGeneral},
span,
sync::Uid,
};
@ -54,7 +54,7 @@ impl<'a> System<'a> for Sys {
if let (Some(client), Some(target)) =
(clients.get_mut(*inviter), uids.get(invitee).copied())
{
client.send_msg(ServerInGame::InviteComplete {
client.send_msg(ServerGeneral::InviteComplete {
target,
answer: InviteAnswer::TimedOut,
})

View File

@ -15,10 +15,9 @@ use common::{
},
event::{EventBus, ServerEvent},
msg::{
validate_chat_msg, CharacterInfo, ChatMsgValidationError, ClientCharacterScreen,
ClientGeneral, ClientInGame, ClientIngame, ClientRegister, DisconnectReason, PingMsg,
PlayerInfo, PlayerListUpdate, RegisterError, ServerCharacterScreen, ServerGeneral,
ServerInGame, ServerRegisterAnswer, MAX_BYTES_CHAT_MSG,
validate_chat_msg, CharacterInfo, ChatMsgValidationError, ClientGeneral, ClientInGame,
ClientRegister, DisconnectReason, PingMsg, PlayerInfo, PlayerListUpdate, RegisterError,
ServerGeneral, ServerRegisterAnswer, MAX_BYTES_CHAT_MSG,
},
span,
state::{BlockChange, Time},
@ -79,6 +78,7 @@ impl Sys {
.inc();
server_emitter.emit(ServerEvent::ClientDisconnect(entity));
},
_ => unreachable!("not a client_general msg"),
}
Ok(())
}
@ -100,24 +100,24 @@ impl Sys {
players: &mut WriteStorage<'_, Player>,
controllers: &mut WriteStorage<'_, Controller>,
settings: &Read<'_, Settings>,
msg: ClientInGame,
msg: ClientGeneral,
) -> Result<(), crate::error::Error> {
if client.in_game.is_none() {
debug!(?entity, "client is not in_game, ignoring msg");
trace!(?msg, "ignored msg content");
if matches!(msg, ClientInGame::TerrainChunkRequest{ .. }) {
if matches!(msg, ClientGeneral::TerrainChunkRequest{ .. }) {
network_metrics.chunks_request_dropped.inc();
}
return Ok(());
}
match msg {
// Go back to registered state (char selection screen)
ClientInGame::ExitInGame => {
ClientGeneral::ExitInGame => {
client.in_game = None;
server_emitter.emit(ServerEvent::ExitIngame { entity });
client.send_msg(ServerInGame::ExitInGameSuccess);
client.send_msg(ServerGeneral::ExitInGameSuccess);
},
ClientInGame::SetViewDistance(view_distance) => {
ClientGeneral::SetViewDistance(view_distance) => {
players.get_mut(entity).map(|player| {
player.view_distance = Some(
settings
@ -133,20 +133,20 @@ impl Sys {
.map(|max| view_distance > max)
.unwrap_or(false)
{
client.send_msg(ServerInGame::SetViewDistance(
client.send_msg(ServerGeneral::SetViewDistance(
settings.max_view_distance.unwrap_or(0),
));
}
},
ClientInGame::ControllerInputs(inputs) => {
if let Some(ClientIngame::Character) = client.in_game {
ClientGeneral::ControllerInputs(inputs) => {
if let Some(ClientInGame::Character) = client.in_game {
if let Some(controller) = controllers.get_mut(entity) {
controller.inputs.update_with_new(inputs);
}
}
},
ClientInGame::ControlEvent(event) => {
if let Some(ClientIngame::Character) = client.in_game {
ClientGeneral::ControlEvent(event) => {
if let Some(ClientInGame::Character) = client.in_game {
// Skip respawn if client entity is alive
if let ControlEvent::Respawn = event {
if stats.get(entity).map_or(true, |s| !s.is_dead) {
@ -159,15 +159,15 @@ impl Sys {
}
}
},
ClientInGame::ControlAction(event) => {
if let Some(ClientIngame::Character) = client.in_game {
ClientGeneral::ControlAction(event) => {
if let Some(ClientInGame::Character) = client.in_game {
if let Some(controller) = controllers.get_mut(entity) {
controller.actions.push(event);
}
}
},
ClientInGame::PlayerPhysics { pos, vel, ori } => {
if let Some(ClientIngame::Character) = client.in_game {
ClientGeneral::PlayerPhysics { pos, vel, ori } => {
if let Some(ClientInGame::Character) = client.in_game {
if force_updates.get(entity).is_none()
&& stats.get(entity).map_or(true, |s| !s.is_dead)
{
@ -177,17 +177,17 @@ impl Sys {
}
}
},
ClientInGame::BreakBlock(pos) => {
ClientGeneral::BreakBlock(pos) => {
if let Some(block) = can_build.get(entity).and_then(|_| terrain.get(pos).ok()) {
block_changes.set(pos, block.into_vacant());
}
},
ClientInGame::PlaceBlock(pos, block) => {
ClientGeneral::PlaceBlock(pos, block) => {
if can_build.get(entity).is_some() {
block_changes.try_set(pos, block);
}
},
ClientInGame::TerrainChunkRequest { key } => {
ClientGeneral::TerrainChunkRequest { key } => {
let in_vd = if let (Some(view_distance), Some(pos)) = (
players.get(entity).and_then(|p| p.view_distance),
positions.get(entity),
@ -203,7 +203,7 @@ impl Sys {
match terrain.get_key(key) {
Some(chunk) => {
network_metrics.chunks_served_from_memory.inc();
client.send_msg(ServerInGame::TerrainChunkUpdate {
client.send_msg(ServerGeneral::TerrainChunkUpdate {
key,
chunk: Ok(Box::new(chunk.clone())),
})
@ -217,21 +217,22 @@ impl Sys {
network_metrics.chunks_request_dropped.inc();
}
},
ClientInGame::UnlockSkill(skill) => {
ClientGeneral::UnlockSkill(skill) => {
stats
.get_mut(entity)
.map(|s| s.skill_set.unlock_skill(skill));
},
ClientInGame::RefundSkill(skill) => {
ClientGeneral::RefundSkill(skill) => {
stats
.get_mut(entity)
.map(|s| s.skill_set.refund_skill(skill));
},
ClientInGame::UnlockSkillGroup(skill_group_type) => {
ClientGeneral::UnlockSkillGroup(skill_group_type) => {
stats
.get_mut(entity)
.map(|s| s.skill_set.unlock_skill_group(skill_group_type));
},
_ => unreachable!("not a client_in_game msg"),
}
Ok(())
}
@ -247,17 +248,15 @@ impl Sys {
players: &mut WriteStorage<'_, Player>,
editable_settings: &ReadExpect<'_, EditableSettings>,
alias_validator: &ReadExpect<'_, AliasValidator>,
msg: ClientCharacterScreen,
msg: ClientGeneral,
) -> Result<(), crate::error::Error> {
match msg {
// Request spectator state
ClientCharacterScreen::Spectate if client.registered => {
client.in_game = Some(ClientIngame::Spectator)
ClientGeneral::Spectate if client.registered => {
client.in_game = Some(ClientInGame::Spectator)
},
ClientCharacterScreen::Spectate => {
debug!("dropped Spectate msg from unregistered client")
},
ClientCharacterScreen::Character(character_id)
ClientGeneral::Spectate => debug!("dropped Spectate msg from unregistered client"),
ClientGeneral::Character(character_id)
if client.registered && client.in_game.is_none() =>
{
if let Some(player) = players.get(entity) {
@ -296,27 +295,25 @@ impl Sys {
}
}
} else {
client.send_msg(ServerCharacterScreen::CharacterDataLoadError(String::from(
client.send_msg(ServerGeneral::CharacterDataLoadError(String::from(
"Failed to fetch player entity",
)))
}
}
ClientCharacterScreen::Character(_) => {
ClientGeneral::Character(_) => {
let registered = client.registered;
let in_game = client.in_game;
debug!(?registered, ?in_game, "dropped Character msg from client");
},
ClientCharacterScreen::RequestCharacterList => {
ClientGeneral::RequestCharacterList => {
if let Some(player) = players.get(entity) {
character_loader.load_character_list(entity, player.uuid().to_string())
}
},
ClientCharacterScreen::CreateCharacter { alias, tool, body } => {
ClientGeneral::CreateCharacter { alias, tool, body } => {
if let Err(error) = alias_validator.validate(&alias) {
debug!(?error, ?alias, "denied alias as it contained a banned word");
client.send_msg(ServerCharacterScreen::CharacterActionError(
error.to_string(),
));
client.send_msg(ServerGeneral::CharacterActionError(error.to_string()));
} else if let Some(player) = players.get(entity) {
character_creator::create_character(
entity,
@ -328,7 +325,7 @@ impl Sys {
);
}
},
ClientCharacterScreen::DeleteCharacter(character_id) => {
ClientGeneral::DeleteCharacter(character_id) => {
if let Some(player) = players.get(entity) {
character_loader.delete_character(
entity,
@ -337,6 +334,7 @@ impl Sys {
);
}
},
_ => unreachable!("not a client_character_screen msg"),
}
Ok(())
}
@ -379,7 +377,7 @@ impl Sys {
};
const INITIAL_VD: Option<u32> = Some(5); //will be changed after login
let player = Player::new(username.clone(), None, INITIAL_VD, uuid);
let player = Player::new(username, None, INITIAL_VD, uuid);
let is_admin = editable_settings.admins.contains(&uuid);
if !player.is_valid() {

View File

@ -4,7 +4,7 @@ use common::{
comp::{self, bird_medium, Alignment, Player, Pos},
event::{EventBus, ServerEvent},
generation::get_npc_name,
msg::ServerInGame,
msg::ServerGeneral,
npc::NPC_NAMES,
span,
state::TerrainChanges,
@ -63,7 +63,7 @@ impl<'a> System<'a> for Sys {
Ok((chunk, supplement)) => (chunk, supplement),
Err(Some(entity)) => {
if let Some(client) = clients.get_mut(entity) {
client.send_msg(ServerInGame::TerrainChunkUpdate {
client.send_msg(ServerGeneral::TerrainChunkUpdate {
key,
chunk: Err(()),
});
@ -90,7 +90,7 @@ impl<'a> System<'a> for Sys {
.magnitude_squared();
if adjusted_dist_sqr <= view_distance.pow(2) {
client.send_msg(ServerInGame::TerrainChunkUpdate {
client.send_msg(ServerGeneral::TerrainChunkUpdate {
key,
chunk: Ok(Box::new(chunk.clone())),
});

View File

@ -2,7 +2,7 @@ use super::SysTimer;
use crate::client::Client;
use common::{
comp::{Player, Pos},
msg::ServerInGame,
msg::ServerGeneral,
span,
state::TerrainChanges,
terrain::TerrainGrid,
@ -38,7 +38,7 @@ impl<'a> System<'a> for Sys {
.map(|vd| super::terrain::chunk_in_vd(pos.0, *chunk_key, &terrain, vd))
.unwrap_or(false)
{
client.send_msg(ServerInGame::TerrainChunkUpdate {
client.send_msg(ServerGeneral::TerrainChunkUpdate {
key: *chunk_key,
chunk: Ok(Box::new(match terrain.get_key(*chunk_key) {
Some(chunk) => chunk.clone(),
@ -51,7 +51,7 @@ impl<'a> System<'a> for Sys {
// TODO: Don't send all changed blocks to all clients
// Sync changed blocks
let msg = ServerInGame::TerrainBlockUpdates(terrain_changes.modified_blocks.clone());
let msg = ServerGeneral::TerrainBlockUpdates(terrain_changes.modified_blocks.clone());
for (player, client) in (&players, &mut clients).join() {
if player.view_distance.is_some() {
client.send_msg(msg.clone());