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-21 03:01:49 +08:00
parent a219b7549d
commit 37c507b45f
19 changed files with 373 additions and 126 deletions

View File

@@ -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;
}
}

View File

@@ -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<Object> packets) {
public void initPackets(int entityId, World world, double x, double y, double z, float yaw, Quaternionf conjugated, Consumer<Object> 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,

View File

@@ -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;

View File

@@ -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<Entity> baseEntity;
private final int baseEntityId;
// colliders
private final CollisionEntity[] collisionEntities;
private final Collider[] colliderEntities;
// cache
private final List<Integer> fakeEntityIds;
private final List<Integer> entityIds;
private final Map<Integer, HitBox> hitBoxes;
private final Map<Integer, HitBox> hitBoxes = new HashMap<>();
private final Map<Integer, AABB> aabb = new HashMap<>();
private final boolean minimized;
private final boolean hasExternalModel;
// seats
private final Set<Vector3f> occupiedSeats = Collections.synchronizedSet(new HashSet<>());
private final Vector<Entity> seats = new Vector<>();
private final Vector<WeakReference<Entity>> 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<Integer> fakeEntityIds = new ArrayList<>();
List<Integer> mainEntityIds = new ArrayList<>();
@@ -92,10 +92,11 @@ public class LoadedFurniture implements Furniture {
List<Object> minimizedPackets = new ArrayList<>();
List<Collider> 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<Entity> 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> 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);
}

View File

@@ -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<Object> 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<Object, Boolean> packets, Consumer<Collider> collider) {
public void initPacketsAndColliders(int[] entityId, World world, double x, double y, double z, float yaw, Quaternionf conjugated, BiConsumer<Object, Boolean> packets, Consumer<Collider> collider, BiConsumer<Integer, AABB> aabb) {
Vector3f offset = conjugated.transform(new Vector3f(position()));
try {
packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(

View File

@@ -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<Object, Boolean> packets, Consumer<Collider> collider) {
public void initPacketsAndColliders(int[] entityId, World world, double x, double y, double z, float yaw, Quaternionf conjugated, BiConsumer<Object, Boolean> packets, Consumer<Collider> collider, BiConsumer<Integer, AABB> aabb) {
// todo 乐魂
}
@@ -44,10 +46,11 @@ public class HappyGhastHitBox extends AbstractHitBox {
@Override
public HitBox create(Map<String, Object> 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
);
}
}

View File

@@ -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<Object> 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<Object, Boolean> packets, Consumer<Collider> collider) {
public void initPacketsAndColliders(int[] entityId, World world, double x, double y, double z, float yaw, Quaternionf conjugated, BiConsumer<Object, Boolean> packets, Consumer<Collider> collider, BiConsumer<Integer, AABB> 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
);
}
}

View File

@@ -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<Object> 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<Object> 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<Integer, AABB> 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<Object, Boolean> packets, Consumer<Collider> collider) {
public void initPacketsAndColliders(int[] entityIds, World world, double x, double y, double z, float yaw, Quaternionf conjugated, BiConsumer<Object, Boolean> packets, Consumer<Collider> collider, BiConsumer<Integer, AABB> 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<Object, Boolean> packets, Consumer<Collider> collider);
void accept(int[] entityIds, World world, double x, double y, double z, float yaw, Vector3f offset, BiConsumer<Object, Boolean> packets, Consumer<Collider> collider, BiConsumer<Integer, AABB> 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
);
}
}

View File

@@ -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<ItemStack> 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<EntityHitResult> 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) {