1
2
Fork 0
mirror of https://github.com/mat-1/azalea.git synced 2025-08-02 06:16:04 +00:00

add more collision stuff

This commit is contained in:
mat 2022-09-11 10:18:31 -05:00
parent 3364b82a1e
commit dd0589b512
6 changed files with 226 additions and 4 deletions

View file

@ -64,3 +64,39 @@ pub fn binary_search(mut min: i32, max: i32, predicate: &dyn Fn(i32) -> bool) ->
min
}
pub fn lcm(a: u32, b: u32) -> u64 {
let gcd = gcd(a, b);
(a as u64) * (b / gcd) as u64
}
pub fn gcd(mut a: u32, mut b: u32) -> u32 {
while b != 0 {
let t = b;
b = a % b;
a = t;
}
a
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_gcd() {
assert_eq!(gcd(0, 0), 0);
assert_eq!(gcd(1, 1), 1);
assert_eq!(gcd(0, 1), 1);
assert_eq!(gcd(1, 0), 1);
assert_eq!(gcd(12, 8), 4);
assert_eq!(gcd(8, 12), 4);
assert_eq!(gcd(12, 9), 3);
assert_eq!(gcd(9, 12), 3);
assert_eq!(gcd(12, 7), 1);
assert_eq!(gcd(7, 12), 1);
}
}

View file

