diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitCollider.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitCollider.java new file mode 100644 index 000000000..f2d94e95f --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitCollider.java @@ -0,0 +1,35 @@ +package net.momirealms.craftengine.bukkit.entity.furniture; + +import net.momirealms.craftengine.bukkit.nms.CollisionEntity; +import net.momirealms.craftengine.core.entity.furniture.Collider; +import net.momirealms.craftengine.core.entity.furniture.ColliderType; + +public class BukkitCollider implements Collider { + private final CollisionEntity collisionEntity; + private final ColliderType type; + + public BukkitCollider(CollisionEntity collisionEntity, ColliderType type) { + this.collisionEntity = collisionEntity; + this.type = type; + } + + @Override + public void destroy() { + this.collisionEntity.destroy(); + } + + @Override + public int entityId() { + return this.collisionEntity.getId(); + } + + @Override + public ColliderType type() { + return this.type; + } + + @Override + public Object handle() { + return this.collisionEntity; + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureElement.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureElement.java index 0a4737c20..f1b88b0fb 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureElement.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureElement.java @@ -10,6 +10,7 @@ import net.momirealms.craftengine.core.entity.furniture.ItemDisplayContext; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.world.World; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.joml.Quaternionf; @@ -34,7 +35,7 @@ public class BukkitFurnitureElement extends AbstractFurnitureElement { } @Override - public void initPackets(int entityId, double x, double y, double z, float yaw, Quaternionf conjugated, Consumer packets) { + public void initPackets(int entityId, World world, double x, double y, double z, float yaw, Quaternionf conjugated, Consumer packets) { Vector3f offset = conjugated.transform(new Vector3f(position())); packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket( entityId, UUID.randomUUID(), x + offset.x, y + offset.y, z - offset.z, 0, yaw, diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java index 1521edffc..6923ed6c6 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java @@ -260,10 +260,6 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { for (int sub : furniture.entityIds()) { this.furnitureByEntityId.remove(sub); } -// for (CollisionEntity collision : furniture.collisionEntities()) { -// this.furnitureByRealEntityId.remove(FastNMS.INSTANCE.method$Entity$getId(collision)); -// if (!isPreventing) collision.destroy(); -// } } } @@ -406,8 +402,8 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { for (int entityId : loadedFurniture.entityIds()) { this.furnitureByEntityId.put(entityId, loadedFurniture); } - for (CollisionEntity collisionEntity : loadedFurniture.collisionEntities()) { - int collisionEntityId = FastNMS.INSTANCE.method$Entity$getId(collisionEntity); + for (Collider collisionEntity : loadedFurniture.collisionEntities()) { + int collisionEntityId = FastNMS.INSTANCE.method$Entity$getId(collisionEntity.handle()); this.furnitureByRealEntityId.put(collisionEntityId, loadedFurniture); } return loadedFurniture; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java index 86a73c16b..72588c70a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java @@ -1,7 +1,6 @@ package net.momirealms.craftengine.bukkit.entity.furniture; import net.momirealms.craftengine.bukkit.entity.BukkitEntity; -import net.momirealms.craftengine.bukkit.nms.CollisionEntity; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.util.EntityUtils; import net.momirealms.craftengine.bukkit.util.LegacyAttributeUtils; @@ -15,13 +14,14 @@ import net.momirealms.craftengine.core.util.QuaternionUtils; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.collision.AABB; import org.bukkit.Location; import org.bukkit.attribute.Attribute; import org.bukkit.entity.*; import org.bukkit.persistence.PersistentDataType; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.joml.Quaternionf; -import org.joml.Vector3d; import org.joml.Vector3f; import java.lang.ref.WeakReference; @@ -37,16 +37,17 @@ public class LoadedFurniture implements Furniture { private final WeakReference baseEntity; private final int baseEntityId; // colliders - private final CollisionEntity[] collisionEntities; + private final Collider[] colliderEntities; // cache private final List fakeEntityIds; private final List entityIds; - private final Map hitBoxes; + private final Map hitBoxes = new HashMap<>(); + private final Map aabb = new HashMap<>(); private final boolean minimized; private final boolean hasExternalModel; // seats private final Set occupiedSeats = Collections.synchronizedSet(new HashSet<>()); - private final Vector seats = new Vector<>(); + private final Vector> seats = new Vector<>(); // cached spawn packet private Object cachedSpawnPacket; private Object cachedMinimizedSpawnPacket; @@ -60,7 +61,6 @@ public class LoadedFurniture implements Furniture { this.location = baseEntity.getLocation(); this.baseEntity = new WeakReference<>(baseEntity); this.furniture = furniture; - this.hitBoxes = new HashMap<>(); this.minimized = furniture.settings().minimized(); List fakeEntityIds = new ArrayList<>(); List mainEntityIds = new ArrayList<>(); @@ -92,10 +92,11 @@ public class LoadedFurniture implements Furniture { List minimizedPackets = new ArrayList<>(); List colliders = new ArrayList<>(); + World world = world(); for (FurnitureElement element : placement.elements()) { int entityId = Reflections.instance$Entity$ENTITY_COUNTER.incrementAndGet(); fakeEntityIds.add(entityId); - element.initPackets(entityId, x, y, z, yaw, conjugated, packet -> { + element.initPackets(entityId, world, x, y, z, yaw, conjugated, packet -> { packets.add(packet); if (this.minimized) minimizedPackets.add(packet); }); @@ -107,12 +108,12 @@ public class LoadedFurniture implements Furniture { mainEntityIds.add(entityId); this.hitBoxes.put(entityId, hitBox); } - hitBox.initPacketsAndColliders(ids, x, y, z, yaw, conjugated, (packet, canBeMinimized) -> { + hitBox.initPacketsAndColliders(ids, world, x, y, z, yaw, conjugated, (packet, canBeMinimized) -> { packets.add(packet); if (this.minimized && !canBeMinimized) { minimizedPackets.add(packet); } - }, colliders::add); + }, colliders::add, this.aabb::put); } try { this.cachedSpawnPacket = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(packets); @@ -124,34 +125,15 @@ public class LoadedFurniture implements Furniture { } this.fakeEntityIds = fakeEntityIds; this.entityIds = mainEntityIds; - int colliderSize = colliders.size(); - this.collisionEntities = new CollisionEntity[colliderSize]; - if (colliderSize != 0) { - Object world = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(this.location.getWorld()); - for (int i = 0; i < colliderSize; i++) { - Collider collider = colliders.get(i); - Vector3f offset = conjugated.transform(new Vector3f(collider.position())); - Vector3d offset1 = collider.point1(); - Vector3d offset2 = collider.point2(); - double x1 = x + offset1.x() + offset.x(); - double x2 = x + offset2.x() + offset.x(); - double y1 = y + offset1.y() + offset.y(); - double y2 = y + offset2.y() + offset.y(); - double z1 = z + offset1.z() - offset.z(); - double z2 = z + offset2.z() - offset.z(); - Object aabb = FastNMS.INSTANCE.constructor$AABB(x1, y1, z1, x2, y2, z2); - CollisionEntity entity = FastNMS.INSTANCE.createCollisionShulker(world, aabb, x, y, z, collider.canBeHitByProjectile()); - this.collisionEntities[i] = entity; - } - } + this.colliderEntities = colliders.toArray(new Collider[0]); } @Override public void initializeColliders() { Object world = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(this.location.getWorld()); - for (CollisionEntity entity : this.collisionEntities) { - FastNMS.INSTANCE.method$LevelWriter$addFreshEntity(world, entity); - Entity bukkitEntity = FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity); + for (Collider entity : this.colliderEntities) { + FastNMS.INSTANCE.method$LevelWriter$addFreshEntity(world, entity.handle()); + Entity bukkitEntity = FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity.handle()); bukkitEntity.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_COLLISION, PersistentDataType.BYTE, (byte) 1); } } @@ -201,11 +183,13 @@ public class LoadedFurniture implements Furniture { return; } this.baseEntity().remove(); - for (CollisionEntity entity : this.collisionEntities) { + for (Collider entity : this.colliderEntities) { if (entity != null) entity.destroy(); } - for (Entity entity : this.seats) { + for (WeakReference r : this.seats) { + Entity entity = r.get(); + if (entity == null) continue; for (Entity passenger : entity.getPassengers()) { entity.removePassenger(passenger); } @@ -216,8 +200,11 @@ public class LoadedFurniture implements Furniture { @Override public void destroySeats() { - for (Entity entity : this.seats) { - entity.remove(); + for (WeakReference entity : this.seats) { + Entity e = entity.get(); + if (e != null) { + e.remove(); + } } this.seats.clear(); } @@ -269,8 +256,18 @@ public class LoadedFurniture implements Furniture { return Collections.unmodifiableList(this.fakeEntityIds); } - public CollisionEntity[] collisionEntities() { - return this.collisionEntities; + public Collider[] collisionEntities() { + return this.colliderEntities; + } + + @Nullable + public HitBox hitBoxByEntityId(int id) { + return this.hitBoxes.get(id); + } + + @Nullable + public AABB aabbByEntityId(int id) { + return this.aabb.get(id); } @Override @@ -326,7 +323,7 @@ public class LoadedFurniture implements Furniture { itemDisplay.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_SEAT_BASE_ENTITY_KEY, PersistentDataType.INTEGER, this.baseEntityId()); itemDisplay.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_SEAT_VECTOR_3F_KEY, PersistentDataType.STRING, seat.offset().x + ", " + seat.offset().y + ", " + seat.offset().z); }); - this.seats.add(seatEntity); + this.seats.add(new WeakReference<>(seatEntity)); seatEntity.addPassenger(player); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/CustomHitBox.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/CustomHitBox.java index fd98180ca..a10a9faa3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/CustomHitBox.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/CustomHitBox.java @@ -7,6 +7,8 @@ import net.momirealms.craftengine.core.entity.furniture.*; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.collision.AABB; import org.bukkit.NamespacedKey; import org.bukkit.Registry; import org.bukkit.entity.EntityType; @@ -25,7 +27,7 @@ public class CustomHitBox extends AbstractHitBox { private final List cachedValues = new ArrayList<>(); public CustomHitBox(Seat[] seats, Vector3f position, EntityType type, float scale) { - super(seats, position); + super(seats, position, false); this.scale = scale; this.entityType = type; BaseEntityData.NoGravity.addEntityDataIfNotDefaultValue(true, this.cachedValues); @@ -47,7 +49,7 @@ public class CustomHitBox extends AbstractHitBox { } @Override - public void initPacketsAndColliders(int[] entityId, double x, double y, double z, float yaw, Quaternionf conjugated, BiConsumer packets, Consumer collider) { + public void initPacketsAndColliders(int[] entityId, World world, double x, double y, double z, float yaw, Quaternionf conjugated, BiConsumer packets, Consumer collider, BiConsumer aabb) { Vector3f offset = conjugated.transform(new Vector3f(position())); try { packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket( diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/HappyGhastHitBox.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/HappyGhastHitBox.java index adb0d4944..d6f133c33 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/HappyGhastHitBox.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/HappyGhastHitBox.java @@ -3,6 +3,8 @@ package net.momirealms.craftengine.bukkit.entity.furniture.hitbox; import net.momirealms.craftengine.core.entity.furniture.*; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.collision.AABB; import org.joml.Quaternionf; import org.joml.Vector3f; @@ -15,8 +17,8 @@ public class HappyGhastHitBox extends AbstractHitBox { public static final Factory FACTORY = new Factory(); private final double scale; - public HappyGhastHitBox(Seat[] seats, Vector3f position, double scale) { - super(seats, position); + public HappyGhastHitBox(Seat[] seats, Vector3f position, double scale, boolean canUseOn) { + super(seats, position, canUseOn); this.scale = scale; } @@ -30,7 +32,7 @@ public class HappyGhastHitBox extends AbstractHitBox { } @Override - public void initPacketsAndColliders(int[] entityId, double x, double y, double z, float yaw, Quaternionf conjugated, BiConsumer packets, Consumer collider) { + public void initPacketsAndColliders(int[] entityId, World world, double x, double y, double z, float yaw, Quaternionf conjugated, BiConsumer packets, Consumer collider, BiConsumer aabb) { // todo 乐魂 } @@ -44,10 +46,11 @@ public class HappyGhastHitBox extends AbstractHitBox { @Override public HitBox create(Map arguments) { double scale = MiscUtils.getAsDouble(arguments.getOrDefault("scale", "1")); + boolean canUseOn = (boolean) arguments.getOrDefault("can-use-item-on", false); return new HappyGhastHitBox( HitBoxFactory.getSeats(arguments), MiscUtils.getVector3f(arguments.getOrDefault("position", "0")), - scale + scale, canUseOn ); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/InteractionHitBox.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/InteractionHitBox.java index a00af2460..c723b47ad 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/InteractionHitBox.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/InteractionHitBox.java @@ -6,6 +6,9 @@ import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.entity.furniture.*; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.world.Vec3d; +import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.collision.AABB; import org.joml.Quaternionf; import org.joml.Vector3f; @@ -19,14 +22,14 @@ import java.util.function.Supplier; public class InteractionHitBox extends AbstractHitBox { public static final Factory FACTORY = new Factory(); - public static final InteractionHitBox DEFAULT = new InteractionHitBox(new Seat[0], new Vector3f(), new Vector3f(1,1,1), true); + public static final InteractionHitBox DEFAULT = new InteractionHitBox(new Seat[0], new Vector3f(), new Vector3f(1,1,1), true, false); private final Vector3f size; private final boolean responsive; private final List cachedValues = new ArrayList<>(); - public InteractionHitBox(Seat[] seats, Vector3f position, Vector3f size, boolean responsive) { - super(seats, position); + public InteractionHitBox(Seat[] seats, Vector3f position, Vector3f size, boolean responsive, boolean canUseOn) { + super(seats, position, canUseOn); this.size = size; this.responsive = responsive; InteractionEntityData.Height.addEntityDataIfNotDefaultValue(size.y, cachedValues); @@ -48,13 +51,16 @@ public class InteractionHitBox extends AbstractHitBox { } @Override - public void initPacketsAndColliders(int[] entityId, double x, double y, double z, float yaw, Quaternionf conjugated, BiConsumer packets, Consumer collider) { + public void initPacketsAndColliders(int[] entityId, World world, double x, double y, double z, float yaw, Quaternionf conjugated, BiConsumer packets, Consumer collider, BiConsumer aabb) { Vector3f offset = conjugated.transform(new Vector3f(position())); packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket( entityId[0], UUID.randomUUID(), x + offset.x, y + offset.y, z - offset.z, 0, yaw, Reflections.instance$EntityType$INTERACTION, 0, Reflections.instance$Vec3$Zero, 0 ), true); packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId[0], List.copyOf(this.cachedValues)), true); + if (canPlaceAgainst()) { + aabb.accept(entityId[0], AABB.fromInteraction(new Vec3d(x + offset.x, y + offset.y, z - offset.z), this.size.x, this.size.y)); + } } @Override @@ -77,11 +83,13 @@ public class InteractionHitBox extends AbstractHitBox { width = MiscUtils.getAsFloat(arguments.getOrDefault("width", "1")); height = MiscUtils.getAsFloat(arguments.getOrDefault("height", "1")); } + boolean canUseOn = (boolean) arguments.getOrDefault("can-use-item-on", false); + boolean interactive = (boolean) arguments.getOrDefault("interactive", true); return new InteractionHitBox( HitBoxFactory.getSeats(arguments), position, new Vector3f(width, height, width), - (boolean) arguments.getOrDefault("interactive", true) + interactive, canUseOn ); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/ShulkerHitBox.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/ShulkerHitBox.java index b7be758e4..b0e54c54d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/ShulkerHitBox.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/ShulkerHitBox.java @@ -2,13 +2,16 @@ package net.momirealms.craftengine.bukkit.entity.furniture.hitbox; import net.momirealms.craftengine.bukkit.entity.data.InteractionEntityData; import net.momirealms.craftengine.bukkit.entity.data.ShulkerData; +import net.momirealms.craftengine.bukkit.entity.furniture.BukkitCollider; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.util.DirectionUtils; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.entity.furniture.*; import net.momirealms.craftengine.core.util.*; +import net.momirealms.craftengine.core.world.Vec3d; +import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.collision.AABB; import org.joml.Quaternionf; -import org.joml.Vector3d; import org.joml.Vector3f; import java.util.*; @@ -27,8 +30,8 @@ public class ShulkerHitBox extends AbstractHitBox { private final List cachedShulkerValues = new ArrayList<>(); private final DirectionalShulkerSpawner spawner; - public ShulkerHitBox(Seat[] seats, Vector3f position, Direction direction, float scale, byte peek, boolean interactionEntity, boolean interactive) { - super(seats, position); + public ShulkerHitBox(Seat[] seats, Vector3f position, Direction direction, float scale, byte peek, boolean interactionEntity, boolean interactive, boolean canUseOn) { + super(seats, position, canUseOn); this.direction = direction; this.scale = scale; this.peek = peek; @@ -45,27 +48,28 @@ public class ShulkerHitBox extends AbstractHitBox { float shulkerHeight = (getPhysicalPeek(peek * 0.01F) + 1) * scale; List cachedInteractionValues = new ArrayList<>(); if (this.direction == Direction.UP) { - Collider c = createCollider(Direction.UP); InteractionEntityData.Height.addEntityDataIfNotDefaultValue(shulkerHeight + 0.01f, cachedInteractionValues); InteractionEntityData.Width.addEntityDataIfNotDefaultValue(scale + 0.005f, cachedInteractionValues); InteractionEntityData.Responsive.addEntityDataIfNotDefaultValue(interactive, cachedInteractionValues); - this.spawner = (entityIds, x, y, z, yaw, offset, packets, collider) -> { - collider.accept(c); + this.spawner = (entityIds, world, x, y, z, yaw, offset, packets, collider, aabb) -> { + collider.accept(this.createCollider(Direction.UP, world, offset, x, y, z, entityIds[1], aabb)); if (interactionEntity) { packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket( entityIds[2], UUID.randomUUID(), x + offset.x, y + offset.y - 0.005f, z - offset.z, 0, yaw, Reflections.instance$EntityType$INTERACTION, 0, Reflections.instance$Vec3$Zero, 0 ), true); packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityIds[2], List.copyOf(cachedInteractionValues)), true); + if (canUseOn) { + aabb.accept(entityIds[2], AABB.fromInteraction(new Vec3d(x + offset.x, y + offset.y, z - offset.z), scale, shulkerHeight)); + } } }; } else if (this.direction == Direction.DOWN) { - Collider c = createCollider(Direction.DOWN); InteractionEntityData.Height.addEntityDataIfNotDefaultValue(shulkerHeight + 0.01f, cachedInteractionValues); InteractionEntityData.Width.addEntityDataIfNotDefaultValue(scale + 0.005f, cachedInteractionValues); InteractionEntityData.Responsive.addEntityDataIfNotDefaultValue(interactive, cachedInteractionValues); - this.spawner = (entityIds, x, y, z, yaw, offset, packets, collider) -> { - collider.accept(c); + this.spawner = (entityIds, world, x, y, z, yaw, offset, packets, collider, aabb) -> { + collider.accept(this.createCollider(Direction.DOWN, world, offset, x, y, z, entityIds[1], aabb)); packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityIds[1], List.of(ShulkerData.AttachFace.createEntityDataIfNotDefaultValue(Reflections.instance$Direction$UP))), false); if (interactionEntity) { packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket( @@ -73,16 +77,19 @@ public class ShulkerHitBox extends AbstractHitBox { Reflections.instance$EntityType$INTERACTION, 0, Reflections.instance$Vec3$Zero, 0 ), true); packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityIds[2], List.copyOf(cachedInteractionValues)), true); + if (canUseOn) { + aabb.accept(entityIds[2], AABB.fromInteraction(new Vec3d(x + offset.x, y + offset.y - shulkerHeight + scale, z - offset.z), scale, shulkerHeight)); + } } }; } else { InteractionEntityData.Height.addEntityDataIfNotDefaultValue(scale + 0.01f, cachedInteractionValues); InteractionEntityData.Width.addEntityDataIfNotDefaultValue(scale + 0.005f, cachedInteractionValues); InteractionEntityData.Responsive.addEntityDataIfNotDefaultValue(interactive, cachedInteractionValues); - this.spawner = (entityIds, x, y, z, yaw, offset, packets, collider) -> { + this.spawner = (entityIds, world, x, y, z, yaw, offset, packets, collider, aabb) -> { Direction shulkerAnchor = getOriginalDirection(direction, Direction.fromYaw(yaw)); Direction shulkerDirection = shulkerAnchor.opposite(); - collider.accept(this.createCollider(shulkerDirection)); + collider.accept(this.createCollider(shulkerDirection, world, offset, x, y, z, entityIds[1], aabb)); packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityIds[1], List.of(ShulkerData.AttachFace.createEntityDataIfNotDefaultValue(DirectionUtils.toNMSDirection(shulkerAnchor)))), false); if (interactionEntity) { // first interaction @@ -98,12 +105,16 @@ public class ShulkerHitBox extends AbstractHitBox { Reflections.instance$EntityType$INTERACTION, 0, Reflections.instance$Vec3$Zero, 0 ), true); packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityIds[3], List.copyOf(cachedInteractionValues)), true); + if (canUseOn) { + aabb.accept(entityIds[2], AABB.fromInteraction(new Vec3d(x + offset.x, y + offset.y, z - offset.z), scale, scale)); + aabb.accept(entityIds[3], AABB.fromInteraction(new Vec3d(x + offset.x + shulkerDirection.stepX() * distance, y + offset.y, z - offset.z + shulkerDirection.stepZ() * distance), scale, scale)); + } } }; } } - public Collider createCollider(Direction d) { + public Collider createCollider(Direction direction, World world, Vector3f offset, double x, double y, double z, int entityId, BiConsumer aabb) { float peek = getPhysicalPeek(this.peek() * 0.01F); double x1 = -this.scale * 0.5; double y1 = 0.0; @@ -112,29 +123,37 @@ public class ShulkerHitBox extends AbstractHitBox { double y2 = this.scale; double z2 = this.scale * 0.5; - double dx = (double) d.stepX() * peek * (double) this.scale; + double dx = (double) direction.stepX() * peek * (double) this.scale; if (dx > 0) { x2 += dx; } else if (dx < 0) { x1 += dx; } - double dy = (double) d.stepY() * peek * (double) this.scale; + double dy = (double) direction.stepY() * peek * (double) this.scale; if (dy > 0) { y2 += dy; } else if (dy < 0) { y1 += dy; } - double dz = (double) d.stepZ() * peek * (double) this.scale; + double dz = (double) direction.stepZ() * peek * (double) this.scale; if (dz > 0) { z2 += dz; } else if (dz < 0) { z1 += dz; } - return new Collider( - true, - this.position, - new Vector3d(x1, y1, z1), - new Vector3d(x2, y2, z2) + + Object level = world.serverWorld(); + double minX = x + x1 + offset.x(); + double maxX = x + x2 + offset.x(); + double minY = y + y1 + offset.y(); + double maxY = y + y2 + offset.y(); + double minZ = z + z1 - offset.z(); + double maxZ = z + z2 - offset.z(); + Object nmsAABB = FastNMS.INSTANCE.constructor$AABB(minX, minY, minZ, maxX, maxY, maxZ); + aabb.accept(entityId, new AABB(minX, minY, minZ, maxX, maxY, maxZ)); + return new BukkitCollider( + FastNMS.INSTANCE.createCollisionShulker(level, nmsAABB, x, y, z, true), + ColliderType.SHULKER ); } @@ -168,7 +187,7 @@ public class ShulkerHitBox extends AbstractHitBox { } @Override - public void initPacketsAndColliders(int[] entityIds, double x, double y, double z, float yaw, Quaternionf conjugated, BiConsumer packets, Consumer collider) { + public void initPacketsAndColliders(int[] entityIds, World world, double x, double y, double z, float yaw, Quaternionf conjugated, BiConsumer packets, Consumer collider, BiConsumer aabb) { Vector3f offset = conjugated.transform(new Vector3f(position())); try { double originalY = y + offset.y; @@ -200,7 +219,7 @@ public class ShulkerHitBox extends AbstractHitBox { Reflections.method$AttributeInstance$setBaseValue.invoke(attributeInstance, this.scale); packets.accept(Reflections.constructor$ClientboundUpdateAttributesPacket0.newInstance(entityIds[1], Collections.singletonList(attributeInstance)), false); } - this.spawner.accept(entityIds, x, y, z, yaw, offset, packets, collider); + this.spawner.accept(entityIds, world, x, y, z, yaw, offset, packets, collider, aabb); } catch (ReflectiveOperationException e) { throw new RuntimeException("Failed to construct shulker hitbox spawn packet", e); } @@ -209,7 +228,7 @@ public class ShulkerHitBox extends AbstractHitBox { @FunctionalInterface interface DirectionalShulkerSpawner { - void accept(int[] entityIds, double x, double y, double z, float yaw, Vector3f offset, BiConsumer packets, Consumer collider); + void accept(int[] entityIds, World world, double x, double y, double z, float yaw, Vector3f offset, BiConsumer packets, Consumer collider, BiConsumer aabb); } @Override @@ -238,10 +257,11 @@ public class ShulkerHitBox extends AbstractHitBox { Direction directionEnum = Optional.ofNullable(arguments.get("direction")).map(it -> Direction.valueOf(it.toString().toUpperCase(Locale.ENGLISH))).orElse(Direction.UP); boolean interactive = (boolean) arguments.getOrDefault("interactive", true); boolean interactionEntity = (boolean) arguments.getOrDefault("interaction-entity", true); + boolean canUseItemOn = (boolean) arguments.getOrDefault("can-use-item-on", true); return new ShulkerHitBox( HitBoxFactory.getSeats(arguments), position, directionEnum, - scale, peek, interactionEntity, interactive + scale, peek, interactionEntity, interactive, canUseItemOn ); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java index 522dd68cf..6dc8a2af8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java @@ -12,6 +12,7 @@ import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.compatibility.modelengine.ModelEngineUtils; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; import net.momirealms.craftengine.bukkit.entity.furniture.LoadedFurniture; +import net.momirealms.craftengine.bukkit.item.behavior.FurnitureItemBehavior; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.pack.BukkitPackManager; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; @@ -22,6 +23,9 @@ import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.font.FontManager; import net.momirealms.craftengine.core.font.IllegalCharacterProcessResult; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.behavior.ItemBehavior; +import net.momirealms.craftengine.core.item.context.UseOnContext; import net.momirealms.craftengine.core.pack.host.ResourcePackDownloadData; import net.momirealms.craftengine.core.pack.host.ResourcePackHost; import net.momirealms.craftengine.core.plugin.CraftEngine; @@ -30,19 +34,21 @@ import net.momirealms.craftengine.core.plugin.network.ConnectionState; import net.momirealms.craftengine.core.plugin.network.NetWorkUser; import net.momirealms.craftengine.core.plugin.network.NetworkManager; import net.momirealms.craftengine.core.util.*; -import net.momirealms.craftengine.core.world.BlockPos; -import net.momirealms.craftengine.core.world.WorldEvents; +import net.momirealms.craftengine.core.world.*; import net.momirealms.craftengine.core.world.chunk.Palette; import net.momirealms.craftengine.core.world.chunk.PalettedContainer; import net.momirealms.craftengine.core.world.chunk.packet.MCSection; +import net.momirealms.craftengine.core.world.collision.AABB; import net.momirealms.sparrow.nbt.Tag; import org.bukkit.*; +import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; import org.bukkit.util.RayTraceResult; +import org.bukkit.util.Vector; import java.lang.reflect.InvocationTargetException; import java.nio.charset.StandardCharsets; @@ -1621,13 +1627,36 @@ public class PacketConsumers { if (EventUtils.fireAndCheckCancel(interactEvent)) { return; } - if (player.isSneaking()) - return; - furniture.findFirstAvailableSeat(entityId).ifPresent(seatPos -> { - if (furniture.tryOccupySeat(seatPos)) { - furniture.spawnSeatEntityForPlayer(Objects.requireNonNull(player.getPlayer()), seatPos); - } - }); + if (player.isSneaking()) { + // try placing another furniture above it + AABB hitBox = furniture.aabbByEntityId(entityId); + if (hitBox == null) return; + Item itemInHand = serverPlayer.getItemInHand(InteractionHand.MAIN_HAND); + if (itemInHand == null) return; + itemInHand.getCustomItem().ifPresent(customItem -> { + Location eyeLocation = player.getEyeLocation(); + Vector direction = eyeLocation.getDirection(); + Location endLocation = eyeLocation.clone(); + endLocation.add(direction.multiply(serverPlayer.getCachedInteractionRange())); + Optional result = hitBox.clip(LocationUtils.toVec3d(eyeLocation), LocationUtils.toVec3d(endLocation)); + if (result.isPresent()) { + EntityHitResult hitResult = result.get(); + Vec3d vec3d = hitResult.position(); + for (ItemBehavior behavior : customItem.behaviors()) { + if (behavior instanceof FurnitureItemBehavior) { + behavior.useOnBlock(new UseOnContext(serverPlayer, InteractionHand.MAIN_HAND, new BlockHitResult(vec3d, hitResult.direction(), BlockPos.fromVec3d(vec3d), false))); + return; + } + } + } + }); + } else { + furniture.findFirstAvailableSeat(entityId).ifPresent(seatPos -> { + if (furniture.tryOccupySeat(seatPos)) { + furniture.spawnSeatEntityForPlayer(Objects.requireNonNull(player.getPlayer()), seatPos); + } + }); + } } }, player.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4); } catch (Exception e) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractHitBox.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractHitBox.java index a8d0fb934..17867d8c6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractHitBox.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractHitBox.java @@ -5,19 +5,26 @@ import org.joml.Vector3f; public abstract class AbstractHitBox implements HitBox { protected final Seat[] seats; protected final Vector3f position; + protected final boolean canUseItemOn; - public AbstractHitBox(Seat[] seats, Vector3f position) { + public AbstractHitBox(Seat[] seats, Vector3f position, boolean canUseItemOn) { this.seats = seats; this.position = position; + this.canUseItemOn = canUseItemOn; } @Override public Seat[] seats() { - return seats; + return this.seats; } @Override public Vector3f position() { - return position; + return this.position; + } + + @Override + public boolean canPlaceAgainst() { + return this.canUseItemOn; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/Collider.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/Collider.java index 930887836..fccdbc3f8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/Collider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/Collider.java @@ -1,34 +1,12 @@ package net.momirealms.craftengine.core.entity.furniture; -import org.joml.Vector3d; -import org.joml.Vector3f; +public interface Collider { -public class Collider { - private final Vector3f position; - private final Vector3d point1; - private final Vector3d point2; - private final boolean canBeHitByProjectile; + void destroy(); - public Collider(boolean canBeHitByProjectile, Vector3f position, Vector3d point1, Vector3d point2) { - this.canBeHitByProjectile = canBeHitByProjectile; - this.position = position; - this.point1 = point1; - this.point2 = point2; - } + int entityId(); - public Vector3f position() { - return position; - } + ColliderType type(); - public boolean canBeHitByProjectile() { - return canBeHitByProjectile; - } - - public Vector3d point1() { - return point1; - } - - public Vector3d point2() { - return point2; - } + Object handle(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/ColliderType.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/ColliderType.java new file mode 100644 index 000000000..c935a40c8 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/ColliderType.java @@ -0,0 +1,5 @@ +package net.momirealms.craftengine.core.entity.furniture; + +public enum ColliderType { + SHULKER +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureElement.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureElement.java index 340a057e6..b92b56dc5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureElement.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureElement.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.core.entity.furniture; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.world.World; import org.joml.Quaternionf; import org.joml.Vector3f; @@ -21,5 +22,5 @@ public interface FurnitureElement { Vector3f position(); - void initPackets(int entityId, double x, double y, double z, float yaw, Quaternionf conjugated, Consumer packets); + void initPackets(int entityId, World world, double x, double y, double z, float yaw, Quaternionf conjugated, Consumer packets); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBox.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBox.java index 8a9923f3e..07b40bf3d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBox.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBox.java @@ -1,6 +1,8 @@ package net.momirealms.craftengine.core.entity.furniture; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.collision.AABB; import org.joml.Quaternionf; import org.joml.Vector3f; @@ -12,11 +14,14 @@ public interface HitBox { Key type(); - void initPacketsAndColliders(int[] entityId, double x, double y, double z, float yaw, Quaternionf conjugated, BiConsumer packets, Consumer collider); + void initPacketsAndColliders(int[] entityId, World world, double x, double y, double z, float yaw, Quaternionf conjugated, + BiConsumer packets, Consumer collider, BiConsumer aabb); int[] acquireEntityIds(Supplier entityIdSupplier); Seat[] seats(); Vector3f position(); + + boolean canPlaceAgainst(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/BlockPos.java b/core/src/main/java/net/momirealms/craftengine/core/world/BlockPos.java index d5d7a7eb7..fa120ee5f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/BlockPos.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/BlockPos.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.core.world; import net.momirealms.craftengine.core.util.Direction; +import net.momirealms.craftengine.core.util.MCUtils; public class BlockPos extends Vec3i { @@ -20,6 +21,10 @@ public class BlockPos extends Vec3i { }; } + public static BlockPos fromVec3d(Vec3d vec) { + return new BlockPos(MCUtils.fastFloor(vec.x), MCUtils.fastFloor(vec.y), MCUtils.fastFloor(vec.z)); + } + public static BlockPos of(long packedPos) { return new BlockPos((int) (packedPos >> 38), (int) ((packedPos << 52) >> 52), (int) ((packedPos << 26) >> 38)); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/EntityHitResult.java b/core/src/main/java/net/momirealms/craftengine/core/world/EntityHitResult.java new file mode 100644 index 000000000..ca8e433f1 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/world/EntityHitResult.java @@ -0,0 +1,21 @@ +package net.momirealms.craftengine.core.world; + +import net.momirealms.craftengine.core.util.Direction; + +public class EntityHitResult { + private final Direction direction; + private final Vec3d position; + + public EntityHitResult(Direction direction, Vec3d position) { + this.direction = direction; + this.position = position; + } + + public Direction direction() { + return direction; + } + + public Vec3d position() { + return position; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/Vec3d.java b/core/src/main/java/net/momirealms/craftengine/core/world/Vec3d.java index d322b84a1..1a367fc03 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/Vec3d.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/Vec3d.java @@ -3,9 +3,9 @@ package net.momirealms.craftengine.core.world; import net.momirealms.craftengine.core.util.MCUtils; public class Vec3d implements Position { - private final double x; - private final double y; - private final double z; + public final double x; + public final double y; + public final double z; public Vec3d(double x, double y, double z) { this.x = x; @@ -17,6 +17,14 @@ public class Vec3d implements Position { return new Vec3d(MCUtils.fastFloor(x) + 0.5, MCUtils.fastFloor(y) + 0.5, MCUtils.fastFloor(z) + 0.5); } + public Vec3d add(Vec3d vec) { + return new Vec3d(x + vec.x, y + vec.y, z + vec.z); + } + + public Vec3d add(double x, double y, double z) { + return new Vec3d(x + this.x, y + this.y, z + this.z); + } + public static Vec3d atLowerCornerOf(Vec3i vec) { return new Vec3d(vec.x(), vec.y(), vec.z()); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/collision/AABB.java b/core/src/main/java/net/momirealms/craftengine/core/world/collision/AABB.java new file mode 100644 index 000000000..faf6b5bc2 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/world/collision/AABB.java @@ -0,0 +1,126 @@ +package net.momirealms.craftengine.core.world.collision; + +import net.momirealms.craftengine.core.util.Direction; +import net.momirealms.craftengine.core.world.EntityHitResult; +import net.momirealms.craftengine.core.world.Vec3d; + +import javax.annotation.Nullable; +import java.util.Optional; + +public class AABB { + private static final double EPSILON = 1.0E-7; + public final double minX; + public final double minY; + public final double minZ; + public final double maxX; + public final double maxY; + public final double maxZ; + + public AABB(double x1, double y1, double z1, double x2, double y2, double z2) { + this.minX = Math.min(x1, x2); + this.minY = Math.min(y1, y2); + this.minZ = Math.min(z1, z2); + this.maxX = Math.max(x1, x2); + this.maxY = Math.max(y1, y2); + this.maxZ = Math.max(z1, z2); + } + + public AABB(Vec3d pos1, Vec3d pos2) { + this.minX = Math.min(pos1.x, pos2.x); + this.minY = Math.min(pos1.y, pos2.y); + this.minZ = Math.min(pos1.z, pos2.z); + this.maxX = Math.max(pos1.x, pos2.x); + this.maxY = Math.max(pos1.y, pos2.y); + this.maxZ = Math.max(pos1.z, pos2.z); + } + + public static AABB fromInteraction(Vec3d pos, double width, double height) { + return new AABB( + pos.x - width / 2, + pos.y, + pos.z - width / 2, + pos.x + width / 2, + pos.y + height, + pos.z + width / 2 + ); + } + + public Optional clip(Vec3d min, Vec3d max) { + double[] traceDistance = {1.0}; + double deltaX = max.x - min.x; + double deltaY = max.y - min.y; + double deltaZ = max.z - min.z; + + Direction direction = calculateCollisionDirection(min, traceDistance, deltaX, deltaY, deltaZ); + return direction != null + ? Optional.of(new EntityHitResult(direction, min.add(traceDistance[0] * deltaX, traceDistance[0] * deltaY, traceDistance[0] * deltaZ))) + : Optional.empty(); + } + + private Direction calculateCollisionDirection(Vec3d intersectingVector, double[] traceDistance, double deltaX, double deltaY, double deltaZ) { + Direction direction = null; + + // Check each axis for potential collision + direction = checkAxis(deltaX, deltaY, deltaZ, Direction.WEST, Direction.EAST, + minX, maxX, intersectingVector.x, intersectingVector.y, intersectingVector.z, + minY, maxY, minZ, maxZ, traceDistance, direction); + + direction = checkAxis(deltaY, deltaZ, deltaX, Direction.DOWN, Direction.UP, + minY, maxY, intersectingVector.y, intersectingVector.z, intersectingVector.x, + minZ, maxZ, minX, maxX, traceDistance, direction); + + direction = checkAxis(deltaZ, deltaX, deltaY, Direction.NORTH, Direction.SOUTH, + minZ, maxZ, intersectingVector.z, intersectingVector.x, intersectingVector.y, + minX, maxX, minY, maxY, traceDistance, direction); + + return direction; + } + + private Direction checkAxis(double primaryDelta, double secondary1Delta, double secondary2Delta, + Direction positiveDir, Direction negativeDir, + double positiveFace, double negativeFace, + double startPrimary, double startSecondary1, double startSecondary2, + double secondary1Min, double secondary1Max, + double secondary2Min, double secondary2Max, + double[] traceDistance, @Nullable Direction currentDir) { + if (primaryDelta > EPSILON) { + return checkFace(traceDistance, currentDir, positiveFace, + primaryDelta, secondary1Delta, secondary2Delta, + secondary1Min, secondary1Max, secondary2Min, secondary2Max, + positiveDir, startPrimary, startSecondary1, startSecondary2); + } else if (primaryDelta < -EPSILON) { + return checkFace(traceDistance, currentDir, negativeFace, + primaryDelta, secondary1Delta, secondary2Delta, + secondary1Min, secondary1Max, secondary2Min, secondary2Max, + negativeDir, startPrimary, startSecondary1, startSecondary2); + } + return currentDir; + } + + private static Direction checkFace(double[] traceDistance, @Nullable Direction currentDir, + double facePosition, + double primaryDelta, double secondary1Delta, double secondary2Delta, + double secondary1Min, double secondary1Max, + double secondary2Min, double secondary2Max, + Direction direction, + double startPrimary, double startSecondary1, double startSecondary2) { + double d = (facePosition - startPrimary) / primaryDelta; + if (d <= 0.0 || d >= traceDistance[0]) { + return currentDir; + } + + double secondary1 = startSecondary1 + d * secondary1Delta; + double secondary2 = startSecondary2 + d * secondary2Delta; + + if (isWithinBounds(secondary1, secondary1Min, secondary1Max) && + isWithinBounds(secondary2, secondary2Min, secondary2Max)) { + traceDistance[0] = d; + return direction; + } + return currentDir; + } + + private static boolean isWithinBounds(double value, double min, double max) { + return (value >= min - EPSILON) && (value <= max + EPSILON); + } +} diff --git a/gradle.properties b/gradle.properties index 679d4e46e..b1e4b0865 100644 --- a/gradle.properties +++ b/gradle.properties @@ -51,7 +51,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 anti_grief_version=0.15 -nms_helper_version=0.59.7 +nms_helper_version=0.59.8 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 amazon_awssdk_eventstream_version=1.0.1