9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-19 15:09:15 +00:00

家具重构part4

This commit is contained in:
XiaoMoMi
2025-12-03 04:45:29 +08:00
parent d2bb9103bd
commit 34cb3936b0
17 changed files with 533 additions and 150 deletions

View File

@@ -1,12 +1,10 @@
package net.momirealms.craftengine.bukkit.api.event;
import net.momirealms.craftengine.core.entity.furniture.AnchorType;
import net.momirealms.craftengine.core.entity.furniture.FurnitureConfig;
import net.momirealms.craftengine.core.entity.furniture.FurnitureVariant;
import net.momirealms.craftengine.core.entity.player.InteractionHand;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;

View File

@@ -153,7 +153,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
}
// 当元数据实体被卸载了
protected void handleMetaEntityUnload(Entity entity) {
protected void handleMetaEntityUnload(ItemDisplay entity) {
// 不是持久化的
if (!entity.isPersistent()) {
return;

View File

@@ -75,8 +75,8 @@ public class FurnitureEventListener implements Listener {
public void onChunkUnload(ChunkUnloadEvent event) {
Entity[] entities = event.getChunk().getEntities();
for (Entity entity : entities) {
if (entity instanceof ItemDisplay) {
this.manager.handleMetaEntityUnload(entity);
if (entity instanceof ItemDisplay itemDisplay) {
this.manager.handleMetaEntityUnload(itemDisplay);
} else if (BukkitFurnitureManager.COLLISION_ENTITY_CLASS.isInstance(entity)) {
this.manager.handleCollisionEntityUnload(entity);
}
@@ -87,8 +87,8 @@ public class FurnitureEventListener implements Listener {
public void onWorldUnload(WorldUnloadEvent event) {
List<Entity> entities = event.getWorld().getEntities();
for (Entity entity : entities) {
if (entity instanceof ItemDisplay) {
this.manager.handleMetaEntityUnload(entity);
if (entity instanceof ItemDisplay itemDisplay) {
this.manager.handleMetaEntityUnload(itemDisplay);
} else if (BukkitFurnitureManager.COLLISION_ENTITY_CLASS.isInstance(entity)) {
this.manager.handleCollisionEntityUnload(entity);
}
@@ -98,8 +98,8 @@ public class FurnitureEventListener implements Listener {
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onEntityUnload(EntityRemoveFromWorldEvent event) {
Entity entity = event.getEntity();
if (entity instanceof ItemDisplay) {
this.manager.handleMetaEntityUnload(entity);
if (entity instanceof ItemDisplay itemDisplay) {
this.manager.handleMetaEntityUnload(itemDisplay);
} else if (BukkitFurnitureManager.COLLISION_ENTITY_CLASS.isInstance(entity)) {
this.manager.handleCollisionEntityUnload(entity);
}

View File

@@ -2,11 +2,11 @@ package net.momirealms.craftengine.bukkit.entity.furniture.element;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import net.momirealms.craftengine.bukkit.entity.data.ItemDisplayEntityData;
import net.momirealms.craftengine.core.entity.furniture.FurnitureColorSource;
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
import net.momirealms.craftengine.core.entity.display.Billboard;
import net.momirealms.craftengine.core.entity.display.ItemDisplayContext;
import net.momirealms.craftengine.core.entity.furniture.Furniture;
import net.momirealms.craftengine.core.entity.furniture.FurnitureColorSource;
import net.momirealms.craftengine.core.entity.furniture.element.FurnitureElementConfig;
import net.momirealms.craftengine.core.entity.furniture.element.FurnitureElementConfigFactory;
import net.momirealms.craftengine.core.entity.player.Player;

View File

@@ -1,6 +1,5 @@
package net.momirealms.craftengine.bukkit.entity.furniture.hitbox;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import net.momirealms.craftengine.bukkit.entity.furniture.BukkitCollider;
import net.momirealms.craftengine.bukkit.entity.seat.BukkitSeat;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
@@ -8,7 +7,6 @@ import net.momirealms.craftengine.core.entity.furniture.Collider;
import net.momirealms.craftengine.core.entity.furniture.Furniture;
import net.momirealms.craftengine.core.entity.furniture.hitbox.FurnitureHitBox;
import net.momirealms.craftengine.core.entity.furniture.hitbox.FurnitureHitBoxConfig;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.entity.seat.Seat;
import net.momirealms.craftengine.core.entity.seat.SeatConfig;
import net.momirealms.craftengine.core.world.Vec3d;
@@ -51,13 +49,4 @@ public abstract class AbstractFurnitureHitBox implements FurnitureHitBox {
Object nmsAABB = FastNMS.INSTANCE.constructor$AABB(ceAABB.minX, ceAABB.minY, ceAABB.minZ, ceAABB.maxX, ceAABB.maxY, ceAABB.maxZ);
return new BukkitCollider(world.serverWorld(), nmsAABB, position.x, position.y, position.z, canBeHitByProjectile, canCollide, blocksBuilding);
}
protected Object createDespawnPacket(int[] entityIds) {
return FastNMS.INSTANCE.constructor$ClientboundRemoveEntitiesPacket(new IntArrayList(entityIds));
}
@Override
public void hide(Player player) {
player.sendPacket(createDespawnPacket(this.virtualEntityIds()), false);
}
}

View File

@@ -8,7 +8,7 @@ public class BukkitFurnitureHitboxTypes extends FurnitureHitBoxTypes {
static {
register(INTERACTION, InteractionFurnitureHitboxConfig.FACTORY);
// register(SHULKER, ShulkerFurnitureHitboxConfig.FACTORY);
register(SHULKER, ShulkerFurnitureHitboxConfig.FACTORY);
// register(HAPPY_GHAST, HappyGhastFurnitureHitboxConfig.FACTORY);
// register(CUSTOM, CustomFurnitureHitboxConfig.FACTORY);
}

View File

@@ -1,5 +1,6 @@
package net.momirealms.craftengine.bukkit.entity.furniture.hitbox;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import net.momirealms.craftengine.bukkit.entity.data.BaseEntityData;
import net.momirealms.craftengine.bukkit.entity.data.InteractionEntityData;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
@@ -7,6 +8,7 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflect
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityTypes;
import net.momirealms.craftengine.core.entity.furniture.Collider;
import net.momirealms.craftengine.core.entity.furniture.Furniture;
import net.momirealms.craftengine.core.entity.furniture.hitbox.FurnitureHitboxPart;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.world.Vec3d;
import net.momirealms.craftengine.core.world.WorldPosition;
@@ -15,24 +17,22 @@ import net.momirealms.craftengine.core.world.collision.AABB;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.function.Consumer;
public class InteractionFurnitureHitbox extends AbstractFurnitureHitBox {
private final InteractionFurnitureHitboxConfig config;
private final Vec3d position;
private final AABB aabb;
private final Collider collider;
private final int interactionId;
private final Object spawnPacket;
private final Object despawnPacket;
private final FurnitureHitboxPart part;
public InteractionFurnitureHitbox(Furniture furniture, InteractionFurnitureHitboxConfig config) {
super(furniture, config);
this.config = config;
WorldPosition position = furniture.position();
this.position = Furniture.getRelativePosition(position, config.position());
this.aabb = AABB.fromInteraction(this.position, config.size.x, config.size.y);
this.collider = createCollider(furniture.world(), this.position, this.aabb, false, config.blocksBuilding(), config.canBeHitByProjectile());
this.interactionId = CoreReflections.instance$Entity$ENTITY_COUNTER.incrementAndGet();
Vec3d pos = Furniture.getRelativePosition(position, config.position());
AABB aabb = AABB.fromInteraction(pos, config.size.x, config.size.y);
this.collider = createCollider(furniture.world(), pos, aabb, false, config.blocksBuilding(), config.canBeHitByProjectile());
int interactionId = CoreReflections.instance$Entity$ENTITY_COUNTER.incrementAndGet();
List<Object> values = new ArrayList<>(4);
InteractionEntityData.Height.addEntityDataIfNotDefaultValue(config.size.y, values);
InteractionEntityData.Width.addEntityDataIfNotDefaultValue(config.size.x, values);
@@ -42,11 +42,28 @@ public class InteractionFurnitureHitbox extends AbstractFurnitureHitBox {
}
this.spawnPacket = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(List.of(
FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(
this.interactionId, UUID.randomUUID(), position.x, position.y, position.z, 0, position.yRot,
interactionId, UUID.randomUUID(), position.x, position.y, position.z, 0, position.yRot,
MEntityTypes.INTERACTION, 0, CoreReflections.instance$Vec3$Zero, 0
),
FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(this.interactionId, values)
FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(interactionId, values)
));
this.part = new FurnitureHitboxPart(interactionId, aabb, pos);
this.despawnPacket = FastNMS.INSTANCE.constructor$ClientboundRemoveEntitiesPacket(new IntArrayList() {{ add(interactionId); }});
}
@Override
public List<Collider> colliders() {
return List.of(this.collider);
}
@Override
public List<FurnitureHitboxPart> parts() {
return List.of(this.part);
}
@Override
public InteractionFurnitureHitboxConfig config() {
return this.config;
}
@Override
@@ -55,31 +72,7 @@ public class InteractionFurnitureHitbox extends AbstractFurnitureHitBox {
}
@Override
public AABB[] aabb() {
return new AABB[] { this.aabb };
}
@Override
public Vec3d position() {
return this.position;
}
@Override
public List<Collider> colliders() {
return List.of(this.collider);
}
@Override
public int[] virtualEntityIds() {
return new int[] { this.interactionId };
}
@Override
public void collectVirtualEntityIds(Consumer<Integer> collector) {
collector.accept(this.interactionId);
}
public InteractionFurnitureHitboxConfig config() {
return this.config;
public void hide(Player player) {
player.sendPacket(this.despawnPacket, false);
}
}

View File

@@ -0,0 +1,131 @@
package net.momirealms.craftengine.bukkit.entity.furniture.hitbox;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MAttributeHolders;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityTypes;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections;
import net.momirealms.craftengine.core.entity.furniture.Collider;
import net.momirealms.craftengine.core.entity.furniture.Furniture;
import net.momirealms.craftengine.core.entity.furniture.hitbox.FurnitureHitboxPart;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.util.QuaternionUtils;
import net.momirealms.craftengine.core.util.VersionHelper;
import net.momirealms.craftengine.core.world.WorldPosition;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class ShulkerFurnitureHitbox extends AbstractFurnitureHitBox {
private final ShulkerFurnitureHitboxConfig config;
private final List<FurnitureHitboxPart> parts;
private final List<Collider> colliders;
private final Object spawnPacket;
private final Object despawnPacket;
public ShulkerFurnitureHitbox(Furniture furniture, ShulkerFurnitureHitboxConfig config) {
super(furniture, config);
this.config = config;
int[] entityIds = acquireEntityIds(CoreReflections.instance$Entity$ENTITY_COUNTER::incrementAndGet);
WorldPosition position = furniture.position();
Quaternionf conjugated = QuaternionUtils.toQuaternionf(0f, (float) Math.toRadians(180 - position.yRot()), 0f).conjugate();
Vector3f offset = conjugated.transform(new Vector3f(config.position()));
double x = position.x();
double y = position.y();
double z = position.z();
float yaw = position.yRot();
double originalY = y + offset.y;
double integerPart = Math.floor(originalY);
double fractionalPart = originalY - integerPart;
double processedY = (fractionalPart >= 0.5) ? integerPart + 1 : originalY;
List<Object> packets = new ArrayList<>();
List<Collider> colliders = new ArrayList<>();
List<FurnitureHitboxPart> parts = new ArrayList<>();
packets.add(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(
entityIds[0], UUID.randomUUID(), x + offset.x, originalY, z - offset.z, 0, yaw,
MEntityTypes.ITEM_DISPLAY, 0, CoreReflections.instance$Vec3$Zero, 0
));
packets.add(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(
entityIds[1], UUID.randomUUID(), x + offset.x, processedY, z - offset.z, 0, yaw,
MEntityTypes.SHULKER, 0, CoreReflections.instance$Vec3$Zero, 0
));
packets.add(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityIds[1], List.copyOf(config.cachedShulkerValues)));
packets.add(FastNMS.INSTANCE.constructor$ClientboundSetPassengersPacket(entityIds[0], entityIds[1]));
// fix some special occasions
if (originalY != processedY) {
double deltaY = originalY - processedY;
short ya = (short) (deltaY * 8192);
try {
packets.add(NetworkReflections.constructor$ClientboundMoveEntityPacket$Pos.newInstance(
entityIds[1], (short) 0, ya, (short) 0, true
));
} catch (ReflectiveOperationException e) {
CraftEngine.instance().logger().warn("Failed to construct ClientboundMoveEntityPacket$Pos", e);
}
}
if (VersionHelper.isOrAbove1_20_5() && config.scale != 1) {
try {
Object attributeInstance = CoreReflections.constructor$AttributeInstance.newInstance(MAttributeHolders.SCALE, (Consumer<?>) (o) -> {});
CoreReflections.method$AttributeInstance$setBaseValue.invoke(attributeInstance, config.scale);
packets.add(NetworkReflections.constructor$ClientboundUpdateAttributesPacket0.newInstance(entityIds[1], Collections.singletonList(attributeInstance)));
} catch (ReflectiveOperationException e) {
CraftEngine.instance().logger().warn("Failed to apply scale attribute", e);
}
}
config.spawner.accept(entityIds, position.world(), x, y, z, yaw, offset, packets::add, colliders::add, parts::add);
this.parts = parts;
this.colliders = colliders;
this.spawnPacket = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(packets);
this.despawnPacket = FastNMS.INSTANCE.constructor$ClientboundRemoveEntitiesPacket(new IntArrayList(entityIds));
}
@Override
public List<Collider> colliders() {
return this.colliders;
}
@Override
public List<FurnitureHitboxPart> parts() {
return this.parts;
}
@Override
public void show(Player player) {
player.sendPacket(this.spawnPacket, false);
}
@Override
public void hide(Player player) {
player.sendPacket(this.despawnPacket, false);
}
@Override
public ShulkerFurnitureHitboxConfig config() {
return this.config;
}
public int[] acquireEntityIds(Supplier<Integer> entityIdSupplier) {
if (config.interactionEntity) {
if (config.direction.stepY() != 0) {
// 展示实体 // 潜影贝 // 交互实体
return new int[] {entityIdSupplier.get(), entityIdSupplier.get(), entityIdSupplier.get()};
} else {
// 展示实体 // 潜影贝 // 交互实体1 // 交互实体2
return new int[] {entityIdSupplier.get(), entityIdSupplier.get(), entityIdSupplier.get(), entityIdSupplier.get()};
}
} else {
// 展示实体 // 潜影贝
return new int[] {entityIdSupplier.get(), entityIdSupplier.get()};
}
}
}

View File

@@ -0,0 +1,317 @@
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.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityTypes;
import net.momirealms.craftengine.bukkit.util.DirectionUtils;
import net.momirealms.craftengine.core.entity.furniture.Collider;
import net.momirealms.craftengine.core.entity.furniture.Furniture;
import net.momirealms.craftengine.core.entity.furniture.hitbox.AbstractFurnitureHitBoxConfig;
import net.momirealms.craftengine.core.entity.furniture.hitbox.FurnitureHitBoxConfigFactory;
import net.momirealms.craftengine.core.entity.furniture.hitbox.FurnitureHitboxPart;
import net.momirealms.craftengine.core.entity.seat.SeatConfig;
import net.momirealms.craftengine.core.util.Direction;
import net.momirealms.craftengine.core.util.MiscUtils;
import net.momirealms.craftengine.core.util.QuaternionUtils;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import net.momirealms.craftengine.core.world.Vec3d;
import net.momirealms.craftengine.core.world.World;
import net.momirealms.craftengine.core.world.WorldPosition;
import net.momirealms.craftengine.core.world.collision.AABB;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.function.Consumer;
public class ShulkerFurnitureHitboxConfig extends AbstractFurnitureHitBoxConfig<ShulkerFurnitureHitbox> {
public static final Factory FACTORY = new Factory();
public final float scale;
public final byte peek;
public final boolean interactive;
public final boolean interactionEntity;
public final Direction direction;
public final DirectionalShulkerSpawner spawner;
public final List<Object> cachedShulkerValues = new ArrayList<>();
public final AABBCreator aabbCreator;
public ShulkerFurnitureHitboxConfig(SeatConfig[] seats,
Vector3f position,
boolean canUseItemOn,
boolean blocksBuilding,
boolean canBeHitByProjectile,
float scale,
byte peek,
boolean interactive,
boolean interactionEntity,
Direction direction) {
super(seats, position, canUseItemOn, blocksBuilding, canBeHitByProjectile);
this.scale = scale;
this.peek = peek;
this.interactive = interactive;
this.interactionEntity = interactionEntity;
this.direction = direction;
ShulkerData.Peek.addEntityDataIfNotDefaultValue(peek, this.cachedShulkerValues);
ShulkerData.Color.addEntityDataIfNotDefaultValue((byte) 0, this.cachedShulkerValues);
ShulkerData.NoGravity.addEntityDataIfNotDefaultValue(true, this.cachedShulkerValues);
ShulkerData.Silent.addEntityDataIfNotDefaultValue(true, this.cachedShulkerValues);
ShulkerData.MobFlags.addEntityDataIfNotDefaultValue((byte) 0x01, this.cachedShulkerValues); // NO AI
ShulkerData.SharedFlags.addEntityDataIfNotDefaultValue((byte) 0x20, this.cachedShulkerValues); // Invisible
List<Object> cachedInteractionValues = new ArrayList<>();
float shulkerHeight = (getPhysicalPeek(peek * 0.01F) + 1) * scale;
if (direction == Direction.UP) {
InteractionEntityData.Height.addEntityDataIfNotDefaultValue(shulkerHeight + 0.01f, cachedInteractionValues);
InteractionEntityData.Width.addEntityDataIfNotDefaultValue(scale + 0.005f, cachedInteractionValues);
InteractionEntityData.Responsive.addEntityDataIfNotDefaultValue(interactive, cachedInteractionValues);
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,
MEntityTypes.INTERACTION, 0, CoreReflections.instance$Vec3$Zero, 0
));
packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityIds[2], List.copyOf(cachedInteractionValues)));
if (canUseItemOn) {
Vec3d vec3d = new Vec3d(x + offset.x, y + offset.y, z - offset.z);
aabb.accept(new FurnitureHitboxPart(entityIds[2], AABB.fromInteraction(vec3d, scale, shulkerHeight), vec3d));
}
}
};
this.aabbCreator = (x, y, z, yaw, offset) -> createAABB(Direction.UP, offset, x, y, z);
} else if (direction == Direction.DOWN) {
InteractionEntityData.Height.addEntityDataIfNotDefaultValue(shulkerHeight + 0.01f, cachedInteractionValues);
InteractionEntityData.Width.addEntityDataIfNotDefaultValue(scale + 0.005f, cachedInteractionValues);
InteractionEntityData.Responsive.addEntityDataIfNotDefaultValue(interactive, cachedInteractionValues);
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(CoreReflections.instance$Direction$UP))));
if (interactionEntity) {
packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(
entityIds[2], UUID.randomUUID(), x + offset.x, y + offset.y - 0.005f - shulkerHeight + scale, z - offset.z, 0, yaw,
MEntityTypes.INTERACTION, 0, CoreReflections.instance$Vec3$Zero, 0
));
packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityIds[2], List.copyOf(cachedInteractionValues)));
if (canUseItemOn) {
Vec3d vec3d = new Vec3d(x + offset.x, y + offset.y - shulkerHeight + scale, z - offset.z);
aabb.accept(new FurnitureHitboxPart(entityIds[2], AABB.fromInteraction(vec3d, scale, shulkerHeight), vec3d));
}
}
};
this.aabbCreator = (x, y, z, yaw, offset) -> createAABB(Direction.DOWN, offset, x, y, z);
} else {
InteractionEntityData.Height.addEntityDataIfNotDefaultValue(scale + 0.01f, cachedInteractionValues);
InteractionEntityData.Width.addEntityDataIfNotDefaultValue(scale + 0.005f, cachedInteractionValues);
InteractionEntityData.Responsive.addEntityDataIfNotDefaultValue(interactive, cachedInteractionValues);
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, world, offset, x, y, z, entityIds[1], aabb));
packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityIds[1], List.of(ShulkerData.AttachFace.createEntityDataIfNotDefaultValue(DirectionUtils.toNMSDirection(shulkerAnchor)))));
if (interactionEntity) {
// first interaction
packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(
entityIds[2], UUID.randomUUID(), x + offset.x, y + offset.y - 0.005f, z - offset.z, 0, yaw,
MEntityTypes.INTERACTION, 0, CoreReflections.instance$Vec3$Zero, 0
));
packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityIds[2], List.copyOf(cachedInteractionValues)));
// second interaction
double distance = shulkerHeight - scale;
packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(
entityIds[3], UUID.randomUUID(), x + offset.x + shulkerDirection.stepX() * distance, y + offset.y - 0.005f, z - offset.z + shulkerDirection.stepZ() * distance, 0, yaw,
MEntityTypes.INTERACTION, 0, CoreReflections.instance$Vec3$Zero, 0
));
packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityIds[3], List.copyOf(cachedInteractionValues)));
if (canUseItemOn) {
Vec3d vec3d1 = new Vec3d(x + offset.x, y + offset.y, z - offset.z);
Vec3d vec3d2 = new Vec3d(x + offset.x + shulkerDirection.stepX() * distance, y + offset.y, z - offset.z + shulkerDirection.stepZ() * distance);
aabb.accept(new FurnitureHitboxPart(entityIds[2], AABB.fromInteraction(vec3d1, scale, scale), vec3d1));
aabb.accept(new FurnitureHitboxPart(entityIds[3], AABB.fromInteraction(vec3d2, scale, scale), vec3d2));
}
}
};
this.aabbCreator = (x, y, z, yaw, offset) -> {
Direction shulkerAnchor = getOriginalDirection(direction, Direction.fromYaw(yaw));
Direction shulkerDirection = shulkerAnchor.opposite();
return createAABB(shulkerDirection, offset, x, y, z);
};
}
}
public static float getPhysicalPeek(float peek) {
return 0.5F - MiscUtils.sin((0.5F + peek) * 3.1415927F) * 0.5F;
}
@Override
public void prepareForPlacement(WorldPosition targetPos, Consumer<AABB> aabbConsumer) {
if (this.blocksBuilding) {
Quaternionf conjugated = QuaternionUtils.toQuaternionf(0f, (float) Math.toRadians(180 - targetPos.yRot()), 0f).conjugate();
Vector3f offset = conjugated.transform(new Vector3f(position()));
aabbConsumer.accept(this.aabbCreator.create(targetPos.x, targetPos.y, targetPos.z, targetPos.yRot, offset));
}
}
public float scale() {
return scale;
}
public byte peek() {
return peek;
}
public boolean interactive() {
return interactive;
}
public boolean interactionEntity() {
return interactionEntity;
}
public Direction direction() {
return direction;
}
@Override
public ShulkerFurnitureHitbox create(Furniture furniture) {
return new ShulkerFurnitureHitbox(furniture, this);
}
@FunctionalInterface
public interface AABBCreator {
AABB create(double x, double y, double z, float yaw, Vector3f offset);
}
@FunctionalInterface
public interface DirectionalShulkerSpawner {
void accept(int[] entityIds,
World world,
double x,
double y,
double z,
float yaw,
Vector3f offset,
Consumer<Object> packets,
Consumer<Collider> collider,
Consumer<FurnitureHitboxPart> aabb);
}
public Collider createCollider(Direction direction, World world,
Vector3f offset, double x, double y, double z,
int entityId,
Consumer<FurnitureHitboxPart> aabb) {
AABB ceAABB = createAABB(direction, offset, x, y, z);
Object level = world.serverWorld();
Object nmsAABB = FastNMS.INSTANCE.constructor$AABB(ceAABB.minX, ceAABB.minY, ceAABB.minZ, ceAABB.maxX, ceAABB.maxY, ceAABB.maxZ);
aabb.accept(new FurnitureHitboxPart(entityId, ceAABB, new Vec3d(x, y, z)));
return new BukkitCollider(level, nmsAABB, x, y, z, this.canBeHitByProjectile(), true, this.blocksBuilding());
}
public AABB createAABB(Direction direction, Vector3f relativePos, double x, double y, double z) {
float peek = getPhysicalPeek(this.peek * 0.01F);
double x1 = -this.scale * 0.5;
double y1 = 0.0;
double z1 = -this.scale * 0.5;
double x2 = this.scale * 0.5;
double y2 = this.scale;
double z2 = this.scale * 0.5;
double dx = (double) direction.stepX() * peek * (double) this.scale;
if (dx > 0) {
x2 += dx;
} else if (dx < 0) {
x1 += dx;
}
double dy = (double) direction.stepY() * peek * (double) this.scale;
if (dy > 0) {
y2 += dy;
} else if (dy < 0) {
y1 += dy;
}
double dz = (double) direction.stepZ() * peek * (double) this.scale;
if (dz > 0) {
z2 += dz;
} else if (dz < 0) {
z1 += dz;
}
double minX = x + x1 + relativePos.x();
double maxX = x + x2 + relativePos.x();
double minY = y + y1 + relativePos.y();
double maxY = y + y2 + relativePos.y();
double minZ = z + z1 - relativePos.z();
double maxZ = z + z2 - relativePos.z();
return new AABB(minX, minY, minZ, maxX, maxY, maxZ);
}
public static Direction getOriginalDirection(Direction newDirection, Direction oldDirection) {
switch (newDirection) {
case NORTH -> {
return switch (oldDirection) {
case NORTH -> Direction.NORTH;
case SOUTH -> Direction.SOUTH;
case WEST -> Direction.EAST;
case EAST -> Direction.WEST;
default -> throw new IllegalStateException("Unexpected value: " + oldDirection);
};
}
case SOUTH -> {
return switch (oldDirection) {
case SOUTH -> Direction.NORTH;
case WEST -> Direction.WEST;
case EAST -> Direction.EAST;
case NORTH -> Direction.SOUTH;
default -> throw new IllegalStateException("Unexpected value: " + oldDirection);
};
}
case WEST -> {
return switch (oldDirection) {
case SOUTH -> Direction.EAST;
case WEST -> Direction.NORTH;
case EAST -> Direction.SOUTH;
case NORTH -> Direction.WEST;
default -> throw new IllegalStateException("Unexpected value: " + oldDirection);
};
}
case EAST -> {
return switch (oldDirection) {
case SOUTH -> Direction.WEST;
case WEST -> Direction.SOUTH;
case EAST -> Direction.NORTH;
case NORTH -> Direction.EAST;
default -> throw new IllegalStateException("Unexpected value: " + oldDirection);
};
}
default -> throw new IllegalStateException("Unexpected value: " + newDirection);
}
}
public static class Factory implements FurnitureHitBoxConfigFactory<ShulkerFurnitureHitbox> {
@Override
public ShulkerFurnitureHitboxConfig create(Map<String, Object> arguments) {
Vector3f position = ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("position", "0"), "position");
float scale = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("scale", "1"), "scale");
byte peek = (byte) ResourceConfigUtils.getAsInt(arguments.getOrDefault("peek", 0), "peek");
Direction directionEnum = ResourceConfigUtils.getAsEnum(arguments.get("direction"), Direction.class, Direction.UP);
boolean interactive = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("interactive", true), "interactive");
boolean interactionEntity = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("interaction-entity", true), "interaction-entity");
boolean canUseItemOn = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-use-item-on", true), "can-use-item-on");
boolean canBeHitByProjectile = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-be-hit-by-projectile", true), "can-be-hit-by-projectile");
boolean blocksBuilding = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blocks-building", true), "blocks-building");
return new ShulkerFurnitureHitboxConfig(
SeatConfig.fromObj(arguments.get("seats")),
position,
canUseItemOn, blocksBuilding, canBeHitByProjectile,
scale, peek, interactive, interactionEntity, directionEnum
);
}
}
}

