Add LoD zone data to char select screen

This commit is contained in:
Joshua Barretto 2024-01-14 22:27:34 +00:00
parent 5d4133eea5
commit 5bc60f2436
7 changed files with 78 additions and 65 deletions

View File

@ -242,6 +242,7 @@ pub struct Client {
available_recipes: HashMap<String, Option<SpriteKind>>, available_recipes: HashMap<String, Option<SpriteKind>>,
lod_zones: HashMap<Vec2<i32>, lod::Zone>, lod_zones: HashMap<Vec2<i32>, lod::Zone>,
lod_last_requested: Option<Instant>, lod_last_requested: Option<Instant>,
lod_pos_fallback: Option<Vec2<f32>>,
force_update_counter: u64, force_update_counter: u64,
max_group_size: u32, max_group_size: u32,
@ -753,6 +754,7 @@ impl Client {
lod_zones: HashMap::new(), lod_zones: HashMap::new(),
lod_last_requested: None, lod_last_requested: None,
lod_pos_fallback: None,
force_update_counter: 0, force_update_counter: 0,
@ -890,7 +892,7 @@ impl Client {
| ClientGeneral::DeleteCharacter(_) | ClientGeneral::DeleteCharacter(_)
| ClientGeneral::Character(_, _) | ClientGeneral::Character(_, _)
| ClientGeneral::Spectate(_) => &mut self.character_screen_stream, | ClientGeneral::Spectate(_) => &mut self.character_screen_stream,
//Only in game // Only in game
ClientGeneral::ControllerInputs(_) ClientGeneral::ControllerInputs(_)
| ClientGeneral::ControlEvent(_) | ClientGeneral::ControlEvent(_)
| ClientGeneral::ControlAction(_) | ClientGeneral::ControlAction(_)
@ -911,7 +913,7 @@ impl Client {
} }
&mut self.in_game_stream &mut self.in_game_stream
}, },
//Only in game, terrain // Terrain
ClientGeneral::TerrainChunkRequest { .. } ClientGeneral::TerrainChunkRequest { .. }
| ClientGeneral::LodZoneRequest { .. } => { | ClientGeneral::LodZoneRequest { .. } => {
#[cfg(feature = "tracy")] #[cfg(feature = "tracy")]
@ -920,7 +922,7 @@ impl Client {
} }
&mut self.terrain_stream &mut self.terrain_stream
}, },
//Always possible // Always possible
ClientGeneral::ChatMsg(_) ClientGeneral::ChatMsg(_)
| ClientGeneral::Command(_, _) | ClientGeneral::Command(_, _)
| ClientGeneral::Terminate => &mut self.general_stream, | ClientGeneral::Terminate => &mut self.general_stream,
@ -1196,6 +1198,10 @@ impl Client {
pub fn lod_zones(&self) -> &HashMap<Vec2<i32>, lod::Zone> { &self.lod_zones } pub fn lod_zones(&self) -> &HashMap<Vec2<i32>, 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<f32>) { self.lod_pos_fallback = Some(pos); }
/// Returns whether the specified recipe can be crafted and the sprite, if /// Returns whether the specified recipe can be crafted and the sprite, if
/// any, that is required to do so. /// any, that is required to do so.
pub fn can_craft_recipe(&self, recipe: &str, amount: u32) -> (bool, Option<SpriteKind>) { pub fn can_craft_recipe(&self, recipe: &str, amount: u32) -> (bool, Option<SpriteKind>) {
@ -2088,9 +2094,11 @@ impl Client {
let now = Instant::now(); let now = Instant::now();
self.pending_chunks self.pending_chunks
.retain(|_, created| now.duration_since(*created) < Duration::from_secs(3)); .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 // 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 // Request LoD zones that are in range
if self if self

View File

@ -128,7 +128,6 @@ impl ClientMsg {
| ClientGeneral::ExitInGame | ClientGeneral::ExitInGame
| ClientGeneral::PlayerPhysics { .. } | ClientGeneral::PlayerPhysics { .. }
| ClientGeneral::TerrainChunkRequest { .. } | ClientGeneral::TerrainChunkRequest { .. }
| ClientGeneral::LodZoneRequest { .. }
| ClientGeneral::UnlockSkill(_) | ClientGeneral::UnlockSkill(_)
| ClientGeneral::RequestSiteInfo(_) | ClientGeneral::RequestSiteInfo(_)
| ClientGeneral::RequestPlayerPhysics { .. } | ClientGeneral::RequestPlayerPhysics { .. }
@ -140,7 +139,9 @@ impl ClientMsg {
//Always possible //Always possible
ClientGeneral::ChatMsg(_) ClientGeneral::ChatMsg(_)
| ClientGeneral::Command(_, _) | ClientGeneral::Command(_, _)
| ClientGeneral::Terminate => true, | ClientGeneral::Terminate
// LodZoneRequest is required by the char select screen
| ClientGeneral::LodZoneRequest { .. } => true,
} }
}, },
ClientMsg::Ping(_) => true, ClientMsg::Ping(_) => true,

View File

@ -324,7 +324,6 @@ impl ServerMsg {
| ServerGeneral::InventoryUpdate(_, _) | ServerGeneral::InventoryUpdate(_, _)
| ServerGeneral::GroupInventoryUpdate(_, _, _) | ServerGeneral::GroupInventoryUpdate(_, _, _)
| ServerGeneral::TerrainChunkUpdate { .. } | ServerGeneral::TerrainChunkUpdate { .. }
| ServerGeneral::LodZoneUpdate { .. }
| ServerGeneral::TerrainBlockUpdates(_) | ServerGeneral::TerrainBlockUpdates(_)
| ServerGeneral::SetViewDistance(_) | ServerGeneral::SetViewDistance(_)
| ServerGeneral::Outcomes(_) | ServerGeneral::Outcomes(_)
@ -348,7 +347,8 @@ impl ServerMsg {
| ServerGeneral::CreateEntity(_) | ServerGeneral::CreateEntity(_)
| ServerGeneral::DeleteEntity(_) | ServerGeneral::DeleteEntity(_)
| ServerGeneral::Disconnect(_) | ServerGeneral::Disconnect(_)
| ServerGeneral::Notification(_) => true, | ServerGeneral::Notification(_)
| ServerGeneral::LodZoneUpdate { .. } => true,
} }
}, },
ServerMsg::Ping(_) => true, ServerMsg::Ping(_) => true,

