mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
create a ServerMsg and ClientMsg enum and verify the state when in debug mode to benefit from the transition
This commit is contained in:
parent
e8452fafc6
commit
ff374eab59
@ -25,11 +25,11 @@ use common::{
|
||||
},
|
||||
event::{EventBus, LocalEvent},
|
||||
msg::{
|
||||
validate_chat_msg, ChatMsgValidationError, ClientCharacterScreenMsg, ClientGeneralMsg,
|
||||
ClientInGameMsg, ClientIngame, ClientRegisterMsg, ClientType, DisconnectReason,
|
||||
validate_chat_msg, ChatMsgValidationError, ClientCharacterScreen, ClientGeneral,
|
||||
ClientInGame, ClientIngame, ClientMsg, ClientRegister, ClientType, DisconnectReason,
|
||||
InviteAnswer, Notification, PingMsg, PlayerInfo, PlayerListUpdate, RegisterError,
|
||||
ServerCharacterScreenMsg, ServerGeneralMsg, ServerInGameMsg, ServerInfo, ServerInitMsg,
|
||||
ServerRegisterAnswerMsg, MAX_BYTES_CHAT_MSG,
|
||||
ServerCharacterScreen, ServerGeneral, ServerInGame, ServerInfo, ServerInit,
|
||||
ServerRegisterAnswer, MAX_BYTES_CHAT_MSG,
|
||||
},
|
||||
outcome::Outcome,
|
||||
recipe::RecipeBook,
|
||||
@ -71,7 +71,7 @@ pub enum Event {
|
||||
|
||||
pub struct Client {
|
||||
registered: bool,
|
||||
client_ingame: Option<ClientIngame>,
|
||||
in_game: Option<ClientIngame>,
|
||||
thread_pool: ThreadPool,
|
||||
pub server_info: ServerInfo,
|
||||
/// Just the "base" layer for LOD; currently includes colors and nothing
|
||||
@ -193,7 +193,7 @@ impl Client {
|
||||
max_group_size,
|
||||
client_timeout,
|
||||
) = match block_on(register_stream.recv())? {
|
||||
ServerInitMsg::GameSync {
|
||||
ServerInit::GameSync {
|
||||
entity_package,
|
||||
time_of_day,
|
||||
max_group_size,
|
||||
@ -362,7 +362,7 @@ impl Client {
|
||||
client_timeout,
|
||||
))
|
||||
},
|
||||
ServerInitMsg::TooManyPlayers => Err(Error::TooManyPlayers),
|
||||
ServerInit::TooManyPlayers => Err(Error::TooManyPlayers),
|
||||
}?;
|
||||
ping_stream.send(PingMsg::Ping)?;
|
||||
|
||||
@ -376,7 +376,7 @@ impl Client {
|
||||
|
||||
Ok(Self {
|
||||
registered: false,
|
||||
client_ingame: None,
|
||||
in_game: None,
|
||||
thread_pool,
|
||||
server_info,
|
||||
world_map,
|
||||
@ -444,10 +444,9 @@ impl Client {
|
||||
}
|
||||
).unwrap_or(Ok(username))?;
|
||||
|
||||
self.register_stream
|
||||
.send(ClientRegisterMsg { token_or_username })?;
|
||||
self.send_msg_err(ClientRegister { token_or_username })?;
|
||||
|
||||
match block_on(self.register_stream.recv::<ServerRegisterAnswerMsg>())? {
|
||||
match block_on(self.register_stream.recv::<ServerRegisterAnswer>())? {
|
||||
Err(RegisterError::AlreadyLoggedIn) => Err(Error::AlreadyLoggedIn),
|
||||
Err(RegisterError::AuthError(err)) => Err(Error::AuthErr(err)),
|
||||
Err(RegisterError::InvalidCharacter) => Err(Error::InvalidCharacter),
|
||||
@ -460,14 +459,69 @@ impl Client {
|
||||
}
|
||||
}
|
||||
|
||||
fn send_msg_err<S>(&mut self, msg: S) -> Result<(), network::StreamError>
|
||||
where
|
||||
S: Into<ClientMsg>,
|
||||
{
|
||||
let msg: ClientMsg = msg.into();
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
//There assertions veriy that the state is correct when a msg is send!
|
||||
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(_) => (),
|
||||
}
|
||||
}
|
||||
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::Ping(msg) => self.ping_stream.send(msg),
|
||||
}
|
||||
}
|
||||
|
||||
fn send_msg<S>(&mut self, msg: S)
|
||||
where
|
||||
S: Into<ClientMsg>,
|
||||
{
|
||||
let res = self.send_msg_err(msg);
|
||||
if let Err(e) = res {
|
||||
warn!(
|
||||
?e,
|
||||
"connection to server no longer possible, couldn't send msg"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Request a state transition to `ClientState::Character`.
|
||||
pub fn request_character(&mut self, character_id: CharacterId) {
|
||||
self.character_screen_stream
|
||||
.send(ClientCharacterScreenMsg::Character(character_id))
|
||||
.unwrap();
|
||||
self.send_msg(ClientCharacterScreen::Character(character_id));
|
||||
|
||||
//Assume we are in_game unless server tells us otherwise
|
||||
self.client_ingame = Some(ClientIngame::Character);
|
||||
self.in_game = Some(ClientIngame::Character);
|
||||
|
||||
self.active_character_id = Some(character_id);
|
||||
}
|
||||
@ -475,87 +529,59 @@ impl Client {
|
||||
/// Load the current players character list
|
||||
pub fn load_character_list(&mut self) {
|
||||
self.character_list.loading = true;
|
||||
self.character_screen_stream
|
||||
.send(ClientCharacterScreenMsg::RequestCharacterList)
|
||||
.unwrap();
|
||||
self.send_msg(ClientCharacterScreen::RequestCharacterList);
|
||||
}
|
||||
|
||||
/// New character creation
|
||||
pub fn create_character(&mut self, alias: String, tool: Option<String>, body: comp::Body) {
|
||||
self.character_list.loading = true;
|
||||
self.character_screen_stream
|
||||
.send(ClientCharacterScreenMsg::CreateCharacter { alias, tool, body })
|
||||
.unwrap();
|
||||
self.send_msg(ClientCharacterScreen::CreateCharacter { alias, tool, body });
|
||||
}
|
||||
|
||||
/// Character deletion
|
||||
pub fn delete_character(&mut self, character_id: CharacterId) {
|
||||
self.character_list.loading = true;
|
||||
self.character_screen_stream
|
||||
.send(ClientCharacterScreenMsg::DeleteCharacter(character_id))
|
||||
.unwrap();
|
||||
self.send_msg(ClientCharacterScreen::DeleteCharacter(character_id));
|
||||
}
|
||||
|
||||
/// Send disconnect message to the server
|
||||
pub fn request_logout(&mut self) {
|
||||
debug!("Requesting logout from server");
|
||||
if let Err(e) = self.general_stream.send(ClientGeneralMsg::Disconnect) {
|
||||
error!(
|
||||
?e,
|
||||
"Couldn't send disconnect package to server, did server close already?"
|
||||
);
|
||||
}
|
||||
self.send_msg(ClientGeneral::Disconnect);
|
||||
}
|
||||
|
||||
/// Request a state transition to `ClientState::Registered` from an ingame
|
||||
/// state.
|
||||
pub fn request_remove_character(&mut self) {
|
||||
self.in_game_stream
|
||||
.send(ClientInGameMsg::ExitInGame)
|
||||
.unwrap();
|
||||
}
|
||||
pub fn request_remove_character(&mut self) { self.send_msg(ClientInGame::ExitInGame); }
|
||||
|
||||
pub fn set_view_distance(&mut self, view_distance: u32) {
|
||||
self.view_distance = Some(view_distance.max(1).min(65));
|
||||
self.in_game_stream
|
||||
.send(ClientInGameMsg::SetViewDistance(
|
||||
self.view_distance.unwrap(),
|
||||
))
|
||||
.unwrap();
|
||||
// Can't fail
|
||||
self.send_msg(ClientInGame::SetViewDistance(self.view_distance.unwrap()));
|
||||
}
|
||||
|
||||
pub fn use_slot(&mut self, slot: comp::slot::Slot) {
|
||||
self.in_game_stream
|
||||
.send(ClientInGameMsg::ControlEvent(ControlEvent::InventoryManip(
|
||||
InventoryManip::Use(slot),
|
||||
)))
|
||||
.unwrap();
|
||||
self.send_msg(ClientInGame::ControlEvent(ControlEvent::InventoryManip(
|
||||
InventoryManip::Use(slot),
|
||||
)));
|
||||
}
|
||||
|
||||
pub fn swap_slots(&mut self, a: comp::slot::Slot, b: comp::slot::Slot) {
|
||||
self.in_game_stream
|
||||
.send(ClientInGameMsg::ControlEvent(ControlEvent::InventoryManip(
|
||||
InventoryManip::Swap(a, b),
|
||||
)))
|
||||
.unwrap();
|
||||
self.send_msg(ClientInGame::ControlEvent(ControlEvent::InventoryManip(
|
||||
InventoryManip::Swap(a, b),
|
||||
)));
|
||||
}
|
||||
|
||||
pub fn drop_slot(&mut self, slot: comp::slot::Slot) {
|
||||
self.in_game_stream
|
||||
.send(ClientInGameMsg::ControlEvent(ControlEvent::InventoryManip(
|
||||
InventoryManip::Drop(slot),
|
||||
)))
|
||||
.unwrap();
|
||||
self.send_msg(ClientInGame::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.in_game_stream
|
||||
.send(ClientInGameMsg::ControlEvent(ControlEvent::InventoryManip(
|
||||
InventoryManip::Pickup(uid),
|
||||
)))
|
||||
.unwrap();
|
||||
self.send_msg(ClientInGame::ControlEvent(ControlEvent::InventoryManip(
|
||||
InventoryManip::Pickup(uid),
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -573,11 +599,9 @@ impl Client {
|
||||
|
||||
pub fn craft_recipe(&mut self, recipe: &str) -> bool {
|
||||
if self.can_craft_recipe(recipe) {
|
||||
self.in_game_stream
|
||||
.send(ClientInGameMsg::ControlEvent(ControlEvent::InventoryManip(
|
||||
InventoryManip::CraftRecipe(recipe.to_string()),
|
||||
)))
|
||||
.unwrap();
|
||||
self.send_msg(ClientInGame::ControlEvent(ControlEvent::InventoryManip(
|
||||
InventoryManip::CraftRecipe(recipe.to_string()),
|
||||
)));
|
||||
true
|
||||
} else {
|
||||
false
|
||||
@ -594,15 +618,11 @@ impl Client {
|
||||
}
|
||||
|
||||
pub fn enable_lantern(&mut self) {
|
||||
self.singleton_stream
|
||||
.send(ClientInGameMsg::ControlEvent(ControlEvent::EnableLantern))
|
||||
.unwrap();
|
||||
self.send_msg(ClientInGame::ControlEvent(ControlEvent::EnableLantern));
|
||||
}
|
||||
|
||||
pub fn disable_lantern(&mut self) {
|
||||
self.singleton_stream
|
||||
.send(ClientInGameMsg::ControlEvent(ControlEvent::DisableLantern))
|
||||
.unwrap();
|
||||
self.send_msg(ClientInGame::ControlEvent(ControlEvent::DisableLantern));
|
||||
}
|
||||
|
||||
pub fn max_group_size(&self) -> u32 { self.max_group_size }
|
||||
@ -620,55 +640,43 @@ impl Client {
|
||||
pub fn pending_invites(&self) -> &HashSet<Uid> { &self.pending_invites }
|
||||
|
||||
pub fn send_group_invite(&mut self, invitee: Uid) {
|
||||
self.in_game_stream
|
||||
.send(ClientInGameMsg::ControlEvent(ControlEvent::GroupManip(
|
||||
GroupManip::Invite(invitee),
|
||||
)))
|
||||
.unwrap()
|
||||
self.send_msg(ClientInGame::ControlEvent(ControlEvent::GroupManip(
|
||||
GroupManip::Invite(invitee),
|
||||
)))
|
||||
}
|
||||
|
||||
pub fn accept_group_invite(&mut self) {
|
||||
// Clear invite
|
||||
self.group_invite.take();
|
||||
self.in_game_stream
|
||||
.send(ClientInGameMsg::ControlEvent(ControlEvent::GroupManip(
|
||||
GroupManip::Accept,
|
||||
)))
|
||||
.unwrap();
|
||||
self.send_msg(ClientInGame::ControlEvent(ControlEvent::GroupManip(
|
||||
GroupManip::Accept,
|
||||
)));
|
||||
}
|
||||
|
||||
pub fn decline_group_invite(&mut self) {
|
||||
// Clear invite
|
||||
self.group_invite.take();
|
||||
self.in_game_stream
|
||||
.send(ClientInGameMsg::ControlEvent(ControlEvent::GroupManip(
|
||||
GroupManip::Decline,
|
||||
)))
|
||||
.unwrap();
|
||||
self.send_msg(ClientInGame::ControlEvent(ControlEvent::GroupManip(
|
||||
GroupManip::Decline,
|
||||
)));
|
||||
}
|
||||
|
||||
pub fn leave_group(&mut self) {
|
||||
self.in_game_stream
|
||||
.send(ClientInGameMsg::ControlEvent(ControlEvent::GroupManip(
|
||||
GroupManip::Leave,
|
||||
)))
|
||||
.unwrap();
|
||||
self.send_msg(ClientInGame::ControlEvent(ControlEvent::GroupManip(
|
||||
GroupManip::Leave,
|
||||
)));
|
||||
}
|
||||
|
||||
pub fn kick_from_group(&mut self, uid: Uid) {
|
||||
self.in_game_stream
|
||||
.send(ClientInGameMsg::ControlEvent(ControlEvent::GroupManip(
|
||||
GroupManip::Kick(uid),
|
||||
)))
|
||||
.unwrap();
|
||||
self.send_msg(ClientInGame::ControlEvent(ControlEvent::GroupManip(
|
||||
GroupManip::Kick(uid),
|
||||
)));
|
||||
}
|
||||
|
||||
pub fn assign_group_leader(&mut self, uid: Uid) {
|
||||
self.in_game_stream
|
||||
.send(ClientInGameMsg::ControlEvent(ControlEvent::GroupManip(
|
||||
GroupManip::AssignLeader(uid),
|
||||
)))
|
||||
.unwrap();
|
||||
self.send_msg(ClientInGame::ControlEvent(ControlEvent::GroupManip(
|
||||
GroupManip::AssignLeader(uid),
|
||||
)));
|
||||
}
|
||||
|
||||
pub fn is_mounted(&self) -> bool {
|
||||
@ -689,17 +697,11 @@ impl Client {
|
||||
|
||||
pub fn mount(&mut self, entity: EcsEntity) {
|
||||
if let Some(uid) = self.state.read_component_copied(entity) {
|
||||
self.in_game_stream
|
||||
.send(ClientInGameMsg::ControlEvent(ControlEvent::Mount(uid)))
|
||||
.unwrap();
|
||||
self.send_msg(ClientInGame::ControlEvent(ControlEvent::Mount(uid)));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unmount(&mut self) {
|
||||
self.in_game_stream
|
||||
.send(ClientInGameMsg::ControlEvent(ControlEvent::Unmount))
|
||||
.unwrap();
|
||||
}
|
||||
pub fn unmount(&mut self) { self.send_msg(ClientInGame::ControlEvent(ControlEvent::Unmount)); }
|
||||
|
||||
pub fn respawn(&mut self) {
|
||||
if self
|
||||
@ -709,9 +711,7 @@ impl Client {
|
||||
.get(self.entity)
|
||||
.map_or(false, |s| s.is_dead)
|
||||
{
|
||||
self.in_game_stream
|
||||
.send(ClientInGameMsg::ControlEvent(ControlEvent::Respawn))
|
||||
.unwrap();
|
||||
self.send_msg(ClientInGame::ControlEvent(ControlEvent::Respawn));
|
||||
}
|
||||
}
|
||||
|
||||
@ -808,9 +808,7 @@ impl Client {
|
||||
{
|
||||
controller.actions.push(control_action);
|
||||
}
|
||||
self.in_game_stream
|
||||
.send(ClientInGameMsg::ControlAction(control_action))
|
||||
.unwrap();
|
||||
self.send_msg(ClientInGame::ControlAction(control_action));
|
||||
}
|
||||
|
||||
pub fn view_distance(&self) -> Option<u32> { self.view_distance }
|
||||
@ -839,10 +837,7 @@ impl Client {
|
||||
/// Send a chat message to the server.
|
||||
pub fn send_chat(&mut self, message: String) {
|
||||
match validate_chat_msg(&message) {
|
||||
Ok(()) => self
|
||||
.general_stream
|
||||
.send(ClientGeneralMsg::ChatMsg(message))
|
||||
.unwrap(),
|
||||
Ok(()) => self.send_msg(ClientGeneral::ChatMsg(message)),
|
||||
Err(ChatMsgValidationError::TooLong) => tracing::warn!(
|
||||
"Attempted to send a message that's too long (Over {} bytes)",
|
||||
MAX_BYTES_CHAT_MSG
|
||||
@ -857,23 +852,15 @@ impl Client {
|
||||
}
|
||||
|
||||
pub fn place_block(&mut self, pos: Vec3<i32>, block: Block) {
|
||||
self.in_game_stream
|
||||
.send(ClientInGameMsg::PlaceBlock(pos, block))
|
||||
.unwrap();
|
||||
self.send_msg(ClientInGame::PlaceBlock(pos, block));
|
||||
}
|
||||
|
||||
pub fn remove_block(&mut self, pos: Vec3<i32>) {
|
||||
self.in_game_stream
|
||||
.send(ClientInGameMsg::BreakBlock(pos))
|
||||
.unwrap();
|
||||
}
|
||||
pub fn remove_block(&mut self, pos: Vec3<i32>) { self.send_msg(ClientInGame::BreakBlock(pos)); }
|
||||
|
||||
pub fn collect_block(&mut self, pos: Vec3<i32>) {
|
||||
self.in_game_stream
|
||||
.send(ClientInGameMsg::ControlEvent(ControlEvent::InventoryManip(
|
||||
InventoryManip::Collect(pos),
|
||||
)))
|
||||
.unwrap();
|
||||
self.send_msg(ClientInGame::ControlEvent(ControlEvent::InventoryManip(
|
||||
InventoryManip::Collect(pos),
|
||||
)));
|
||||
}
|
||||
|
||||
/// Execute a single client tick, handle input and update the game state by
|
||||
@ -905,7 +892,7 @@ impl Client {
|
||||
|
||||
// 1) Handle input from frontend.
|
||||
// Pass character actions from frontend input to the player's entity.
|
||||
if self.client_ingame.is_some() {
|
||||
if self.in_game.is_some() {
|
||||
if let Err(e) = self
|
||||
.state
|
||||
.ecs()
|
||||
@ -928,8 +915,7 @@ impl Client {
|
||||
"Couldn't access controller component on client entity"
|
||||
);
|
||||
}
|
||||
self.in_game_stream
|
||||
.send(ClientInGameMsg::ControllerInputs(inputs))?;
|
||||
self.send_msg_err(ClientInGame::ControllerInputs(inputs))?;
|
||||
}
|
||||
|
||||
// 2) Build up a list of events for this frame, to be passed to the frontend.
|
||||
@ -1033,8 +1019,9 @@ 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.in_game_stream
|
||||
.send(ClientInGameMsg::TerrainChunkRequest { key: *key })?;
|
||||
self.send_msg_err(ClientInGame::TerrainChunkRequest {
|
||||
key: *key,
|
||||
})?;
|
||||
self.pending_chunks.insert(*key, Instant::now());
|
||||
} else {
|
||||
skip_mode = true;
|
||||
@ -1066,19 +1053,19 @@ impl Client {
|
||||
|
||||
// Send a ping to the server once every second
|
||||
if self.state.get_time() - self.last_server_ping > 1. {
|
||||
self.ping_stream.send(PingMsg::Ping)?;
|
||||
self.send_msg_err(PingMsg::Ping)?;
|
||||
self.last_server_ping = self.state.get_time();
|
||||
}
|
||||
|
||||
// 6) Update the server about the player's physics attributes.
|
||||
if self.client_ingame.is_some() {
|
||||
if self.in_game.is_some() {
|
||||
if let (Some(pos), Some(vel), Some(ori)) = (
|
||||
self.state.read_storage().get(self.entity).cloned(),
|
||||
self.state.read_storage().get(self.entity).cloned(),
|
||||
self.state.read_storage().get(self.entity).cloned(),
|
||||
) {
|
||||
self.in_game_stream
|
||||
.send(ClientInGameMsg::PlayerPhysics { pos, vel, ori })?;
|
||||
.send(ClientInGame::PlayerPhysics { pos, vel, ori })?;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1108,26 +1095,26 @@ impl Client {
|
||||
fn handle_server_msg(
|
||||
&mut self,
|
||||
frontend_events: &mut Vec<Event>,
|
||||
msg: ServerGeneralMsg,
|
||||
msg: ServerGeneral,
|
||||
) -> Result<(), Error> {
|
||||
match msg {
|
||||
ServerGeneralMsg::Disconnect(reason) => match reason {
|
||||
ServerGeneral::Disconnect(reason) => match reason {
|
||||
DisconnectReason::Shutdown => return Err(Error::ServerShutdown),
|
||||
DisconnectReason::Requested => {
|
||||
debug!("finally sending ClientMsg::Terminate");
|
||||
frontend_events.push(Event::Disconnect);
|
||||
self.general_stream.send(ClientGeneralMsg::Terminate)?;
|
||||
self.send_msg_err(ClientGeneral::Terminate)?;
|
||||
},
|
||||
DisconnectReason::Kicked(reason) => {
|
||||
debug!("sending ClientMsg::Terminate because we got kicked");
|
||||
frontend_events.push(Event::Kicked(reason));
|
||||
self.general_stream.send(ClientGeneralMsg::Terminate)?;
|
||||
self.send_msg_err(ClientGeneral::Terminate)?;
|
||||
},
|
||||
},
|
||||
ServerGeneralMsg::PlayerListUpdate(PlayerListUpdate::Init(list)) => {
|
||||
ServerGeneral::PlayerListUpdate(PlayerListUpdate::Init(list)) => {
|
||||
self.player_list = list
|
||||
},
|
||||
ServerGeneralMsg::PlayerListUpdate(PlayerListUpdate::Add(uid, player_info)) => {
|
||||
ServerGeneral::PlayerListUpdate(PlayerListUpdate::Add(uid, player_info)) => {
|
||||
if let Some(old_player_info) = self.player_list.insert(uid, player_info.clone()) {
|
||||
warn!(
|
||||
"Received msg to insert {} with uid {} into the player list but there was \
|
||||
@ -1136,7 +1123,7 @@ impl Client {
|
||||
);
|
||||
}
|
||||
},
|
||||
ServerGeneralMsg::PlayerListUpdate(PlayerListUpdate::Admin(uid, admin)) => {
|
||||
ServerGeneral::PlayerListUpdate(PlayerListUpdate::Admin(uid, admin)) => {
|
||||
if let Some(player_info) = self.player_list.get_mut(&uid) {
|
||||
player_info.is_admin = admin;
|
||||
} else {
|
||||
@ -1147,7 +1134,7 @@ impl Client {
|
||||
);
|
||||
}
|
||||
},
|
||||
ServerGeneralMsg::PlayerListUpdate(PlayerListUpdate::SelectedCharacter(
|
||||
ServerGeneral::PlayerListUpdate(PlayerListUpdate::SelectedCharacter(
|
||||
uid,
|
||||
char_info,
|
||||
)) => {
|
||||
@ -1161,7 +1148,7 @@ impl Client {
|
||||
);
|
||||
}
|
||||
},
|
||||
ServerGeneralMsg::PlayerListUpdate(PlayerListUpdate::LevelChange(uid, next_level)) => {
|
||||
ServerGeneral::PlayerListUpdate(PlayerListUpdate::LevelChange(uid, next_level)) => {
|
||||
if let Some(player_info) = self.player_list.get_mut(&uid) {
|
||||
player_info.character = match &player_info.character {
|
||||
Some(character) => Some(common::msg::CharacterInfo {
|
||||
@ -1180,7 +1167,7 @@ impl Client {
|
||||
};
|
||||
}
|
||||
},
|
||||
ServerGeneralMsg::PlayerListUpdate(PlayerListUpdate::Remove(uid)) => {
|
||||
ServerGeneral::PlayerListUpdate(PlayerListUpdate::Remove(uid)) => {
|
||||
// Instead of removing players, mark them as offline because we need to
|
||||
// remember the names of disconnected players in chat.
|
||||
//
|
||||
@ -1205,7 +1192,7 @@ impl Client {
|
||||
);
|
||||
}
|
||||
},
|
||||
ServerGeneralMsg::PlayerListUpdate(PlayerListUpdate::Alias(uid, new_name)) => {
|
||||
ServerGeneral::PlayerListUpdate(PlayerListUpdate::Alias(uid, new_name)) => {
|
||||
if let Some(player_info) = self.player_list.get_mut(&uid) {
|
||||
player_info.player_alias = new_name;
|
||||
} else {
|
||||
@ -1216,38 +1203,38 @@ impl Client {
|
||||
);
|
||||
}
|
||||
},
|
||||
ServerGeneralMsg::ChatMsg(m) => frontend_events.push(Event::Chat(m)),
|
||||
ServerGeneralMsg::SetPlayerEntity(uid) => {
|
||||
ServerGeneral::ChatMsg(m) => frontend_events.push(Event::Chat(m)),
|
||||
ServerGeneral::SetPlayerEntity(uid) => {
|
||||
if let Some(entity) = self.state.ecs().entity_from_uid(uid.0) {
|
||||
self.entity = entity;
|
||||
} else {
|
||||
return Err(Error::Other("Failed to find entity from uid.".to_owned()));
|
||||
}
|
||||
},
|
||||
ServerGeneralMsg::TimeOfDay(time_of_day) => {
|
||||
ServerGeneral::TimeOfDay(time_of_day) => {
|
||||
*self.state.ecs_mut().write_resource() = time_of_day;
|
||||
},
|
||||
ServerGeneralMsg::EntitySync(entity_sync_package) => {
|
||||
ServerGeneral::EntitySync(entity_sync_package) => {
|
||||
self.state
|
||||
.ecs_mut()
|
||||
.apply_entity_sync_package(entity_sync_package);
|
||||
},
|
||||
ServerGeneralMsg::CompSync(comp_sync_package) => {
|
||||
ServerGeneral::CompSync(comp_sync_package) => {
|
||||
self.state
|
||||
.ecs_mut()
|
||||
.apply_comp_sync_package(comp_sync_package);
|
||||
},
|
||||
ServerGeneralMsg::CreateEntity(entity_package) => {
|
||||
ServerGeneral::CreateEntity(entity_package) => {
|
||||
self.state.ecs_mut().apply_entity_package(entity_package);
|
||||
},
|
||||
ServerGeneralMsg::DeleteEntity(entity) => {
|
||||
ServerGeneral::DeleteEntity(entity) => {
|
||||
if self.uid() != Some(entity) {
|
||||
self.state
|
||||
.ecs_mut()
|
||||
.delete_entity_and_clear_from_uid_allocator(entity.0);
|
||||
}
|
||||
},
|
||||
ServerGeneralMsg::Notification(n) => {
|
||||
ServerGeneral::Notification(n) => {
|
||||
frontend_events.push(Event::Notification(n));
|
||||
},
|
||||
}
|
||||
@ -1257,10 +1244,10 @@ impl Client {
|
||||
fn handle_server_in_game_msg(
|
||||
&mut self,
|
||||
frontend_events: &mut Vec<Event>,
|
||||
msg: ServerInGameMsg,
|
||||
msg: ServerInGame,
|
||||
) -> Result<(), Error> {
|
||||
match msg {
|
||||
ServerInGameMsg::GroupUpdate(change_notification) => {
|
||||
ServerInGame::GroupUpdate(change_notification) => {
|
||||
use comp::group::ChangeNotification::*;
|
||||
// Note: we use a hashmap since this would not work with entities outside
|
||||
// the view distance
|
||||
@ -1332,15 +1319,15 @@ impl Client {
|
||||
},
|
||||
}
|
||||
},
|
||||
ServerInGameMsg::GroupInvite { inviter, timeout } => {
|
||||
ServerInGame::GroupInvite { inviter, timeout } => {
|
||||
self.group_invite = Some((inviter, std::time::Instant::now(), timeout));
|
||||
},
|
||||
ServerInGameMsg::InvitePending(uid) => {
|
||||
ServerInGame::InvitePending(uid) => {
|
||||
if !self.pending_invites.insert(uid) {
|
||||
warn!("Received message about pending invite that was already pending");
|
||||
}
|
||||
},
|
||||
ServerInGameMsg::InviteComplete { target, answer } => {
|
||||
ServerInGame::InviteComplete { target, answer } => {
|
||||
if !self.pending_invites.remove(&target) {
|
||||
warn!(
|
||||
"Received completed invite message for invite that was not in the list of \
|
||||
@ -1358,11 +1345,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`
|
||||
ServerInGameMsg::ExitInGameSuccess => {
|
||||
self.client_ingame = None;
|
||||
ServerInGame::ExitInGameSuccess => {
|
||||
self.in_game = None;
|
||||
self.clean_state();
|
||||
},
|
||||
ServerInGameMsg::InventoryUpdate(mut inventory, event) => {
|
||||
ServerInGame::InventoryUpdate(mut inventory, event) => {
|
||||
match event {
|
||||
InventoryUpdateEvent::CollectFailed => {},
|
||||
_ => {
|
||||
@ -1376,25 +1363,25 @@ impl Client {
|
||||
|
||||
frontend_events.push(Event::InventoryUpdated(event));
|
||||
},
|
||||
ServerInGameMsg::TerrainChunkUpdate { key, chunk } => {
|
||||
ServerInGame::TerrainChunkUpdate { key, chunk } => {
|
||||
if let Ok(chunk) = chunk {
|
||||
self.state.insert_chunk(key, *chunk);
|
||||
}
|
||||
self.pending_chunks.remove(&key);
|
||||
},
|
||||
ServerInGameMsg::TerrainBlockUpdates(mut blocks) => {
|
||||
ServerInGame::TerrainBlockUpdates(mut blocks) => {
|
||||
blocks.drain().for_each(|(pos, block)| {
|
||||
self.state.set_block(pos, block);
|
||||
});
|
||||
},
|
||||
ServerInGameMsg::SetViewDistance(vd) => {
|
||||
ServerInGame::SetViewDistance(vd) => {
|
||||
self.view_distance = Some(vd);
|
||||
frontend_events.push(Event::SetViewDistance(vd));
|
||||
},
|
||||
ServerInGameMsg::Outcomes(outcomes) => {
|
||||
ServerInGame::Outcomes(outcomes) => {
|
||||
frontend_events.extend(outcomes.into_iter().map(Event::Outcome))
|
||||
},
|
||||
ServerInGameMsg::Knockback(impulse) => {
|
||||
ServerInGame::Knockback(impulse) => {
|
||||
self.state
|
||||
.ecs()
|
||||
.read_resource::<EventBus<LocalEvent>>()
|
||||
@ -1409,24 +1396,24 @@ impl Client {
|
||||
|
||||
fn handle_server_character_screen_msg(
|
||||
&mut self,
|
||||
msg: ServerCharacterScreenMsg,
|
||||
msg: ServerCharacterScreen,
|
||||
) -> Result<(), Error> {
|
||||
match msg {
|
||||
ServerCharacterScreenMsg::CharacterListUpdate(character_list) => {
|
||||
ServerCharacterScreen::CharacterListUpdate(character_list) => {
|
||||
self.character_list.characters = character_list;
|
||||
self.character_list.loading = false;
|
||||
},
|
||||
ServerCharacterScreenMsg::CharacterActionError(error) => {
|
||||
ServerCharacterScreen::CharacterActionError(error) => {
|
||||
warn!("CharacterActionError: {:?}.", error);
|
||||
self.character_list.error = Some(error);
|
||||
},
|
||||
ServerCharacterScreenMsg::CharacterDataLoadError(error) => {
|
||||
ServerCharacterScreen::CharacterDataLoadError(error) => {
|
||||
trace!("Handling join error by server");
|
||||
self.client_ingame = None;
|
||||
self.in_game = None;
|
||||
self.clean_state();
|
||||
self.character_list.error = Some(error);
|
||||
},
|
||||
ServerCharacterScreenMsg::CharacterSuccess => {
|
||||
ServerCharacterScreen::CharacterSuccess => {
|
||||
debug!("client is now in ingame state on server");
|
||||
if let Some(vd) = self.view_distance {
|
||||
self.set_view_distance(vd);
|
||||
@ -1439,7 +1426,7 @@ impl Client {
|
||||
fn handle_ping_msg(&mut self, msg: PingMsg) -> Result<(), Error> {
|
||||
match msg {
|
||||
PingMsg::Ping => {
|
||||
self.ping_stream.send(PingMsg::Pong)?;
|
||||
self.send_msg_err(PingMsg::Pong)?;
|
||||
},
|
||||
PingMsg::Pong => {
|
||||
self.last_server_pong = self.state.get_time();
|
||||
@ -1535,7 +1522,7 @@ impl Client {
|
||||
|
||||
pub fn get_client_type(&self) -> ClientType { ClientType::Game }
|
||||
|
||||
pub fn get_in_game(&self) -> Option<ClientIngame> { self.client_ingame }
|
||||
pub fn get_in_game(&self) -> Option<ClientIngame> { self.in_game }
|
||||
|
||||
pub fn get_registered(&self) -> bool { self.registered }
|
||||
|
||||
@ -1810,12 +1797,16 @@ impl Client {
|
||||
impl Drop for Client {
|
||||
fn drop(&mut self) {
|
||||
trace!("Dropping client");
|
||||
if let Err(e) = self.general_stream.send(ClientGeneralMsg::Disconnect) {
|
||||
warn!(
|
||||
?e,
|
||||
"Error during drop of client, couldn't send disconnect package, is the connection \
|
||||
already closed?",
|
||||
);
|
||||
if self.registered {
|
||||
if let Err(e) = self.send_msg_err(ClientGeneral::Disconnect) {
|
||||
warn!(
|
||||
?e,
|
||||
"Error during drop of client, couldn't send disconnect package, is the \
|
||||
connection already closed?",
|
||||
);
|
||||
}
|
||||
} else {
|
||||
trace!("no disconnect msg necessary as client wasn't registered")
|
||||
}
|
||||
if let Err(e) = block_on(self.participant.take().unwrap().disconnect()) {
|
||||
warn!(?e, "error when disconnecting, couldn't send all data");
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::{comp::group::Group, msg::ServerGeneralMsg, sync::Uid};
|
||||
use crate::{comp::group::Group, msg::ServerGeneral, sync::Uid};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use specs::Component;
|
||||
use specs_idvs::IdvStorage;
|
||||
@ -118,11 +118,11 @@ impl<G> ChatType<G> {
|
||||
}
|
||||
}
|
||||
impl ChatType<String> {
|
||||
pub fn server_msg<S>(self, msg: S) -> ServerGeneralMsg
|
||||
pub fn server_msg<S>(self, msg: S) -> ServerGeneral
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
ServerGeneralMsg::ChatMsg(self.chat_msg(msg))
|
||||
ServerGeneral::ChatMsg(self.chat_msg(msg))
|
||||
}
|
||||
}
|
||||
// Stores chat text, type
|
||||
|
@ -1,3 +1,4 @@
|
||||
use super::PingMsg;
|
||||
use crate::{
|
||||
character::CharacterId,
|
||||
comp,
|
||||
@ -7,25 +8,48 @@ use crate::{
|
||||
use serde::{Deserialize, Serialize};
|
||||
use vek::*;
|
||||
|
||||
///This struct contains all messages the client might send (on different
|
||||
/// streams though). It's used to verify the correctness of the state in
|
||||
/// debug_assertions
|
||||
#[derive(Debug, Clone)]
|
||||
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),
|
||||
}
|
||||
|
||||
/*
|
||||
2nd Level Enums
|
||||
*/
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ClientType {
|
||||
// Regular Client like Voxygen who plays the game
|
||||
/// Regular Client like Voxygen who plays the game
|
||||
Game,
|
||||
// A Chatonly client, which doesn't want to connect via its character
|
||||
/// A Chatonly client, which doesn't want to connect via its character
|
||||
ChatOnly,
|
||||
// A unprivileged bot, e.g. to request world information
|
||||
// Or a privileged bot, e.g. to run admin commands used by server-cli
|
||||
/// A unprivileged bot, e.g. to request world information
|
||||
/// Or a privileged bot, e.g. to run admin commands used by server-cli
|
||||
Bot { privileged: bool },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ClientRegisterMsg {
|
||||
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 ClientCharacterScreenMsg {
|
||||
pub enum ClientCharacterScreen {
|
||||
RequestCharacterList,
|
||||
CreateCharacter {
|
||||
alias: String,
|
||||
@ -39,7 +63,7 @@ pub enum ClientCharacterScreenMsg {
|
||||
|
||||
//messages send by clients only valid when in game (with a character)
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ClientInGameMsg {
|
||||
pub enum ClientInGame {
|
||||
ControllerInputs(comp::ControllerInputs),
|
||||
ControlEvent(comp::ControlEvent),
|
||||
ControlAction(comp::ControlAction),
|
||||
@ -62,8 +86,36 @@ pub enum ClientInGameMsg {
|
||||
|
||||
/// Messages sent from the client to the server
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum ClientGeneralMsg {
|
||||
pub enum ClientGeneral {
|
||||
ChatMsg(String),
|
||||
Disconnect,
|
||||
Terminate,
|
||||
}
|
||||
|
||||
/*
|
||||
end of 2nd level Enums
|
||||
*/
|
||||
|
||||
impl Into<ClientMsg> for ClientType {
|
||||
fn into(self) -> ClientMsg { ClientMsg::Type(self) }
|
||||
}
|
||||
|
||||
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) }
|
||||
}
|
||||
|
||||
impl Into<ClientMsg> for PingMsg {
|
||||
fn into(self) -> ClientMsg { ClientMsg::Ping(self) }
|
||||
}
|
||||
|
@ -1,18 +1,20 @@
|
||||
pub mod client;
|
||||
pub mod ecs_packet;
|
||||
pub mod server;
|
||||
pub mod world_packet;
|
||||
|
||||
// Reexports
|
||||
pub use self::{
|
||||
client::{
|
||||
ClientCharacterScreenMsg, ClientGeneralMsg, ClientInGameMsg, ClientRegisterMsg, ClientType,
|
||||
ClientCharacterScreen, ClientGeneral, ClientInGame, ClientMsg, ClientRegister, ClientType,
|
||||
},
|
||||
ecs_packet::EcsCompPacket,
|
||||
server::{
|
||||
CharacterInfo, DisconnectReason, InviteAnswer, Notification, PlayerInfo, PlayerListUpdate,
|
||||
RegisterError, ServerCharacterScreenMsg, ServerGeneralMsg, ServerInGameMsg, ServerInfo,
|
||||
ServerInitMsg, ServerRegisterAnswerMsg,
|
||||
RegisterError, ServerCharacterScreen, ServerGeneral, ServerInGame, ServerInfo, ServerInit,
|
||||
ServerMsg, ServerRegisterAnswer,
|
||||
},
|
||||
world_packet::WorldMapMsg,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
use super::EcsCompPacket;
|
||||
use super::{EcsCompPacket, PingMsg};
|
||||
use crate::{
|
||||
character::CharacterItem,
|
||||
comp,
|
||||
@ -14,6 +14,31 @@ use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use vek::*;
|
||||
|
||||
///This struct contains all messages the server might send (on different
|
||||
/// streams though)
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ServerMsg {
|
||||
/// Basic info about server, send ONCE, clients need it to Register
|
||||
Info(ServerInfo),
|
||||
/// Initial data package, send BEFORE Register ONCE. Not Register relevant
|
||||
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),
|
||||
}
|
||||
|
||||
/*
|
||||
2nd Level Enums
|
||||
*/
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ServerInfo {
|
||||
pub name: String,
|
||||
@ -23,195 +48,26 @@ pub struct ServerInfo {
|
||||
pub auth_provider: Option<String>,
|
||||
}
|
||||
|
||||
/// Inform the client of updates to the player list.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum PlayerListUpdate {
|
||||
Init(HashMap<Uid, PlayerInfo>),
|
||||
Add(Uid, PlayerInfo),
|
||||
SelectedCharacter(Uid, CharacterInfo),
|
||||
LevelChange(Uid, u32),
|
||||
Admin(Uid, bool),
|
||||
Remove(Uid),
|
||||
Alias(Uid, String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct PlayerInfo {
|
||||
pub is_admin: bool,
|
||||
pub is_online: bool,
|
||||
pub player_alias: String,
|
||||
pub character: Option<CharacterInfo>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct CharacterInfo {
|
||||
pub name: String,
|
||||
pub level: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
/// World map information. Note that currently, we always send the whole thing
|
||||
/// in one go, but the structure aims to try to provide information as locally
|
||||
/// as possible, so that in the future we can split up large maps into multiple
|
||||
/// WorldMapMsg fragments.
|
||||
///
|
||||
/// TODO: Update message format to make fragmentable, allowing us to send more
|
||||
/// information without running into bandwidth issues.
|
||||
///
|
||||
/// TODO: Add information for rivers (currently, we just prerender them on the
|
||||
/// server, but this is not a great solution for LoD. The map rendering code is
|
||||
/// already set up to be able to take advantage of the river rendering being
|
||||
/// split out, but the format is a little complicated for space reasons and it
|
||||
/// may take some tweaking to get right, so we avoid sending it for now).
|
||||
///
|
||||
/// TODO: measure explicit compression schemes that might save space, e.g.
|
||||
/// repeating the "small angles" optimization that works well on more detailed
|
||||
/// shadow maps intended for height maps.
|
||||
pub struct WorldMapMsg {
|
||||
/// Log base 2 of world map dimensions (width × height) in chunks.
|
||||
///
|
||||
/// NOTE: Invariant: chunk count fits in a u16.
|
||||
pub dimensions_lg: Vec2<u32>,
|
||||
/// Sea level (used to provide a base altitude).
|
||||
pub sea_level: f32,
|
||||
/// Max height (used to scale altitudes).
|
||||
pub max_height: f32,
|
||||
/// RGB+A; the alpha channel is currently unused, but will be used in the
|
||||
/// future. Entries are in the usual chunk order.
|
||||
pub rgba: Vec<u32>,
|
||||
/// Altitudes: bits 2 to 0 are unused, then bits 15 to 3 are used for
|
||||
/// altitude. The remainder are currently unused, but we have plans to
|
||||
/// use 7 bits for water depth (using an integer f7 encoding), and we
|
||||
/// will find other uses for the remaining 12 bits.
|
||||
pub alt: Vec<u32>,
|
||||
/// Horizon mapping. This is a variant of shadow mapping that is
|
||||
/// specifically designed for height maps; it takes advantage of their
|
||||
/// regular structure (e.g. no holes) to compress all information needed
|
||||
/// to decide when to cast a sharp shadow into a single nagle, the "horizon
|
||||
/// angle." This is the smallest angle with the ground at which light can
|
||||
/// pass through any occluders to reach the chunk, in some chosen
|
||||
/// horizontal direction. This would not be sufficient for a more
|
||||
/// complicated 3D structure, but it works for height maps since:
|
||||
///
|
||||
/// 1. they have no gaps, so as soon as light can shine through it will
|
||||
/// always be able to do so, and
|
||||
/// 2. we only care about lighting from the top, and only from the east and
|
||||
/// west (since at a large scale like this we mostly just want to
|
||||
/// handle variable sunlight; moonlight would present more challenges
|
||||
/// but we currently have no plans to try to cast accurate shadows in
|
||||
/// moonlight).
|
||||
///
|
||||
/// Our chosen format is two pairs of vectors,
|
||||
/// with the first pair representing west-facing light (casting shadows on
|
||||
/// the left side) and the second representing east-facing light
|
||||
/// (casting shadows on the east side).
|
||||
///
|
||||
/// The pair of vectors consists of (with each vector in the usual chunk
|
||||
/// order):
|
||||
///
|
||||
/// * Horizon angle pointing east (1 byte, scaled so 1 unit = 255° / 360).
|
||||
/// We might consider switching to tangent if that represents the
|
||||
/// information we care about better.
|
||||
/// * Approximate (floor) height of maximal occluder. We currently use this
|
||||
/// to try to deliver some approximation of soft shadows, which isn't that
|
||||
/// big a deal on the world map but is probably needed in order to ensure
|
||||
/// smooth transitions between chunks in LoD view. Additionally, when we
|
||||
/// start using the shadow information to do local lighting on the world
|
||||
/// map, we'll want a quick way to test where we can go out of shadow at
|
||||
/// arbitrary heights (since the player and other entities cajn find
|
||||
/// themselves far from the ground at times). While this is only an
|
||||
/// approximation to a proper distance map, hopefully it will give us
|
||||
/// something that feels reasonable enough for Veloren's style.
|
||||
///
|
||||
/// NOTE: On compression.
|
||||
///
|
||||
/// Horizon mapping has a lot of advantages for height maps (simple, easy to
|
||||
/// understand, doesn't require any fancy math or approximation beyond
|
||||
/// precision loss), though it loses a few of them by having to store
|
||||
/// distance to occluder as well. However, just storing tons
|
||||
/// and tons of regular shadow maps (153 for a full day cycle, stored at
|
||||
/// irregular intervals) combined with clever explicit compression and
|
||||
/// avoiding recording sharp local shadows (preferring retracing for
|
||||
/// these), yielded a compression rate of under 3 bits per column! Since
|
||||
/// we likely want to avoid per-column shadows for worlds of the sizes we
|
||||
/// want, we'd still need to store *some* extra information to create
|
||||
/// soft shadows, but it would still be nice to try to drive down our
|
||||
/// size as much as possible given how compressible shadows of height
|
||||
/// maps seem to be in practice. Therefore, we try to take advantage of the
|
||||
/// way existing compression algorithms tend to work to see if we can
|
||||
/// achieve significant gains without doing a lot of custom work.
|
||||
///
|
||||
/// Specifically, since our rays are cast east/west, we expect that for each
|
||||
/// row, the horizon angles in each direction should be sequences of
|
||||
/// monotonically increasing values (as chunks approach a tall
|
||||
/// occluder), followed by sequences of no shadow, repeated
|
||||
/// until the end of the map. Monotonic sequences and same-byte sequences
|
||||
/// are usually easy to compress and existing algorithms are more likely
|
||||
/// to be able to deal with them than jumbled data. If we were to keep
|
||||
/// both directions in the same vector, off-the-shelf compression would
|
||||
/// probably be less effective.
|
||||
///
|
||||
/// For related reasons, rather than storing distances as in a standard
|
||||
/// distance map (which would lead to monotonically *decreasing* values
|
||||
/// as we approached the occluder from a given direction), we store the
|
||||
/// estimated *occluder height.* The idea here is that we replace the
|
||||
/// monotonic sequences with constant sequences, which are extremely
|
||||
/// straightforward to compress and mostly handled automatically by anything
|
||||
/// that does run-length encoding (i.e. most off-the-shelf compression
|
||||
/// algorithms).
|
||||
///
|
||||
/// We still need to benchmark this properly, as there's no guarantee our
|
||||
/// current compression algorithms will actually work well on this data
|
||||
/// in practice. It's possible that some other permutation (e.g. more
|
||||
/// bits reserved for "distance to occluder" in exchange for an even
|
||||
/// more predictible sequence) would end up compressing better than storing
|
||||
/// angles, or that we don't need as much precision as we currently have
|
||||
/// (256 possible angles).
|
||||
pub horizons: [(Vec<u8>, Vec<u8>); 2],
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum InviteAnswer {
|
||||
Accepted,
|
||||
Declined,
|
||||
TimedOut,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum Notification {
|
||||
WaypointSaved,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum DisconnectReason {
|
||||
/// Server shut down
|
||||
Shutdown,
|
||||
/// Client sent disconnect message
|
||||
Requested,
|
||||
/// Client was kicked
|
||||
Kicked(String),
|
||||
}
|
||||
|
||||
/// Reponse To ClientType
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[allow(clippy::clippy::large_enum_variant)]
|
||||
pub enum ServerInitMsg {
|
||||
pub enum ServerInit {
|
||||
TooManyPlayers,
|
||||
GameSync {
|
||||
entity_package: sync::EntityPackage<EcsCompPacket>,
|
||||
time_of_day: state::TimeOfDay,
|
||||
max_group_size: u32,
|
||||
client_timeout: Duration,
|
||||
world_map: WorldMapMsg,
|
||||
world_map: crate::msg::world_packet::WorldMapMsg,
|
||||
recipe_book: RecipeBook,
|
||||
},
|
||||
}
|
||||
|
||||
pub type ServerRegisterAnswerMsg = Result<(), RegisterError>;
|
||||
pub type ServerRegisterAnswer = Result<(), RegisterError>;
|
||||
|
||||
//Messages only allowed while client in character screen
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum ServerCharacterScreenMsg {
|
||||
pub enum ServerCharacterScreen {
|
||||
/// An error occurred while loading character data
|
||||
CharacterDataLoadError(String),
|
||||
/// A list of characters belonging to the a authenticated player was sent
|
||||
@ -223,7 +79,7 @@ pub enum ServerCharacterScreenMsg {
|
||||
|
||||
//Messages only allowed while client is in game (with a character)
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum ServerInGameMsg {
|
||||
pub enum ServerInGame {
|
||||
GroupUpdate(comp::group::ChangeNotification<sync::Uid>),
|
||||
// Indicate to the client that they are invited to join a group
|
||||
GroupInvite {
|
||||
@ -256,7 +112,7 @@ pub enum ServerInGameMsg {
|
||||
|
||||
/// Messages sent from the server to the client
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum ServerGeneralMsg {
|
||||
pub enum ServerGeneral {
|
||||
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.
|
||||
@ -272,6 +128,58 @@ pub enum ServerGeneralMsg {
|
||||
Notification(Notification),
|
||||
}
|
||||
|
||||
/*
|
||||
end of 2nd level Enums
|
||||
*/
|
||||
|
||||
/// Inform the client of updates to the player list.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum PlayerListUpdate {
|
||||
Init(HashMap<Uid, PlayerInfo>),
|
||||
Add(Uid, PlayerInfo),
|
||||
SelectedCharacter(Uid, CharacterInfo),
|
||||
LevelChange(Uid, u32),
|
||||
Admin(Uid, bool),
|
||||
Remove(Uid),
|
||||
Alias(Uid, String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct PlayerInfo {
|
||||
pub is_admin: bool,
|
||||
pub is_online: bool,
|
||||
pub player_alias: String,
|
||||
pub character: Option<CharacterInfo>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct CharacterInfo {
|
||||
pub name: String,
|
||||
pub level: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum InviteAnswer {
|
||||
Accepted,
|
||||
Declined,
|
||||
TimedOut,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum Notification {
|
||||
WaypointSaved,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum DisconnectReason {
|
||||
/// Server shut down
|
||||
Shutdown,
|
||||
/// Client sent disconnect message
|
||||
Requested,
|
||||
/// Client was kicked
|
||||
Kicked(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum RegisterError {
|
||||
AlreadyLoggedIn,
|
||||
@ -286,6 +194,34 @@ impl From<AuthClientError> for RegisterError {
|
||||
fn from(err: AuthClientError) -> Self { Self::AuthError(err.to_string()) }
|
||||
}
|
||||
|
||||
impl From<comp::ChatMsg> for ServerGeneralMsg {
|
||||
fn from(v: comp::ChatMsg) -> Self { ServerGeneralMsg::ChatMsg(v) }
|
||||
impl From<comp::ChatMsg> for ServerGeneral {
|
||||
fn from(v: comp::ChatMsg) -> Self { ServerGeneral::ChatMsg(v) }
|
||||
}
|
||||
|
||||
impl Into<ServerMsg> for ServerInfo {
|
||||
fn into(self) -> ServerMsg { ServerMsg::Info(self) }
|
||||
}
|
||||
|
||||
impl Into<ServerMsg> for ServerInit {
|
||||
fn into(self) -> ServerMsg { ServerMsg::Init(self) }
|
||||
}
|
||||
|
||||
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) }
|
||||
}
|
||||
|
||||
impl Into<ServerMsg> for PingMsg {
|
||||
fn into(self) -> ServerMsg { ServerMsg::Ping(self) }
|
||||
}
|
||||
|
123
common/src/msg/world_packet.rs
Normal file
123
common/src/msg/world_packet.rs
Normal file
@ -0,0 +1,123 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use vek::*;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
/// World map information. Note that currently, we always send the whole thing
|
||||
/// in one go, but the structure aims to try to provide information as locally
|
||||
/// as possible, so that in the future we can split up large maps into multiple
|
||||
/// WorldMapMsg fragments.
|
||||
///
|
||||
/// TODO: Update message format to make fragmentable, allowing us to send more
|
||||
/// information without running into bandwidth issues.
|
||||
///
|
||||
/// TODO: Add information for rivers (currently, we just prerender them on the
|
||||
/// server, but this is not a great solution for LoD. The map rendering code is
|
||||
/// already set up to be able to take advantage of the river rendering being
|
||||
/// split out, but the format is a little complicated for space reasons and it
|
||||
/// may take some tweaking to get right, so we avoid sending it for now).
|
||||
///
|
||||
/// TODO: measure explicit compression schemes that might save space, e.g.
|
||||
/// repeating the "small angles" optimization that works well on more detailed
|
||||
/// shadow maps intended for height maps.
|
||||
pub struct WorldMapMsg {
|
||||
/// Log base 2 of world map dimensions (width × height) in chunks.
|
||||
///
|
||||
/// NOTE: Invariant: chunk count fits in a u16.
|
||||
pub dimensions_lg: Vec2<u32>,
|
||||
/// Sea level (used to provide a base altitude).
|
||||
pub sea_level: f32,
|
||||
/// Max height (used to scale altitudes).
|
||||
pub max_height: f32,
|
||||
/// RGB+A; the alpha channel is currently unused, but will be used in the
|
||||
/// future. Entries are in the usual chunk order.
|
||||
pub rgba: Vec<u32>,
|
||||
/// Altitudes: bits 2 to 0 are unused, then bits 15 to 3 are used for
|
||||
/// altitude. The remainder are currently unused, but we have plans to
|
||||
/// use 7 bits for water depth (using an integer f7 encoding), and we
|
||||
/// will find other uses for the remaining 12 bits.
|
||||
pub alt: Vec<u32>,
|
||||
/// Horizon mapping. This is a variant of shadow mapping that is
|
||||
/// specifically designed for height maps; it takes advantage of their
|
||||
/// regular structure (e.g. no holes) to compress all information needed
|
||||
/// to decide when to cast a sharp shadow into a single nagle, the "horizon
|
||||
/// angle." This is the smallest angle with the ground at which light can
|
||||
/// pass through any occluders to reach the chunk, in some chosen
|
||||
/// horizontal direction. This would not be sufficient for a more
|
||||
/// complicated 3D structure, but it works for height maps since:
|
||||
///
|
||||
/// 1. they have no gaps, so as soon as light can shine through it will
|
||||
/// always be able to do so, and
|
||||
/// 2. we only care about lighting from the top, and only from the east and
|
||||
/// west (since at a large scale like this we mostly just want to
|
||||
/// handle variable sunlight; moonlight would present more challenges
|
||||
/// but we currently have no plans to try to cast accurate shadows in
|
||||
/// moonlight).
|
||||
///
|
||||
/// Our chosen format is two pairs of vectors,
|
||||
/// with the first pair representing west-facing light (casting shadows on
|
||||
/// the left side) and the second representing east-facing light
|
||||
/// (casting shadows on the east side).
|
||||
///
|
||||
/// The pair of vectors consists of (with each vector in the usual chunk
|
||||
/// order):
|
||||
///
|
||||
/// * Horizon angle pointing east (1 byte, scaled so 1 unit = 255° / 360).
|
||||
/// We might consider switching to tangent if that represents the
|
||||
/// information we care about better.
|
||||
/// * Approximate (floor) height of maximal occluder. We currently use this
|
||||
/// to try to deliver some approximation of soft shadows, which isn't that
|
||||
/// big a deal on the world map but is probably needed in order to ensure
|
||||
/// smooth transitions between chunks in LoD view. Additionally, when we
|
||||
/// start using the shadow information to do local lighting on the world
|
||||
/// map, we'll want a quick way to test where we can go out of shadow at
|
||||
/// arbitrary heights (since the player and other entities cajn find
|
||||
/// themselves far from the ground at times). While this is only an
|
||||
/// approximation to a proper distance map, hopefully it will give us
|
||||
/// something that feels reasonable enough for Veloren's style.
|
||||
///
|
||||
/// NOTE: On compression.
|
||||
///
|
||||
/// Horizon mapping has a lot of advantages for height maps (simple, easy to
|
||||
/// understand, doesn't require any fancy math or approximation beyond
|
||||
/// precision loss), though it loses a few of them by having to store
|
||||
/// distance to occluder as well. However, just storing tons
|
||||
/// and tons of regular shadow maps (153 for a full day cycle, stored at
|
||||
/// irregular intervals) combined with clever explicit compression and
|
||||
/// avoiding recording sharp local shadows (preferring retracing for
|
||||
/// these), yielded a compression rate of under 3 bits per column! Since
|
||||
/// we likely want to avoid per-column shadows for worlds of the sizes we
|
||||
/// want, we'd still need to store *some* extra information to create
|
||||
/// soft shadows, but it would still be nice to try to drive down our
|
||||
/// size as much as possible given how compressible shadows of height
|
||||
/// maps seem to be in practice. Therefore, we try to take advantage of the
|
||||
/// way existing compression algorithms tend to work to see if we can
|
||||
/// achieve significant gains without doing a lot of custom work.
|
||||
///
|
||||
/// Specifically, since our rays are cast east/west, we expect that for each
|
||||
/// row, the horizon angles in each direction should be sequences of
|
||||
/// monotonically increasing values (as chunks approach a tall
|
||||
/// occluder), followed by sequences of no shadow, repeated
|
||||
/// until the end of the map. Monotonic sequences and same-byte sequences
|
||||
/// are usually easy to compress and existing algorithms are more likely
|
||||
/// to be able to deal with them than jumbled data. If we were to keep
|
||||
/// both directions in the same vector, off-the-shelf compression would
|
||||
/// probably be less effective.
|
||||
///
|
||||
/// For related reasons, rather than storing distances as in a standard
|
||||
/// distance map (which would lead to monotonically *decreasing* values
|
||||
/// as we approached the occluder from a given direction), we store the
|
||||
/// estimated *occluder height.* The idea here is that we replace the
|
||||
/// monotonic sequences with constant sequences, which are extremely
|
||||
/// straightforward to compress and mostly handled automatically by anything
|
||||
/// that does run-length encoding (i.e. most off-the-shelf compression
|
||||
/// algorithms).
|
||||
///
|
||||
/// We still need to benchmark this properly, as there's no guarantee our
|
||||
/// current compression algorithms will actually work well on this data
|
||||
/// in practice. It's possible that some other permutation (e.g. more
|
||||
/// bits reserved for "distance to occluder" in exchange for an even
|
||||
/// more predictible sequence) would end up compressing better than storing
|
||||
/// angles, or that we don't need as much precision as we currently have
|
||||
/// (256 possible angles).
|
||||
pub horizons: [(Vec<u8>, Vec<u8>); 2],
|
||||
}
|
@ -1,16 +1,16 @@
|
||||
use crate::error::Error;
|
||||
use common::msg::{
|
||||
ClientCharacterScreenMsg, ClientGeneralMsg, ClientInGameMsg, ClientIngame, ClientType, PingMsg,
|
||||
ServerCharacterScreenMsg, ServerGeneralMsg, ServerInGameMsg, ServerInitMsg,
|
||||
ClientCharacterScreen, ClientGeneral, ClientInGame, ClientIngame, ClientType, PingMsg,
|
||||
ServerMsg,
|
||||
};
|
||||
use hashbrown::HashSet;
|
||||
use network::{MessageBuffer, Participant, Stream};
|
||||
use network::{Participant, Stream};
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
use specs::{Component, FlaggedStorage};
|
||||
use specs_idvs::IdvStorage;
|
||||
use std::sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Arc, Mutex,
|
||||
Mutex,
|
||||
};
|
||||
use tracing::debug;
|
||||
use vek::*;
|
||||
@ -20,7 +20,7 @@ pub struct Client {
|
||||
pub client_type: ClientType,
|
||||
pub in_game: Option<ClientIngame>,
|
||||
pub participant: Mutex<Option<Participant>>,
|
||||
pub singleton_stream: Stream,
|
||||
pub general_stream: Stream,
|
||||
pub ping_stream: Stream,
|
||||
pub register_stream: Stream,
|
||||
pub character_screen_stream: Stream,
|
||||
@ -44,6 +44,7 @@ impl Client {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
fn internal_send_raw(b: &AtomicBool, s: &mut Stream, msg: Arc<MessageBuffer>) {
|
||||
if !b.load(Ordering::Relaxed) {
|
||||
if let Err(e) = s.send_raw(msg) {
|
||||
@ -52,29 +53,32 @@ impl Client {
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
pub fn send_init(&mut self, msg: ServerInitMsg) {
|
||||
Self::internal_send(&self.network_error, &mut self.register_stream, msg);
|
||||
}
|
||||
|
||||
pub fn send_msg(&mut self, msg: ServerGeneralMsg) {
|
||||
Self::internal_send(&self.network_error, &mut self.singleton_stream, msg);
|
||||
}
|
||||
|
||||
pub fn send_in_game(&mut self, msg: ServerInGameMsg) {
|
||||
Self::internal_send(&self.network_error, &mut self.in_game_stream, msg);
|
||||
}
|
||||
|
||||
pub fn send_character_screen(&mut self, msg: ServerCharacterScreenMsg) {
|
||||
Self::internal_send(&self.network_error, &mut self.character_screen_stream, msg);
|
||||
}
|
||||
|
||||
pub fn send_ping(&mut self, msg: PingMsg) {
|
||||
Self::internal_send(&self.network_error, &mut self.ping_stream, msg);
|
||||
}
|
||||
|
||||
pub fn send_msg_raw(&mut self, msg: Arc<MessageBuffer>) {
|
||||
Self::internal_send_raw(&self.network_error, &mut self.singleton_stream, msg);
|
||||
pub fn send_msg<S>(&mut self, msg: S)
|
||||
where
|
||||
S: Into<ServerMsg>,
|
||||
{
|
||||
const ERR: &str = "Dont do that, thats only done once at the start, no via this class";
|
||||
match msg.into() {
|
||||
ServerMsg::Info(_) => panic!(ERR),
|
||||
ServerMsg::Init(_) => panic!(ERR),
|
||||
ServerMsg::RegisterAnswer(msg) => {
|
||||
Self::internal_send(&self.network_error, &mut self.register_stream, &msg)
|
||||
},
|
||||
ServerMsg::CharacterScreen(msg) => {
|
||||
Self::internal_send(&self.network_error, &mut self.character_screen_stream, &msg)
|
||||
},
|
||||
ServerMsg::InGame(msg) => {
|
||||
Self::internal_send(&self.network_error, &mut self.in_game_stream, &msg)
|
||||
},
|
||||
ServerMsg::General(msg) => {
|
||||
Self::internal_send(&self.network_error, &mut self.general_stream, &msg)
|
||||
},
|
||||
ServerMsg::Ping(msg) => {
|
||||
Self::internal_send(&self.network_error, &mut self.ping_stream, &msg)
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
pub async fn internal_recv<M: DeserializeOwned>(
|
||||
@ -95,15 +99,15 @@ impl Client {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn recv_msg(&mut self) -> Result<ClientGeneralMsg, Error> {
|
||||
Self::internal_recv(&self.network_error, &mut self.singleton_stream).await
|
||||
pub async fn recv_msg(&mut self) -> Result<ClientGeneral, Error> {
|
||||
Self::internal_recv(&self.network_error, &mut self.general_stream).await
|
||||
}
|
||||
|
||||
pub async fn recv_in_game_msg(&mut self) -> Result<ClientInGameMsg, Error> {
|
||||
pub async fn recv_in_game_msg(&mut self) -> Result<ClientInGame, Error> {
|
||||
Self::internal_recv(&self.network_error, &mut self.in_game_stream).await
|
||||
}
|
||||
|
||||
pub async fn recv_character_screen_msg(&mut self) -> Result<ClientCharacterScreenMsg, Error> {
|
||||
pub async fn recv_character_screen_msg(&mut self) -> Result<ClientCharacterScreen, Error> {
|
||||
Self::internal_recv(&self.network_error, &mut self.character_screen_stream).await
|
||||
}
|
||||
|
||||
|
@ -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, ServerGeneralMsg, ServerInGameMsg},
|
||||
msg::{DisconnectReason, Notification, PlayerListUpdate, ServerGeneral, ServerInGame},
|
||||
npc::{self, get_npc_name},
|
||||
state::TimeOfDay,
|
||||
sync::{Uid, WorldSyncExt},
|
||||
@ -504,7 +504,7 @@ fn handle_alias(
|
||||
ecs.read_storage::<comp::Player>().get(target),
|
||||
old_alias_optional,
|
||||
) {
|
||||
let msg = ServerGeneralMsg::PlayerListUpdate(PlayerListUpdate::Alias(
|
||||
let msg = ServerGeneral::PlayerListUpdate(PlayerListUpdate::Alias(
|
||||
*uid,
|
||||
player.alias.clone(),
|
||||
));
|
||||
@ -669,9 +669,7 @@ fn handle_spawn(
|
||||
.try_map(|e| uids.get(e).copied())
|
||||
.map(|g| (g, c))
|
||||
})
|
||||
.map(|(g, c)| {
|
||||
c.send_in_game(ServerInGameMsg::GroupUpdate(g))
|
||||
});
|
||||
.map(|(g, c)| c.send_msg(ServerInGame::GroupUpdate(g)));
|
||||
},
|
||||
);
|
||||
} else if let Some(group) = match alignment {
|
||||
@ -1161,7 +1159,7 @@ fn handle_waypoint(
|
||||
server.notify_client(client, ChatType::CommandInfo.server_msg("Waypoint saved!"));
|
||||
server.notify_client(
|
||||
client,
|
||||
ServerGeneralMsg::Notification(Notification::WaypointSaved),
|
||||
ServerGeneral::Notification(Notification::WaypointSaved),
|
||||
);
|
||||
},
|
||||
None => server.notify_client(
|
||||
@ -1198,7 +1196,7 @@ fn handle_adminify(
|
||||
ecs.write_storage().insert(player, comp::Admin).is_ok()
|
||||
};
|
||||
// Update player list so the player shows up as admin in client chat.
|
||||
let msg = ServerGeneralMsg::PlayerListUpdate(PlayerListUpdate::Admin(
|
||||
let msg = ServerGeneral::PlayerListUpdate(PlayerListUpdate::Admin(
|
||||
*ecs.read_storage::<Uid>()
|
||||
.get(player)
|
||||
.expect("Player should have uid"),
|
||||
@ -1591,7 +1589,7 @@ fn find_target(
|
||||
ecs: &specs::World,
|
||||
opt_alias: Option<String>,
|
||||
fallback: EcsEntity,
|
||||
) -> Result<EcsEntity, ServerGeneralMsg> {
|
||||
) -> Result<EcsEntity, ServerGeneral> {
|
||||
if let Some(alias) = opt_alias {
|
||||
(&ecs.entities(), &ecs.read_storage::<comp::Player>())
|
||||
.join()
|
||||
@ -1663,7 +1661,7 @@ fn handle_set_level(
|
||||
.expect("Failed to get uid for player");
|
||||
server
|
||||
.state
|
||||
.notify_registered_clients(ServerGeneralMsg::PlayerListUpdate(
|
||||
.notify_registered_clients(ServerGeneral::PlayerListUpdate(
|
||||
PlayerListUpdate::LevelChange(uid, lvl),
|
||||
));
|
||||
|
||||
@ -1903,7 +1901,7 @@ fn kick_player(server: &mut Server, target_player: EcsEntity, reason: &str) {
|
||||
.emit_now(ServerEvent::ClientDisconnect(target_player));
|
||||
server.notify_client(
|
||||
target_player,
|
||||
ServerGeneralMsg::Disconnect(DisconnectReason::Kicked(reason.to_string())),
|
||||
ServerGeneral::Disconnect(DisconnectReason::Kicked(reason.to_string())),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -134,7 +134,7 @@ impl ConnectionHandler {
|
||||
client_type,
|
||||
in_game: None,
|
||||
participant: std::sync::Mutex::new(Some(participant)),
|
||||
singleton_stream: general_stream,
|
||||
general_stream,
|
||||
ping_stream,
|
||||
register_stream,
|
||||
in_game_stream,
|
||||
|
@ -12,7 +12,7 @@ use common::{
|
||||
Player, Pos, Stats,
|
||||
},
|
||||
lottery::Lottery,
|
||||
msg::{PlayerListUpdate, ServerGeneralMsg, ServerInGameMsg},
|
||||
msg::{PlayerListUpdate, ServerGeneral, ServerInGame},
|
||||
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_in_game(ServerInGameMsg::Knockback(impulse));
|
||||
client.send_msg(ServerInGame::Knockback(impulse));
|
||||
}
|
||||
}
|
||||
|
||||
@ -656,7 +656,7 @@ pub fn handle_level_up(server: &mut Server, entity: EcsEntity, new_level: u32) {
|
||||
|
||||
server
|
||||
.state
|
||||
.notify_registered_clients(ServerGeneralMsg::PlayerListUpdate(
|
||||
.notify_registered_clients(ServerGeneral::PlayerListUpdate(
|
||||
PlayerListUpdate::LevelChange(*uid, new_level),
|
||||
));
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ use common::{
|
||||
group::{self, Group, GroupManager, Invite, PendingInvites},
|
||||
ChatType, GroupManip,
|
||||
},
|
||||
msg::{InviteAnswer, ServerInGameMsg},
|
||||
msg::{InviteAnswer, ServerInGame},
|
||||
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_in_game(ServerInGameMsg::GroupInvite {
|
||||
client.send_msg(ServerInGame::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_in_game(ServerInGameMsg::InvitePending(uid));
|
||||
client.send_msg(ServerInGame::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_in_game(ServerInGameMsg::InviteComplete {
|
||||
client.send_msg(ServerInGame::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_in_game(ServerInGameMsg::GroupUpdate(g)));
|
||||
.map(|(g, c)| c.send_msg(ServerInGame::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_in_game(ServerInGameMsg::InviteComplete {
|
||||
client.send_msg(ServerInGame::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_in_game(ServerInGameMsg::GroupUpdate(g)));
|
||||
.map(|(g, c)| c.send_msg(ServerInGame::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_in_game(ServerInGameMsg::GroupUpdate(g)));
|
||||
.map(|(g, c)| c.send_msg(ServerInGame::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_in_game(ServerInGameMsg::GroupUpdate(g)));
|
||||
.map(|(g, c)| c.send_msg(ServerInGame::GroupUpdate(g)));
|
||||
},
|
||||
);
|
||||
// Tell them they are the leader
|
||||
|
@ -4,7 +4,7 @@ use crate::{
|
||||
};
|
||||
use common::{
|
||||
comp::{self, item},
|
||||
msg::ServerGeneralMsg,
|
||||
msg::ServerGeneral,
|
||||
sync::{Uid, WorldSyncExt},
|
||||
};
|
||||
use specs::{world::WorldExt, Entity as EcsEntity};
|
||||
@ -116,7 +116,7 @@ pub fn handle_possess(server: &Server, possessor_uid: Uid, possesse_uid: Uid) {
|
||||
let mut clients = ecs.write_storage::<Client>();
|
||||
if clients.get_mut(possesse).is_none() {
|
||||
if let Some(mut client) = clients.remove(possessor) {
|
||||
client.send_msg(ServerGeneralMsg::SetPlayerEntity(possesse_uid));
|
||||
client.send_msg(ServerGeneral::SetPlayerEntity(possesse_uid));
|
||||
clients
|
||||
.insert(possesse, client)
|
||||
.err()
|
||||
|
@ -5,7 +5,7 @@ use common::{
|
||||
slot::{self, Slot},
|
||||
Pos, MAX_PICKUP_RANGE_SQR,
|
||||
},
|
||||
msg::ServerInGameMsg,
|
||||
msg::ServerInGame,
|
||||
recipe::default_recipe_book,
|
||||
sync::{Uid, WorldSyncExt},
|
||||
vol::ReadVol,
|
||||
@ -281,9 +281,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
|
||||
.map(|g| (g, c))
|
||||
})
|
||||
.map(|(g, c)| {
|
||||
c.send_in_game(
|
||||
ServerInGameMsg::GroupUpdate(g),
|
||||
)
|
||||
c.send_msg(ServerInGame::GroupUpdate(g))
|
||||
});
|
||||
},
|
||||
);
|
||||
|
@ -5,7 +5,7 @@ use crate::{
|
||||
use common::{
|
||||
comp,
|
||||
comp::{group, Player},
|
||||
msg::{PlayerListUpdate, ServerGeneralMsg, ServerInGameMsg},
|
||||
msg::{PlayerListUpdate, ServerGeneral, ServerInGame},
|
||||
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_in_game(ServerInGameMsg::ExitInGameSuccess);
|
||||
client.send_msg(ServerInGame::ExitInGameSuccess);
|
||||
|
||||
let entity_builder = state.ecs_mut().create_entity().with(client).with(player);
|
||||
|
||||
@ -130,9 +130,9 @@ pub fn handle_client_disconnect(server: &mut Server, entity: EcsEntity) -> Event
|
||||
) {
|
||||
state.notify_registered_clients(comp::ChatType::Offline(*uid).server_msg(""));
|
||||
|
||||
state.notify_registered_clients(ServerGeneralMsg::PlayerListUpdate(
|
||||
PlayerListUpdate::Remove(*uid),
|
||||
));
|
||||
state.notify_registered_clients(ServerGeneral::PlayerListUpdate(PlayerListUpdate::Remove(
|
||||
*uid,
|
||||
)));
|
||||
}
|
||||
|
||||
// Make sure to remove the player from the logged in list. (See LoginProvider)
|
||||
|
@ -47,8 +47,8 @@ use common::{
|
||||
comp::{self, ChatType},
|
||||
event::{EventBus, ServerEvent},
|
||||
msg::{
|
||||
server::WorldMapMsg, ClientType, DisconnectReason, ServerCharacterScreenMsg,
|
||||
ServerGeneralMsg, ServerInGameMsg, ServerInfo, ServerInitMsg,
|
||||
ClientType, DisconnectReason, ServerCharacterScreen, ServerGeneral, ServerInfo, ServerInit,
|
||||
ServerMsg, WorldMapMsg,
|
||||
},
|
||||
outcome::Outcome,
|
||||
recipe::default_recipe_book,
|
||||
@ -525,13 +525,13 @@ impl Server {
|
||||
.messages()
|
||||
.for_each(|query_result| match query_result.result {
|
||||
CharacterLoaderResponseType::CharacterList(result) => match result {
|
||||
Ok(character_list_data) => self.notify_character_screen_client(
|
||||
Ok(character_list_data) => self.notify_client(
|
||||
query_result.entity,
|
||||
ServerCharacterScreenMsg::CharacterListUpdate(character_list_data),
|
||||
ServerCharacterScreen::CharacterListUpdate(character_list_data),
|
||||
),
|
||||
Err(error) => self.notify_character_screen_client(
|
||||
Err(error) => self.notify_client(
|
||||
query_result.entity,
|
||||
ServerCharacterScreenMsg::CharacterActionError(error.to_string()),
|
||||
ServerCharacterScreen::CharacterActionError(error.to_string()),
|
||||
),
|
||||
},
|
||||
CharacterLoaderResponseType::CharacterData(result) => {
|
||||
@ -544,9 +544,9 @@ impl Server {
|
||||
// We failed to load data for the character from the DB. Notify the
|
||||
// client to push the state back to character selection, with the error
|
||||
// to display
|
||||
self.notify_character_screen_client(
|
||||
self.notify_client(
|
||||
query_result.entity,
|
||||
ServerCharacterScreenMsg::CharacterDataLoadError(error.to_string()),
|
||||
ServerCharacterScreen::CharacterDataLoadError(error.to_string()),
|
||||
);
|
||||
|
||||
// Clean up the entity data on the server
|
||||
@ -815,7 +815,7 @@ impl Server {
|
||||
?client.participant,
|
||||
"to many players, wont allow participant to connect"
|
||||
);
|
||||
client.register_stream.send(ServerInitMsg::TooManyPlayers)?;
|
||||
client.register_stream.send(ServerInit::TooManyPlayers)?;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -839,7 +839,7 @@ impl Server {
|
||||
.get_mut(entity)
|
||||
.unwrap()
|
||||
.register_stream
|
||||
.send(ServerInitMsg::GameSync {
|
||||
.send(ServerInit::GameSync {
|
||||
// Send client their entity
|
||||
entity_package: TrackedComps::fetch(&self.state.ecs())
|
||||
.create_entity_package(entity, None, None, None),
|
||||
@ -858,32 +858,14 @@ impl Server {
|
||||
|
||||
pub fn notify_client<S>(&self, entity: EcsEntity, msg: S)
|
||||
where
|
||||
S: Into<ServerGeneralMsg>,
|
||||
S: Into<ServerMsg>,
|
||||
{
|
||||
if let Some(client) = self.state.ecs().write_storage::<Client>().get_mut(entity) {
|
||||
client.send_msg(msg.into())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn notify_in_game_client<S>(&self, entity: EcsEntity, msg: S)
|
||||
where
|
||||
S: Into<ServerInGameMsg>,
|
||||
{
|
||||
if let Some(client) = self.state.ecs().write_storage::<Client>().get_mut(entity) {
|
||||
client.send_in_game(msg.into())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn notify_character_screen_client<S>(&self, entity: EcsEntity, msg: S)
|
||||
where
|
||||
S: Into<ServerCharacterScreenMsg>,
|
||||
{
|
||||
if let Some(client) = self.state.ecs().write_storage::<Client>().get_mut(entity) {
|
||||
client.send_character_screen(msg.into())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn notify_registered_clients(&mut self, msg: ServerGeneralMsg) {
|
||||
pub fn notify_registered_clients(&mut self, msg: ServerGeneral) {
|
||||
self.state.notify_registered_clients(msg);
|
||||
}
|
||||
|
||||
@ -963,7 +945,7 @@ impl Server {
|
||||
impl Drop for Server {
|
||||
fn drop(&mut self) {
|
||||
self.state
|
||||
.notify_registered_clients(ServerGeneralMsg::Disconnect(DisconnectReason::Shutdown));
|
||||
.notify_registered_clients(ServerGeneral::Disconnect(DisconnectReason::Shutdown));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,8 +6,8 @@ use common::{
|
||||
comp,
|
||||
effect::Effect,
|
||||
msg::{
|
||||
CharacterInfo, ClientIngame, PlayerListUpdate, ServerCharacterScreenMsg, ServerGeneralMsg,
|
||||
ServerInGameMsg,
|
||||
CharacterInfo, ClientIngame, PlayerListUpdate, ServerCharacterScreen, ServerGeneral,
|
||||
ServerInGame, ServerMsg,
|
||||
},
|
||||
state::State,
|
||||
sync::{Uid, UidAllocator, WorldSyncExt},
|
||||
@ -62,7 +62,8 @@ pub trait StateExt {
|
||||
fn update_character_data(&mut self, entity: EcsEntity, components: PersistedComponents);
|
||||
/// Iterates over registered clients and send each `ServerMsg`
|
||||
fn send_chat(&self, msg: comp::UnresolvedChatMsg);
|
||||
fn notify_registered_clients(&self, msg: ServerGeneralMsg);
|
||||
fn notify_registered_clients(&self, msg: ServerGeneral);
|
||||
fn notify_in_game_clients(&self, msg: ServerInGame);
|
||||
/// Delete an entity, recording the deletion in [`DeletedEntities`]
|
||||
fn delete_entity_recorded(
|
||||
&mut self,
|
||||
@ -220,7 +221,7 @@ 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_character_screen(ServerCharacterScreenMsg::CharacterSuccess)
|
||||
client.send_msg(ServerCharacterScreen::CharacterSuccess)
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,7 +230,7 @@ impl StateExt for State {
|
||||
|
||||
if let Some(player_uid) = self.read_component_copied::<Uid>(entity) {
|
||||
// Notify clients of a player list update
|
||||
self.notify_registered_clients(ServerGeneralMsg::PlayerListUpdate(
|
||||
self.notify_registered_clients(ServerGeneral::PlayerListUpdate(
|
||||
PlayerListUpdate::SelectedCharacter(player_uid, CharacterInfo {
|
||||
name: String::from(&stats.name),
|
||||
level: stats.level.level(),
|
||||
@ -276,7 +277,7 @@ impl StateExt for State {
|
||||
| comp::ChatType::Kill(_, _)
|
||||
| comp::ChatType::Meta
|
||||
| comp::ChatType::World(_) => {
|
||||
self.notify_registered_clients(ServerGeneralMsg::ChatMsg(resolved_msg))
|
||||
self.notify_registered_clients(ServerGeneral::ChatMsg(resolved_msg))
|
||||
},
|
||||
comp::ChatType::Tell(u, t) => {
|
||||
for (client, uid) in (
|
||||
@ -286,7 +287,7 @@ impl StateExt for State {
|
||||
.join()
|
||||
{
|
||||
if uid == u || uid == t {
|
||||
client.send_msg(ServerGeneralMsg::ChatMsg(resolved_msg.clone()));
|
||||
client.send_msg(ServerGeneral::ChatMsg(resolved_msg.clone()));
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -298,7 +299,7 @@ impl StateExt for State {
|
||||
if let Some(speaker_pos) = entity_opt.and_then(|e| positions.get(e)) {
|
||||
for (client, pos) in (&mut ecs.write_storage::<Client>(), &positions).join() {
|
||||
if is_within(comp::ChatMsg::SAY_DISTANCE, pos, speaker_pos) {
|
||||
client.send_msg(ServerGeneralMsg::ChatMsg(resolved_msg.clone()));
|
||||
client.send_msg(ServerGeneral::ChatMsg(resolved_msg.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -310,7 +311,7 @@ impl StateExt for State {
|
||||
if let Some(speaker_pos) = entity_opt.and_then(|e| positions.get(e)) {
|
||||
for (client, pos) in (&mut ecs.write_storage::<Client>(), &positions).join() {
|
||||
if is_within(comp::ChatMsg::REGION_DISTANCE, pos, speaker_pos) {
|
||||
client.send_msg(ServerGeneralMsg::ChatMsg(resolved_msg.clone()));
|
||||
client.send_msg(ServerGeneral::ChatMsg(resolved_msg.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -322,7 +323,7 @@ impl StateExt for State {
|
||||
if let Some(speaker_pos) = entity_opt.and_then(|e| positions.get(e)) {
|
||||
for (client, pos) in (&mut ecs.write_storage::<Client>(), &positions).join() {
|
||||
if is_within(comp::ChatMsg::NPC_DISTANCE, pos, speaker_pos) {
|
||||
client.send_msg(ServerGeneralMsg::ChatMsg(resolved_msg.clone()));
|
||||
client.send_msg(ServerGeneral::ChatMsg(resolved_msg.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -336,7 +337,7 @@ impl StateExt for State {
|
||||
.join()
|
||||
{
|
||||
if s == &faction.0 {
|
||||
client.send_msg(ServerGeneralMsg::ChatMsg(resolved_msg.clone()));
|
||||
client.send_msg(ServerGeneral::ChatMsg(resolved_msg.clone()));
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -348,7 +349,7 @@ impl StateExt for State {
|
||||
.join()
|
||||
{
|
||||
if g == group {
|
||||
client.send_msg(ServerGeneralMsg::ChatMsg(resolved_msg.clone()));
|
||||
client.send_msg(ServerGeneral::ChatMsg(resolved_msg.clone()));
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -356,7 +357,8 @@ impl StateExt for State {
|
||||
}
|
||||
|
||||
/// Sends the message to all connected clients
|
||||
fn notify_registered_clients(&self, msg: ServerGeneralMsg) {
|
||||
fn notify_registered_clients(&self, msg: ServerGeneral) {
|
||||
let msg: ServerMsg = msg.into();
|
||||
for client in (&mut self.ecs().write_storage::<Client>())
|
||||
.join()
|
||||
.filter(|c| c.registered)
|
||||
@ -365,6 +367,17 @@ impl StateExt for State {
|
||||
}
|
||||
}
|
||||
|
||||
/// Sends the message to all clients playing in game
|
||||
fn notify_in_game_clients(&self, msg: ServerInGame) {
|
||||
let msg: ServerMsg = msg.into();
|
||||
for client in (&mut self.ecs().write_storage::<Client>())
|
||||
.join()
|
||||
.filter(|c| c.in_game.is_some())
|
||||
{
|
||||
client.send_msg(msg.clone());
|
||||
}
|
||||
}
|
||||
|
||||
fn delete_entity_recorded(
|
||||
&mut self,
|
||||
entity: EcsEntity,
|
||||
@ -388,7 +401,7 @@ impl StateExt for State {
|
||||
.try_map(|e| uids.get(e).copied())
|
||||
.map(|g| (g, c))
|
||||
})
|
||||
.map(|(g, c)| c.send_in_game(ServerInGameMsg::GroupUpdate(g)));
|
||||
.map(|(g, c)| c.send_msg(ServerInGame::GroupUpdate(g)));
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ use crate::{
|
||||
};
|
||||
use common::{
|
||||
comp::{ForceUpdate, Inventory, InventoryUpdate, Last, Ori, Player, Pos, Vel},
|
||||
msg::{ServerGeneralMsg, ServerInGameMsg},
|
||||
msg::{ServerGeneral, ServerInGame},
|
||||
outcome::Outcome,
|
||||
region::{Event as RegionEvent, RegionMap},
|
||||
span,
|
||||
@ -128,14 +128,13 @@ impl<'a> System<'a> for Sys {
|
||||
(uid, pos, velocities.get(entity), orientations.get(entity))
|
||||
})
|
||||
}) {
|
||||
let create_msg = ServerGeneralMsg::CreateEntity(
|
||||
tracked_comps.create_entity_package(
|
||||
let create_msg =
|
||||
ServerGeneral::CreateEntity(tracked_comps.create_entity_package(
|
||||
entity,
|
||||
Some(*pos),
|
||||
vel.copied(),
|
||||
ori.copied(),
|
||||
),
|
||||
);
|
||||
));
|
||||
for (client, regions, client_entity, _) in &mut subscribers {
|
||||
if maybe_key
|
||||
.as_ref()
|
||||
@ -158,7 +157,7 @@ impl<'a> System<'a> for Sys {
|
||||
.map(|key| !regions.contains(key))
|
||||
.unwrap_or(true)
|
||||
{
|
||||
client.send_msg(ServerGeneralMsg::DeleteEntity(uid));
|
||||
client.send_msg(ServerGeneral::DeleteEntity(uid));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -175,14 +174,14 @@ impl<'a> System<'a> for Sys {
|
||||
.take_deleted_in_region(key)
|
||||
.unwrap_or_default(),
|
||||
);
|
||||
let entity_sync_msg = ServerGeneralMsg::EntitySync(entity_sync_package);
|
||||
let comp_sync_msg = ServerGeneralMsg::CompSync(comp_sync_package);
|
||||
let entity_sync_msg = ServerGeneral::EntitySync(entity_sync_package);
|
||||
let comp_sync_msg = ServerGeneral::CompSync(comp_sync_package);
|
||||
subscribers.iter_mut().for_each(move |(client, _, _, _)| {
|
||||
client.send_msg(entity_sync_msg.clone());
|
||||
client.send_msg(comp_sync_msg.clone());
|
||||
});
|
||||
|
||||
let mut send_msg = |msg: ServerGeneralMsg,
|
||||
let mut send_msg = |msg: ServerGeneral,
|
||||
entity: EcsEntity,
|
||||
pos: Pos,
|
||||
force_update: Option<&ForceUpdate>,
|
||||
@ -288,7 +287,7 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
|
||||
send_msg(
|
||||
ServerGeneralMsg::CompSync(comp_sync_package),
|
||||
ServerGeneral::CompSync(comp_sync_package),
|
||||
entity,
|
||||
pos,
|
||||
force_update,
|
||||
@ -312,7 +311,7 @@ impl<'a> System<'a> for Sys {
|
||||
})
|
||||
{
|
||||
for uid in &deleted {
|
||||
client.send_msg(ServerGeneralMsg::DeleteEntity(Uid(*uid)));
|
||||
client.send_msg(ServerGeneral::DeleteEntity(Uid(*uid)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -321,7 +320,7 @@ impl<'a> System<'a> for Sys {
|
||||
|
||||
// Sync inventories
|
||||
for (client, inventory, update) in (&mut clients, &inventories, &inventory_updates).join() {
|
||||
client.send_in_game(ServerInGameMsg::InventoryUpdate(
|
||||
client.send_msg(ServerInGame::InventoryUpdate(
|
||||
inventory.clone(),
|
||||
update.event(),
|
||||
));
|
||||
@ -342,7 +341,7 @@ impl<'a> System<'a> for Sys {
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
if !outcomes.is_empty() {
|
||||
client.send_in_game(ServerInGameMsg::Outcomes(outcomes));
|
||||
client.send_msg(ServerInGame::Outcomes(outcomes));
|
||||
}
|
||||
}
|
||||
outcomes.clear();
|
||||
@ -354,7 +353,7 @@ impl<'a> System<'a> for Sys {
|
||||
// Sync resources
|
||||
// TODO: doesn't really belong in this system (rename system or create another
|
||||
// system?)
|
||||
let tof_msg = ServerGeneralMsg::TimeOfDay(*time_of_day);
|
||||
let tof_msg = ServerGeneral::TimeOfDay(*time_of_day);
|
||||
for client in (&mut clients).join() {
|
||||
client.send_msg(tof_msg.clone());
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use super::SysTimer;
|
||||
use crate::client::Client;
|
||||
use common::{
|
||||
comp::group::{Invite, PendingInvites},
|
||||
msg::{InviteAnswer, ServerInGameMsg},
|
||||
msg::{InviteAnswer, ServerInGame},
|
||||
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_in_game(ServerInGameMsg::InviteComplete {
|
||||
client.send_msg(ServerInGame::InviteComplete {
|
||||
target,
|
||||
answer: InviteAnswer::TimedOut,
|
||||
})
|
||||
|
@ -15,10 +15,10 @@ use common::{
|
||||
},
|
||||
event::{EventBus, ServerEvent},
|
||||
msg::{
|
||||
validate_chat_msg, CharacterInfo, ChatMsgValidationError, ClientCharacterScreenMsg,
|
||||
ClientGeneralMsg, ClientInGameMsg, ClientIngame, ClientRegisterMsg, DisconnectReason,
|
||||
PingMsg, PlayerInfo, PlayerListUpdate, RegisterError, ServerCharacterScreenMsg,
|
||||
ServerGeneralMsg, ServerInGameMsg, ServerRegisterAnswerMsg, MAX_BYTES_CHAT_MSG,
|
||||
validate_chat_msg, CharacterInfo, ChatMsgValidationError, ClientCharacterScreen,
|
||||
ClientGeneral, ClientInGame, ClientIngame, ClientRegister, DisconnectReason, PingMsg,
|
||||
PlayerInfo, PlayerListUpdate, RegisterError, ServerCharacterScreen, ServerGeneral,
|
||||
ServerInGame, ServerRegisterAnswer, MAX_BYTES_CHAT_MSG,
|
||||
},
|
||||
span,
|
||||
state::{BlockChange, Time},
|
||||
@ -45,10 +45,10 @@ impl Sys {
|
||||
player_metrics: &ReadExpect<'_, PlayerMetrics>,
|
||||
uids: &ReadStorage<'_, Uid>,
|
||||
chat_modes: &ReadStorage<'_, ChatMode>,
|
||||
msg: ClientGeneralMsg,
|
||||
msg: ClientGeneral,
|
||||
) -> Result<(), crate::error::Error> {
|
||||
match msg {
|
||||
ClientGeneralMsg::ChatMsg(message) => {
|
||||
ClientGeneral::ChatMsg(message) => {
|
||||
if client.registered {
|
||||
match validate_chat_msg(&message) {
|
||||
Ok(()) => {
|
||||
@ -68,10 +68,10 @@ impl Sys {
|
||||
}
|
||||
}
|
||||
},
|
||||
ClientGeneralMsg::Disconnect => {
|
||||
client.send_msg(ServerGeneralMsg::Disconnect(DisconnectReason::Requested));
|
||||
ClientGeneral::Disconnect => {
|
||||
client.send_msg(ServerGeneral::Disconnect(DisconnectReason::Requested));
|
||||
},
|
||||
ClientGeneralMsg::Terminate => {
|
||||
ClientGeneral::Terminate => {
|
||||
debug!(?entity, "Client send message to termitate session");
|
||||
player_metrics
|
||||
.clients_disconnected
|
||||
@ -100,24 +100,24 @@ impl Sys {
|
||||
players: &mut WriteStorage<'_, Player>,
|
||||
controllers: &mut WriteStorage<'_, Controller>,
|
||||
settings: &Read<'_, Settings>,
|
||||
msg: ClientInGameMsg,
|
||||
msg: ClientInGame,
|
||||
) -> 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, ClientInGameMsg::TerrainChunkRequest{ .. }) {
|
||||
if matches!(msg, ClientInGame::TerrainChunkRequest{ .. }) {
|
||||
network_metrics.chunks_request_dropped.inc();
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
match msg {
|
||||
// Go back to registered state (char selection screen)
|
||||
ClientInGameMsg::ExitInGame => {
|
||||
ClientInGame::ExitInGame => {
|
||||
client.in_game = None;
|
||||
server_emitter.emit(ServerEvent::ExitIngame { entity });
|
||||
client.send_in_game(ServerInGameMsg::ExitInGameSuccess);
|
||||
client.send_msg(ServerInGame::ExitInGameSuccess);
|
||||
},
|
||||
ClientInGameMsg::SetViewDistance(view_distance) => {
|
||||
ClientInGame::SetViewDistance(view_distance) => {
|
||||
players.get_mut(entity).map(|player| {
|
||||
player.view_distance = Some(
|
||||
settings
|
||||
@ -133,19 +133,19 @@ impl Sys {
|
||||
.map(|max| view_distance > max)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
client.send_in_game(ServerInGameMsg::SetViewDistance(
|
||||
client.send_msg(ServerInGame::SetViewDistance(
|
||||
settings.max_view_distance.unwrap_or(0),
|
||||
));
|
||||
}
|
||||
},
|
||||
ClientInGameMsg::ControllerInputs(inputs) => {
|
||||
ClientInGame::ControllerInputs(inputs) => {
|
||||
if let Some(ClientIngame::Character) = client.in_game {
|
||||
if let Some(controller) = controllers.get_mut(entity) {
|
||||
controller.inputs.update_with_new(inputs);
|
||||
}
|
||||
}
|
||||
},
|
||||
ClientInGameMsg::ControlEvent(event) => {
|
||||
ClientInGame::ControlEvent(event) => {
|
||||
if let Some(ClientIngame::Character) = client.in_game {
|
||||
// Skip respawn if client entity is alive
|
||||
if let ControlEvent::Respawn = event {
|
||||
@ -159,14 +159,14 @@ impl Sys {
|
||||
}
|
||||
}
|
||||
},
|
||||
ClientInGameMsg::ControlAction(event) => {
|
||||
ClientInGame::ControlAction(event) => {
|
||||
if let Some(ClientIngame::Character) = client.in_game {
|
||||
if let Some(controller) = controllers.get_mut(entity) {
|
||||
controller.actions.push(event);
|
||||
}
|
||||
}
|
||||
},
|
||||
ClientInGameMsg::PlayerPhysics { pos, vel, ori } => {
|
||||
ClientInGame::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 {
|
||||
}
|
||||
}
|
||||
},
|
||||
ClientInGameMsg::BreakBlock(pos) => {
|
||||
ClientInGame::BreakBlock(pos) => {
|
||||
if let Some(block) = can_build.get(entity).and_then(|_| terrain.get(pos).ok()) {
|
||||
block_changes.set(pos, block.into_vacant());
|
||||
}
|
||||
},
|
||||
ClientInGameMsg::PlaceBlock(pos, block) => {
|
||||
ClientInGame::PlaceBlock(pos, block) => {
|
||||
if can_build.get(entity).is_some() {
|
||||
block_changes.try_set(pos, block);
|
||||
}
|
||||
},
|
||||
ClientInGameMsg::TerrainChunkRequest { key } => {
|
||||
ClientInGame::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_in_game(ServerInGameMsg::TerrainChunkUpdate {
|
||||
client.send_msg(ServerInGame::TerrainChunkUpdate {
|
||||
key,
|
||||
chunk: Ok(Box::new(chunk.clone())),
|
||||
})
|
||||
@ -217,17 +217,17 @@ impl Sys {
|
||||
network_metrics.chunks_request_dropped.inc();
|
||||
}
|
||||
},
|
||||
ClientInGameMsg::UnlockSkill(skill) => {
|
||||
ClientInGame::UnlockSkill(skill) => {
|
||||
stats
|
||||
.get_mut(entity)
|
||||
.map(|s| s.skill_set.unlock_skill(skill));
|
||||
},
|
||||
ClientInGameMsg::RefundSkill(skill) => {
|
||||
ClientInGame::RefundSkill(skill) => {
|
||||
stats
|
||||
.get_mut(entity)
|
||||
.map(|s| s.skill_set.refund_skill(skill));
|
||||
},
|
||||
ClientInGameMsg::UnlockSkillGroup(skill_group_type) => {
|
||||
ClientInGame::UnlockSkillGroup(skill_group_type) => {
|
||||
stats
|
||||
.get_mut(entity)
|
||||
.map(|s| s.skill_set.unlock_skill_group(skill_group_type));
|
||||
@ -247,18 +247,18 @@ impl Sys {
|
||||
players: &mut WriteStorage<'_, Player>,
|
||||
editable_settings: &ReadExpect<'_, EditableSettings>,
|
||||
alias_validator: &ReadExpect<'_, AliasValidator>,
|
||||
msg: ClientCharacterScreenMsg,
|
||||
msg: ClientCharacterScreen,
|
||||
) -> Result<(), crate::error::Error> {
|
||||
match msg {
|
||||
// Request spectator state
|
||||
ClientCharacterScreenMsg::Spectate => {
|
||||
ClientCharacterScreen::Spectate => {
|
||||
if client.registered {
|
||||
client.in_game = Some(ClientIngame::Spectator)
|
||||
} else {
|
||||
debug!("dropped Spectate msg from unregistered client");
|
||||
}
|
||||
},
|
||||
ClientCharacterScreenMsg::Character(character_id) => {
|
||||
ClientCharacterScreen::Character(character_id) => {
|
||||
if client.registered && client.in_game.is_none() {
|
||||
// Only send login message if it wasn't already
|
||||
// sent previously
|
||||
@ -301,11 +301,9 @@ impl Sys {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
client.send_character_screen(
|
||||
ServerCharacterScreenMsg::CharacterDataLoadError(String::from(
|
||||
"Failed to fetch player entity",
|
||||
)),
|
||||
)
|
||||
client.send_msg(ServerCharacterScreen::CharacterDataLoadError(
|
||||
String::from("Failed to fetch player entity"),
|
||||
))
|
||||
}
|
||||
} else {
|
||||
let registered = client.registered;
|
||||
@ -313,15 +311,15 @@ impl Sys {
|
||||
debug!(?registered, ?in_game, "dropped Character msg from client");
|
||||
}
|
||||
},
|
||||
ClientCharacterScreenMsg::RequestCharacterList => {
|
||||
ClientCharacterScreen::RequestCharacterList => {
|
||||
if let Some(player) = players.get(entity) {
|
||||
character_loader.load_character_list(entity, player.uuid().to_string())
|
||||
}
|
||||
},
|
||||
ClientCharacterScreenMsg::CreateCharacter { alias, tool, body } => {
|
||||
ClientCharacterScreen::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_character_screen(ServerCharacterScreenMsg::CharacterActionError(
|
||||
client.send_msg(ServerCharacterScreen::CharacterActionError(
|
||||
error.to_string(),
|
||||
));
|
||||
} else if let Some(player) = players.get(entity) {
|
||||
@ -335,7 +333,7 @@ impl Sys {
|
||||
);
|
||||
}
|
||||
},
|
||||
ClientCharacterScreenMsg::DeleteCharacter(character_id) => {
|
||||
ClientCharacterScreen::DeleteCharacter(character_id) => {
|
||||
if let Some(player) = players.get(entity) {
|
||||
character_loader.delete_character(
|
||||
entity,
|
||||
@ -351,7 +349,7 @@ impl Sys {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn handle_ping_msg(client: &mut Client, msg: PingMsg) -> Result<(), crate::error::Error> {
|
||||
match msg {
|
||||
PingMsg::Ping => client.send_ping(PingMsg::Pong),
|
||||
PingMsg::Ping => client.send_msg(PingMsg::Pong),
|
||||
PingMsg::Pong => {},
|
||||
}
|
||||
Ok(())
|
||||
@ -368,7 +366,7 @@ impl Sys {
|
||||
admins: &mut WriteStorage<'_, Admin>,
|
||||
players: &mut WriteStorage<'_, Player>,
|
||||
editable_settings: &ReadExpect<'_, EditableSettings>,
|
||||
msg: ClientRegisterMsg,
|
||||
msg: ClientRegister,
|
||||
) -> Result<(), crate::error::Error> {
|
||||
let (username, uuid) = match login_provider.try_login(
|
||||
&msg.token_or_username,
|
||||
@ -379,7 +377,7 @@ impl Sys {
|
||||
Err(err) => {
|
||||
client
|
||||
.register_stream
|
||||
.send(ServerRegisterAnswerMsg::Err(err))?;
|
||||
.send(ServerRegisterAnswer::Err(err))?;
|
||||
return Ok(());
|
||||
},
|
||||
Ok((username, uuid)) => (username, uuid),
|
||||
@ -391,9 +389,9 @@ impl Sys {
|
||||
|
||||
if !player.is_valid() {
|
||||
// Invalid player
|
||||
client.register_stream.send(ServerRegisterAnswerMsg::Err(
|
||||
RegisterError::InvalidCharacter,
|
||||
))?;
|
||||
client
|
||||
.register_stream
|
||||
.send(ServerRegisterAnswer::Err(RegisterError::InvalidCharacter))?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@ -410,12 +408,10 @@ impl Sys {
|
||||
|
||||
// Tell the client its request was successful.
|
||||
client.registered = true;
|
||||
client
|
||||
.register_stream
|
||||
.send(ServerRegisterAnswerMsg::Ok(()))?;
|
||||
client.register_stream.send(ServerRegisterAnswer::Ok(()))?;
|
||||
|
||||
// Send initial player list
|
||||
client.send_msg(ServerGeneralMsg::PlayerListUpdate(PlayerListUpdate::Init(
|
||||
client.send_msg(ServerGeneral::PlayerListUpdate(PlayerListUpdate::Init(
|
||||
player_list.clone(),
|
||||
)));
|
||||
|
||||
@ -458,7 +454,7 @@ impl Sys {
|
||||
alias_validator: &ReadExpect<'_, AliasValidator>,
|
||||
) -> Result<(), crate::error::Error> {
|
||||
loop {
|
||||
let q1 = Client::internal_recv(&client.network_error, &mut client.singleton_stream);
|
||||
let q1 = Client::internal_recv(&client.network_error, &mut client.general_stream);
|
||||
let q2 = Client::internal_recv(&client.network_error, &mut client.in_game_stream);
|
||||
let q3 =
|
||||
Client::internal_recv(&client.network_error, &mut client.character_screen_stream);
|
||||
@ -693,7 +689,7 @@ impl<'a> System<'a> for Sys {
|
||||
server_emitter.emit(ServerEvent::ClientDisconnect(entity));
|
||||
} else if time.0 - client.last_ping > settings.client_timeout.as_secs() as f64 * 0.5 {
|
||||
// Try pinging the client if the timeout is nearing.
|
||||
client.send_ping(PingMsg::Ping);
|
||||
client.send_msg(PingMsg::Ping);
|
||||
}
|
||||
}
|
||||
|
||||
@ -702,7 +698,7 @@ impl<'a> System<'a> for Sys {
|
||||
for entity in new_players {
|
||||
if let (Some(uid), Some(player)) = (uids.get(entity), players.get(entity)) {
|
||||
let msg =
|
||||
ServerGeneralMsg::PlayerListUpdate(PlayerListUpdate::Add(*uid, PlayerInfo {
|
||||
ServerGeneral::PlayerListUpdate(PlayerListUpdate::Add(*uid, PlayerInfo {
|
||||
player_alias: player.alias.clone(),
|
||||
is_online: true,
|
||||
is_admin: admins.get(entity).is_some(),
|
||||
|
@ -5,7 +5,7 @@ use super::{
|
||||
use crate::client::{self, Client, RegionSubscription};
|
||||
use common::{
|
||||
comp::{Ori, Player, Pos, Vel},
|
||||
msg::ServerGeneralMsg,
|
||||
msg::ServerGeneral,
|
||||
region::{region_in_vd, regions_in_vd, Event as RegionEvent, RegionMap},
|
||||
span,
|
||||
sync::Uid,
|
||||
@ -153,7 +153,7 @@ impl<'a> System<'a> for Sys {
|
||||
.map(|key| subscription.regions.contains(key))
|
||||
.unwrap_or(false)
|
||||
{
|
||||
client.send_msg(ServerGeneralMsg::DeleteEntity(uid));
|
||||
client.send_msg(ServerGeneral::DeleteEntity(uid));
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -161,7 +161,7 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
// Tell client to delete entities in the region
|
||||
for (&uid, _) in (&uids, region.entities()).join() {
|
||||
client.send_msg(ServerGeneralMsg::DeleteEntity(uid));
|
||||
client.send_msg(ServerGeneral::DeleteEntity(uid));
|
||||
}
|
||||
}
|
||||
// Send deleted entities since they won't be processed for this client in entity
|
||||
@ -171,7 +171,7 @@ impl<'a> System<'a> for Sys {
|
||||
.iter()
|
||||
.flat_map(|v| v.iter())
|
||||
{
|
||||
client.send_msg(ServerGeneralMsg::DeleteEntity(Uid(*uid)));
|
||||
client.send_msg(ServerGeneral::DeleteEntity(Uid(*uid)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -196,7 +196,7 @@ impl<'a> System<'a> for Sys {
|
||||
{
|
||||
// Send message to create entity and tracked components and physics
|
||||
// components
|
||||
client.send_msg(ServerGeneralMsg::CreateEntity(
|
||||
client.send_msg(ServerGeneral::CreateEntity(
|
||||
tracked_comps.create_entity_package(
|
||||
entity,
|
||||
Some(*pos),
|
||||
@ -249,7 +249,7 @@ pub fn initialize_region_subscription(world: &World, entity: specs::Entity) {
|
||||
.join()
|
||||
{
|
||||
// Send message to create entity and tracked components and physics components
|
||||
client.send_msg(ServerGeneralMsg::CreateEntity(
|
||||
client.send_msg(ServerGeneral::CreateEntity(
|
||||
tracked_comps.create_entity_package(
|
||||
entity,
|
||||
Some(*pos),
|
||||
|
@ -4,7 +4,7 @@ use common::{
|
||||
comp::{self, bird_medium, Alignment, Player, Pos},
|
||||
event::{EventBus, ServerEvent},
|
||||
generation::get_npc_name,
|
||||
msg::ServerInGameMsg,
|
||||
msg::ServerInGame,
|
||||
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_in_game(ServerInGameMsg::TerrainChunkUpdate {
|
||||
client.send_msg(ServerInGame::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_in_game(ServerInGameMsg::TerrainChunkUpdate {
|
||||
client.send_msg(ServerInGame::TerrainChunkUpdate {
|
||||
key,
|
||||
chunk: Ok(Box::new(chunk.clone())),
|
||||
});
|
||||
|
@ -2,7 +2,7 @@ use super::SysTimer;
|
||||
use crate::client::Client;
|
||||
use common::{
|
||||
comp::{Player, Pos},
|
||||
msg::ServerInGameMsg,
|
||||
msg::ServerInGame,
|
||||
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_in_game(ServerInGameMsg::TerrainChunkUpdate {
|
||||
client.send_msg(ServerInGame::TerrainChunkUpdate {
|
||||
key: *chunk_key,
|
||||
chunk: Ok(Box::new(match terrain.get_key(*chunk_key) {
|
||||
Some(chunk) => chunk.clone(),
|
||||
@ -51,10 +51,10 @@ impl<'a> System<'a> for Sys {
|
||||
|
||||
// TODO: Don't send all changed blocks to all clients
|
||||
// Sync changed blocks
|
||||
let msg = ServerInGameMsg::TerrainBlockUpdates(terrain_changes.modified_blocks.clone());
|
||||
let msg = ServerInGame::TerrainBlockUpdates(terrain_changes.modified_blocks.clone());
|
||||
for (player, client) in (&players, &mut clients).join() {
|
||||
if player.view_distance.is_some() {
|
||||
client.send_in_game(msg.clone());
|
||||
client.send_msg(msg.clone());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@ use super::SysTimer;
|
||||
use crate::client::Client;
|
||||
use common::{
|
||||
comp::{Player, Pos, Waypoint, WaypointArea},
|
||||
msg::{Notification, ServerGeneralMsg},
|
||||
msg::{Notification, ServerGeneral},
|
||||
span,
|
||||
state::Time,
|
||||
};
|
||||
@ -42,9 +42,8 @@ impl<'a> System<'a> for Sys {
|
||||
if let Ok(wp_old) = waypoints.insert(entity, Waypoint::new(player_pos.0, *time))
|
||||
{
|
||||
if wp_old.map_or(true, |w| w.elapsed(*time) > NOTIFY_TIME) {
|
||||
client.send_msg(ServerGeneralMsg::Notification(
|
||||
Notification::WaypointSaved,
|
||||
));
|
||||
client
|
||||
.send_msg(ServerGeneral::Notification(Notification::WaypointSaved));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ use crate::{
|
||||
use common::{
|
||||
comp::{self, bird_medium, quadruped_low, quadruped_medium, quadruped_small},
|
||||
generation::{ChunkSupplement, EntityInfo},
|
||||
msg::server::WorldMapMsg,
|
||||
msg::WorldMapMsg,
|
||||
terrain::{Block, BlockKind, SpriteKind, TerrainChunk, TerrainChunkMeta, TerrainChunkSize},
|
||||
vol::{ReadVol, RectVolSize, WriteVol},
|
||||
};
|
||||
|
@ -33,7 +33,7 @@ use crate::{
|
||||
};
|
||||
use common::{
|
||||
assets,
|
||||
msg::server::WorldMapMsg,
|
||||
msg::WorldMapMsg,
|
||||
store::Id,
|
||||
terrain::{
|
||||
map::MapConfig, uniform_idx_as_vec2, vec2_as_uniform_idx, BiomeKind, MapSizeLg,
|
||||
|
Loading…
Reference in New Issue
Block a user