Compare commits

...
Author SHA1 Message Date
Axionize 6b863655f1 Merge remote-tracking branch 'origin/2.0' into flatten-complexcollisionboxes
# Conflicts:
#	src/main/java/ac/grim/grimac/utils/collisions/HitboxData.java
2024-11-22 09:13:17 -05:00
Axionize 631be06ec2 Remove unused calls to makeShapes() 2024-11-22 09:11:04 -05:00
Axionize 1c4361f2c6 Make makeShapes() CCD extra maxIndex explicit; Fix DynamicCollisionWall error 2024-11-22 09:10:04 -05:00
Axionize 83e06bce77 Make CCD length private var 2024-11-21 18:32:33 -05:00
Axionize 42fd3e1cc7 Rename variable for clarity 2024-11-21 17:14:13 -05:00
Axionize 26a771e4da Fix copying CCBs in edge case 2024-11-21 17:12:38 -05:00
Axionize 1dc4361938 Remove debug print statement 2024-11-21 12:06:03 -05:00
Axionize 3d5491de4f Fix logic error again in CCB constructor 2024-11-21 12:04:04 -05:00
Axionize 75ff92c326 Optimize DynamicHitboxFence 2024-11-21 11:59:19 -05:00
Axionize c530dcfa17 Fix logic error in CCB constructor 2024-11-21 11:58:04 -05:00
Axionize d720b8864f Fix new downCast() for SimpleCollisionBox 2024-11-21 11:41:52 -05:00
Axionize 3e3dbf0f30 Manually size ComplexCollisionBoxes Pt. 2 2024-11-21 11:38:32 -05:00
Axionize 0bd154974b Manually size ComplexCollisionBoxes Pt. 1 2024-11-21 10:28:34 -05:00
Axionize 3f57026960 implement new downCast() API for Dynamic, Simple, and No Collision Boxes 2024-11-21 10:26:46 -05:00
Axionize be9841fb9f Port everything to new internal .downCast() API besides getCollisionBoxes 2024-11-20 12:37:52 -05:00
Axionize d8b529e837 Optimize ComplexCollisionBoxes by using primitives internally; Make new more efficient constructors available 2024-11-20 12:37:01 -05:00
Axionize 743a2d9cdb Ensure ComplexCollisionBoxes can only contain SimpleCollisionBoxes 2024-11-17 11:45:55 -05:00
22 changed files with 224 additions and 144 deletions

No files matched your search