View File

@@ -6,13 +6,11 @@ import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture;
import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.bukkit.util.DirectionUtils;
import net.momirealms.craftengine.bukkit.util.EventUtils;
import net.momirealms.craftengine.bukkit.util.LocationUtils;
import net.momirealms.craftengine.core.entity.furniture.FurnitureConfig;
import net.momirealms.craftengine.core.entity.furniture.FurnitureDataAccessor;
import net.momirealms.craftengine.core.entity.furniture.FurnitureVariant;
import net.momirealms.craftengine.core.entity.furniture.hitbox.FurnitureHitBox;
import net.momirealms.craftengine.core.entity.furniture.hitbox.FurnitureHitBoxConfig;
import net.momirealms.craftengine.core.entity.player.InteractionResult;
import net.momirealms.craftengine.core.entity.player.Player;
@@ -28,7 +26,10 @@ import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext;
import net.momirealms.craftengine.core.plugin.context.event.EventTrigger;
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
import net.momirealms.craftengine.core.util.*;
import net.momirealms.craftengine.core.util.Cancellable;
import net.momirealms.craftengine.core.util.ItemUtils;
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.WorldPosition;
import net.momirealms.craftengine.core.world.collision.AABB;

View File

@@ -60,6 +60,7 @@ import net.momirealms.craftengine.core.advancement.network.AdvancementHolder;
import net.momirealms.craftengine.core.advancement.network.AdvancementProgress;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.entity.furniture.hitbox.FurnitureHitBox;
import net.momirealms.craftengine.core.entity.furniture.hitbox.FurnitureHitboxPart;
import net.momirealms.craftengine.core.entity.player.InteractionHand;
import net.momirealms.craftengine.core.entity.seat.Seat;
import net.momirealms.craftengine.core.font.FontManager;
@@ -358,8 +359,6 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
registerNMSPacketConsumer(new EntityEventListener(), NetworkReflections.clazz$ClientboundEntityEventPacket);
registerNMSPacketConsumer(new MovePosAndRotateEntityListener(), NetworkReflections.clazz$ClientboundMoveEntityPacket$PosRot);
registerNMSPacketConsumer(new MovePosEntityListener(), NetworkReflections.clazz$ClientboundMoveEntityPacket$Pos);
registerNMSPacketConsumer(new RotateHeadListener(), NetworkReflections.clazz$ClientboundRotateHeadPacket);
registerNMSPacketConsumer(new SetEntityMotionListener(), NetworkReflections.clazz$ClientboundSetEntityMotionPacket);
registerNMSPacketConsumer(new FinishConfigurationListener(), NetworkReflections.clazz$ClientboundFinishConfigurationPacket);
registerNMSPacketConsumer(new LoginFinishedListener(), NetworkReflections.clazz$ClientboundLoginFinishedPacket);
registerNMSPacketConsumer(new UpdateTagsListener(), NetworkReflections.clazz$ClientboundUpdateTagsPacket);
@@ -1765,43 +1764,6 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
}
}
public static class RotateHeadListener implements NMSPacketListener {
@Override
public void onPacketSend(NetWorkUser user, NMSPacketEvent event, Object packet) {
int entityId;
try {
entityId = (int) NetworkReflections.methodHandle$ClientboundRotateHeadPacket$entityIdGetter.invokeExact(packet);
} catch (Throwable t) {
CraftEngine.instance().logger().warn("Failed to get entity id from ClientboundRotateHeadPacket", t);
return;
}
if (BukkitFurnitureManager.instance().isFurnitureMetaEntity(entityId)) {
System.out.println("RotateHeadListener");
event.setCancelled(true);
}
}
}
public static class SetEntityMotionListener implements NMSPacketListener {
@Override
public void onPacketSend(NetWorkUser user, NMSPacketEvent event, Object packet) {
if (!VersionHelper.isOrAbove1_21_6()) return;
int entityId;
try {
entityId = (int) NetworkReflections.methodHandle$ClientboundSetEntityMotionPacket$idGetter.invokeExact(packet);
} catch (Throwable t) {
CraftEngine.instance().logger().warn("Failed to get entity id from ClientboundSetEntityMotionPacket", t);
return;
}
if (BukkitFurnitureManager.instance().isFurnitureMetaEntity(entityId)) {
System.out.println("SetEntityMotionListener");
event.setCancelled(true);
}
}
}
public static class FinishConfigurationListener implements NMSPacketListener {
@SuppressWarnings("unchecked")
@@ -3726,11 +3688,13 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
// 先检查碰撞箱部分是否存在
FurnitureHitBox hitBox = furniture.hitboxByEntityId(entityId);
if (hitBox == null) return;
Vec3d pos = hitBox.position();
// 检查玩家是否能破坏此点
if (!serverPlayer.canInteractPoint(pos, 16d)) {
return;
for (FurnitureHitboxPart part : hitBox.parts()) {
if (part.entityId() == entityId) {
// 检查玩家是否能破坏此点
if (!serverPlayer.canInteractPoint(part.pos(), 16d)) {
return;
}
}
}
FurnitureAttemptBreakEvent preBreakEvent = new FurnitureAttemptBreakEvent(serverPlayer.platformPlayer(), furniture);
@@ -3787,10 +3751,18 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
// 先检查碰撞箱部分是否存在
FurnitureHitBox hitBox = furniture.hitboxByEntityId(entityId);
if (hitBox == null) return;
Vec3d pos = hitBox.position();
// 检测距离
if (!serverPlayer.canInteractPoint(pos, 16d)) {
FurnitureHitboxPart part = null;
for (FurnitureHitboxPart p : hitBox.parts()) {
if (p.entityId() == entityId) {
Vec3d pos = p.pos();
// 检测距离
if (!serverPlayer.canInteractPoint(pos, 16d)) {
return;
}
part = p;
}
}
if (part == null) {
return;
}
@@ -3799,7 +3771,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
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));
Optional<EntityHitResult> result = part.aabb().clip(LocationUtils.toVec3d(eyeLocation), LocationUtils.toVec3d(endLocation));
if (result.isEmpty()) {
return;
}

View File

@@ -33,9 +33,4 @@ public class FurniturePacketHandler implements EntityPacketHandler {
public void handleMove(NetWorkUser user, NMSPacketEvent event, Object packet) {
event.setCancelled(true);
}
@Override
public void handleMoveAndRotate(NetWorkUser user, NMSPacketEvent event, Object packet) {
event.setCancelled(true);
}
}

View File

@@ -10,6 +10,7 @@ import net.momirealms.craftengine.core.entity.furniture.element.FurnitureElement
import net.momirealms.craftengine.core.entity.furniture.element.FurnitureElementConfig;
import net.momirealms.craftengine.core.entity.furniture.hitbox.FurnitureHitBox;
import net.momirealms.craftengine.core.entity.furniture.hitbox.FurnitureHitBoxConfig;
import net.momirealms.craftengine.core.entity.furniture.hitbox.FurnitureHitboxPart;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.entity.seat.Seat;
import net.momirealms.craftengine.core.plugin.entityculling.CullingData;
@@ -24,13 +25,12 @@ import org.jetbrains.annotations.Nullable;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import java.lang.ref.WeakReference;
import java.util.UUID;
public abstract class Furniture implements Cullable {
public final FurnitureConfig config;
public final FurnitureDataAccessor dataAccessor;
public final WeakReference<Entity> metaDataEntity;
public final Entity metaDataEntity;
protected CullingData cullingData;
protected FurnitureVariant currentVariant;
@@ -44,11 +44,11 @@ public abstract class Furniture implements Cullable {
protected Furniture(Entity metaDataEntity, FurnitureDataAccessor data, FurnitureConfig config) {
this.config = config;
this.dataAccessor = data;
this.metaDataEntity = new WeakReference<>(metaDataEntity);
this.metaDataEntity = metaDataEntity;
this.setVariant(config.getVariant(data));
}
public WeakReference<Entity> metaDataEntity() {
public Entity metaDataEntity() {
return this.metaDataEntity;
}
@@ -75,11 +75,11 @@ public abstract class Furniture implements Cullable {
for (int i = 0; i < furnitureHitBoxConfigs.length; i++) {
FurnitureHitBox hitbox = furnitureHitBoxConfigs[i].create(this);
this.hitboxes[i] = hitbox;
for (int hitboxEntityId : hitbox.virtualEntityIds()) {
this.hitboxMap.put(hitboxEntityId, hitbox);
for (FurnitureHitboxPart part : hitbox.parts()) {
this.hitboxMap.put(part.entityId(), hitbox);
virtualEntityIds.add(part.entityId());
}
colliders.addAll(hitbox.colliders());
hitbox.collectVirtualEntityIds(virtualEntityIds::addLast);
}
// 虚拟碰撞箱的实体id
this.virtualEntityIds = virtualEntityIds.toIntArray();
@@ -122,9 +122,7 @@ public abstract class Furniture implements Cullable {
}
public UUID uuid() {
Entity entity = this.metaDataEntity.get();
if (entity == null) return null;
return entity.uuid();
return this.metaDataEntity.uuid();
}
@Override
@@ -158,9 +156,7 @@ public abstract class Furniture implements Cullable {
}
public boolean isValid() {
Entity entity = this.metaDataEntity.get();
if (entity == null) return false;
return entity.isValid();
return this.metaDataEntity.isValid();
}
public abstract void destroy();
@@ -178,15 +174,11 @@ public abstract class Furniture implements Cullable {
}
public WorldPosition position() {
Entity entity = this.metaDataEntity.get();
if (entity == null) return null;
return entity.position();
return this.metaDataEntity.position();
}
public int entityId() {
Entity entity = this.metaDataEntity.get();
if (entity == null) return -1;
return entity.entityID();
return this.metaDataEntity.entityID();
}
public Vec3d getRelativePosition(Vector3f position) {
@@ -200,8 +192,6 @@ public abstract class Furniture implements Cullable {
}
public World world() {
Entity entity = this.metaDataEntity.get();
if (entity == null) return null;
return entity.world();
return this.metaDataEntity.world();
}
}

View File

@@ -5,7 +5,6 @@ import net.momirealms.craftengine.core.loot.LootTable;
import net.momirealms.craftengine.core.plugin.context.Context;
import net.momirealms.craftengine.core.plugin.context.event.EventTrigger;
import net.momirealms.craftengine.core.plugin.context.function.Function;
import net.momirealms.craftengine.core.plugin.entityculling.CullingData;
import net.momirealms.craftengine.core.util.Key;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

View File

@@ -7,7 +7,6 @@ import net.momirealms.craftengine.core.loot.LootTable;
import net.momirealms.craftengine.core.plugin.context.Context;
import net.momirealms.craftengine.core.plugin.context.event.EventTrigger;
import net.momirealms.craftengine.core.plugin.context.function.Function;
import net.momirealms.craftengine.core.plugin.entityculling.CullingData;
import net.momirealms.craftengine.core.util.Key;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

View File

@@ -6,25 +6,17 @@ import net.momirealms.craftengine.core.entity.seat.Seat;
import net.momirealms.craftengine.core.entity.seat.SeatOwner;
import net.momirealms.craftengine.core.world.EntityHitResult;
import net.momirealms.craftengine.core.world.Vec3d;
import net.momirealms.craftengine.core.world.collision.AABB;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
public interface FurnitureHitBox extends SeatOwner {
Vec3d position();
Seat<FurnitureHitBox>[] seats();
AABB[] aabb();
List<Collider> colliders();
int[] virtualEntityIds();
void collectVirtualEntityIds(Consumer<Integer> collector);
List<FurnitureHitboxPart> parts();
void show(Player player);
@@ -33,8 +25,8 @@ public interface FurnitureHitBox extends SeatOwner {
FurnitureHitBoxConfig<?> config();
default Optional<EntityHitResult> clip(Vec3d min, Vec3d max) {
for (AABB value : aabb()) {
Optional<EntityHitResult> clip = value.clip(min, max);
for (FurnitureHitboxPart value : parts()) {
Optional<EntityHitResult> clip = value.aabb().clip(min, max);
if (clip.isPresent()) {
return clip;
}

View File

@@ -0,0 +1,7 @@
package net.momirealms.craftengine.core.entity.furniture.hitbox;
import net.momirealms.craftengine.core.world.Vec3d;
import net.momirealms.craftengine.core.world.collision.AABB;
public record FurnitureHitboxPart(int entityId, AABB aabb, Vec3d pos) {
}