9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-30 20:39:10 +00:00

更好的碰撞方案

This commit is contained in:
XiaoMoMi
2025-04-22 17:19:06 +08:00
parent a0e1041d86
commit 493601fb11
14 changed files with 63 additions and 50 deletions

View File

@@ -1,16 +1,17 @@
package net.momirealms.craftengine.bukkit.entity.furniture;
import net.momirealms.craftengine.bukkit.nms.CollisionEntity;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
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;
public BukkitCollider(Object world, Object aabb, double x, double y, double z, boolean canProjectileHit, boolean canCollide, boolean blocksBuilding) {
this.collisionEntity = BukkitFurnitureManager.COLLISION_ENTITY_TYPE == ColliderType.INTERACTION ?
FastNMS.INSTANCE.createCollisionInteraction(world, aabb, x, y, z, canProjectileHit, canCollide, blocksBuilding) :
FastNMS.INSTANCE.createCollisionBoat(world, aabb, x, y, z, canProjectileHit, canCollide, blocksBuilding);
}
@Override
@@ -23,11 +24,6 @@ public class BukkitCollider implements Collider {
return this.collisionEntity.getId();
}
@Override
public ColliderType type() {
return this.type;
}
@Override
public Object handle() {
return this.collisionEntity;

View File

@@ -39,6 +39,9 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
public static final NamespacedKey FURNITURE_SEAT_BASE_ENTITY_KEY = Objects.requireNonNull(NamespacedKey.fromString("craftengine:seat_to_base_entity"));
public static final NamespacedKey FURNITURE_SEAT_VECTOR_3F_KEY = Objects.requireNonNull(NamespacedKey.fromString("craftengine:seat_vector"));
public static final NamespacedKey FURNITURE_COLLISION = Objects.requireNonNull(NamespacedKey.fromString("craftengine:collision"));
public static Class<?> COLLISION_ENTITY_CLASS = Interaction.class;
public static Object NMS_COLLISION_ENTITY_TYPE = Reflections.instance$EntityType$INTERACTION;
public static ColliderType COLLISION_ENTITY_TYPE = ColliderType.INTERACTION;
private static BukkitFurnitureManager instance;
private final BukkitCraftEngine plugin;
private final FurnitureParser furnitureParser;
@@ -204,6 +207,9 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
@Override
public void delayedInit() {
COLLISION_ENTITY_CLASS = Config.colliderType() == ColliderType.INTERACTION ? Interaction.class : Boat.class;
NMS_COLLISION_ENTITY_TYPE = Config.colliderType() == ColliderType.INTERACTION ? Reflections.instance$EntityType$INTERACTION : Reflections.instance$EntityType$OAK_BOAT;
COLLISION_ENTITY_TYPE = Config.colliderType();
Bukkit.getPluginManager().registerEvents(this.dismountListener, this.plugin.bootstrap());
Bukkit.getPluginManager().registerEvents(this.furnitureEventListener, this.plugin.bootstrap());
for (World world : Bukkit.getWorlds()) {
@@ -211,8 +217,11 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
for (Entity entity : entities) {
if (entity instanceof ItemDisplay display) {
handleBaseEntityLoadEarly(display);
} else if (entity instanceof Interaction interaction) {
handleCollisionEntityLoadOnEntitiesLoad(interaction);
} else if (COLLISION_ENTITY_CLASS.isInstance(entity)) {
handleCollisionEntityLoadOnEntitiesLoad(entity);
} else if (entity instanceof Shulker shulker) {
// TODO 移除这一行,预计过一个月
handleCollisionEntityLoadOnEntitiesLoad(shulker);
}
}
}
@@ -310,29 +319,29 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
this.plugin.scheduler().sync().runLater(() -> handleBaseEntityLoadLate(display, depth + 1), 1, location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4);
}
protected void handleCollisionEntityLoadLate(Interaction interaction, int depth) {
// remove the interaction if it's not a collision entity, it might be wrongly copied by WorldEdit
if (FastNMS.INSTANCE.method$CraftEntity$getHandle(interaction) instanceof CollisionEntity) {
protected void handleCollisionEntityLoadLate(Entity entity, int depth) {
// remove the entity if it's not a collision entity, it might be wrongly copied by WorldEdit
if (FastNMS.INSTANCE.method$CraftEntity$getHandle(entity) instanceof CollisionEntity) {
return;
}
// not a collision entity
Byte flag = interaction.getPersistentDataContainer().get(FURNITURE_COLLISION, PersistentDataType.BYTE);
Byte flag = entity.getPersistentDataContainer().get(FURNITURE_COLLISION, PersistentDataType.BYTE);
if (flag == null || flag != 1) {
return;
}
Location location = interaction.getLocation();
Location location = entity.getLocation();
World world = location.getWorld();
int chunkX = location.getBlockX() >> 4;
int chunkZ = location.getBlockZ() >> 4;
if (!FastNMS.INSTANCE.isPreventingStatusUpdates(world, chunkX, chunkZ)) {
interaction.remove();
entity.remove();
return;
}
if (depth > 2) return;
plugin.scheduler().sync().runLater(() -> {
handleCollisionEntityLoadLate(interaction, depth + 1);
handleCollisionEntityLoadLate(entity, depth + 1);
}, 1, world, chunkX, chunkZ);
}
@@ -364,20 +373,20 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
}
}
public void handleCollisionEntityLoadOnEntitiesLoad(Interaction interaction) {
public void handleCollisionEntityLoadOnEntitiesLoad(Entity collisionEntity) {
// faster
if (FastNMS.INSTANCE.method$CraftEntity$getHandle(interaction) instanceof CollisionEntity) {
interaction.remove();
if (FastNMS.INSTANCE.method$CraftEntity$getHandle(collisionEntity) instanceof CollisionEntity) {
collisionEntity.remove();
return;
}
// not a collision entity
Byte flag = interaction.getPersistentDataContainer().get(FURNITURE_COLLISION, PersistentDataType.BYTE);
Byte flag = collisionEntity.getPersistentDataContainer().get(FURNITURE_COLLISION, PersistentDataType.BYTE);
if (flag == null || flag != 1) {
return;
}
interaction.remove();
collisionEntity.remove();
}
private AnchorType getAnchorType(Entity baseEntity, CustomFurniture furniture) {

View File

@@ -2,7 +2,10 @@ package net.momirealms.craftengine.bukkit.entity.furniture;
import com.destroystokyo.paper.event.entity.EntityAddToWorldEvent;
import com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent;
import org.bukkit.entity.*;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Entity;
import org.bukkit.entity.ItemDisplay;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
@@ -33,8 +36,8 @@ public class FurnitureEventListener implements Listener {
for (Entity entity : entities) {
if (entity instanceof ItemDisplay itemDisplay) {
this.manager.handleBaseEntityLoadEarly(itemDisplay);
} else if (entity instanceof Interaction interaction) {
this.manager.handleCollisionEntityLoadOnEntitiesLoad(interaction);
} else if (BukkitFurnitureManager.COLLISION_ENTITY_CLASS.isInstance(entity)) {
this.manager.handleCollisionEntityLoadOnEntitiesLoad(entity);
}
}
}
@@ -45,8 +48,8 @@ public class FurnitureEventListener implements Listener {
for (Entity entity : entities) {
if (entity instanceof ItemDisplay itemDisplay) {
this.manager.handleBaseEntityLoadEarly(itemDisplay);
} else if (entity instanceof Interaction interaction) {
this.manager.handleCollisionEntityLoadOnEntitiesLoad(interaction);
} else if (BukkitFurnitureManager.COLLISION_ENTITY_CLASS.isInstance(entity)) {
this.manager.handleCollisionEntityLoadOnEntitiesLoad(entity);
}
}
}
@@ -56,8 +59,8 @@ public class FurnitureEventListener implements Listener {
Entity entity = event.getEntity();
if (entity instanceof ItemDisplay itemDisplay) {
this.manager.handleBaseEntityLoadLate(itemDisplay, 0);
} else if (entity instanceof Interaction interaction) {
this.manager.handleCollisionEntityLoadLate(interaction, 0);
} else if (BukkitFurnitureManager.COLLISION_ENTITY_CLASS.isInstance(entity)) {
this.manager.handleCollisionEntityLoadLate(entity, 0);
}
}
@@ -70,7 +73,7 @@ public class FurnitureEventListener implements Listener {
for (Entity entity : entities) {
if (entity instanceof ItemDisplay) {
this.manager.handleBaseEntityUnload(entity);
} else if (entity instanceof Interaction) {
} else if (BukkitFurnitureManager.COLLISION_ENTITY_CLASS.isInstance(entity)) {
this.manager.handleCollisionEntityUnload(entity);
}
}
@@ -82,7 +85,7 @@ public class FurnitureEventListener implements Listener {
for (Entity entity : entities) {
if (entity instanceof ItemDisplay) {
this.manager.handleBaseEntityUnload(entity);
} else if (entity instanceof Interaction) {
} else if (BukkitFurnitureManager.COLLISION_ENTITY_CLASS.isInstance(entity)) {
this.manager.handleCollisionEntityUnload(entity);
}
}
@@ -93,7 +96,7 @@ public class FurnitureEventListener implements Listener {
Entity entity = event.getEntity();
if (entity instanceof ItemDisplay) {
this.manager.handleBaseEntityUnload(entity);
} else if (entity instanceof Interaction) {
} else if (BukkitFurnitureManager.COLLISION_ENTITY_CLASS.isInstance(entity)) {
this.manager.handleCollisionEntityUnload(entity);
}
}

View File

@@ -65,10 +65,7 @@ public class InteractionHitBox extends AbstractHitBox {
if (blocksBuilding() || this.canBeHitByProjectile()) {
AABB ceAABB = AABB.fromInteraction(new Vec3d(x + offset.x, y + offset.y, z - offset.z), this.size.x, this.size.y);
Object nmsAABB = FastNMS.INSTANCE.constructor$AABB(ceAABB.minX, ceAABB.minY, ceAABB.minZ, ceAABB.maxX, ceAABB.maxY, ceAABB.maxZ);
collider.accept(new BukkitCollider(
FastNMS.INSTANCE.createCollisionInteraction(world.serverWorld(), nmsAABB, x, y, z, this.canBeHitByProjectile(), false, this.blocksBuilding()),
ColliderType.SHULKER
));
collider.accept(new BukkitCollider(world.serverWorld(), nmsAABB, x, y, z, this.canBeHitByProjectile(), false, this.blocksBuilding()));
}
}

View File

@@ -127,10 +127,7 @@ public class ShulkerHitBox extends AbstractHitBox {
Object level = world.serverWorld();
Object nmsAABB = FastNMS.INSTANCE.constructor$AABB(ceAABB.minX, ceAABB.minY, ceAABB.minZ, ceAABB.maxX, ceAABB.maxY, ceAABB.maxZ);
aabb.accept(entityId, ceAABB);
return new BukkitCollider(
FastNMS.INSTANCE.createCollisionInteraction(level, nmsAABB, x, y, z, this.canBeHitByProjectile(), true, this.blocksBuilding()),
ColliderType.SHULKER
);
return new BukkitCollider(level, nmsAABB, x, y, z, this.canBeHitByProjectile(), true, this.blocksBuilding());
}
public AABB createAABB(Direction direction, Vector3f offset, double x, double y, double z) {

View File

@@ -24,7 +24,6 @@ import net.momirealms.craftengine.core.world.Vec3d;
import net.momirealms.craftengine.core.world.collision.AABB;
import org.bukkit.Location;
import org.bukkit.World;
import org.joml.Quaternionf;
import java.nio.file.Path;
import java.util.ArrayList;

View File

@@ -1516,7 +1516,7 @@ public class PacketConsumers {
event.setCancelled(true);
}
}
} else if (entityType == Reflections.instance$EntityType$INTERACTION) {
} else if (entityType == BukkitFurnitureManager.NMS_COLLISION_ENTITY_TYPE) {
// Cancel collider entity packet
int entityId = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$entityId(packet);
LoadedFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(entityId);

View File

@@ -3773,6 +3773,7 @@ public class Reflections {
public static final Object instance$EntityType$FALLING_BLOCK;
public static final Object instance$EntityType$INTERACTION;
public static final Object instance$EntityType$SHULKER;
public static final Object instance$EntityType$OAK_BOAT;
static {
try {
@@ -3790,6 +3791,8 @@ public class Reflections {
instance$EntityType$SHULKER = Reflections.method$Registry$get.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, shulker);
Object armorStand = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "armor_stand");
instance$EntityType$ARMOR_STAND = Reflections.method$Registry$get.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, armorStand);
Object oakBoat = VersionHelper.isVersionNewerThan1_21_2() ? FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "oak_boat") : FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "boat");
instance$EntityType$OAK_BOAT = Reflections.method$Registry$get.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, oakBoat);
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}