From d2bb9103bd0583eb311641552aff8cf74550c4b6 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 3 Dec 2025 01:30:29 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=B6=E5=85=B7=E9=87=8D=E6=9E=84part3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/api/CraftEngineFurniture.java | 12 +- .../api/event/FurnitureAttemptPlaceEvent.java | 19 +- .../entity/furniture/BukkitFurniture.java | 1 - .../furniture/BukkitFurnitureManager.java | 109 ++++---- .../entity/furniture/ItemColorSource.java | 6 - .../element/ItemDisplayFurnitureElement.java | 43 +++- .../ItemDisplayFurnitureElementConfig.java | 114 +++++---- .../hitbox/AbstractFurnitureHitBox.java | 6 + .../hitbox/InteractionFurnitureHitbox.java | 38 +-- .../InteractionFurnitureHitboxConfig.java | 26 +- .../item/behavior/FurnitureItemBehavior.java | 239 +++++++++--------- .../plugin/network/BukkitNetworkManager.java | 41 +-- .../handler/FurniturePacketHandler.java | 23 +- .../plugin/user/BukkitServerPlayer.java | 96 ++++--- .../furniture/AbstractFurnitureManager.java | 11 +- .../core/entity/furniture/Furniture.java | 64 +++-- .../furniture/FurnitureColorSource.java | 6 + .../entity/furniture/FurnitureConfig.java | 4 - .../entity/furniture/FurnitureConfigImpl.java | 17 +- .../furniture/FurnitureDataAccessor.java | 14 +- .../entity/furniture/FurnitureManager.java | 11 +- .../entity/furniture/FurnitureVariant.java | 8 +- .../furniture/element/FurnitureElement.java | 6 + .../hitbox/AbstractFurnitureHitBoxConfig.java | 6 +- .../furniture/hitbox/FurnitureHitBox.java | 29 ++- .../hitbox/FurnitureHitBoxConfig.java | 6 + .../core/entity/player/Player.java | 7 + .../parameter/FurnitureParameterProvider.java | 2 +- .../plugin/network/EntityPacketHandler.java | 2 +- .../core/util/ResourceConfigUtils.java | 2 + 30 files changed, 580 insertions(+), 388 deletions(-) delete mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/ItemColorSource.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureColorSource.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java index 39ae861f4..5d5c4532f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java @@ -185,7 +185,7 @@ public final class CraftEngineFurniture { */ @Nullable public static BukkitFurniture getLoadedFurnitureByBaseEntity(@NotNull Entity baseEntity) { - return BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(baseEntity.getEntityId()); + return BukkitFurnitureManager.instance().loadedFurnitureByMetaEntityId(baseEntity.getEntityId()); } /** @@ -199,7 +199,7 @@ public final class CraftEngineFurniture { if (isSeat(seat)) { CompoundTag seatExtraData = BukkitSeatManager.instance().getSeatExtraData(seat); int entityId = seatExtraData.getInt("entity_id"); - BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(entityId); + BukkitFurnitureManager.instance().loadedFurnitureByMetaEntityId(entityId); } return null; } @@ -212,7 +212,7 @@ public final class CraftEngineFurniture { */ public static boolean remove(@NotNull Entity entity) { if (!isFurniture(entity)) return false; - BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(entity.getEntityId()); + BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByMetaEntityId(entity.getEntityId()); if (furniture == null) return false; furniture.destroy(); return true; @@ -230,7 +230,7 @@ public final class CraftEngineFurniture { boolean dropLoot, boolean playSound) { if (!isFurniture(entity)) return false; - BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(entity.getEntityId()); + BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByMetaEntityId(entity.getEntityId()); if (furniture == null) return false; remove(furniture, (net.momirealms.craftengine.core.entity.player.Player) null, dropLoot, playSound); return true; @@ -250,7 +250,7 @@ public final class CraftEngineFurniture { boolean dropLoot, boolean playSound) { if (!isFurniture(entity)) return false; - Furniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(entity.getEntityId()); + Furniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByMetaEntityId(entity.getEntityId()); if (furniture == null) return false; remove(furniture, player, dropLoot, playSound); return true; @@ -320,7 +320,7 @@ public final class CraftEngineFurniture { } } if (playSound) { - world.playBlockSound(position, furniture.config().settings().sounds().breakSound()); + world.playBlockSound(position, furniture.config.settings().sounds().breakSound()); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureAttemptPlaceEvent.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureAttemptPlaceEvent.java index dd1920ca0..d7d053413 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureAttemptPlaceEvent.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureAttemptPlaceEvent.java @@ -2,6 +2,7 @@ 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; @@ -17,23 +18,20 @@ public final class FurnitureAttemptPlaceEvent extends PlayerEvent implements Can private boolean cancelled; private final FurnitureConfig furniture; private final Location location; - private final AnchorType anchorType; - private final BlockFace clickedFace; + private final FurnitureVariant variant; private final Block clickedBlock; private final InteractionHand hand; public FurnitureAttemptPlaceEvent(@NotNull Player player, @NotNull FurnitureConfig furniture, - @NotNull AnchorType anchorType, + @NotNull FurnitureVariant variant, @NotNull Location location, - @NotNull BlockFace clickedFace, @NotNull InteractionHand hand, @NotNull Block clickedBlock) { super(player); this.furniture = furniture; this.location = location; - this.anchorType = anchorType; - this.clickedFace = clickedFace; + this.variant = variant; this.clickedBlock = clickedBlock; this.hand = hand; } @@ -48,19 +46,14 @@ public final class FurnitureAttemptPlaceEvent extends PlayerEvent implements Can return hand; } - @NotNull - public BlockFace clickedFace() { - return clickedFace; - } - @NotNull public Player player() { return getPlayer(); } @NotNull - public AnchorType anchorType() { - return anchorType; + public FurnitureVariant variant() { + return variant; } @NotNull diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurniture.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurniture.java index 7236d1ba0..4455884dc 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurniture.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurniture.java @@ -25,7 +25,6 @@ public class BukkitFurniture extends Furniture { super(new BukkitEntity(metaEntity), data, config); this.metaEntity = new WeakReference<>(metaEntity); this.location = metaEntity.getLocation(); - this.setVariant(super.config().getVariant(data)); } @Override 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 f2edfe2df..a1dee6c88 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 @@ -5,23 +5,20 @@ 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.plugin.reflection.minecraft.MEntityTypes; +import net.momirealms.craftengine.bukkit.util.EntityUtils; import net.momirealms.craftengine.bukkit.util.KeyUtils; +import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.core.entity.furniture.*; import net.momirealms.craftengine.core.entity.furniture.hitbox.FurnitureHitBoxConfig; import net.momirealms.craftengine.core.plugin.config.Config; +import net.momirealms.craftengine.core.sound.SoundData; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.CEWorld; import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.core.world.chunk.CEChunk; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.NamespacedKey; -import org.bukkit.World; -import org.bukkit.entity.Boat; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Interaction; -import org.bukkit.entity.ItemDisplay; +import org.bukkit.*; +import org.bukkit.entity.*; import org.bukkit.event.HandlerList; import org.bukkit.persistence.PersistentDataType; import org.jetbrains.annotations.Nullable; @@ -46,7 +43,8 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { private final BukkitCraftEngine plugin; private final Map byMetaEntityId = new ConcurrentHashMap<>(256, 0.5f); - private final Map byEntityId = new ConcurrentHashMap<>(512, 0.5f); + private final Map byVirtualEntityId = new ConcurrentHashMap<>(512, 0.5f); + private final Map byColliderEntityId = new ConcurrentHashMap<>(512, 0.5f); // Event listeners private final FurnitureEventListener furnitureEventListener; @@ -63,31 +61,25 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { @Override public Furniture place(WorldPosition position, FurnitureConfig furniture, FurnitureDataAccessor dataAccessor, boolean playSound) { -// return this.place(LocationUtils.toLocation(position), furniture, dataAccessor, playSound); - return null; + return this.place(LocationUtils.toLocation(position), furniture, dataAccessor, playSound); } - public BukkitFurniture place(Location location, FurnitureConfig furniture, FurnitureDataAccessor extraData, boolean playSound) { -// Optional optionalAnchorType = extraData.anchorType(); -// if (optionalAnchorType.isEmpty() || !furniture.isAllowedPlacement(optionalAnchorType.get())) { -// extraData.anchorType(furniture.getAnyAnchorType()); -// } -// Entity furnitureEntity = EntityUtils.spawnEntity(location.getWorld(), location, EntityType.ITEM_DISPLAY, entity -> { -// ItemDisplay display = (ItemDisplay) entity; -// display.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_KEY, PersistentDataType.STRING, furniture.id().toString()); -// try { -// display.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_EXTRA_DATA_KEY, PersistentDataType.BYTE_ARRAY, extraData.toBytes()); -// } catch (IOException e) { -// this.plugin.logger().warn("Failed to set furniture PDC for " + furniture.id().toString(), e); -// } -// handleBaseEntityLoadEarly(display); -// }); -// if (playSound) { -// SoundData data = furniture.settings().sounds().placeSound(); -// location.getWorld().playSound(location, data.id().toString(), SoundCategory.BLOCKS, data.volume().get(), data.pitch().get()); -// } -// return loadedFurnitureByRealEntityId(furnitureEntity.getEntityId()); - return null; + public BukkitFurniture place(Location location, FurnitureConfig furniture, FurnitureDataAccessor data, boolean playSound) { + Entity furnitureEntity = EntityUtils.spawnEntity(location.getWorld(), location, EntityType.ITEM_DISPLAY, entity -> { + ItemDisplay display = (ItemDisplay) entity; + display.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_KEY, PersistentDataType.STRING, furniture.id().toString()); + try { + display.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_EXTRA_DATA_KEY, PersistentDataType.BYTE_ARRAY, data.toBytes()); + } catch (IOException e) { + this.plugin.logger().warn("Failed to set furniture PDC for " + furniture.id().toString(), e); + } + handleMetaEntityAfterChunkLoad(display); + }); + if (playSound) { + SoundData sound = furniture.settings().sounds().placeSound(); + location.getWorld().playSound(location, sound.id().toString(), SoundCategory.BLOCKS, sound.volume().get(), sound.pitch().get()); + } + return loadedFurnitureByMetaEntityId(furnitureEntity.getEntityId()); } @Override @@ -138,43 +130,59 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { } @Override - public boolean isFurnitureRealEntity(int entityId) { + public boolean isFurnitureMetaEntity(int entityId) { return this.byMetaEntityId.containsKey(entityId); } @Nullable @Override - public BukkitFurniture loadedFurnitureByRealEntityId(int entityId) { + public BukkitFurniture loadedFurnitureByMetaEntityId(int entityId) { return this.byMetaEntityId.get(entityId); } - @Override @Nullable - public BukkitFurniture loadedFurnitureByEntityId(int entityId) { - return this.byEntityId.get(entityId); + @Override + public BukkitFurniture loadedFurnitureByVirtualEntityId(int entityId) { + return this.byVirtualEntityId.get(entityId); } + @Nullable + @Override + public BukkitFurniture loadedFurnitureByColliderEntityId(int entityId) { + return this.byColliderEntityId.get(entityId); + } + + // 当元数据实体被卸载了 protected void handleMetaEntityUnload(Entity entity) { + // 不是持久化的 + if (!entity.isPersistent()) { + return; + } int id = entity.getEntityId(); BukkitFurniture furniture = this.byMetaEntityId.remove(id); if (furniture != null) { Location location = entity.getLocation(); - // 区块还在加载的时候,就重复卸载了 + // 区块还在加载的时候,就重复卸载了。为极其特殊情况 boolean isPreventing = FastNMS.INSTANCE.method$ServerLevel$isPreventingStatusUpdates(FastNMS.INSTANCE.field$CraftWorld$ServerLevel(location.getWorld()), location.getBlockX() >> 4, location.getBlockZ() >> 4); if (!isPreventing) { furniture.destroySeats(); } - for (int sub : furniture.entityIds()) { - this.byEntityId.remove(sub); + for (int sub : furniture.virtualEntityIds()) { + this.byVirtualEntityId.remove(sub); + } + for (int sub : furniture.colliderEntityIds()) { + this.byColliderEntityId.remove(sub); } } } + // 保险起见,collision实体卸载也移除一下 protected void handleCollisionEntityUnload(Entity entity) { int id = entity.getEntityId(); - this.byMetaEntityId.remove(id); + this.byColliderEntityId.remove(id); } + // 检查这个区块的实体是否已经被加载了 private boolean isEntitiesLoaded(Location location) { CEWorld ceWorld = this.plugin.worldManager().getWorld(location.getWorld()); CEChunk ceChunk = ceWorld.getChunkAtIfLoaded(location.getBlockX() >> 4, location.getBlockZ() >> 4); @@ -216,8 +224,8 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { BukkitFurniture previous = this.byMetaEntityId.get(entity.getEntityId()); if (previous != null) return; - BukkitFurniture furniture = addNewFurniture(entity, customFurniture); - furniture.addCollidersToWorld(); + // 创建新的家具 + createFurnitureInstance(entity, customFurniture); } protected void handleMetaEntityAfterChunkLoad(ItemDisplay entity) { @@ -245,8 +253,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { BukkitFurniture previous = this.byMetaEntityId.get(entity.getEntityId()); if (previous != null) return; - BukkitFurniture furniture = addNewFurniture(entity, customFurniture); - furniture.addCollidersToWorld(); + createFurnitureInstance(entity, customFurniture); } protected void handleCollisionEntityAfterChunkLoad(Entity entity) { @@ -298,17 +305,17 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { } } - private synchronized BukkitFurniture addNewFurniture(ItemDisplay display, FurnitureConfig furniture) { + // 创建家具实例,并初始化碰撞实体 + private void createFurnitureInstance(ItemDisplay display, FurnitureConfig furniture) { BukkitFurniture bukkitFurniture = new BukkitFurniture(display, furniture, getFurnitureDataAccessor(display)); this.byMetaEntityId.put(display.getEntityId(), bukkitFurniture); - for (int entityId : bukkitFurniture.entityIds()) { - this.byEntityId.put(entityId, bukkitFurniture); + for (int entityId : bukkitFurniture.virtualEntityIds()) { + this.byVirtualEntityId.put(entityId, bukkitFurniture); } for (Collider collisionEntity : bukkitFurniture.colliders()) { - int collisionEntityId = FastNMS.INSTANCE.method$Entity$getId(collisionEntity.handle()); - this.byEntityId.put(collisionEntityId, bukkitFurniture); + this.byColliderEntityId.put(collisionEntity.entityId(), bukkitFurniture); } - return bukkitFurniture; + bukkitFurniture.addCollidersToWorld(); } @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/ItemColorSource.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/ItemColorSource.java deleted file mode 100644 index 339dad09d..000000000 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/ItemColorSource.java +++ /dev/null @@ -1,6 +0,0 @@ -package net.momirealms.craftengine.bukkit.entity.furniture; - -import net.momirealms.craftengine.core.util.Color; - -public record ItemColorSource(Color dyedColor, int[] fireworkColors) { -} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/element/ItemDisplayFurnitureElement.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/element/ItemDisplayFurnitureElement.java index 5c92715cf..ae884d0c7 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/element/ItemDisplayFurnitureElement.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/element/ItemDisplayFurnitureElement.java @@ -1,22 +1,61 @@ package net.momirealms.craftengine.bukkit.entity.furniture.element; +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.MEntityTypes; +import net.momirealms.craftengine.core.entity.furniture.Furniture; +import net.momirealms.craftengine.core.entity.furniture.FurnitureColorSource; import net.momirealms.craftengine.core.entity.furniture.element.FurnitureElement; import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.world.Vec3d; +import net.momirealms.craftengine.core.world.WorldPosition; + +import java.util.List; +import java.util.UUID; +import java.util.function.Consumer; public class ItemDisplayFurnitureElement implements FurnitureElement { private final ItemDisplayFurnitureElementConfig config; + private final WorldPosition position; + private final int entityId; + private final Object despawnPacket; + private final FurnitureColorSource colorSource; - public ItemDisplayFurnitureElement(ItemDisplayFurnitureElementConfig config) { + public ItemDisplayFurnitureElement(Furniture furniture, ItemDisplayFurnitureElementConfig config) { this.config = config; + this.entityId = CoreReflections.instance$Entity$ENTITY_COUNTER.incrementAndGet(); + WorldPosition furniturePos = furniture.position(); + Vec3d position = Furniture.getRelativePosition(furniturePos, config.position()); + this.position = new WorldPosition(furniturePos.world, position.x, position.y, position.z, furniturePos.xRot, furniturePos.yRot); + this.despawnPacket = FastNMS.INSTANCE.constructor$ClientboundRemoveEntitiesPacket(new IntArrayList() {{ add(entityId); }}); + this.colorSource = furniture.dataAccessor.getColorSource(); } @Override public void show(Player player) { - + player.sendPacket(FastNMS.INSTANCE.constructor$ClientboundBundlePacket(List.of( + FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket( + this.entityId, UUID.randomUUID(), + this.position.x, this.position.y, this.position.z, 0, this.position.yRot, + MEntityTypes.ITEM_DISPLAY, 0, CoreReflections.instance$Vec3$Zero, 0 + ), + FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(this.entityId, this.config.metadata.apply(player, this.colorSource)) + )), false); } @Override public void hide(Player player) { + player.sendPacket(this.despawnPacket, false); + } + @Override + public int[] virtualEntityIds() { + return new int[] {this.entityId}; + } + + @Override + public void collectVirtualEntityId(Consumer collector) { + collector.accept(this.entityId); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/element/ItemDisplayFurnitureElementConfig.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/element/ItemDisplayFurnitureElementConfig.java index fe52c4c83..cf58886a5 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/element/ItemDisplayFurnitureElementConfig.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/element/ItemDisplayFurnitureElementConfig.java @@ -2,7 +2,7 @@ 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.bukkit.entity.furniture.ItemColorSource; +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; @@ -28,21 +28,21 @@ import java.util.function.BiFunction; public class ItemDisplayFurnitureElementConfig implements FurnitureElementConfig { public static final Factory FACTORY = new Factory(); - private final BiFunction> lazyMetadataPacket; - private final BiFunction> item; - private final Vector3f scale; - private final Vector3f position; - private final Vector3f translation; - private final float xRot; - private final float yRot; - private final Quaternionf rotation; - private final ItemDisplayContext displayContext; - private final Billboard billboard; - private final float shadowRadius; - private final float shadowStrength; - private final boolean applyDyedColor; + public final BiFunction> metadata; + public final Key itemId; + public final Vector3f scale; + public final Vector3f position; + public final Vector3f translation; + public final float xRot; + public final float yRot; + public final Quaternionf rotation; + public final ItemDisplayContext displayContext; + public final Billboard billboard; + public final float shadowRadius; + public final float shadowStrength; + public final boolean applyDyedColor; - public ItemDisplayFurnitureElementConfig(BiFunction> item, + public ItemDisplayFurnitureElementConfig(Key itemId, Vector3f scale, Vector3f position, Vector3f translation, @@ -65,10 +65,24 @@ public class ItemDisplayFurnitureElementConfig implements FurnitureElementConfig this.shadowRadius = shadowRadius; this.shadowStrength = shadowStrength; this.applyDyedColor = applyDyedColor; - this.item = item; - this.lazyMetadataPacket = (player, source) -> { + this.itemId = itemId; + BiFunction> itemFunction = (player, colorSource) -> { + Item wrappedItem = BukkitItemManager.instance().createWrappedItem(itemId, player); + if (applyDyedColor && colorSource != null && wrappedItem != null) { + Optional.ofNullable(colorSource.dyedColor()).ifPresent(wrappedItem::dyedColor); + Optional.ofNullable(colorSource.fireworkColors()).ifPresent(colors -> wrappedItem.fireworkExplosion(new FireworkExplosion( + FireworkExplosion.Shape.SMALL_BALL, + new IntArrayList(colors), + new IntArrayList(), + false, + false + ))); + } + return Optional.ofNullable(wrappedItem).orElseGet(() -> BukkitItemManager.instance().createWrappedItem(ItemKeys.BARRIER, null)); + }; + this.metadata = (player, source) -> { List dataValues = new ArrayList<>(); - ItemDisplayEntityData.DisplayedItem.addEntityData(item.apply(player, source).getLiteralObject(), dataValues); + ItemDisplayEntityData.DisplayedItem.addEntityData(itemFunction.apply(player, source).getLiteralObject(), dataValues); ItemDisplayEntityData.Scale.addEntityData(this.scale, dataValues); ItemDisplayEntityData.RotationLeft.addEntityData(this.rotation, dataValues); ItemDisplayEntityData.BillboardConstraints.addEntityData(this.billboard.id(), dataValues); @@ -81,52 +95,56 @@ public class ItemDisplayFurnitureElementConfig implements FurnitureElementConfig } public Vector3f scale() { - return scale; + return this.scale; } public Vector3f position() { - return position; + return this.position; } public Vector3f translation() { - return translation; + return this.translation; } public float xRot() { - return xRot; + return this.xRot; } public float yRot() { - return yRot; + return this.yRot; } public Quaternionf rotation() { - return rotation; + return this.rotation; } public ItemDisplayContext displayContext() { - return displayContext; + return this.displayContext; } public Billboard billboard() { - return billboard; + return this.billboard; } public float shadowRadius() { - return shadowRadius; + return this.shadowRadius; } public float shadowStrength() { - return shadowStrength; + return this.shadowStrength; } public boolean applyDyedColor() { - return applyDyedColor; + return this.applyDyedColor; + } + + public Key itemId() { + return this.itemId; } @Override public ItemDisplayFurnitureElement create(@NotNull Furniture furniture) { - return new ItemDisplayFurnitureElement(this); + return new ItemDisplayFurnitureElement(furniture, this); } public static class Factory implements FurnitureElementConfigFactory { @@ -136,22 +154,9 @@ public class ItemDisplayFurnitureElementConfig implements FurnitureElementConfig Key itemId = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("item"), "warning.config.furniture.element.item_display.missing_item")); boolean applyDyedColor = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("apply-dyed-color", true), "apply-dyed-color"); return new ItemDisplayFurnitureElementConfig( - (player, colorSource) -> { - Item wrappedItem = BukkitItemManager.instance().createWrappedItem(itemId, player); - if (applyDyedColor && colorSource != null && wrappedItem != null) { - Optional.ofNullable(colorSource.dyedColor()).ifPresent(wrappedItem::dyedColor); - Optional.ofNullable(colorSource.fireworkColors()).ifPresent(colors -> wrappedItem.fireworkExplosion(new FireworkExplosion( - FireworkExplosion.Shape.SMALL_BALL, - new IntArrayList(colors), - new IntArrayList(), - false, - false - ))); - } - return Optional.ofNullable(wrappedItem).orElseGet(() -> BukkitItemManager.instance().createWrappedItem(ItemKeys.BARRIER, null)); - }, + itemId, ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("scale", 1f), "scale"), - ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("position", 0.5f), "position"), + ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("position", 0f), "position"), ResourceConfigUtils.getAsVector3f(arguments.get("translation"), "translation"), ResourceConfigUtils.getAsFloat(arguments.getOrDefault("pitch", 0f), "pitch"), ResourceConfigUtils.getAsFloat(arguments.getOrDefault("yaw", 0f), "yaw"), @@ -164,4 +169,23 @@ public class ItemDisplayFurnitureElementConfig implements FurnitureElementConfig ); } } + + @Override + public String toString() { + return "ItemDisplayFurnitureElementConfig{" + + "metadata=" + metadata + + ", itemId=" + itemId + + ", scale=" + scale + + ", position=" + position + + ", translation=" + translation + + ", xRot=" + xRot + + ", yRot=" + yRot + + ", rotation=" + rotation + + ", displayContext=" + displayContext + + ", billboard=" + billboard + + ", shadowRadius=" + shadowRadius + + ", shadowStrength=" + shadowStrength + + ", applyDyedColor=" + applyDyedColor + + '}'; + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/AbstractFurnitureHitBox.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/AbstractFurnitureHitBox.java index 5ae471042..2789d4347 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/AbstractFurnitureHitBox.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/AbstractFurnitureHitBox.java @@ -8,6 +8,7 @@ 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; @@ -54,4 +55,9 @@ public abstract class AbstractFurnitureHitBox implements FurnitureHitBox { 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); + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/InteractionFurnitureHitbox.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/InteractionFurnitureHitbox.java index 9f8bc0366..65836a4b5 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/InteractionFurnitureHitbox.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/InteractionFurnitureHitbox.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.bukkit.entity.furniture.hitbox; +import net.momirealms.craftengine.bukkit.entity.data.BaseEntityData; import net.momirealms.craftengine.bukkit.entity.data.InteractionEntityData; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; @@ -14,15 +15,15 @@ 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[] entityIds; + private final int interactionId; private final Object spawnPacket; - private final Object despawnPacket; public InteractionFurnitureHitbox(Furniture furniture, InteractionFurnitureHitboxConfig config) { super(furniture, config); @@ -31,20 +32,21 @@ public class InteractionFurnitureHitbox extends AbstractFurnitureHitBox { 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()); - int interactionId = CoreReflections.instance$Entity$ENTITY_COUNTER.incrementAndGet(); - this.entityIds = new int[] {interactionId}; - List values = new ArrayList<>(3); + this.interactionId = CoreReflections.instance$Entity$ENTITY_COUNTER.incrementAndGet(); + List values = new ArrayList<>(4); InteractionEntityData.Height.addEntityDataIfNotDefaultValue(config.size.y, values); InteractionEntityData.Width.addEntityDataIfNotDefaultValue(config.size.x, values); InteractionEntityData.Responsive.addEntityDataIfNotDefaultValue(config.responsive, values); + if (config.invisible) { + BaseEntityData.SharedFlags.addEntityDataIfNotDefaultValue((byte) 0x20, values); + } this.spawnPacket = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(List.of( FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket( - interactionId, UUID.randomUUID(), position.x, position.y, position.z, 0, position.yRot, + this.interactionId, UUID.randomUUID(), position.x, position.y, position.z, 0, position.yRot, MEntityTypes.INTERACTION, 0, CoreReflections.instance$Vec3$Zero, 0 ), - FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(interactionId, values) + FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(this.interactionId, values) )); - this.despawnPacket = createDespawnPacket(this.entityIds); } @Override @@ -53,13 +55,8 @@ public class InteractionFurnitureHitbox extends AbstractFurnitureHitBox { } @Override - public void hide(Player player) { - player.sendPacket(this.despawnPacket, false); - } - - @Override - public AABB aabb() { - return this.aabb; + public AABB[] aabb() { + return new AABB[] { this.aabb }; } @Override @@ -68,13 +65,18 @@ public class InteractionFurnitureHitbox extends AbstractFurnitureHitBox { } @Override - public Collider collider() { - return this.collider; + public List colliders() { + return List.of(this.collider); } @Override public int[] virtualEntityIds() { - return this.entityIds; + return new int[] { this.interactionId }; + } + + @Override + public void collectVirtualEntityIds(Consumer collector) { + collector.accept(this.interactionId); } public InteractionFurnitureHitboxConfig config() { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/InteractionFurnitureHitboxConfig.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/InteractionFurnitureHitboxConfig.java index 2a1efd59f..7711218c2 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/InteractionFurnitureHitboxConfig.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/InteractionFurnitureHitboxConfig.java @@ -5,27 +5,34 @@ import net.momirealms.craftengine.core.entity.furniture.hitbox.AbstractFurniture import net.momirealms.craftengine.core.entity.furniture.hitbox.FurnitureHitBoxConfigFactory; import net.momirealms.craftengine.core.entity.seat.SeatConfig; import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.world.Vec3d; +import net.momirealms.craftengine.core.world.WorldPosition; +import net.momirealms.craftengine.core.world.collision.AABB; import org.joml.Vector3f; import java.util.Map; +import java.util.function.Consumer; public class InteractionFurnitureHitboxConfig extends AbstractFurnitureHitBoxConfig { public static final Factory FACTORY = new Factory(); - public static final InteractionFurnitureHitboxConfig DEFAULT = new InteractionFurnitureHitboxConfig(new SeatConfig[0], new Vector3f(), false, false, false, new Vector3f(1,1,1), true); + public static final InteractionFurnitureHitboxConfig DEFAULT = new InteractionFurnitureHitboxConfig(new SeatConfig[0], new Vector3f(), false, false, false, false, new Vector3f(1,1,1), true); public final Vector3f size; public final boolean responsive; + public final boolean invisible; public InteractionFurnitureHitboxConfig(SeatConfig[] seats, Vector3f position, boolean canUseItemOn, boolean blocksBuilding, boolean canBeHitByProjectile, + boolean invisible, Vector3f size, boolean responsive) { super(seats, position, canUseItemOn, blocksBuilding, canBeHitByProjectile); this.size = size; this.responsive = responsive; + this.invisible = invisible; } public Vector3f size() { @@ -36,6 +43,18 @@ public class InteractionFurnitureHitboxConfig extends AbstractFurnitureHitBoxCon return responsive; } + public boolean invisible() { + return invisible; + } + + @Override + public void prepareForPlacement(WorldPosition targetPos, Consumer aabbConsumer) { + if (this.blocksBuilding) { + Vec3d relativePosition = Furniture.getRelativePosition(targetPos, this.position); + aabbConsumer.accept(AABB.fromInteraction(relativePosition, size.x, size.y)); + } + } + @Override public InteractionFurnitureHitbox create(Furniture furniture) { return new InteractionFurnitureHitbox(furniture, this); @@ -45,7 +64,7 @@ public class InteractionFurnitureHitboxConfig extends AbstractFurnitureHitBoxCon @Override public InteractionFurnitureHitboxConfig create(Map arguments) { - Vector3f position = ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("position", "0"), "position"); + Vector3f position = ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("position", 0), "position"); float width; float height; if (arguments.containsKey("scale")) { @@ -60,9 +79,10 @@ public class InteractionFurnitureHitboxConfig extends AbstractFurnitureHitBoxCon boolean interactive = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("interactive", true), "interactive"); boolean canBeHitByProjectile = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-be-hit-by-projectile", false), "can-be-hit-by-projectile"); boolean blocksBuilding = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blocks-building", true), "blocks-building"); + boolean invisible = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("invisible", false), "invisible"); return new InteractionFurnitureHitboxConfig( SeatConfig.fromObj(arguments.get("seats")), - position, canUseOn, blocksBuilding, canBeHitByProjectile, + position, canUseOn, blocksBuilding, canBeHitByProjectile, invisible, new Vector3f(width, height, width), interactive ); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java index b92b4440e..3b85c0ef7 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java @@ -1,18 +1,46 @@ package net.momirealms.craftengine.bukkit.item.behavior; +import net.momirealms.craftengine.bukkit.api.event.FurnitureAttemptPlaceEvent; +import net.momirealms.craftengine.bukkit.api.event.FurniturePlaceEvent; +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; +import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; import net.momirealms.craftengine.core.item.context.UseOnContext; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.pack.PendingConfigSection; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.context.ContextHolder; +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.Key; -import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.*; +import net.momirealms.craftengine.core.world.Vec3d; +import net.momirealms.craftengine.core.world.WorldPosition; +import net.momirealms.craftengine.core.world.collision.AABB; +import net.momirealms.sparrow.nbt.CompoundTag; +import org.bukkit.Location; +import org.bukkit.World; import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; import java.util.Map; +import java.util.Optional; public class FurnitureItemBehavior extends ItemBehavior { public static final Factory FACTORY = new Factory(); @@ -23,7 +51,7 @@ public class FurnitureItemBehavior extends ItemBehavior { } public Key furnitureId() { - return id; + return this.id; } @Override @@ -32,121 +60,96 @@ public class FurnitureItemBehavior extends ItemBehavior { } public InteractionResult place(UseOnContext context) { -// Optional optionalCustomFurniture = BukkitFurnitureManager.instance().furnitureById(this.id); -// if (optionalCustomFurniture.isEmpty()) { -// CraftEngine.instance().logger().warn("Furniture " + this.id + " not found"); -// return InteractionResult.FAIL; -// } -// FurnitureConfig customFurniture = optionalCustomFurniture.get(); -// -// Direction clickedFace = context.getClickedFace(); -// AnchorType anchorType = switch (clickedFace) { -// case EAST, WEST, NORTH, SOUTH -> AnchorType.WALL; -// case UP -> AnchorType.GROUND; -// case DOWN -> AnchorType.CEILING; -// }; -// -// FurnitureConfig.Variant placement = customFurniture.getPlacement(anchorType); -// if (placement == null) { -// return InteractionResult.FAIL; -// } -// -// Player player = context.getPlayer(); -// // todo adventure check -// if (player != null && player.isAdventureMode()) { -// return InteractionResult.FAIL; -// } -// -// Vec3d clickedPosition = context.getClickLocation(); -// -// // trigger event -// org.bukkit.entity.Player bukkitPlayer = player != null ? (org.bukkit.entity.Player) player.platformPlayer() : null; -// World world = (World) context.getLevel().platformWorld(); -// -// // get position and rotation for placement -// Vec3d finalPlacePosition; -// double furnitureYaw; -// if (anchorType == AnchorType.WALL) { -// furnitureYaw = Direction.getYaw(clickedFace); -// if (clickedFace == Direction.EAST || clickedFace == Direction.WEST) { -// Pair xz = placement.alignmentRule().apply(Pair.of(clickedPosition.y(), clickedPosition.z())); -// finalPlacePosition = new Vec3d(clickedPosition.x(), xz.left(), xz.right()); -// } else { -// Pair xz = placement.alignmentRule().apply(Pair.of(clickedPosition.x(), clickedPosition.y())); -// finalPlacePosition = new Vec3d(xz.left(), xz.right(), clickedPosition.z()); -// } -// } else { -// furnitureYaw = placement.rotationRule().apply(180 + (player != null ? player.yRot() : 0)); -// Pair xz = placement.alignmentRule().apply(Pair.of(clickedPosition.x(), clickedPosition.z())); -// finalPlacePosition = new Vec3d(xz.left(), clickedPosition.y(), xz.right()); -// } -// -// Location furnitureLocation = new Location(world, finalPlacePosition.x(), finalPlacePosition.y(), finalPlacePosition.z(), (float) furnitureYaw, 0); -// -// List aabbs = new ArrayList<>(); -// for (HitBoxConfig hitBoxConfig : placement.hitBoxConfigs()) { -// hitBoxConfig.initShapeForPlacement(finalPlacePosition.x(), finalPlacePosition.y(), finalPlacePosition.z(), (float) furnitureYaw, QuaternionUtils.toQuaternionf(0, Math.toRadians(180 - furnitureYaw), 0).conjugate(), aabbs::add); -// } -// if (!aabbs.isEmpty()) { -// if (!FastNMS.INSTANCE.checkEntityCollision(context.getLevel().serverWorld(), aabbs.stream().map(it -> FastNMS.INSTANCE.constructor$AABB(it.minX, it.minY, it.minZ, it.maxX, it.maxY, it.maxZ)).toList())) { -// return InteractionResult.FAIL; -// } -// } -// -// if (!BukkitCraftEngine.instance().antiGriefProvider().canPlace(bukkitPlayer, furnitureLocation)) { -// return InteractionResult.FAIL; -// } -// -// if (player != null) { -// FurnitureAttemptPlaceEvent attemptPlaceEvent = new FurnitureAttemptPlaceEvent(bukkitPlayer, customFurniture, anchorType, furnitureLocation.clone(), -// DirectionUtils.toBlockFace(clickedFace), context.getHand(), world.getBlockAt(context.getClickedPos().x(), context.getClickedPos().y(), context.getClickedPos().z())); -// if (EventUtils.fireAndCheckCancel(attemptPlaceEvent)) { -// return InteractionResult.FAIL; -// } -// } -// -// Item item = context.getItem(); -// // 不可能 -// if (ItemUtils.isEmpty(item)) return InteractionResult.FAIL; -// -// BukkitFurniture bukkitFurniture = BukkitFurnitureManager.instance().place( -// furnitureLocation.clone(), customFurniture, -// FurnitureDataAccessor.builder() -// .item(item.copyWithCount(1)) -// .anchorType(anchorType) -// .dyedColor(item.dyedColor().orElse(null)) -// .fireworkExplosionColors(item.fireworkExplosion().map(explosion -> explosion.colors().toIntArray()).orElse(null)) -// .build(), false); -// -// if (player != null) { -// FurniturePlaceEvent placeEvent = new FurniturePlaceEvent(bukkitPlayer, bukkitFurniture, furnitureLocation, context.getHand()); -// if (EventUtils.fireAndCheckCancel(placeEvent)) { -// bukkitFurniture.destroy(); -// return InteractionResult.FAIL; -// } -// } -// -// Cancellable dummy = Cancellable.dummy(); -// PlayerOptionalContext functionContext = PlayerOptionalContext.of(player, ContextHolder.builder() -// .withParameter(DirectContextParameters.FURNITURE, bukkitFurniture) -// .withParameter(DirectContextParameters.POSITION, LocationUtils.toWorldPosition(furnitureLocation)) -// .withParameter(DirectContextParameters.EVENT, dummy) -// .withParameter(DirectContextParameters.HAND, context.getHand()) -// .withParameter(DirectContextParameters.ITEM_IN_HAND, item) -// ); -// customFurniture.execute(functionContext, EventTrigger.PLACE); -// if (dummy.isCancelled()) { -// return InteractionResult.SUCCESS_AND_CANCEL; -// } -// -// if (player != null) { -// if (!player.canInstabuild()) { -// item.count(item.count() - 1); -// } -// player.swingHand(context.getHand()); -// } -// -// context.getLevel().playBlockSound(finalPlacePosition, customFurniture.settings().sounds().placeSound()); + Optional optionalCustomFurniture = BukkitFurnitureManager.instance().furnitureById(this.id); + if (optionalCustomFurniture.isEmpty()) { + CraftEngine.instance().logger().warn("Furniture " + this.id + " not found"); + return InteractionResult.FAIL; + } + + FurnitureConfig customFurniture = optionalCustomFurniture.get(); + FurnitureVariant variant = customFurniture.anyVariant(); + if (variant == null) { + return InteractionResult.FAIL; + } + + Player player = context.getPlayer(); + if (player != null && player.isAdventureMode()) { + return InteractionResult.FAIL; + } + + Vec3d clickedPosition = context.getClickLocation(); + + // trigger event + org.bukkit.entity.Player bukkitPlayer = player != null ? (org.bukkit.entity.Player) player.platformPlayer() : null; + World world = (World) context.getLevel().platformWorld(); + + // get position and rotation for placement + Vec3d finalPlacePosition = clickedPosition; + double furnitureYaw = 180 + (player != null ? player.yRot() : 0); + + Location furnitureLocation = new Location(world, finalPlacePosition.x(), finalPlacePosition.y(), finalPlacePosition.z(), (float) furnitureYaw, 0); + WorldPosition furniturePos = LocationUtils.toWorldPosition(furnitureLocation); + List aabbs = new ArrayList<>(); + // 收集阻挡的碰撞箱 + for (FurnitureHitBoxConfig hitBoxConfig : variant.hitBoxConfigs()) { + hitBoxConfig.prepareForPlacement(furniturePos, aabbs::add); + } + // 检查方块、实体阻挡 + if (!aabbs.isEmpty()) { + if (!FastNMS.INSTANCE.checkEntityCollision(context.getLevel().serverWorld(), aabbs.stream().map(it -> FastNMS.INSTANCE.constructor$AABB(it.minX, it.minY, it.minZ, it.maxX, it.maxY, it.maxZ)).toList())) { + return InteractionResult.FAIL; + } + } + // 检查其他插件兼容性 + if (!BukkitCraftEngine.instance().antiGriefProvider().canPlace(bukkitPlayer, furnitureLocation)) { + return InteractionResult.FAIL; + } + // 触发尝试放置的事件 + if (player != null) { + FurnitureAttemptPlaceEvent attemptPlaceEvent = new FurnitureAttemptPlaceEvent(bukkitPlayer, customFurniture, variant, furnitureLocation.clone(), context.getHand(), world.getBlockAt(context.getClickedPos().x(), context.getClickedPos().y(), context.getClickedPos().z())); + if (EventUtils.fireAndCheckCancel(attemptPlaceEvent)) { + return InteractionResult.FAIL; + } + } + Item item = context.getItem(); + if (ItemUtils.isEmpty(item)) return InteractionResult.FAIL; + // 获取家具物品的一些属性 + FurnitureDataAccessor dataAccessor = FurnitureDataAccessor.of(new CompoundTag()); + dataAccessor.setVariant(variant.name()); + dataAccessor.setItem(item.copyWithCount(1)); + dataAccessor.setDyedColor(item.dyedColor().orElse(null)); + dataAccessor.setFireworkExplosionColors(item.fireworkExplosion().map(explosion -> explosion.colors().toIntArray()).orElse(null)); + // 放置家具 + BukkitFurniture bukkitFurniture = BukkitFurnitureManager.instance().place(furnitureLocation.clone(), customFurniture, dataAccessor, false); + // 触发放置事件 + if (player != null) { + FurniturePlaceEvent placeEvent = new FurniturePlaceEvent(bukkitPlayer, bukkitFurniture, furnitureLocation, context.getHand()); + if (EventUtils.fireAndCheckCancel(placeEvent)) { + bukkitFurniture.destroy(); + return InteractionResult.FAIL; + } + } + // 触发ce事件 + Cancellable dummy = Cancellable.dummy(); + PlayerOptionalContext functionContext = PlayerOptionalContext.of(player, ContextHolder.builder() + .withParameter(DirectContextParameters.FURNITURE, bukkitFurniture) + .withParameter(DirectContextParameters.POSITION, LocationUtils.toWorldPosition(furnitureLocation)) + .withParameter(DirectContextParameters.EVENT, dummy) + .withParameter(DirectContextParameters.HAND, context.getHand()) + .withParameter(DirectContextParameters.ITEM_IN_HAND, item) + ); + customFurniture.execute(functionContext, EventTrigger.PLACE); + if (dummy.isCancelled()) { + return InteractionResult.SUCCESS_AND_CANCEL; + } + // 后续处理 + if (player != null) { + if (!player.canInstabuild()) { + item.count(item.count() - 1); + } + player.swingHand(context.getHand()); + } + context.getLevel().playBlockSound(finalPlacePosition, customFurniture.settings().sounds().placeSound()); return InteractionResult.SUCCESS; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java index 9ab146c37..57a5f59cc 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java @@ -1247,7 +1247,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes CraftEngine.instance().logger().warn("Failed to get entityId from ServerboundPickItemFromEntityPacket", e); return; } - BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByEntityId(entityId); + BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByVirtualEntityId(entityId); if (furniture == null) return; Player player = (Player) user.platformPlayer(); if (player == null) return; @@ -1469,6 +1469,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes player.setClientSideWorld(BukkitAdaptors.adapt(world)); player.clearTrackedChunks(); player.clearTrackedBlockEntities(); + player.clearTrackedFurniture(); } else { CraftEngine.instance().logger().warn("Failed to handle ClientboundRespawnPacket: World " + location + " does not exist"); } @@ -1745,9 +1746,6 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes @Override public void onPacketSend(NetWorkUser user, NMSPacketEvent event, Object packet) { int entityId = ProtectedFieldVisitor.get().field$ClientboundMoveEntityPacket$entityId(packet); - if (BukkitFurnitureManager.instance().isFurnitureRealEntity(entityId)) { - event.setCancelled(true); - } EntityPacketHandler handler = user.entityPacketHandlers().get(entityId); if (handler != null) { handler.handleMoveAndRotate(user, event, packet); @@ -1778,7 +1776,8 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes CraftEngine.instance().logger().warn("Failed to get entity id from ClientboundRotateHeadPacket", t); return; } - if (BukkitFurnitureManager.instance().isFurnitureRealEntity(entityId)) { + if (BukkitFurnitureManager.instance().isFurnitureMetaEntity(entityId)) { + System.out.println("RotateHeadListener"); event.setCancelled(true); } } @@ -1796,7 +1795,8 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes CraftEngine.instance().logger().warn("Failed to get entity id from ClientboundSetEntityMotionPacket", t); return; } - if (BukkitFurnitureManager.instance().isFurnitureRealEntity(entityId)) { + if (BukkitFurnitureManager.instance().isFurnitureMetaEntity(entityId)) { + System.out.println("SetEntityMotionListener"); event.setCancelled(true); } } @@ -3349,7 +3349,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes for (int i = 0, size = intList.size(); i < size; i++) { int entityId = intList.getInt(i); EntityPacketHandler handler = user.entityPacketHandlers().remove(entityId); - if (handler != null && handler.handleEntitiesRemove(intList)) { + if (handler != null && handler.handleEntitiesRemove(user, intList)) { changed = true; } } @@ -3698,7 +3698,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes public void onPacketReceive(NetWorkUser user, ByteBufPacketEvent event) { FriendlyByteBuf buf = event.getBuffer(); int entityId = hasModelEngine() ? plugin.compatibilityManager().interactionToBaseEntity(buf.readVarInt()) : buf.readVarInt(); - BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByEntityId(entityId); + BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByVirtualEntityId(entityId); if (furniture == null) return; int actionType = buf.readVarInt(); BukkitServerPlayer serverPlayer = (BukkitServerPlayer) user; @@ -3799,7 +3799,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes Vector direction = eyeLocation.getDirection(); Location endLocation = eyeLocation.clone(); endLocation.add(direction.multiply(serverPlayer.getCachedInteractionRange())); - Optional result = hitBox.aabb().clip(LocationUtils.toVec3d(eyeLocation), LocationUtils.toVec3d(endLocation)); + Optional result = hitBox.clip(LocationUtils.toVec3d(eyeLocation), LocationUtils.toVec3d(endLocation)); if (result.isEmpty()) { return; } @@ -3976,16 +3976,19 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes this.handlers[MEntityTypes.ITEM_DISPLAY$registryId] = (user, event) -> { FriendlyByteBuf buf = event.getBuffer(); int id = buf.readVarInt(); - BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(id); + BukkitServerPlayer serverPlayer = (BukkitServerPlayer) user; + BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByMetaEntityId(id); if (furniture != null) { - furniture.show((BukkitServerPlayer) user); - event.setCancelled(true); + serverPlayer.entityPacketHandlers().put(id, new FurniturePacketHandler(id, furniture.virtualEntityIds())); + if (Config.enableEntityCulling()) { + serverPlayer.addTrackedFurniture(id, furniture); + } else { + furniture.show(serverPlayer); + } // fixme 外部模型 -// user.entityPacketHandlers().put(id, new FurniturePacketHandler(furniture.fakeEntityIds())); -// user.sendPacket(furniture.spawnPacket((Player) user.platformPlayer()), false); -// if (Config.hideBaseEntity() && !furniture.hasExternalModel()) { -// event.setCancelled(true); -// } + if (Config.hideBaseEntity() && true) { + event.setCancelled(true); + } } else { user.entityPacketHandlers().put(id, ItemDisplayPacketHandler.INSTANCE); } @@ -3995,7 +3998,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes FriendlyByteBuf buf = event.getBuffer(); int id = buf.readVarInt(); // Cancel collider entity packet - BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(id); + BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByColliderEntityId(id); if (furniture != null) { event.setCancelled(true); user.entityPacketHandlers().put(id, FurnitureCollisionPacketHandler.INSTANCE); @@ -4006,7 +4009,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes FriendlyByteBuf buf = event.getBuffer(); int id = buf.readVarInt(); // Cancel collider entity packet - BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(id); + BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByColliderEntityId(id); if (furniture != null) { event.setCancelled(true); user.entityPacketHandlers().put(id, FurnitureCollisionPacketHandler.INSTANCE); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/FurniturePacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/FurniturePacketHandler.java index 0a60cfc3a..3e7277429 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/FurniturePacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/FurniturePacketHandler.java @@ -1,22 +1,26 @@ package net.momirealms.craftengine.bukkit.plugin.network.handler; import it.unimi.dsi.fastutil.ints.IntList; +import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler; import net.momirealms.craftengine.core.plugin.network.NMSPacketEvent; import net.momirealms.craftengine.core.plugin.network.NetWorkUser; -import java.util.List; - public class FurniturePacketHandler implements EntityPacketHandler { - private final List fakeEntities; + private final int metaEntityId; + private final int[] virtualHitboxEntities; - public FurniturePacketHandler(List fakeEntities) { - this.fakeEntities = fakeEntities; + public FurniturePacketHandler(int metaEntityId, int[] virtualHitboxEntities) { + this.virtualHitboxEntities = virtualHitboxEntities; + this.metaEntityId = metaEntityId; } @Override - public boolean handleEntitiesRemove(IntList entityIds) { - entityIds.addAll(this.fakeEntities); + public boolean handleEntitiesRemove(NetWorkUser user, IntList entityIds) { + ((Player) user).removeTrackedFurniture(this.metaEntityId); + for (int entityId : this.virtualHitboxEntities) { + entityIds.add(entityId); + } return true; } @@ -29,4 +33,9 @@ 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); + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java index e7bdc3bea..a67b52a51 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java @@ -25,6 +25,7 @@ import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.entity.BlockEntity; import net.momirealms.craftengine.core.block.entity.render.ConstantBlockEntityRenderer; import net.momirealms.craftengine.core.entity.data.EntityData; +import net.momirealms.craftengine.core.entity.furniture.Furniture; import net.momirealms.craftengine.core.entity.player.GameMode; import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.entity.player.Player; @@ -144,6 +145,7 @@ public class BukkitServerPlayer extends Player { private int lastStopMiningTick; // 跟踪到的方块实体渲染器 private final Map trackedBlockEntityRenderers = new ConcurrentHashMap<>(); + private final Map trackedFurniture = new ConcurrentHashMap<>(); private final EntityCulling culling; private Vec3d firstPersonCameraVec3; private Vec3d thirdPersonCameraVec3; @@ -603,44 +605,54 @@ public class BukkitServerPlayer extends Player { boolean useRayTracing = Config.entityCullingRayTracing(); if (this.enableEntityCulling) { for (VirtualCullableObject cullableObject : this.trackedBlockEntityRenderers.values()) { - CullingData cullingData = cullableObject.cullable.cullingData(); - if (cullingData != null) { - boolean firstPersonVisible = this.culling.isVisible(cullingData, this.firstPersonCameraVec3, useRayTracing); - // 之前可见 - if (cullableObject.isShown) { - boolean thirdPersonVisible = this.culling.isVisible(cullingData, this.thirdPersonCameraVec3, useRayTracing); - if (!firstPersonVisible && !thirdPersonVisible) { - cullableObject.setShown(this, false); - } - } - // 之前不可见 - else { - // 但是第一人称可见了 - if (firstPersonVisible) { - // 下次再说 - if (Config.enableEntityCullingRateLimiting() && !this.culling.takeToken()) { - continue; - } - cullableObject.setShown(this, true); - continue; - } - if (this.culling.isVisible(cullingData, this.thirdPersonCameraVec3, useRayTracing)) { - // 下次再说 - if (Config.enableEntityCullingRateLimiting() && !this.culling.takeToken()) { - continue; - } - cullableObject.setShown(this, true); - } - // 仍然不可见 - } - } else { - cullableObject.setShown(this, true); - } + cullEntity(useRayTracing, cullableObject); + } + for (VirtualCullableObject cullableObject : this.trackedFurniture.values()) { + cullEntity(useRayTracing, cullableObject); } } else { for (VirtualCullableObject cullableObject : this.trackedBlockEntityRenderers.values()) { cullableObject.setShown(this, true); } + for (VirtualCullableObject cullableObject : this.trackedFurniture.values()) { + cullableObject.setShown(this, true); + } + } + } + + private void cullEntity(boolean useRayTracing, VirtualCullableObject cullableObject) { + CullingData cullingData = cullableObject.cullable.cullingData(); + if (cullingData != null) { + boolean firstPersonVisible = this.culling.isVisible(cullingData, this.firstPersonCameraVec3, useRayTracing); + // 之前可见 + if (cullableObject.isShown) { + boolean thirdPersonVisible = this.culling.isVisible(cullingData, this.thirdPersonCameraVec3, useRayTracing); + if (!firstPersonVisible && !thirdPersonVisible) { + cullableObject.setShown(this, false); + } + } + // 之前不可见 + else { + // 但是第一人称可见了 + if (firstPersonVisible) { + // 下次再说 + if (Config.enableEntityCullingRateLimiting() && !this.culling.takeToken()) { + return; + } + cullableObject.setShown(this, true); + return; + } + if (this.culling.isVisible(cullingData, this.thirdPersonCameraVec3, useRayTracing)) { + // 下次再说 + if (Config.enableEntityCullingRateLimiting() && !this.culling.takeToken()) { + return; + } + cullableObject.setShown(this, true); + } + // 仍然不可见 + } + } else { + cullableObject.setShown(this, true); } } @@ -1427,6 +1439,24 @@ public class BukkitServerPlayer extends Player { this.trackedBlockEntityRenderers.clear(); } + @Override + public void addTrackedFurniture(int entityId, Furniture furniture) { + this.trackedFurniture.put(entityId, new VirtualCullableObject(furniture)); + } + + @Override + public void removeTrackedFurniture(int entityId) { + VirtualCullableObject remove = this.trackedFurniture.remove(entityId); + if (remove != null && remove.isShown()) { + remove.cullable().hide(this); + } + } + + @Override + public void clearTrackedFurniture() { + this.trackedFurniture.clear(); + } + @Override public WorldPosition eyePosition() { return LocationUtils.toWorldPosition(this.getEyeLocation()); diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractFurnitureManager.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractFurnitureManager.java index 092e70ea7..c0569fd87 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractFurnitureManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractFurnitureManager.java @@ -124,7 +124,7 @@ public abstract class AbstractFurnitureManager implements FurnitureManager { String variantName = e0.getKey(); Map variantArguments = ResourceConfigUtils.getAsMap(e0.getValue(), variantName); Optional optionalLootSpawnOffset = Optional.ofNullable(variantArguments.get("loot-spawn-offset")).map(it -> ResourceConfigUtils.getAsVector3f(it, "loot-spawn-offset")); - List> elements = ResourceConfigUtils.parseConfigAsList(variantArguments.get("elementConfigs"), FurnitureElementConfigs::fromMap); + List> elements = ResourceConfigUtils.parseConfigAsList(variantArguments.get("elements"), FurnitureElementConfigs::fromMap); // fixme 外部模型不应该在这 Optional externalModel; @@ -141,7 +141,12 @@ public abstract class AbstractFurnitureManager implements FurnitureManager { hitboxes = List.of(defaultHitBox()); } + // fixme 动态计算aabb,因为家具具有朝向 + AABB maxAABB = new AABB(0,0,0,1,1,1); + variants.put(variantName, new FurnitureVariant( + variantName, + parseCullingData(section.get("entity-culling"), maxAABB), elements.toArray(new FurnitureElementConfig[0]), hitboxes.toArray(new FurnitureHitBoxConfig[0]), externalModel, @@ -149,15 +154,13 @@ public abstract class AbstractFurnitureManager implements FurnitureManager { )); } - AABB maxAABB = null; - FurnitureConfig furniture = FurnitureConfig.builder() .id(id) .settings(FurnitureSettings.fromMap(MiscUtils.castToMap(section.get("settings"), true))) .variants(variants) .events(EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event"))) .lootTable(LootTable.fromMap(MiscUtils.castToMap(section.get("loot"), true))) - .cullingData(parseCullingData(section.get("entity-culling"), maxAABB)) + .build(); AbstractFurnitureManager.this.byId.put(id, furniture); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/Furniture.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/Furniture.java index d50a23ea0..32f0b7c4a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/Furniture.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/Furniture.java @@ -1,6 +1,10 @@ package net.momirealms.craftengine.core.entity.furniture; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.momirealms.craftengine.core.entity.Entity; import net.momirealms.craftengine.core.entity.furniture.element.FurnitureElement; import net.momirealms.craftengine.core.entity.furniture.element.FurnitureElementConfig; @@ -15,13 +19,12 @@ import net.momirealms.craftengine.core.world.Cullable; 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.jetbrains.annotations.Nullable; import org.joml.Quaternionf; import org.joml.Vector3f; import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.List; import java.util.UUID; public abstract class Furniture implements Cullable { @@ -29,18 +32,20 @@ public abstract class Furniture implements Cullable { public final FurnitureDataAccessor dataAccessor; public final WeakReference metaDataEntity; + protected CullingData cullingData; protected FurnitureVariant currentVariant; protected FurnitureElement[] elements; protected Collider[] colliders; protected FurnitureHitBox[] hitboxes; - protected Int2ObjectMap hitboxMap; - protected int[] entityIds; + protected int[] virtualEntityIds; + protected int[] colliderEntityIds; protected Furniture(Entity metaDataEntity, FurnitureDataAccessor data, FurnitureConfig config) { this.config = config; this.dataAccessor = data; this.metaDataEntity = new WeakReference<>(metaDataEntity); + this.setVariant(config.getVariant(data)); } public WeakReference metaDataEntity() { @@ -48,25 +53,24 @@ public abstract class Furniture implements Cullable { } public FurnitureVariant getCurrentVariant() { - return currentVariant; - } - - public String getCurrentVariantName() { - return null; + return this.currentVariant; } public void setVariant(FurnitureVariant variant) { this.currentVariant = variant; - WorldPosition position = this.position(); + this.hitboxMap = new Int2ObjectOpenHashMap<>(); // 初始化家具元素 + IntList virtualEntityIds = new IntArrayList(); FurnitureElementConfig[] elementConfigs = variant.elementConfigs(); this.elements = new FurnitureElement[elementConfigs.length]; for (int i = 0; i < elementConfigs.length; i++) { - this.elements[i] = elementConfigs[i].create(this); + FurnitureElement element = elementConfigs[i].create(this); + this.elements[i] = element; + element.collectVirtualEntityId(virtualEntityIds::addLast); } // 初始化碰撞箱 - FurnitureHitBoxConfig[] furnitureHitBoxConfigs = variant.furnitureHitBoxConfigs(); - List colliders = new ArrayList<>(furnitureHitBoxConfigs.length); + FurnitureHitBoxConfig[] furnitureHitBoxConfigs = variant.hitBoxConfigs(); + ObjectArrayList colliders = new ObjectArrayList<>(furnitureHitBoxConfigs.length); this.hitboxes = new FurnitureHitBox[furnitureHitBoxConfigs.length]; for (int i = 0; i < furnitureHitBoxConfigs.length; i++) { FurnitureHitBox hitbox = furnitureHitBoxConfigs[i].create(this); @@ -74,12 +78,23 @@ public abstract class Furniture implements Cullable { for (int hitboxEntityId : hitbox.virtualEntityIds()) { this.hitboxMap.put(hitboxEntityId, hitbox); } - Collider collider = hitbox.collider(); - if (collider != null) { - colliders.add(collider); - } + colliders.addAll(hitbox.colliders()); + hitbox.collectVirtualEntityIds(virtualEntityIds::addLast); } + // 虚拟碰撞箱的实体id + this.virtualEntityIds = virtualEntityIds.toIntArray(); this.colliders = colliders.toArray(new Collider[0]); + this.colliderEntityIds = colliders.stream().mapToInt(Collider::entityId).toArray(); + this.cullingData = createCullingData(variant.cullingData()); + } + + private CullingData createCullingData(CullingData parent) { + if (parent == null) return null; + AABB aabb = parent.aabb; + WorldPosition position = position(); + Vec3d pos1 = getRelativePosition(position, new Vector3f((float) aabb.minX, (float) aabb.minY, (float) aabb.minZ)); + Vec3d pos2 = getRelativePosition(position, new Vector3f((float) aabb.maxX, (float) aabb.maxY, (float) aabb.maxZ)); + return new CullingData(new AABB(pos1.x, pos1.y, pos1.z, pos2.x, pos2.y, pos2.z), parent.maxDistance, parent.aabbExpansion, parent.rayTracing); } @Nullable @@ -90,15 +105,20 @@ public abstract class Furniture implements Cullable { @Nullable @Override public CullingData cullingData() { - return this.config.cullingData(); + return this.cullingData; } public Key id() { return this.config.id(); } - public int[] entityIds() { - return this.entityIds; + // 会发给玩家的包 + public int[] virtualEntityIds() { + return this.virtualEntityIds; + } + + public int[] colliderEntityIds() { + return colliderEntityIds; } public UUID uuid() { @@ -146,11 +166,11 @@ public abstract class Furniture implements Cullable { public abstract void destroy(); public FurnitureConfig config() { - return config; + return this.config; } public FurnitureDataAccessor dataAccessor() { - return dataAccessor; + return this.dataAccessor; } public Collider[] colliders() { diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureColorSource.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureColorSource.java new file mode 100644 index 000000000..2a6427080 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureColorSource.java @@ -0,0 +1,6 @@ +package net.momirealms.craftengine.core.entity.furniture; + +import net.momirealms.craftengine.core.util.Color; + +public record FurnitureColorSource(Color dyedColor, int[] fireworkColors) { +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureConfig.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureConfig.java index 6e70376e6..7ef9ffd4c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureConfig.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureConfig.java @@ -67,8 +67,6 @@ public interface FurnitureConfig { } - CullingData cullingData(); - static Builder builder() { return new FurnitureConfigImpl.BuilderImpl(); } @@ -87,8 +85,6 @@ public interface FurnitureConfig { Builder behavior(FurnitureBehavior behavior); - Builder cullingData(CullingData cullingData); - FurnitureConfig build(); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureConfigImpl.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureConfigImpl.java index 8d6fe94b8..632e4fe80 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureConfigImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureConfigImpl.java @@ -23,7 +23,6 @@ class FurnitureConfigImpl implements FurnitureConfig { private final Map variants; private final Map>> events; private final FurnitureBehavior behavior; - private final CullingData cullingData; @Nullable private final LootTable lootTable; @@ -32,14 +31,12 @@ class FurnitureConfigImpl implements FurnitureConfig { @NotNull Map variants, @NotNull Map>> events, @NotNull FurnitureBehavior behavior, - @Nullable CullingData cullingData, @Nullable LootTable lootTable) { this.id = id; this.settings = settings; this.variants = ImmutableMap.copyOf(variants); this.lootTable = lootTable; this.behavior = behavior; - this.cullingData = cullingData; this.events = events; } @@ -75,11 +72,6 @@ class FurnitureConfigImpl implements FurnitureConfig { return this.behavior; } - @Override - public CullingData cullingData() { - return this.cullingData; - } - @Nullable @Override public FurnitureVariant getVariant(String variantName) { @@ -93,11 +85,10 @@ class FurnitureConfigImpl implements FurnitureConfig { private Map>> events; private LootTable lootTable; private FurnitureBehavior behavior = EmptyFurnitureBehavior.INSTANCE; - private CullingData cullingData; @Override public FurnitureConfig build() { - return new FurnitureConfigImpl(this.id, this.settings, this.variants, this.events, this.behavior, this.cullingData, this.lootTable); + return new FurnitureConfigImpl(this.id, this.settings, this.variants, this.events, this.behavior, this.lootTable); } @Override @@ -130,12 +121,6 @@ class FurnitureConfigImpl implements FurnitureConfig { return this; } - @Override - public Builder cullingData(CullingData cullingData) { - this.cullingData = cullingData; - return this; - } - @Override public Builder behavior(FurnitureBehavior behavior) { this.behavior = behavior; diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureDataAccessor.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureDataAccessor.java index 34f862f4f..e1bb1bd0e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureDataAccessor.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureDataAccessor.java @@ -68,12 +68,20 @@ public class FurnitureDataAccessor { this.data.putByteArray(ITEM, item.toByteArray()); } + public FurnitureColorSource getColorSource() { + return new FurnitureColorSource(dyedColor().orElse(null), fireworkExplosionColors().orElse(null)); + } + public Optional fireworkExplosionColors() { if (this.data.containsKey(FIREWORK_EXPLOSION_COLORS)) return Optional.of(this.data.getIntArray(FIREWORK_EXPLOSION_COLORS)); return Optional.empty(); } public void setFireworkExplosionColors(int[] colors) { + if (colors == null) { + this.data.remove(FIREWORK_EXPLOSION_COLORS); + return; + } this.data.putIntArray(FIREWORK_EXPLOSION_COLORS, colors); } @@ -82,7 +90,11 @@ public class FurnitureDataAccessor { return Optional.empty(); } - public void setDyedColor(Color color) { + public void setDyedColor(@Nullable Color color) { + if (color == null) { + this.data.remove(DYED_COLOR); + return; + } this.data.putInt(DYED_COLOR, color.color()); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java index 5f8ca181a..99d4ee3a0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java @@ -1,6 +1,5 @@ package net.momirealms.craftengine.core.entity.furniture; -import net.momirealms.craftengine.core.entity.AbstractEntity; import net.momirealms.craftengine.core.plugin.Manageable; import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.util.Key; @@ -31,16 +30,14 @@ public interface FurnitureManager extends Manageable { Map loadedFurniture(); - boolean isFurnitureRealEntity(int entityId); + boolean isFurnitureMetaEntity(int entityId); @Nullable - Furniture loadedFurnitureByRealEntityId(int entityId); + Furniture loadedFurnitureByMetaEntityId(int entityId); @Nullable - default Furniture loadedFurnitureByRealEntity(AbstractEntity entity) { - return loadedFurnitureByRealEntityId(entity.entityID()); - } + Furniture loadedFurnitureByVirtualEntityId(int entityId); @Nullable - Furniture loadedFurnitureByEntityId(int entityId); + Furniture loadedFurnitureByColliderEntityId(int entityId); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureVariant.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureVariant.java index 056a8f47f..206a5ddf7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureVariant.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureVariant.java @@ -2,12 +2,16 @@ package net.momirealms.craftengine.core.entity.furniture; import net.momirealms.craftengine.core.entity.furniture.element.FurnitureElementConfig; import net.momirealms.craftengine.core.entity.furniture.hitbox.FurnitureHitBoxConfig; +import net.momirealms.craftengine.core.plugin.entityculling.CullingData; +import org.jetbrains.annotations.Nullable; import org.joml.Vector3f; import java.util.Optional; -public record FurnitureVariant(FurnitureElementConfig[] elementConfigs, - FurnitureHitBoxConfig[] furnitureHitBoxConfigs, +public record FurnitureVariant(String name, + @Nullable CullingData cullingData, + FurnitureElementConfig[] elementConfigs, + FurnitureHitBoxConfig[] hitBoxConfigs, Optional externalModel, Optional dropOffset) { } \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/element/FurnitureElement.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/element/FurnitureElement.java index 118d5bd92..6a625f941 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/element/FurnitureElement.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/element/FurnitureElement.java @@ -2,8 +2,14 @@ package net.momirealms.craftengine.core.entity.furniture.element; import net.momirealms.craftengine.core.entity.player.Player; +import java.util.function.Consumer; + public interface FurnitureElement { + int[] virtualEntityIds(); + + void collectVirtualEntityId(Consumer collector); + void show(Player player); void hide(Player player); diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/hitbox/AbstractFurnitureHitBoxConfig.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/hitbox/AbstractFurnitureHitBoxConfig.java index f977145e7..b121fbe02 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/hitbox/AbstractFurnitureHitBoxConfig.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/hitbox/AbstractFurnitureHitBoxConfig.java @@ -10,7 +10,11 @@ public abstract class AbstractFurnitureHitBoxConfig i protected final boolean blocksBuilding; protected final boolean canBeHitByProjectile; - public AbstractFurnitureHitBoxConfig(SeatConfig[] seats, Vector3f position, boolean canUseItemOn, boolean blocksBuilding, boolean canBeHitByProjectile) { + public AbstractFurnitureHitBoxConfig(SeatConfig[] seats, + Vector3f position, + boolean canUseItemOn, + boolean blocksBuilding, + boolean canBeHitByProjectile) { this.seats = seats; this.position = position; this.canUseItemOn = canUseItemOn; diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/hitbox/FurnitureHitBox.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/hitbox/FurnitureHitBox.java index 7fbb4ca70..7f3d894c4 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/hitbox/FurnitureHitBox.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/hitbox/FurnitureHitBox.java @@ -4,26 +4,41 @@ import net.momirealms.craftengine.core.entity.furniture.Collider; import net.momirealms.craftengine.core.entity.player.Player; 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 org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Optional; +import java.util.function.Consumer; public interface FurnitureHitBox extends SeatOwner { - Seat[] seats(); - - AABB aabb(); - Vec3d position(); - @Nullable - Collider collider(); + Seat[] seats(); + + AABB[] aabb(); + + List colliders(); int[] virtualEntityIds(); + void collectVirtualEntityIds(Consumer collector); + void show(Player player); void hide(Player player); FurnitureHitBoxConfig config(); + + default Optional clip(Vec3d min, Vec3d max) { + for (AABB value : aabb()) { + Optional clip = value.clip(min, max); + if (clip.isPresent()) { + return clip; + } + } + return Optional.empty(); + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/hitbox/FurnitureHitBoxConfig.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/hitbox/FurnitureHitBoxConfig.java index e1730c7f2..689cb130c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/hitbox/FurnitureHitBoxConfig.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/hitbox/FurnitureHitBoxConfig.java @@ -2,8 +2,12 @@ package net.momirealms.craftengine.core.entity.furniture.hitbox; import net.momirealms.craftengine.core.entity.furniture.Furniture; import net.momirealms.craftengine.core.entity.seat.SeatConfig; +import net.momirealms.craftengine.core.world.WorldPosition; +import net.momirealms.craftengine.core.world.collision.AABB; import org.joml.Vector3f; +import java.util.function.Consumer; + public interface FurnitureHitBoxConfig { H create(Furniture furniture); @@ -17,4 +21,6 @@ public interface FurnitureHitBoxConfig { boolean canBeHitByProjectile(); boolean canUseItemOn(); + + void prepareForPlacement(WorldPosition targetPos, Consumer aabbConsumer); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java b/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java index ae13804e6..2f89bf90b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java @@ -4,6 +4,7 @@ import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.advancement.AdvancementType; import net.momirealms.craftengine.core.block.entity.render.ConstantBlockEntityRenderer; import net.momirealms.craftengine.core.entity.AbstractEntity; +import net.momirealms.craftengine.core.entity.furniture.Furniture; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.context.CooldownData; import net.momirealms.craftengine.core.plugin.network.NetWorkUser; @@ -217,12 +218,18 @@ public abstract class Player extends AbstractEntity implements NetWorkUser { public abstract void removeTrackedBlockEntities(Collection renders); + public abstract void addTrackedFurniture(int entityId, Furniture furniture); + public abstract void clearTrackedBlockEntities(); @Override public void remove() { } + public abstract void removeTrackedFurniture(int entityId); + + public abstract void clearTrackedFurniture(); + public abstract WorldPosition eyePosition(); @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/FurnitureParameterProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/FurnitureParameterProvider.java index dcf69a5e4..c7dd3f082 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/FurnitureParameterProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/FurnitureParameterProvider.java @@ -14,7 +14,7 @@ public class FurnitureParameterProvider implements ChainParameterProvider f.config().id()); CONTEXT_FUNCTIONS.put(DirectContextParameters.UUID, Furniture::uuid); - CONTEXT_FUNCTIONS.put(DirectContextParameters.VARIANT, Furniture::getCurrentVariantName); + CONTEXT_FUNCTIONS.put(DirectContextParameters.VARIANT, f -> f.getCurrentVariant().name()); CONTEXT_FUNCTIONS.put(DirectContextParameters.X, furniture -> furniture.position().x()); CONTEXT_FUNCTIONS.put(DirectContextParameters.Y, furniture -> furniture.position().y()); CONTEXT_FUNCTIONS.put(DirectContextParameters.Z, furniture -> furniture.position().z()); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/EntityPacketHandler.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/EntityPacketHandler.java index 57fb85de9..233b09cf5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/EntityPacketHandler.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/EntityPacketHandler.java @@ -5,7 +5,7 @@ import net.momirealms.craftengine.core.entity.player.Player; public interface EntityPacketHandler { - default boolean handleEntitiesRemove(IntList entityIds) { + default boolean handleEntitiesRemove(NetWorkUser user, IntList entityIds) { return false; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java index 4461e5d93..08308a8fa 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java @@ -266,6 +266,8 @@ public final class ResourceConfigUtils { if (o == null) return new Vector3f(); if (o instanceof List list && list.size() == 3) { return new Vector3f(Float.parseFloat(list.get(0).toString()), Float.parseFloat(list.get(1).toString()), Float.parseFloat(list.get(2).toString())); + } else if (o instanceof Number number) { + return new Vector3f(number.floatValue()); } else { String stringFormat = o.toString(); String[] split = stringFormat.split(",");