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 7f6fa3f4d..77e8964d3 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 @@ -3,6 +3,7 @@ package net.momirealms.craftengine.bukkit.entity.furniture; import net.momirealms.craftengine.bukkit.compatibility.bettermodel.BetterModelModel; import net.momirealms.craftengine.bukkit.compatibility.modelengine.ModelEngineModel; import net.momirealms.craftengine.bukkit.entity.furniture.hitbox.InteractionHitBox; +import net.momirealms.craftengine.bukkit.nms.CollisionEntity; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.util.EntityUtils; @@ -26,6 +27,7 @@ import org.jetbrains.annotations.NotNull; import org.joml.Vector3f; import javax.annotation.Nullable; +import java.lang.reflect.InvocationTargetException; import java.nio.file.Path; import java.util.*; import java.util.concurrent.ConcurrentHashMap; @@ -42,6 +44,7 @@ public class BukkitFurnitureManager implements FurnitureManager { private final Map furnitureByBaseEntityId = new ConcurrentHashMap<>(256, 0.5f); private final Map furnitureByEntityId = new ConcurrentHashMap<>(512, 0.5f); + private final Map furnitureByCollisionEntitiesId = new ConcurrentHashMap<>(256, 0.5f); // Event listeners private final Listener dismountListener; private final FurnitureEventListener furnitureEventListener; @@ -270,6 +273,11 @@ public class BukkitFurnitureManager implements FurnitureManager { return this.furnitureByEntityId.get(entityId); } + @Nullable + public LoadedFurniture getLoadedFurnitureByCollisionEntityId(int entityId) { + return this.furnitureByCollisionEntitiesId.get(entityId); + } + protected void handleBaseFurnitureUnload(Entity entity) { int id = entity.getEntityId(); LoadedFurniture furniture = this.furnitureByBaseEntityId.remove(id); @@ -348,6 +356,14 @@ public class BukkitFurnitureManager implements FurnitureManager { for (int entityId : loadedFurniture.entityIds()) { this.furnitureByEntityId.put(entityId, loadedFurniture); } + for (CollisionEntity collisionEntity : loadedFurniture.collisionEntities()) { + try { + int collisionEntityId = (int) Reflections.method$Entity$getId.invoke(collisionEntity); + this.furnitureByCollisionEntitiesId.put(collisionEntityId, loadedFurniture); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } return loadedFurniture; } @@ -377,7 +393,7 @@ public class BukkitFurnitureManager implements FurnitureManager { Location vehicleLocation = vehicle.getLocation(); Location originalLocation = vehicleLocation.clone(); originalLocation.setY(furniture.location().getY()); - Location targetLocation = originalLocation.clone().add(vehicleLocation.getDirection()); + Location targetLocation = originalLocation.clone().add(vehicleLocation.getDirection().multiply(1.1)); if (!isSafeLocation(targetLocation)) { targetLocation = findSafeLocationNearby(originalLocation); if (targetLocation == null) return; @@ -426,7 +442,7 @@ public class BukkitFurnitureManager implements FurnitureManager { World world = location.getWorld(); if (world == null) return true; try { - Collection nearbyEntities = world.getNearbyEntities(location, 0.5, 2, 0.5); + Collection nearbyEntities = world.getNearbyEntities(location, 0.38, 2, 0.38); for (Entity bukkitEntity : nearbyEntities) { if (bukkitEntity instanceof Player) continue; Object nmsEntity = FastNMS.INSTANCE.method$CraftEntity$getHandle(bukkitEntity); 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 6d79a3080..7f2f9c3e0 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 @@ -41,6 +41,7 @@ public class LoadedFurniture { private final Map hitBoxes; private final boolean minimized; private final boolean hasExternalModel; + private final CustomFurniture.Placement placement; // seats private final Set occupiedSeats = Collections.synchronizedSet(new HashSet<>()); private final Vector seats = new Vector<>(); @@ -64,6 +65,7 @@ public class LoadedFurniture { mainEntityIds.add(this.baseEntityId); CustomFurniture.Placement placement = furniture.getPlacement(anchorType); + this.placement = placement; // bind external furniture Optional optionalExternal = placement.externalModel(); if (optionalExternal.isPresent()) { @@ -240,6 +242,10 @@ public class LoadedFurniture { return Collections.unmodifiableList(this.fakeEntityIds); } + public CollisionEntity[] collisionEntities() { + return this.collisionEntities; + } + @NotNull public AnchorType anchorType() { return this.anchorType; @@ -259,6 +265,14 @@ public class LoadedFurniture { return hasExternalModel; } + public CustomFurniture.Placement placement() { + return this.placement; + } + + public Map hitBoxes() { + return this.hitBoxes; + } + public void spawnSeatEntityForPlayer(org.bukkit.entity.Player player, Seat seat) { Location location = this.calculateSeatLocation(seat); Entity seatEntity = seat.limitPlayerRotation() ? 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 57aa921a4..2c3362f93 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 @@ -37,6 +37,7 @@ public class ShulkerHitBox extends AbstractHitBox { this.interactionEntity = interactionEntity; ShulkerData.Peek.addEntityDataIfNotDefaultValue(peek, this.cachedShulkerValues); + ShulkerData.Color.addEntityDataIfNotDefaultValue((byte) 0, this.cachedShulkerValues); // ShulkerData.AttachFace.addEntityDataIfNotDefaultValue(DirectionUtils.toNMSDirection(direction), this.cachedShulkerValues); ShulkerData.NoGravity.addEntityDataIfNotDefaultValue(true, this.cachedShulkerValues); ShulkerData.Silent.addEntityDataIfNotDefaultValue(true, this.cachedShulkerValues); @@ -44,7 +45,7 @@ public class ShulkerHitBox extends AbstractHitBox { ShulkerData.SharedFlags.addEntityDataIfNotDefaultValue((byte) 0x20, this.cachedShulkerValues); // 不可见 if (this.interactionEntity) { - InteractionEntityData.Height.addEntityDataIfNotDefaultValue((float) ((1 + getPeekHeight(peek)) * scale) + 0.001f, cachedInteractionValues); + InteractionEntityData.Height.addEntityDataIfNotDefaultValue(getPeekHeight(peek, scale) + 0.001f, cachedInteractionValues); InteractionEntityData.Width.addEntityDataIfNotDefaultValue((float) scale + 0.001f, cachedInteractionValues); InteractionEntityData.Responsive.addEntityDataIfNotDefaultValue(interactive, cachedInteractionValues); } @@ -56,12 +57,17 @@ public class ShulkerHitBox extends AbstractHitBox { true, position(), (float) scale(), - 1 + getPeekHeight(peek()) + getPeekHeight(peek(), scale()) )); } - private static float getPeekHeight(byte peek) { - return (float) (0.5F - Math.sin((0.5F + peek * 0.01F) * 3.1415927F) * 0.5F); + private static float getPeekHeight(byte peek, double scale) { + double sineValue = Math.sin( + (0.5 + peek * 0.01) * Math.PI + ); + return (float) ( + (1.0 + (0.5 - sineValue * 0.5)) * scale + ); } public boolean interactionEntity() { 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 cd71a2638..c3782a22c 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 @@ -625,6 +625,13 @@ public class PacketConsumers { event.setCancelled(true); } } + } else if (entityType == Reflections.instance$EntityType$INTERACTION) { + // 取消服务端碰撞实体 + int entityId = (int) Reflections.field$ClientboundAddEntityPacket$entityId.get(packet); + LoadedFurniture furniture = BukkitFurnitureManager.instance().getLoadedFurnitureByCollisionEntityId(entityId); + if (furniture != null) { + event.setCancelled(true); + } } } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundAddEntityPacket", e); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index 073b30bdf..16ecc73d9 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -38,6 +38,7 @@ import java.util.function.Consumer; import static java.util.Objects.requireNonNull; +@SuppressWarnings("unused") public class Reflections { public static void init() { @@ -5917,4 +5918,16 @@ public class Reflections { clazz$CraftEntity, clazz$Entity, 0 ) ); + + public static final Method method$Entity$getId = requireNonNull( + VersionHelper.isVersionNewerThan1_20_5() + ? ReflectionUtils.getMethod(clazz$Entity, int.class, new String[]{"getId"}) + : VersionHelper.isVersionNewerThan1_20_3() + ? ReflectionUtils.getMethod(clazz$Entity, int.class, new String[]{"aj"}) + : VersionHelper.isVersionNewerThan1_20_2() + ? ReflectionUtils.getMethod(clazz$Entity, int.class, new String[]{"ah"}) + : VersionHelper.isVersionNewerThan1_20() + ? ReflectionUtils.getMethod(clazz$Entity, int.class, new String[]{"af"}) + : ReflectionUtils.getMethod(clazz$Entity, int.class, new String[]{"getId", "aj", "ah", "af"}) + ); }