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;
|
pub mod assets;
|
||||||
#[cfg(not(target_arch = "wasm32"))] pub mod astar;
|
#[cfg(not(target_arch = "wasm32"))] pub mod astar;
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
mod cached_spatial_grid;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub mod character;
|
pub mod character;
|
||||||
#[cfg(not(target_arch = "wasm32"))] pub mod clock;
|
#[cfg(not(target_arch = "wasm32"))] pub mod clock;
|
||||||
#[cfg(not(target_arch = "wasm32"))] pub mod cmd;
|
#[cfg(not(target_arch = "wasm32"))] pub mod cmd;
|
||||||
@ -78,6 +80,8 @@ pub mod uid;
|
|||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub mod volumes;
|
pub mod volumes;
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
pub use cached_spatial_grid::CachedSpatialGrid;
|
||||||
pub use combat::DamageSource;
|
pub use combat::DamageSource;
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub use combat::{Damage, GroupTarget, Knockback, KnockbackDir};
|
pub use combat::{Damage, GroupTarget, Knockback, KnockbackDir};
|
||||||
|
@ -4,6 +4,9 @@ pub mod find_dist;
|
|||||||
mod option;
|
mod option;
|
||||||
pub mod plane;
|
pub mod plane;
|
||||||
pub mod projection;
|
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_VERSION: &str = include_str!(concat!(env!("OUT_DIR"), "/githash"));
|
||||||
pub const GIT_TAG: &str = include_str!(concat!(env!("OUT_DIR"), "/gittag"));
|
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 color::*;
|
||||||
pub use dir::*;
|
pub use dir::*;
|
||||||
pub use option::*;
|
pub use option::either_with;
|
||||||
pub use plane::*;
|
pub use plane::Plane;
|
||||||
pub use projection::*;
|
pub use projection::Projection;
|
||||||
|
pub use spatial_grid::SpatialGrid;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct SpatialGrid {
|
pub struct SpatialGrid {
|
||||||
// Uses two scales of grids so that we can have a hard limit on how far to search in the
|
// Uses two scales of grids so that we can have a hard limit on how far to search in the
|
||||||
// smaller grid
|
// smaller grid
|
||||||
@ -74,4 +75,10 @@ impl SpatialGrid {
|
|||||||
self.lg2_large_cell_size,
|
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
|
//! This crate contains the [`State`] and shared between
|
||||||
//! server (`veloren-server`) and the client (`veloren-client`)
|
//! server (`veloren-server`) and the client (`veloren-client`)
|
||||||
|
|
||||||
|
mod build_areas;
|
||||||
#[cfg(feature = "plugins")] pub mod plugin;
|
#[cfg(feature = "plugins")] pub mod plugin;
|
||||||
mod state;
|
mod state;
|
||||||
|
// TODO: breakup state module and remove glob
|
||||||
// TODO: breakup state module and remove globs
|
pub use build_areas::{BuildAreaError, BuildAreas};
|
||||||
pub use state::*;
|
pub use state::{BlockChange, State, TerrainChanges};
|
||||||
|
@ -6,7 +6,6 @@ use crate::plugin::PluginMgr;
|
|||||||
use common::uid::UidAllocator;
|
use common::uid::UidAllocator;
|
||||||
use common::{
|
use common::{
|
||||||
comp,
|
comp,
|
||||||
depot::{Depot, Id},
|
|
||||||
event::{EventBus, LocalEvent, ServerEvent},
|
event::{EventBus, LocalEvent, ServerEvent},
|
||||||
outcome::Outcome,
|
outcome::Outcome,
|
||||||
region::RegionMap,
|
region::RegionMap,
|
||||||
@ -21,7 +20,7 @@ use common_base::span;
|
|||||||
use common_ecs::{PhysicsMetrics, SysMetrics};
|
use common_ecs::{PhysicsMetrics, SysMetrics};
|
||||||
use common_net::sync::{interpolation as sync_interp, WorldSyncExt};
|
use common_net::sync::{interpolation as sync_interp, WorldSyncExt};
|
||||||
use core::{convert::identity, time::Duration};
|
use core::{convert::identity, time::Duration};
|
||||||
use hashbrown::{hash_map, HashMap, HashSet};
|
use hashbrown::{HashMap, HashSet};
|
||||||
use rayon::{ThreadPool, ThreadPoolBuilder};
|
use rayon::{ThreadPool, ThreadPoolBuilder};
|
||||||
use specs::{
|
use specs::{
|
||||||
prelude::Resource,
|
prelude::Resource,
|
||||||
@ -43,57 +42,6 @@ const DAY_CYCLE_FACTOR: f64 = 24.0 * 2.0;
|
|||||||
/// avoid such a situation.
|
/// avoid such a situation.
|
||||||
const MAX_DELTA_TIME: f32 = 1.0;
|
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)]
|
#[derive(Default)]
|
||||||
pub struct BlockChange {
|
pub struct BlockChange {
|
||||||
blocks: HashMap<Vec3<i32>, Block>,
|
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
|
/// A type used to represent game state stored on both the client and the
|
||||||
/// server. This includes things like entity components, terrain data, and
|
/// server. This includes things like entity components, terrain data, and
|
||||||
/// global states like weather, time of day, etc.
|
/// global states like weather, time of day, etc.
|
||||||
@ -260,7 +201,7 @@ impl State {
|
|||||||
ecs.insert(PlayerEntity(None));
|
ecs.insert(PlayerEntity(None));
|
||||||
ecs.insert(TerrainGrid::new().unwrap());
|
ecs.insert(TerrainGrid::new().unwrap());
|
||||||
ecs.insert(BlockChange::default());
|
ecs.insert(BlockChange::default());
|
||||||
ecs.insert(BuildAreas::default());
|
ecs.insert(crate::build_areas::BuildAreas::default());
|
||||||
ecs.insert(TerrainChanges::default());
|
ecs.insert(TerrainChanges::default());
|
||||||
ecs.insert(EventBus::<LocalEvent>::default());
|
ecs.insert(EventBus::<LocalEvent>::default());
|
||||||
ecs.insert(game_mode);
|
ecs.insert(game_mode);
|
||||||
|
@ -1,7 +1,3 @@
|
|||||||
mod spatial_grid;
|
|
||||||
|
|
||||||
use spatial_grid::SpatialGrid;
|
|
||||||
|
|
||||||
use common::{
|
use common::{
|
||||||
comp::{
|
comp::{
|
||||||
body::ship::figuredata::{VoxelCollider, VOXEL_COLLIDER_MANIFEST},
|
body::ship::figuredata::{VoxelCollider, VOXEL_COLLIDER_MANIFEST},
|
||||||
@ -15,7 +11,7 @@ use common::{
|
|||||||
resources::DeltaTime,
|
resources::DeltaTime,
|
||||||
terrain::{Block, TerrainGrid},
|
terrain::{Block, TerrainGrid},
|
||||||
uid::Uid,
|
uid::Uid,
|
||||||
util::Projection,
|
util::{Projection, SpatialGrid},
|
||||||
vol::{BaseVol, ReadVol},
|
vol::{BaseVol, ReadVol},
|
||||||
};
|
};
|
||||||
use common_base::{prof_span, span};
|
use common_base::{prof_span, span};
|
||||||
@ -148,6 +144,7 @@ pub struct PhysicsRead<'a> {
|
|||||||
#[derive(SystemData)]
|
#[derive(SystemData)]
|
||||||
pub struct PhysicsWrite<'a> {
|
pub struct PhysicsWrite<'a> {
|
||||||
physics_metrics: WriteExpect<'a, PhysicsMetrics>,
|
physics_metrics: WriteExpect<'a, PhysicsMetrics>,
|
||||||
|
cached_spatial_grid: WriteExpect<'a, common::CachedSpatialGrid>,
|
||||||
physics_states: WriteStorage<'a, PhysicsState>,
|
physics_states: WriteStorage<'a, PhysicsState>,
|
||||||
positions: WriteStorage<'a, Pos>,
|
positions: WriteStorage<'a, Pos>,
|
||||||
velocities: WriteStorage<'a, Vel>,
|
velocities: WriteStorage<'a, Vel>,
|
||||||
@ -1119,6 +1116,32 @@ impl<'a> PhysicsData<'a> {
|
|||||||
event_emitter.emit(ServerEvent::LandOnGround { entity, vel: vel.0 });
|
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 {
|
impl<'a> System<'a> for Sys {
|
||||||
@ -1128,8 +1151,8 @@ impl<'a> System<'a> for Sys {
|
|||||||
const ORIGIN: Origin = Origin::Common;
|
const ORIGIN: Origin = Origin::Common;
|
||||||
const PHASE: Phase = Phase::Create;
|
const PHASE: Phase = Phase::Create;
|
||||||
|
|
||||||
fn run(job: &mut Job<Self>, mut psd: Self::SystemData) {
|
fn run(job: &mut Job<Self>, mut physics_data: Self::SystemData) {
|
||||||
psd.reset();
|
physics_data.reset();
|
||||||
|
|
||||||
// Apply pushback
|
// Apply pushback
|
||||||
//
|
//
|
||||||
@ -1144,13 +1167,16 @@ impl<'a> System<'a> for Sys {
|
|||||||
// terrain collision code below, although that's not trivial to do since
|
// 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
|
// it means the step needs to take into account the speeds of both
|
||||||
// entities.
|
// entities.
|
||||||
psd.maintain_pushback_cache();
|
physics_data.maintain_pushback_cache();
|
||||||
|
|
||||||
let spatial_grid = psd.construct_spatial_grid();
|
let spatial_grid = physics_data.construct_spatial_grid();
|
||||||
psd.apply_pushback(job, &spatial_grid);
|
physics_data.apply_pushback(job, &spatial_grid);
|
||||||
|
|
||||||
let voxel_collider_spatial_grid = psd.construct_voxel_collider_spatial_grid();
|
let voxel_collider_spatial_grid = physics_data.construct_voxel_collider_spatial_grid();
|
||||||
psd.handle_movement_and_terrain(job, &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