Skip to content

Commit

Permalink
refactor into multiple files
Browse files Browse the repository at this point in the history
  • Loading branch information
Bendzae committed May 24, 2024
1 parent 7e4afcd commit a57b990
Show file tree
Hide file tree
Showing 6 changed files with 221 additions and 175 deletions.
2 changes: 1 addition & 1 deletion examples/interpolated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use bevy_replicon_renet::{
RenetChannelsExt, RepliconRenetPlugins,
};
use bevy_replicon_snap::{
AppInterpolationExt, Interpolated, NetworkOwner, SnapshotInterpolationPlugin,
interpolation::Interpolated, AppInterpolationExt, NetworkOwner, SnapshotInterpolationPlugin,
};
use bevy_replicon_snap_macros::Interpolate;
use clap::Parser;
Expand Down
7 changes: 4 additions & 3 deletions examples/owner_predicted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::{
time::SystemTime,
};

use bevy::{prelude::*, winit::WinitSettings, winit::UpdateMode::Continuous};
use bevy::{prelude::*, winit::UpdateMode::Continuous, winit::WinitSettings};
use bevy_replicon::{client::ServerEntityTicks, prelude::*};
use bevy_replicon_renet::{
renet::{
Expand All @@ -20,8 +20,9 @@ use bevy_replicon_renet::{
RenetChannelsExt, RepliconRenetPlugins,
};
use bevy_replicon_snap::{
AppInterpolationExt, Interpolated, NetworkOwner, OwnerPredicted, Predicted,
PredictedEventHistory, SnapshotBuffer, SnapshotInterpolationPlugin,
interpolation::Interpolated, interpolation::SnapshotBuffer, prediction::OwnerPredicted,
prediction::Predicted, prediction::PredictedEventHistory, AppInterpolationExt, NetworkOwner,
SnapshotInterpolationPlugin,
};
use bevy_replicon_snap_macros::Interpolate;
use clap::Parser;
Expand Down
2 changes: 1 addition & 1 deletion macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ pub fn derive_interpolate(input: TokenStream) -> TokenStream {
_ => panic!("expected a struct"),
};
let output = quote! {
impl ::bevy_replicon_snap::Interpolate for #ident {
impl ::bevy_replicon_snap::interpolation::Interpolate for #ident {
fn interpolate(&self, other: Self, t: f32) -> Self {
#body
}
Expand Down
111 changes: 111 additions & 0 deletions src/interpolation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
use std::collections::VecDeque;

use bevy::{
ecs::{
component::Component,
entity::Entity,
query::{Added, Or, With, Without},
system::{Commands, Query, Res, Resource},
},
reflect::Reflect,
time::Time,
};
use bevy_replicon::client::ServerEntityTicks;
use serde::{Deserialize, Serialize};

use crate::prediction::Predicted;

pub trait Interpolate {
fn interpolate(&self, other: Self, t: f32) -> Self;
}

#[derive(Component, Deserialize, Serialize, Reflect)]
pub struct Interpolated;

#[derive(Deserialize, Serialize, Reflect)]
pub struct Snapshot<T: Component + Interpolate + Clone> {
tick: u32,
value: T,
}

#[derive(Component, Deserialize, Serialize, Reflect)]
pub struct SnapshotBuffer<T: Component + Interpolate + Clone> {
pub buffer: VecDeque<T>,
pub time_since_last_snapshot: f32,
pub latest_snapshot_tick: u32,
}

#[derive(Resource, Serialize, Deserialize, Debug)]
pub struct SnapshotInterpolationConfig {
pub max_tick_rate: u16,
}

impl<T: Component + Interpolate + Clone> SnapshotBuffer<T> {
pub fn new() -> Self {
Self {
buffer: VecDeque::new(),
time_since_last_snapshot: 0.0,
latest_snapshot_tick: 0,
}
}
pub fn insert(&mut self, element: T, tick: u32) {
if self.buffer.len() > 1 {
self.buffer.pop_front();
}
self.buffer.push_back(element);
self.time_since_last_snapshot = 0.0;
self.latest_snapshot_tick = tick;
}

pub fn latest_snapshot(&self) -> T {
self.buffer.iter().last().unwrap().clone()
}

pub fn latest_snapshot_tick(&self) -> u32 {
self.latest_snapshot_tick
}

pub fn age(&self) -> f32 {
self.time_since_last_snapshot
}
}

/// Initialize snapshot buffers for new entities.
pub fn snapshot_buffer_init_system<T: Component + Interpolate + Clone>(
q_new: Query<(Entity, &T), Or<(Added<Predicted>, Added<Interpolated>)>>,
mut commands: Commands,
server_ticks: Res<ServerEntityTicks>,
) {
for (e, initial_value) in q_new.iter() {
if let Some(tick) = (*server_ticks).get(&e) {
let mut buffer = SnapshotBuffer::new();
buffer.insert(initial_value.clone(), tick.get());
commands.entity(e).insert(buffer);
}
}
}

/// Interpolate between snapshots.
pub fn snapshot_interpolation_system<T: Component + Interpolate + Clone>(
mut q: Query<(&mut T, &mut SnapshotBuffer<T>), (With<Interpolated>, Without<Predicted>)>,
time: Res<Time>,
config: Res<SnapshotInterpolationConfig>,
) {
for (mut component, mut snapshot_buffer) in q.iter_mut() {
let buffer = &snapshot_buffer.buffer;
let elapsed = snapshot_buffer.time_since_last_snapshot;
if buffer.len() < 2 {
continue;
}

let tick_duration = 1.0 / (config.max_tick_rate as f32);

if elapsed > tick_duration + time.delta_seconds() {
continue;
}

let t = (elapsed / tick_duration).clamp(0., 1.);
*component = buffer[0].interpolate(buffer[1].clone(), t);
snapshot_buffer.time_since_last_snapshot += time.delta_seconds();
}
}
185 changes: 15 additions & 170 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
use std::collections::vec_deque::Iter;
use std::collections::VecDeque;
use std::fmt::Debug;
use std::io::Cursor;

use bevy::prelude::*;
use bevy_replicon::bincode;
use bevy_replicon::bincode::deserialize_from;
use bevy_replicon::client::client_mapper::ServerEntityMap;
use bevy_replicon::client::ServerEntityTicks;
use bevy_replicon::core::replication_rules;
use bevy_replicon::core::replication_rules::{
serialize_component, DeserializeFn, RemoveComponentFn, SerializeFn,
Expand All @@ -21,6 +18,20 @@ use serde::{Deserialize, Serialize};

pub use bevy_replicon_snap_macros;

use crate::{
interpolation::{
snapshot_buffer_init_system, snapshot_interpolation_system, Interpolate, Interpolated,
SnapshotBuffer, SnapshotInterpolationConfig,
},
prediction::{
owner_prediction_init_system, predicted_snapshot_system, OwnerPredicted, Predicted,
PredictedEventHistory,
},
};

pub mod interpolation;
pub mod prediction;

pub struct SnapshotInterpolationPlugin {
/// Should reflect the server max tick rate
pub max_tick_rate: u16,
Expand Down Expand Up @@ -59,181 +70,15 @@ impl Plugin for SnapshotInterpolationPlugin {
.run_if(resource_exists::<NetcodeClientTransport>)
.in_set(InterpolationSet::Init),
)
.insert_resource(InterpolationConfig {
.insert_resource(SnapshotInterpolationConfig {
max_tick_rate: self.max_tick_rate,
});
}
}

#[derive(Resource, Serialize, Deserialize, Debug)]
pub struct InterpolationConfig {
pub max_tick_rate: u16,
}

#[derive(Component, Deserialize, Serialize, Reflect)]
pub struct Interpolated;

#[derive(Component, Deserialize, Serialize, Reflect)]
pub struct OwnerPredicted;

#[derive(Component, Deserialize, Serialize, Reflect)]
pub struct NetworkOwner(pub u64);

#[derive(Component, Reflect)]
pub struct Predicted;

pub trait Interpolate {
fn interpolate(&self, other: Self, t: f32) -> Self;
}

#[derive(Deserialize, Serialize, Reflect)]
pub struct Snapshot<T: Component + Interpolate + Clone> {
tick: u32,
value: T,
}

#[derive(Component, Deserialize, Serialize, Reflect)]
pub struct SnapshotBuffer<T: Component + Interpolate + Clone> {
buffer: VecDeque<T>,
time_since_last_snapshot: f32,
latest_snapshot_tick: u32,
}

impl<T: Component + Interpolate + Clone> SnapshotBuffer<T> {
pub fn new() -> Self {
Self {
buffer: VecDeque::new(),
time_since_last_snapshot: 0.0,
latest_snapshot_tick: 0,
}
}
pub fn insert(&mut self, element: T, tick: u32) {
if self.buffer.len() > 1 {
self.buffer.pop_front();
}
self.buffer.push_back(element);
self.time_since_last_snapshot = 0.0;
self.latest_snapshot_tick = tick;
}

pub fn latest_snapshot(&self) -> T {
self.buffer.iter().last().unwrap().clone()
}

pub fn latest_snapshot_tick(&self) -> u32 {
self.latest_snapshot_tick
}

pub fn age(&self) -> f32 {
self.time_since_last_snapshot
}
}

pub struct EventSnapshot<T: Event> {
pub value: T,
pub tick: u32,
pub delta_time: f32,
}

#[derive(Resource)]
pub struct PredictedEventHistory<T: Event>(pub VecDeque<EventSnapshot<T>>);

impl<T: Event> PredictedEventHistory<T> {
pub fn new() -> PredictedEventHistory<T> {
Self(VecDeque::new())
}
pub fn insert(&mut self, value: T, tick: u32, delta_time: f32) -> &mut Self {
self.0.push_back(EventSnapshot {
value,
tick,
delta_time,
});
self
}
pub fn remove_stale(&mut self, latest_server_snapshot_tick: u32) -> &mut Self {
if let Some(last_index) = self
.0
.iter()
.position(|v| v.tick >= latest_server_snapshot_tick)
{
self.0.drain(0..last_index);
} else {
self.0.clear();
}
self
}

pub fn predict(&mut self, latest_server_snapshot_tick: u32) -> Iter<'_, EventSnapshot<T>> {
self.remove_stale(latest_server_snapshot_tick);
self.0.iter()
}
}

fn owner_prediction_init_system(
q_owners: Query<(Entity, &NetworkOwner), Added<OwnerPredicted>>,
client: Res<NetcodeClientTransport>,
mut commands: Commands,
) {
let client_id = client.client_id();
for (e, id) in q_owners.iter() {
if id.0 == client_id.raw() {
commands.entity(e).insert(Predicted);
} else {
commands.entity(e).insert(Interpolated);
}
}
}

/// Initialize snapshot buffers for new entities.
fn snapshot_buffer_init_system<T: Component + Interpolate + Clone>(
q_new: Query<(Entity, &T), Or<(Added<Predicted>, Added<Interpolated>)>>,
mut commands: Commands,
server_ticks: Res<ServerEntityTicks>,
) {
for (e, initial_value) in q_new.iter() {
if let Some(tick) = (*server_ticks).get(&e) {
let mut buffer = SnapshotBuffer::new();
buffer.insert(initial_value.clone(), tick.get());
commands.entity(e).insert(buffer);
}
}
}

/// Interpolate between snapshots.
fn snapshot_interpolation_system<T: Component + Interpolate + Clone>(
mut q: Query<(&mut T, &mut SnapshotBuffer<T>), (With<Interpolated>, Without<Predicted>)>,
time: Res<Time>,
config: Res<InterpolationConfig>,
) {
for (mut component, mut snapshot_buffer) in q.iter_mut() {
let buffer = &snapshot_buffer.buffer;
let elapsed = snapshot_buffer.time_since_last_snapshot;
if buffer.len() < 2 {
continue;
}

let tick_duration = 1.0 / (config.max_tick_rate as f32);

if elapsed > tick_duration + time.delta_seconds() {
continue;
}

let t = (elapsed / tick_duration).clamp(0., 1.);
*component = buffer[0].interpolate(buffer[1].clone(), t);
snapshot_buffer.time_since_last_snapshot += time.delta_seconds();
}
}

/// Advances the snapshot buffer time for predicted entities.
fn predicted_snapshot_system<T: Component + Interpolate + Clone>(
mut q: Query<&mut SnapshotBuffer<T>, (Without<Interpolated>, With<Predicted>)>,
time: Res<Time>,
) {
for mut snapshot_buffer in q.iter_mut() {
snapshot_buffer.time_since_last_snapshot += time.delta_seconds();
}
}

pub fn deserialize_snap_component<C: Clone + Interpolate + Component + DeserializeOwned>(
entity: &mut EntityWorldMut,
_entity_map: &mut ServerEntityMap,
Expand Down
Loading

0 comments on commit a57b990

Please sign in to comment.