2019-01-02 19:22:01 +00:00
|
|
|
// Standard
|
|
|
|
use std::time::Duration;
|
|
|
|
|
2019-01-23 20:01:58 +00:00
|
|
|
// Library
|
|
|
|
use shred::{Fetch, FetchMut};
|
2019-03-02 03:48:30 +00:00
|
|
|
use specs::{Builder, Component, DispatcherBuilder, Entity as EcsEntity, World as EcsWorld};
|
2019-01-23 20:01:58 +00:00
|
|
|
use vek::*;
|
2019-01-02 19:22:01 +00:00
|
|
|
|
|
|
|
// Crate
|
2019-03-02 03:48:30 +00:00
|
|
|
use crate::{comp, sys, terrain::TerrainMap};
|
2019-01-02 19:22:01 +00:00
|
|
|
|
2019-01-12 15:57:19 +00:00
|
|
|
/// How much faster should an in-game day be compared to a real day?
|
|
|
|
// TODO: Don't hard-code this
|
|
|
|
const DAY_CYCLE_FACTOR: f64 = 24.0 * 60.0;
|
|
|
|
|
|
|
|
/// A resource to store the time of day
|
|
|
|
struct TimeOfDay(f64);
|
|
|
|
|
|
|
|
/// A resource to store the tick (i.e: physics) time
|
2019-01-23 20:01:58 +00:00
|
|
|
struct Time(f64);
|
|
|
|
|
2019-03-02 03:48:30 +00:00
|
|
|
/// A resource used to store the time since the last tick
|
|
|
|
#[derive(Default)]
|
|
|
|
pub struct DeltaTime(pub f64);
|
|
|
|
|
2019-01-23 20:01:58 +00:00
|
|
|
pub struct Changes {
|
|
|
|
pub new_chunks: Vec<Vec3<i32>>,
|
|
|
|
pub changed_chunks: Vec<Vec3<i32>>,
|
|
|
|
pub removed_chunks: Vec<Vec3<i32>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Changes {
|
|
|
|
pub fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
new_chunks: vec![],
|
|
|
|
changed_chunks: vec![],
|
|
|
|
removed_chunks: vec![],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn cleanup(&mut self) {
|
|
|
|
self.new_chunks.clear();
|
|
|
|
self.changed_chunks.clear();
|
|
|
|
self.removed_chunks.clear();
|
|
|
|
}
|
|
|
|
}
|
2019-01-12 15:57:19 +00:00
|
|
|
|
|
|
|
/// A type used to represent game state stored on both the client and the server. This includes
|
|
|
|
/// things like entity components, terrain data, and global state like weather, time of day, etc.
|
2019-01-02 19:22:01 +00:00
|
|
|
pub struct State {
|
|
|
|
ecs_world: EcsWorld,
|
2019-01-23 20:01:58 +00:00
|
|
|
changes: Changes,
|
2019-01-02 19:22:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl State {
|
2019-01-12 15:57:19 +00:00
|
|
|
/// Create a new `State`.
|
2019-01-02 19:22:01 +00:00
|
|
|
pub fn new() -> Self {
|
|
|
|
let mut ecs_world = EcsWorld::new();
|
|
|
|
|
2019-01-12 15:57:19 +00:00
|
|
|
// Register resources used by the ECS
|
|
|
|
ecs_world.add_resource(TimeOfDay(0.0));
|
2019-01-23 20:01:58 +00:00
|
|
|
ecs_world.add_resource(Time(0.0));
|
2019-03-02 03:48:30 +00:00
|
|
|
ecs_world.add_resource(DeltaTime(0.0));
|
2019-01-14 18:49:53 +00:00
|
|
|
ecs_world.add_resource(TerrainMap::new());
|
2019-01-12 15:57:19 +00:00
|
|
|
|
|
|
|
// Register common components with the state
|
2019-01-02 19:22:01 +00:00
|
|
|
comp::register_local_components(&mut ecs_world);
|
|
|
|
|
|
|
|
Self {
|
|
|
|
ecs_world,
|
2019-01-23 20:01:58 +00:00
|
|
|
changes: Changes::default(),
|
2019-01-02 19:22:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-02 03:48:30 +00:00
|
|
|
// TODO: Get rid of this
|
|
|
|
pub fn new_test_player(&mut self) -> EcsEntity {
|
|
|
|
self.ecs_world
|
|
|
|
.create_entity()
|
|
|
|
.with(comp::phys::Pos(Vec3::default()))
|
|
|
|
.with(comp::phys::Vel(Vec3::default()))
|
|
|
|
.with(comp::phys::Dir(Vec3::default()))
|
|
|
|
.build()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Write a component
|
|
|
|
pub fn write_component<C: Component>(&mut self, e: EcsEntity, c: C) {
|
|
|
|
let _ = self.ecs_world.write_storage().insert(e, c);
|
|
|
|
}
|
|
|
|
|
2019-01-23 20:01:58 +00:00
|
|
|
/// Get a reference to the internal ECS world
|
2019-03-02 03:48:30 +00:00
|
|
|
pub fn ecs_world(&self) -> &EcsWorld {
|
|
|
|
&self.ecs_world
|
|
|
|
}
|
2019-01-23 20:01:58 +00:00
|
|
|
|
|
|
|
/// Get a reference to the `Changes` structure of the state. This contains
|
|
|
|
/// information about state that has changed since the last game tick.
|
2019-03-02 03:48:30 +00:00
|
|
|
pub fn changes(&self) -> &Changes {
|
|
|
|
&self.changes
|
|
|
|
}
|
2019-01-23 20:01:58 +00:00
|
|
|
|
|
|
|
// TODO: Get rid of this since it shouldn't be needed
|
2019-03-02 03:48:30 +00:00
|
|
|
pub fn changes_mut(&mut self) -> &mut Changes {
|
|
|
|
&mut self.changes
|
|
|
|
}
|
2019-01-23 20:01:58 +00:00
|
|
|
|
2019-01-12 15:57:19 +00:00
|
|
|
/// Get the current in-game time of day.
|
|
|
|
///
|
|
|
|
/// Note that this should not be used for physics, animations or other such localised timings.
|
|
|
|
pub fn get_time_of_day(&self) -> f64 {
|
|
|
|
self.ecs_world.read_resource::<TimeOfDay>().0
|
|
|
|
}
|
|
|
|
|
2019-01-23 20:01:58 +00:00
|
|
|
/// Get the current in-game time.
|
2019-01-12 15:57:19 +00:00
|
|
|
///
|
|
|
|
/// Note that this does not correspond to the time of day.
|
2019-01-23 20:01:58 +00:00
|
|
|
pub fn get_time(&self) -> f64 {
|
|
|
|
self.ecs_world.read_resource::<Time>().0
|
2019-01-12 15:57:19 +00:00
|
|
|
}
|
|
|
|
|
2019-01-14 18:49:53 +00:00
|
|
|
/// Get a reference to this state's terrain.
|
2019-03-02 03:48:30 +00:00
|
|
|
pub fn terrain(&self) -> Fetch<TerrainMap> {
|
2019-01-14 18:49:53 +00:00
|
|
|
self.ecs_world.read_resource::<TerrainMap>()
|
|
|
|
}
|
|
|
|
|
2019-01-23 20:01:58 +00:00
|
|
|
// TODO: Get rid of this since it shouldn't be needed
|
2019-03-02 03:48:30 +00:00
|
|
|
pub fn terrain_mut(&mut self) -> FetchMut<TerrainMap> {
|
2019-01-23 20:01:58 +00:00
|
|
|
self.ecs_world.write_resource::<TerrainMap>()
|
|
|
|
}
|
|
|
|
|
2019-01-12 15:57:19 +00:00
|
|
|
/// Execute a single tick, simulating the game state by the given duration.
|
2019-01-02 19:22:01 +00:00
|
|
|
pub fn tick(&mut self, dt: Duration) {
|
2019-01-12 15:57:19 +00:00
|
|
|
// Change the time accordingly
|
|
|
|
self.ecs_world.write_resource::<TimeOfDay>().0 += dt.as_float_secs() * DAY_CYCLE_FACTOR;
|
2019-01-23 20:01:58 +00:00
|
|
|
self.ecs_world.write_resource::<Time>().0 += dt.as_float_secs();
|
2019-03-02 03:48:30 +00:00
|
|
|
|
|
|
|
// Run systems to update the world
|
|
|
|
self.ecs_world.write_resource::<DeltaTime>().0 = dt.as_float_secs();
|
|
|
|
|
|
|
|
// Create and run dispatcher for ecs systems
|
|
|
|
let mut dispatch_builder = DispatcherBuilder::new();
|
|
|
|
sys::add_local_systems(&mut dispatch_builder);
|
|
|
|
// This dispatches all the systems in parallel
|
|
|
|
dispatch_builder.build().dispatch(&self.ecs_world.res);
|
|
|
|
|
|
|
|
self.ecs_world.maintain();
|
2019-01-23 20:01:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Clean up the state after a tick
|
|
|
|
pub fn cleanup(&mut self) {
|
|
|
|
// Clean up data structures from the last tick
|
|
|
|
self.changes.cleanup();
|
2019-01-02 19:22:01 +00:00
|
|
|
}
|
|
|
|
}
|