Merge branch 'master' into 'master'

Solve physics fighting problem

See merge request veloren/veloren!27

Former-commit-id: 010af4fb0f31b854dd1f8c42f6a65711cc9d84cd
This commit is contained in:
Joshua Barretto 2019-04-15 16:43:41 +00:00
commit a41b642570
8 changed files with 108 additions and 51 deletions

2
.gitignore vendored
View File

@ -1,9 +1,7 @@
# Rust # Rust
/target/ /target/
/Cargo.lock
/*/target/ /*/target/
/*/Cargo.lock
# IntelliJ # IntelliJ

View File

@ -40,7 +40,7 @@ pub struct Client {
tick: u64, tick: u64,
state: State, state: State,
player: Option<EcsEntity>, player: EcsEntity,
view_distance: u64, view_distance: u64,
pending_chunks: HashSet<Vec3<i32>>, pending_chunks: HashSet<Vec3<i32>>,
@ -68,7 +68,7 @@ impl Client {
let (state, player) = match postbox.next_message() { let (state, player) = match postbox.next_message() {
Some(ServerMsg::Handshake { ecs_state, player_entity }) => { Some(ServerMsg::Handshake { ecs_state, player_entity }) => {
let mut state = State::from_state_package(ecs_state); let mut state = State::from_state_package(ecs_state);
let player_entity = state.ecs().entity_from_uid(player_entity); let player_entity = state.ecs().entity_from_uid(player_entity).ok_or(Error::ServerWentMad)?;
(state, player_entity) (state, player_entity)
}, },
_ => return Err(Error::ServerWentMad), _ => return Err(Error::ServerWentMad),
@ -107,7 +107,7 @@ impl Client {
/// Get the player entity /// Get the player entity
#[allow(dead_code)] #[allow(dead_code)]
pub fn player(&self) -> Option<EcsEntity> { pub fn player(&self) -> EcsEntity {
self.player self.player
} }
@ -149,13 +149,17 @@ impl Client {
}); });
// Step 1 // Step 1
if let Some(ecs_entity) = self.player { if
self.state.read_storage::<comp::phys::Pos>().get(self.player).is_some() &&
self.state.read_storage::<comp::phys::Vel>().get(self.player).is_some() &&
self.state.read_storage::<comp::phys::Dir>().get(self.player).is_some() == true
{
// TODO: remove this // TODO: remove this
const PLAYER_VELOCITY: f32 = 100.0; const PLAYER_VELOCITY: f32 = 100.0;
// TODO: Set acceleration instead // TODO: Set acceleration instead
self.state.write_component(ecs_entity, comp::phys::Vel(Vec3::from(input.move_dir * PLAYER_VELOCITY) * 0.1)); self.state.write_component(self.player, comp::phys::Vel(Vec3::from(input.move_dir * PLAYER_VELOCITY) * 0.1));
if input.move_dir.magnitude() > 0.01 { if input.move_dir.magnitude() > 0.01 {
self.state.write_component(ecs_entity, comp::phys::Dir(input.move_dir.normalized().into())); self.state.write_component(self.player, comp::phys::Dir(input.move_dir.normalized().into()));
} }
} }
@ -163,27 +167,24 @@ impl Client {
self.state.tick(dt); self.state.tick(dt);
// Update the server about the player's physics attributes // Update the server about the player's physics attributes
if let Some(ecs_entity) = self.player {
match ( match (
self.state.read_storage().get(ecs_entity).cloned(), self.state.read_storage().get(self.player).cloned(),
self.state.read_storage().get(ecs_entity).cloned(), self.state.read_storage().get(self.player).cloned(),
self.state.read_storage().get(ecs_entity).cloned(), self.state.read_storage().get(self.player).cloned(),
) { ) {
(Some(pos), Some(vel), Some(dir)) => { (Some(pos), Some(vel), Some(dir)) => {
self.postbox.send_message(ClientMsg::PlayerPhysics { pos, vel, dir }); self.postbox.send_message(ClientMsg::PlayerPhysics { pos, vel, dir });
}, },
_ => {}, _ => {},
} }
}
// Request chunks from the server // Request chunks from the server
if let Some(player_entity) = self.player { if let Some(pos) = self.state.read_storage::<comp::phys::Pos>().get(self.player) {
if let Some(pos) = self.state.read_storage::<comp::phys::Pos>().get(player_entity) {
let chunk_pos = self.state.terrain().pos_key(pos.0.map(|e| e as i32)); let chunk_pos = self.state.terrain().pos_key(pos.0.map(|e| e as i32));
for i in chunk_pos.x - 0..chunk_pos.x + 1 { for i in chunk_pos.x - 1..chunk_pos.x + 1 {
for j in chunk_pos.y - 0..chunk_pos.y + 1 { for j in chunk_pos.y - 1..chunk_pos.y + 1 {
for k in 0..3 { for k in -1..3 {
let key = chunk_pos + Vec3::new(i, j, k); let key = chunk_pos + Vec3::new(i, j, k);
if self.state.terrain().get_key(key).is_none() && !self.pending_chunks.contains(&key) { if self.state.terrain().get_key(key).is_none() && !self.pending_chunks.contains(&key) {
self.postbox.send_message(ClientMsg::TerrainChunkRequest { key }); self.postbox.send_message(ClientMsg::TerrainChunkRequest { key });
@ -193,7 +194,6 @@ impl Client {
} }
} }
} }
}
// Finish the tick, pass control back to the frontend (step 6) // Finish the tick, pass control back to the frontend (step 6)
self.tick += 1; self.tick += 1;
@ -224,8 +224,16 @@ impl Client {
ServerMsg::Ping => self.postbox.send_message(ClientMsg::Pong), ServerMsg::Ping => self.postbox.send_message(ClientMsg::Pong),
ServerMsg::Pong => {}, ServerMsg::Pong => {},
ServerMsg::Chat(msg) => frontend_events.push(Event::Chat(msg)), ServerMsg::Chat(msg) => frontend_events.push(Event::Chat(msg)),
ServerMsg::SetPlayerEntity(uid) => self.player = Some(self.state.ecs().entity_from_uid(uid).unwrap()), // TODO: Don't unwrap here! ServerMsg::SetPlayerEntity(uid) => self.player = self.state.ecs().entity_from_uid(uid).unwrap(), // TODO: Don't unwrap here!
ServerMsg::EcsSync(sync_package) => self.state.ecs_mut().sync_with_package(sync_package), ServerMsg::EcsSync(sync_package) => self.state.ecs_mut().sync_with_package(sync_package),
ServerMsg::EntityPhysics { entity, pos, vel, dir } => match self.state.ecs().entity_from_uid(entity) {
Some(entity) => {
self.state.write_component(entity, pos);
self.state.write_component(entity, vel);
self.state.write_component(entity, dir);
},
None => {},
},
ServerMsg::TerrainChunkUpdate { key, chunk } => { ServerMsg::TerrainChunkUpdate { key, chunk } => {
self.state.insert_chunk(key, *chunk); self.state.insert_chunk(key, *chunk);
self.pending_chunks.remove(&key); self.pending_chunks.remove(&key);

View File

@ -1,4 +1,4 @@
use specs::{Component, VecStorage, FlaggedStorage}; use specs::{Component, VecStorage, FlaggedStorage, NullStorage};
use vek::*; use vek::*;
// Pos // Pos
@ -27,3 +27,12 @@ pub struct Dir(pub Vec3<f32>);
impl Component for Dir { impl Component for Dir {
type Storage = FlaggedStorage<Self, VecStorage<Self>>; type Storage = FlaggedStorage<Self, VecStorage<Self>>;
} }
// Dir
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)]
pub struct ForceUpdate;
impl Component for ForceUpdate {
type Storage = NullStorage<Self>;
}

View File

@ -1,5 +1,8 @@
use vek::*; use vek::*;
use crate::terrain::TerrainChunk; use crate::{
comp,
terrain::TerrainChunk,
};
use super::EcsPacket; use super::EcsPacket;
#[derive(Clone, Serialize, Deserialize)] #[derive(Clone, Serialize, Deserialize)]
@ -14,6 +17,12 @@ pub enum ServerMsg {
Chat(String), Chat(String),
SetPlayerEntity(u64), SetPlayerEntity(u64),
EcsSync(sphynx::SyncPackage<EcsPacket>), EcsSync(sphynx::SyncPackage<EcsPacket>),
EntityPhysics {
entity: u64,
pos: comp::phys::Pos,
vel: comp::phys::Vel,
dir: comp::phys::Dir,
},
TerrainChunkUpdate { TerrainChunkUpdate {
key: Vec3<i32>, key: Vec3<i32>,
chunk: Box<TerrainChunk>, chunk: Box<TerrainChunk>,

View File

@ -1,3 +1,6 @@
// Reexports
pub use sphynx::Uid;
use std::{ use std::{
time::Duration, time::Duration,
collections::HashSet, collections::HashSet,
@ -90,12 +93,14 @@ impl State {
// Create a new Sphynx ECS world // Create a new Sphynx ECS world
fn setup_sphynx_world(ecs: &mut sphynx::World<EcsPacket>) { fn setup_sphynx_world(ecs: &mut sphynx::World<EcsPacket>) {
// Register synced components // Register synced components
ecs.register_synced::<comp::phys::Pos>();
ecs.register_synced::<comp::phys::Vel>();
ecs.register_synced::<comp::phys::Dir>();
ecs.register_synced::<comp::Character>(); ecs.register_synced::<comp::Character>();
ecs.register_synced::<comp::Player>(); ecs.register_synced::<comp::Player>();
// Register unsynched (or synced by other means) components
ecs.internal_mut().register::<comp::phys::Pos>();
ecs.internal_mut().register::<comp::phys::Vel>();
ecs.internal_mut().register::<comp::phys::Dir>();
// Register resources used by the ECS // Register resources used by the ECS
ecs.internal_mut().add_resource(TimeOfDay(0.0)); ecs.internal_mut().add_resource(TimeOfDay(0.0));
ecs.internal_mut().add_resource(Time(0.0)); ecs.internal_mut().add_resource(Time(0.0));

View File

@ -27,7 +27,7 @@ use vek::*;
use threadpool::ThreadPool; use threadpool::ThreadPool;
use common::{ use common::{
comp, comp,
state::State, state::{State, Uid},
net::PostOffice, net::PostOffice,
msg::{ServerMsg, ClientMsg}, msg::{ServerMsg, ClientMsg},
terrain::TerrainChunk, terrain::TerrainChunk,
@ -73,8 +73,11 @@ impl Server {
pub fn new() -> Result<Self, Error> { pub fn new() -> Result<Self, Error> {
let (chunk_tx, chunk_rx) = mpsc::channel(); let (chunk_tx, chunk_rx) = mpsc::channel();
let mut state = State::new();
state.ecs_mut().internal_mut().register::<comp::phys::ForceUpdate>();
Ok(Self { Ok(Self {
state: State::new(), state,
world: World::new(), world: World::new(),
postoffice: PostOffice::bind(SocketAddr::from(([0; 4], 59003)))?, postoffice: PostOffice::bind(SocketAddr::from(([0; 4], 59003)))?,
@ -184,6 +187,9 @@ impl Server {
.create_entity_synced() .create_entity_synced()
.build(); .build();
// Make sure the entity gets properly created
self.state.ecs_mut().internal_mut().maintain();
self.clients.add(entity, Client { self.clients.add(entity, Client {
state: ClientState::Connecting, state: ClientState::Connecting,
postbox, postbox,
@ -229,6 +235,7 @@ impl Server {
if let Some(character) = character { if let Some(character) = character {
state.write_component(entity, character); state.write_component(entity, character);
} }
state.write_component(entity, comp::phys::ForceUpdate);
client.state = ClientState::Connected; client.state = ClientState::Connected;
@ -303,7 +310,7 @@ impl Server {
// Handle client disconnects // Handle client disconnects
for entity in disconnected_clients { for entity in disconnected_clients {
state.ecs_mut().delete_entity_synced(entity); state.ecs_mut().delete_entity_synced(entity).unwrap();
frontend_events.push(Event::ClientDisconnected { frontend_events.push(Event::ClientDisconnected {
entity, entity,
@ -320,7 +327,33 @@ impl Server {
/// Sync client states with the most up to date information /// Sync client states with the most up to date information
fn sync_clients(&mut self) { fn sync_clients(&mut self) {
// Sync 'logical' state using Sphynx
self.clients.notify_connected(ServerMsg::EcsSync(self.state.ecs_mut().next_sync_package())); self.clients.notify_connected(ServerMsg::EcsSync(self.state.ecs_mut().next_sync_package()));
// Sync 'physical' state
for (entity, &uid, &pos, &vel, &dir, force_update) in (
&self.state.ecs().internal().entities(),
&self.state.ecs().internal().read_storage::<Uid>(),
&self.state.ecs().internal().read_storage::<comp::phys::Pos>(),
&self.state.ecs().internal().read_storage::<comp::phys::Vel>(),
&self.state.ecs().internal().read_storage::<comp::phys::Dir>(),
self.state.ecs().internal().read_storage::<comp::phys::ForceUpdate>().maybe(),
).join() {
let msg = ServerMsg::EntityPhysics {
entity: uid.into(),
pos,
vel,
dir,
};
match force_update {
Some(_) => self.clients.notify_connected(msg),
None => self.clients.notify_connected_except(entity, msg),
}
}
// Remove all force flags
self.state.ecs_mut().internal_mut().write_storage::<comp::phys::ForceUpdate>().clear();
} }
pub fn generate_chunk(&mut self, key: Vec3<i32>) { pub fn generate_chunk(&mut self, key: Vec3<i32>) {

View File

@ -109,15 +109,12 @@ impl Scene {
pub fn maintain(&mut self, renderer: &mut Renderer, client: &mut Client) { pub fn maintain(&mut self, renderer: &mut Renderer, client: &mut Client) {
// Get player position // Get player position
let player_pos = client let player_pos = client
.player()
.and_then(|ent| client
.state() .state()
.ecs() .ecs()
.internal() .internal()
.read_storage::<comp::phys::Pos>() .read_storage::<comp::phys::Pos>()
.get(ent) .get(client.player())
.map(|pos| pos.0) .map(|pos| pos.0)
)
.unwrap_or(Vec3::zero()); .unwrap_or(Vec3::zero());
// Alter camera position to match player // Alter camera position to match player

View File

@ -143,9 +143,7 @@ impl Window {
pub fn grab_cursor(&mut self, grab: bool) { pub fn grab_cursor(&mut self, grab: bool) {
self.cursor_grabbed = grab; self.cursor_grabbed = grab;
self.window.hide_cursor(grab); self.window.hide_cursor(grab);
self.window let _ = self.window.grab_cursor(grab);
.grab_cursor(grab)
.expect("Failed to grab/ungrab cursor");
} }
pub fn needs_refresh_resize(&mut self) { pub fn needs_refresh_resize(&mut self) {