sync - introduceconcept of a rewind_tick

This commit is contained in:
Marcel Märtens 2022-03-13 17:18:43 +01:00
parent 4343dd3aea
commit 820b3f06b0
3 changed files with 88 additions and 13 deletions

View File

@ -39,7 +39,7 @@ use common::{
mounting::Rider,
outcome::Outcome,
recipe::{ComponentRecipeBook, RecipeBook},
resources::{DeltaTime, GameMode, MonotonicTime, PlayerEntity, Time, TimeOfDay},
resources::{MonotonicTime, GameMode, PlayerEntity, Time, TimeOfDay},
spiral::Spiral2d,
terrain::{
block::Block, map::MapConfig, neighbors, site::DungeonKindMeta, BiomeKind,
@ -64,7 +64,7 @@ use common_net::{
sync::WorldSyncExt,
};
use common_state::State;
use common_systems::add_local_systems;
use common_systems::{add_local_systems, add_rewind_systems};
use comp::BuffKind;
use hashbrown::{HashMap, HashSet};
use image::DynamicImage;
@ -237,6 +237,7 @@ pub struct Client {
local_command_gen: CommandGenerator,
next_control: Controller,
inter_tick_rewind_time: Option<Duration>,
network: Option<Network>,
participant: Option<Participant>,
@ -721,6 +722,7 @@ impl Client {
local_command_gen: CommandGenerator::default(),
next_control: Controller::default(),
inter_tick_rewind_time: None,
network: Some(network),
participant: Some(participant),
@ -1699,6 +1701,7 @@ impl Client {
// 1) Build up a list of events for this frame, to be passed to the frontend.
let mut frontend_events = Vec::new();
self.inter_tick_rewind_time = None;
// Prepare for new events
{
@ -1728,6 +1731,36 @@ impl Client {
// Handle new messages from the server.
frontend_events.append(&mut self.handle_new_messages()?);
// Simulate Ahead
if let Some(_rewind_time) = self.inter_tick_rewind_time {
let _time = self.state.ecs().read_resource::<Time>().0 as f64;
let simulate_ahead = self
.state
.ecs()
.read_storage::<RemoteController>()
.get(self.entity())
.map(|rc| rc.simulate_ahead())
.unwrap_or_default();
let simulate_ahead = simulate_ahead.max(dt) - dt;
tracing::warn!(?simulate_ahead, ?dt, "simulating ahead again");
self.state.rewind_tick(
simulate_ahead.max(dt) - dt,
|dispatch_builder| {
add_rewind_systems(dispatch_builder);
},
false,
);
}
self.state.tick(
dt,
|dispatch_builder| {
add_local_systems(dispatch_builder);
add_foreign_systems(dispatch_builder);
},
true,
);
// 2) Handle input from frontend.
// Pass character actions from frontend input to the player's entity.
if self.presence.is_some() {
@ -2158,17 +2191,17 @@ impl Client {
prof_span!("handle_server_in_game_msg");
match msg {
ServerGeneral::TimeSync(time) => {
let dt = self.state.ecs().read_resource::<DeltaTime>().0 as f64;
let simulate_ahead = self
.state
.ecs()
.read_storage::<RemoteController>()
.get(self.entity())
.map(|rc| rc.simulate_ahead())
.unwrap_or_default();
//remove dt as it is applied in state.tick again
self.state.ecs().write_resource::<Time>().0 =
time.0 + simulate_ahead.as_secs_f64() - dt;
let old_time = self.state.ecs().read_resource::<Time>().0;
let diff = old_time - time.0;
self.state.ecs().write_resource::<Time>().0 = time.0;
if diff > 0.0 {
tracing::warn!(?old_time, ?diff, "Time was reverted by server");
let rewind_time = self.inter_tick_rewind_time.unwrap_or_default()
+ Duration::from_secs_f64(diff);
self.inter_tick_rewind_time = Some(rewind_time);
} else {
tracing::warn!(?old_time, ?diff, "Time was advanced by server");
}
},
ServerGeneral::AckControl(acked_ids, _time) => {
if let Some(remote_controller) = self

View File

@ -590,6 +590,28 @@ impl State {
self.ecs.write_resource::<TerrainChanges>().modified_blocks = modified_blocks;
}
/// Rewind local changes after the server send some old state
pub fn rewind_tick(
&mut self,
simulate_ahead: Duration,
add_systems: impl Fn(&mut DispatcherBuilder),
update_terrain_and_regions: bool,
) {
let time_of_day = self.ecs.read_resource::<TimeOfDay>().0;
let _time = self.ecs.read_resource::<Time>().0;
let monotonic_time = self.ecs.read_resource::<MonotonicTime>().0;
let delta_time = self.ecs.read_resource::<DeltaTime>().0;
self.tick(simulate_ahead, add_systems, update_terrain_and_regions);
// rewind changes
self.ecs.write_resource::<TimeOfDay>().0 = time_of_day;
//self.ecs.write_resource::<Time>().0 = time;
self.ecs.write_resource::<MonotonicTime>().0 = monotonic_time;
self.ecs.write_resource::<DeltaTime>().0 = delta_time;
}
/// Execute a single tick, simulating the game state by the given duration.
pub fn tick(
&mut self,

View File

@ -39,3 +39,23 @@ pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) {
dispatch::<beam::Sys>(dispatch_builder, &[&phys::Sys::sys_name()]);
dispatch::<aura::Sys>(dispatch_builder, &[]);
}
pub fn add_rewind_systems(dispatch_builder: &mut DispatcherBuilder) {
//TODO: don't run interpolation on server
dispatch::<interpolation::Sys>(dispatch_builder, &[]);
dispatch::<mount::Sys>(dispatch_builder, &[]);
dispatch::<controller::Sys>(dispatch_builder, &[&mount::Sys::sys_name()]);
dispatch::<character_behavior::Sys>(dispatch_builder, &[&controller::Sys::sys_name()]);
dispatch::<buff::Sys>(dispatch_builder, &[]);
dispatch::<stats::Sys>(dispatch_builder, &[&buff::Sys::sys_name()]);
dispatch::<phys::Sys>(dispatch_builder, &[
&interpolation::Sys::sys_name(),
&controller::Sys::sys_name(),
&mount::Sys::sys_name(),
&stats::Sys::sys_name(),
]);
dispatch::<projectile::Sys>(dispatch_builder, &[&phys::Sys::sys_name()]);
dispatch::<shockwave::Sys>(dispatch_builder, &[&phys::Sys::sys_name()]);
dispatch::<beam::Sys>(dispatch_builder, &[&phys::Sys::sys_name()]);
dispatch::<aura::Sys>(dispatch_builder, &[]);
}