Stop drawing entities outside the vd

Former-commit-id: 34878fb66ec22ac77a7400724b80ad7f8321f4cf
This commit is contained in:
Imbris 2019-05-27 13:01:00 -04:00
parent 59967c603c
commit e3e8afd99b
5 changed files with 105 additions and 21 deletions

View File

@ -110,6 +110,10 @@ impl Client {
.send_message(ClientMsg::SetViewDistance(self.view_distance.unwrap())); // Can't fail
}
pub fn view_distance(&self) -> Option<u32> {
self.view_distance
}
/// Send a chat message to the server.
#[allow(dead_code)]
pub fn send_chat(&mut self, msg: String) {

View File

@ -283,19 +283,22 @@ impl Server {
// Also, send the chunk data to anybody that is close by.
if let Ok((key, chunk)) = self.chunk_rx.try_recv() {
// Send the chunk to all nearby players.
for (entity, player, pos) in (
for (entity, view_distance, pos) in (
&self.state.ecs().entities(),
&self.state.ecs().read_storage::<comp::Player>(),
&self.state.ecs().read_storage::<comp::phys::Pos>(),
)
.join()
.filter_map(|(entity, player, pos)| {
player.view_distance.map(|vd| (entity, vd, pos))
})
{
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;
if player.view_distance.map(|vd| dist <= vd).unwrap_or(false) {
if dist <= view_distance {
self.clients.notify(
entity,
ServerMsg::TerrainChunkUpdate {

View File

@ -31,8 +31,7 @@ use crate::{
GlobalState,
};
use client::Client;
use common::comp;
use common::comp::phys::Pos;
use common::{comp, terrain::TerrainChunkSize, vol::VolSize};
use conrod_core::{
color, graph,
widget::{self, Button, Image, Rectangle, Text},
@ -105,7 +104,7 @@ font_ids! {
pub struct DebugInfo {
pub tps: f64,
pub ping_ms: f64,
pub coordinates: Option<Pos>,
pub coordinates: Option<comp::phys::Pos>,
}
pub enum Event {
@ -305,6 +304,14 @@ impl Hud {
let player = ecs.read_storage::<comp::Player>();
let entities = ecs.entities();
let me = client.entity();
let view_distance = client.view_distance().unwrap_or(1);
// Get player position.
let player_pos = client
.state()
.ecs()
.read_storage::<comp::phys::Pos>()
.get(client.entity())
.map_or(Vec3::zero(), |pos| pos.0);
let mut name_id_walker = self.ids.name_tags.walk();
let mut health_id_walker = self.ids.health_bars.walk();
let mut health_back_id_walker = self.ids.health_bar_backs.walk();
@ -313,6 +320,14 @@ impl Hud {
for (pos, name) in (&entities, &pos, &actor, &stats, player.maybe())
.join()
.filter(|(entity, _, _, stats, _)| *entity != me && !stats.is_dead)
// 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()
})
.map(|(entity, pos, actor, _, player)| match actor {
comp::Actor::Character {
name: char_name, ..
@ -342,14 +357,21 @@ impl Hud {
}
// Render Health Bars
for (entity, pos, stats) in
(&entities, &pos, &stats)
.join()
.filter(|(entity, _, stats)| {
*entity != me
&& !stats.is_dead
&& stats.hp.get_current() != stats.hp.get_maximum()
})
for (entity, pos, stats) in (&entities, &pos, &stats)
.join()
.filter(|(entity, _, stats)| {
*entity != me
&& !stats.is_dead
&& stats.hp.get_current() != stats.hp.get_maximum()
})
// 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()
})
{
let back_id = health_back_id_walker.next(
&mut self.ids.health_bar_backs,

View File

@ -26,6 +26,8 @@ use common::{
figure::Segment,
msg,
msg::ClientState,
terrain::TerrainChunkSize,
vol::VolSize,
};
use dot_vox::DotVoxData;
use specs::{Component, Entity as EcsEntity, Join, VecStorage};
@ -461,6 +463,15 @@ impl FigureMgr {
pub fn maintain(&mut self, renderer: &mut Renderer, client: &Client) {
let time = client.state().get_time();
let ecs = client.state().ecs();
let view_distance = client.view_distance().unwrap_or(1);
// Get player position.
let player_pos = client
.state()
.ecs()
.read_storage::<comp::phys::Pos>()
.get(client.entity())
.map_or(Vec3::zero(), |pos| pos.0);
for (entity, pos, vel, dir, actor, animation_info, stats) in (
&ecs.entities(),
&ecs.read_storage::<comp::phys::Pos>(),
@ -472,6 +483,32 @@ 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();
// Keep from re-adding/removing entities on the border of the vd
if vd_percent > 120 {
match actor {
comp::Actor::Character { body, .. } => match body {
Body::Humanoid(_) => {
self.character_states.remove(&entity);
}
Body::Quadruped(_) => {
self.quadruped_states.remove(&entity);
}
Body::QuadrupedMedium(_) => {
self.QuadrupedMedium_states.remove(&entity);
}
},
}
continue;
} else if vd_percent > 100 {
continue;
}
// Change in health as color!
let col = stats
.and_then(|stats| stats.hp.last_change)
@ -610,17 +647,36 @@ impl FigureMgr {
let tick = client.get_tick();
let ecs = client.state().ecs();
for (entity, actor, stat) in (
let view_distance = client.view_distance().unwrap_or(1);
// Get player position.
let player_pos = client
.state()
.ecs()
.read_storage::<comp::phys::Pos>()
.get(client.entity())
.map_or(Vec3::zero(), |pos| pos.0);
for (entity, _, _, _, actor, _, _) in (
&ecs.entities(),
&ecs.read_storage::<comp::phys::Pos>(),
&ecs.read_storage::<comp::phys::Vel>(),
&ecs.read_storage::<comp::phys::Dir>(),
&ecs.read_storage::<comp::Actor>(),
&ecs.read_storage::<comp::Stats>(), // Just to make sure the entity is alive
&ecs.read_storage::<comp::AnimationInfo>(),
ecs.read_storage::<comp::Stats>().maybe(),
)
.join()
// 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()
})
// Don't render dead entities
.filter(|(e, _, _, _, a, _, stats)| stats.map_or(true, |s| !s.is_dead))
{
if stat.is_dead {
continue;
}
match actor {
comp::Actor::Character { body, .. } => {
if let Some((locals, bone_consts)) = match body {

View File

@ -116,8 +116,7 @@ impl Scene {
.ecs()
.read_storage::<comp::phys::Pos>()
.get(client.entity())
.map(|pos| pos.0)
.unwrap_or(Vec3::zero());
.map_or(Vec3::zero(), |pos| pos.0);
// Alter camera position to match player.
self.camera.set_focus_pos(player_pos + Vec3::unit_z() * 2.1);