aboutsummaryrefslogtreecommitdiff
path: root/azalea-physics/src/collision/shape_offset.rs
diff options
context:
space:
mode:
authormat <git@matdoes.dev>2026-05-07 01:42:52 -0330
committermat <git@matdoes.dev>2026-05-07 08:05:58 -1200
commitee7358ebc2d3a033b48b3a97af4255e1efba9ef9 (patch)
tree7a69c0676225bab4e37b44fb398829d554708623 /azalea-physics/src/collision/shape_offset.rs
parenta6fbdea961c2f8a788b362cbde1eab356d298e84 (diff)
downloadazalea-drasl-ee7358ebc2d3a033b48b3a97af4255e1efba9ef9.tar.xz
correct shapes for blocks with random offsets
Diffstat (limited to 'azalea-physics/src/collision/shape_offset.rs')
-rw-r--r--azalea-physics/src/collision/shape_offset.rs79
1 files changed, 79 insertions, 0 deletions
diff --git a/azalea-physics/src/collision/shape_offset.rs b/azalea-physics/src/collision/shape_offset.rs
new file mode 100644
index 00000000..2832d680
--- /dev/null
+++ b/azalea-physics/src/collision/shape_offset.rs
@@ -0,0 +1,79 @@
+use std::borrow::Cow;
+
+use azalea_block::BlockState;
+use azalea_core::{
+ math::get_seed,
+ position::{BlockPos, Vec3},
+};
+use azalea_registry::builtin::BlockKind;
+
+use crate::collision::{VoxelShape, blocks::RANDOM_SHAPE_OFFSETS_MAP};
+
+/// Adds the random offset for the shape, given the block state and position.
+///
+/// For most blocks, this won't have any effect. It's only used for a few blocks
+/// like flowers and bamboo.
+pub fn apply_shape_offset(
+ block: BlockState,
+ pos: BlockPos,
+ shape: &'static VoxelShape,
+) -> Cow<'static, VoxelShape> {
+ // don't waste time checking the block if it's already known to be empty. also,
+ // it's faster to compare addresses than to call `.is_empty`.
+ if std::ptr::eq(shape, &*super::EMPTY_SHAPE) {
+ return Cow::Borrowed(shape);
+ }
+
+ let offset_kind = RANDOM_SHAPE_OFFSETS_MAP[block.id() as usize];
+ if offset_kind == 0 {
+ return Cow::Borrowed(shape);
+ }
+
+ let kind = block.as_block_kind();
+
+ let mut max_horizontal_offset = 0.25;
+ // search `getMaxHorizontalOffset` in the vanilla code
+ // TODO: sulfur spike gets added here in 26.2
+ if kind == BlockKind::PointedDripstone {
+ max_horizontal_offset = 2. / 16.;
+ }
+
+ // these ids are required to be the same as the ones in shapes.py
+ let delta = match offset_kind {
+ // see offsetType in BlockBehaviour.java
+ 1 => {
+ // xz
+ xyz_offset_for_pos(pos.with_y(0), max_horizontal_offset, 0.)
+ }
+ 2 => {
+ // xyz
+
+ let mut max_vertical_offset = 0.2;
+ if kind == BlockKind::SmallDripleaf {
+ // search `getMaxVerticalOffset` in the vanilla code
+ max_vertical_offset = 0.1;
+ }
+
+ xyz_offset_for_pos(pos, max_horizontal_offset, max_vertical_offset)
+ }
+ _ => unreachable!(),
+ };
+
+ Cow::Owned(shape.move_relative(delta))
+}
+
+fn xyz_offset_for_pos(pos: BlockPos, max_horizontal_offset: f64, max_vertical_offset: f64) -> Vec3 {
+ let seed = get_seed(pos);
+ let y = if max_vertical_offset == 0. {
+ 0.
+ } else {
+ ((((seed >> 4) & 15) as f32 / 15.) as f64 - 1.) * max_vertical_offset
+ };
+
+ let x = (((seed & 15) as f32 / 15.) as f64 - 0.5) * 0.5;
+ let x = x.clamp(-max_horizontal_offset, max_horizontal_offset);
+ let z = ((((seed >> 8) & 15) as f32 / 15.) as f64 - 0.5) * 0.5;
+ let z = z.clamp(-max_horizontal_offset, max_horizontal_offset);
+
+ Vec3 { x, y, z }
+}