From 5bc60f2436783b32ce9f1b929094efbf2deb98a3 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Sun, 14 Jan 2024 22:27:34 +0000 Subject: [PATCH] Add LoD zone data to char select screen --- client/src/lib.rs | 16 +++- common/net/src/msg/client.rs | 5 +- common/net/src/msg/server.rs | 4 +- server/src/client.rs | 2 +- server/src/sys/msg/terrain.rs | 110 +++++++++++++------------ voxygen/src/menu/char_selection/mod.rs | 2 +- voxygen/src/scene/simple.rs | 4 +- 7 files changed, 78 insertions(+), 65 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index 6977133a8f..1ea5995b40 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -242,6 +242,7 @@ pub struct Client { available_recipes: HashMap>, lod_zones: HashMap, lod::Zone>, lod_last_requested: Option, + lod_pos_fallback: Option>, force_update_counter: u64, max_group_size: u32, @@ -753,6 +754,7 @@ impl Client { lod_zones: HashMap::new(), lod_last_requested: None, + lod_pos_fallback: None, force_update_counter: 0, @@ -890,7 +892,7 @@ impl Client { | ClientGeneral::DeleteCharacter(_) | ClientGeneral::Character(_, _) | ClientGeneral::Spectate(_) => &mut self.character_screen_stream, - //Only in game + // Only in game ClientGeneral::ControllerInputs(_) | ClientGeneral::ControlEvent(_) | ClientGeneral::ControlAction(_) @@ -911,7 +913,7 @@ impl Client { } &mut self.in_game_stream }, - //Only in game, terrain + // Terrain ClientGeneral::TerrainChunkRequest { .. } | ClientGeneral::LodZoneRequest { .. } => { #[cfg(feature = "tracy")] @@ -920,7 +922,7 @@ impl Client { } &mut self.terrain_stream }, - //Always possible + // Always possible ClientGeneral::ChatMsg(_) | ClientGeneral::Command(_, _) | ClientGeneral::Terminate => &mut self.general_stream, @@ -1196,6 +1198,10 @@ impl Client { pub fn lod_zones(&self) -> &HashMap, lod::Zone> { &self.lod_zones } + /// Set the fallback position used for loading LoD zones when the client + /// entity does not have a position. + pub fn set_lod_pos_fallback(&mut self, pos: Vec2) { self.lod_pos_fallback = Some(pos); } + /// Returns whether the specified recipe can be crafted and the sprite, if /// any, that is required to do so. pub fn can_craft_recipe(&self, recipe: &str, amount: u32) -> (bool, Option) { @@ -2088,9 +2094,11 @@ impl Client { let now = Instant::now(); self.pending_chunks .retain(|_, created| now.duration_since(*created) < Duration::from_secs(3)); + } + if let Some(lod_pos) = pos.map(|p| p.0.xy()).or(self.lod_pos_fallback) { // Manage LoD zones - let lod_zone = pos.0.xy().map(|e| lod::from_wpos(e as i32)); + let lod_zone = lod_pos.map(|e| lod::from_wpos(e as i32)); // Request LoD zones that are in range if self diff --git a/common/net/src/msg/client.rs b/common/net/src/msg/client.rs index f752db223d..be4d2f5e91 100644 --- a/common/net/src/msg/client.rs +++ b/common/net/src/msg/client.rs @@ -128,7 +128,6 @@ impl ClientMsg { | ClientGeneral::ExitInGame | ClientGeneral::PlayerPhysics { .. } | ClientGeneral::TerrainChunkRequest { .. } - | ClientGeneral::LodZoneRequest { .. } | ClientGeneral::UnlockSkill(_) | ClientGeneral::RequestSiteInfo(_) | ClientGeneral::RequestPlayerPhysics { .. } @@ -140,7 +139,9 @@ impl ClientMsg { //Always possible ClientGeneral::ChatMsg(_) | ClientGeneral::Command(_, _) - | ClientGeneral::Terminate => true, + | ClientGeneral::Terminate + // LodZoneRequest is required by the char select screen + | ClientGeneral::LodZoneRequest { .. } => true, } }, ClientMsg::Ping(_) => true, diff --git a/common/net/src/msg/server.rs b/common/net/src/msg/server.rs index d626017eaf..9ad6c8f5b4 100644 --- a/common/net/src/msg/server.rs +++ b/common/net/src/msg/server.rs @@ -324,7 +324,6 @@ impl ServerMsg { | ServerGeneral::InventoryUpdate(_, _) | ServerGeneral::GroupInventoryUpdate(_, _, _) | ServerGeneral::TerrainChunkUpdate { .. } - | ServerGeneral::LodZoneUpdate { .. } | ServerGeneral::TerrainBlockUpdates(_) | ServerGeneral::SetViewDistance(_) | ServerGeneral::Outcomes(_) @@ -348,7 +347,8 @@ impl ServerMsg { | ServerGeneral::CreateEntity(_) | ServerGeneral::DeleteEntity(_) | ServerGeneral::Disconnect(_) - | ServerGeneral::Notification(_) => true, + | ServerGeneral::Notification(_) + | ServerGeneral::LodZoneUpdate { .. } => true, } }, ServerMsg::Ping(_) => true, diff --git a/server/src/client.rs b/server/src/client.rs index d2a76bf44a..47ea174ffa 100644 --- a/server/src/client.rs +++ b/server/src/client.rs @@ -192,7 +192,7 @@ impl Client { | ServerGeneral::SpectatePosition(_) => { PreparedMsg::new(2, &g, &self.in_game_stream_params) }, - //In-game related, terrain + // Terrain ServerGeneral::TerrainChunkUpdate { .. } | ServerGeneral::LodZoneUpdate { .. } | ServerGeneral::TerrainBlockUpdates(_) => { diff --git a/server/src/sys/msg/terrain.rs b/server/src/sys/msg/terrain.rs index 6c81c837a5..46ecff6570 100644 --- a/server/src/sys/msg/terrain.rs +++ b/server/src/sys/msg/terrain.rs @@ -61,61 +61,63 @@ impl<'a> System<'a> for Sys { |(chunk_send_emitter, server_emitter), (entity, client, maybe_presence)| { let mut chunk_requests = Vec::new(); let _ = super::try_recv_all(client, 5, |client, msg| { - let presence = match maybe_presence { - Some(g) => g, - None => { - debug!(?entity, "client is not in_game, ignoring msg"); - trace!(?msg, "ignored msg content"); - if matches!(msg, ClientGeneral::TerrainChunkRequest { .. }) { - network_metrics.chunks_request_dropped.inc(); - } - return Ok(()); - }, - }; - match msg { - ClientGeneral::TerrainChunkRequest { key } => { - let in_vd = if let Some(pos) = positions.get(entity) { - pos.0.xy().map(|e| e as f64).distance_squared( - key.map(|e| e as f64 + 0.5) - * TerrainChunkSize::RECT_SIZE.map(|e| e as f64), - ) < ((presence.terrain_view_distance.current() as f64 - 1.0 - + 2.5 * 2.0_f64.sqrt()) - * TerrainChunkSize::RECT_SIZE.x as f64) - .powi(2) - } else { - true - }; - if in_vd { - if terrain.get_key_arc(key).is_some() { - network_metrics.chunks_served_from_memory.inc(); - chunk_send_emitter.emit(ChunkSendEntry { - chunk_key: key, - entity, - }); - } else { - network_metrics.chunks_generation_triggered.inc(); - chunk_requests.push(ChunkRequest { entity, key }); + // SPECIAL CASE: LOD zone requests can be sent by non-present players + if let ClientGeneral::LodZoneRequest { key } = &msg { + client.send(ServerGeneral::LodZoneUpdate { + key: *key, + zone: lod.zone(*key).clone(), + })?; + } else { + let presence = match maybe_presence { + Some(g) => g, + None => { + debug!(?entity, "client is not in_game, ignoring msg"); + trace!(?msg, "ignored msg content"); + if matches!(msg, ClientGeneral::TerrainChunkRequest { .. }) { + network_metrics.chunks_request_dropped.inc(); } - } else { - network_metrics.chunks_request_dropped.inc(); - } - }, - ClientGeneral::LodZoneRequest { key } => { - client.send(ServerGeneral::LodZoneUpdate { - key, - zone: lod.zone(key).clone(), - })?; - }, - _ => { - debug!( - "Kicking possibly misbehaving client due to invalud terrain \ - request" - ); - server_emitter.emit(ServerEvent::ClientDisconnect( - entity, - common::comp::DisconnectReason::NetworkError, - )); - }, + return Ok(()); + }, + }; + match msg { + ClientGeneral::TerrainChunkRequest { key } => { + let in_vd = if let Some(pos) = positions.get(entity) { + pos.0.xy().map(|e| e as f64).distance_squared( + key.map(|e| e as f64 + 0.5) + * TerrainChunkSize::RECT_SIZE.map(|e| e as f64), + ) < ((presence.terrain_view_distance.current() as f64 - 1.0 + + 2.5 * 2.0_f64.sqrt()) + * TerrainChunkSize::RECT_SIZE.x as f64) + .powi(2) + } else { + true + }; + if in_vd { + if terrain.get_key_arc(key).is_some() { + network_metrics.chunks_served_from_memory.inc(); + chunk_send_emitter.emit(ChunkSendEntry { + chunk_key: key, + entity, + }); + } else { + network_metrics.chunks_generation_triggered.inc(); + chunk_requests.push(ChunkRequest { entity, key }); + } + } else { + network_metrics.chunks_request_dropped.inc(); + } + }, + _ => { + debug!( + "Kicking possibly misbehaving client due to invalud terrain \ + request" + ); + server_emitter.emit(ServerEvent::ClientDisconnect( + entity, + common::comp::DisconnectReason::NetworkError, + )); + }, + } } Ok(()) }); diff --git a/voxygen/src/menu/char_selection/mod.rs b/voxygen/src/menu/char_selection/mod.rs index 7073a773ed..b60bfed85f 100644 --- a/voxygen/src/menu/char_selection/mod.rs +++ b/voxygen/src/menu/char_selection/mod.rs @@ -27,7 +27,7 @@ impl CharSelectionState { pub fn new(global_state: &mut GlobalState, client: Rc>) -> Self { let scene = Scene::new( global_state.window.renderer_mut(), - &client.borrow(), + &mut client.borrow_mut(), &global_state.settings, ); let char_selection_ui = CharSelectionUi::new(global_state, &client.borrow()); diff --git a/voxygen/src/scene/simple.rs b/voxygen/src/scene/simple.rs index 568c82b9b3..047a94d6a4 100644 --- a/voxygen/src/scene/simple.rs +++ b/voxygen/src/scene/simple.rs @@ -96,7 +96,7 @@ pub struct SceneData<'a> { } impl Scene { - pub fn new(renderer: &mut Renderer, client: &Client, settings: &Settings) -> Self { + pub fn new(renderer: &mut Renderer, client: &mut Client, settings: &Settings) -> Self { let start_angle = -90.0f32.to_radians(); let resolution = renderer.resolution().map(|e| e as f32); @@ -132,6 +132,8 @@ impl Scene { .get(char_chunk) .map_or(0.0, |z| *z as f32 + 100.0), ); + client.set_lod_pos_fallback(char_pos.xy()); + client.set_lod_distance(settings.graphics.lod_distance); Self { data,