mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'imbris/vd_circle' into 'master'
Circular View Distance See merge request veloren/veloren!248
This commit is contained in:
commit
81932ac509
@ -45,6 +45,7 @@ pub struct Client {
|
||||
tick: u64,
|
||||
state: State,
|
||||
entity: EcsEntity,
|
||||
|
||||
view_distance: Option<u32>,
|
||||
loaded_distance: Option<u32>,
|
||||
|
||||
@ -230,9 +231,9 @@ impl Client {
|
||||
let mut chunks_to_remove = Vec::new();
|
||||
self.state.terrain().iter().for_each(|(key, _)| {
|
||||
if (Vec2::from(chunk_pos) - Vec2::from(key))
|
||||
.map(|e: i32| e.abs() as u32)
|
||||
.reduce_max()
|
||||
> view_distance + 1
|
||||
.map(|e: i32| (e.abs() as u32).checked_sub(2).unwrap_or(0))
|
||||
.magnitude_squared()
|
||||
> view_distance.pow(2)
|
||||
{
|
||||
chunks_to_remove.push(key);
|
||||
}
|
||||
@ -242,18 +243,39 @@ impl Client {
|
||||
}
|
||||
|
||||
// Request chunks from the server.
|
||||
// TODO: This is really inefficient.
|
||||
let mut all_loaded = true;
|
||||
'outer: for dist in 0..=view_distance as i32 {
|
||||
for i in chunk_pos.x - dist..=chunk_pos.x + 1 + dist {
|
||||
for j in chunk_pos.y - dist..=chunk_pos.y + 1 + dist {
|
||||
let key = Vec2::new(i, j);
|
||||
if self.state.terrain().get_key(key).is_none() {
|
||||
if !self.pending_chunks.contains_key(&key) {
|
||||
// Only iterate through chunks that need to be loaded for circular vd
|
||||
// The (dist - 2) explained:
|
||||
// -0.5 because a chunk is visible if its corner is within the view distance
|
||||
// -0.5 for being able to move to the corner of the current chunk
|
||||
// -1 because chunks are not meshed if they don't have all their neighbors
|
||||
// (notice also that view_distance is decreased by 1)
|
||||
// (this subtraction on vd is ommitted elsewhere in order to provide a buffer layer of loaded chunks)
|
||||
let top = if 2 * (dist - 2).max(0).pow(2) > (view_distance - 1).pow(2) as i32 {
|
||||
((view_distance - 1).pow(2) as f32 - (dist - 2).pow(2) as f32)
|
||||
.sqrt()
|
||||
.round() as i32
|
||||
+ 1
|
||||
} else {
|
||||
dist
|
||||
};
|
||||
|
||||
for i in -top..=top {
|
||||
let keys = [
|
||||
chunk_pos + Vec2::new(dist, i),
|
||||
chunk_pos + Vec2::new(i, dist),
|
||||
chunk_pos + Vec2::new(-dist, i),
|
||||
chunk_pos + Vec2::new(i, -dist),
|
||||
];
|
||||
|
||||
for key in keys.iter() {
|
||||
if self.state.terrain().get_key(*key).is_none() {
|
||||
if !self.pending_chunks.contains_key(key) {
|
||||
if self.pending_chunks.len() < 4 {
|
||||
self.postbox
|
||||
.send_message(ClientMsg::TerrainChunkRequest { key });
|
||||
self.pending_chunks.insert(key, Instant::now());
|
||||
.send_message(ClientMsg::TerrainChunkRequest { key: *key });
|
||||
self.pending_chunks.insert(*key, Instant::now());
|
||||
} else {
|
||||
break 'outer;
|
||||
}
|
||||
|
@ -295,11 +295,11 @@ impl Server {
|
||||
})
|
||||
{
|
||||
let chunk_pos = self.state.terrain().pos_key(pos.0.map(|e| e as i32));
|
||||
let dist = (Vec2::from(chunk_pos) - Vec2::from(key))
|
||||
.map(|e: i32| e.abs())
|
||||
.reduce_max() as u32;
|
||||
let adjusted_dist_sqr = (Vec2::from(chunk_pos) - Vec2::from(key))
|
||||
.map(|e: i32| (e.abs() as u32).checked_sub(2).unwrap_or(0))
|
||||
.magnitude_squared();
|
||||
|
||||
if dist <= view_distance + 1 {
|
||||
if adjusted_dist_sqr <= view_distance.pow(2) {
|
||||
self.clients.notify(
|
||||
entity,
|
||||
ServerMsg::TerrainChunkUpdate {
|
||||
@ -327,13 +327,14 @@ impl Server {
|
||||
.join()
|
||||
{
|
||||
let chunk_pos = self.state.terrain().pos_key(pos.0.map(|e| e as i32));
|
||||
let dist = Vec2::from(chunk_pos - key)
|
||||
.map(|e: i32| e.abs() as u32)
|
||||
.reduce_max();
|
||||
|
||||
let adjusted_dist_sqr = Vec2::from(chunk_pos - key)
|
||||
.map(|e: i32| (e.abs() as u32).checked_sub(2).unwrap_or(0))
|
||||
.magnitude_squared();
|
||||
|
||||
if player
|
||||
.view_distance
|
||||
.map(|vd| dist <= vd + 1)
|
||||
.map(|vd| adjusted_dist_sqr <= vd.pow(2))
|
||||
.unwrap_or(false)
|
||||
{
|
||||
should_drop = false;
|
||||
@ -696,9 +697,10 @@ impl Server {
|
||||
|
||||
(pos.0 - client_pos)
|
||||
.map2(TerrainChunkSize::SIZE, |d, sz| {
|
||||
(d.abs() as u32) < client_vd * sz as u32
|
||||
(d.abs() as u32 / sz).checked_sub(2).unwrap_or(0)
|
||||
})
|
||||
.reduce_and()
|
||||
.magnitude_squared()
|
||||
< client_vd.pow(2)
|
||||
};
|
||||
|
||||
match force_update {
|
||||
|
@ -55,11 +55,13 @@ widget_ids! {
|
||||
|
||||
// Test
|
||||
bag_space_add,
|
||||
|
||||
// Debug
|
||||
debug_bg,
|
||||
fps_counter,
|
||||
ping,
|
||||
coordinates,
|
||||
loaded_distance,
|
||||
|
||||
// Game Version
|
||||
version,
|
||||
@ -336,10 +338,9 @@ impl Hud {
|
||||
// Don't process nametags outside the vd (visibility further limited by ui backend)
|
||||
.filter(|(_, pos, _, _, _)| {
|
||||
(pos.0 - player_pos)
|
||||
.map2(TerrainChunkSize::SIZE, |d, sz| {
|
||||
(d.abs() as u32) < view_distance * sz as u32
|
||||
})
|
||||
.reduce_and()
|
||||
.map2(TerrainChunkSize::SIZE, |d, sz| d.abs() as f32 / sz as f32)
|
||||
.magnitude()
|
||||
< view_distance as f32
|
||||
})
|
||||
.map(|(_, pos, actor, _, player)| match actor {
|
||||
comp::Actor::Character {
|
||||
@ -380,10 +381,9 @@ impl Hud {
|
||||
// Don't process health bars outside the vd (visibility further limited by ui backend)
|
||||
.filter(|(_, pos, _)| {
|
||||
(pos.0 - player_pos)
|
||||
.map2(TerrainChunkSize::SIZE, |d, sz| {
|
||||
(d.abs() as u32) < view_distance * sz as u32
|
||||
})
|
||||
.reduce_and()
|
||||
.map2(TerrainChunkSize::SIZE, |d, sz| d.abs() as f32 / sz as f32)
|
||||
.magnitude()
|
||||
< view_distance as f32
|
||||
})
|
||||
{
|
||||
let back_id = health_back_id_walker.next(
|
||||
@ -425,18 +425,21 @@ impl Hud {
|
||||
.font_id(self.fonts.opensans)
|
||||
.color(TEXT_COLOR)
|
||||
.set(self.ids.version, ui_widgets);
|
||||
// Ticks per second
|
||||
Text::new(&format!("FPS: {:.1}", debug_info.tps))
|
||||
.color(TEXT_COLOR)
|
||||
.down_from(self.ids.version, 5.0)
|
||||
.font_id(self.fonts.opensans)
|
||||
.font_size(14)
|
||||
.set(self.ids.fps_counter, ui_widgets);
|
||||
// Ping
|
||||
Text::new(&format!("Ping: {:.1}ms", debug_info.ping_ms))
|
||||
.color(TEXT_COLOR)
|
||||
.down_from(self.ids.fps_counter, 5.0)
|
||||
.font_id(self.fonts.opensans)
|
||||
.font_size(14)
|
||||
.set(self.ids.ping, ui_widgets);
|
||||
// Players position
|
||||
let coordinates_text = match debug_info.coordinates {
|
||||
Some(coordinates) => format!("Coordinates: {:.1}", coordinates.0),
|
||||
None => "Player has no Pos component".to_owned(),
|
||||
@ -447,6 +450,16 @@ impl Hud {
|
||||
.font_id(self.fonts.opensans)
|
||||
.font_size(14)
|
||||
.set(self.ids.coordinates, ui_widgets);
|
||||
// Loaded distance
|
||||
Text::new(&format!(
|
||||
"View distance: {} chunks",
|
||||
client.loaded_distance().unwrap_or(0)
|
||||
))
|
||||
.color(TEXT_COLOR)
|
||||
.down_from(self.ids.coordinates, 5.0)
|
||||
.font_id(self.fonts.opensans)
|
||||
.font_size(14)
|
||||
.set(self.ids.loaded_distance, ui_widgets);
|
||||
}
|
||||
|
||||
// Add Bag-Space Button.
|
||||
|
@ -493,13 +493,12 @@ impl FigureMgr {
|
||||
.join()
|
||||
{
|
||||
// Don't process figures outside the vd
|
||||
let vd_percent = (pos.0 - player_pos)
|
||||
.map2(TerrainChunkSize::SIZE, |d, sz| {
|
||||
(100 * d.abs() as u32) / (view_distance * sz)
|
||||
})
|
||||
.reduce_max();
|
||||
let vd_frac = (pos.0 - player_pos)
|
||||
.map2(TerrainChunkSize::SIZE, |d, sz| d.abs() as f32 / sz as f32)
|
||||
.magnitude()
|
||||
/ view_distance as f32;
|
||||
// Keep from re-adding/removing entities on the border of the vd
|
||||
if vd_percent > 120 {
|
||||
if vd_frac > 1.2 {
|
||||
match actor {
|
||||
comp::Actor::Character { body, .. } => match body {
|
||||
Body::Humanoid(_) => {
|
||||
@ -514,7 +513,7 @@ impl FigureMgr {
|
||||
},
|
||||
}
|
||||
continue;
|
||||
} else if vd_percent > 100 {
|
||||
} else if vd_frac > 1.0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -693,10 +692,9 @@ impl FigureMgr {
|
||||
// Don't render figures outside the vd
|
||||
.filter(|(_, pos, _, _, _, _, _)| {
|
||||
(pos.0 - player_pos)
|
||||
.map2(TerrainChunkSize::SIZE, |d, sz| {
|
||||
(d.abs() as u32) < view_distance * sz as u32
|
||||
})
|
||||
.reduce_and()
|
||||
.map2(TerrainChunkSize::SIZE, |d, sz| d.abs() as f32 / sz as f32)
|
||||
.magnitude()
|
||||
< view_distance as f32
|
||||
})
|
||||
// Don't render dead entities
|
||||
.filter(|(_, _, _, _, _, _, stats)| stats.map_or(true, |s| !s.is_dead))
|
||||
|
Loading…
Reference in New Issue
Block a user