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