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>>,
lod_zones: HashMap<Vec2<i32>, lod::Zone>,
lod_last_requested: Option<Instant>,
lod_pos_fallback: Option<Vec2<f32>>,
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<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
/// any, that is required to do so.
pub fn can_craft_recipe(&self, recipe: &str, amount: u32) -> (bool, Option<SpriteKind>) {
@ -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

View File

@ -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,

View File

@ -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,

View File

@ -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(_) => {

View File

@ -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(())
});

View File

@ -27,7 +27,7 @@ impl CharSelectionState {
pub fn new(global_state: &mut GlobalState, client: Rc<RefCell<Client>>) -> 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());

View File

@ -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,