@ -303,7 +303,6 @@ const X_OFFSET: u64 = PACKED_Y_LENGTH + PACKED_Z_LENGTH;
impl McBufReadable for BlockPos {
fn read_from(buf: &mut impl Read) -> Result<Self, BufReadError> {
let val = i64::read_from(buf)?;
println!("reading blockpos from {}", val);
let x = (val << (64 - X_OFFSET - PACKED_X_LENGTH) >> (64 - PACKED_X_LENGTH)) as i32;
let y = (val << (64 - PACKED_Y_LENGTH) >> (64 - PACKED_Y_LENGTH)) as i32;
let z = (val << (64 - Z_OFFSET - PACKED_Z_LENGTH) >> (64 - PACKED_Z_LENGTH)) as i32;

View file

@ -44,7 +44,7 @@ pub trait DiscreteVoxelShape: Send + Sync {
fn clone(&self) -> Box<dyn DiscreteVoxelShape>;
}
#[derive(Default, Clone)]
#[derive(Default, Clone, Eq, PartialEq)]
pub struct BitSetDiscreteVoxelShape {
x_size: u32,
y_size: u32,

View file

@ -0,0 +1,37 @@
pub trait IndexMerger {
// DoubleList getList();
// boolean forMergedIndexes(IndexMerger.IndexConsumer var1);
// int size();
// public interface IndexConsumer {
// boolean merge(int var1, int var2, int var3);
// }
fn get_list(&self) -> Vec<f64>;
fn for_merged_indexes(&self, consumer: &IndexConsumer) -> bool;
fn size(&self) -> usize;
}
type IndexConsumer = dyn FnOnce(i32, i32, i32) -> bool;
pub struct IdenticalMerger {
pub coords: Vec<f64>,
}
impl IndexMerger for IdenticalMerger {
fn get_list(&self) -> Vec<f64> {
self.coords.clone()
}
fn for_merged_indexes(&self, consumer: &IndexConsumer) -> bool {
let mut var2 = self.coords.len() - 1;
for var3 in 0..var2 {
if !consumer(var3 as i32, var3 as i32, var3 as i32) {
return false;
}
}
true
}
fn size(&self) -> usize {
self.coords.len()
}
}

View file

@ -1,6 +1,7 @@
mod blocks;
mod dimension_collisions;
mod discrete_voxel_shape;
mod mergers;
mod shape;
use azalea_core::{Axis, PositionXYZ, Vec3, AABB, EPSILON};

View file

@ -1,6 +1,8 @@
use crate::collision::{BitSetDiscreteVoxelShape, DiscreteVoxelShape, AABB};
use azalea_core::{binary_search, Axis, AxisCycle, EPSILON};
use std::cmp;
use azalea_core::{binary_search, lcm, Axis, AxisCycle, EPSILON};
use std::{any::Any, cmp, num::NonZeroU32};
use super::mergers::IndexMerger;
pub struct Shapes {}
@ -9,6 +11,11 @@ pub fn block_shape() -> Box<dyn VoxelShape> {
shape.fill(0, 0, 0);
Box::new(CubeVoxelShape::new(Box::new(shape)))
}
pub fn block_box_shape() -> Box<dyn VoxelShape> {
let mut shape = BitSetDiscreteVoxelShape::new(1, 1, 1);
shape.fill(0, 0, 0);
Box::new(CubeVoxelShape::new(Box::new(shape)))
}
pub fn empty_shape() -> Box<dyn VoxelShape> {
Box::new(ArrayVoxelShape::new(
Box::new(BitSetDiscreteVoxelShape::new(0, 0, 0)),
@ -33,6 +40,110 @@ impl Shapes {
}
movement
}
pub fn join_unoptimized(
a: Box<dyn VoxelShape>,
b: Box<dyn VoxelShape>,
op: impl FnOnce(bool, bool) -> bool,
) -> Box<dyn VoxelShape> {
if op(false, false) {
panic!("Illegal operation");
};
// if (a == b) {
// return if op(true, true) { a } else { empty_shape() };
// }
let op_true_false = op(true, false);
let op_false_true = op(false, true);
if a.is_empty() {
return if op_false_true { b } else { empty_shape() };
}
if b.is_empty() {
return if op_true_false { a } else { empty_shape() };
}
// IndexMerger var5 = createIndexMerger(1, a.getCoords(Direction.Axis.X), b.getCoords(Direction.Axis.X), var3, var4);
// IndexMerger var6 = createIndexMerger(var5.size() - 1, a.getCoords(Direction.Axis.Y), b.getCoords(Direction.Axis.Y), var3, var4);
// IndexMerger var7 = createIndexMerger((var5.size() - 1) * (var6.size() - 1), a.getCoords(Direction.Axis.Z), b.getCoords(Direction.Axis.Z), var3, var4);
// BitSetDiscreteVoxelShape var8 = BitSetDiscreteVoxelShape.join(a.shape, b.shape, var5, var6, var7, op);
// return (VoxelShape)(var5 instanceof DiscreteCubeMerger && var6 instanceof DiscreteCubeMerger && var7 instanceof DiscreteCubeMerger ? new CubeVoxelShape(var8) : new ArrayVoxelShape(var8, var5.getList(), var6.getList(), var7.getList()));
let var5 = Self::create_index_merger(
1,
a.get_coords(Axis::X),
b.get_coords(Axis::X),
op_true_false,
op_false_true,
);
let var6 = Self::create_index_merger(
(var5.size() - 1).try_into().unwrap(),
a.get_coords(Axis::Y),
b.get_coords(Axis::Y),
op_true_false,
op_false_true,
);
let var7 = Self::create_index_merger(
((var5.size() - 1) * (var6.size() - 1)).try_into().unwrap(),
a.get_coords(Axis::Z),
b.get_coords(Axis::Z),
op_true_false,
op_false_true,
);
let var8 = BitSetDiscreteVoxelShape::join(a.shape(), b.shape(), &var5, &var6, &var7, &op);
if var5.is_discrete_cube_merger()
&& var6.is_discrete_cube_merger()
&& var7.is_discrete_cube_merger()
{
Box::new(CubeVoxelShape::new(Box::new(var8)))
} else {
Box::new(ArrayVoxelShape::new(
Box::new(var8),
var5.get_list(),
var6.get_list(),
var7.get_list(),
))
}
}
pub fn create_index_merger(
var0: i32,
var1: Vec<f64>,
var2: Vec<f64>,
var3: bool,
var4: bool,
) -> impl IndexMerger {
// int var5 = var1.size() - 1;
let var5 = var1.len() - 1;
// int var6 = var2.size() - 1
let var6 = var2.len() - 1;
// if (var1 instanceof CubePointRange && var2 instanceof CubePointRange) {
// downcast
if (&var1 as &dyn Any).is::<CubePointRange>() && (&var2 as &dyn Any).is::<CubePointRange>()
{
// return new DiscreteCubeMerger(var0, var5, var6, var3, var4);
let var7: i64 = lcm(var5 as u32, var6 as u32).try_into().unwrap();
// if ((long)var0 * var7 <= 256L) {
if (var0 as i64 * var7 <= 256) {
return DiscreteCubeMerger::new(var5, var6);
}
}
// if (var1.getDouble(var5) < var2.getDouble(0) - 1.0E-7D) {
// return new NonOverlappingMerger(var1, var2, false);
// } else if (var2.getDouble(var6) < var1.getDouble(0) - 1.0E-7D) {
// return new NonOverlappingMerger(var2, var1, true);
// } else {
// return (IndexMerger)(var5 == var6 && Objects.equals(var1, var2) ? new IdenticalMerger(var1) : new IndirectMerger(var1, var2, var3, var4));
// }
if var1.get_double(var5) < var2.get_double(0) - 1.0E-7 {
return NonOverlappingMerger::new(var1, var2, false);
} else if var2.get_double(var6) < var1.get_double(0) - 1.0E-7 {
return NonOverlappingMerger::new(var2, var1, true);
} else {
if var5 == var6 && var1 == var2 {
return IdenticalMerger::new(var1);
} else {
return IndirectMerger::new(var1, var2, var3, var4);
}
}
}
}
pub trait VoxelShape: Send + Sync {
@ -40,6 +151,10 @@ pub trait VoxelShape: Send + Sync {
fn get_coords(&self, axis: Axis) -> Vec<f64>;
fn is_empty(&self) -> bool {
self.shape().is_empty()
}
// TODO: optimization: should this be changed to return ArrayVoxelShape?
// i might change the implementation of empty_shape in the future so not 100% sure
fn move_relative(&self, x: f64, y: f64, z: f64) -> Box<dyn VoxelShape> {
@ -236,6 +351,40 @@ impl VoxelShape for CubeVoxelShape {
}
}
// public class CubePointRange extends AbstractDoubleList {
// private final int parts;
// CubePointRange(int var1) {
// super();
// if (var1 <= 0) {
// throw new IllegalArgumentException("Need at least 1 part");
// } else {
// this.parts = var1;
// }
// }
// public double getDouble(int var1) {
// return (double)var1 / (double)this.parts;
// }
// public int size() {
// return this.parts + 1;
// }
// }
pub struct CubePointRange {
/// Needs at least 1 part
pub parts: NonZeroU32,
}
impl CubePointRange {
pub fn get_double(&self, index: u32) -> f64 {
index as f64 / self.parts.get() as f64
}
pub fn size(&self) -> u32 {
self.parts.get() + 1
}
}
#[cfg(test)]
mod tests {
use super::*;