Skip to content

Commit

Permalink
Use proper accessibility checks for everything except search
Browse files Browse the repository at this point in the history
  • Loading branch information
DomWilliams0 committed Nov 4, 2023
1 parent 342c610 commit 2c0db0a
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 52 deletions.
31 changes: 10 additions & 21 deletions world/src/chunk/chunk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ use crate::navigationv2::{
};
use crate::neighbour::NeighbourOffset;
use crate::world::LoadNotifier;
use crate::{BlockOcclusion, Slab, SliceRange, World, WorldArea, WorldAreaV2, WorldContext};
use crate::{
does_entity_fit_in_area, BlockOcclusion, Slab, SliceRange, World, WorldArea, WorldAreaV2,
WorldContext,
};
use enumflags2::bitflags;
use parking_lot::RwLock;
use petgraph::visit::Walker;
Expand Down Expand Up @@ -445,7 +448,7 @@ impl<C: WorldContext> Chunk<C> {
}
}

/// Searches downwards in vertical space for area z
/// Searches downwards in vertical space for area z. Only checks height requirement, not accessibility
pub fn find_area_for_block_with_height(
&self,
block: BlockPosition,
Expand All @@ -463,7 +466,7 @@ impl<C: WorldContext> Chunk<C> {
let info = self
.area_info(slab_idx, a)
.unwrap_or_else(|| panic!("unknown area {a:?} in chunk {:?}", self.pos));
if info.fits_requirement(requirement) && info.contains(slice_block) {
if info.height >= requirement.height && info.contains(slice_block) {
return Some((a, info));
}
}
Expand Down Expand Up @@ -510,13 +513,11 @@ impl AreaInfo {
}

/// Point is relative to this area
pub fn random_point(&self, xy_blocks: (f32, f32), random: &mut dyn RngCore) -> (f32, f32) {
debug_assert!(self.fits_xy(xy_blocks.0.powi(2) + xy_blocks.1.powi(2)));
pub fn random_point(&self, random: &mut dyn RngCore) -> (f32, f32) {
let ((xmin, ymin), (xmax, ymax)) = self.range;
let half_width = xy_blocks.0.min(xy_blocks.1) * 0.5;
(
random.gen_range(xmin as f32 + half_width, xmax as f32 - half_width + 1.0) - half_width,
random.gen_range(ymin as f32 + half_width, ymax as f32 - half_width + 1.0) - half_width,
random.gen_range(xmin as f32, xmax as f32 + 1.0),
random.gen_range(ymin as f32, ymax as f32 + 1.0),
)
}

Expand All @@ -526,12 +527,11 @@ impl AreaInfo {

pub fn random_world_point(
&self,
xy_blocks: (f32, f32),
slice: GlobalSliceIndex,
chunk: ChunkLocation,
random: &mut dyn RngCore,
) -> WorldPoint {
let (x, y) = self.random_point(xy_blocks, random);
let (x, y) = self.random_point(random);

// TODO new BlockPoint for BlockPosition but floats. this conversion is gross
let block_pos = BlockPosition::new_unchecked(x as BlockCoord, y as BlockCoord, slice);
Expand All @@ -540,17 +540,6 @@ impl AreaInfo {
world_pos + (x.fract(), y.fract(), 0.0)
}

pub fn fits_xy(&self, xy_diagonal_sqrd: f32) -> bool {
let (x, y) = self.size();
let x = (x as u32).pow(2);
let y = (y as u32).pow(2);
xy_diagonal_sqrd < (x + y) as f32
}

pub fn fits_requirement(&self, req: NavRequirement) -> bool {
self.height >= req.height && self.fits_xy(req.xy_diagonal_sqrd())
}

fn pos_to_world(
area: crate::navigationv2::world_graph::WorldArea,
(x, y): (BlockCoord, BlockCoord),
Expand Down
2 changes: 1 addition & 1 deletion world/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub use self::context::{
pub use self::mesh::BaseVertex;
pub use self::navigation::{EdgeCost, NavigationError, SearchGoal, WorldArea, WorldPath};
pub use self::navigationv2::{
accessible::AccessibilityCalculator,
accessible::{does_entity_fit_in_area, AccessibilityCalculator},
world_graph::{
OngoingPathSearchFuture, Path, SearchError, SearchStatus, WorldArea as WorldAreaV2,
},
Expand Down
20 changes: 20 additions & 0 deletions world/src/navigationv2/accessible.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,25 @@ use crate::navigationv2::world_graph::WorldGraphNodeIndex;
use crate::navigationv2::WorldArea;
use crate::{NavRequirement, World, WorldContext};

pub fn does_entity_fit_in_area<C: WorldContext>(
agent_bounds: &WorldPointRange,
agent_req: NavRequirement,
world: &World<C>,
agent_area: WorldArea,
filter_fn: impl Fn(WorldGraphNodeIndex) -> bool,
save_debug_files: bool,
) -> bool {
AccessibilityCalculator::with_graph(
agent_bounds,
agent_req,
world,
agent_area,
filter_fn,
save_debug_files,
)
.process_fully_and_check()
}

#[cfg_attr(feature = "debug-accessibility", derive(serde::Serialize))]
#[derive(Clone)]
struct Rect {
Expand All @@ -23,6 +42,7 @@ pub struct AccessibilityCalculator {
#[cfg(feature = "debug-accessibility")]
dbg: RefCell<Option<debug_renderer::DebugRenderer>>,
}

impl AccessibilityCalculator {
pub fn with_graph<C: WorldContext>(
agent_bounds: &WorldPointRange,
Expand Down
14 changes: 13 additions & 1 deletion world/src/navigationv2/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use petgraph::stable_graph::EdgeIndex;
use misc::Itertools;
use unit::world::{
BlockCoord, ChunkLocation, GlobalSliceIndex, LocalSliceIndex, SlabIndex, SliceIndex,
BLOCKS_PER_METRE, CHUNK_SIZE, SLAB_SIZE,
WorldPoint, WorldPointRange, BLOCKS_PER_METRE, BLOCKS_SCALE, CHUNK_SIZE, SLAB_SIZE,
};
pub use world_graph::{PathExistsResult, WorldArea};

Expand Down Expand Up @@ -544,6 +544,18 @@ impl NavRequirement {
pub fn xy_diagonal_sqrd(&self) -> f32 {
(self.dims.0 * self.dims.0) + (self.dims.1 * self.dims.1)
}

/// In blocks around given centre
pub fn max_rotated_aabb(&self, centre: WorldPoint) -> WorldPointRange {
let (w, h) = self.dims;
let hw = w * 0.5;
let hh = h * 0.5;
let diag = ((hw * hw) + (hh * hh)).sqrt();
WorldPointRange::with_inclusive_range(
centre + (-diag, -diag, 0.0),
centre + (diag, diag, self.height as f32 * BLOCKS_SCALE),
)
}
}

impl DirectionalSlabNavEdge<'_> {
Expand Down
67 changes: 38 additions & 29 deletions world/src/world.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
use std::collections::HashSet;
use std::iter::once;

use enumflags2::BitFlags;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;

use enumflags2::BitFlags;
use tokio::sync::broadcast;
use tokio::sync::broadcast::error::SendError;

use misc::derive_more::Constructor;
use misc::*;
use unit::world::{
BlockCoord, BlockPosition, ChunkLocation, GlobalSliceIndex, LocalSliceIndex, SlabIndex,
SlabLocation, SliceBlock, SliceIndex, WorldPosition, WorldPositionRange,
BlockPosition, ChunkLocation, GlobalSliceIndex, LocalSliceIndex, SlabLocation, SliceBlock,
SliceIndex, WorldPointRange, WorldPosition, WorldPositionRange,
};
use unit::world::{WorldPoint, CHUNK_SIZE};

Expand All @@ -27,15 +24,16 @@ use crate::chunk::{
use crate::context::WorldContext;
use crate::loader::{SlabTerrainUpdate, SlabVerticalSpace};
use crate::navigation::{
AreaGraph, AreaGraphSearchContext, AreaNavEdge, AreaPath, BlockGraph, BlockGraphSearchContext,
BlockPath, ExploreResult, NavigationError, SearchGoal, WorldArea, WorldPath, WorldPathNode,
AreaGraph, AreaNavEdge, AreaPath, BlockPath, NavigationError, SearchGoal, WorldArea, WorldPath,
WorldPathNode,
};
use crate::navigationv2::world_graph::WorldGraph;
use crate::navigationv2::{as_border_area, ChunkArea, NavRequirement, SlabArea, SlabNavEdge};
use crate::neighbour::{NeighbourOffset, WorldNeighbours};
use crate::navigationv2::{ChunkArea, NavRequirement};
use crate::neighbour::WorldNeighbours;
use crate::occlusion::NeighbourOpacity;
use crate::{
BlockOcclusion, BlockType, OcclusionFace, SearchError, Slab, SliceRange, WorldAreaV2, WorldRef,
does_entity_fit_in_area, AccessibilityCalculator, BlockOcclusion, BlockType, OcclusionFace,
Slab, SliceRange, WorldAreaV2, WorldRef,
};

/// All mutable world changes must go through `loader.apply_terrain_updates`
Expand Down Expand Up @@ -327,7 +325,9 @@ impl<C: WorldContext> World<C> {
let ai = self
.lookup_area_info(a)
.unwrap_or_else(|| panic!("missing area info {:?}", a));
(ai.fits_requirement(req)).then_some((a, ai))
unreachable!();
Some((a, ai))
// (ai.fits_requirement(req)).then_some((a, ai))
})
.choose(&mut random)
{
Expand Down Expand Up @@ -632,13 +632,23 @@ impl<C: WorldContext> World<C> {
let chunk = self.all_chunks().choose(random).unwrap(); // never empty

// choose random area
let (a, ai) = chunk
.iter_areas_with_info()
.filter(|(a, ai)| ai.fits_requirement(requirement))
.choose(random)?;
let (a, ai) = chunk.iter_areas_with_info().choose(random)?;

// take random point in this area
Some(ai.random_world_point(requirement.dims, a.slice(), chunk.pos(), random))
let centre = ai.random_world_point(a.slice(), chunk.pos(), random);

// ensure adjacent areas can hold us
let bounds_here = requirement.max_rotated_aabb(centre);

does_entity_fit_in_area(
&bounds_here,
requirement,
self,
a.to_world_area(chunk.pos()),
|_| true,
false,
)
.then_some(centre)
})
}

Expand Down Expand Up @@ -1166,14 +1176,15 @@ impl AreaLookup {

/// Helpers to create a world synchronously for tests and benchmarks
pub mod helpers {
use color::Color;
use futures::future::BoxFuture;
use futures::FutureExt;
use std::sync::Arc;
use std::time::Duration;

use futures::future::BoxFuture;
use futures::FutureExt;

use color::Color;
use misc::Itertools;
use unit::world::{ChunkLocation, SlabLocation, WorldPoint};
use unit::world::{ChunkLocation, SlabLocation};

use crate::block::{Block, BlockDurability, BlockOpacity};
use crate::chunk::slab::SlabGridImpl;
Expand Down Expand Up @@ -1330,28 +1341,26 @@ pub mod helpers {
//noinspection DuplicatedCode
#[cfg(test)]
mod tests {
use std::convert::TryFrom;
use std::time::Duration;

use misc::{logging, thread_rng, Itertools, Rng, SeedableRng, StdRng};
use unit::world::{all_slabs_in_range, SliceBlock, SliceIndex, WorldPoint, CHUNK_SIZE};
use misc::{thread_rng, Itertools, Rng, SeedableRng, StdRng};
use unit::world::{all_slabs_in_range, SliceIndex, WorldPoint, CHUNK_SIZE};
use unit::world::{
BlockPosition, ChunkLocation, GlobalSliceIndex, SlabLocation, WorldPosition,
WorldPositionRange, SLAB_SIZE,
BlockPosition, ChunkLocation, GlobalSliceIndex, SlabLocation, WorldPositionRange, SLAB_SIZE,
};

use crate::chunk::ChunkBuilder;
use crate::helpers::{DummyBlockType, DummyWorldContext};
use crate::loader::{AsyncWorkerPool, MemoryTerrainSource, WorldLoader, WorldTerrainUpdate};
use crate::loader::{AsyncWorkerPool, WorldLoader, WorldTerrainUpdate};
use crate::navigation::EdgeCost;
use crate::navigationv2::NavRequirement;
use crate::occlusion::{NeighbourOpacity, VertexOcclusion};
use crate::occlusion::VertexOcclusion;
use crate::presets::from_preset;
use crate::world::helpers::{
apply_updates, loader_from_chunks_blocking, world_from_chunks_blocking,
};
use crate::world::ContiguousChunkIterator;
use crate::{presets, BlockType, SearchGoal, World, WorldContext, WorldRef};
use crate::{presets, BlockType, SearchGoal, World, WorldContext};

#[test]
fn world_context() {
Expand Down

0 comments on commit 2c0db0a

Please sign in to comment.