Optimised entity sync code, increased animation throttling distance

This commit is contained in:
Joshua Barretto 2021-03-16 02:49:33 +00:00
parent bf66886e7c
commit 6f10a56589
2 changed files with 53 additions and 113 deletions

View File

@ -15,9 +15,7 @@ use common::{
}; };
use common_ecs::{Job, Origin, Phase, System}; use common_ecs::{Job, Origin, Phase, System};
use common_net::{msg::ServerGeneral, sync::CompSyncPackage}; use common_net::{msg::ServerGeneral, sync::CompSyncPackage};
use specs::{ use specs::{Entities, Join, Read, ReadExpect, ReadStorage, Write, WriteStorage};
Entities, Entity as EcsEntity, Join, Read, ReadExpect, ReadStorage, Write, WriteStorage,
};
use vek::*; use vek::*;
/// This system will send physics updates to the client /// This system will send physics updates to the client
@ -201,22 +199,35 @@ impl<'a> System<'a> for Sys {
.map(|msg| client.send_prepared(&msg)); .map(|msg| client.send_prepared(&msg));
}); });
let mut send_general = |msg: ServerGeneral,
entity: EcsEntity,
pos: Pos,
force_update: Option<&ForceUpdate>,
throttle: bool| {
for (client, _, client_entity, client_pos) in &mut subscribers { for (client, _, client_entity, client_pos) in &mut subscribers {
if if client_entity == &entity { let mut comp_sync_package = CompSyncPackage::new();
for (_, entity, &uid, &pos, vel, ori, force_update, collider) in (
region.entities(),
&entities,
&uids,
&positions,
velocities.maybe(),
orientations.maybe(),
force_updates.maybe(),
colliders.maybe(),
)
.join()
{
// Decide how regularly to send physics updates.
let send_now = if client_entity == &entity {
// Don't send client physics updates about itself unless force update is set // Don't send client physics updates about itself unless force update is set
force_update.is_some() force_update.is_some()
} else if !throttle { } else if matches!(collider, Some(Collider::Voxel { .. })) {
// Send the message if not throttling // Things with a voxel collider (airships, etc.) need to have very stable
// physics so we always send updated for these where
// we can.
true true
} else { } else {
// Throttle update rate based on distance to client // Throttle update rates for all other entities based on distance to client
let distance_sq = client_pos.0.distance_squared(pos.0); let distance_sq = client_pos.0.distance_squared(pos.0);
let id_staggered_tick = tick + entity.id() as u64; let id_staggered_tick = tick + entity.id() as u64;
// More entities farther away so checks start there // More entities farther away so checks start there
if distance_sq > 350.0f32.powi(2) { if distance_sq > 350.0f32.powi(2) {
id_staggered_tick % 64 == 0 id_staggered_tick % 64 == 0
@ -231,108 +242,37 @@ impl<'a> System<'a> for Sys {
} else { } else {
id_staggered_tick % 3 == 0 id_staggered_tick % 3 == 0
} }
} {
client.send_fallible(msg.clone());
}
}
}; };
// Sync physics components if send_now {
for (_, entity, &uid, &pos, maybe_vel, maybe_ori, force_update, collider) in ( if last_pos.get(entity).is_none() {
region.entities(),
&entities,
&uids,
&positions,
velocities.maybe(),
orientations.maybe(),
force_updates.maybe(),
colliders.maybe(),
)
.join()
{
let mut comp_sync_package = CompSyncPackage::new();
let mut throttle = true;
// Extrapolation depends on receiving several frames indicating that something
// has stopped in order for the extrapolated value to have
// stopped
const SEND_UNCHANGED_PHYSICS_DATA: bool = true;
// TODO: An entity that stopped moving on a tick that it wasn't sent to the
// player will never have its position updated
match last_pos
.get(entity)
.map(|&l| l.0 != pos || SEND_UNCHANGED_PHYSICS_DATA)
{
Some(false) => {},
Some(true) => {
let _ = last_pos.insert(entity, Last(pos));
comp_sync_package.comp_modified(uid, pos);
},
None => {
let _ = last_pos.insert(entity, Last(pos));
throttle = false;
comp_sync_package.comp_inserted(uid, pos); comp_sync_package.comp_inserted(uid, pos);
}, let _ = last_pos.insert(entity, Last(pos));
} else {
comp_sync_package.comp_modified(uid, pos);
} }
if let Some(&vel) = maybe_vel { vel.map(|v| {
match last_vel if last_vel.get(entity).is_none() {
.get(entity) comp_sync_package.comp_inserted(uid, *v);
.map(|&l| l.0 != vel || SEND_UNCHANGED_PHYSICS_DATA) let _ = last_vel.insert(entity, Last(*v));
{ } else {
Some(false) => {}, comp_sync_package.comp_modified(uid, *v);
Some(true) => { }
let _ = last_vel.insert(entity, Last(vel)); });
comp_sync_package.comp_modified(uid, vel);
}, ori.map(|o| {
None => { if last_ori.get(entity).is_none() {
let _ = last_vel.insert(entity, Last(vel)); comp_sync_package.comp_inserted(uid, *o);
throttle = false; let _ = last_ori.insert(entity, Last(*o));
comp_sync_package.comp_inserted(uid, vel); } else {
}, comp_sync_package.comp_modified(uid, *o);
}
});
} }
} else if last_vel.remove(entity).is_some() {
// Send removal message if Vel was removed
// Note: we don't have to handle this for position because the entity will be
// removed from the client by the region system
throttle = false;
comp_sync_package.comp_removed::<Vel>(uid);
} }
if let Some(&ori) = maybe_ori { client.send_fallible(ServerGeneral::CompSync(comp_sync_package));
match last_ori
.get(entity)
.map(|&l| l.0 != ori || SEND_UNCHANGED_PHYSICS_DATA)
{
Some(false) => {},
Some(true) => {
let _ = last_ori.insert(entity, Last(ori));
comp_sync_package.comp_modified(uid, ori);
},
None => {
let _ = last_ori.insert(entity, Last(ori));
throttle = false;
comp_sync_package.comp_inserted(uid, ori);
},
}
} else if last_ori.remove(entity).is_some() {
// Send removal message if Ori was removed
throttle = false;
comp_sync_package.comp_removed::<Ori>(uid);
}
if matches!(collider, Some(Collider::Voxel { .. })) {
throttle = false;
}
send_general(
ServerGeneral::CompSync(comp_sync_package),
entity,
pos,
force_update,
throttle,
);
} }
} }

View File

@ -635,7 +635,7 @@ impl FigureMgr {
// goes further and further away, we start to 'skip' update ticks. // goes further and further away, we start to 'skip' update ticks.
// TODO: Investigate passing the velocity into the shader so we can at least // TODO: Investigate passing the velocity into the shader so we can at least
// interpolate motion // interpolate motion
const MIN_PERFECT_RATE_DIST: f32 = 50.0; const MIN_PERFECT_RATE_DIST: f32 = 100.0;
if (i as u64 + tick) if (i as u64 + tick)
% (1 + ((pos.0.distance_squared(focus_pos).powf(0.25) % (1 + ((pos.0.distance_squared(focus_pos).powf(0.25)