mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Began implementing rtsim
This commit is contained in:
parent
9e290d59ae
commit
808d1873bd
@ -37,6 +37,7 @@ pub enum ServerEvent {
|
||||
entity: EcsEntity,
|
||||
change: comp::HealthChange,
|
||||
},
|
||||
Delete(EcsEntity),
|
||||
Destroy {
|
||||
entity: EcsEntity,
|
||||
cause: comp::HealthSource,
|
||||
|
@ -470,6 +470,16 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, cause: HealthSourc
|
||||
*/
|
||||
}
|
||||
|
||||
/// Delete an entity without any special actions (this is generally used for
|
||||
/// temporarily unloading an entity when it leaves the view distance). As much
|
||||
/// as possible, this function should simply make an entity cease to exist.
|
||||
pub fn handle_delete(server: &mut Server, entity: EcsEntity) {
|
||||
let _ = server
|
||||
.state_mut()
|
||||
.delete_entity_recorded(entity)
|
||||
.map_err(|e| error!(?e, ?entity, "Failed to delete destroyed entity"));
|
||||
}
|
||||
|
||||
pub fn handle_land_on_ground(server: &Server, entity: EcsEntity, vel: Vec3<f32>) {
|
||||
let state = &server.state;
|
||||
if vel.z <= -30.0 {
|
||||
|
@ -8,7 +8,7 @@ use entity_creation::{
|
||||
handle_loaded_character_data, handle_shockwave, handle_shoot,
|
||||
};
|
||||
use entity_manipulation::{
|
||||
handle_buff, handle_damage, handle_destroy, handle_energy_change, handle_explosion,
|
||||
handle_buff, handle_damage, handle_destroy, handle_delete, handle_energy_change, handle_explosion,
|
||||
handle_knockback, handle_land_on_ground, handle_level_up, handle_respawn,
|
||||
};
|
||||
use group_manip::handle_group;
|
||||
@ -83,6 +83,7 @@ impl Server {
|
||||
handle_knockback(&self, entity, impulse)
|
||||
},
|
||||
ServerEvent::Damage { entity, change } => handle_damage(&self, entity, change),
|
||||
ServerEvent::Delete(entity) => handle_delete(self, entity),
|
||||
ServerEvent::Destroy { entity, cause } => handle_destroy(self, entity, cause),
|
||||
ServerEvent::InventoryManip(entity, manip) => handle_inventory(self, entity, manip),
|
||||
ServerEvent::GroupManip(entity, manip) => handle_group(self, entity, manip),
|
||||
|
@ -492,7 +492,14 @@ impl Server {
|
||||
// 4) Tick the server's LocalState.
|
||||
// 5) Fetch any generated `TerrainChunk`s and insert them into the terrain.
|
||||
// in sys/terrain.rs
|
||||
self.state.tick(dt, sys::add_server_systems, false);
|
||||
self.state.tick(
|
||||
dt,
|
||||
|dispatcher_builder| {
|
||||
sys::add_server_systems(dispatcher_builder);
|
||||
rtsim::add_server_systems(dispatcher_builder);
|
||||
},
|
||||
false,
|
||||
);
|
||||
|
||||
let before_handle_events = Instant::now();
|
||||
|
||||
@ -517,7 +524,6 @@ impl Server {
|
||||
|
||||
// Tick the world
|
||||
self.world.tick(dt);
|
||||
rtsim::tick(&mut self.state);
|
||||
|
||||
let before_entity_cleanup = Instant::now();
|
||||
|
||||
|
17
server/src/rtsim/load_chunks.rs
Normal file
17
server/src/rtsim/load_chunks.rs
Normal file
@ -0,0 +1,17 @@
|
||||
use super::*;
|
||||
use common::event::{EventBus, ServerEvent};
|
||||
use specs::{Join, Read, ReadStorage, System, Write, WriteExpect};
|
||||
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (
|
||||
Read<'a, EventBus<ServerEvent>>,
|
||||
WriteExpect<'a, RtSim>,
|
||||
);
|
||||
|
||||
fn run(&mut self, (server_event_bus, mut rtsim): Self::SystemData) {
|
||||
for chunk in std::mem::take(&mut rtsim.chunks_to_load) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
}
|
@ -1,14 +1,78 @@
|
||||
pub mod state;
|
||||
mod load_chunks;
|
||||
mod unload_chunks;
|
||||
|
||||
use vek::*;
|
||||
use world::util::Grid;
|
||||
use common::state::State;
|
||||
use specs::{DispatcherBuilder, Component, WorldExt};
|
||||
use specs_idvs::IdvStorage;
|
||||
|
||||
type EntityId = u64;
|
||||
|
||||
pub struct RtSim {
|
||||
chunks: Grid<Chunk>,
|
||||
chunks_to_load: Vec<Vec2<i32>>,
|
||||
chunks_to_unload: Vec<Vec2<i32>>,
|
||||
}
|
||||
|
||||
impl RtSim {
|
||||
pub fn new(world_chunk_size: Vec2<u32>) -> Self {
|
||||
Self {
|
||||
chunks: Grid::populate_from(world_chunk_size.map(|e| e as i32), |_| Chunk {
|
||||
is_loaded: false,
|
||||
}),
|
||||
chunks_to_load: Vec::new(),
|
||||
chunks_to_unload: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hook_load_chunk(&mut self, key: Vec2<i32>) {
|
||||
if let Some(chunk) = self.chunks.get_mut(key) {
|
||||
if !chunk.is_loaded {
|
||||
chunk.is_loaded = true;
|
||||
self.chunks_to_load.push(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hook_unload_chunk(&mut self, key: Vec2<i32>) {
|
||||
if let Some(chunk) = self.chunks.get_mut(key) {
|
||||
if chunk.is_loaded {
|
||||
chunk.is_loaded = false;
|
||||
self.chunks_to_unload.push(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn assimilate_entity(&mut self, entity: EntityId) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
pub fn update_entity(&mut self, entity: EntityId, pos: Vec3<f32>) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Chunk {
|
||||
is_loaded: bool,
|
||||
}
|
||||
|
||||
pub struct RtSimEntity(EntityId);
|
||||
|
||||
impl Component for RtSimEntity {
|
||||
type Storage = IdvStorage<Self>;
|
||||
}
|
||||
|
||||
const LOAD_CHUNK_SYS: &str = "rtsim_load_chunk_sys";
|
||||
const UNLOAD_CHUNK_SYS: &str = "rtsim_unload_chunk_sys";
|
||||
|
||||
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, &[]);
|
||||
}
|
||||
|
||||
pub fn init(state: &mut State, world: &world::World) {
|
||||
state
|
||||
.ecs_mut()
|
||||
.insert(state::SimState::new(world.sim().get_size()));
|
||||
state.ecs_mut().insert(RtSim::new(world.sim().get_size()));
|
||||
state.ecs_mut().register::<RtSimEntity>();
|
||||
tracing::info!("Initiated real-time world simulation");
|
||||
}
|
||||
|
||||
pub fn tick(state: &mut State) {
|
||||
// TODO
|
||||
}
|
||||
|
@ -1,20 +0,0 @@
|
||||
use vek::*;
|
||||
use world::util::Grid;
|
||||
|
||||
pub struct SimState {
|
||||
chunks: Grid<Chunk>,
|
||||
}
|
||||
|
||||
impl SimState {
|
||||
pub fn new(world_chunk_size: Vec2<u32>) -> Self {
|
||||
Self {
|
||||
chunks: Grid::populate_from(world_chunk_size.map(|e| e as i32), |_| Chunk {
|
||||
is_loaded: false,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Chunk {
|
||||
is_loaded: bool,
|
||||
}
|
54
server/src/rtsim/unload_chunks.rs
Normal file
54
server/src/rtsim/unload_chunks.rs
Normal file
@ -0,0 +1,54 @@
|
||||
use super::*;
|
||||
use common::{
|
||||
event::{EventBus, ServerEvent},
|
||||
terrain::TerrainGrid,
|
||||
comp::Pos,
|
||||
};
|
||||
use specs::{Join, Read, ReadStorage, System, Write, ReadExpect, WriteExpect, Entities};
|
||||
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (
|
||||
Read<'a, EventBus<ServerEvent>>,
|
||||
WriteExpect<'a, RtSim>,
|
||||
ReadExpect<'a, TerrainGrid>,
|
||||
Entities<'a>,
|
||||
ReadStorage<'a, RtSimEntity>,
|
||||
ReadStorage<'a, Pos>,
|
||||
);
|
||||
|
||||
fn run(
|
||||
&mut self,
|
||||
(
|
||||
server_event_bus,
|
||||
mut rtsim,
|
||||
terrain_grid,
|
||||
entities,
|
||||
rtsim_entities,
|
||||
positions,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
let chunks = std::mem::take(&mut rtsim.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 {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,11 @@
|
||||
use super::SysTimer;
|
||||
use crate::{chunk_generator::ChunkGenerator, client::Client, presence::Presence, Tick};
|
||||
use crate::{
|
||||
chunk_generator::ChunkGenerator,
|
||||
client::Client,
|
||||
presence::Presence,
|
||||
rtsim::RtSim,
|
||||
Tick,
|
||||
};
|
||||
use common::{
|
||||
comp::{self, bird_medium, item::tool::AbilityMap, Alignment, Pos},
|
||||
event::{EventBus, ServerEvent},
|
||||
@ -32,6 +38,7 @@ impl<'a> System<'a> for Sys {
|
||||
WriteExpect<'a, ChunkGenerator>,
|
||||
WriteExpect<'a, TerrainGrid>,
|
||||
Write<'a, TerrainChanges>,
|
||||
WriteExpect<'a, RtSim>,
|
||||
ReadStorage<'a, Pos>,
|
||||
ReadStorage<'a, Presence>,
|
||||
ReadStorage<'a, Client>,
|
||||
@ -47,6 +54,7 @@ impl<'a> System<'a> for Sys {
|
||||
mut chunk_generator,
|
||||
mut terrain,
|
||||
mut terrain_changes,
|
||||
mut rtsim,
|
||||
positions,
|
||||
presences,
|
||||
clients,
|
||||
@ -100,6 +108,7 @@ impl<'a> System<'a> for Sys {
|
||||
terrain_changes.modified_chunks.insert(key);
|
||||
} else {
|
||||
terrain_changes.new_chunks.insert(key);
|
||||
rtsim.hook_load_chunk(key);
|
||||
}
|
||||
|
||||
// Handle chunk supplement
|
||||
@ -217,10 +226,12 @@ impl<'a> System<'a> for Sys {
|
||||
chunks_to_remove.push(chunk_key);
|
||||
}
|
||||
});
|
||||
|
||||
for key in chunks_to_remove {
|
||||
// TODO: code duplication for chunk insertion between here and state.rs
|
||||
if terrain.remove(key).is_some() {
|
||||
terrain_changes.removed_chunks.insert(key);
|
||||
rtsim.hook_unload_chunk(key);
|
||||
}
|
||||
|
||||
chunk_generator.cancel_if_pending(key);
|
||||
|
@ -48,20 +48,23 @@ pub fn apply_trees_to(canvas: &mut Canvas) {
|
||||
let tree = if let Some(tree) = tree_cache.entry(tree_wpos).or_insert_with(|| {
|
||||
let col = ColumnGen::new(info.land()).get((tree_wpos, info.index()))?;
|
||||
|
||||
let is_quirky = QUIRKY_RAND.chance(seed, 1.0 / 500.0);
|
||||
|
||||
// Ensure that it's valid to place a tree here
|
||||
if ((seed.wrapping_mul(13)) & 0xFF) as f32 / 256.0 > col.tree_density
|
||||
|| col.alt < col.water_level
|
||||
if col.alt < col.water_level
|
||||
|| col.spawn_rate < 0.5
|
||||
|| col.water_dist.map(|d| d < 8.0).unwrap_or(false)
|
||||
|| col.path.map(|(d, _, _, _)| d < 12.0).unwrap_or(false)
|
||||
{
|
||||
return None;
|
||||
} else if !is_quirky && ((seed.wrapping_mul(13)) & 0xFF) as f32 / 256.0 > col.tree_density {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(Tree {
|
||||
pos: Vec3::new(tree_wpos.x, tree_wpos.y, col.alt as i32),
|
||||
model: {
|
||||
let models: &'static [_] = if QUIRKY_RAND.get(seed) % 512 == 17 {
|
||||
let models: &'static [_] = if is_quirky {
|
||||
if col.temp > CONFIG.desert_temp {
|
||||
&QUIRKY_DRY
|
||||
} else {
|
||||
@ -69,8 +72,8 @@ pub fn apply_trees_to(canvas: &mut Canvas) {
|
||||
}
|
||||
} else {
|
||||
match col.forest_kind {
|
||||
ForestKind::Oak if QUIRKY_RAND.get(seed) % 16 == 7 => &OAK_STUMPS,
|
||||
ForestKind::Oak if QUIRKY_RAND.get(seed) % 19 == 7 => &FRUIT_TREES,
|
||||
ForestKind::Oak if QUIRKY_RAND.chance(seed + 1, 1.0 / 16.0) => &OAK_STUMPS,
|
||||
ForestKind::Oak if QUIRKY_RAND.chance(seed + 2, 1.0 / 20.0) => &FRUIT_TREES,
|
||||
ForestKind::Palm => &PALMS,
|
||||
ForestKind::Savannah => &ACACIAS,
|
||||
ForestKind::Oak => &OAKS,
|
||||
|
@ -20,7 +20,6 @@ mod column;
|
||||
pub mod config;
|
||||
pub mod index;
|
||||
pub mod layer;
|
||||
pub mod rtsim;
|
||||
pub mod sim;
|
||||
pub mod sim2;
|
||||
pub mod site;
|
||||
|
@ -1 +0,0 @@
|
||||
|
@ -45,6 +45,10 @@ pub struct RandomPerm {
|
||||
|
||||
impl RandomPerm {
|
||||
pub const fn new(seed: u32) -> Self { Self { seed } }
|
||||
|
||||
pub fn chance(&self, perm: u32, chance: f32) -> bool {
|
||||
(self.get(perm) % (1 << 16)) as f32 / ((1 << 16) as f32) < chance
|
||||
}
|
||||
}
|
||||
|
||||
impl Sampler<'static> for RandomPerm {
|
||||
|
Loading…
Reference in New Issue
Block a user