Skip to content

Commit

Permalink
improve error handling on Queryable
Browse files Browse the repository at this point in the history
  • Loading branch information
Utsira committed Jan 27, 2024
1 parent f1286af commit 89c59d9
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 23 deletions.
4 changes: 2 additions & 2 deletions examples/voxel-collisions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ fn update_snow(
model.global_point_to_voxel_space(snowflake_xform.translation, item_xform);
// check whether snowflake has landed on something solid
let pos_below_snowflake = vox_pos - IVec3::Y;
let Some(voxel) = model.get_voxel_at_point(pos_below_snowflake) else { continue };
let Ok(voxel) = model.get_voxel_at_point(pos_below_snowflake) else { continue };
if voxel == Voxel::EMPTY {
continue;
};
Expand All @@ -129,7 +129,7 @@ fn update_snow(
move |pos, voxel, model| {
// a signed distance field for a sphere, but _only_ drawing it on empty cells directly above solid voxels
if *voxel == Voxel::EMPTY && pos.distance_squared(vox_pos) <= radius_squared {
if let Some(voxel_below) = model.get_voxel_at_point(pos - IVec3::Y) {
if let Ok(voxel_below) = model.get_voxel_at_point(pos - IVec3::Y) {
if voxel_below != Voxel::EMPTY {
// draw our snow material
return Voxel(234);
Expand Down
2 changes: 0 additions & 2 deletions src/model/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,6 @@ impl VoxelModel {
}

/// The voxel data used to create a mesh and a material.
///
/// Note that all coordinates are in Bevy's right-handed Y-up space
pub struct VoxelData {
pub(crate) shape: RuntimeShape<u32, 3>,
pub(crate) voxels: Vec<RawVoxel>,
Expand Down
30 changes: 14 additions & 16 deletions src/model/queryable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ use bevy::{
};
use ndshape::Shape;

#[derive(Debug, Clone, PartialEq)]
pub struct OutOfBoundsError;

/// Methods for converting from global and local to voxel-space coordinates, getting the size of a voxel model, and the voxel at a given point
pub trait VoxelQueryable {
/// The size of the voxel model.
Expand Down Expand Up @@ -49,20 +52,20 @@ pub trait VoxelQueryable {
}

/// If the voxel-space `point` is within the bounds of the model, it will be returned as a [`bevy::math::UVec3`].
fn point_in_model(&self, point: IVec3) -> Option<UVec3> {
fn point_in_model(&self, point: IVec3) -> Result<UVec3, OutOfBoundsError> {
if point.greater_than_or_equal(self.size()).any() {
return None;
return Err(OutOfBoundsError);
};
UVec3::try_from(point).ok()
UVec3::try_from(point).map_err(|_| OutOfBoundsError)
}
/// Returns the [`Voxel`] at the point (given in voxel space)
///
/// ### Arguments
/// * `position` - the position in voxel space
///
/// ### Returns
/// the voxel at this point. If the point lies outside the bounds of the model, it will return [`None`].
fn get_voxel_at_point(&self, position: IVec3) -> Option<Voxel>;
/// the voxel at this point. If the point lies outside the bounds of the model, it will return [`OutOfBoundsError`].
fn get_voxel_at_point(&self, position: IVec3) -> Result<Voxel, OutOfBoundsError>;
}

impl VoxelQueryable for VoxelModel {
Expand All @@ -71,7 +74,7 @@ impl VoxelQueryable for VoxelModel {
self.data.size()
}

fn get_voxel_at_point(&self, position: IVec3) -> Option<Voxel> {
fn get_voxel_at_point(&self, position: IVec3) -> Result<Voxel, OutOfBoundsError> {
self.data.get_voxel_at_point(position)
}
}
Expand All @@ -84,19 +87,16 @@ impl VoxelQueryable for VoxelData {
IVec3::try_from(padded).unwrap_or(IVec3::ZERO)
}

fn get_voxel_at_point(&self, position: IVec3) -> Option<Voxel> {
fn get_voxel_at_point(&self, position: IVec3) -> Result<Voxel, OutOfBoundsError> {
let position = self.point_in_model(position)?;
let leading_padding = UVec3::splat(self.padding() / 2);
let index = self.shape.linearize((position + leading_padding).into()) as usize;
let raw_voxel = self.voxels.get(index)?;
let raw_voxel = self.voxels.get(index).ok_or(OutOfBoundsError)?;
let voxel: Voxel = raw_voxel.clone().into();
Some(voxel)
Ok(voxel)
}
}

#[derive(Debug, Clone)]
pub struct OutOfBoundsError;

impl VoxelData {
/// Writes a voxel to a point in the model
///
Expand All @@ -105,11 +105,9 @@ impl VoxelData {
/// * `point` - the position at which the voxel will be written
///
/// ### Returns
/// `Ok(())` if the operation was successful, or [`OutOfBoundsError`] if `point` lies outside the model
/// [`Result::Ok`] if the operation was successful, or [`OutOfBoundsError`] if `point` lies outside the model
pub fn set_voxel(&mut self, voxel: Voxel, point: Vec3) -> Result<(), OutOfBoundsError> {
let position = self
.point_in_model(point.as_ivec3())
.ok_or(OutOfBoundsError)?;
let position = self.point_in_model(point.as_ivec3())?;
let leading_padding = UVec3::splat(self.padding() / 2);
let index = self.shape.linearize((position + leading_padding).into()) as usize;
let raw_voxel: RawVoxel = voxel.into();
Expand Down
10 changes: 7 additions & 3 deletions src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
use super::*;
use crate::{model::RawVoxel, scene::VoxelModelInstance, VoxScenePlugin, VoxelRegion};
use crate::{
model::{queryable::OutOfBoundsError, RawVoxel},
scene::VoxelModelInstance,
VoxScenePlugin, VoxelRegion,
};
use bevy::{
app::App,
asset::{AssetApp, AssetPlugin, AssetServer, Assets, Handle, LoadState},
Expand Down Expand Up @@ -279,12 +283,12 @@ async fn test_modify_voxels() {
.expect("retrieve model from Res<Assets>");
assert_eq!(
model.get_voxel_at_point(IVec3::splat(4)),
None,
Err(OutOfBoundsError),
"Max coordinate should be 3,3,3"
);
assert_eq!(
model.get_voxel_at_point(IVec3::splat(-1)),
None,
Err(OutOfBoundsError),
"Min coordinate should be 0,0,0"
);
let voxel = model
Expand Down

0 comments on commit 89c59d9

Please sign in to comment.