Apply ForcedUpdate messages to the interpolation system, potentially improving the handling of teleports.

This commit is contained in:
Avi Weinstock 2021-03-16 11:55:01 -04:00
parent f4fa1e9cd3
commit 62de0816e0
4 changed files with 62 additions and 25 deletions

View File

@ -76,7 +76,7 @@ sum_type! {
impl sync::CompPacket for EcsCompPacket { impl sync::CompPacket for EcsCompPacket {
type Phantom = EcsCompPhantom; type Phantom = EcsCompPhantom;
fn apply_insert(self, entity: specs::Entity, world: &specs::World) { fn apply_insert(self, entity: specs::Entity, world: &specs::World, force_update: bool) {
match self { match self {
EcsCompPacket::Body(comp) => sync::handle_insert(comp, entity, world), EcsCompPacket::Body(comp) => sync::handle_insert(comp, entity, world),
EcsCompPacket::Player(comp) => sync::handle_insert(comp, entity, world), EcsCompPacket::Player(comp) => sync::handle_insert(comp, entity, world),
@ -100,15 +100,21 @@ impl sync::CompPacket for EcsCompPacket {
EcsCompPacket::Gravity(comp) => sync::handle_insert(comp, entity, world), EcsCompPacket::Gravity(comp) => sync::handle_insert(comp, entity, world),
EcsCompPacket::Sticky(comp) => sync::handle_insert(comp, entity, world), EcsCompPacket::Sticky(comp) => sync::handle_insert(comp, entity, world),
EcsCompPacket::CharacterState(comp) => sync::handle_insert(comp, entity, world), EcsCompPacket::CharacterState(comp) => sync::handle_insert(comp, entity, world),
EcsCompPacket::Pos(comp) => sync::handle_interp_insert(comp, entity, world), EcsCompPacket::Pos(comp) => {
EcsCompPacket::Vel(comp) => sync::handle_interp_insert(comp, entity, world), sync::handle_interp_insert(comp, entity, world, force_update)
EcsCompPacket::Ori(comp) => sync::handle_interp_insert(comp, entity, world), },
EcsCompPacket::Vel(comp) => {
sync::handle_interp_insert(comp, entity, world, force_update)
},
EcsCompPacket::Ori(comp) => {
sync::handle_interp_insert(comp, entity, world, force_update)
},
EcsCompPacket::Shockwave(comp) => sync::handle_insert(comp, entity, world), EcsCompPacket::Shockwave(comp) => sync::handle_insert(comp, entity, world),
EcsCompPacket::BeamSegment(comp) => sync::handle_insert(comp, entity, world), EcsCompPacket::BeamSegment(comp) => sync::handle_insert(comp, entity, world),
} }
} }
fn apply_modify(self, entity: specs::Entity, world: &specs::World) { fn apply_modify(self, entity: specs::Entity, world: &specs::World, force_update: bool) {
match self { match self {
EcsCompPacket::Body(comp) => sync::handle_modify(comp, entity, world), EcsCompPacket::Body(comp) => sync::handle_modify(comp, entity, world),
EcsCompPacket::Player(comp) => sync::handle_modify(comp, entity, world), EcsCompPacket::Player(comp) => sync::handle_modify(comp, entity, world),
@ -132,9 +138,15 @@ impl sync::CompPacket for EcsCompPacket {
EcsCompPacket::Gravity(comp) => sync::handle_modify(comp, entity, world), EcsCompPacket::Gravity(comp) => sync::handle_modify(comp, entity, world),
EcsCompPacket::Sticky(comp) => sync::handle_modify(comp, entity, world), EcsCompPacket::Sticky(comp) => sync::handle_modify(comp, entity, world),
EcsCompPacket::CharacterState(comp) => sync::handle_modify(comp, entity, world), EcsCompPacket::CharacterState(comp) => sync::handle_modify(comp, entity, world),
EcsCompPacket::Pos(comp) => sync::handle_interp_modify(comp, entity, world), EcsCompPacket::Pos(comp) => {
EcsCompPacket::Vel(comp) => sync::handle_interp_modify(comp, entity, world), sync::handle_interp_modify(comp, entity, world, force_update)
EcsCompPacket::Ori(comp) => sync::handle_interp_modify(comp, entity, world), },
EcsCompPacket::Vel(comp) => {
sync::handle_interp_modify(comp, entity, world, force_update)
},
EcsCompPacket::Ori(comp) => {
sync::handle_interp_modify(comp, entity, world, force_update)
},
EcsCompPacket::Shockwave(comp) => sync::handle_modify(comp, entity, world), EcsCompPacket::Shockwave(comp) => sync::handle_modify(comp, entity, world),
EcsCompPacket::BeamSegment(comp) => sync::handle_modify(comp, entity, world), EcsCompPacket::BeamSegment(comp) => sync::handle_modify(comp, entity, world),
} }

View File

@ -14,7 +14,7 @@ pub struct InterpBuffer<T> {
pub i: usize, pub i: usize,
} }
impl<T> InterpBuffer<T> { impl<T: Clone> InterpBuffer<T> {
fn push(&mut self, time: f64, x: T) { fn push(&mut self, time: f64, x: T) {
let InterpBuffer { let InterpBuffer {
ref mut buf, ref mut buf,
@ -24,6 +24,20 @@ impl<T> InterpBuffer<T> {
*i %= buf.len(); *i %= buf.len();
buf[*i] = (time, x); buf[*i] = (time, x);
} }
fn force_update(&mut self, time: f64, x: T) {
for i in 0..self.buf.len() {
self.buf[i] = (time, x.clone());
}
}
fn update(&mut self, time: f64, x: T, force_update: bool) {
if force_update {
self.force_update(time, x);
} else {
self.push(time, x);
}
}
} }
impl<T: 'static + Send + Sync> Component for InterpBuffer<T> { impl<T: 'static + Send + Sync> Component for InterpBuffer<T> {
@ -40,8 +54,8 @@ impl InterpolatableComponent for Pos {
type InterpData = InterpBuffer<Pos>; type InterpData = InterpBuffer<Pos>;
type ReadData = InterpBuffer<Vel>; type ReadData = InterpBuffer<Vel>;
fn update_component(&self, interp_data: &mut Self::InterpData, time: f64) { fn update_component(&self, interp_data: &mut Self::InterpData, time: f64, force_update: bool) {
interp_data.push(time, *self); interp_data.update(time, *self, force_update);
} }
fn interpolate(self, interp_data: &Self::InterpData, t2: f64, vel: &InterpBuffer<Vel>) -> Self { fn interpolate(self, interp_data: &Self::InterpData, t2: f64, vel: &InterpBuffer<Vel>) -> Self {
@ -94,8 +108,8 @@ impl InterpolatableComponent for Vel {
type InterpData = InterpBuffer<Vel>; type InterpData = InterpBuffer<Vel>;
type ReadData = (); type ReadData = ();
fn update_component(&self, interp_data: &mut Self::InterpData, time: f64) { fn update_component(&self, interp_data: &mut Self::InterpData, time: f64, force_update: bool) {
interp_data.push(time, *self); interp_data.update(time, *self, force_update);
} }
fn interpolate(self, interp_data: &Self::InterpData, t2: f64, _: &()) -> Self { fn interpolate(self, interp_data: &Self::InterpData, t2: f64, _: &()) -> Self {
@ -129,8 +143,8 @@ impl InterpolatableComponent for Ori {
type InterpData = InterpBuffer<Ori>; type InterpData = InterpBuffer<Ori>;
type ReadData = (); type ReadData = ();
fn update_component(&self, interp_data: &mut Self::InterpData, time: f64) { fn update_component(&self, interp_data: &mut Self::InterpData, time: f64, force_update: bool) {
interp_data.push(time, *self); interp_data.update(time, *self, force_update);
} }
fn interpolate(self, interp_data: &Self::InterpData, t2: f64, _: &()) -> Self { fn interpolate(self, interp_data: &Self::InterpData, t2: f64, _: &()) -> Self {

View File

@ -19,8 +19,8 @@ use tracing::error;
pub trait CompPacket: Clone + Debug + Send + 'static { pub trait CompPacket: Clone + Debug + Send + 'static {
type Phantom: Clone + Debug + Serialize + DeserializeOwned; type Phantom: Clone + Debug + Serialize + DeserializeOwned;
fn apply_insert(self, entity: Entity, world: &World); fn apply_insert(self, entity: Entity, world: &World, force_update: bool);
fn apply_modify(self, entity: Entity, world: &World); fn apply_modify(self, entity: Entity, world: &World, force_update: bool);
fn apply_remove(phantom: Self::Phantom, entity: Entity, world: &World); fn apply_remove(phantom: Self::Phantom, entity: Entity, world: &World);
} }
@ -50,14 +50,19 @@ pub trait InterpolatableComponent: Component {
type InterpData: Component + Default; type InterpData: Component + Default;
type ReadData; type ReadData;
fn update_component(&self, data: &mut Self::InterpData, time: f64); fn update_component(&self, data: &mut Self::InterpData, time: f64, force_update: bool);
fn interpolate(self, data: &Self::InterpData, time: f64, read_data: &Self::ReadData) -> Self; fn interpolate(self, data: &Self::InterpData, time: f64, read_data: &Self::ReadData) -> Self;
} }
pub fn handle_interp_insert<C: InterpolatableComponent>(comp: C, entity: Entity, world: &World) { pub fn handle_interp_insert<C: InterpolatableComponent>(
comp: C,
entity: Entity,
world: &World,
force_update: bool,
) {
let mut interp_data = C::InterpData::default(); let mut interp_data = C::InterpData::default();
let time = world.read_resource::<Time>().0; let time = world.read_resource::<Time>().0;
comp.update_component(&mut interp_data, time); comp.update_component(&mut interp_data, time, force_update);
handle_insert(comp, entity, world); handle_insert(comp, entity, world);
handle_insert(interp_data, entity, world); handle_insert(interp_data, entity, world);
} }
@ -66,10 +71,11 @@ pub fn handle_interp_modify<C: InterpolatableComponent + Debug>(
comp: C, comp: C,
entity: Entity, entity: Entity,
world: &World, world: &World,
force_update: bool,
) { ) {
if let Some(mut interp_data) = world.write_storage::<C::InterpData>().get_mut(entity) { if let Some(mut interp_data) = world.write_storage::<C::InterpData>().get_mut(entity) {
let time = world.read_resource::<Time>().0; let time = world.read_resource::<Time>().0;
comp.update_component(&mut interp_data, time); comp.update_component(&mut interp_data, time, force_update);
handle_modify(comp, entity, world); handle_modify(comp, entity, world);
} else { } else {
error!( error!(

View File

@ -4,7 +4,10 @@ use super::{
}, },
track::UpdateTracker, track::UpdateTracker,
}; };
use common::uid::{Uid, UidAllocator}; use common::{
resources::PlayerEntity,
uid::{Uid, UidAllocator},
};
use specs::{ use specs::{
saveload::{MarkedBuilder, MarkerAllocator}, saveload::{MarkedBuilder, MarkerAllocator},
world::Builder, world::Builder,
@ -80,7 +83,7 @@ impl WorldSyncExt for specs::World {
let entity = create_entity_with_uid(self, uid); let entity = create_entity_with_uid(self, uid);
for packet in comps { for packet in comps {
packet.apply_insert(entity, self) packet.apply_insert(entity, self, true)
} }
entity entity
@ -129,17 +132,19 @@ impl WorldSyncExt for specs::World {
fn apply_comp_sync_package<P: CompPacket>(&mut self, package: CompSyncPackage<P>) { fn apply_comp_sync_package<P: CompPacket>(&mut self, package: CompSyncPackage<P>) {
// Update components // Update components
let player_entity = self.read_resource::<PlayerEntity>().0;
package.comp_updates.into_iter().for_each(|(uid, update)| { package.comp_updates.into_iter().for_each(|(uid, update)| {
if let Some(entity) = self if let Some(entity) = self
.read_resource::<UidAllocator>() .read_resource::<UidAllocator>()
.retrieve_entity_internal(uid) .retrieve_entity_internal(uid)
{ {
let force_update = player_entity == Some(entity);
match update { match update {
CompUpdateKind::Inserted(packet) => { CompUpdateKind::Inserted(packet) => {
packet.apply_insert(entity, self); packet.apply_insert(entity, self, force_update);
}, },
CompUpdateKind::Modified(packet) => { CompUpdateKind::Modified(packet) => {
packet.apply_modify(entity, self); packet.apply_modify(entity, self, force_update);
}, },
CompUpdateKind::Removed(phantom) => { CompUpdateKind::Removed(phantom) => {
P::apply_remove(phantom, entity, self); P::apply_remove(phantom, entity, self);