Compare commits
22
Commits
simd
...
los-containers
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e4afe412a5 | ||
|
|
45f5b5060c | ||
|
|
a6af4cbbd9 | ||
|
|
e76a59f14a | ||
|
|
ea2673541c | ||
|
|
0193d342e0 | ||
|
|
0a1881592a | ||
|
|
fcfb5d0cbb | ||
|
|
a8fc80dd50 | ||
|
|
8805899f39 | ||
|
|
5dc6d47dd0 | ||
|
|
4450bd5c5d | ||
|
|
45faec8290 | ||
|
|
a19a70813c | ||
|
|
34582ffe50 | ||
|
|
0d4c1ed81e | ||
|
|
e1d739be1b | ||
|
|
2c72efd3ea | ||
|
|
270f160dd2 | ||
|
|
b026f494d8 | ||
|
|
8a690e2423 | ||
|
|
08678e4252 |
No files matched your search
@@ -5,8 +5,10 @@ import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.BlockPlaceCheck;
|
||||
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.RaycastData;
|
||||
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
|
||||
import ac.grim.grimac.utils.data.Pair;
|
||||
import ac.grim.grimac.utils.data.HitData;
|
||||
import ac.grim.grimac.utils.nmsutil.BlockRayTrace;
|
||||
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
@@ -14,8 +16,11 @@ import com.github.retrooper.packetevents.protocol.player.GameMode;
|
||||
import com.github.retrooper.packetevents.protocol.world.BlockFace;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
|
||||
import com.github.retrooper.packetevents.util.Vector3i;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
@CheckData(name = "LineOfSightPlace")
|
||||
public class LineOfSightPlace extends BlockPlaceCheck {
|
||||
@@ -66,7 +71,6 @@ public class LineOfSightPlace extends BlockPlaceCheck {
|
||||
|
||||
private boolean checkIfShouldSkip(BlockPlace place) {
|
||||
StateType targetBlockStateType = player.compensatedWorld.getWrappedBlockStateAt(place.getPlacedAgainstBlockLocation()).getType();
|
||||
if (place.getMaterial() == StateTypes.SCAFFOLDING) return true; // Scaffolding
|
||||
if (player.gamemode == GameMode.SPECTATOR) return true; // A waste to check creative mode players
|
||||
if (targetBlockStateType == StateTypes.REDSTONE_WIRE) return true; // Redstone too buggy
|
||||
if (player.compensatedWorld.isNearHardEntity(player.boundingBox.copy().expand(4))) return true; // Shulkers and Pistons are too buggy
|
||||
@@ -168,10 +172,12 @@ public class LineOfSightPlace extends BlockPlaceCheck {
|
||||
result[2] = xz * player.trigHandler.cos(rotX);
|
||||
}
|
||||
|
||||
private boolean getTargetBlock(double[] eyePosition, double[] eyeDirection, double maxDistance, int[] targetBlockVec, BlockFace expectedBlockFace) {
|
||||
Pair<int[], BlockFace> hitData = BlockRayTrace.getNearestReachHitResult(player, eyePosition, eyeDirection, maxDistance, maxDistance, targetBlockVec, expectedBlockFace);
|
||||
private boolean getTargetBlock(double[] eyePos, double[] eyeDir, double maxDistance, int[] targetBlockVec, BlockFace expectedBlockFace) {
|
||||
HitData hitData = BlockRayTrace.getNearestReachHitResult(player, eyePos, eyeDir, maxDistance, maxDistance, targetBlockVec, false);
|
||||
|
||||
|
||||
// we check for hitdata != null because of being in expanded hitbox, or there was no result, do we still need this?
|
||||
return hitData != null && Arrays.equals(targetBlockVec, hitData.getFirst()) && hitData.getSecond() == expectedBlockFace;
|
||||
return hitData != null && new Vector3i(targetBlockVec[0], targetBlockVec[1], targetBlockVec[2]).equals(hitData.getPosition()) && hitData.getClosestDirection() == expectedBlockFace;
|
||||
}
|
||||
|
||||
private boolean isBlockTypeWhitelisted(StateType type) {
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.viaversion.viaversion.api.Via;
|
||||
import io.github.retrooper.packetevents.util.viaversion.ViaVersionUtil;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
// Warning for major game updates!
|
||||
// Do not use an enum for stuff like Axis and other data types not in 1.7
|
||||
@@ -193,8 +194,6 @@ public enum CollisionData {
|
||||
}
|
||||
}, StateTypes.PIGLIN_WALL_HEAD),
|
||||
|
||||
CORAL_FAN(new HexCollisionBox(2.0D, 0.0D, 2.0D, 14.0D, 4.0D, 14.0D), BlockTags.CORALS.getStates().toArray(new StateType[0])),
|
||||
|
||||
DOOR(new DoorHandler(), BlockTags.DOORS.getStates().toArray(new StateType[0])),
|
||||
|
||||
HOPPER((player, version, data, x, y, z) -> {
|
||||
@@ -259,6 +258,8 @@ public enum CollisionData {
|
||||
return new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 9.0D, 16.0D);
|
||||
}, StateTypes.STONECUTTER),
|
||||
|
||||
CORAL_FAN(NoCollisionBox.INSTANCE, BlockTags.CORALS.getStates().toArray(new StateType[0])),
|
||||
|
||||
RAILS(NoCollisionBox.INSTANCE, BlockTags.RAILS.getStates().toArray(new StateType[0])),
|
||||
|
||||
BANNER(NoCollisionBox.INSTANCE, BlockTags.BANNERS.getStates().toArray(new StateType[0])),
|
||||
@@ -409,33 +410,6 @@ public enum CollisionData {
|
||||
return new HexCollisionBox(1.0D, 0.0D, 1.0D, 15.0D, 15.0D, 15.0D); // post
|
||||
}, StateTypes.HONEY_BLOCK),
|
||||
|
||||
SPORE_BLOSSOM(new HexCollisionBox(2.0D, 13.0D, 2.0D, 14.0D, 16.0D, 14.0D), StateTypes.SPORE_BLOSSOM),
|
||||
|
||||
GLOW_LICHEN((player, version, data, x, y, z) -> {
|
||||
ComplexCollisionBox box = new ComplexCollisionBox();
|
||||
|
||||
if (data.isUp()) {
|
||||
box.add(new HexCollisionBox(0.0D, 15.0D, 0.0D, 16.0D, 16.0D, 16.0D));
|
||||
}
|
||||
if (data.isDown()) {
|
||||
box.add(new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 1.0D, 16.0D));
|
||||
}
|
||||
if (data.getWest() == West.TRUE) {
|
||||
box.add(new HexCollisionBox(0.0D, 0.0D, 0.0D, 1.0D, 16.0D, 16.0D));
|
||||
}
|
||||
if (data.getEast() == East.TRUE) {
|
||||
box.add(new HexCollisionBox(15.0D, 0.0D, 0.0D, 16.0D, 16.0D, 16.0D));
|
||||
}
|
||||
if (data.getNorth() == North.TRUE) {
|
||||
box.add(new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 16.0D, 1.0D));
|
||||
}
|
||||
if (data.getSouth() == South.TRUE) {
|
||||
box.add(new HexCollisionBox(0.0D, 0.0D, 15.0D, 16.0D, 16.0D, 16.0D));
|
||||
}
|
||||
|
||||
return box;
|
||||
}, StateTypes.GLOW_LICHEN),
|
||||
|
||||
DRAGON_EGG_BLOCK(new HexCollisionBox(1.0D, 0.0D, 1.0D, 15.0D, 16.0D, 15.0D), StateTypes.DRAGON_EGG),
|
||||
|
||||
GRINDSTONE((player, version, data, x, y, z) -> {
|
||||
@@ -708,17 +682,36 @@ public enum CollisionData {
|
||||
}, StateTypes.END_ROD, StateTypes.LIGHTNING_ROD),
|
||||
|
||||
CAULDRON((player, version, data, x, y, z) -> {
|
||||
double height = 0.25;
|
||||
if (version.isNewerThan(ClientVersion.getById(467))) { // changed in 19w13a, 1.14 Snapshot
|
||||
return new ComplexCollisionBox(
|
||||
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),
|
||||
new SimpleCollisionBox(0.125, 0.0, 0.875, 0.25, 1.0, 1.0, false),
|
||||
new SimpleCollisionBox(0.75, 0.0, 0.0, 1.0, 1.0, 0.125, false),
|
||||
new SimpleCollisionBox(0.75, 0.0, 0.875, 1.0, 1.0, 1.0, false),
|
||||
new SimpleCollisionBox(0.875, 0.0, 0.125, 1.0, 1.0, 0.25, false),
|
||||
new SimpleCollisionBox(0.875, 0.0, 0.75, 1.0, 1.0, 0.875, false),
|
||||
new SimpleCollisionBox(0.0, 0.1875, 0.25, 1.0, 0.25, 0.75, false),
|
||||
new SimpleCollisionBox(0.125, 0.1875, 0.125, 0.875, 0.25, 0.25, false),
|
||||
new SimpleCollisionBox(0.125, 0.1875, 0.75, 0.875, 0.25, 0.875, false),
|
||||
new SimpleCollisionBox(0.25, 0.1875, 0.0, 0.75, 1.0, 0.125, false),
|
||||
new SimpleCollisionBox(0.25, 0.1875, 0.875, 0.75, 1.0, 1.0, false),
|
||||
new SimpleCollisionBox(0.0, 0.25, 0.25, 0.125, 1.0, 0.75, false),
|
||||
new SimpleCollisionBox(0.875, 0.25, 0.25, 1.0, 1.0, 0.75, false)
|
||||
);
|
||||
} else {
|
||||
double height = 0.25;
|
||||
if (version.isOlderThan(ClientVersion.V_1_13))
|
||||
height = 0.3125;
|
||||
|
||||
if (version.isOlderThan(ClientVersion.V_1_13))
|
||||
height = 0.3125;
|
||||
|
||||
return new ComplexCollisionBox(
|
||||
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),
|
||||
new SimpleCollisionBox(0, height, 0, 1, 1, 0.125, false),
|
||||
new SimpleCollisionBox(0, height, 1 - 0.125, 1, 1, 1, false));
|
||||
return new ComplexCollisionBox(
|
||||
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),
|
||||
new SimpleCollisionBox(0, height, 0, 1, 1, 0.125, false),
|
||||
new SimpleCollisionBox(0, height, 1 - 0.125, 1, 1, 1, false));
|
||||
}
|
||||
}, BlockTags.CAULDRONS.getStates().toArray(new StateType[0])),
|
||||
|
||||
CACTUS(new SimpleCollisionBox(0.0625, 0, 0.0625,
|
||||
@@ -791,7 +784,14 @@ public enum CollisionData {
|
||||
|
||||
CORAL_PLANT((player, version, data, x, y, z) -> {
|
||||
return new HexCollisionBox(2.0D, 0.0D, 2.0D, 14.0D, 15.0D, 14.0D);
|
||||
}, BlockTags.CORAL_PLANTS.getStates().toArray(new StateType[0])),
|
||||
}, Stream.concat(
|
||||
Arrays.stream(BlockTags.CORAL_PLANTS.getStates().toArray(new StateType[0])),
|
||||
Stream.of(StateTypes.DEAD_HORN_CORAL, StateTypes.DEAD_TUBE_CORAL, StateTypes.DEAD_BRAIN_CORAL,
|
||||
StateTypes.DEAD_BUBBLE_CORAL, StateTypes.DEAD_FIRE_CORAL)
|
||||
)
|
||||
.distinct() // This will remove duplicates
|
||||
.toArray(StateType[]::new)
|
||||
),
|
||||
|
||||
SIGN(new SimpleCollisionBox(0.25, 0.0, 0.25, 0.75, 1.0, 0.75, false),
|
||||
BlockTags.STANDING_SIGNS.getStates().toArray(new StateType[0])),
|
||||
@@ -889,7 +889,13 @@ public enum CollisionData {
|
||||
|
||||
SCULK_SENSOR(new HexCollisionBox(0.0, 0.0, 0.0, 16.0, 8.0, 16.0), StateTypes.SCULK_SENSOR, StateTypes.CALIBRATED_SCULK_SENSOR),
|
||||
|
||||
DECORATED_POT(new HexCollisionBox(1.0D, 0.0D, 1.0D, 15.0D, 16.0D, 15.0), StateTypes.DECORATED_POT),
|
||||
DECORATED_POT((player, version, data, x, y, z) -> {
|
||||
if (version.isNewerThan(ClientVersion.V_1_19_3)) {
|
||||
return new HexCollisionBox(1.0D, 0.0D, 1.0D, 15.0D, 16.0D, 15.0);
|
||||
} else { // ViaVersion replacement is a Brick
|
||||
return new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true);
|
||||
}
|
||||
}, StateTypes.DECORATED_POT),
|
||||
|
||||
BIG_DRIPLEAF((player, version, data, x, y, z) -> {
|
||||
if (version.isOlderThanOrEquals(ClientVersion.V_1_16_4))
|
||||
@@ -1001,20 +1007,34 @@ public enum CollisionData {
|
||||
}
|
||||
}, StateTypes.MANGROVE_PROPAGULE),
|
||||
|
||||
SCULK_SHRIKER(new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 8.0D, 16.0D), StateTypes.SCULK_SHRIEKER),
|
||||
SCULK_SHRIKER((player, version, data, x, y, z) -> {
|
||||
if (version.isNewerThan(ClientVersion.V_1_18_2)) {
|
||||
return new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 8.0D, 16.0D);
|
||||
} else {
|
||||
return new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true);
|
||||
}
|
||||
}, StateTypes.SCULK_SHRIEKER),
|
||||
|
||||
FROGSPAWN(new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 1.5D, 16.0D), StateTypes.FROGSPAWN),
|
||||
|
||||
SNIFFER_EGG(new HexCollisionBox(1.0D, 0.0D, 2.0D, 15.0D, 16.0D, 14.0D), StateTypes.SNIFFER_EGG),
|
||||
SNIFFER_EGG((player, version, data, x, y, z) -> {
|
||||
if (version.isNewerThan(ClientVersion.V_1_19_4)) {
|
||||
return new HexCollisionBox(1.0D, 0.0D, 2.0D, 15.0D, 16.0D, 14.0D);
|
||||
} else {
|
||||
return new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true);
|
||||
}
|
||||
}, StateTypes.SNIFFER_EGG),
|
||||
|
||||
PITCHER_CROP((player, version, data, x, y, z) -> {
|
||||
final SimpleCollisionBox COLLISION_SHAPE_BULB = new HexCollisionBox(5.0D, -1.0D, 5.0D, 11.0D, 3.0D, 11.0D);
|
||||
final SimpleCollisionBox COLLISION_SHAPE_CROP = new HexCollisionBox(3.0D, -1.0D, 3.0D, 13.0D, 5.0D, 13.0D);
|
||||
if (version.isNewerThan(ClientVersion.V_1_19_4)) {
|
||||
final SimpleCollisionBox COLLISION_SHAPE_BULB = new HexCollisionBox(5.0D, -1.0D, 5.0D, 11.0D, 3.0D, 11.0D);
|
||||
final SimpleCollisionBox COLLISION_SHAPE_CROP = new HexCollisionBox(3.0D, -1.0D, 3.0D, 13.0D, 5.0D, 13.0D);
|
||||
|
||||
if (data.getAge() == 0) {
|
||||
return COLLISION_SHAPE_BULB;
|
||||
if (data.getAge() == 0) {
|
||||
return COLLISION_SHAPE_BULB;
|
||||
} else {
|
||||
return data.getHalf() == Half.LOWER ? COLLISION_SHAPE_CROP : NoCollisionBox.INSTANCE;
|
||||
}
|
||||
} else {
|
||||
return data.getHalf() == Half.LOWER ? COLLISION_SHAPE_CROP : NoCollisionBox.INSTANCE;
|
||||
return NoCollisionBox.INSTANCE;
|
||||
}
|
||||
}, StateTypes.PITCHER_CROP),
|
||||
|
||||
|
||||
@@ -357,15 +357,56 @@ public enum HitboxData {
|
||||
return common;
|
||||
}, StateTypes.LECTERN),
|
||||
|
||||
PITCHER_CROP((player, item, version, data, x, y, z) -> {
|
||||
final SimpleCollisionBox FULL_UPPER_SHAPE = new HexCollisionBox(3.0D, 0.0D, 3.0D, 13.0D, 15.0D, 13.0D);
|
||||
final SimpleCollisionBox FULL_LOWER_SHAPE = new HexCollisionBox(3.0D, -1.0D, 3.0D, 13.0D, 16.0D, 13.0D);
|
||||
final SimpleCollisionBox COLLISION_SHAPE_BULB = new HexCollisionBox(5.0D, -1.0D, 5.0D, 11.0D, 3.0D, 11.0D);
|
||||
final SimpleCollisionBox COLLISION_SHAPE_CROP = new HexCollisionBox(3.0D, -1.0D, 3.0D, 13.0D, 5.0D, 13.0D);
|
||||
final SimpleCollisionBox[] UPPER_SHAPE_BY_AGE = new SimpleCollisionBox[]{new HexCollisionBox(3.0D, 0.0D, 3.0D, 13.0D, 11.0D, 13.0D), FULL_UPPER_SHAPE};
|
||||
final SimpleCollisionBox[] LOWER_SHAPE_BY_AGE = new SimpleCollisionBox[]{COLLISION_SHAPE_BULB, new HexCollisionBox(3.0D, -1.0D, 3.0D, 13.0D, 14.0D, 13.0D), FULL_LOWER_SHAPE, FULL_LOWER_SHAPE, FULL_LOWER_SHAPE};
|
||||
GLOW_LICHEN_SCULK_VEIN((player, item, version, data, x, y, z) -> {
|
||||
if (version.isNewerThan(ClientVersion.V_1_16_4)) {
|
||||
ComplexCollisionBox box = new ComplexCollisionBox();
|
||||
|
||||
return data.getHalf() == Half.UPPER ? UPPER_SHAPE_BY_AGE[Math.min(Math.abs(4 - (data.getAge() + 1)), UPPER_SHAPE_BY_AGE.length - 1)] : LOWER_SHAPE_BY_AGE[data.getAge()];
|
||||
if (data.isUp()) {
|
||||
box.add(new HexCollisionBox(0.0D, 15.0D, 0.0D, 16.0D, 16.0D, 16.0D));
|
||||
}
|
||||
if (data.isDown()) {
|
||||
box.add(new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 1.0D, 16.0D));
|
||||
}
|
||||
if (data.getWest() == West.TRUE) {
|
||||
box.add(new HexCollisionBox(0.0D, 0.0D, 0.0D, 1.0D, 16.0D, 16.0D));
|
||||
}
|
||||
if (data.getEast() == East.TRUE) {
|
||||
box.add(new HexCollisionBox(15.0D, 0.0D, 0.0D, 16.0D, 16.0D, 16.0D));
|
||||
}
|
||||
if (data.getNorth() == North.TRUE) {
|
||||
box.add(new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 16.0D, 1.0D));
|
||||
}
|
||||
if (data.getSouth() == South.TRUE) {
|
||||
box.add(new HexCollisionBox(0.0D, 0.0D, 15.0D, 16.0D, 16.0D, 16.0D));
|
||||
}
|
||||
|
||||
return box;
|
||||
} else { // ViaVersion just replaces this with... nothing
|
||||
return NoCollisionBox.INSTANCE;
|
||||
}
|
||||
}, StateTypes.GLOW_LICHEN, StateTypes.SCULK_CATALYST),
|
||||
|
||||
SPORE_BLOSSOM((player, item, version, data, x, y, z) -> {
|
||||
if (version.isNewerThan(ClientVersion.V_1_16_4)) {
|
||||
return new HexCollisionBox(2.0D, 13.0D, 2.0D, 14.0D, 16.0D, 14.0D);
|
||||
} else { // ViaVersion replacement is a Peony
|
||||
return new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true);
|
||||
}
|
||||
}, StateTypes.SPORE_BLOSSOM),
|
||||
|
||||
PITCHER_CROP((player, item, version, data, x, y, z) -> {
|
||||
if (version.isNewerThan(ClientVersion.V_1_19_4)) {
|
||||
final SimpleCollisionBox FULL_UPPER_SHAPE = new HexCollisionBox(3.0D, 0.0D, 3.0D, 13.0D, 15.0D, 13.0D);
|
||||
final SimpleCollisionBox FULL_LOWER_SHAPE = new HexCollisionBox(3.0D, -1.0D, 3.0D, 13.0D, 16.0D, 13.0D);
|
||||
final SimpleCollisionBox COLLISION_SHAPE_BULB = new HexCollisionBox(5.0D, -1.0D, 5.0D, 11.0D, 3.0D, 11.0D);
|
||||
final SimpleCollisionBox COLLISION_SHAPE_CROP = new HexCollisionBox(3.0D, -1.0D, 3.0D, 13.0D, 5.0D, 13.0D);
|
||||
final SimpleCollisionBox[] UPPER_SHAPE_BY_AGE = new SimpleCollisionBox[]{new HexCollisionBox(3.0D, 0.0D, 3.0D, 13.0D, 11.0D, 13.0D), FULL_UPPER_SHAPE};
|
||||
final SimpleCollisionBox[] LOWER_SHAPE_BY_AGE = new SimpleCollisionBox[]{COLLISION_SHAPE_BULB, new HexCollisionBox(3.0D, -1.0D, 3.0D, 13.0D, 14.0D, 13.0D), FULL_LOWER_SHAPE, FULL_LOWER_SHAPE, FULL_LOWER_SHAPE};
|
||||
|
||||
return data.getHalf() == Half.UPPER ? UPPER_SHAPE_BY_AGE[Math.min(Math.abs(4 - (data.getAge() + 1)), UPPER_SHAPE_BY_AGE.length - 1)] : LOWER_SHAPE_BY_AGE[data.getAge()];
|
||||
} else {
|
||||
return new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true);
|
||||
}
|
||||
}, StateTypes.PITCHER_CROP),
|
||||
|
||||
WHEAT_BEETROOTS((player, item, version, data, x, y, z) -> {
|
||||
@@ -420,7 +461,7 @@ public enum HitboxData {
|
||||
return new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true);
|
||||
}, StateTypes.SWEET_BERRY_BUSH),
|
||||
|
||||
PINK_PETALS_BLOCK(new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 3.0D, 16.0D), StateTypes.PINK_PETALS),
|
||||
CORAL_FAN(new HexCollisionBox(2.0D, 0.0D, 2.0D, 14.0D, 4.0D, 14.0D), BlockTags.CORALS.getStates().toArray(new StateType[0])),
|
||||
|
||||
TORCHFLOWER_CROP((player, item, version, data, x, y, z) -> {
|
||||
if (data.getAge() == 0) {
|
||||
@@ -455,9 +496,18 @@ public enum HitboxData {
|
||||
|
||||
CAVE_VINES(new HexCollisionBox(1.0D, 0.0D, 1.0D, 15.0D, 16.0D, 15.0D), StateTypes.CAVE_VINES, StateTypes.CAVE_VINES_PLANT),
|
||||
|
||||
TWISTING_VINES_BLOCK(new HexCollisionBox(4.0D, 0.0D, 4.0D, 12.0D, 15.0D, 12.0D), StateTypes.TWISTING_VINES, StateTypes.WEEPING_VINES),
|
||||
// Then your enum entries become:
|
||||
TWISTING_VINES_BLOCK((player, item, version, data, x, y, z) ->
|
||||
getVineCollisionBox(version, false, true), StateTypes.TWISTING_VINES),
|
||||
|
||||
TWISTING_VINES(new HexCollisionBox(4.0D, 0.0D, 4.0D, 12.0D, 16.0D, 12.0D), StateTypes.TWISTING_VINES_PLANT, StateTypes.WEEPING_VINES_PLANT),
|
||||
WEEPING_VINES_BLOCK((player, item, version, data, x, y, z) ->
|
||||
getVineCollisionBox(version, true, true), StateTypes.WEEPING_VINES),
|
||||
|
||||
TWISTING_VINES((player, item, version, data, x, y, z) ->
|
||||
getVineCollisionBox(version, false, false), StateTypes.TWISTING_VINES_PLANT),
|
||||
|
||||
WEEPING_VINES((player, item, version, data, x, y, z) ->
|
||||
getVineCollisionBox(version, true, false), StateTypes.WEEPING_VINES_PLANT),
|
||||
|
||||
TALL_PLANT(new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true), StateTypes.TALL_GRASS, StateTypes.LARGE_FERN),
|
||||
|
||||
@@ -470,8 +520,8 @@ public enum HitboxData {
|
||||
}, StateTypes.BAMBOO_SAPLING),
|
||||
|
||||
SCAFFOLDING((player, item, version, data, x, y, z) -> {
|
||||
// If is holding scaffolding
|
||||
if (item == StateTypes.SCAFFOLDING) {
|
||||
// If is holding scaffolding or Via replacement - hay bale
|
||||
if (item == StateTypes.SCAFFOLDING || version.isOlderThan(ClientVersion.V_1_14)) {
|
||||
return new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true);
|
||||
}
|
||||
|
||||
@@ -519,14 +569,54 @@ public enum HitboxData {
|
||||
|
||||
}, StateTypes.BIG_DRIPLEAF),
|
||||
|
||||
PINK_PETALS_BLOCK((player, item, version, data, x, y, z) -> {
|
||||
if (version.isNewerThan(ClientVersion.V_1_20_2)) {
|
||||
int flowerAmount = data.getFlowerAmount();
|
||||
int horizontalIndex = getHorizontalID(data.getFacing());
|
||||
|
||||
CollisionBox result = NoCollisionBox.INSTANCE;
|
||||
|
||||
// Pre-defined collision boxes for each quadrant
|
||||
HexCollisionBox[] boxes = new HexCollisionBox[] {
|
||||
new HexCollisionBox(8, 0, 8, 16, 3, 16), // SE
|
||||
new HexCollisionBox(8, 0, 0, 16, 3, 8), // NE
|
||||
new HexCollisionBox(0, 0, 0, 8, 3, 8), // NW
|
||||
new HexCollisionBox(0, 0, 8, 8, 3, 16) // SW
|
||||
};
|
||||
|
||||
// Add boxes based on flower amount and facing
|
||||
for (int i = 0; i < flowerAmount; i++) {
|
||||
int index = Math.floorMod(i - horizontalIndex, 4);
|
||||
result = result.union(boxes[index]);
|
||||
}
|
||||
|
||||
return result;
|
||||
} else if (version.isNewerThan(ClientVersion.V_1_19_3)) {
|
||||
return new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 3.0D, 16.0D);
|
||||
} else if (version.isNewerThan(ClientVersion.V_1_12_2)) {
|
||||
return CORAL_FAN.dynamic.fetch(player, item, version, data, x, y, z);
|
||||
}
|
||||
return GRASS_FERN.dynamic.fetch(player, item, version, data, x, y, z);
|
||||
}, StateTypes.PINK_PETALS),
|
||||
|
||||
MANGROVE_PROPAGULE(((player, item, version, data, x, y, z) -> {
|
||||
if (data.isHanging()) {
|
||||
return new HexOffsetCollisionBox(data.getType(), 7.0, 0.0, 7.0, 9.0, 16.0, 9.0);
|
||||
} else {
|
||||
return new HexOffsetCollisionBox(data.getType(), 7.0, getPropaguleMinHeight(data.getAge()), 7.0, 9.0, 16.0, 9.0);
|
||||
}
|
||||
}), StateTypes.MANGROVE_PROPAGULE);
|
||||
}), StateTypes.MANGROVE_PROPAGULE),
|
||||
|
||||
FROGSPAWN((player, item, version, data, x, y, z) -> {
|
||||
if (version.isNewerThan(ClientVersion.V_1_18_2)) {
|
||||
return new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 1.5D, 16.0D);
|
||||
} else { // ViaVersion just replaces this with... nothing
|
||||
return NoCollisionBox.INSTANCE;
|
||||
}
|
||||
}, StateTypes.FROGSPAWN),
|
||||
|
||||
// always a fullblock hitbox. Via replacement is obsidian
|
||||
SCULK_SHRIKER(new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true), StateTypes.SCULK_SHRIEKER);
|
||||
|
||||
private static final Map<StateType, HitboxData> lookup = new HashMap<>();
|
||||
|
||||
@@ -591,4 +681,41 @@ public enum HitboxData {
|
||||
}
|
||||
throw new IllegalStateException("Impossible Propagule Height");
|
||||
}
|
||||
|
||||
private static CollisionBox getVineCollisionBox(ClientVersion version, boolean isWeeping, boolean isBlock) {
|
||||
if (version.isNewerThan(ClientVersion.V_1_15_2)) {
|
||||
if (isWeeping) {
|
||||
return isBlock
|
||||
? new HexCollisionBox(4.0, 9.0, 4.0, 12.0, 16.0, 12.0)
|
||||
: new HexCollisionBox(1.0, 0.0, 1.0, 15.0, 16.0, 15.0);
|
||||
} else {
|
||||
return new HexCollisionBox(4.0D, 0.0D, 4.0D, 12.0D, isBlock ? 15.0D : 16.0D, 12.0D);
|
||||
}
|
||||
} else {
|
||||
// Via replacement - 4 sided vine
|
||||
return new ComplexCollisionBox(
|
||||
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),
|
||||
new HexCollisionBox(0.0D, 0.0D, 15.0D, 16.0D, 16.0D, 16.0D)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static int getHorizontalID(BlockFace facing) {
|
||||
switch (facing) {
|
||||
case DOWN:
|
||||
case UP:
|
||||
return -1;
|
||||
case NORTH:
|
||||
return 2;
|
||||
case SOUTH:
|
||||
return 0;
|
||||
case WEST:
|
||||
return 1;
|
||||
case EAST:
|
||||
return 3;
|
||||
}
|
||||
throw new IllegalStateException("Impossible blockface for getHorizontalID");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package ac.grim.grimac.utils.collisions;
|
||||
|
||||
/*
|
||||
|
||||
*/
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.collisions.datatypes.*;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.defaulttags.BlockTags;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
// Expansion to the CollisionData class, which is different than regular ray tracing hitboxes
|
||||
public enum RaycastData {
|
||||
|
||||
HOPPER((player, item, version, data, x, y, z) -> {
|
||||
CollisionBox insideShape = new HexCollisionBox(2.0, 11.0, 2.0, 14.0, 16.0, 14.0);
|
||||
switch (data.getFacing()) {
|
||||
case NORTH:
|
||||
new ComplexCollisionBox(insideShape, new HexCollisionBox(6.0, 8.0, 0.0, 10.0, 10.0, 4.0));
|
||||
case SOUTH:
|
||||
new ComplexCollisionBox(insideShape, new HexCollisionBox(6.0, 8.0, 12.0, 10.0, 10.0, 16.0));
|
||||
case WEST:
|
||||
new ComplexCollisionBox(insideShape, new HexCollisionBox(0.0, 8.0, 6.0, 4.0, 10.0, 10.0));
|
||||
case EAST:
|
||||
new ComplexCollisionBox(insideShape, new HexCollisionBox(12.0, 8.0, 6.0, 16.0, 10.0, 10.0));
|
||||
default:
|
||||
return insideShape;
|
||||
}
|
||||
}, StateTypes.HOPPER),
|
||||
|
||||
CAULDRON((player, item, version, data, x, y, z) -> {
|
||||
return new HexCollisionBox(2.0, 4.0, 2.0, 14.0, 16.0, 14.0);
|
||||
}, BlockTags.CAULDRONS.getStates().toArray(new StateType[0])),
|
||||
|
||||
FULL_BLOCK((player, item, version, data, x, y, z) -> {
|
||||
return new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true);
|
||||
}, StateTypes.COMPOSTER, StateTypes.SCAFFOLDING);
|
||||
|
||||
|
||||
private static final Map<StateType, RaycastData> lookup = new HashMap<>();
|
||||
|
||||
static {
|
||||
for (RaycastData data : RaycastData.values()) {
|
||||
for (StateType type : data.materials) {
|
||||
lookup.put(type, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final StateType[] materials;
|
||||
private CollisionBox box;
|
||||
private HitBoxFactory dynamic;
|
||||
|
||||
RaycastData(CollisionBox box, StateType... materials) {
|
||||
this.box = box;
|
||||
Set<StateType> mList = new HashSet<>(Arrays.asList(materials));
|
||||
mList.remove(null); // Sets can contain one null
|
||||
this.materials = mList.toArray(new StateType[0]);
|
||||
}
|
||||
|
||||
RaycastData(HitBoxFactory dynamic, StateType... materials) {
|
||||
this.dynamic = dynamic;
|
||||
Set<StateType> mList = new HashSet<>(Arrays.asList(materials));
|
||||
mList.remove(null); // Sets can contain one null
|
||||
this.materials = mList.toArray(new StateType[0]);
|
||||
}
|
||||
|
||||
public static RaycastData getData(StateType material) {
|
||||
return lookup.get(material);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static CollisionBox getBlockHitbox(GrimPlayer player, StateType heldItem, ClientVersion version, WrappedBlockState block, int x, int y, int z) {
|
||||
RaycastData data = getData(block.getType());
|
||||
|
||||
if (data == null) {
|
||||
// We explicitly do not want to fallback on HitBoxData or CollisionBox
|
||||
// Because we only ever use this as a 2nd ray trace
|
||||
return NoCollisionBox.INSTANCE;
|
||||
}
|
||||
|
||||
// Simple collision box to override
|
||||
if (data.box != null)
|
||||
return data.box.copy().offset(x, y, z);
|
||||
|
||||
// Allow this class to override collision boxes when they aren't the same as regular boxes
|
||||
HitBoxFactory hitBoxFactory = data.dynamic;
|
||||
CollisionBox collisionBox = hitBoxFactory.fetch(player, heldItem, version, block, x, y, z);
|
||||
collisionBox.offset(x, y, z);
|
||||
return collisionBox;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ import com.github.retrooper.packetevents.protocol.world.BlockFace;
|
||||
import java.util.List;
|
||||
|
||||
public interface CollisionBox {
|
||||
CollisionBox union(SimpleCollisionBox other);
|
||||
|
||||
boolean isCollided(SimpleCollisionBox other);
|
||||
|
||||
boolean isIntersected(SimpleCollisionBox other);
|
||||
|
||||
@@ -16,6 +16,12 @@ public class ComplexCollisionBox implements CollisionBox {
|
||||
return boxes.add(collisionBox);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollisionBox union(SimpleCollisionBox other) {
|
||||
add(other);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCollided(SimpleCollisionBox other) {
|
||||
for (CollisionBox box : boxes) {
|
||||
|
||||
@@ -21,6 +21,14 @@ public class DynamicCollisionBox implements CollisionBox {
|
||||
this.block = block;
|
||||
}
|
||||
|
||||
// Untested but currently unused
|
||||
// *should* work because every single one of these eventually becomes a Complex, Simple, or NoCollision Box
|
||||
@Override
|
||||
public CollisionBox union(SimpleCollisionBox other) {
|
||||
CollisionBox dynamicBox = box.fetch(player, version, block, x, y, z).offset(x, y, z);
|
||||
return dynamicBox.union(other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCollided(SimpleCollisionBox other) {
|
||||
return box.fetch(player, version, block, x, y, z).offset(x, y, z).isCollided(other);
|
||||
|
||||
@@ -9,6 +9,11 @@ public class NoCollisionBox implements CollisionBox {
|
||||
private NoCollisionBox() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollisionBox union(SimpleCollisionBox other) {
|
||||
return other;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCollided(SimpleCollisionBox other) {
|
||||
return false;
|
||||
|
||||
@@ -163,7 +163,8 @@ public class SimpleCollisionBox implements CollisionBox {
|
||||
return vectors;
|
||||
}
|
||||
|
||||
public SimpleCollisionBox union(SimpleCollisionBox other) {
|
||||
@Override
|
||||
public CollisionBox union(SimpleCollisionBox other) {
|
||||
this.minX = Math.min(this.minX, other.minX);
|
||||
this.minY = Math.min(this.minY, other.minY);
|
||||
this.minZ = Math.min(this.minZ, other.minZ);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package ac.grim.grimac.utils.math;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.world.BlockFace;
|
||||
import com.github.retrooper.packetevents.util.Vector3d;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -2,6 +2,7 @@ package ac.grim.grimac.utils.nmsutil;
|
||||
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.collisions.HitboxData;
|
||||
import ac.grim.grimac.utils.collisions.RaycastData;
|
||||
import ac.grim.grimac.utils.collisions.datatypes.CollisionBox;
|
||||
import ac.grim.grimac.utils.collisions.datatypes.NoCollisionBox;
|
||||
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
|
||||
@@ -17,6 +18,8 @@ import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
|
||||
import com.github.retrooper.packetevents.util.Vector3d;
|
||||
import com.github.retrooper.packetevents.util.Vector3i;
|
||||
import org.bukkit.util.Vector;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -29,6 +32,7 @@ public class BlockRayTrace {
|
||||
//
|
||||
// I do have to admit that I'm starting to like bifunctions/new java 8 things more than I originally did.
|
||||
// although I still don't understand Mojang's obsession with streams in some of the hottest methods... that kills performance
|
||||
@Nullable
|
||||
public static Pair<int[], BlockFace> traverseBlocksLOSP(GrimPlayer player, double[] start, double[] end, BiFunction<WrappedBlockState, int[], Pair<int[], BlockFace>> predicate) {
|
||||
// I guess go back by the collision epsilon?
|
||||
double endX = GrimMath.lerp(-1.0E-7D, end[0], start[0]);
|
||||
@@ -168,22 +172,21 @@ public class BlockRayTrace {
|
||||
return traverseBlocks(player, new double[]{start.x, start.y, start.z}, new double[]{end.x, end.y, end.z}, predicate);
|
||||
}
|
||||
|
||||
public static Pair<int[], BlockFace> getNearestReachHitResult(GrimPlayer player, double[] eyePos, double[] lookVec, double currentDistance, double maxDistance, int[] targetBlockVec, BlockFace expectedBlockFace) {
|
||||
@Nullable
|
||||
public static HitData getNearestReachHitResult(GrimPlayer player, double[] startPos, double[] lookVec, double currentDistance, double maxDistance, int[] targetBlockVec, boolean raycastContext) {
|
||||
double[] endPos = new double[]{
|
||||
eyePos[0] + lookVec[0] * maxDistance,
|
||||
eyePos[1] + lookVec[1] * maxDistance,
|
||||
eyePos[2] + lookVec[2] * maxDistance
|
||||
startPos[0] + lookVec[0] * maxDistance,
|
||||
startPos[1] + lookVec[1] * maxDistance,
|
||||
startPos[2] + lookVec[2] * maxDistance
|
||||
};
|
||||
|
||||
double[] currentEnd = new double[]{
|
||||
eyePos[0] + lookVec[0] * currentDistance,
|
||||
eyePos[1] + lookVec[1] * currentDistance,
|
||||
eyePos[2] + lookVec[2] * currentDistance
|
||||
};
|
||||
|
||||
return traverseBlocksLOSP(player, eyePos, endPos, (block, vector3i) -> {
|
||||
ClientVersion clientVersion = player.getClientVersion();
|
||||
CollisionBox data = HitboxData.getBlockHitbox(player, null, clientVersion, block, vector3i[0], vector3i[1], vector3i[2]);
|
||||
return traverseBlocks(player, startPos, endPos, (block, vector3i) -> {
|
||||
CollisionBox data;
|
||||
if (!raycastContext) {
|
||||
data = HitboxData.getBlockHitbox(player, player.getInventory().getHeldItem().getType().getPlacedType(), player.getClientVersion(), block, vector3i.x, vector3i.y, vector3i.z);
|
||||
} else {
|
||||
data = RaycastData.getBlockHitbox(player, null, player.getClientVersion(), block, vector3i.x, vector3i.y, vector3i.z);
|
||||
}
|
||||
if (data == NoCollisionBox.INSTANCE) return null;
|
||||
List<SimpleCollisionBox> boxes = new ArrayList<>();
|
||||
data.downCast(boxes);
|
||||
@@ -194,21 +197,23 @@ public class BlockRayTrace {
|
||||
|
||||
// BEWARE OF 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
|
||||
if (block.getType() == StateTypes.BREWING_STAND && clientVersion.equals(ClientVersion.V_1_8) && Arrays.equals(vector3i, targetBlockVec)) {
|
||||
if (block.getType() == StateTypes.BREWING_STAND && player.getClientVersion().equals(ClientVersion.V_1_8) && Arrays.equals(new int[]{vector3i.x, vector3i.y, vector3i.z}, targetBlockVec)) {
|
||||
boxes.add(new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true));
|
||||
}
|
||||
|
||||
currentEnd[0] = eyePos[0] + lookVec[0] * currentDistance;
|
||||
currentEnd[1] = eyePos[1] + lookVec[1] * currentDistance;
|
||||
currentEnd[2] = eyePos[2] + lookVec[2] * currentDistance;
|
||||
double[] currentEnd = new double[]{
|
||||
startPos[0] + lookVec[0] * currentDistance,
|
||||
startPos[1] + lookVec[1] * currentDistance,
|
||||
startPos[2] + lookVec[2] * currentDistance
|
||||
};
|
||||
|
||||
for (SimpleCollisionBox box : boxes) {
|
||||
Pair<double[], BlockFace> intercept = ReachUtilsPrimitives.calculateIntercept(box, eyePos, currentEnd);
|
||||
Pair<double[], BlockFace> intercept = ReachUtilsPrimitives.calculateIntercept(box, startPos, currentEnd);
|
||||
if (intercept.getFirst() == null) continue; // No intercept or wrong blockFace
|
||||
|
||||
double[] hitLoc = intercept.getFirst();
|
||||
|
||||
double distSq = distanceSquared(hitLoc, eyePos);
|
||||
double distSq = distanceSquared(hitLoc, startPos);
|
||||
if (distSq < bestHitResult) {
|
||||
bestHitResult = distSq;
|
||||
bestHitLoc = hitLoc;
|
||||
@@ -216,8 +221,29 @@ public class BlockRayTrace {
|
||||
}
|
||||
}
|
||||
|
||||
// Yes, this is not the most optimal algorithm for handling Cauldrons, Hoppers, Composters, and Scaffolding
|
||||
// that is to say, blocks that have a different outline/hitbox shape from the box used to calculate placement blockfaces
|
||||
// but it is the one vanilla uses
|
||||
// No we will not
|
||||
// 1. Calculate the ray trace from a new closer startPos to reduce iterations
|
||||
// because it adds a lot of code complexity for very little performance gain
|
||||
// 2. Run a switch case on the target block and check if the index of the SimpleCollisionBox corresponds to a wall with an inside face
|
||||
// and hardcode in blockface fixes for placements against those compnents above a certain relative y level
|
||||
// because that is version-specific, will break if the implementation of the returned ComplexCollisionBox changes
|
||||
// and again, lots of code complexity for little performance gain
|
||||
if (bestHitLoc != null) {
|
||||
return new Pair<>(vector3i, bestFace);
|
||||
HitData hitData = new HitData(vector3i, new Vector(bestHitLoc[0], bestHitLoc[1], bestHitLoc[2]), bestFace, block);
|
||||
if (!raycastContext) {
|
||||
HitData hitData2 = BlockRayTrace.getNearestReachHitResult(player, startPos, lookVec, maxDistance, maxDistance, targetBlockVec, true);
|
||||
if (hitData2 != null) {
|
||||
Vector startVector = new Vector(startPos[0], startPos[1], startPos[2]);
|
||||
if (hitData2.getBlockHitLocation().subtract(startVector).lengthSquared() <
|
||||
hitData.getBlockHitLocation().subtract(startVector).lengthSquared()) {
|
||||
return new HitData(vector3i, hitData.getBlockHitLocation(), hitData2.getClosestDirection(), block);
|
||||
}
|
||||
}
|
||||
}
|
||||
return hitData;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -5,9 +5,11 @@ import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
|
||||
import ac.grim.grimac.utils.data.Pair;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.world.BlockFace;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ReachUtilsPrimitives {
|
||||
public static Pair<double[], BlockFace> calculateIntercept(SimpleCollisionBox self, double[] origin, double[] end) {
|
||||
public static @NotNull Pair<@Nullable double[], @Nullable BlockFace> calculateIntercept(SimpleCollisionBox self, double[] origin, double[] end) {
|
||||
double[] minX = getIntermediateWithXValue(origin, end, self.minX);
|
||||
double[] maxX = getIntermediateWithXValue(origin, end, self.maxX);
|
||||
double[] minY = getIntermediateWithYValue(origin, end, self.minY);
|
||||
|
||||
Reference in new issue
Block a user