-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Client-side prediction first steps (wip)
- Loading branch information
1 parent
e74b2f5
commit 53589b6
Showing
17 changed files
with
352 additions
and
236 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,57 @@ | ||
use bevy::{prelude::*, utils::HashSet}; | ||
use serde::{Deserialize, Serialize}; | ||
use shared::messages::NetworkPlayerInput; | ||
use shared::messages::PlayerFrameInput; | ||
|
||
#[derive(Debug, Default, Resource)] | ||
pub struct BufferedInputs { | ||
#[allow(dead_code)] | ||
pub buffer: Vec<PlayerFrameInputs>, | ||
pub struct PlayerTickInputsBuffer { | ||
pub buffer: Vec<PlayerFrameInput>, | ||
} | ||
|
||
#[derive(Debug, Clone, Serialize, Deserialize)] | ||
pub struct PlayerFrameInputs { | ||
pub time_ms: u64, | ||
pub inputs: HashSet<NetworkPlayerInput>, | ||
pub camera: Quat, | ||
#[derive(Resource, Default)] | ||
pub struct CurrentFrameInputs(pub PlayerFrameInput); | ||
|
||
pub trait CurrentFrameInputsExt { | ||
fn reset(&mut self, time: u64); | ||
} | ||
|
||
impl CurrentFrameInputsExt for CurrentFrameInputs { | ||
fn reset(&mut self, time: u64) { | ||
self.0 = PlayerFrameInput { | ||
time_ms: time, | ||
inputs: HashSet::default(), | ||
camera: Quat::default(), | ||
}; | ||
} | ||
} | ||
|
||
// Represents the synchronized time of the client | ||
// Currently, this is just the UNIX timestamp in milliseconds, assumed to be the same on the server and client | ||
// A NTP-like system could be implemented in the future | ||
#[derive(Resource)] | ||
pub struct SyncTime { | ||
pub last_time_ms: u64, | ||
pub curr_time_ms: u64, | ||
} | ||
|
||
impl Default for SyncTime { | ||
fn default() -> Self { | ||
let current_time_ms = std::time::SystemTime::now() | ||
.duration_since(std::time::UNIX_EPOCH) | ||
.unwrap() | ||
.as_millis() as u64; | ||
|
||
Self { | ||
last_time_ms: current_time_ms, | ||
curr_time_ms: current_time_ms, | ||
} | ||
} | ||
} | ||
|
||
pub trait SyncTimeExt { | ||
fn delta(&self) -> u64; | ||
} | ||
|
||
impl SyncTimeExt for SyncTime { | ||
fn delta(&self) -> u64 { | ||
self.curr_time_ms - self.last_time_ms | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,71 +1,18 @@ | ||
use crate::input::keyboard::is_action_pressed; | ||
use crate::KeyMap; | ||
use crate::{input::data::GameAction, world::time::ClientTime}; | ||
use bevy::input::ButtonInput; | ||
use bevy::prelude::*; | ||
use bevy_renet::renet::RenetClient; | ||
use ordered_float::OrderedFloat; | ||
use shared::messages::{CustomQuaternion, NetworkPlayerInput, PlayerInputs}; | ||
use shared::messages::ClientToServerMessage; | ||
|
||
use super::buffered_client::PlayerTickInputsBuffer; | ||
use super::SendGameMessageExtension; | ||
|
||
pub fn upload_player_inputs_system( | ||
mut client: ResMut<RenetClient>, | ||
keyboard_input: Res<ButtonInput<KeyCode>>, | ||
key_map: Res<KeyMap>, | ||
mut last_camera_orientation: Local<Option<Quat>>, | ||
camera: Query<&Transform, With<Camera>>, | ||
client_time: Res<ClientTime>, | ||
mut inputs: ResMut<PlayerTickInputsBuffer>, | ||
) { | ||
let mut actions: Vec<NetworkPlayerInput> = vec![]; | ||
if is_action_pressed(GameAction::MoveBackward, &keyboard_input, &key_map) { | ||
actions.push(NetworkPlayerInput::MoveBackward) | ||
} | ||
if is_action_pressed(GameAction::MoveForward, &keyboard_input, &key_map) { | ||
actions.push(NetworkPlayerInput::MoveForward) | ||
} | ||
if is_action_pressed(GameAction::MoveLeft, &keyboard_input, &key_map) { | ||
actions.push(NetworkPlayerInput::MoveLeft) | ||
} | ||
if is_action_pressed(GameAction::MoveRight, &keyboard_input, &key_map) { | ||
actions.push(NetworkPlayerInput::MoveRight) | ||
} | ||
if is_action_pressed(GameAction::Jump, &keyboard_input, &key_map) { | ||
actions.push(NetworkPlayerInput::Jump); | ||
} | ||
if is_action_pressed(GameAction::ToggleFlyMode, &keyboard_input, &key_map) { | ||
actions.push(NetworkPlayerInput::ToggleFlyMode) | ||
} | ||
if is_action_pressed(GameAction::FlyUp, &keyboard_input, &key_map) { | ||
actions.push(NetworkPlayerInput::FlyUp); | ||
} | ||
if is_action_pressed(GameAction::FlyDown, &keyboard_input, &key_map) { | ||
actions.push(NetworkPlayerInput::FlyDown); | ||
} | ||
|
||
let camera_transform = camera.single(); | ||
let camera_orientation = camera_transform.rotation; | ||
|
||
if let Some(last_cam) = last_camera_orientation.as_mut() { | ||
if *last_cam != camera_orientation { | ||
actions.push(NetworkPlayerInput::CameraMovement(CustomQuaternion { | ||
x: OrderedFloat(camera_orientation.x), | ||
y: OrderedFloat(camera_orientation.y), | ||
z: OrderedFloat(camera_orientation.z), | ||
w: OrderedFloat(camera_orientation.w), | ||
})); | ||
*last_camera_orientation = Some(camera_orientation); | ||
} | ||
} else { | ||
*last_camera_orientation = Some(camera_orientation); | ||
} | ||
|
||
let msg = PlayerInputs { | ||
tick: client_time.0, | ||
actions, | ||
}; | ||
if !msg.actions.is_empty() { | ||
// debug!("Sending player inputs: {:?}", msg); | ||
client.send_game_message(msg.into()); | ||
let mut frames = vec![]; | ||
for input in inputs.buffer.iter() { | ||
frames.push(input.clone()); | ||
} | ||
client.send_game_message(ClientToServerMessage::PlayerInputs(frames)); | ||
inputs.buffer.clear(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.