From 0affc06e09b1a74a4925aa708536cdf78428af1f Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Sat, 20 May 2023 15:59:52 +0200 Subject: [PATCH] Fixed timestamps! (use them to fix networking) --- kubi/src/fixed_timestamp.rs | 45 +++++++++++++++++++++++++++++++++++++ kubi/src/main.rs | 5 ++++- kubi/src/networking.rs | 11 +++++---- 3 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 kubi/src/fixed_timestamp.rs diff --git a/kubi/src/fixed_timestamp.rs b/kubi/src/fixed_timestamp.rs new file mode 100644 index 0000000..81ccdeb --- /dev/null +++ b/kubi/src/fixed_timestamp.rs @@ -0,0 +1,45 @@ +use shipyard::{Workload, WorkloadModificator, Unique, AllStoragesView, UniqueViewMut, IntoWorkload}; +use hashbrown::HashMap; +use std::time::{Duration, Instant}; +use nohash_hasher::BuildNoHashHasher; + +#[derive(Unique)] +#[repr(transparent)] +struct FixedTimestampStorage(HashMap>); +impl FixedTimestampStorage { + pub fn new() -> Self { + Self(HashMap::with_capacity_and_hasher(16, BuildNoHashHasher::default())) + } +} +impl Default for FixedTimestampStorage { + fn default() -> Self { + Self::new() + } +} + +pub trait FixedTimestamp { + fn make_fixed(self, rate_millis: u16, unique_id: u16) -> Self; +} +impl FixedTimestamp for Workload { + fn make_fixed(self, rate_millis: u16, unique_id: u16) -> Self { + let key = (rate_millis as u32) | ((unique_id as u32) << 16); + let duration = Duration::from_millis(rate_millis as u64); + (self,).into_workload().run_if(move |mut timestamps: UniqueViewMut| { + let Some(t) = timestamps.0.get_mut(&key) else { + timestamps.0.insert_unique_unchecked(key, Instant::now()); + return true + }; + if t.elapsed() >= duration { + *t = Instant::now(); + return true + } + false + }) + } +} + +pub fn init_fixed_timestamp_storage( + storages: AllStoragesView +) { + storages.add_unique(FixedTimestampStorage::new()); +} diff --git a/kubi/src/main.rs b/kubi/src/main.rs index 2196dc1..6de4157 100644 --- a/kubi/src/main.rs +++ b/kubi/src/main.rs @@ -41,6 +41,7 @@ pub(crate) mod init; pub(crate) mod color; pub(crate) mod loading_screen; pub(crate) mod connecting_screen; +pub(crate) mod fixed_timestamp; use world::{ init_game_world, @@ -83,6 +84,7 @@ use init::initialize_from_args; use gui::{render_gui, init_gui, update_gui}; use loading_screen::update_loading_screen; use connecting_screen::switch_to_loading_if_connected; +use fixed_timestamp::init_fixed_timestamp_storage; /// stuff required to init the renderer and other basic systems fn pre_startup() -> Workload { @@ -93,6 +95,7 @@ fn pre_startup() -> Workload { fn startup() -> Workload { ( + init_fixed_timestamp_storage, initial_resize_event, init_window_size, load_prefabs, @@ -119,7 +122,7 @@ fn update() -> Workload { spawn_player.run_if_storage_empty::(), ).into_sequential_workload().run_if(is_singleplayer), ).into_sequential_workload().run_if(is_ingame_or_loading), - update_networking.run_if(is_multiplayer), + update_networking().run_if(is_multiplayer), ( switch_to_loading_if_connected ).into_sequential_workload().run_if(is_connecting), diff --git a/kubi/src/networking.rs b/kubi/src/networking.rs index af3bf0b..a0afa00 100644 --- a/kubi/src/networking.rs +++ b/kubi/src/networking.rs @@ -14,7 +14,8 @@ use crate::{ events::EventComponent, control_flow::SetControlFlow, world::tasks::ChunkTaskManager, - state::is_ingame_or_loading + state::is_ingame_or_loading, + fixed_timestamp::FixedTimestamp }; mod handshake; @@ -34,9 +35,11 @@ use world::{ use player::{ init_client_map, send_player_movement_events, + receive_player_movement_events, + receive_player_connect_events }; -use self::player::{receive_player_movement_events, receive_player_connect_events}; +const NET_TICKRATE: u16 = 33; #[derive(Unique, Clone, Copy, PartialEq, Eq)] pub enum GameType { @@ -119,7 +122,7 @@ pub fn update_networking() -> Workload { ( init_client_map.run_if_missing_unique::(), connect_client.run_if_missing_unique::(), - poll_client, + poll_client.into_workload().make_fixed(NET_TICKRATE, 0), ( set_client_join_state_to_connected, say_hello, @@ -147,7 +150,7 @@ pub fn update_networking_late() -> Workload { send_block_place_events, send_player_movement_events, ).into_workload().run_if(is_join_state::<{ClientJoinState::Joined as u8}>), - flush_client, + flush_client.into_workload().make_fixed(NET_TICKRATE, 1) ).into_sequential_workload() }