@@ -6,6 +6,7 @@ import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.update.BlockPlace;
import ac.grim.grimac.utils.collisions.HitboxData;
import ac.grim.grimac.utils.collisions.datatypes.CollisionBox;
import ac.grim.grimac.utils.collisions.datatypes.ComplexCollisionBox;
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
import com.github.retrooper.packetevents.protocol.world.states.defaulttags.BlockTags;
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
@@ -18,6 +19,7 @@ import java.util.List;
public class BlockPlaceCheck extends Check implements RotationCheck, PostPredictionCheck {
private static final List<StateType> weirdBoxes = new ArrayList<>();
private static final List<StateType> buggyBoxes = new ArrayList<>();
private final SimpleCollisionBox[] boxes = new SimpleCollisionBox[ComplexCollisionBox.DEFAULT_MAX_COLLISION_BOX_SIZE];
protected int cancelVL;
@@ -69,11 +71,11 @@ public class BlockPlaceCheck extends Check implements RotationCheck, PostPredict
Vector3i clicked = place.getPlacedAgainstBlockLocation();
CollisionBox placedOn = HitboxData.getBlockHitbox(player, place.getMaterial(), player.getClientVersion(), player.compensatedWorld.getWrappedBlockStateAt(clicked), clicked.getX(), clicked.getY(), clicked.getZ());
List<SimpleCollisionBox> boxes = new ArrayList<>();
placedOn.downCast(boxes);
int size = placedOn.downCast(boxes);
SimpleCollisionBox combined = new SimpleCollisionBox(clicked.getX(), clicked.getY(), clicked.getZ());
for (SimpleCollisionBox box : boxes) {
for (int i = 0; i < size; i++) {
SimpleCollisionBox box = boxes[i];
double minX = Math.max(box.minX, combined.minX);
double minY = Math.max(box.minY, combined.minY);
double minZ = Math.max(box.minZ, combined.minZ);
@@ -13,7 +13,6 @@ import ac.grim.grimac.utils.nmsutil.ReachUtils;
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import org.bukkit.util.Vector;
import java.util.*;
@@ -7,6 +7,7 @@ import ac.grim.grimac.utils.collisions.AxisUtil;
import ac.grim.grimac.utils.collisions.CollisionData;
import ac.grim.grimac.utils.collisions.blocks.DoorHandler;
import ac.grim.grimac.utils.collisions.datatypes.CollisionBox;
import ac.grim.grimac.utils.collisions.datatypes.ComplexCollisionBox;
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
import ac.grim.grimac.utils.data.HitData;
import ac.grim.grimac.utils.data.packetentity.PacketEntity;
@@ -37,7 +38,6 @@ import lombok.Setter;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -72,6 +72,9 @@ public class BlockPlace {
@Getter private final boolean block;
// Allocated once instead of in functions to reduce new[] calls that need to be made. Since per-instance BlockPlace is always dealt with on the same thread we can use 1 buffer array
private final SimpleCollisionBox[] collisions = new SimpleCollisionBox[ComplexCollisionBox.DEFAULT_MAX_COLLISION_BOX_SIZE];
public BlockPlace(GrimPlayer player, InteractionHand hand, Vector3i blockPosition, int faceId, BlockFace face, ItemStack itemStack, HitData hitData) {
this.player = player;
this.hand = hand;
@@ -200,12 +203,12 @@ public class BlockPlace {
if (BlockTags.LEAVES.contains(data.getType())) return false;
if (BlockTags.FENCE_GATES.contains(data.getType())) return false;
List<SimpleCollisionBox> collisions = new ArrayList<>();
box.downCast(collisions);
int size = box.downCast(collisions);
AxisSelect axis = AxisUtil.getAxis(facing.getOppositeFace());
for (SimpleCollisionBox simpleBox : collisions) {
for (int i = 0; i < size; i++) {
SimpleCollisionBox simpleBox = collisions[i];
simpleBox = axis.modify(simpleBox);
if (simpleBox.minX <= 7 / 16d && simpleBox.maxX >= 7 / 16d
&& simpleBox.minY <= 0 && simpleBox.maxY >= 10 / 16d
@@ -225,12 +228,12 @@ public class BlockPlace {
if (isFullFace(facing)) return true;
if (BlockTags.LEAVES.contains(data.getType())) return false;
List<SimpleCollisionBox> collisions = new ArrayList<>();
box.downCast(collisions);
int size = box.downCast(collisions);
AxisSelect axis = AxisUtil.getAxis(facing.getOppositeFace());
for (SimpleCollisionBox simpleBox : collisions) {
for (int i = 0; i < size; i++) {
SimpleCollisionBox simpleBox = collisions[i];
simpleBox = axis.modify(simpleBox);
if (simpleBox.minX <= 2 / 16d && simpleBox.maxX >= 14 / 16d
&& simpleBox.minY <= 0 && simpleBox.maxY >= 1
@@ -289,10 +292,10 @@ public class BlockPlace {
}
}
List<SimpleCollisionBox> collisions = new ArrayList<>();
box.downCast(collisions);
int size = box.downCast(collisions);
for (SimpleCollisionBox simpleBox : collisions) {
for (int i = 0; i < size; i++) {
SimpleCollisionBox simpleBox = collisions[i];
if (axis.modify(simpleBox).isFullBlockNoCache()) return true;
}
@@ -318,12 +321,12 @@ public class BlockPlace {
if (isFullFace(facing)) return true;
if (BlockTags.LEAVES.contains(data.getType())) return false;
List<SimpleCollisionBox> collisions = new ArrayList<>();
box.downCast(collisions);
int size = box.downCast(collisions);
AxisSelect axis = AxisUtil.getAxis(facing.getOppositeFace());
for (SimpleCollisionBox simpleBox : collisions) {
for (int i = 0; i < size; i++) {
SimpleCollisionBox simpleBox = collisions[i];
simpleBox = axis.modify(simpleBox);
// If all sides to the box have width, there is collision.
switch (facing) {
@@ -36,7 +36,7 @@ import java.util.stream.Stream;
// This is actually mean to be put into PacketEvents, but I don't like proprietary plugins stealing my code...
public enum CollisionData {
VINE((player, version, block, x, y, z) -> {
ComplexCollisionBox boxes = new ComplexCollisionBox();
ComplexCollisionBox boxes = new ComplexCollisionBox(5);
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_13) && block.isUp())
boxes.add(new HexCollisionBox(0.0D, 15.0D, 0.0D, 16.0D, 16.0D, 16.0D));
@@ -73,11 +73,19 @@ public enum CollisionData {
BREWING_STAND((player, version, block, x, y, z) -> {
int base = 0;
// maxIndex is 3 instead of 2 for legacy clients because for 1.8 players there is a very rare bug
// That we handle later in the code requiring us to add a box https://bugs.mojang.com/browse/MC-85109 For 1.8 PLAYERS
// 1.8 Brewing Stand hitbox is a fullblock until it is hit sometimes, can be caused be restarting client and joining server
int maxIndex = 3;
if (version.isNewerThanOrEquals(ClientVersion.V_1_13))
// Yes I know we only need maxIndex = 3 for 1.8 specifically
// No I'm not adding a special clause for which would require another if check, I'll take compute > memory any day
if (version.isNewerThanOrEquals(ClientVersion.V_1_13)) {
maxIndex = 2;
base = 1;
}
return new ComplexCollisionBox(
return new ComplexCollisionBox(maxIndex,
new HexCollisionBox(base, 0, base, 16 - base, 2, 16 - base),
new SimpleCollisionBox(0.4375, 0.0, 0.4375, 0.5625, 0.875, 0.5625, false));
@@ -100,7 +108,7 @@ public enum CollisionData {
if (version.isOlderThanOrEquals(ClientVersion.V_1_12_2))
height = 0.3125;
return new ComplexCollisionBox(
return new ComplexCollisionBox(5,
new SimpleCollisionBox(0, 0, 0, 1, height, 1, false),
new SimpleCollisionBox(0, height, 0, 0.125, 1, 1, false),
new SimpleCollisionBox(1 - 0.125, height, 0, 1, 1, 1, false),
@@ -119,7 +127,7 @@ public enum CollisionData {
// The base is 0.75×0.75, and its floor is 0.25b high.
// The top is 1×0.625, and its ceiling is 0.375b low.
if (version.isNewerThanOrEquals(ClientVersion.V_1_13)) {
ComplexCollisionBox complexAnvil = new ComplexCollisionBox();
ComplexCollisionBox complexAnvil = new ComplexCollisionBox(4);
// Base of the anvil
complexAnvil.add(new HexCollisionBox(2, 0, 2, 14, 4, 14));
if (face == BlockFace.NORTH || face == BlockFace.SOUTH) {
@@ -188,7 +196,7 @@ public enum CollisionData {
HOPPER((player, version, data, x, y, z) -> {
if (version.isNewerThanOrEquals(ClientVersion.V_1_13)) {
ComplexCollisionBox hopperBox = new ComplexCollisionBox();
ComplexCollisionBox hopperBox = new ComplexCollisionBox(7);
switch (data.getFacing()) {
case DOWN:
@@ -219,7 +227,7 @@ public enum CollisionData {
} else {
double height = 0.125 * 5;
return new ComplexCollisionBox(
return new ComplexCollisionBox(5,
new SimpleCollisionBox(0, 0, 0, 1, height, 1, false),
new SimpleCollisionBox(0, height, 0, 0.125, 1, 1, false),
new SimpleCollisionBox(1 - 0.125, height, 0, 1, 1, 1, false),
@@ -290,7 +298,7 @@ public enum CollisionData {
}
ComplexCollisionBox complex = new ComplexCollisionBox(
ComplexCollisionBox complex = new ComplexCollisionBox(3,
new HexCollisionBox(5.0D, 6.0D, 5.0D, 11.0D, 13.0D, 11.0D),
new HexCollisionBox(4.0D, 4.0D, 4.0D, 12.0D, 6.0D, 12.0D));
@@ -324,7 +332,8 @@ public enum CollisionData {
return new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true);
if (player.lastY > y + 1 - 1e-5 && !player.isSneaking) {
return new ComplexCollisionBox(new HexCollisionBox(0.0D, 14.0D, 0.0D, 16.0D, 16.0D, 16.0D),
return new ComplexCollisionBox(5,
new HexCollisionBox(0.0D, 14.0D, 0.0D, 16.0D, 16.0D, 16.0D),
new HexCollisionBox(0.0D, 0.0D, 0.0D, 2.0D, 16.0D, 2.0D),
new HexCollisionBox(14.0D, 0.0D, 0.0D, 16.0D, 16.0D, 2.0D),
new HexCollisionBox(0.0D, 0.0D, 14.0D, 2.0D, 16.0D, 16.0),
@@ -368,11 +377,13 @@ public enum CollisionData {
return new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true);
if (data.isHanging()) {
return new ComplexCollisionBox(new HexCollisionBox(5.0D, 1.0D, 5.0D, 11.0D, 8.0D, 11.0D),
return new ComplexCollisionBox(2,
new HexCollisionBox(5.0D, 1.0D, 5.0D, 11.0D, 8.0D, 11.0D),
new HexCollisionBox(6.0D, 8.0D, 6.0D, 10.0D, 10.0D, 10.0D));
}
return new ComplexCollisionBox(new HexCollisionBox(5.0D, 0.0D, 5.0D, 11.0D, 7.0D, 11.0D),
return new ComplexCollisionBox(2,
new HexCollisionBox(5.0D, 0.0D, 5.0D, 11.0D, 7.0D, 11.0D),
new HexCollisionBox(6.0D, 7.0D, 6.0D, 10.0D, 9.0D, 10.0D));
}, StateTypes.LANTERN, StateTypes.SOUL_LANTERN),
@@ -382,7 +393,7 @@ public enum CollisionData {
if (version.isOlderThanOrEquals(ClientVersion.V_1_13_2))
return new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true);
return new ComplexCollisionBox(
return new ComplexCollisionBox(2,
new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 2.0D, 16.0D), // base
new HexCollisionBox(4.0D, 2.0D, 4.0D, 12.0D, 14.0D, 12.0D)); // post
}, StateTypes.LECTERN),
@@ -411,7 +422,7 @@ public enum CollisionData {
}
if (version.isOlderThanOrEquals(ClientVersion.V_1_13_2)) {
ComplexCollisionBox complexAnvil = new ComplexCollisionBox();
ComplexCollisionBox complexAnvil = new ComplexCollisionBox(4);
// Base of the anvil
complexAnvil.add(new HexCollisionBox(2, 0, 2, 14, 4, 14));
@@ -431,13 +442,15 @@ public enum CollisionData {
Face attachment = data.getFace();
if (attachment == Face.FLOOR) {
if (facing == BlockFace.NORTH || facing == BlockFace.SOUTH) {
return new ComplexCollisionBox(new HexCollisionBox(2.0D, 0.0D, 6.0D, 4.0D, 7.0D, 10.0D),
return new ComplexCollisionBox(5,
new HexCollisionBox(2.0D, 0.0D, 6.0D, 4.0D, 7.0D, 10.0D),
new HexCollisionBox(12.0D, 0.0D, 6.0D, 14.0D, 7.0D, 10.0D),
new HexCollisionBox(2.0D, 7.0D, 5.0D, 4.0D, 13.0D, 11.0D),
new HexCollisionBox(12.0D, 7.0D, 5.0D, 14.0D, 13.0D, 11.0D),
new HexCollisionBox(4.0D, 4.0D, 2.0D, 12.0D, 16.0D, 14.0D));
} else {
return new ComplexCollisionBox(new HexCollisionBox(6.0D, 0.0D, 2.0D, 10.0D, 7.0D, 4.0D),
return new ComplexCollisionBox(5,
new HexCollisionBox(6.0D, 0.0D, 2.0D, 10.0D, 7.0D, 4.0D),
new HexCollisionBox(6.0D, 0.0D, 12.0D, 10.0D, 7.0D, 14.0D),
new HexCollisionBox(5.0D, 7.0D, 2.0D, 11.0D, 13.0D, 4.0D),
new HexCollisionBox(5.0D, 7.0D, 12.0D, 11.0D, 13.0D, 14.0D),
@@ -446,25 +459,29 @@ public enum CollisionData {
} else if (attachment == Face.WALL) {
switch (facing) {
case NORTH:
return new ComplexCollisionBox(new HexCollisionBox(2.0D, 6.0D, 7.0D, 4.0D, 10.0D, 16.0D),
return new ComplexCollisionBox(5,
new HexCollisionBox(2.0D, 6.0D, 7.0D, 4.0D, 10.0D, 16.0D),
new HexCollisionBox(12.0D, 6.0D, 7.0D, 14.0D, 10.0D, 16.0D),
new HexCollisionBox(2.0D, 5.0D, 3.0D, 4.0D, 11.0D, 9.0D),
new HexCollisionBox(12.0D, 5.0D, 3.0D, 14.0D, 11.0D, 9.0D),
new HexCollisionBox(4.0D, 2.0D, 0.0D, 12.0D, 14.0D, 12.0D));
case WEST:
return new ComplexCollisionBox(new HexCollisionBox(7.0D, 6.0D, 2.0D, 16.0D, 10.0D, 4.0D),
return new ComplexCollisionBox(5,
new HexCollisionBox(7.0D, 6.0D, 2.0D, 16.0D, 10.0D, 4.0D),
new HexCollisionBox(7.0D, 6.0D, 12.0D, 16.0D, 10.0D, 14.0D),
new HexCollisionBox(3.0D, 5.0D, 2.0D, 9.0D, 11.0D, 4.0D),
new HexCollisionBox(3.0D, 5.0D, 12.0D, 9.0D, 11.0D, 14.0D),
new HexCollisionBox(0.0D, 2.0D, 4.0D, 12.0D, 14.0D, 12.0D));
case SOUTH:
return new ComplexCollisionBox(new HexCollisionBox(2.0D, 6.0D, 0.0D, 4.0D, 10.0D, 7.0D),
return new ComplexCollisionBox(5,
new HexCollisionBox(2.0D, 6.0D, 0.0D, 4.0D, 10.0D, 7.0D),
new HexCollisionBox(12.0D, 6.0D, 0.0D, 14.0D, 10.0D, 7.0D),
new HexCollisionBox(2.0D, 5.0D, 7.0D, 4.0D, 11.0D, 13.0D),
new HexCollisionBox(12.0D, 5.0D, 7.0D, 14.0D, 11.0D, 13.0D),
new HexCollisionBox(4.0D, 2.0D, 4.0D, 12.0D, 14.0D, 16.0D));
case EAST:
return new ComplexCollisionBox(new HexCollisionBox(0.0D, 6.0D, 2.0D, 9.0D, 10.0D, 4.0D),
return new ComplexCollisionBox(5,
new HexCollisionBox(0.0D, 6.0D, 2.0D, 9.0D, 10.0D, 4.0D),
new HexCollisionBox(0.0D, 6.0D, 12.0D, 9.0D, 10.0D, 14.0D),
new HexCollisionBox(7.0D, 5.0D, 2.0D, 13.0D, 11.0D, 4.0D),
new HexCollisionBox(7.0D, 5.0D, 12.0D, 13.0D, 11.0D, 14.0D),
@@ -472,13 +489,15 @@ public enum CollisionData {
}
} else {
if (facing == BlockFace.NORTH || facing == BlockFace.SOUTH) {
return new ComplexCollisionBox(new HexCollisionBox(2.0D, 9.0D, 6.0D, 4.0D, 16.0D, 10.0D),
return new ComplexCollisionBox(5,
new HexCollisionBox(2.0D, 9.0D, 6.0D, 4.0D, 16.0D, 10.0D),
new HexCollisionBox(12.0D, 9.0D, 6.0D, 14.0D, 16.0D, 10.0D),
new HexCollisionBox(2.0D, 3.0D, 5.0D, 4.0D, 9.0D, 11.0D),
new HexCollisionBox(12.0D, 3.0D, 5.0D, 14.0D, 9.0D, 11.0D),
new HexCollisionBox(4.0D, 0.0D, 2.0D, 12.0D, 12.0D, 14.0D));
} else {
return new ComplexCollisionBox(new HexCollisionBox(6.0D, 9.0D, 2.0D, 10.0D, 16.0D, 4.0D),
return new ComplexCollisionBox(5,
new HexCollisionBox(6.0D, 9.0D, 2.0D, 10.0D, 16.0D, 4.0D),
new HexCollisionBox(6.0D, 9.0D, 12.0D, 10.0D, 16.0D, 14.0D),
new HexCollisionBox(5.0D, 3.0D, 2.0D, 11.0D, 9.0D, 4.0D),
new HexCollisionBox(5.0D, 3.0D, 12.0D, 11.0D, 9.0D, 14.0D),
@@ -551,7 +570,7 @@ public enum CollisionData {
StateTypes.ENCHANTING_TABLE),
FRAME((player, version, data, x, y, z) -> {
ComplexCollisionBox complexCollisionBox = new ComplexCollisionBox(new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 13.0D, 16.0D));
ComplexCollisionBox complexCollisionBox = new ComplexCollisionBox(2, new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 13.0D, 16.0D));
if (data.isEye()) {
if (version.isNewerThanOrEquals(ClientVersion.V_1_13)) { // 1.13 players have a 0.5x0.5 eye
@@ -622,7 +641,7 @@ public enum CollisionData {
if (version.isOlderThan(ClientVersion.V_1_14))
return new SimpleCollisionBox(0.0F, 0.0F, 0.0F, 1.0F, 0.5625, 1.0F, false);
ComplexCollisionBox baseBox = new ComplexCollisionBox(new HexCollisionBox(0.0D, 3.0D, 0.0D, 16.0D, 9.0D, 16.0D));
ComplexCollisionBox baseBox = new ComplexCollisionBox(3, new HexCollisionBox(0.0D, 3.0D, 0.0D, 16.0D, 9.0D, 16.0D));
switch (data.getFacing()) {
case NORTH:
@@ -662,7 +681,7 @@ public enum CollisionData {
CAULDRON((player, version, data, x, y, z) -> {
if (version.isNewerThan(ClientVersion.getById(467))) { // changed in 19w13a, 1.14 Snapshot
return new ComplexCollisionBox(
return new ComplexCollisionBox(15,
new SimpleCollisionBox(0.0, 0.0, 0.0, 0.125, 1.0, 0.25, false),
new SimpleCollisionBox(0.0, 0.0, 0.75, 0.125, 1.0, 1.0, false),
new SimpleCollisionBox(0.125, 0.0, 0.0, 0.25, 1.0, 0.125, false),
@@ -684,7 +703,7 @@ public enum CollisionData {
if (version.isOlderThan(ClientVersion.V_1_13))
height = 0.3125;
return new ComplexCollisionBox(
return new ComplexCollisionBox(5,
new SimpleCollisionBox(0, 0, 0, 1, height, 1, false),
new SimpleCollisionBox(0, height, 0, 0.125, 1, 1, false),
new SimpleCollisionBox(1 - 0.125, height, 0, 1, 1, 1, false),
@@ -834,10 +853,14 @@ public enum CollisionData {
}, BlockTags.CANDLES.getStates().toArray(new StateType[0])),
CANDLE_CAKE((player, version, data, x, y, z) -> {
ComplexCollisionBox cake = new ComplexCollisionBox(new HexCollisionBox(1.0, 0.0, 1.0, 15.0, 8.0, 15.0));
if (version.isNewerThanOrEquals(ClientVersion.V_1_17))
cake.add(new HexCollisionBox(7.0, 8.0, 7.0, 9.0, 14.0, 9.0));
return cake;
SimpleCollisionBox cake = new HexCollisionBox(1.0, 0.0, 1.0, 15.0, 8.0, 15.0);
if (version.isOlderThan(ClientVersion.V_1_17)) {
return cake;
} else {
return new ComplexCollisionBox(2,
cake,
new HexCollisionBox(7.0, 8.0, 7.0, 9.0, 14.0, 9.0));
}
}, BlockTags.CANDLE_CAKES.getStates().toArray(new StateType[0])),
SCULK_SENSOR(new HexCollisionBox(0.0, 0.0, 0.0, 16.0, 8.0, 16.0), StateTypes.SCULK_SENSOR, StateTypes.CALIBRATED_SCULK_SENSOR),
@@ -914,7 +937,8 @@ public enum CollisionData {
}, StateTypes.NETHER_PORTAL),
AZALEA((player, version, data, x, y, z) -> {
return new ComplexCollisionBox(new HexCollisionBox(0.0, 8.0, 0.0, 16.0, 16.0, 16.0),
return new ComplexCollisionBox(2,
new HexCollisionBox(0.0, 8.0, 0.0, 16.0, 16.0, 16.0),
new HexCollisionBox(6.0, 0.0, 6.0, 10.0, 8.0, 10.0));
}, StateTypes.AZALEA, StateTypes.FLOWERING_AZALEA),
@@ -216,9 +216,11 @@ public enum HitboxData {
WALL_HANGING_SIGN((player, item, version, data, x, y, z) -> {
return switch (data.getFacing()) {
case NORTH, SOUTH -> new ComplexCollisionBox(new HexCollisionBox(0.0D, 14.0D, 6.0D, 16.0D, 16.0D, 10.0D),
case NORTH, SOUTH -> new ComplexCollisionBox(2,
new HexCollisionBox(0.0D, 14.0D, 6.0D, 16.0D, 16.0D, 10.0D),
new HexCollisionBox(1.0D, 0.0D, 7.0D, 15.0D, 10.0D, 9.0D));
default -> new ComplexCollisionBox(new HexCollisionBox(6.0D, 14.0D, 0.0D, 10.0D, 16.0D, 16.0D),
default -> new ComplexCollisionBox(2,
new HexCollisionBox(6.0D, 14.0D, 0.0D, 10.0D, 16.0D, 16.0D),
new HexCollisionBox(7.0D, 0.0D, 1.0D, 9.0D, 10.0D, 15.0D));
};
}, BlockTags.WALL_HANGING_SIGNS.getStates().toArray(new StateType[0])),
@@ -263,7 +265,7 @@ public enum HitboxData {
if (version.isOlderThan(ClientVersion.V_1_13)) {
return new SimpleCollisionBox(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F);
} else {
return new ComplexCollisionBox(
return new ComplexCollisionBox(2,
new HexCollisionBox(1.0, 0.0, 1.0, 15.0, 2.0, 15.0),
new SimpleCollisionBox(0.4375, 0.0, 0.4375, 0.5625, 0.875, 0.5625, false));
}
@@ -303,7 +305,8 @@ public enum HitboxData {
}, StateTypes.SNOW),
LECTERN_BLOCK((player, item, version, data, x, y, z) -> {
ComplexCollisionBox common = new ComplexCollisionBox(new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 2.0D, 16.0D),
ComplexCollisionBox common = new ComplexCollisionBox(5,
new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 2.0D, 16.0D),
new HexCollisionBox(4.0D, 2.0D, 4.0D, 12.0D, 14.0D, 12.0D));
if (data.getFacing() == BlockFace.WEST) {
@@ -329,7 +332,7 @@ public enum HitboxData {
GLOW_LICHEN_SCULK_VEIN((player, item, version, data, x, y, z) -> {
if (version.isNewerThan(ClientVersion.V_1_16_4)) {
ComplexCollisionBox box = new ComplexCollisionBox();
ComplexCollisionBox box = new ComplexCollisionBox(6);
if (data.isUp()) {
box.add(new HexCollisionBox(0.0D, 15.0D, 0.0D, 16.0D, 16.0D, 16.0D));
@@ -491,7 +494,7 @@ public enum HitboxData {
}
// STABLE_SHAPE for the scaffolding
ComplexCollisionBox box = new ComplexCollisionBox(
ComplexCollisionBox box = new ComplexCollisionBox(9,
new HexCollisionBox(0.0D, 14.0D, 0.0D, 16.0D, 16.0D, 16.0D),
new HexCollisionBox(0.0D, 0.0D, 0.0D, 2.0D, 16.0D, 2.0D),
new HexCollisionBox(14.0D, 0.0D, 0.0D, 16.0D, 16.0D, 2.0D),
@@ -512,7 +515,7 @@ public enum HitboxData {
if (version.isOlderThanOrEquals(ClientVersion.V_1_16_4))
return new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true);
ComplexCollisionBox box = new ComplexCollisionBox();
ComplexCollisionBox box = new ComplexCollisionBox(2);
if (data.getFacing() == BlockFace.NORTH) { // Stem
box.add(new HexCollisionBox(5.0D, 0.0D, 9.0D, 11.0D, 15.0D, 15.0D));
@@ -653,7 +656,7 @@ public enum HitboxData {
}
} else {
// Via replacement - 4 sided vine
return new ComplexCollisionBox(
return new ComplexCollisionBox(4,
new HexCollisionBox(0.0D, 0.0D, 0.0D, 1.0D, 16.0D, 16.0D),
new HexCollisionBox(15.0D, 0.0D, 0.0D, 16.0D, 16.0D, 16.0D),
new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 16.0D, 1.0D),
@@ -31,7 +31,7 @@ public class DynamicChorusPlant implements CollisionFactory {
float f = 0.5F - (float) 0.3125;
float f1 = 0.5F + (float) 0.3125;
SimpleCollisionBox baseShape = new SimpleCollisionBox(f, f, f, f1, f1, f1, false);
CollisionBox[] avoxelshape = new CollisionBox[directions.length];
SimpleCollisionBox[] avoxelshape = new SimpleCollisionBox[directions.length];
for (int i = 0; i < directions.length; ++i) {
BlockFace direction = directions[i];
@@ -41,7 +41,7 @@ public class DynamicChorusPlant implements CollisionFactory {
CollisionBox[] avoxelshape1 = new CollisionBox[64];
for (int k = 0; k < 64; ++k) {
ComplexCollisionBox directionalShape = new ComplexCollisionBox(baseShape);
ComplexCollisionBox directionalShape = new ComplexCollisionBox(7, baseShape); // how big is this one??
for (int j = 0; j < directions.length; ++j) {
if ((k & 1 << j) != 0) {
@@ -1,10 +1,7 @@
package ac.grim.grimac.utils.collisions.blocks;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.collisions.datatypes.CollisionBox;
import ac.grim.grimac.utils.collisions.datatypes.CollisionFactory;
import ac.grim.grimac.utils.collisions.datatypes.ComplexCollisionBox;
import ac.grim.grimac.utils.collisions.datatypes.HexCollisionBox;
import ac.grim.grimac.utils.collisions.datatypes.*;
import ac.grim.grimac.utils.nmsutil.Materials;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
@@ -18,16 +15,16 @@ import com.github.retrooper.packetevents.protocol.world.states.enums.Shape;
import java.util.stream.IntStream;
public class DynamicStair implements CollisionFactory {
protected static final CollisionBox TOP_AABB = new HexCollisionBox(0, 8, 0, 16, 16, 16);
protected static final CollisionBox BOTTOM_AABB = new HexCollisionBox(0, 0, 0, 16, 8, 16);
protected static final CollisionBox OCTET_NNN = new HexCollisionBox(0.0D, 0.0D, 0.0D, 8.0D, 8.0D, 8.0D);
protected static final CollisionBox OCTET_NNP = new HexCollisionBox(0.0D, 0.0D, 8.0D, 8.0D, 8.0D, 16.0D);
protected static final CollisionBox OCTET_NPN = new HexCollisionBox(0.0D, 8.0D, 0.0D, 8.0D, 16.0D, 8.0D);
protected static final CollisionBox OCTET_NPP = new HexCollisionBox(0.0D, 8.0D, 8.0D, 8.0D, 16.0D, 16.0D);
protected static final CollisionBox OCTET_PNN = new HexCollisionBox(8.0D, 0.0D, 0.0D, 16.0D, 8.0D, 8.0D);
protected static final CollisionBox OCTET_PNP = new HexCollisionBox(8.0D, 0.0D, 8.0D, 16.0D, 8.0D, 16.0D);
protected static final CollisionBox OCTET_PPN = new HexCollisionBox(8.0D, 8.0D, 0.0D, 16.0D, 16.0D, 8.0D);
protected static final CollisionBox OCTET_PPP = new HexCollisionBox(8.0D, 8.0D, 8.0D, 16.0D, 16.0D, 16.0D);
protected static final SimpleCollisionBox TOP_AABB = new HexCollisionBox(0, 8, 0, 16, 16, 16);
protected static final SimpleCollisionBox BOTTOM_AABB = new HexCollisionBox(0, 0, 0, 16, 8, 16);
protected static final SimpleCollisionBox OCTET_NNN = new HexCollisionBox(0.0D, 0.0D, 0.0D, 8.0D, 8.0D, 8.0D);
protected static final SimpleCollisionBox OCTET_NNP = new HexCollisionBox(0.0D, 0.0D, 8.0D, 8.0D, 8.0D, 16.0D);
protected static final SimpleCollisionBox OCTET_NPN = new HexCollisionBox(0.0D, 8.0D, 0.0D, 8.0D, 16.0D, 8.0D);
protected static final SimpleCollisionBox OCTET_NPP = new HexCollisionBox(0.0D, 8.0D, 8.0D, 8.0D, 16.0D, 16.0D);
protected static final SimpleCollisionBox OCTET_PNN = new HexCollisionBox(8.0D, 0.0D, 0.0D, 16.0D, 8.0D, 8.0D);
protected static final SimpleCollisionBox OCTET_PNP = new HexCollisionBox(8.0D, 0.0D, 8.0D, 16.0D, 8.0D, 16.0D);
protected static final SimpleCollisionBox OCTET_PPN = new HexCollisionBox(8.0D, 8.0D, 0.0D, 16.0D, 16.0D, 8.0D);
protected static final SimpleCollisionBox OCTET_PPP = new HexCollisionBox(8.0D, 8.0D, 8.0D, 16.0D, 16.0D, 16.0D);
protected static final CollisionBox[] TOP_SHAPES = makeShapes(TOP_AABB, OCTET_NNN, OCTET_PNN, OCTET_NNP, OCTET_PNP);
protected static final CollisionBox[] BOTTOM_SHAPES = makeShapes(BOTTOM_AABB, OCTET_NPN, OCTET_PPN, OCTET_NPP, OCTET_PPP);
private static final int[] SHAPE_BY_STATE = new int[]{12, 5, 3, 10, 14, 13, 7, 11, 13, 7, 11, 14, 8, 4, 1, 2, 4, 1, 2, 8};
@@ -85,12 +82,12 @@ public class DynamicStair implements CollisionFactory {
};
}
private static CollisionBox[] makeShapes(CollisionBox p_199779_0_, CollisionBox p_199779_1_, CollisionBox p_199779_2_, CollisionBox p_199779_3_, CollisionBox p_199779_4_) {
private static CollisionBox[] makeShapes(SimpleCollisionBox p_199779_0_, SimpleCollisionBox p_199779_1_, SimpleCollisionBox p_199779_2_, SimpleCollisionBox p_199779_3_, SimpleCollisionBox p_199779_4_) {
return IntStream.range(0, 16).mapToObj((p_199780_5_) -> makeStairShape(p_199780_5_, p_199779_0_, p_199779_1_, p_199779_2_, p_199779_3_, p_199779_4_)).toArray(CollisionBox[]::new);
}
private static CollisionBox makeStairShape(int p_199781_0_, CollisionBox p_199781_1_, CollisionBox p_199781_2_, CollisionBox p_199781_3_, CollisionBox p_199781_4_, CollisionBox p_199781_5_) {
ComplexCollisionBox voxelshape = new ComplexCollisionBox(p_199781_1_);
private static CollisionBox makeStairShape(int p_199781_0_, SimpleCollisionBox p_199781_1_, SimpleCollisionBox p_199781_2_, SimpleCollisionBox p_199781_3_, SimpleCollisionBox p_199781_4_, SimpleCollisionBox p_199781_5_) {
ComplexCollisionBox voxelshape = new ComplexCollisionBox(5, p_199781_1_); // can we do better than 5?
if ((p_199781_0_ & 1) != 0) {
voxelshape.add(p_199781_2_);
}
@@ -39,33 +39,41 @@ public class PistonHeadCollision implements CollisionFactory {
return switch (block.getFacing()) {
case UP -> new ComplexCollisionBox(new HexCollisionBox(0, 12, 0, 16, 16, 16),
case UP -> new ComplexCollisionBox(2,
new HexCollisionBox(0, 12, 0, 16, 16, 16),
new HexCollisionBox(6, 0 - longAmount, 6, 10, 12, 10));
case NORTH -> new ComplexCollisionBox(new HexCollisionBox(0, 0, 0, 16, 16, 4),
case NORTH -> new ComplexCollisionBox(2,
new HexCollisionBox(0, 0, 0, 16, 16, 4),
new HexCollisionBox(6, 6, 4, 10, 10, 16 + longAmount));
case SOUTH -> {
// SOUTH piston is glitched in 1.7 and 1.8, fixed in 1.9
// Don't bother with short piston boxes as 1.7/1.8 clients don't have them
if (version.isOlderThanOrEquals(ClientVersion.V_1_8))
yield new ComplexCollisionBox(new HexCollisionBox(0, 0, 12, 16, 16, 16),
yield new ComplexCollisionBox(2,
new HexCollisionBox(0, 0, 12, 16, 16, 16),
new HexCollisionBox(4, 6, 0, 12, 10, 12));
yield new ComplexCollisionBox(new HexCollisionBox(0, 0, 12, 16, 16, 16),
yield new ComplexCollisionBox(2,
new HexCollisionBox(0, 0, 12, 16, 16, 16),
new HexCollisionBox(6, 6, 0 - longAmount, 10, 10, 12));
}
case WEST -> {
// WEST piston is glitched in 1.7 and 1.8, fixed in 1.9
// Don't bother with short piston boxes as 1.7/1.8 clients don't have them
if (version.isOlderThanOrEquals(ClientVersion.V_1_8))
yield new ComplexCollisionBox(new HexCollisionBox(0, 0, 0, 4, 16, 16),
yield new ComplexCollisionBox(2,
new HexCollisionBox(0, 0, 0, 4, 16, 16),
new HexCollisionBox(6, 4, 4, 10, 12, 16));
yield new ComplexCollisionBox(new HexCollisionBox(0, 0, 0, 4, 16, 16),
yield new ComplexCollisionBox(2,
new HexCollisionBox(0, 0, 0, 4, 16, 16),
new HexCollisionBox(4, 6, 6, 16 + longAmount, 10, 10));
}
case EAST -> new ComplexCollisionBox(new HexCollisionBox(12, 0, 0, 16, 16, 16),
case EAST -> new ComplexCollisionBox(2,
new HexCollisionBox(12, 0, 0, 16, 16, 16),
new HexCollisionBox(0 - longAmount, 6, 4, 12, 10, 12));
default -> new ComplexCollisionBox(new HexCollisionBox(0, 0, 0, 16, 4, 16),
default -> new ComplexCollisionBox(2,
new HexCollisionBox(0, 0, 0, 16, 4, 16),
new HexCollisionBox(6, 4, 6, 10, 16 + longAmount, 10));
};
}
@@ -18,7 +18,7 @@ import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
public class DynamicCollisionFence extends DynamicConnecting implements CollisionFactory {
private static final CollisionBox[] COLLISION_BOXES = makeShapes(2.0F, 2.0F, 24.0F, 0.0F, 24.0F, true);
private static final CollisionBox[] COLLISION_BOXES = makeShapes(2.0F, 2.0F, 24.0F, 0.0F, 24.0F, true, 1);
@Override
public CollisionBox fetch(GrimPlayer player, ClientVersion version, WrappedBlockState block, int x, int y, int z) {
@@ -21,7 +21,7 @@ import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
public class DynamicCollisionPane extends DynamicConnecting implements CollisionFactory {
private static final CollisionBox[] COLLISION_BOXES = makeShapes(1.0F, 1.0F, 16.0F, 0.0F, 16.0F, true);
private static final CollisionBox[] COLLISION_BOXES = makeShapes(1.0F, 1.0F, 16.0F, 0.0F, 16.0F, true, 1);
@Override
public CollisionBox fetch(GrimPlayer player, ClientVersion version, WrappedBlockState block, int x, int y, int z) {
@@ -52,7 +52,7 @@ public class DynamicCollisionPane extends DynamicConnecting implements Collision
if (version.isNewerThanOrEquals(ClientVersion.V_1_9)) {
return COLLISION_BOXES[getAABBIndex(north, east, south, west)].copy();
} else { // 1.8 and below clients have pane bounding boxes one pixel less
ComplexCollisionBox boxes = new ComplexCollisionBox();
ComplexCollisionBox boxes = new ComplexCollisionBox(2);
if ((!west || !east) && (west || east || north || south)) {
if (west) {
boxes.add(new SimpleCollisionBox(0.0F, 0.0F, 0.4375F, 0.5F, 1.0F, 0.5625F));
@@ -16,10 +16,9 @@ import com.github.retrooper.packetevents.protocol.world.states.enums.West;
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
public class DynamicCollisionWall extends DynamicConnecting implements CollisionFactory {
public static final CollisionBox[] BOXES = makeShapes(4.0F, 3.0F, 16.0F, 0.0F, 16.0F, false);
// https://bugs.mojang.com/browse/MC-9565
// https://bugs.mojang.com/browse/MC-94016
private static final CollisionBox[] COLLISION_BOXES = makeShapes(4.0F, 3.0F, 24.0F, 0.0F, 24.0F, false);
private static final CollisionBox[] COLLISION_BOXES = makeShapes(4.0F, 3.0F, 24.0F, 0.0F, 24.0F, false, 1);
/**
* @deprecated use DynamicHitboxWall
@@ -53,12 +52,11 @@ public class DynamicCollisionWall extends DynamicConnecting implements Collision
// On 1.13+ clients the bounding box is much more complicated
if (version.isNewerThanOrEquals(ClientVersion.V_1_13)) {
ComplexCollisionBox box = new ComplexCollisionBox();
ComplexCollisionBox box = new ComplexCollisionBox(5);
// Proper and faster way would be to compute all this beforehand
if (up == 1) {
box.add(new HexCollisionBox(4, 0, 4, 12, 16, 12));
return box;
}
if (north == 1) {
@@ -81,6 +79,7 @@ public class DynamicCollisionWall extends DynamicConnecting implements Collision
} else if (east == 2) {
box.add(new HexCollisionBox(5, 0, 5, 16, 16, 11));
}
return box;
}
// Magic 1.8 code for walls that I copied over, 1.12 below uses this mess
@@ -143,9 +142,7 @@ public class DynamicCollisionWall extends DynamicConnecting implements Collision
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_13)) {
// Proper and faster way would be to compute all this beforehand
if (up) {
ComplexCollisionBox box = new ComplexCollisionBox(COLLISION_BOXES[getAABBIndex(north, east, south, west)].copy());
box.add(new HexCollisionBox(4, 0, 4, 12, 24, 12));
return box;
return COLLISION_BOXES[getAABBIndex(north, east, south, west)].copy().union(new HexCollisionBox(4, 0, 4, 12, 24, 12));
}
return COLLISION_BOXES[getAABBIndex(north, east, south, west)].copy();
@@ -18,7 +18,7 @@ import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
public class DynamicConnecting {
public static CollisionBox[] makeShapes(float p_196408_1_, float p_196408_2_, float p_196408_3_, float p_196408_4_, float p_196408_5_, boolean includeCenter) {
public static CollisionBox[] makeShapes(float p_196408_1_, float p_196408_2_, float p_196408_3_, float p_196408_4_, float p_196408_5_, boolean includeCenter, int additionalMaxIndex) {
float middleMin = 8.0F - p_196408_1_;
float middleMax = 8.0F + p_196408_1_;
float f2 = 8.0F - p_196408_2_;
@@ -29,14 +29,21 @@ public class DynamicConnecting {
SimpleCollisionBox voxelshape3 = new HexCollisionBox(0.0D, p_196408_4_, f2, f3, p_196408_5_, f3);
SimpleCollisionBox voxelshape4 = new HexCollisionBox(f2, p_196408_4_, f2, 16.0D, p_196408_5_, f3);
ComplexCollisionBox voxelshape5 = new ComplexCollisionBox(voxelshape1, voxelshape4);
ComplexCollisionBox voxelshape6 = new ComplexCollisionBox(voxelshape2, voxelshape3);
ComplexCollisionBox voxelshape5 = new ComplexCollisionBox(2 + additionalMaxIndex, voxelshape1, voxelshape4);
ComplexCollisionBox voxelshape6 = new ComplexCollisionBox(2 + additionalMaxIndex, voxelshape2, voxelshape3);
CollisionBox[] avoxelshape = new CollisionBox[]{NoCollisionBox.INSTANCE, voxelshape2, voxelshape3, voxelshape6, voxelshape1, new ComplexCollisionBox(voxelshape2, voxelshape1), new ComplexCollisionBox(voxelshape3, voxelshape1), new ComplexCollisionBox(voxelshape6, voxelshape1), voxelshape4, new ComplexCollisionBox(voxelshape2, voxelshape4), new ComplexCollisionBox(voxelshape3, voxelshape4), new ComplexCollisionBox(voxelshape6, voxelshape4), voxelshape5, new ComplexCollisionBox(voxelshape2, voxelshape5), new ComplexCollisionBox(voxelshape3, voxelshape5), new ComplexCollisionBox(voxelshape6, voxelshape5)};
CollisionBox[] avoxelshape = new CollisionBox[]{
NoCollisionBox.INSTANCE, voxelshape2, voxelshape3, voxelshape6, voxelshape1,
new ComplexCollisionBox(2 + additionalMaxIndex, voxelshape2, voxelshape1), new ComplexCollisionBox(2 + additionalMaxIndex, voxelshape3, voxelshape1),
new ComplexCollisionBox(3 + additionalMaxIndex, voxelshape2, voxelshape3, voxelshape1), voxelshape4,
new ComplexCollisionBox(2 + additionalMaxIndex, voxelshape2, voxelshape4), new ComplexCollisionBox(2 + additionalMaxIndex, voxelshape3, voxelshape4),
new ComplexCollisionBox(3 + additionalMaxIndex, voxelshape2, voxelshape3, voxelshape4), voxelshape5,
new ComplexCollisionBox(3 + additionalMaxIndex, voxelshape2, voxelshape1, voxelshape4), new ComplexCollisionBox(3 + additionalMaxIndex, voxelshape3, voxelshape1, voxelshape4),
new ComplexCollisionBox(4 + additionalMaxIndex, voxelshape1, voxelshape2, voxelshape3, voxelshape4)};
if (includeCenter) {
for (int i = 0; i < 16; ++i) {
avoxelshape[i] = new ComplexCollisionBox(up, avoxelshape[i]);
avoxelshape[i] = avoxelshape[i].union(up);
}
}
@@ -16,27 +16,30 @@ import com.github.retrooper.packetevents.protocol.world.states.enums.*;
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import java.util.ArrayList;
import java.util.List;
public class DynamicHitboxFence extends DynamicConnecting implements HitBoxFactory {
private static final CollisionBox[] MODERN_HITBOXES = makeShapes(2.0F, 2.0F, 24.0F, 0.0F, 24.0F, true);
private static final CollisionBox[] MODERN_HITBOXES = makeShapes(2.0F, 2.0F, 24.0F, 0.0F, 24.0F, true, 1);
public static SimpleCollisionBox[] LEGACY_HITBOXES = new SimpleCollisionBox[] {new SimpleCollisionBox(0.375D, 0.0D, 0.375D, 0.625D, 1.0D, 0.625D), new SimpleCollisionBox(0.375D, 0.0D, 0.375D, 0.625D, 1.0D, 1.0D), new SimpleCollisionBox(0.0D, 0.0D, 0.375D, 0.625D, 1.0D, 0.625D), new SimpleCollisionBox(0.0D, 0.0D, 0.375D, 0.625D, 1.0D, 1.0D), new SimpleCollisionBox(0.375D, 0.0D, 0.0D, 0.625D, 1.0D, 0.625D), new SimpleCollisionBox(0.375D, 0.0D, 0.0D, 0.625D, 1.0D, 1.0D), new SimpleCollisionBox(0.0D, 0.0D, 0.0D, 0.625D, 1.0D, 0.625D), new SimpleCollisionBox(0.0D, 0.0D, 0.0D, 0.625D, 1.0D, 1.0D), new SimpleCollisionBox(0.375D, 0.0D, 0.375D, 1.0D, 1.0D, 0.625D), new SimpleCollisionBox(0.375D, 0.0D, 0.375D, 1.0D, 1.0D, 1.0D), new SimpleCollisionBox(0.0D, 0.0D, 0.375D, 1.0D, 1.0D, 0.625D), new SimpleCollisionBox(0.0D, 0.0D, 0.375D, 1.0D, 1.0D, 1.0D), new SimpleCollisionBox(0.375D, 0.0D, 0.0D, 1.0D, 1.0D, 0.625D), new SimpleCollisionBox(0.375D, 0.0D, 0.0D, 1.0D, 1.0D, 1.0D), new SimpleCollisionBox(0.0D, 0.0D, 0.0D, 1.0D, 1.0D, 0.625D), new SimpleCollisionBox(0.0D, 0.0D, 0.0D, 1.0D, 1.0D, 1.0D)};
static {
for (int i = 0; i < MODERN_HITBOXES.length; i++) {
CollisionBox collisionBox = MODERN_HITBOXES[i];
List<SimpleCollisionBox> boxes = new ArrayList<>();
collisionBox.downCast(boxes);
// no ComplexCollisionBox produced by makeShapes is every larger than 5 SimpleCollisionBoxes
private static final int MAX_MODERN_HITBOX_COMPLEX_COLLISION_BOX_SIZE = 5;
for (SimpleCollisionBox box : boxes) {
if (box.maxY > 1) {
box.maxY = 1;
static {
SimpleCollisionBox[] boxes = new SimpleCollisionBox[MAX_MODERN_HITBOX_COMPLEX_COLLISION_BOX_SIZE];
// we start from one because MODERN_HITBOXES[0] is a NoCollisionBox
for (int i = 1; i < MODERN_HITBOXES.length; i++) {
CollisionBox collisionBox = MODERN_HITBOXES[i];
int size = collisionBox.downCast(boxes);
for (int j = 0; j < size; j++) {
if (boxes[j].maxY > 1) {
boxes[j].maxY = 1;
}
}
MODERN_HITBOXES[i] = new ComplexCollisionBox(boxes.toArray(new SimpleCollisionBox[0]));
MODERN_HITBOXES[i] = size == 1 ? boxes[0] : new ComplexCollisionBox(size, boxes);
}
}
@@ -15,7 +15,7 @@ import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
public class DynamicHitboxPane extends DynamicConnecting implements HitBoxFactory {
private static final CollisionBox[] COLLISION_BOXES = makeShapes(1.0F, 1.0F, 16.0F, 0.0F, 16.0F, true);
private static final CollisionBox[] COLLISION_BOXES = makeShapes(1.0F, 1.0F, 16.0F, 0.0F, 16.0F, true, 1);
@Override
public CollisionBox fetch(GrimPlayer player, StateType item, ClientVersion version, WrappedBlockState block, int x, int y, int z) {
@@ -13,8 +13,6 @@ import com.github.retrooper.packetevents.protocol.world.states.enums.*;
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
public class DynamicHitboxWall extends DynamicConnecting implements HitBoxFactory {
private static final CollisionBox[] HIT_BOXES = makeShapes(4.0F, 3.0F, 16.0F, 0.0F, 16.0F, false);
@Override
public CollisionBox fetch(GrimPlayer player, StateType heldItem, ClientVersion version, WrappedBlockState state, int x, int y, int z) {
int[] connections = getConnections(player, version, state, x, y, z);
@@ -60,7 +58,7 @@ public class DynamicHitboxWall extends DynamicConnecting implements HitBoxFactor
}
private CollisionBox getModernHitBox(int north, int south, int west, int east, int up) {
ComplexCollisionBox box = new ComplexCollisionBox();
ComplexCollisionBox box = new ComplexCollisionBox(5);
if (up == 1) {
box.add(new HexCollisionBox(4, 0, 4, 12, 16, 12));
}
@@ -17,6 +17,13 @@ public interface CollisionBox {
void downCast(List<SimpleCollisionBox> list);
/**
* @param list - A list that will contain all of the SimpleCollisionBoxes representing the CollisionBox.
* @return - int representing the size of elements in the array that belong to this downcast.
* The contents of elements starting from list[size] and above are undefined and should not be iterated over.
*/
int downCast(SimpleCollisionBox[] list);
boolean isNull();
boolean isFullBlock();
@@ -1,19 +1,33 @@
package ac.grim.grimac.utils.collisions.datatypes;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Arrays;
import java.util.List;
public class ComplexCollisionBox implements CollisionBox {
private final List<CollisionBox> boxes = new ArrayList<>();
// Most complex shape is the Modern MC Cauldron which is made up of 15 boxes
public static int DEFAULT_MAX_COLLISION_BOX_SIZE = 15; // increase if we somehow have a shape made of more than 15 parts.
private final SimpleCollisionBox[] boxes;
private int currentLength;
public ComplexCollisionBox(CollisionBox... boxes) {
Collections.addAll(this.boxes, boxes);
public ComplexCollisionBox(SimpleCollisionBox... boxes) {
this(DEFAULT_MAX_COLLISION_BOX_SIZE, boxes);
}
public boolean add(CollisionBox collisionBox) {
return boxes.add(collisionBox);
public ComplexCollisionBox(int maxIndex) {
this.boxes = new SimpleCollisionBox[maxIndex];
}
public ComplexCollisionBox(int maxIndex, SimpleCollisionBox... boxes) {
this.boxes = new SimpleCollisionBox[maxIndex];
System.arraycopy(boxes, 0, this.boxes, 0, Math.min(maxIndex, boxes.length));
currentLength = boxes.length;
}
public boolean add(SimpleCollisionBox collisionBox) {
boxes[currentLength] = collisionBox;
currentLength++;
return currentLength <= boxes.length;
}
@Override
@@ -24,47 +38,54 @@ public class ComplexCollisionBox implements CollisionBox {
@Override
public boolean isCollided(SimpleCollisionBox other) {
for (CollisionBox box : boxes) {
if (box.isCollided(other)) return true;
for (int i = 0; i < currentLength; i++) {
if (boxes[i].isCollided(other)) return true;
}
return false;
}
@Override
public boolean isIntersected(SimpleCollisionBox other) {
for (CollisionBox box : boxes) {
if (box.isIntersected(other))
return true;
for (int i = 0; i < currentLength; i++) {
if (boxes[i].isIntersected(other)) return true;
}
return false;
}
@Override
public CollisionBox copy() {
ComplexCollisionBox cc = new ComplexCollisionBox();
for (CollisionBox b : boxes)
cc.boxes.add(b.copy());
return cc;
ComplexCollisionBox copy = new ComplexCollisionBox(boxes.length);
for (int i = 0; i < currentLength; i++) {
copy.boxes[i] = boxes[i].copy();
}
copy.currentLength = this.currentLength;
return copy;
}
@Override
public CollisionBox offset(double x, double y, double z) {
for (CollisionBox b : boxes)
b.offset(x, y, z);
for (int i = 0; i < currentLength; i++) {
boxes[i].offset(x, y ,z);
}
return this;
}
@Override
public void downCast(List<SimpleCollisionBox> list) {
for (CollisionBox box : boxes)
box.downCast(list);
list.addAll(Arrays.asList(boxes).subList(0, currentLength));
}
@Override
public int downCast(SimpleCollisionBox[] list) {
System.arraycopy(boxes, 0, list, 0, currentLength);
return currentLength;
}
@Override
public boolean isNull() {
for (CollisionBox box : boxes)
if (!box.isNull())
return false;
for (int i = 0; i < currentLength; i++) {
if (!boxes[i].isNull()) return false;
}
return true;
}
@@ -52,6 +52,11 @@ public class DynamicCollisionBox implements CollisionBox {
return this;
}
@Override
public int downCast(SimpleCollisionBox[] list) {
return box.fetch(player, version, block, x, y, z).offset(x, y, z).downCast(list);
}
@Override
public void downCast(List<SimpleCollisionBox> list) {
box.fetch(player, version, block, x, y, z).offset(x, y, z).downCast(list);
@@ -32,6 +32,9 @@ public class NoCollisionBox implements CollisionBox {
@Override
public void downCast(List<SimpleCollisionBox> list) { /**/ }
@Override
public int downCast(SimpleCollisionBox[] list) { return 0; }
@Override
public boolean isNull() {
return true;
@@ -10,7 +10,6 @@ import it.unimi.dsi.fastutil.doubles.DoubleList;
import org.bukkit.Location;
import org.bukkit.util.Vector;
import java.util.ArrayList;
import java.util.List;
public class SimpleCollisionBox implements CollisionBox {
@@ -20,6 +19,8 @@ public class SimpleCollisionBox implements CollisionBox {
public double minX, minY, minZ, maxX, maxY, maxZ;
private boolean isFullBlock = false;
SimpleCollisionBox[] boxes = new SimpleCollisionBox[ComplexCollisionBox.DEFAULT_MAX_COLLISION_BOX_SIZE];
public SimpleCollisionBox() {
this(0, 0, 0, 0, 0, 0, false);
}
@@ -233,11 +234,10 @@ public class SimpleCollisionBox implements CollisionBox {
return isIntersected((SimpleCollisionBox) other);
}
List<SimpleCollisionBox> boxes = new ArrayList<>();
other.downCast(boxes);
int size = other.downCast(boxes);
for (SimpleCollisionBox box : boxes) {
if (isIntersected(box)) return true;
for (int i = 0; i < size; i++) {
if (isIntersected(boxes[i])) return true;
}
return false;
@@ -268,6 +268,12 @@ public class SimpleCollisionBox implements CollisionBox {
list.add(this);
}
@Override
public int downCast(SimpleCollisionBox[] list) {
list[0] = this;
return 1;
}
@Override
public boolean isNull() {
return false;
@@ -32,7 +32,6 @@ import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import lombok.Getter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.OptionalInt;
@@ -4,8 +4,6 @@ import ac.grim.grimac.utils.data.Pair;
import it.unimi.dsi.fastutil.doubles.Double2IntMap;
import it.unimi.dsi.fastutil.doubles.Double2IntOpenHashMap;
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;