mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Expose CachedSpatialGrid resource that is updated by the physics system, move BuildAreas into its own module, removed unused ExecMode
This commit is contained in:
parent
26222a0a2d
commit
a76fdbc325
21
common/src/cached_spatial_grid.rs
Normal file
21
common/src/cached_spatial_grid.rs
Normal file
@ -0,0 +1,21 @@
|
||||
use crate::util::SpatialGrid;
|
||||
|
||||
/// Cached [`SpatialGrid`] for reuse within different ecs systems during a tick.
|
||||
/// This is used to accelerate queries on entities within a specific area.
|
||||
/// Updated within the physics system [`crate::sys::phys::Sys`] after new entity
|
||||
/// positions are calculated for the tick. So any position modifications outside
|
||||
/// the physics system will not be reflected here until the next tick when the
|
||||
/// physics system runs.
|
||||
pub struct CachedSpatialGrid(pub SpatialGrid);
|
||||
|
||||
impl Default for CachedSpatialGrid {
|
||||
fn default() -> Self {
|
||||
let lg2_cell_size = 5; // 32
|
||||
let lg2_large_cell_size = 6; // 64
|
||||
let radius_cutoff = 8;
|
||||
|
||||
let spatial_grid = SpatialGrid::new(lg2_cell_size, lg2_large_cell_size, radius_cutoff);
|
||||
|
||||
Self(spatial_grid)
|
||||
}
|
||||
}
|
@ -26,6 +26,8 @@ pub use uuid;
|
||||
pub mod assets;
|
||||
#[cfg(not(target_arch = "wasm32"))] pub mod astar;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
mod cached_spatial_grid;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub mod character;
|
||||
#[cfg(not(target_arch = "wasm32"))] pub mod clock;
|
||||
#[cfg(not(target_arch = "wasm32"))] pub mod cmd;
|
||||
@ -78,6 +80,8 @@ pub mod uid;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub mod volumes;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub use cached_spatial_grid::CachedSpatialGrid;
|
||||
pub use combat::DamageSource;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub use combat::{Damage, GroupTarget, Knockback, KnockbackDir};
|
||||
|
@ -4,6 +4,9 @@ pub mod find_dist;
|
||||
mod option;
|
||||
pub mod plane;
|
||||
pub mod projection;
|
||||
/// Contains [`SpatialGrid`] which is useful for accelerating queries of nearby
|
||||
/// entities
|
||||
mod spatial_grid;
|
||||
|
||||
pub const GIT_VERSION: &str = include_str!(concat!(env!("OUT_DIR"), "/githash"));
|
||||
pub const GIT_TAG: &str = include_str!(concat!(env!("OUT_DIR"), "/gittag"));
|
||||
@ -28,6 +31,7 @@ lazy_static::lazy_static! {
|
||||
|
||||
pub use color::*;
|
||||
pub use dir::*;
|
||||
pub use option::*;
|
||||
pub use plane::*;
|
||||
pub use projection::*;
|
||||
pub use option::either_with;
|
||||
pub use plane::Plane;
|
||||
pub use projection::Projection;
|
||||
pub use spatial_grid::SpatialGrid;
|
||||
|
@ -1,5 +1,6 @@
|
||||
use vek::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SpatialGrid {
|
||||
// Uses two scales of grids so that we can have a hard limit on how far to search in the
|
||||
// smaller grid
|
||||
@ -74,4 +75,10 @@ impl SpatialGrid {
|
||||
self.lg2_large_cell_size,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.grid.clear();
|
||||
self.large_grid.clear();
|
||||
self.largest_large_radius = self.radius_cutoff;
|
||||
}
|
||||
}
|
54
common/state/src/build_areas.rs
Normal file
54
common/state/src/build_areas.rs
Normal file
@ -0,0 +1,54 @@
|
||||
use common::depot::{Depot, Id};
|
||||
use hashbrown::{hash_map, HashMap};
|
||||
use vek::*;
|
||||
|
||||
/// NOTE: Please don't add `Deserialize` without checking to make sure we
|
||||
/// can guarantee the invariant that every entry in `area_names` points to a
|
||||
/// valid id in `areas`.
|
||||
#[derive(Default)]
|
||||
pub struct BuildAreas {
|
||||
areas: Depot<Aabb<i32>>,
|
||||
area_names: HashMap<String, Id<Aabb<i32>>>,
|
||||
}
|
||||
|
||||
pub enum BuildAreaError {
|
||||
/// This build area name is reserved by the system.
|
||||
Reserved,
|
||||
/// The build area name was not found.
|
||||
NotFound,
|
||||
}
|
||||
|
||||
/// Build area names that can only be inserted, not removed.
|
||||
const RESERVED_BUILD_AREA_NAMES: &[&str] = &["world"];
|
||||
|
||||
impl BuildAreas {
|
||||
pub fn areas(&self) -> &Depot<geom::Aabb<i32>> { &self.areas }
|
||||
|
||||
pub fn area_names(&self) -> &HashMap<String, Id<Aabb<i32>>> { &self.area_names }
|
||||
|
||||
/// If the area_name is already in the map, returns Err(area_name).
|
||||
pub fn insert(&mut self, area_name: String, area: Aabb<i32>) -> Result<Id<Aabb<i32>>, String> {
|
||||
let area_name_entry = match self.area_names.entry(area_name) {
|
||||
hash_map::Entry::Occupied(o) => return Err(o.replace_key()),
|
||||
hash_map::Entry::Vacant(v) => v,
|
||||
};
|
||||
let bb_id = self.areas.insert(area.made_valid());
|
||||
area_name_entry.insert(bb_id);
|
||||
Ok(bb_id)
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, area_name: &str) -> Result<Aabb<i32>, BuildAreaError> {
|
||||
if RESERVED_BUILD_AREA_NAMES.contains(&area_name) {
|
||||
return Err(BuildAreaError::Reserved);
|
||||
}
|
||||
let bb_id = self
|
||||
.area_names
|
||||
.remove(area_name)
|
||||
.ok_or(BuildAreaError::NotFound)?;
|
||||
let area = self.areas.remove(bb_id).expect(
|
||||
"Entries in `areas` are added before entries in `area_names` in `insert`, and that is \
|
||||
the only exposed way to add elements to `area_names`.",
|
||||
);
|
||||
Ok(area)
|
||||
}
|
||||
}
|
@ -1,8 +1,9 @@
|
||||
//! This crate contains the [`State`] and shared between
|
||||
//! server (`veloren-server`) and the client (`veloren-client`)
|
||||
|
||||
mod build_areas;
|
||||
#[cfg(feature = "plugins")] pub mod plugin;
|
||||
mod state;
|
||||
|
||||
// TODO: breakup state module and remove globs
|
||||
pub use state::*;
|
||||
// TODO: breakup state module and remove glob
|
||||
pub use build_areas::{BuildAreaError, BuildAreas};
|
||||
pub use state::{BlockChange, State, TerrainChanges};
|
||||
|
@ -6,7 +6,6 @@ use crate::plugin::PluginMgr;
|
||||
use common::uid::UidAllocator;
|
||||
use common::{
|
||||
comp,
|
||||
depot::{Depot, Id},
|
||||
event::{EventBus, LocalEvent, ServerEvent},
|
||||
outcome::Outcome,
|
||||
region::RegionMap,
|
||||
@ -21,7 +20,7 @@ use common_base::span;
|
||||
use common_ecs::{PhysicsMetrics, SysMetrics};
|
||||
use common_net::sync::{interpolation as sync_interp, WorldSyncExt};
|
||||
use core::{convert::identity, time::Duration};
|
||||
use hashbrown::{hash_map, HashMap, HashSet};
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
use rayon::{ThreadPool, ThreadPoolBuilder};
|
||||
use specs::{
|
||||
prelude::Resource,
|
||||
@ -43,57 +42,6 @@ const DAY_CYCLE_FACTOR: f64 = 24.0 * 2.0;
|
||||
/// avoid such a situation.
|
||||
const MAX_DELTA_TIME: f32 = 1.0;
|
||||
|
||||
/// NOTE: Please don't add `Deserialize` without checking to make sure we
|
||||
/// can guarantee the invariant that every entry in `area_names` points to a
|
||||
/// valid id in `areas`.
|
||||
#[derive(Default)]
|
||||
pub struct BuildAreas {
|
||||
areas: Depot<Aabb<i32>>,
|
||||
area_names: HashMap<String, Id<Aabb<i32>>>,
|
||||
}
|
||||
|
||||
pub enum BuildAreaError {
|
||||
/// This build area name is reserved by the system.
|
||||
Reserved,
|
||||
/// The build area name was not found.
|
||||
NotFound,
|
||||
}
|
||||
|
||||
/// Build area names that can only be inserted, not removed.
|
||||
const RESERVED_BUILD_AREA_NAMES: &[&str] = &["world"];
|
||||
|
||||
impl BuildAreas {
|
||||
pub fn areas(&self) -> &Depot<geom::Aabb<i32>> { &self.areas }
|
||||
|
||||
pub fn area_names(&self) -> &HashMap<String, Id<Aabb<i32>>> { &self.area_names }
|
||||
|
||||
/// If the area_name is already in the map, returns Err(area_name).
|
||||
pub fn insert(&mut self, area_name: String, area: Aabb<i32>) -> Result<Id<Aabb<i32>>, String> {
|
||||
let area_name_entry = match self.area_names.entry(area_name) {
|
||||
hash_map::Entry::Occupied(o) => return Err(o.replace_key()),
|
||||
hash_map::Entry::Vacant(v) => v,
|
||||
};
|
||||
let bb_id = self.areas.insert(area.made_valid());
|
||||
area_name_entry.insert(bb_id);
|
||||
Ok(bb_id)
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, area_name: &str) -> Result<Aabb<i32>, BuildAreaError> {
|
||||
if RESERVED_BUILD_AREA_NAMES.contains(&area_name) {
|
||||
return Err(BuildAreaError::Reserved);
|
||||
}
|
||||
let bb_id = self
|
||||
.area_names
|
||||
.remove(area_name)
|
||||
.ok_or(BuildAreaError::NotFound)?;
|
||||
let area = self.areas.remove(bb_id).expect(
|
||||
"Entries in `areas` are added before entries in `area_names` in `insert`, and that is \
|
||||
the only exposed way to add elements to `area_names`.",
|
||||
);
|
||||
Ok(area)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct BlockChange {
|
||||
blocks: HashMap<Vec3<i32>, Block>,
|
||||
@ -130,13 +78,6 @@ impl TerrainChanges {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum ExecMode {
|
||||
Server,
|
||||
Client,
|
||||
Singleplayer,
|
||||
}
|
||||
|
||||
/// 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 states like weather, time of day, etc.
|
||||
@ -260,7 +201,7 @@ impl State {
|
||||
ecs.insert(PlayerEntity(None));
|
||||
ecs.insert(TerrainGrid::new().unwrap());
|
||||
ecs.insert(BlockChange::default());
|
||||
ecs.insert(BuildAreas::default());
|
||||
ecs.insert(crate::build_areas::BuildAreas::default());
|
||||
ecs.insert(TerrainChanges::default());
|
||||
ecs.insert(EventBus::<LocalEvent>::default());
|
||||
ecs.insert(game_mode);
|
||||
|
@ -1,7 +1,3 @@
|
||||
mod spatial_grid;
|
||||
|
||||
use spatial_grid::SpatialGrid;
|
||||
|
||||
use common::{
|
||||
comp::{
|
||||
body::ship::figuredata::{VoxelCollider, VOXEL_COLLIDER_MANIFEST},
|
||||
@ -15,7 +11,7 @@ use common::{
|
||||
resources::DeltaTime,
|
||||
terrain::{Block, TerrainGrid},
|
||||
uid::Uid,
|
||||
util::Projection,
|
||||
util::{Projection, SpatialGrid},
|
||||
vol::{BaseVol, ReadVol},
|
||||
};
|
||||
use common_base::{prof_span, span};
|
||||
@ -148,6 +144,7 @@ pub struct PhysicsRead<'a> {
|
||||
#[derive(SystemData)]
|
||||
pub struct PhysicsWrite<'a> {
|
||||
physics_metrics: WriteExpect<'a, PhysicsMetrics>,
|
||||
cached_spatial_grid: WriteExpect<'a, common::CachedSpatialGrid>,
|
||||
physics_states: WriteStorage<'a, PhysicsState>,
|
||||
positions: WriteStorage<'a, Pos>,
|
||||
velocities: WriteStorage<'a, Vel>,
|
||||
@ -1119,6 +1116,32 @@ impl<'a> PhysicsData<'a> {
|
||||
event_emitter.emit(ServerEvent::LandOnGround { entity, vel: vel.0 });
|
||||
});
|
||||
}
|
||||
|
||||
fn update_cached_spatial_grid(&mut self) {
|
||||
span!(_guard, "Update cached spatial grid");
|
||||
let PhysicsData {
|
||||
ref read,
|
||||
ref mut write,
|
||||
} = self;
|
||||
|
||||
let spatial_grid = &mut write.cached_spatial_grid.0;
|
||||
spatial_grid.clear();
|
||||
(
|
||||
&read.entities,
|
||||
&write.positions,
|
||||
read.scales.maybe(),
|
||||
read.colliders.maybe(),
|
||||
)
|
||||
.join()
|
||||
.for_each(|(entity, pos, scale, collider)| {
|
||||
let scale = scale.map(|s| s.0).unwrap_or(1.0);
|
||||
let radius_2d =
|
||||
(collider.map(|c| c.get_radius()).unwrap_or(0.5) * scale).ceil() as u32;
|
||||
let pos_2d = pos.0.xy().map(|e| e as i32);
|
||||
const POS_TRUNCATION_ERROR: u32 = 1;
|
||||
spatial_grid.insert(pos_2d, radius_2d + POS_TRUNCATION_ERROR, entity);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> System<'a> for Sys {
|
||||
@ -1128,8 +1151,8 @@ impl<'a> System<'a> for Sys {
|
||||
const ORIGIN: Origin = Origin::Common;
|
||||
const PHASE: Phase = Phase::Create;
|
||||
|
||||
fn run(job: &mut Job<Self>, mut psd: Self::SystemData) {
|
||||
psd.reset();
|
||||
fn run(job: &mut Job<Self>, mut physics_data: Self::SystemData) {
|
||||
physics_data.reset();
|
||||
|
||||
// Apply pushback
|
||||
//
|
||||
@ -1144,13 +1167,16 @@ impl<'a> System<'a> for Sys {
|
||||
// terrain collision code below, although that's not trivial to do since
|
||||
// it means the step needs to take into account the speeds of both
|
||||
// entities.
|
||||
psd.maintain_pushback_cache();
|
||||
physics_data.maintain_pushback_cache();
|
||||
|
||||
let spatial_grid = psd.construct_spatial_grid();
|
||||
psd.apply_pushback(job, &spatial_grid);
|
||||
let spatial_grid = physics_data.construct_spatial_grid();
|
||||
physics_data.apply_pushback(job, &spatial_grid);
|
||||
|
||||
let voxel_collider_spatial_grid = psd.construct_voxel_collider_spatial_grid();
|
||||
psd.handle_movement_and_terrain(job, &voxel_collider_spatial_grid);
|
||||
let voxel_collider_spatial_grid = physics_data.construct_voxel_collider_spatial_grid();
|
||||
physics_data.handle_movement_and_terrain(job, &voxel_collider_spatial_grid);
|
||||
|
||||
// Spatial grid used by other systems
|
||||
physics_data.update_cached_spatial_grid();
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user