View File

@ -192,7 +192,7 @@ impl Client {
| ServerGeneral::SpectatePosition(_) => { | ServerGeneral::SpectatePosition(_) => {
PreparedMsg::new(2, &g, &self.in_game_stream_params) PreparedMsg::new(2, &g, &self.in_game_stream_params)
}, },
//In-game related, terrain // Terrain
ServerGeneral::TerrainChunkUpdate { .. } ServerGeneral::TerrainChunkUpdate { .. }
| ServerGeneral::LodZoneUpdate { .. } | ServerGeneral::LodZoneUpdate { .. }
| ServerGeneral::TerrainBlockUpdates(_) => { | ServerGeneral::TerrainBlockUpdates(_) => {

View File

@ -61,61 +61,63 @@ impl<'a> System<'a> for Sys {
|(chunk_send_emitter, server_emitter), (entity, client, maybe_presence)| { |(chunk_send_emitter, server_emitter), (entity, client, maybe_presence)| {
let mut chunk_requests = Vec::new(); let mut chunk_requests = Vec::new();
let _ = super::try_recv_all(client, 5, |client, msg| { let _ = super::try_recv_all(client, 5, |client, msg| {
let presence = match maybe_presence { // SPECIAL CASE: LOD zone requests can be sent by non-present players
Some(g) => g, if let ClientGeneral::LodZoneRequest { key } = &msg {
None => { client.send(ServerGeneral::LodZoneUpdate {
debug!(?entity, "client is not in_game, ignoring msg"); key: *key,
trace!(?msg, "ignored msg content"); zone: lod.zone(*key).clone(),
if matches!(msg, ClientGeneral::TerrainChunkRequest { .. }) { })?;
network_metrics.chunks_request_dropped.inc(); } else {
} let presence = match maybe_presence {
return Ok(()); Some(g) => g,
}, None => {
}; debug!(?entity, "client is not in_game, ignoring msg");
match msg { trace!(?msg, "ignored msg content");
ClientGeneral::TerrainChunkRequest { key } => { if matches!(msg, ClientGeneral::TerrainChunkRequest { .. }) {
let in_vd = if let Some(pos) = positions.get(entity) { network_metrics.chunks_request_dropped.inc();
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 { return Ok(());
network_metrics.chunks_request_dropped.inc(); },
} };
}, match msg {
ClientGeneral::LodZoneRequest { key } => { ClientGeneral::TerrainChunkRequest { key } => {
client.send(ServerGeneral::LodZoneUpdate { let in_vd = if let Some(pos) = positions.get(entity) {
key, pos.0.xy().map(|e| e as f64).distance_squared(
zone: lod.zone(key).clone(), 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())
debug!( * TerrainChunkSize::RECT_SIZE.x as f64)
"Kicking possibly misbehaving client due to invalud terrain \ .powi(2)
request" } else {
); true
server_emitter.emit(ServerEvent::ClientDisconnect( };
entity, if in_vd {
common::comp::DisconnectReason::NetworkError, 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(()) Ok(())
}); });

View File

@ -27,7 +27,7 @@ impl CharSelectionState {
pub fn new(global_state: &mut GlobalState, client: Rc<RefCell<Client>>) -> Self { pub fn new(global_state: &mut GlobalState, client: Rc<RefCell<Client>>) -> Self {
let scene = Scene::new( let scene = Scene::new(
global_state.window.renderer_mut(), global_state.window.renderer_mut(),
&client.borrow(), &mut client.borrow_mut(),
&global_state.settings, &global_state.settings,
); );
let char_selection_ui = CharSelectionUi::new(global_state, &client.borrow()); let char_selection_ui = CharSelectionUi::new(global_state, &client.borrow());

View File

@ -96,7 +96,7 @@ pub struct SceneData<'a> {
} }
impl Scene { 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 start_angle = -90.0f32.to_radians();
let resolution = renderer.resolution().map(|e| e as f32); let resolution = renderer.resolution().map(|e| e as f32);
@ -132,6 +132,8 @@ impl Scene {
.get(char_chunk) .get(char_chunk)
.map_or(0.0, |z| *z as f32 + 100.0), .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 { Self {
data, data,