mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added entity simulation to rtsim, reification, assimilation
This commit is contained in:
parent
2b5e09e32e
commit
99a881f349
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -5402,10 +5402,12 @@ dependencies = [
|
|||||||
"portpicker",
|
"portpicker",
|
||||||
"prometheus",
|
"prometheus",
|
||||||
"rand 0.7.3",
|
"rand 0.7.3",
|
||||||
|
"rand_chacha 0.2.2",
|
||||||
"ron",
|
"ron",
|
||||||
"scan_fmt",
|
"scan_fmt",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"slab",
|
||||||
"specs",
|
"specs",
|
||||||
"specs-idvs",
|
"specs-idvs",
|
||||||
"tiny_http",
|
"tiny_http",
|
||||||
|
@ -179,12 +179,12 @@ void main() {
|
|||||||
// float reflected_light_point = /*length*/(diffuse_light_point.r) + f_light * point_shadow;
|
// float reflected_light_point = /*length*/(diffuse_light_point.r) + f_light * point_shadow;
|
||||||
// reflected_light += k_d * (diffuse_light_point + f_light * point_shadow * shade_frac) + specular_light_point;
|
// reflected_light += k_d * (diffuse_light_point + f_light * point_shadow * shade_frac) + specular_light_point;
|
||||||
|
|
||||||
float passthrough = /*pow(*/dot(cam_norm, -cam_to_frag/*view_dir*/)/*, 0.5)*/;
|
float passthrough = clamp(dot(cam_norm, -cam_to_frag) * 1.0 - 0.2, 0, 1);
|
||||||
float min_refl = min(emitted_light.r, min(emitted_light.g, emitted_light.b));
|
float min_refl = min(emitted_light.r, min(emitted_light.g, emitted_light.b));
|
||||||
|
|
||||||
vec3 surf_color = illuminate(max_light, view_dir, water_color * /* fog_color * */emitted_light, /*surf_color * */water_color * reflected_light);
|
vec3 surf_color = illuminate(max_light, view_dir, water_color * /* fog_color * */emitted_light, /*surf_color * */water_color * reflected_light);
|
||||||
// vec4 color = vec4(surf_color, passthrough * 1.0 / (1.0 + min_refl));// * (1.0 - /*log(1.0 + cam_attenuation)*//*cam_attenuation*/1.0 / (2.0 - log_cam)));
|
// vec4 color = vec4(surf_color, passthrough * 1.0 / (1.0 + min_refl));// * (1.0 - /*log(1.0 + cam_attenuation)*//*cam_attenuation*/1.0 / (2.0 - log_cam)));
|
||||||
vec4 color = mix(vec4(surf_color, 1.0), vec4(surf_color, 1.0 / (1.0 + /*diffuse_light*//*(f_light * point_shadow + point_light)*//*4.0 * reflected_light_point*/min_refl/* * 0.25*/)), passthrough);
|
vec4 color = vec4(surf_color, (1.0 - passthrough) * 1.0 / (1.0 + min_refl));
|
||||||
|
|
||||||
tgt_color = color;
|
tgt_color = color;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,11 @@
|
|||||||
use crate::{character::CharacterId, comp, sync::Uid, util::Dir, Explosion};
|
use crate::{
|
||||||
|
character::CharacterId,
|
||||||
|
sync::Uid,
|
||||||
|
util::Dir,
|
||||||
|
comp,
|
||||||
|
Explosion,
|
||||||
|
rtsim::RtSimEntity,
|
||||||
|
};
|
||||||
use comp::{
|
use comp::{
|
||||||
item::{Item, Reagent},
|
item::{Item, Reagent},
|
||||||
Ori, Pos,
|
Ori, Pos,
|
||||||
@ -96,6 +103,7 @@ pub enum ServerEvent {
|
|||||||
ExitIngame {
|
ExitIngame {
|
||||||
entity: EcsEntity,
|
entity: EcsEntity,
|
||||||
},
|
},
|
||||||
|
// TODO: to avoid breakage when adding new fields, perhaps have an `NpcBuilder` type?
|
||||||
CreateNpc {
|
CreateNpc {
|
||||||
pos: comp::Pos,
|
pos: comp::Pos,
|
||||||
stats: comp::Stats,
|
stats: comp::Stats,
|
||||||
@ -107,6 +115,7 @@ pub enum ServerEvent {
|
|||||||
scale: comp::Scale,
|
scale: comp::Scale,
|
||||||
home_chunk: Option<comp::HomeChunk>,
|
home_chunk: Option<comp::HomeChunk>,
|
||||||
drop_item: Option<Item>,
|
drop_item: Option<Item>,
|
||||||
|
rtsim_entity: Option<RtSimEntity>,
|
||||||
},
|
},
|
||||||
CreateWaypoint(Vec3<f32>),
|
CreateWaypoint(Vec3<f32>),
|
||||||
ClientDisconnect(EcsEntity),
|
ClientDisconnect(EcsEntity),
|
||||||
|
@ -40,6 +40,7 @@ pub mod path;
|
|||||||
pub mod ray;
|
pub mod ray;
|
||||||
pub mod recipe;
|
pub mod recipe;
|
||||||
pub mod region;
|
pub mod region;
|
||||||
|
pub mod rtsim;
|
||||||
pub mod spiral;
|
pub mod spiral;
|
||||||
pub mod state;
|
pub mod state;
|
||||||
pub mod states;
|
pub mod states;
|
||||||
|
15
common/src/rtsim.rs
Normal file
15
common/src/rtsim.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// We'd like to not have this file in `common`, but sadly there are
|
||||||
|
// things in `common` that require it (currently, `ServerEvent`). When
|
||||||
|
// possible, this should be moved to the `rtsim` module in `server`.
|
||||||
|
|
||||||
|
use specs_idvs::IdvStorage;
|
||||||
|
use specs::Component;
|
||||||
|
|
||||||
|
pub type RtSimId = usize;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub struct RtSimEntity(pub RtSimId);
|
||||||
|
|
||||||
|
impl Component for RtSimEntity {
|
||||||
|
type Storage = IdvStorage<Self>;
|
||||||
|
}
|
@ -18,7 +18,10 @@ pub use self::{
|
|||||||
use roots::find_roots_cubic;
|
use roots::find_roots_cubic;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{vol::RectVolSize, volumes::vol_grid_2d::VolGrid2d};
|
use crate::{
|
||||||
|
vol::{RectVolSize, ReadVol},
|
||||||
|
volumes::vol_grid_2d::VolGrid2d,
|
||||||
|
};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
// TerrainChunkSize
|
// TerrainChunkSize
|
||||||
@ -106,6 +109,27 @@ impl TerrainChunkMeta {
|
|||||||
pub type TerrainChunk = chonk::Chonk<Block, TerrainChunkSize, TerrainChunkMeta>;
|
pub type TerrainChunk = chonk::Chonk<Block, TerrainChunkSize, TerrainChunkMeta>;
|
||||||
pub type TerrainGrid = VolGrid2d<TerrainChunk>;
|
pub type TerrainGrid = VolGrid2d<TerrainChunk>;
|
||||||
|
|
||||||
|
impl TerrainGrid {
|
||||||
|
/// Find a location suitable for spawning an entity near the given
|
||||||
|
/// position (but in the same chunk).
|
||||||
|
pub fn find_space(&self, pos: Vec3<i32>) -> Vec3<i32> {
|
||||||
|
let mut z_diff = 0;
|
||||||
|
for _ in 0..128 {
|
||||||
|
let test_pos = pos + Vec3::unit_z() * z_diff;
|
||||||
|
if (0..2)
|
||||||
|
.all(|z| self
|
||||||
|
.get(test_pos + Vec3::unit_z() * z)
|
||||||
|
.map(|b| !b.is_solid())
|
||||||
|
.unwrap_or(true))
|
||||||
|
{
|
||||||
|
return test_pos;
|
||||||
|
}
|
||||||
|
z_diff = -z_diff + if z_diff <= 0 { 1 } else { 0 };
|
||||||
|
}
|
||||||
|
pos
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Terrain helper functions used across multiple crates.
|
// Terrain helper functions used across multiple crates.
|
||||||
|
|
||||||
/// Computes the position Vec2 of a SimChunk from an index, where the index was
|
/// Computes the position Vec2 of a SimChunk from an index, where the index was
|
||||||
|
@ -43,3 +43,5 @@ libsqlite3-sys = { version = "0.18", features = ["bundled"] }
|
|||||||
diesel = { version = "1.4.3", features = ["sqlite"] }
|
diesel = { version = "1.4.3", features = ["sqlite"] }
|
||||||
diesel_migrations = "1.4.0"
|
diesel_migrations = "1.4.0"
|
||||||
dotenv = "0.15.0"
|
dotenv = "0.15.0"
|
||||||
|
slab = "0.4"
|
||||||
|
rand_chacha = "0.2"
|
||||||
|
@ -7,6 +7,7 @@ use common::{
|
|||||||
},
|
},
|
||||||
outcome::Outcome,
|
outcome::Outcome,
|
||||||
util::Dir,
|
util::Dir,
|
||||||
|
rtsim::RtSimEntity,
|
||||||
};
|
};
|
||||||
use comp::group;
|
use comp::group;
|
||||||
use specs::{Builder, Entity as EcsEntity, WorldExt};
|
use specs::{Builder, Entity as EcsEntity, WorldExt};
|
||||||
@ -50,6 +51,7 @@ pub fn handle_create_npc(
|
|||||||
scale: Scale,
|
scale: Scale,
|
||||||
drop_item: Option<Item>,
|
drop_item: Option<Item>,
|
||||||
home_chunk: Option<HomeChunk>,
|
home_chunk: Option<HomeChunk>,
|
||||||
|
rtsim_entity: Option<RtSimEntity>,
|
||||||
) {
|
) {
|
||||||
let group = match alignment {
|
let group = match alignment {
|
||||||
Alignment::Wild => None,
|
Alignment::Wild => None,
|
||||||
@ -90,6 +92,12 @@ pub fn handle_create_npc(
|
|||||||
entity
|
entity
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let entity = if let Some(rtsim_entity) = rtsim_entity {
|
||||||
|
entity.with(rtsim_entity)
|
||||||
|
} else {
|
||||||
|
entity
|
||||||
|
};
|
||||||
|
|
||||||
entity.build();
|
entity.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ use crate::{
|
|||||||
client::Client,
|
client::Client,
|
||||||
comp::{biped_large, quadruped_medium, quadruped_small, PhysicsState},
|
comp::{biped_large, quadruped_medium, quadruped_small, PhysicsState},
|
||||||
Server, SpawnPoint, StateExt,
|
Server, SpawnPoint, StateExt,
|
||||||
|
rtsim::RtSim,
|
||||||
};
|
};
|
||||||
use common::{
|
use common::{
|
||||||
assets::Asset,
|
assets::Asset,
|
||||||
@ -20,6 +21,7 @@ use common::{
|
|||||||
terrain::{Block, TerrainGrid},
|
terrain::{Block, TerrainGrid},
|
||||||
vol::ReadVol,
|
vol::ReadVol,
|
||||||
Damage, DamageSource, Explosion, GroupTarget, RadiusEffect,
|
Damage, DamageSource, Explosion, GroupTarget, RadiusEffect,
|
||||||
|
rtsim::RtSimEntity,
|
||||||
};
|
};
|
||||||
use comp::item::Reagent;
|
use comp::item::Reagent;
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
@ -308,7 +310,7 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, cause: HealthSourc
|
|||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
if state
|
let should_delete = if state
|
||||||
.ecs()
|
.ecs()
|
||||||
.write_storage::<Client>()
|
.write_storage::<Client>()
|
||||||
.get_mut(entity)
|
.get_mut(entity)
|
||||||
@ -339,6 +341,8 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, cause: HealthSourc
|
|||||||
.ecs()
|
.ecs()
|
||||||
.write_storage::<comp::CharacterState>()
|
.write_storage::<comp::CharacterState>()
|
||||||
.insert(entity, comp::CharacterState::default());
|
.insert(entity, comp::CharacterState::default());
|
||||||
|
|
||||||
|
false
|
||||||
} else if state.ecs().read_storage::<comp::Agent>().contains(entity) {
|
} else if state.ecs().read_storage::<comp::Agent>().contains(entity) {
|
||||||
use specs::Builder;
|
use specs::Builder;
|
||||||
|
|
||||||
@ -452,10 +456,16 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, cause: HealthSourc
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = state
|
true
|
||||||
.delete_entity_recorded(entity)
|
|
||||||
.map_err(|e| error!(?e, ?entity, "Failed to delete destroyed entity"));
|
|
||||||
} else {
|
} else {
|
||||||
|
true
|
||||||
|
};
|
||||||
|
|
||||||
|
if should_delete {
|
||||||
|
if let Some(rtsim_entity) = state.ecs().read_storage::<RtSimEntity>().get(entity).copied() {
|
||||||
|
state.ecs().write_resource::<RtSim>().destroy_entity(rtsim_entity.0);
|
||||||
|
}
|
||||||
|
|
||||||
let _ = state
|
let _ = state
|
||||||
.delete_entity_recorded(entity)
|
.delete_entity_recorded(entity)
|
||||||
.map_err(|e| error!(?e, ?entity, "Failed to delete destroyed entity"));
|
.map_err(|e| error!(?e, ?entity, "Failed to delete destroyed entity"));
|
||||||
|
@ -118,9 +118,10 @@ impl Server {
|
|||||||
scale,
|
scale,
|
||||||
home_chunk,
|
home_chunk,
|
||||||
drop_item,
|
drop_item,
|
||||||
|
rtsim_entity,
|
||||||
} => handle_create_npc(
|
} => handle_create_npc(
|
||||||
self, pos, stats, health, loadout, body, agent, alignment, scale, drop_item,
|
self, pos, stats, health, loadout, body, agent, alignment, scale, drop_item,
|
||||||
home_chunk,
|
home_chunk, rtsim_entity,
|
||||||
),
|
),
|
||||||
ServerEvent::CreateWaypoint(pos) => handle_create_waypoint(self, pos),
|
ServerEvent::CreateWaypoint(pos) => handle_create_waypoint(self, pos),
|
||||||
ServerEvent::ClientDisconnect(entity) => {
|
ServerEvent::ClientDisconnect(entity) => {
|
||||||
|
@ -44,6 +44,7 @@ use crate::{
|
|||||||
presence::{Presence, RegionSubscription},
|
presence::{Presence, RegionSubscription},
|
||||||
state_ext::StateExt,
|
state_ext::StateExt,
|
||||||
sys::sentinel::{DeletedEntities, TrackedComps},
|
sys::sentinel::{DeletedEntities, TrackedComps},
|
||||||
|
rtsim::RtSim,
|
||||||
};
|
};
|
||||||
use common::{
|
use common::{
|
||||||
assets::Asset,
|
assets::Asset,
|
||||||
@ -58,7 +59,8 @@ use common::{
|
|||||||
state::{State, TimeOfDay},
|
state::{State, TimeOfDay},
|
||||||
sync::WorldSyncExt,
|
sync::WorldSyncExt,
|
||||||
terrain::TerrainChunkSize,
|
terrain::TerrainChunkSize,
|
||||||
vol::RectVolSize,
|
vol::{ReadVol, RectVolSize},
|
||||||
|
rtsim::RtSimEntity,
|
||||||
};
|
};
|
||||||
use futures_executor::block_on;
|
use futures_executor::block_on;
|
||||||
use metrics::{PhysicsMetrics, ServerMetrics, StateTickMetrics, TickMetrics};
|
use metrics::{PhysicsMetrics, ServerMetrics, StateTickMetrics, TickMetrics};
|
||||||
@ -321,6 +323,10 @@ impl Server {
|
|||||||
// set the spawn point we calculated above
|
// set the spawn point we calculated above
|
||||||
state.ecs_mut().insert(SpawnPoint(spawn_point));
|
state.ecs_mut().insert(SpawnPoint(spawn_point));
|
||||||
|
|
||||||
|
// Insert the world into the ECS (todo: Maybe not an Arc?)
|
||||||
|
let world = Arc::new(world);
|
||||||
|
state.ecs_mut().insert(world.clone());
|
||||||
|
|
||||||
// Set starting time for the server.
|
// Set starting time for the server.
|
||||||
state.ecs_mut().write_resource::<TimeOfDay>().0 = settings.start_time;
|
state.ecs_mut().write_resource::<TimeOfDay>().0 = settings.start_time;
|
||||||
|
|
||||||
@ -359,7 +365,7 @@ impl Server {
|
|||||||
|
|
||||||
let this = Self {
|
let this = Self {
|
||||||
state,
|
state,
|
||||||
world: Arc::new(world),
|
world,
|
||||||
index,
|
index,
|
||||||
map,
|
map,
|
||||||
|
|
||||||
@ -550,6 +556,11 @@ impl Server {
|
|||||||
};
|
};
|
||||||
|
|
||||||
for entity in to_delete {
|
for entity in to_delete {
|
||||||
|
// Assimilate entities that are part of the real-time world simulation
|
||||||
|
if let Some(rtsim_entity) = self.state.ecs().read_storage::<RtSimEntity>().get(entity).copied() {
|
||||||
|
self.state.ecs().write_resource::<RtSim>().assimilate_entity(rtsim_entity.0);
|
||||||
|
}
|
||||||
|
|
||||||
if let Err(e) = self.state.delete_entity_recorded(entity) {
|
if let Err(e) = self.state.delete_entity_recorded(entity) {
|
||||||
error!(?e, "Failed to delete agent outside the terrain");
|
error!(?e, "Failed to delete agent outside the terrain");
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
);
|
);
|
||||||
|
|
||||||
fn run(&mut self, (server_event_bus, mut rtsim): Self::SystemData) {
|
fn run(&mut self, (server_event_bus, mut rtsim): Self::SystemData) {
|
||||||
for chunk in std::mem::take(&mut rtsim.chunks_to_load) {
|
for chunk in std::mem::take(&mut rtsim.world.chunks_to_load) {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,55 +1,86 @@
|
|||||||
mod load_chunks;
|
mod load_chunks;
|
||||||
mod unload_chunks;
|
mod unload_chunks;
|
||||||
|
mod tick;
|
||||||
|
|
||||||
use vek::*;
|
use vek::*;
|
||||||
use world::util::Grid;
|
use world::util::Grid;
|
||||||
use common::state::State;
|
use common::{
|
||||||
use specs::{DispatcherBuilder, Component, WorldExt};
|
state::State,
|
||||||
|
terrain::TerrainChunk,
|
||||||
|
rtsim::{RtSimEntity, RtSimId},
|
||||||
|
vol::RectRasterableVol,
|
||||||
|
};
|
||||||
|
use specs::{DispatcherBuilder, WorldExt};
|
||||||
use specs_idvs::IdvStorage;
|
use specs_idvs::IdvStorage;
|
||||||
|
use slab::Slab;
|
||||||
type EntityId = u64;
|
use rand::prelude::*;
|
||||||
|
|
||||||
pub struct RtSim {
|
pub struct RtSim {
|
||||||
chunks: Grid<Chunk>,
|
world: RtWorld,
|
||||||
chunks_to_load: Vec<Vec2<i32>>,
|
entities: Slab<Entity>,
|
||||||
chunks_to_unload: Vec<Vec2<i32>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RtSim {
|
impl RtSim {
|
||||||
pub fn new(world_chunk_size: Vec2<u32>) -> Self {
|
pub fn new(world_chunk_size: Vec2<u32>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
world: RtWorld {
|
||||||
chunks: Grid::populate_from(world_chunk_size.map(|e| e as i32), |_| Chunk {
|
chunks: Grid::populate_from(world_chunk_size.map(|e| e as i32), |_| Chunk {
|
||||||
is_loaded: false,
|
is_loaded: false,
|
||||||
}),
|
}),
|
||||||
chunks_to_load: Vec::new(),
|
chunks_to_load: Vec::new(),
|
||||||
chunks_to_unload: Vec::new(),
|
chunks_to_unload: Vec::new(),
|
||||||
|
},
|
||||||
|
entities: Slab::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hook_load_chunk(&mut self, key: Vec2<i32>) {
|
pub fn hook_load_chunk(&mut self, key: Vec2<i32>) {
|
||||||
if let Some(chunk) = self.chunks.get_mut(key) {
|
if let Some(chunk) = self.world.chunks.get_mut(key) {
|
||||||
if !chunk.is_loaded {
|
if !chunk.is_loaded {
|
||||||
chunk.is_loaded = true;
|
chunk.is_loaded = true;
|
||||||
self.chunks_to_load.push(key);
|
self.world.chunks_to_load.push(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hook_unload_chunk(&mut self, key: Vec2<i32>) {
|
pub fn hook_unload_chunk(&mut self, key: Vec2<i32>) {
|
||||||
if let Some(chunk) = self.chunks.get_mut(key) {
|
if let Some(chunk) = self.world.chunks.get_mut(key) {
|
||||||
if chunk.is_loaded {
|
if chunk.is_loaded {
|
||||||
chunk.is_loaded = false;
|
chunk.is_loaded = false;
|
||||||
self.chunks_to_unload.push(key);
|
self.world.chunks_to_unload.push(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assimilate_entity(&mut self, entity: EntityId) {
|
pub fn assimilate_entity(&mut self, entity: RtSimId) {
|
||||||
// TODO
|
tracing::info!("Assimilated rtsim entity {}", entity);
|
||||||
|
self.entities.get_mut(entity).map(|e| e.is_loaded = false);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_entity(&mut self, entity: EntityId, pos: Vec3<f32>) {
|
pub fn reify_entity(&mut self, entity: RtSimId) {
|
||||||
// TODO
|
tracing::info!("Reified rtsim entity {}", entity);
|
||||||
|
self.entities.get_mut(entity).map(|e| e.is_loaded = true);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_entity(&mut self, entity: RtSimId, pos: Vec3<f32>) {
|
||||||
|
self.entities.get_mut(entity).map(|e| e.pos = pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy_entity(&mut self, entity: RtSimId) {
|
||||||
|
tracing::info!("Destroyed rtsim entity {}", entity);
|
||||||
|
self.entities.remove(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RtWorld {
|
||||||
|
chunks: Grid<Chunk>,
|
||||||
|
chunks_to_load: Vec<Vec2<i32>>,
|
||||||
|
chunks_to_unload: Vec<Vec2<i32>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RtWorld {
|
||||||
|
pub fn chunk_at(&self, pos: Vec2<f32>) -> Option<&Chunk> {
|
||||||
|
self.chunks.get(pos.map2(TerrainChunk::RECT_SIZE, |e, sz| (e.floor() as i32).div_euclid(sz as i32)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,22 +88,41 @@ pub struct Chunk {
|
|||||||
is_loaded: bool,
|
is_loaded: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RtSimEntity(EntityId);
|
pub struct Entity {
|
||||||
|
is_loaded: bool,
|
||||||
impl Component for RtSimEntity {
|
pos: Vec3<f32>,
|
||||||
type Storage = IdvStorage<Self>;
|
seed: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
const LOAD_CHUNK_SYS: &str = "rtsim_load_chunk_sys";
|
const LOAD_CHUNK_SYS: &str = "rtsim_load_chunk_sys";
|
||||||
const UNLOAD_CHUNK_SYS: &str = "rtsim_unload_chunk_sys";
|
const UNLOAD_CHUNK_SYS: &str = "rtsim_unload_chunk_sys";
|
||||||
|
const TICK_SYS: &str = "rtsim_tick_sys";
|
||||||
|
|
||||||
pub fn add_server_systems(dispatch_builder: &mut DispatcherBuilder) {
|
pub fn add_server_systems(dispatch_builder: &mut DispatcherBuilder) {
|
||||||
dispatch_builder.add(load_chunks::Sys, LOAD_CHUNK_SYS, &[]);
|
|
||||||
dispatch_builder.add(unload_chunks::Sys, UNLOAD_CHUNK_SYS, &[]);
|
dispatch_builder.add(unload_chunks::Sys, UNLOAD_CHUNK_SYS, &[]);
|
||||||
|
dispatch_builder.add(load_chunks::Sys, LOAD_CHUNK_SYS, &[UNLOAD_CHUNK_SYS]);
|
||||||
|
dispatch_builder.add(tick::Sys, TICK_SYS, &[LOAD_CHUNK_SYS, UNLOAD_CHUNK_SYS]);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(state: &mut State, world: &world::World) {
|
pub fn init(state: &mut State, world: &world::World) {
|
||||||
state.ecs_mut().insert(RtSim::new(world.sim().get_size()));
|
let mut rtsim = RtSim::new(world.sim().get_size());
|
||||||
|
|
||||||
|
for _ in 0..10 {
|
||||||
|
let pos = Vec2::new(
|
||||||
|
thread_rng().gen_range(0, rtsim.world.chunks.size().x * TerrainChunk::RECT_SIZE.x as i32),
|
||||||
|
thread_rng().gen_range(0, rtsim.world.chunks.size().y * TerrainChunk::RECT_SIZE.y as i32),
|
||||||
|
);
|
||||||
|
|
||||||
|
let id = rtsim.entities.insert(Entity {
|
||||||
|
is_loaded: false,
|
||||||
|
pos: Vec3::from(pos.map(|e| e as f32)),
|
||||||
|
seed: thread_rng().gen(),
|
||||||
|
});
|
||||||
|
|
||||||
|
tracing::info!("Spawned rtsim NPC {} at {:?}", id, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
state.ecs_mut().insert(rtsim);
|
||||||
state.ecs_mut().register::<RtSimEntity>();
|
state.ecs_mut().register::<RtSimEntity>();
|
||||||
tracing::info!("Initiated real-time world simulation");
|
tracing::info!("Initiated real-time world simulation");
|
||||||
}
|
}
|
||||||
|
76
server/src/rtsim/tick.rs
Normal file
76
server/src/rtsim/tick.rs
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
use super::*;
|
||||||
|
use common::{
|
||||||
|
event::{EventBus, ServerEvent},
|
||||||
|
terrain::TerrainGrid,
|
||||||
|
comp,
|
||||||
|
};
|
||||||
|
use specs::{Join, Read, ReadStorage, System, Write, WriteExpect, ReadExpect};
|
||||||
|
use rand_chacha::ChaChaRng;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub struct Sys;
|
||||||
|
impl<'a> System<'a> for Sys {
|
||||||
|
type SystemData = (
|
||||||
|
Read<'a, EventBus<ServerEvent>>,
|
||||||
|
WriteExpect<'a, RtSim>,
|
||||||
|
ReadExpect<'a, TerrainGrid>,
|
||||||
|
ReadExpect<'a, Arc<world::World>>,
|
||||||
|
);
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&mut self,
|
||||||
|
(
|
||||||
|
server_event_bus,
|
||||||
|
mut rtsim,
|
||||||
|
terrain,
|
||||||
|
world,
|
||||||
|
): Self::SystemData,
|
||||||
|
) {
|
||||||
|
let rtsim = &mut *rtsim;
|
||||||
|
|
||||||
|
// TODO: don't update all of them each tick
|
||||||
|
let mut to_reify = Vec::new();
|
||||||
|
for (id, entity) in rtsim.entities.iter_mut() {
|
||||||
|
if entity.is_loaded {
|
||||||
|
continue;
|
||||||
|
} else if rtsim.world.chunk_at(entity.pos.xy()).map(|c| c.is_loaded).unwrap_or(false) {
|
||||||
|
to_reify.push(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(chunk) = world.sim().get_wpos(entity.pos.xy().map(|e| e.floor() as i32)) {
|
||||||
|
entity.pos.z = chunk.alt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut server_emitter = server_event_bus.emitter();
|
||||||
|
for id in to_reify {
|
||||||
|
rtsim.reify_entity(id);
|
||||||
|
let entity = &rtsim.entities[id];
|
||||||
|
let mut rng = ChaChaRng::from_seed([
|
||||||
|
entity.seed.to_le_bytes()[0],
|
||||||
|
entity.seed.to_le_bytes()[1],
|
||||||
|
entity.seed.to_le_bytes()[2],
|
||||||
|
entity.seed.to_le_bytes()[3],
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
]);
|
||||||
|
let species = *(&comp::humanoid::ALL_SPECIES).choose(&mut rng).unwrap();
|
||||||
|
let body = comp::humanoid::Body::random_with(&mut rng, &species).into();
|
||||||
|
server_emitter.emit(ServerEvent::CreateNpc {
|
||||||
|
pos: comp::Pos(terrain.find_space(entity.pos.map(|e| e.floor() as i32)).map(|e| e as f32) + Vec3::new(0.5, 0.5, 0.0)),
|
||||||
|
stats: comp::Stats::new("Rtsim Entity".to_string(), body),
|
||||||
|
health: comp::Health::new(body, 10),
|
||||||
|
loadout: comp::Loadout::default(),
|
||||||
|
body,
|
||||||
|
agent: None,
|
||||||
|
alignment: comp::Alignment::Npc,
|
||||||
|
scale: comp::Scale(1.0),
|
||||||
|
drop_item: None,
|
||||||
|
home_chunk: None,
|
||||||
|
rtsim_entity: Some(RtSimEntity(id)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -28,27 +28,10 @@ impl<'a> System<'a> for Sys {
|
|||||||
positions,
|
positions,
|
||||||
): Self::SystemData,
|
): Self::SystemData,
|
||||||
) {
|
) {
|
||||||
let chunks = std::mem::take(&mut rtsim.chunks_to_unload);
|
let chunks = std::mem::take(&mut rtsim.world.chunks_to_unload);
|
||||||
|
|
||||||
for (entity, rtsim_entity, pos) in (
|
|
||||||
&entities,
|
|
||||||
&rtsim_entities,
|
|
||||||
&positions,
|
|
||||||
).join() {
|
|
||||||
let key = terrain_grid.pos_key(pos.0.map(|e| e.floor() as i32));
|
|
||||||
|
|
||||||
if terrain_grid.get_key(key).is_some() {
|
|
||||||
break;
|
|
||||||
} else if chunks.contains(&key) {
|
|
||||||
// Assimilate the entity back into the simulation
|
|
||||||
rtsim.assimilate_entity(rtsim_entity.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
rtsim.update_entity(rtsim_entity.0, pos.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
for chunk in chunks {
|
for chunk in chunks {
|
||||||
|
// TODO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -198,6 +198,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
scale: comp::Scale(scale),
|
scale: comp::Scale(scale),
|
||||||
home_chunk: Some(comp::HomeChunk(key)),
|
home_chunk: Some(comp::HomeChunk(key)),
|
||||||
drop_item: entity.loot_drop,
|
drop_item: entity.loot_drop,
|
||||||
|
rtsim_entity: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user