Improved State API design

Former-commit-id: a32ab93409b1044fe2838f684d30ca2b963d4eb2
This commit is contained in:
Joshua Barretto 2019-03-06 13:48:44 +00:00
parent 99bd0630b7
commit ffc4e6ebd4
5 changed files with 50 additions and 40 deletions

View File

@ -16,12 +16,9 @@ use std::{
}; };
use vek::*; use vek::*;
use threadpool; use threadpool;
use specs::{ use specs::Builder;
Builder,
saveload::MarkerAllocator,
};
use common::{ use common::{
comp::{self, Uid}, comp,
state::State, state::State,
terrain::TerrainChunk, terrain::TerrainChunk,
net::PostBox, net::PostBox,
@ -104,30 +101,6 @@ impl Client {
#[allow(dead_code)] #[allow(dead_code)]
pub fn state_mut(&mut self) -> &mut State { &mut self.state } pub fn state_mut(&mut self) -> &mut State { &mut self.state }
/// Get an entity from its UID, creating it if it does not exists
pub fn get_or_create_entity_from_uid(&mut self, uid: Uid) -> EcsEntity {
// Find the ECS entity from its UID
let ecs_entity = self.state().ecs_world()
.read_resource::<comp::UidAllocator>()
.retrieve_entity_internal(uid.into());
// Return the entity or create it
if let Some(ecs_entity) = ecs_entity {
ecs_entity
} else {
let ecs_entity = self.state.ecs_world_mut().create_entity()
.build();
// Allocate it the specific UID given
self.state
.ecs_world_mut()
.write_resource::<comp::UidAllocator>()
.allocate(ecs_entity, Some(uid.into()));
ecs_entity
}
}
/// Get the player entity /// Get the player entity
#[allow(dead_code)] #[allow(dead_code)]
pub fn player(&self) -> Option<EcsEntity> { pub fn player(&self) -> Option<EcsEntity> {
@ -222,11 +195,17 @@ impl Client {
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) => { ServerMsg::SetPlayerEntity(uid) => {
let ecs_entity = self.get_or_create_entity_from_uid(uid); let ecs_entity = self.state
.get_entity(uid)
.unwrap_or_else(|| self.state.build_uid_entity_with_uid(uid).build());
self.player = Some(ecs_entity); self.player = Some(ecs_entity);
}, },
ServerMsg::EntityPhysics { uid, pos, vel, dir } => { ServerMsg::EntityPhysics { uid, pos, vel, dir } => {
let ecs_entity = self.get_or_create_entity_from_uid(uid); let ecs_entity = self.state
.get_entity(uid)
.unwrap_or_else(|| self.state.build_uid_entity_with_uid(uid).build());
self.state.write_component(ecs_entity, pos); self.state.write_component(ecs_entity, pos);
self.state.write_component(ecs_entity, vel); self.state.write_component(ecs_entity, vel);
self.state.write_component(ecs_entity, dir); self.state.write_component(ecs_entity, dir);

View File

@ -1,5 +1,6 @@
pub mod phys; pub mod phys;
pub mod uid; pub mod uid;
pub mod util;
// Reexports // Reexports
pub use uid::{Uid, UidAllocator}; pub use uid::{Uid, UidAllocator};
@ -10,6 +11,8 @@ pub fn register_local_components(ecs_world: &mut EcsWorld) {
ecs_world.register::<Uid>(); ecs_world.register::<Uid>();
ecs_world.add_resource(UidAllocator::new()); ecs_world.add_resource(UidAllocator::new());
ecs_world.register::<util::New>();
ecs_world.register::<phys::Pos>(); ecs_world.register::<phys::Pos>();
ecs_world.register::<phys::Vel>(); ecs_world.register::<phys::Vel>();
ecs_world.register::<phys::Dir>(); ecs_world.register::<phys::Dir>();

12
common/src/comp/util.rs Normal file
View File

@ -0,0 +1,12 @@
// Library
use specs::{Component, NullStorage};
use vek::*;
// Pos
#[derive(Copy, Clone, Debug, Default)]
pub struct New;
impl Component for New {
type Storage = NullStorage<Self>;
}

View File

@ -4,13 +4,14 @@ use specs::{
Builder, Builder,
Component, Component,
DispatcherBuilder, DispatcherBuilder,
EntityBuilder as EcsEntityBuilder,
Entity as EcsEntity, Entity as EcsEntity,
World as EcsWorld, World as EcsWorld,
storage::{ storage::{
Storage as EcsStorage, Storage as EcsStorage,
MaskedStorage as EcsMaskedStorage, MaskedStorage as EcsMaskedStorage,
}, },
saveload::MarkerAllocator, saveload::{MarkedBuilder, MarkerAllocator},
}; };
use vek::*; use vek::*;
use crate::{ use crate::{
@ -90,6 +91,24 @@ impl State {
self self
} }
/// Build a new entity with a generated UID
pub fn build_uid_entity(&mut self) -> EcsEntityBuilder {
self.ecs_world.create_entity()
.with(comp::util::New)
.marked::<comp::Uid>()
}
/// Build an entity with a specific UID
pub fn build_uid_entity_with_uid(&mut self, uid: comp::Uid) -> EcsEntityBuilder {
let builder = self.build_uid_entity();
builder.world
.write_resource::<comp::UidAllocator>()
.allocate(builder.entity, Some(uid.into()));
builder
}
/// Get an entity from its UID, if it exists /// Get an entity from its UID, if it exists
pub fn get_entity(&self, uid: comp::Uid) -> Option<EcsEntity> { pub fn get_entity(&self, uid: comp::Uid) -> Option<EcsEntity> {
// Find the ECS entity from its UID // Find the ECS entity from its UID
@ -168,6 +187,9 @@ impl State {
/// Execute a single tick, simulating the game state by the given duration. /// Execute a single tick, simulating the game state by the given duration.
pub fn tick(&mut self, dt: Duration) { pub fn tick(&mut self, dt: Duration) {
// First, wipe all temporary marker components
self.ecs_world.write_storage::<comp::util::New>().clear();
// Change the time accordingly // Change the time accordingly
self.ecs_world.write_resource::<TimeOfDay>().0 += dt.as_secs_f64() * DAY_CYCLE_FACTOR; self.ecs_world.write_resource::<TimeOfDay>().0 += dt.as_secs_f64() * DAY_CYCLE_FACTOR;
self.ecs_world.write_resource::<Time>().0 += dt.as_secs_f64(); self.ecs_world.write_resource::<Time>().0 += dt.as_secs_f64();

View File

@ -77,15 +77,9 @@ impl Server {
#[allow(dead_code)] #[allow(dead_code)]
pub fn state_mut(&mut self) -> &mut State { &mut self.state } pub fn state_mut(&mut self) -> &mut State { &mut self.state }
/// Build a new entity with a generated UID
pub fn build_entity(&mut self) -> EcsEntityBuilder {
self.state.ecs_world_mut().create_entity()
.marked::<comp::Uid>()
}
/// Build a new player with a generated UID /// Build a new player with a generated UID
pub fn build_player(&mut self) -> EcsEntityBuilder { pub fn build_player(&mut self) -> EcsEntityBuilder {
self.build_entity() self.state.build_uid_entity()
.with(comp::phys::Pos(Vec3::zero())) .with(comp::phys::Pos(Vec3::zero()))
.with(comp::phys::Vel(Vec3::zero())) .with(comp::phys::Vel(Vec3::zero()))
.with(comp::phys::Dir(Vec3::unit_y())) .with(comp::phys::Dir(Vec3::unit_y()))
@ -207,7 +201,7 @@ impl Server {
} }
} else if } else if
state.get_time() - client.last_ping > CLIENT_TIMEOUT || // Timeout state.get_time() - client.last_ping > CLIENT_TIMEOUT || // Timeout
client.postbox.error().is_some() // Postbox eror client.postbox.error().is_some() // Postbox error
{ {
disconnected = true; disconnected = true;
} }