Apply coordinate offset only to VoxelShape

VoxelShape coordiantes generally are an integer + a sum of powers of
two between [-1, -3]. Most offsets are generally an integer. As
a result, applying an offset to the coordinates generally results
in an error of 0. However, coordinate inputs do not follow such
trends. Thus, when applying an offset to the coordinate input,
there may be some floating point error.

By applying the offset to the VoxelShape coordinates, we can
eliminate additional floating point error.

This change also fixes the inconsistency when using
the single AABB, as input coordinates were not offset
when using the single AABB as the single AABB is already
offset.

Fixes https://github.com/Tuinity/Moonrise/issues/81
This specific issue is caused by floating point error resulting
in the falling anvil's y position becoming around -8E-17 when it
should be 0.
While this is still very comfortably in the collision
epsilon (1.0E-7), this results in the falling anvil's y block
position to become -1 (as the block position is simply
the floor of the coordinate).
This commit is contained in:
Spottedleaf 2024-12-04 02:52:58 -08:00
parent 97afdbfb02
commit 8999170435

View file

@ -16056,11 +16056,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ // startIndex and endIndex inclusive
+ // assumes indices are in range of array
+ public static int findFloor(final double[] values, final double value, int startIndex, int endIndex) {
+ public static int findFloor(final double[] values, final double offset, final double value, int startIndex, int endIndex) {
+ Objects.checkFromToIndex(startIndex, endIndex + 1, values.length);
+ do {
+ final int middle = (startIndex + endIndex) >>> 1;
+ final double middleVal = values[middle];
+ final double middleVal = (values[middle] + offset);
+
+ if (value < middleVal) {
+ endIndex = middle - 1;
@ -16309,8 +16309,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ // an AABB(coords_x[x], coords_y[y], coords_z[z], coords_x[x + 1], coords_y[y + 1], coords_z[z + 1])
+ // is collidable. this is the fundamental principle of operation for the voxel collision operation
+
+ // note: we should be offsetting coords, but we can also just subtract from source as well - which is
+ // a win in terms of ops / simplicity (see findFloor, allows us to not modify coords for that)
+ // note: for intersection, one we find the floor of the min we can use that as the start index
+ // for the next check as source max >= source min
+ // note: we can fast check intersection on the two other axis by seeing if the min index is >= size,
@ -16319,7 +16317,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ final int floor_min_x = Math.max(
+ 0,
+ findFloor(coords_x, (aabb.minX - off_x) + COLLISION_EPSILON, 0, size_x)
+ findFloor(coords_x, off_x, aabb.minX + COLLISION_EPSILON, 0, size_x)
+ );
+ if (floor_min_x >= size_x) {
+ // cannot intersect
@ -16328,7 +16326,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ final int ceil_max_x = Math.min(
+ size_x,
+ findFloor(coords_x, (aabb.maxX - off_x) - COLLISION_EPSILON, floor_min_x, size_x) + 1
+ findFloor(coords_x, off_x, aabb.maxX - COLLISION_EPSILON, floor_min_x, size_x) + 1
+ );
+ if (floor_min_x >= ceil_max_x) {
+ // cannot intersect
@ -16337,7 +16335,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ final int floor_min_y = Math.max(
+ 0,
+ findFloor(coords_y, (aabb.minY - off_y) + COLLISION_EPSILON, 0, size_y)
+ findFloor(coords_y, off_y, aabb.minY + COLLISION_EPSILON, 0, size_y)
+ );
+ if (floor_min_y >= size_y) {
+ // cannot intersect
@ -16346,7 +16344,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ final int ceil_max_y = Math.min(
+ size_y,
+ findFloor(coords_y, (aabb.maxY - off_y) - COLLISION_EPSILON, floor_min_y, size_y) + 1
+ findFloor(coords_y, off_y, aabb.maxY - COLLISION_EPSILON, floor_min_y, size_y) + 1
+ );
+ if (floor_min_y >= ceil_max_y) {
+ // cannot intersect
@ -16355,7 +16353,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ final int floor_min_z = Math.max(
+ 0,
+ findFloor(coords_z, (aabb.minZ - off_z) + COLLISION_EPSILON, 0, size_z)
+ findFloor(coords_z, off_z, aabb.minZ + COLLISION_EPSILON, 0, size_z)
+ );
+ if (floor_min_z >= size_z) {
+ // cannot intersect
@ -16364,7 +16362,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ final int ceil_max_z = Math.min(
+ size_z,
+ findFloor(coords_z, (aabb.maxZ - off_z) - COLLISION_EPSILON, floor_min_z, size_z) + 1
+ findFloor(coords_z, off_z, aabb.maxZ - COLLISION_EPSILON, floor_min_z, size_z) + 1
+ );
+ if (floor_min_z >= ceil_max_z) {
+ // cannot intersect
@ -16420,8 +16418,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ // is collidable. this is the fundamental principle of operation for the voxel collision operation
+
+
+ // note: we should be offsetting coords, but we can also just subtract from source as well - which is
+ // a win in terms of ops / simplicity (see findFloor, allows us to not modify coords for that)
+ // note: for intersection, one we find the floor of the min we can use that as the start index
+ // for the next check as source max >= source min
+ // note: we can fast check intersection on the two other axis by seeing if the min index is >= size,
@ -16430,7 +16426,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ final int floor_min_y = Math.max(
+ 0,
+ findFloor(coords_y, (source.minY - off_y) + COLLISION_EPSILON, 0, size_y)
+ findFloor(coords_y, off_y, source.minY + COLLISION_EPSILON, 0, size_y)
+ );
+ if (floor_min_y >= size_y) {
+ // cannot intersect
@ -16439,7 +16435,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ final int ceil_max_y = Math.min(
+ size_y,
+ findFloor(coords_y, (source.maxY - off_y) - COLLISION_EPSILON, floor_min_y, size_y) + 1
+ findFloor(coords_y, off_y, source.maxY - COLLISION_EPSILON, floor_min_y, size_y) + 1
+ );
+ if (floor_min_y >= ceil_max_y) {
+ // cannot intersect
@ -16448,7 +16444,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ final int floor_min_z = Math.max(
+ 0,
+ findFloor(coords_z, (source.minZ - off_z) + COLLISION_EPSILON, 0, size_z)
+ findFloor(coords_z, off_z, source.minZ + COLLISION_EPSILON, 0, size_z)
+ );
+ if (floor_min_z >= size_z) {
+ // cannot intersect
@ -16457,7 +16453,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ final int ceil_max_z = Math.min(
+ size_z,
+ findFloor(coords_z, (source.maxZ - off_z) - COLLISION_EPSILON, floor_min_z, size_z) + 1
+ findFloor(coords_z, off_z, source.maxZ - COLLISION_EPSILON, floor_min_z, size_z) + 1
+ );
+ if (floor_min_z >= ceil_max_z) {
+ // cannot intersect
@ -16469,9 +16465,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ final long[] bitset = cached_shape_data.voxelSet();
+
+ if (source_move > 0.0) {
+ final double source_max = source.maxX - off_x;
+ final double source_max = source.maxX;
+ final int ceil_max_x = findFloor(
+ coords_x, source_max - COLLISION_EPSILON, 0, size_x
+ coords_x, off_x, source_max - COLLISION_EPSILON, 0, size_x
+ ) + 1; // add one, we are not interested in (coords[i] + COLLISION_EPSILON) < max
+
+ // note: only the order of the first loop matters
@ -16480,7 +16476,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ final int mul_x = size_y*size_z;
+ for (int curr_x = ceil_max_x; curr_x < size_x; ++curr_x) {
+ double max_dist = coords_x[curr_x] - source_max;
+ double max_dist = (coords_x[curr_x] + off_x) - source_max;
+ if (max_dist >= source_move) {
+ // if we reach here, then we will never have a case where
+ // coords[curr + n] - source_max < source_move, as coords[curr + n] < coords[curr + n + 1]
@ -16507,9 +16503,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ return source_move;
+ } else {
+ final double source_min = source.minX - off_x;
+ final double source_min = source.minX;
+ final int floor_min_x = findFloor(
+ coords_x, source_min + COLLISION_EPSILON, 0, size_x
+ coords_x, off_x, source_min + COLLISION_EPSILON, 0, size_x
+ );
+
+ // note: only the order of the first loop matters
@ -16521,7 +16517,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ // thus, we need to use the voxel index i-1 if we want to check that the face at index i is solid
+ final int mul_x = size_y*size_z;
+ for (int curr_x = floor_min_x - 1; curr_x >= 0; --curr_x) {
+ double max_dist = coords_x[curr_x + 1] - source_min;
+ double max_dist = (coords_x[curr_x + 1] + off_x) - source_min;
+ if (max_dist <= source_move) {
+ // if we reach here, then we will never have a case where
+ // coords[curr + n] - source_max > source_move, as coords[curr + n] > coords[curr + n - 1]
@ -16578,8 +16574,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ // is collidable. this is the fundamental principle of operation for the voxel collision operation
+
+
+ // note: we should be offsetting coords, but we can also just subtract from source as well - which is
+ // a win in terms of ops / simplicity (see findFloor, allows us to not modify coords for that)
+ // note: for intersection, one we find the floor of the min we can use that as the start index
+ // for the next check as source max >= source min
+ // note: we can fast check intersection on the two other axis by seeing if the min index is >= size,
@ -16588,7 +16582,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ final int floor_min_x = Math.max(
+ 0,
+ findFloor(coords_x, (source.minX - off_x) + COLLISION_EPSILON, 0, size_x)
+ findFloor(coords_x, off_x, source.minX + COLLISION_EPSILON, 0, size_x)
+ );
+ if (floor_min_x >= size_x) {
+ // cannot intersect
@ -16597,7 +16591,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ final int ceil_max_x = Math.min(
+ size_x,
+ findFloor(coords_x, (source.maxX - off_x) - COLLISION_EPSILON, floor_min_x, size_x) + 1
+ findFloor(coords_x, off_x, source.maxX - COLLISION_EPSILON, floor_min_x, size_x) + 1
+ );
+ if (floor_min_x >= ceil_max_x) {
+ // cannot intersect
@ -16606,7 +16600,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ final int floor_min_z = Math.max(
+ 0,
+ findFloor(coords_z, (source.minZ - off_z) + COLLISION_EPSILON, 0, size_z)
+ findFloor(coords_z, off_z, source.minZ + COLLISION_EPSILON, 0, size_z)
+ );
+ if (floor_min_z >= size_z) {
+ // cannot intersect
@ -16615,7 +16609,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ final int ceil_max_z = Math.min(
+ size_z,
+ findFloor(coords_z, (source.maxZ - off_z) - COLLISION_EPSILON, floor_min_z, size_z) + 1
+ findFloor(coords_z, off_z, source.maxZ - COLLISION_EPSILON, floor_min_z, size_z) + 1
+ );
+ if (floor_min_z >= ceil_max_z) {
+ // cannot intersect
@ -16627,9 +16621,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ final long[] bitset = cached_shape_data.voxelSet();
+
+ if (source_move > 0.0) {
+ final double source_max = source.maxY - off_y;
+ final double source_max = source.maxY;
+ final int ceil_max_y = findFloor(
+ coords_y, source_max - COLLISION_EPSILON, 0, size_y
+ coords_y, off_y, source_max - COLLISION_EPSILON, 0, size_y
+ ) + 1; // add one, we are not interested in (coords[i] + COLLISION_EPSILON) < max
+
+ // note: only the order of the first loop matters
@ -16638,7 +16632,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ final int mul_x = size_y*size_z;
+ for (int curr_y = ceil_max_y; curr_y < size_y; ++curr_y) {
+ double max_dist = coords_y[curr_y] - source_max;
+ double max_dist = (coords_y[curr_y] + off_y) - source_max;
+ if (max_dist >= source_move) {
+ // if we reach here, then we will never have a case where
+ // coords[curr + n] - source_max < source_move, as coords[curr + n] < coords[curr + n + 1]
@ -16665,9 +16659,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ return source_move;
+ } else {
+ final double source_min = source.minY - off_y;
+ final double source_min = source.minY;
+ final int floor_min_y = findFloor(
+ coords_y, source_min + COLLISION_EPSILON, 0, size_y
+ coords_y, off_y, source_min + COLLISION_EPSILON, 0, size_y
+ );
+
+ // note: only the order of the first loop matters
@ -16679,7 +16673,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ // thus, we need to use the voxel index i-1 if we want to check that the face at index i is solid
+ final int mul_x = size_y*size_z;
+ for (int curr_y = floor_min_y - 1; curr_y >= 0; --curr_y) {
+ double max_dist = coords_y[curr_y + 1] - source_min;
+ double max_dist = (coords_y[curr_y + 1] + off_y) - source_min;
+ if (max_dist <= source_move) {
+ // if we reach here, then we will never have a case where
+ // coords[curr + n] - source_max > source_move, as coords[curr + n] > coords[curr + n - 1]
@ -16736,8 +16730,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ // is collidable. this is the fundamental principle of operation for the voxel collision operation
+
+
+ // note: we should be offsetting coords, but we can also just subtract from source as well - which is
+ // a win in terms of ops / simplicity (see findFloor, allows us to not modify coords for that)
+ // note: for intersection, one we find the floor of the min we can use that as the start index
+ // for the next check as source max >= source min
+ // note: we can fast check intersection on the two other axis by seeing if the min index is >= size,
@ -16746,7 +16738,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ final int floor_min_x = Math.max(
+ 0,
+ findFloor(coords_x, (source.minX - off_x) + COLLISION_EPSILON, 0, size_x)
+ findFloor(coords_x, off_x, source.minX + COLLISION_EPSILON, 0, size_x)
+ );
+ if (floor_min_x >= size_x) {
+ // cannot intersect
@ -16755,7 +16747,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ final int ceil_max_x = Math.min(
+ size_x,
+ findFloor(coords_x, (source.maxX - off_x) - COLLISION_EPSILON, floor_min_x, size_x) + 1
+ findFloor(coords_x, off_x, source.maxX - COLLISION_EPSILON, floor_min_x, size_x) + 1
+ );
+ if (floor_min_x >= ceil_max_x) {
+ // cannot intersect
@ -16764,7 +16756,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ final int floor_min_y = Math.max(
+ 0,
+ findFloor(coords_y, (source.minY - off_y) + COLLISION_EPSILON, 0, size_y)
+ findFloor(coords_y, off_y, source.minY + COLLISION_EPSILON, 0, size_y)
+ );
+ if (floor_min_y >= size_y) {
+ // cannot intersect
@ -16773,7 +16765,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ final int ceil_max_y = Math.min(
+ size_y,
+ findFloor(coords_y, (source.maxY - off_y) - COLLISION_EPSILON, floor_min_y, size_y) + 1
+ findFloor(coords_y, off_y, source.maxY - COLLISION_EPSILON, floor_min_y, size_y) + 1
+ );
+ if (floor_min_y >= ceil_max_y) {
+ // cannot intersect
@ -16785,9 +16777,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ final long[] bitset = cached_shape_data.voxelSet();
+
+ if (source_move > 0.0) {
+ final double source_max = source.maxZ - off_z;
+ final double source_max = source.maxZ;
+ final int ceil_max_z = findFloor(
+ coords_z, source_max - COLLISION_EPSILON, 0, size_z
+ coords_z, off_z, source_max - COLLISION_EPSILON, 0, size_z
+ ) + 1; // add one, we are not interested in (coords[i] + COLLISION_EPSILON) < max
+
+ // note: only the order of the first loop matters
@ -16796,7 +16788,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ final int mul_x = size_y*size_z;
+ for (int curr_z = ceil_max_z; curr_z < size_z; ++curr_z) {
+ double max_dist = coords_z[curr_z] - source_max;
+ double max_dist = (coords_z[curr_z] + off_z) - source_max;
+ if (max_dist >= source_move) {
+ // if we reach here, then we will never have a case where
+ // coords[curr + n] - source_max < source_move, as coords[curr + n] < coords[curr + n + 1]
@ -16823,9 +16815,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ return source_move;
+ } else {
+ final double source_min = source.minZ - off_z;
+ final double source_min = source.minZ;
+ final int floor_min_z = findFloor(
+ coords_z, source_min + COLLISION_EPSILON, 0, size_z
+ coords_z, off_z, source_min + COLLISION_EPSILON, 0, size_z
+ );
+
+ // note: only the order of the first loop matters
@ -16837,7 +16829,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ // thus, we need to use the voxel index i-1 if we want to check that the face at index i is solid
+ final int mul_x = size_y*size_z;
+ for (int curr_z = floor_min_z - 1; curr_z >= 0; --curr_z) {
+ double max_dist = coords_z[curr_z + 1] - source_min;
+ double max_dist = (coords_z[curr_z + 1] + off_z) - source_min;
+ if (max_dist <= source_move) {
+ // if we reach here, then we will never have a case where
+ // coords[curr + n] - source_max > source_move, as coords[curr + n] > coords[curr + n - 1]
@ -16872,7 +16864,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ }
+
+ // does not use epsilon
+ public static boolean strictlyContains(final VoxelShape voxel, double x, double y, double z) {
+ public static boolean strictlyContains(final VoxelShape voxel, final double x, final double y, final double z) {
+ final AABB single_aabb = ((CollisionVoxelShape)voxel).moonrise$getSingleAABBRepresentation();
+ if (single_aabb != null) {
+ return single_aabb.contains(x, y, z);
@ -16883,10 +16875,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ return false;
+ }
+
+ // offset input
+ x -= ((CollisionVoxelShape)voxel).moonrise$offsetX();
+ y -= ((CollisionVoxelShape)voxel).moonrise$offsetY();
+ z -= ((CollisionVoxelShape)voxel).moonrise$offsetZ();
+ final double off_x = ((CollisionVoxelShape)voxel).moonrise$offsetX();
+ final double off_y = ((CollisionVoxelShape)voxel).moonrise$offsetY();
+ final double off_z = ((CollisionVoxelShape)voxel).moonrise$offsetZ();
+
+ final double[] coords_x = ((CollisionVoxelShape)voxel).moonrise$rootCoordinatesX();
+ final double[] coords_y = ((CollisionVoxelShape)voxel).moonrise$rootCoordinatesY();
@ -16902,17 +16893,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ // note: should mirror AABB#contains, which is that for any point X that X >= min and X < max.
+ // specifically, it cannot collide on the max bounds of the shape
+
+ final int index_x = findFloor(coords_x, x, 0, size_x);
+ final int index_x = findFloor(coords_x, off_x, x, 0, size_x);
+ if (index_x < 0 || index_x >= size_x) {
+ return false;
+ }
+
+ final int index_y = findFloor(coords_y, y, 0, size_y);
+ final int index_y = findFloor(coords_y, off_y, y, 0, size_y);
+ if (index_y < 0 || index_y >= size_y) {
+ return false;
+ }
+
+ final int index_z = findFloor(coords_z, z, 0, size_z);
+ final int index_z = findFloor(coords_z, off_z, z, 0, size_z);
+ if (index_z < 0 || index_z >= size_z) {
+ return false;
+ }
@ -17585,74 +17576,56 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ public static double performAABBCollisionsX(final AABB currentBoundingBox, double value, final List<AABB> potentialCollisions) {
+ for (int i = 0, len = potentialCollisions.size(); i < len; ++i) {
+ if (Math.abs(value) < COLLISION_EPSILON) {
+ return 0.0;
+ }
+ final AABB target = potentialCollisions.get(i);
+ value = collideX(target, currentBoundingBox, value);
+ }
+
+ return Math.abs(value) < COLLISION_EPSILON ? 0.0 : value;
+ return value;
+ }
+
+ public static double performAABBCollisionsY(final AABB currentBoundingBox, double value, final List<AABB> potentialCollisions) {
+ for (int i = 0, len = potentialCollisions.size(); i < len; ++i) {
+ if (Math.abs(value) < COLLISION_EPSILON) {
+ return 0.0;
+ }
+ final AABB target = potentialCollisions.get(i);
+ value = collideY(target, currentBoundingBox, value);
+ }
+
+ return Math.abs(value) < COLLISION_EPSILON ? 0.0 : value;
+ return value;
+ }
+
+ public static double performAABBCollisionsZ(final AABB currentBoundingBox, double value, final List<AABB> potentialCollisions) {
+ for (int i = 0, len = potentialCollisions.size(); i < len; ++i) {
+ if (Math.abs(value) < COLLISION_EPSILON) {
+ return 0.0;
+ }
+ final AABB target = potentialCollisions.get(i);
+ value = collideZ(target, currentBoundingBox, value);
+ }
+
+ return Math.abs(value) < COLLISION_EPSILON ? 0.0 : value;
+ return value;
+ }
+
+ public static double performVoxelCollisionsX(final AABB currentBoundingBox, double value, final List<VoxelShape> potentialCollisions) {
+ for (int i = 0, len = potentialCollisions.size(); i < len; ++i) {
+ if (Math.abs(value) < COLLISION_EPSILON) {
+ return 0.0;
+ }
+ final VoxelShape target = potentialCollisions.get(i);
+ value = collideX(target, currentBoundingBox, value);
+ }
+
+ return Math.abs(value) < COLLISION_EPSILON ? 0.0 : value;
+ return value;
+ }
+
+ public static double performVoxelCollisionsY(final AABB currentBoundingBox, double value, final List<VoxelShape> potentialCollisions) {
+ for (int i = 0, len = potentialCollisions.size(); i < len; ++i) {
+ if (Math.abs(value) < COLLISION_EPSILON) {
+ return 0.0;
+ }
+ final VoxelShape target = potentialCollisions.get(i);
+ value = collideY(target, currentBoundingBox, value);
+ }
+
+ return Math.abs(value) < COLLISION_EPSILON ? 0.0 : value;
+ return value;
+ }
+
+ public static double performVoxelCollisionsZ(final AABB currentBoundingBox, double value, final List<VoxelShape> potentialCollisions) {
+ for (int i = 0, len = potentialCollisions.size(); i < len; ++i) {
+ if (Math.abs(value) < COLLISION_EPSILON) {
+ return 0.0;
+ }
+ final VoxelShape target = potentialCollisions.get(i);
+ value = collideZ(target, currentBoundingBox, value);
+ }
+
+ return Math.abs(value) < COLLISION_EPSILON ? 0.0 : value;
+ return value;
+ }
+
+ public static Vec3 performVoxelCollisions(final Vec3 moveVector, AABB axisalignedbb, final List<VoxelShape> potentialCollisions) {
@ -35201,7 +35174,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ // see findIndex
+ final int index = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.findFloor(
+ coords, (positiveDir ? (1.0 - ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON) : (0.0 + ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON)) - offset,
+ coords, offset, (positiveDir ? (1.0 - ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON) : (0.0 + ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON)),
+ 0, coords.length - 1
+ );
+
@ -35513,19 +35486,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ case X: {
+ final double[] values = this.rootCoordinatesX;
+ return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.findFloor(
+ values, value - this.offsetX, 0, values.length - 1
+ values, this.offsetX, value, 0, values.length - 1
+ );
+ }
+ case Y: {
+ final double[] values = this.rootCoordinatesY;
+ return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.findFloor(
+ values, value - this.offsetY, 0, values.length - 1
+ values, this.offsetY, value, 0, values.length - 1
+ );
+ }
+ case Z: {
+ final double[] values = this.rootCoordinatesZ;
+ return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.findFloor(
+ values, value - this.offsetZ, 0, values.length - 1
+ values, this.offsetZ, value, 0, values.length - 1
+ );
+ }
+ default: {