From 63e038db5ad51a1adf4498ec16a6e6922eb8b20a Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Sat, 1 Nov 2025 20:28:18 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=BA=A7=E6=A4=85=E6=9C=BA?= =?UTF-8?q?=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/api/CraftEngineFurniture.java | 14 +- .../api/event/FurnitureInteractEvent.java | 11 +- .../block/behavior/BukkitBlockBehaviors.java | 2 + .../block/behavior/SeatBlockBehavior.java | 80 ++++++++ .../behavior/SimpleParticleBlockBehavior.java | 2 +- .../behavior/SimpleStorageBlockBehavior.java | 2 +- .../UnsafeCompositeBlockBehavior.java | 3 +- .../WallTorchParticleBlockBehavior.java | 2 +- .../block/entity/BukkitBlockEntityTypes.java | 7 +- .../bukkit/block/entity/SeatBlockEntity.java | 69 +++++++ .../bukkit/entity/BukkitEntity.java | 2 +- .../entity/furniture/BukkitFurniture.java | 176 +++++------------- .../furniture/BukkitFurnitureManager.java | 99 +--------- .../bukkit/entity/furniture/BukkitHitBox.java | 70 +++++++ .../furniture/DismountListener1_20_3.java | 13 +- .../furniture/FurnitureEventListener.java | 37 ---- .../furniture/hitbox/BukkitHitBoxTypes.java | 8 +- ...tomHitBox.java => CustomHitBoxConfig.java} | 17 +- ...itBox.java => HappyGhastHitBoxConfig.java} | 29 +-- ...tBox.java => InteractionHitBoxConfig.java} | 39 ++-- ...erHitBox.java => ShulkerHitBoxConfig.java} | 47 +++-- .../bukkit/entity/seat/BukkitSeat.java | 146 +++++++++++++++ .../bukkit/entity/seat/BukkitSeatManager.java | 120 ++++++++++++ .../bukkit/item/LegacyNetworkItemHandler.java | 8 +- .../bukkit/item/ModernNetworkItemHandler.java | 6 +- .../bukkit/item/behavior/AxeItemBehavior.java | 1 - .../item/behavior/FurnitureItemBehavior.java | 6 +- .../bukkit/plugin/BukkitCraftEngine.java | 2 + .../feature/DebugRealStateUsageCommand.java | 5 +- .../plugin/network/BukkitNetworkManager.java | 58 +++--- .../plugin/network/payload/PayloadHelper.java | 2 +- .../bukkit/util/LocationUtils.java | 2 +- common-files/src/main/resources/config.yml | 2 +- .../default/configuration/blocks/sofa.yml | 6 + .../core/block/AbstractBlockManager.java | 2 +- .../craftengine/core/block/BlockBehavior.java | 2 +- .../block/behavior/EntityBlockBehavior.java | 5 +- .../core/block/entity/BlockEntityType.java | 2 +- .../block/entity/BlockEntityTypeKeys.java | 1 + .../core/block/entity/BlockEntityTypes.java | 4 +- .../core/block/properties/type/DoorHinge.java | 3 +- .../properties/type/DoubleBlockHalf.java | 3 +- .../properties/type/SingleBlockHalf.java | 3 +- .../furniture/AbstractFurnitureManager.java | 8 +- ...tHitBox.java => AbstractHitBoxConfig.java} | 9 +- .../entity/furniture/CustomFurniture.java | 2 +- .../core/entity/furniture/Furniture.java | 32 ++-- .../entity/furniture/FurnitureManager.java | 2 - .../core/entity/furniture/HitBox.java | 34 +--- .../core/entity/furniture/HitBoxConfig.java | 34 ++++ .../entity/furniture/HitBoxConfigFactory.java | 8 + .../core/entity/furniture/HitBoxFactory.java | 23 --- .../core/entity/furniture/HitBoxPart.java | 7 + .../core/entity/furniture/HitBoxTypes.java | 8 +- .../core/entity/furniture/Seat.java | 23 --- .../craftengine/core/entity/seat/Seat.java | 17 ++ .../core/entity/seat/SeatConfig.java | 30 +++ .../core/entity/seat/SeatManager.java | 9 + .../core/entity/seat/SeatOwner.java | 8 + .../core/item/NetworkItemBuildContext.java | 46 +++++ .../craftengine/core/plugin/CraftEngine.java | 5 + .../context/function/DamageItemFunction.java | 3 - .../text/component/ComponentProvider.java | 2 +- .../core/plugin/text/minimessage/L10NTag.java | 41 ++++ .../core/registry/BuiltInRegistries.java | 4 +- .../craftengine/core/registry/Registries.java | 4 +- .../DefaultBlockEntitySerializer.java | 13 +- gradle.properties | 2 +- 68 files changed, 998 insertions(+), 494 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SeatBlockBehavior.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/SeatBlockEntity.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitHitBox.java rename bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/{CustomHitBox.java => CustomHitBoxConfig.java} (86%) rename bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/{HappyGhastHitBox.java => HappyGhastHitBoxConfig.java} (83%) rename bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/{InteractionHitBox.java => InteractionHitBoxConfig.java} (74%) rename bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/{ShulkerHitBox.java => ShulkerHitBoxConfig.java} (87%) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/seat/BukkitSeat.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/seat/BukkitSeatManager.java rename core/src/main/java/net/momirealms/craftengine/core/entity/furniture/{AbstractHitBox.java => AbstractHitBoxConfig.java} (71%) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBoxConfig.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBoxConfigFactory.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBoxFactory.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBoxPart.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/entity/furniture/Seat.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/entity/seat/Seat.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/entity/seat/SeatConfig.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/entity/seat/SeatManager.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/entity/seat/SeatOwner.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/NetworkItemBuildContext.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/L10NTag.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 d7367e5cd..4a47cd615 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 @@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.api; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; +import net.momirealms.craftengine.bukkit.entity.seat.BukkitSeatManager; import net.momirealms.craftengine.bukkit.nms.CollisionEntity; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; @@ -18,6 +19,7 @@ import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextPar import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.WorldPosition; +import net.momirealms.sparrow.nbt.CompoundTag; import org.bukkit.Location; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; @@ -159,8 +161,7 @@ public final class CraftEngineFurniture { * @return is seat or not */ public static boolean isSeat(@NotNull Entity entity) { - Integer baseEntityId = entity.getPersistentDataContainer().get(BukkitFurnitureManager.FURNITURE_SEAT_BASE_ENTITY_KEY, PersistentDataType.INTEGER); - return baseEntityId != null; + return entity.getPersistentDataContainer().has(BukkitSeatManager.SEAT_KEY); } /** @@ -182,9 +183,12 @@ public final class CraftEngineFurniture { */ @Nullable public static BukkitFurniture getLoadedFurnitureBySeat(@NotNull Entity seat) { - Integer baseEntityId = seat.getPersistentDataContainer().get(BukkitFurnitureManager.FURNITURE_SEAT_BASE_ENTITY_KEY, PersistentDataType.INTEGER); - if (baseEntityId == null) return null; - return BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(baseEntityId); + if (isSeat(seat)) { + CompoundTag seatExtraData = BukkitSeatManager.instance().getSeatExtraData(seat); + int entityId = seatExtraData.getInt("entity_id"); + BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(entityId); + } + return null; } /** diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureInteractEvent.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureInteractEvent.java index aba399794..1e1adcf47 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureInteractEvent.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureInteractEvent.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.bukkit.api.event; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture; +import net.momirealms.craftengine.core.entity.furniture.HitBox; import net.momirealms.craftengine.core.entity.player.InteractionHand; import org.bukkit.Location; import org.bukkit.entity.Player; @@ -15,15 +16,23 @@ public final class FurnitureInteractEvent extends PlayerEvent implements Cancell private final BukkitFurniture furniture; private final InteractionHand hand; private final Location interactionPoint; + private final HitBox hitBox; public FurnitureInteractEvent(@NotNull Player player, @NotNull BukkitFurniture furniture, @NotNull InteractionHand hand, - @NotNull Location interactionPoint) { + @NotNull Location interactionPoint, + @NotNull HitBox hitBox) { super(player); this.furniture = furniture; this.hand = hand; this.interactionPoint = interactionPoint; + this.hitBox = hitBox; + } + + @NotNull + public HitBox hitBox() { + return hitBox; } @NotNull diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java index 000ecaccd..4bb3daf89 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java @@ -43,6 +43,7 @@ public class BukkitBlockBehaviors extends BlockBehaviors { public static final Key ATTACHED_STEM_BLOCK = Key.from("craftengine:attached_stem_block"); public static final Key CHIME_BLOCK = Key.from("craftengine:chime_block"); public static final Key BUDDING_BLOCK = Key.from("craftengine:budding_block"); + public static final Key SEAT_BLOCK = Key.from("craftengine:seat_block"); public static void init() { register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE); @@ -84,5 +85,6 @@ public class BukkitBlockBehaviors extends BlockBehaviors { register(ATTACHED_STEM_BLOCK, AttachedStemBlockBehavior.FACTORY); register(CHIME_BLOCK, ChimeBlockBehavior.FACTORY); register(BUDDING_BLOCK, BuddingBlockBehavior.FACTORY); + register(SEAT_BLOCK, SeatBlockBehavior.FACTORY); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SeatBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SeatBlockBehavior.java new file mode 100644 index 000000000..c54f6eb66 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SeatBlockBehavior.java @@ -0,0 +1,80 @@ +package net.momirealms.craftengine.bukkit.block.behavior; + +import net.momirealms.craftengine.bukkit.block.entity.BukkitBlockEntityTypes; +import net.momirealms.craftengine.bukkit.block.entity.SeatBlockEntity; +import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; +import net.momirealms.craftengine.core.block.BlockBehavior; +import net.momirealms.craftengine.core.block.CustomBlock; +import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; +import net.momirealms.craftengine.core.block.behavior.EntityBlockBehavior; +import net.momirealms.craftengine.core.block.entity.BlockEntity; +import net.momirealms.craftengine.core.block.entity.BlockEntityType; +import net.momirealms.craftengine.core.block.properties.Property; +import net.momirealms.craftengine.core.entity.player.InteractionResult; +import net.momirealms.craftengine.core.entity.seat.SeatConfig; +import net.momirealms.craftengine.core.item.context.UseOnContext; +import net.momirealms.craftengine.core.util.HorizontalDirection; +import net.momirealms.craftengine.core.world.BlockPos; +import net.momirealms.craftengine.core.world.CEWorld; + +import java.util.Map; + +public class SeatBlockBehavior extends BukkitBlockBehavior implements EntityBlockBehavior { + public static final Factory FACTORY = new Factory(); + private final Property directionProperty; + private final SeatConfig[] seats; + + public SeatBlockBehavior(CustomBlock customBlock, Property directionProperty, SeatConfig[] seats) { + super(customBlock); + this.seats = seats; + this.directionProperty = directionProperty; + } + + @Override + public BlockEntity createBlockEntity(BlockPos pos, ImmutableBlockState state) { + return new SeatBlockEntity(pos, state, this.seats); + } + + @Override + public BlockEntityType blockEntityType(ImmutableBlockState state) { + return EntityBlockBehavior.blockEntityTypeHelper(BukkitBlockEntityTypes.SEAT); + } + + public Property directionProperty() { + return this.directionProperty; + } + + @Override + public InteractionResult useWithoutItem(UseOnContext context, ImmutableBlockState state) { + BukkitServerPlayer player = (BukkitServerPlayer) context.getPlayer(); + if (player == null || player.isSecondaryUseActive()) { + return InteractionResult.PASS; + } + player.swingHand(context.getHand()); + CEWorld world = context.getLevel().storageWorld(); + BlockEntity blockEntity = world.getBlockEntityAtIfLoaded(context.getClickedPos()); + if (!(blockEntity instanceof SeatBlockEntity seatBlockEntity)) { + return InteractionResult.PASS; + } + if (seatBlockEntity.spawnSeat(player)) { + return InteractionResult.SUCCESS_AND_CANCEL; + } else { + return InteractionResult.PASS; + } + } + + public static class Factory implements BlockBehaviorFactory { + + @SuppressWarnings("unchecked") + @Override + public BlockBehavior create(CustomBlock block, Map arguments) { + Property directionProperty = null; + Property facing = block.getProperty("facing"); + if (facing != null && facing.valueClass() == HorizontalDirection.class) { + directionProperty = (Property) facing; + } + return new SeatBlockBehavior(block, directionProperty, SeatConfig.fromObj(arguments.get("seats"))); + } + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SimpleParticleBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SimpleParticleBlockBehavior.java index fa0944580..d75184789 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SimpleParticleBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SimpleParticleBlockBehavior.java @@ -38,7 +38,7 @@ public class SimpleParticleBlockBehavior extends BukkitBlockBehavior implements } @Override - public BlockEntityType blockEntityType() { + public BlockEntityType blockEntityType(ImmutableBlockState state) { return EntityBlockBehavior.blockEntityTypeHelper(BukkitBlockEntityTypes.SIMPLE_PARTICLE); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SimpleStorageBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SimpleStorageBlockBehavior.java index 7a8afdd35..28271e87e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SimpleStorageBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SimpleStorageBlockBehavior.java @@ -116,7 +116,7 @@ public class SimpleStorageBlockBehavior extends BukkitBlockBehavior implements E } @Override - public BlockEntityType blockEntityType() { + public BlockEntityType blockEntityType(ImmutableBlockState state) { return EntityBlockBehavior.blockEntityTypeHelper(BukkitBlockEntityTypes.SIMPLE_STORAGE); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/UnsafeCompositeBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/UnsafeCompositeBlockBehavior.java index cea6a2484..be647e450 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/UnsafeCompositeBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/UnsafeCompositeBlockBehavior.java @@ -1,6 +1,5 @@ package net.momirealms.craftengine.bukkit.block.behavior; -import net.momirealms.craftengine.core.block.BlockBehavior; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.behavior.AbstractBlockBehavior; @@ -47,7 +46,7 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior @SuppressWarnings("unchecked") @Override - public Optional getAs(Class tClass) { + public Optional getAs(Class tClass) { for (AbstractBlockBehavior behavior : this.behaviors) { if (tClass.isInstance(behavior)) { return Optional.of((T) behavior); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/WallTorchParticleBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/WallTorchParticleBlockBehavior.java index 85888fc1e..b88216a98 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/WallTorchParticleBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/WallTorchParticleBlockBehavior.java @@ -47,7 +47,7 @@ public class WallTorchParticleBlockBehavior extends BukkitBlockBehavior implemen } @Override - public BlockEntityType blockEntityType() { + public BlockEntityType blockEntityType(ImmutableBlockState state) { return EntityBlockBehavior.blockEntityTypeHelper(BukkitBlockEntityTypes.WALL_TORCH_PARTICLE); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/BukkitBlockEntityTypes.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/BukkitBlockEntityTypes.java index e2ccd93e6..204d0679f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/BukkitBlockEntityTypes.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/BukkitBlockEntityTypes.java @@ -5,9 +5,10 @@ import net.momirealms.craftengine.core.block.entity.BlockEntityTypeKeys; import net.momirealms.craftengine.core.block.entity.BlockEntityTypes; public class BukkitBlockEntityTypes extends BlockEntityTypes { - public static final BlockEntityType SIMPLE_STORAGE = register(BlockEntityTypeKeys.SIMPLE_STORAGE, SimpleStorageBlockEntity::new); - public static final BlockEntityType SIMPLE_PARTICLE = register(BlockEntityTypeKeys.SIMPLE_PARTICLE, SimpleParticleBlockEntity::new); - public static final BlockEntityType WALL_TORCH_PARTICLE = register(BlockEntityTypeKeys.WALL_TORCH_PARTICLE, WallTorchParticleBlockEntity::new); + public static final BlockEntityType SIMPLE_STORAGE = register(BlockEntityTypeKeys.SIMPLE_STORAGE); + public static final BlockEntityType SIMPLE_PARTICLE = register(BlockEntityTypeKeys.SIMPLE_PARTICLE); + public static final BlockEntityType WALL_TORCH_PARTICLE = register(BlockEntityTypeKeys.WALL_TORCH_PARTICLE); + public static final BlockEntityType SEAT = register(BlockEntityTypeKeys.SEAT); private BukkitBlockEntityTypes() {} } \ No newline at end of file diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/SeatBlockEntity.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/SeatBlockEntity.java new file mode 100644 index 000000000..360e58f38 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/SeatBlockEntity.java @@ -0,0 +1,69 @@ +package net.momirealms.craftengine.bukkit.block.entity; + +import net.momirealms.craftengine.bukkit.block.behavior.SeatBlockBehavior; +import net.momirealms.craftengine.bukkit.entity.seat.BukkitSeat; +import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.block.entity.BlockEntity; +import net.momirealms.craftengine.core.block.properties.Property; +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.entity.seat.SeatOwner; +import net.momirealms.craftengine.core.util.HorizontalDirection; +import net.momirealms.craftengine.core.world.BlockPos; +import net.momirealms.craftengine.core.world.WorldPosition; +import net.momirealms.sparrow.nbt.CompoundTag; + +import java.util.Optional; + +public class SeatBlockEntity extends BlockEntity implements SeatOwner { + private final Seat[] seats; + + @SuppressWarnings("unchecked") + public SeatBlockEntity(BlockPos pos, ImmutableBlockState blockState, SeatConfig[] seats) { + super(BukkitBlockEntityTypes.SEAT, pos, blockState); + this.seats = new Seat[seats.length]; + for (int i = 0; i < seats.length; i++) { + this.seats[i] = new BukkitSeat<>(this, seats[i]); + } + } + + @Override + public void saveCustomData(CompoundTag data) { + data.putString("type", "seat_block_entity"); + } + + @Override + public void preRemove() { + for (Seat seat : this.seats) { + seat.destroy(); + } + } + + public boolean spawnSeat(Player player) { + Optional seatBehavior = super.blockState.behavior().getAs(SeatBlockBehavior.class); + if (seatBehavior.isEmpty()) { + return false; + } + float yRot = 0; + Property directionProperty = seatBehavior.get().directionProperty(); + if (directionProperty != null) { + HorizontalDirection direction = super.blockState.get(directionProperty); + if (direction == HorizontalDirection.NORTH) { + yRot = 180; + } else if (direction == HorizontalDirection.EAST) { + yRot = -90; + } else if (direction == HorizontalDirection.WEST) { + yRot = 90; + } + } + for (Seat seat : this.seats) { + if (!seat.isOccupied()) { + if (seat.spawnSeat(player, new WorldPosition(super.world.world(), super.pos.x() + 0.5, super.pos.y(), super.pos.z() + 0.5, 0, 180 - yRot))) { + return true; + } + } + } + return false; + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/BukkitEntity.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/BukkitEntity.java index 469c9f155..76dfed5d0 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/BukkitEntity.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/BukkitEntity.java @@ -13,7 +13,7 @@ import java.lang.ref.WeakReference; import java.util.UUID; public class BukkitEntity extends AbstractEntity { - private final WeakReference entity; + protected final WeakReference entity; public BukkitEntity(org.bukkit.entity.Entity entity) { this.entity = new WeakReference<>(entity); 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 c31816e18..e53c8da12 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 @@ -5,20 +5,16 @@ import it.unimi.dsi.fastutil.ints.IntArrayList; import net.momirealms.craftengine.bukkit.entity.BukkitEntity; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; -import net.momirealms.craftengine.bukkit.util.EntityUtils; -import net.momirealms.craftengine.bukkit.util.LegacyAttributeUtils; import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.core.entity.furniture.*; +import net.momirealms.craftengine.core.entity.seat.Seat; import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.util.ArrayUtils; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.QuaternionUtils; -import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.WorldPosition; -import net.momirealms.craftengine.core.world.collision.AABB; import org.bukkit.Location; -import org.bukkit.attribute.Attribute; -import org.bukkit.entity.*; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; import org.bukkit.persistence.PersistentDataType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -30,7 +26,6 @@ import java.lang.ref.WeakReference; import java.util.*; public class BukkitFurniture implements Furniture { - private final Key id; private final CustomFurniture furniture; private final CustomFurniture.Placement placement; private FurnitureExtraData extraData; @@ -44,13 +39,10 @@ public class BukkitFurniture implements Furniture { // cache private final List fakeEntityIds; private final List entityIds; - private final Map hitBoxes = new Int2ObjectArrayMap<>(); - private final Map aabb = new Int2ObjectArrayMap<>(); + private final Map hitBoxes = new Int2ObjectArrayMap<>(); + private final Map hitBoxParts = new Int2ObjectArrayMap<>(); private final boolean minimized; private final boolean hasExternalModel; - // seats - private final Set occupiedSeats = Collections.synchronizedSet(new HashSet<>()); - private final Vector> seats = new Vector<>(); // cached spawn packet private Object cachedSpawnPacket; private Object cachedMinimizedSpawnPacket; @@ -58,37 +50,40 @@ public class BukkitFurniture implements Furniture { public BukkitFurniture(Entity baseEntity, CustomFurniture furniture, FurnitureExtraData extraData) { - this.id = furniture.id(); this.extraData = extraData; this.baseEntityId = baseEntity.getEntityId(); - this.location = baseEntity.getLocation(); this.baseEntity = new WeakReference<>(baseEntity); this.furniture = furniture; this.minimized = furniture.settings().minimized(); + this.placement = furniture.getValidPlacement(extraData.anchorType().orElseGet(furniture::getAnyAnchorType)); + List fakeEntityIds = new IntArrayList(); List mainEntityIds = new IntArrayList(); mainEntityIds.add(this.baseEntityId); - this.placement = furniture.getValidPlacement(extraData.anchorType().orElseGet(furniture::getAnyAnchorType)); - // bind external furniture + // 绑定外部模型 Optional optionalExternal = placement.externalModel(); if (optionalExternal.isPresent()) { try { optionalExternal.get().bindModel(new BukkitEntity(baseEntity)); } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to load external model for furniture " + id, e); + CraftEngine.instance().logger().warn("Failed to load external model for furniture " + id(), e); } this.hasExternalModel = true; } else { this.hasExternalModel = false; } + Quaternionf conjugated = QuaternionUtils.toQuaternionf(0, Math.toRadians(180 - this.location.getYaw()), 0).conjugate(); List packets = new ArrayList<>(); List minimizedPackets = new ArrayList<>(); - List colliders = new ArrayList<>(); + List colliders = new ArrayList<>(4); WorldPosition position = position(); + + + // 初始化家具的元素 for (FurnitureElement element : placement.elements()) { int entityId = CoreReflections.instance$Entity$ENTITY_COUNTER.incrementAndGet(); fakeEntityIds.add(entityId); @@ -97,28 +92,41 @@ public class BukkitFurniture implements Furniture { if (this.minimized) minimizedPackets.add(packet); }); } - for (HitBox hitBox : placement.hitBoxes()) { - int[] ids = hitBox.acquireEntityIds(CoreReflections.instance$Entity$ENTITY_COUNTER::incrementAndGet); + + // 初始化碰撞箱 + for (HitBoxConfig hitBoxConfig : this.placement.hitBoxConfigs()) { + int[] ids = hitBoxConfig.acquireEntityIds(CoreReflections.instance$Entity$ENTITY_COUNTER::incrementAndGet); + List aabbs = new ArrayList<>(); + + hitBoxConfig.initPacketsAndColliders(ids, position, conjugated, (packet, canBeMinimized) -> { + packets.add(packet); + if (this.minimized && !canBeMinimized) { + minimizedPackets.add(packet); + } + }, colliders::add, part -> { + this.hitBoxParts.put(part.entityId(), part); + aabbs.add(part); + }); + + BukkitHitBox hitBox = new BukkitHitBox(this, hitBoxConfig, aabbs.toArray(new HitBoxPart[0])); for (int entityId : ids) { fakeEntityIds.add(entityId); mainEntityIds.add(entityId); this.hitBoxes.put(entityId, hitBox); } - hitBox.initPacketsAndColliders(ids, position, conjugated, (packet, canBeMinimized) -> { - packets.add(packet); - if (this.minimized && !canBeMinimized) { - minimizedPackets.add(packet); - } - }, colliders::add, this.aabb::put); } + + // 初始化缓存的家具包 try { this.cachedSpawnPacket = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(packets); if (this.minimized) { this.cachedMinimizedSpawnPacket = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(minimizedPackets); } } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to init spawn packets for furniture " + id, e); + CraftEngine.instance().logger().warn("Failed to init spawn packets for furniture " + id(), e); } + + this.fakeEntityIds = fakeEntityIds; this.entityIds = mainEntityIds; this.colliderEntities = colliders.toArray(new Collider[0]); @@ -186,57 +194,25 @@ public class BukkitFurniture implements Furniture { return; } this.baseEntity().remove(); + this.destroyColliders(); + this.destroySeats(); + } + + @Override + public void destroyColliders() { for (Collider entity : this.colliderEntities) { if (entity != null) entity.destroy(); } - for (WeakReference r : this.seats) { - Entity entity = r.get(); - if (entity == null) continue; - for (Entity passenger : entity.getPassengers()) { - entity.removePassenger(passenger); - } - entity.remove(); - } - this.seats.clear(); } @Override public void destroySeats() { - for (WeakReference entity : this.seats) { - Entity e = entity.get(); - if (e != null) { - e.remove(); + for (HitBox hitBox : this.hitBoxes.values()) { + for (Seat seat : hitBox.seats()) { + seat.destroy(); } } - this.seats.clear(); - } - - @Override - public Optional findFirstAvailableSeat(int targetEntityId) { - HitBox hitbox = hitBoxes.get(targetEntityId); - if (hitbox == null) return Optional.empty(); - - Seat[] seats = hitbox.seats(); - if (ArrayUtils.isEmpty(seats)) return Optional.empty(); - - return Arrays.stream(seats) - .filter(s -> !occupiedSeats.contains(s.offset())) - .findFirst(); - } - - @Override - public boolean removeOccupiedSeat(Vector3f seat) { - return this.occupiedSeats.remove(seat); - } - - @Override - public boolean tryOccupySeat(Seat seat) { - if (this.occupiedSeats.contains(seat.offset())) { - return false; - } - this.occupiedSeats.add(seat.offset()); - return true; } @Override @@ -263,14 +239,14 @@ public class BukkitFurniture implements Furniture { return this.colliderEntities; } - @Nullable - public HitBox hitBoxByEntityId(int id) { + @Override + public @Nullable HitBox hitBoxByEntityId(int id) { return this.hitBoxes.get(id); } - @Nullable - public AABB aabbByEntityId(int id) { - return this.aabb.get(id); + @Override + public @Nullable HitBoxPart hitBoxPartByEntityId(int id) { + return this.hitBoxParts.get(id); } @Override @@ -280,7 +256,7 @@ public class BukkitFurniture implements Furniture { @Override public @NotNull Key id() { - return this.id; + return this.furniture.id(); } @Override @@ -293,11 +269,6 @@ public class BukkitFurniture implements Furniture { return hasExternalModel; } - @Override - public void spawnSeatEntityForPlayer(net.momirealms.craftengine.core.entity.player.Player player, Seat seat) { - spawnSeatEntityForPlayer((Player) player.platformPlayer(), seat); - } - @Override public FurnitureExtraData extraData() { return this.extraData; @@ -317,49 +288,4 @@ public class BukkitFurniture implements Furniture { CraftEngine.instance().logger().warn("Failed to save furniture data.", e); } } - - private void spawnSeatEntityForPlayer(org.bukkit.entity.Player player, Seat seat) { - Location location = this.calculateSeatLocation(seat); - Entity seatEntity = seat.limitPlayerRotation() ? - EntityUtils.spawnEntity(player.getWorld(), VersionHelper.isOrAbove1_20_2() ? location.subtract(0,0.9875,0) : location.subtract(0,0.990625,0), EntityType.ARMOR_STAND, entity -> { - ArmorStand armorStand = (ArmorStand) entity; - if (VersionHelper.isOrAbove1_21_3()) { - Objects.requireNonNull(armorStand.getAttribute(Attribute.MAX_HEALTH)).setBaseValue(0.01); - } else { - LegacyAttributeUtils.setMaxHealth(armorStand); - } - armorStand.setSmall(true); - armorStand.setInvisible(true); - armorStand.setSilent(true); - armorStand.setInvulnerable(true); - armorStand.setArms(false); - armorStand.setCanTick(false); - armorStand.setAI(false); - armorStand.setGravity(false); - armorStand.setPersistent(false); - armorStand.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_SEAT_BASE_ENTITY_KEY, PersistentDataType.INTEGER, this.baseEntityId()); - armorStand.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_SEAT_VECTOR_3F_KEY, PersistentDataType.STRING, seat.offset().x + ", " + seat.offset().y + ", " + seat.offset().z); - }) : - EntityUtils.spawnEntity(player.getWorld(), VersionHelper.isOrAbove1_20_2() ? location : location.subtract(0,0.25,0), EntityType.ITEM_DISPLAY, entity -> { - ItemDisplay itemDisplay = (ItemDisplay) entity; - itemDisplay.setPersistent(false); - itemDisplay.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_SEAT_BASE_ENTITY_KEY, PersistentDataType.INTEGER, this.baseEntityId()); - itemDisplay.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_SEAT_VECTOR_3F_KEY, PersistentDataType.STRING, seat.offset().x + ", " + seat.offset().y + ", " + seat.offset().z); - }); - this.seats.add(new WeakReference<>(seatEntity)); - if (!seatEntity.addPassenger(player)) { - seatEntity.remove(); - this.removeOccupiedSeat(seat.offset()); - } - } - - private Location calculateSeatLocation(Seat seat) { - Vector3f offset = QuaternionUtils.toQuaternionf(0, Math.toRadians(180 - this.location.getYaw()), 0).conjugate().transform(new Vector3f(seat.offset())); - double yaw = seat.yaw() + this.location.getYaw(); - if (yaw < -180) yaw += 360; - Location newLocation = this.location.clone(); - newLocation.setYaw((float) yaw); - newLocation.add(offset.x, offset.y + 0.6, -offset.z); - return newLocation; - } } \ No newline at end of file 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 b7e58f8be..f946e4888 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 @@ -1,7 +1,7 @@ package net.momirealms.craftengine.bukkit.entity.furniture; import net.momirealms.craftengine.bukkit.api.BukkitAdaptors; -import net.momirealms.craftengine.bukkit.entity.furniture.hitbox.InteractionHitBox; +import net.momirealms.craftengine.bukkit.entity.furniture.hitbox.InteractionHitBoxConfig; import net.momirealms.craftengine.bukkit.nms.CollisionEntity; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; @@ -15,17 +15,13 @@ import net.momirealms.craftengine.core.entity.furniture.*; 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.ResourceConfigUtils; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.WorldPosition; import org.bukkit.*; import org.bukkit.entity.*; import org.bukkit.event.HandlerList; -import org.bukkit.event.Listener; import org.bukkit.persistence.PersistentDataType; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.joml.Vector3f; import java.io.IOException; import java.util.List; @@ -37,8 +33,6 @@ import java.util.function.BiConsumer; public class BukkitFurnitureManager extends AbstractFurnitureManager { public static final NamespacedKey FURNITURE_KEY = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_KEY); public static final NamespacedKey FURNITURE_EXTRA_DATA_KEY = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_EXTRA_DATA_KEY); - public static final NamespacedKey FURNITURE_SEAT_BASE_ENTITY_KEY = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_SEAT_BASE_ENTITY_KEY); - public static final NamespacedKey FURNITURE_SEAT_VECTOR_3F_KEY = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_SEAT_VECTOR_3F_KEY); public static final NamespacedKey FURNITURE_COLLISION = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_COLLISION); public static Class COLLISION_ENTITY_CLASS = Interaction.class; public static Object NMS_COLLISION_ENTITY_TYPE = MEntityTypes.INTERACTION; @@ -48,7 +42,6 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { private final Map furnitureByRealEntityId = new ConcurrentHashMap<>(256, 0.5f); private final Map furnitureByEntityId = new ConcurrentHashMap<>(512, 0.5f); // Event listeners - private final Listener dismountListener; private final FurnitureEventListener furnitureEventListener; public static BukkitFurnitureManager instance() { @@ -60,7 +53,6 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { instance = this; this.plugin = plugin; this.furnitureEventListener = new FurnitureEventListener(this); - this.dismountListener = VersionHelper.isOrAbove1_20_3() ? new DismountListener1_20_3(this) : new DismountListener1_20(this::handleDismount); } @Override @@ -95,7 +87,6 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { COLLISION_ENTITY_CLASS = Config.colliderType() == ColliderType.INTERACTION ? Interaction.class : Boat.class; NMS_COLLISION_ENTITY_TYPE = Config.colliderType() == ColliderType.INTERACTION ? MEntityTypes.INTERACTION : MEntityTypes.OAK_BOAT; COLLISION_ENTITY_TYPE = Config.colliderType(); - Bukkit.getPluginManager().registerEvents(this.dismountListener, this.plugin.javaPlugin()); Bukkit.getPluginManager().registerEvents(this.furnitureEventListener, this.plugin.javaPlugin()); if (VersionHelper.isFolia()) { BiConsumer taskExecutor = (entity, runnable) -> entity.getScheduler().run(this.plugin.javaPlugin(), (t) -> runnable.run(), () -> {}); @@ -129,15 +120,8 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { @Override public void disable() { - HandlerList.unregisterAll(this.dismountListener); HandlerList.unregisterAll(this.furnitureEventListener); unload(); - for (Player player : Bukkit.getOnlinePlayers()) { - Entity vehicle = player.getVehicle(); - if (vehicle != null) { - tryLeavingSeat(player, vehicle); - } - } } @Override @@ -327,84 +311,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { } @Override - protected HitBox defaultHitBox() { - return InteractionHitBox.DEFAULT; - } - - protected void handleDismount(Player player, Entity entity) { - if (!isSeatCarrierType(entity)) return; - Location location = entity.getLocation(); - plugin.scheduler().sync().runDelayed(() -> tryLeavingSeat(player, entity), player.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4); - } - - @SuppressWarnings("DuplicatedCode") - protected void tryLeavingSeat(@NotNull Player player, @NotNull Entity vehicle) { - Integer baseFurniture = vehicle.getPersistentDataContainer().get(FURNITURE_SEAT_BASE_ENTITY_KEY, PersistentDataType.INTEGER); - if (baseFurniture == null) return; - vehicle.remove(); - BukkitFurniture furniture = loadedFurnitureByRealEntityId(baseFurniture); - if (furniture == null) { - return; - } - String vector3f = vehicle.getPersistentDataContainer().get(BukkitFurnitureManager.FURNITURE_SEAT_VECTOR_3F_KEY, PersistentDataType.STRING); - if (vector3f == null) { - plugin.logger().warn("Failed to get vector3f for player " + player.getName() + "'s seat"); - return; - } - Vector3f seatPos = ResourceConfigUtils.getAsVector3f(vector3f, "seat"); - furniture.removeOccupiedSeat(seatPos); - - if (player.getVehicle() != null) return; - Location vehicleLocation = vehicle.getLocation(); - Location originalLocation = vehicleLocation.clone(); - originalLocation.setY(furniture.location().getY()); - Location targetLocation = originalLocation.clone().add(vehicleLocation.getDirection().multiply(1.1)); - if (!isSafeLocation(targetLocation)) { - targetLocation = findSafeLocationNearby(originalLocation); - if (targetLocation == null) return; - } - targetLocation.setYaw(player.getLocation().getYaw()); - targetLocation.setPitch(player.getLocation().getPitch()); - if (VersionHelper.isFolia()) { - player.teleportAsync(targetLocation); - } else { - player.teleport(targetLocation); - } - } - - protected boolean isSeatCarrierType(Entity entity) { - return (entity instanceof ArmorStand || entity instanceof ItemDisplay); - } - - @SuppressWarnings("DuplicatedCode") - private boolean isSafeLocation(Location location) { - World world = location.getWorld(); - if (world == null) return false; - int x = location.getBlockX(); - int y = location.getBlockY(); - int z = location.getBlockZ(); - if (!world.getBlockAt(x, y - 1, z).getType().isSolid()) return false; - if (!world.getBlockAt(x, y, z).isPassable()) return false; - return world.getBlockAt(x, y + 1, z).isPassable(); - } - - @SuppressWarnings("DuplicatedCode") - @Nullable - private Location findSafeLocationNearby(Location center) { - World world = center.getWorld(); - if (world == null) return null; - int centerX = center.getBlockX(); - int centerY = center.getBlockY(); - int centerZ = center.getBlockZ(); - for (int dx = -1; dx <= 1; dx++) { - for (int dz = -1; dz <= 1; dz++) { - if (dx == 0 && dz == 0) continue; - int x = centerX + dx; - int z = centerZ + dz; - Location nearbyLocation = new Location(world, x + 0.5, centerY, z + 0.5); - if (isSafeLocation(nearbyLocation)) return nearbyLocation; - } - } - return null; + protected HitBoxConfig defaultHitBox() { + return InteractionHitBoxConfig.DEFAULT; } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitHitBox.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitHitBox.java new file mode 100644 index 000000000..8f725a94b --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitHitBox.java @@ -0,0 +1,70 @@ +package net.momirealms.craftengine.bukkit.entity.furniture; + +import net.momirealms.craftengine.bukkit.entity.seat.BukkitSeat; +import net.momirealms.craftengine.core.entity.furniture.Furniture; +import net.momirealms.craftengine.core.entity.furniture.HitBox; +import net.momirealms.craftengine.core.entity.furniture.HitBoxConfig; +import net.momirealms.craftengine.core.entity.furniture.HitBoxPart; +import net.momirealms.craftengine.core.entity.seat.Seat; +import net.momirealms.craftengine.core.entity.seat.SeatConfig; +import net.momirealms.craftengine.core.world.EntityHitResult; +import net.momirealms.craftengine.core.world.Vec3d; +import net.momirealms.sparrow.nbt.CompoundTag; + +import java.util.Optional; + +public class BukkitHitBox implements HitBox { + private final Furniture furniture; + private final HitBoxConfig config; + private final HitBoxPart[] parts; + private final Seat[] seats; + + public BukkitHitBox(Furniture furniture, HitBoxConfig config, HitBoxPart[] parts) { + this.parts = parts; + this.config = config; + this.furniture = furniture; + this.seats = createSeats(config); + } + + @SuppressWarnings("unchecked") + private Seat[] createSeats(HitBoxConfig config) { + SeatConfig[] seatConfigs = config.seats(); + Seat[] seats = new Seat[seatConfigs.length]; + for (int i = 0; i < seatConfigs.length; i++) { + seats[i] = new BukkitSeat<>(this, seatConfigs[i]); + } + return seats; + } + + @Override + public HitBoxPart[] parts() { + return this.parts; + } + + @Override + public HitBoxConfig config() { + return this.config; + } + + @Override + public Seat[] seats() { + return this.seats; + } + + @Override + public Optional clip(Vec3d min, Vec3d max) { + for (HitBoxPart hbe : this.parts) { + Optional result = hbe.aabb().clip(min, max); + if (result.isPresent()) { + return result; + } + } + return Optional.empty(); + } + + @Override + public void saveCustomData(CompoundTag data) { + data.putString("type", "furniture"); + data.putInt("entity_id", this.furniture.baseEntityId()); + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/DismountListener1_20_3.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/DismountListener1_20_3.java index a35b48ff7..ce5db66cd 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/DismountListener1_20_3.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/DismountListener1_20_3.java @@ -1,21 +1,24 @@ package net.momirealms.craftengine.bukkit.entity.furniture; +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.entity.EntityDismountEvent; -public class DismountListener1_20_3 implements Listener { - private final BukkitFurnitureManager manager; +import java.util.function.BiConsumer; - public DismountListener1_20_3(final BukkitFurnitureManager manager) { - this.manager = manager; +public class DismountListener1_20_3 implements Listener { + private final BiConsumer consumer; + + public DismountListener1_20_3(final BiConsumer consumer) { + this.consumer = consumer; } @EventHandler(ignoreCancelled = true) public void onDismount(EntityDismountEvent event) { if (event.getEntity() instanceof Player player) { - this.manager.handleDismount(player, event.getDismounted()); + this.consumer.accept(player, event.getDismounted()); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/FurnitureEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/FurnitureEventListener.java index f9c526233..ce4864b90 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/FurnitureEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/FurnitureEventListener.java @@ -2,21 +2,15 @@ package net.momirealms.craftengine.bukkit.entity.furniture; import com.destroystokyo.paper.event.entity.EntityAddToWorldEvent; import com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent; -import org.bukkit.entity.ArmorStand; import org.bukkit.entity.Entity; import org.bukkit.entity.ItemDisplay; -import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; -import org.bukkit.event.entity.PlayerDeathEvent; -import org.bukkit.event.player.PlayerInteractAtEntityEvent; -import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.world.ChunkUnloadEvent; import org.bukkit.event.world.EntitiesLoadEvent; import org.bukkit.event.world.WorldLoadEvent; import org.bukkit.event.world.WorldUnloadEvent; -import org.bukkit.persistence.PersistentDataType; import java.util.List; @@ -100,35 +94,4 @@ public class FurnitureEventListener implements Listener { this.manager.handleCollisionEntityUnload(entity); } } - - @EventHandler(ignoreCancelled = true) - public void onPlayerQuit(PlayerQuitEvent event) { - Player player = event.getPlayer(); - Entity entity = player.getVehicle(); - if (entity == null) return; - if (this.manager.isSeatCarrierType(entity)) { - this.manager.tryLeavingSeat(player, entity); - } - } - - @EventHandler(ignoreCancelled = true) - public void onPlayerDeath(PlayerDeathEvent event) { - Player player = event.getPlayer(); - Entity entity = player.getVehicle(); - if (entity == null) return; - if (this.manager.isSeatCarrierType(entity)) { - this.manager.tryLeavingSeat(player, entity); - } - } - - // do not allow players to put item on seats - @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) - public void onInteractArmorStand(PlayerInteractAtEntityEvent event) { - Entity clicked = event.getRightClicked(); - if (clicked instanceof ArmorStand armorStand) { - Integer baseFurniture = armorStand.getPersistentDataContainer().get(BukkitFurnitureManager.FURNITURE_SEAT_BASE_ENTITY_KEY, PersistentDataType.INTEGER); - if (baseFurniture == null) return; - event.setCancelled(true); - } - } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/BukkitHitBoxTypes.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/BukkitHitBoxTypes.java index dda752638..4d92bd7c8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/BukkitHitBoxTypes.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/BukkitHitBoxTypes.java @@ -7,9 +7,9 @@ public class BukkitHitBoxTypes extends HitBoxTypes { public static void init() {} static { - register(INTERACTION, InteractionHitBox.FACTORY); - register(SHULKER, ShulkerHitBox.FACTORY); - register(HAPPY_GHAST, HappyGhastHitBox.FACTORY); - register(CUSTOM, CustomHitBox.FACTORY); + register(INTERACTION, InteractionHitBoxConfig.FACTORY); + register(SHULKER, ShulkerHitBoxConfig.FACTORY); + register(HAPPY_GHAST, HappyGhastHitBoxConfig.FACTORY); + register(CUSTOM, CustomHitBoxConfig.FACTORY); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/CustomHitBox.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/CustomHitBoxConfig.java similarity index 86% rename from bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/CustomHitBox.java rename to bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/CustomHitBoxConfig.java index f5b3d87c1..4ea4cd9b9 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/CustomHitBox.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/CustomHitBoxConfig.java @@ -6,6 +6,7 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflect import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MAttributeHolders; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections; import net.momirealms.craftengine.core.entity.furniture.*; +import net.momirealms.craftengine.core.entity.seat.SeatConfig; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -23,13 +24,13 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Supplier; -public class CustomHitBox extends AbstractHitBox { +public class CustomHitBoxConfig extends AbstractHitBoxConfig { public static final Factory FACTORY = new Factory(); private final float scale; private final EntityType entityType; private final List cachedValues = new ArrayList<>(); - public CustomHitBox(Seat[] seats, Vector3f position, EntityType type, float scale, boolean blocksBuilding, boolean canBeHitByProjectile) { + public CustomHitBoxConfig(SeatConfig[] seats, Vector3f position, EntityType type, float scale, boolean blocksBuilding, boolean canBeHitByProjectile) { super(seats, position, false, blocksBuilding, canBeHitByProjectile); this.scale = scale; this.entityType = type; @@ -39,11 +40,11 @@ public class CustomHitBox extends AbstractHitBox { } public EntityType entityType() { - return entityType; + return this.entityType; } public float scale() { - return scale; + return this.scale; } @Override @@ -52,7 +53,7 @@ public class CustomHitBox extends AbstractHitBox { } @Override - public void initPacketsAndColliders(int[] entityId, WorldPosition position, Quaternionf conjugated, BiConsumer packets, Consumer collider, BiConsumer aabb) { + public void initPacketsAndColliders(int[] entityId, WorldPosition position, Quaternionf conjugated, BiConsumer packets, Consumer collider, Consumer aabb) { Vector3f offset = conjugated.transform(new Vector3f(position())); try { packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket( @@ -79,10 +80,10 @@ public class CustomHitBox extends AbstractHitBox { return new int[] {entityIdSupplier.get()}; } - public static class Factory implements HitBoxFactory { + public static class Factory implements HitBoxConfigFactory { @Override - public HitBox create(Map arguments) { + public HitBoxConfig create(Map arguments) { Vector3f position = ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("position", "0"), "position"); float scale = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("scale", 1), "scale"); String type = (String) arguments.getOrDefault("entity-type", "slime"); @@ -92,7 +93,7 @@ public class CustomHitBox extends AbstractHitBox { } 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"); - return new CustomHitBox(HitBoxFactory.getSeats(arguments), position, entityType, scale, blocksBuilding, canBeHitByProjectile); + return new CustomHitBoxConfig(SeatConfig.fromObj(arguments.get("seats")), position, entityType, scale, blocksBuilding, canBeHitByProjectile); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/HappyGhastHitBox.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/HappyGhastHitBoxConfig.java similarity index 83% rename from bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/HappyGhastHitBox.java rename to bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/HappyGhastHitBoxConfig.java index 91754fd9b..3d2626fb1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/HappyGhastHitBox.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/HappyGhastHitBoxConfig.java @@ -8,9 +8,11 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MAttributeH 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.*; +import net.momirealms.craftengine.core.entity.seat.SeatConfig; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.core.world.collision.AABB; @@ -22,13 +24,13 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Supplier; -public class HappyGhastHitBox extends AbstractHitBox { +public class HappyGhastHitBoxConfig extends AbstractHitBoxConfig { public static final Factory FACTORY = new Factory(); private final double scale; private final boolean hardCollision; private final List cachedValues = new ArrayList<>(); - public HappyGhastHitBox(Seat[] seats, Vector3f position, double scale, boolean canUseOn, boolean blocksBuilding, boolean canBeHitByProjectile, boolean hardCollision) { + public HappyGhastHitBoxConfig(SeatConfig[] seats, Vector3f position, double scale, boolean canUseOn, boolean blocksBuilding, boolean canBeHitByProjectile, boolean hardCollision) { super(seats, position, canUseOn, blocksBuilding, canBeHitByProjectile); this.scale = scale; this.hardCollision = hardCollision; @@ -43,15 +45,20 @@ public class HappyGhastHitBox extends AbstractHitBox { } public double scale() { - return scale; + return this.scale; } public boolean hardCollision() { - return hardCollision; + return this.hardCollision; } @Override - public void initPacketsAndColliders(int[] entityIds, WorldPosition position, Quaternionf conjugated, BiConsumer packets, Consumer collider, BiConsumer aabb) { + public void initPacketsAndColliders(int[] entityIds, + WorldPosition position, + Quaternionf conjugated, + BiConsumer packets, + Consumer collider, + Consumer aabb) { Vector3f offset = conjugated.transform(new Vector3f(position())); try { double x = position.x(); @@ -76,11 +83,11 @@ public class HappyGhastHitBox extends AbstractHitBox { } } - public Collider createCollider(World world, Vector3f offset, double x, double y, double z, int entityId, BiConsumer aabb) { + public Collider createCollider(World world, Vector3f offset, double x, double y, double z, int entityId, Consumer aabb) { AABB ceAABB = createAABB(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(entityId, ceAABB); + aabb.accept(new HitBoxPart(entityId, ceAABB, new Vec3d(x, y, z))); return new BukkitCollider(level, nmsAABB, x, y, z, this.canBeHitByProjectile(), true, this.blocksBuilding()); } @@ -109,10 +116,10 @@ public class HappyGhastHitBox extends AbstractHitBox { return new int[] {entityIdSupplier.get()}; } - public static class Factory implements HitBoxFactory { + public static class Factory implements HitBoxConfigFactory { @Override - public HitBox create(Map arguments) { + public HitBoxConfig create(Map arguments) { if (!VersionHelper.isOrAbove1_21_6()) { throw new UnsupportedOperationException("HappyGhastHitBox is only supported on 1.21.6+"); } @@ -121,8 +128,8 @@ public class HappyGhastHitBox extends AbstractHitBox { boolean canUseOn = 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 HappyGhastHitBox( - HitBoxFactory.getSeats(arguments), + return new HappyGhastHitBoxConfig( + SeatConfig.fromObj(arguments.get("seats")), ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("position", "0"), "position"), scale, canUseOn, blocksBuilding, canBeHitByProjectile, hardCollision ); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/InteractionHitBox.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/InteractionHitBoxConfig.java similarity index 74% rename from bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/InteractionHitBox.java rename to bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/InteractionHitBoxConfig.java index f8ae1852e..145bdb62c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/InteractionHitBox.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/InteractionHitBoxConfig.java @@ -6,6 +6,7 @@ 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.*; +import net.momirealms.craftengine.core.entity.seat.SeatConfig; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.world.Vec3d; @@ -22,15 +23,15 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Supplier; -public class InteractionHitBox extends AbstractHitBox { +public class InteractionHitBoxConfig extends AbstractHitBoxConfig { public static final Factory FACTORY = new Factory(); - public static final InteractionHitBox DEFAULT = new InteractionHitBox(new Seat[0], new Vector3f(), new Vector3f(1,1,1), true, false, false, false); + public static final InteractionHitBoxConfig DEFAULT = new InteractionHitBoxConfig(new SeatConfig[0], new Vector3f(), new Vector3f(1,1,1), true, false, false, false); private final Vector3f size; private final boolean responsive; private final List cachedValues = new ArrayList<>(); - public InteractionHitBox(Seat[] seats, Vector3f position, Vector3f size, boolean responsive, boolean canUseOn, boolean blocksBuilding, boolean canBeHitByProjectile) { + public InteractionHitBoxConfig(SeatConfig[] seats, Vector3f position, Vector3f size, boolean responsive, boolean canUseOn, boolean blocksBuilding, boolean canBeHitByProjectile) { super(seats, position, canUseOn, blocksBuilding, canBeHitByProjectile); this.size = size; this.responsive = responsive; @@ -40,11 +41,11 @@ public class InteractionHitBox extends AbstractHitBox { } public boolean responsive() { - return responsive; + return this.responsive; } public Vector3f size() { - return size; + return this.size; } @Override @@ -53,22 +54,26 @@ public class InteractionHitBox extends AbstractHitBox { } @Override - public void initPacketsAndColliders(int[] entityId, WorldPosition position, Quaternionf conjugated, BiConsumer packets, Consumer collider, BiConsumer aabb) { + public void initPacketsAndColliders(int[] entityId, + WorldPosition position, + Quaternionf conjugated, + BiConsumer packets, + Consumer collider, + Consumer aabb) { Vector3f offset = conjugated.transform(new Vector3f(position())); double x = position.x(); double y = position.y(); double z = position.z(); float yaw = position.xRot(); + Vec3d vec3d = new Vec3d(x + offset.x, y + offset.y, z - offset.z); packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket( - entityId[0], UUID.randomUUID(), x + offset.x, y + offset.y, z - offset.z, 0, yaw, + entityId[0], UUID.randomUUID(), vec3d.x, vec3d.y, vec3d.z, 0, yaw, MEntityTypes.INTERACTION, 0, CoreReflections.instance$Vec3$Zero, 0 ), true); packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId[0], List.copyOf(this.cachedValues)), true); - if (canUseItemOn()) { - aabb.accept(entityId[0], AABB.fromInteraction(new Vec3d(x + offset.x, y + offset.y, z - offset.z), this.size.x, this.size.y)); - } + aabb.accept(new HitBoxPart(entityId[0], AABB.fromInteraction(vec3d, this.size.x, this.size.y), vec3d)); if (blocksBuilding() || this.canBeHitByProjectile()) { - AABB ceAABB = AABB.fromInteraction(new Vec3d(x + offset.x, y + offset.y, z - offset.z), this.size.x, this.size.y); + AABB ceAABB = AABB.fromInteraction(vec3d, this.size.x, this.size.y); Object nmsAABB = FastNMS.INSTANCE.constructor$AABB(ceAABB.minX, ceAABB.minY, ceAABB.minZ, ceAABB.maxX, ceAABB.maxY, ceAABB.maxZ); collider.accept(new BukkitCollider(position.world().serverWorld(), nmsAABB, x, y, z, this.canBeHitByProjectile(), false, this.blocksBuilding())); } @@ -88,10 +93,10 @@ public class InteractionHitBox extends AbstractHitBox { return new int[] {entityIdSupplier.get()}; } - public static class Factory implements HitBoxFactory { + public static class Factory implements HitBoxConfigFactory { @Override - public HitBox create(Map arguments) { + public HitBoxConfig create(Map arguments) { Vector3f position = ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("position", "0"), "position"); float width; float height; @@ -100,15 +105,15 @@ public class InteractionHitBox extends AbstractHitBox { width = Float.parseFloat(split[0]); height = Float.parseFloat(split[1]); } else { - width = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("width", "1"), "width"); - height = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("height", "1"), "height"); + width = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("width", 1), "width"); + height = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("height", 1), "height"); } boolean canUseOn = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-use-item-on", false), "can-use-item-on"); 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"); - return new InteractionHitBox( - HitBoxFactory.getSeats(arguments), + return new InteractionHitBoxConfig( + SeatConfig.fromObj(arguments.get("seats")), position, new Vector3f(width, height, width), interactive, canUseOn, blocksBuilding, canBeHitByProjectile diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/ShulkerHitBox.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/ShulkerHitBoxConfig.java similarity index 87% rename from bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/ShulkerHitBox.java rename to bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/ShulkerHitBoxConfig.java index 9883004cc..8566aaca8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/ShulkerHitBox.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/ShulkerHitBoxConfig.java @@ -10,6 +10,7 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityType import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections; import net.momirealms.craftengine.bukkit.util.DirectionUtils; import net.momirealms.craftengine.core.entity.furniture.*; +import net.momirealms.craftengine.core.entity.seat.SeatConfig; import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.World; @@ -23,7 +24,7 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Supplier; -public class ShulkerHitBox extends AbstractHitBox { +public class ShulkerHitBoxConfig extends AbstractHitBoxConfig { public static final Factory FACTORY = new Factory(); // 1.20.6+ private final float scale; @@ -35,7 +36,7 @@ public class ShulkerHitBox extends AbstractHitBox { private final DirectionalShulkerSpawner spawner; private final AABBCreator aabbCreator; - public ShulkerHitBox(Seat[] seats, Vector3f position, Direction direction, float scale, byte peek, boolean interactionEntity, boolean interactive, boolean canUseOn, boolean blocksBuilding, boolean canBeHitByProjectile) { + public ShulkerHitBoxConfig(SeatConfig[] seats, Vector3f position, Direction direction, float scale, byte peek, boolean interactionEntity, boolean interactive, boolean canUseOn, boolean blocksBuilding, boolean canBeHitByProjectile) { super(seats, position, canUseOn, blocksBuilding, canBeHitByProjectile); this.direction = direction; this.scale = scale; @@ -65,7 +66,8 @@ public class ShulkerHitBox extends AbstractHitBox { ), true); packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityIds[2], List.copyOf(cachedInteractionValues)), true); if (canUseOn) { - aabb.accept(entityIds[2], AABB.fromInteraction(new Vec3d(x + offset.x, y + offset.y, z - offset.z), scale, shulkerHeight)); + Vec3d vec3d = new Vec3d(x + offset.x, y + offset.y, z - offset.z); + aabb.accept(new HitBoxPart(entityIds[2], AABB.fromInteraction(vec3d, scale, shulkerHeight), vec3d)); } } }; @@ -84,7 +86,8 @@ public class ShulkerHitBox extends AbstractHitBox { ), true); packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityIds[2], List.copyOf(cachedInteractionValues)), true); if (canUseOn) { - aabb.accept(entityIds[2], AABB.fromInteraction(new Vec3d(x + offset.x, y + offset.y - shulkerHeight + scale, z - offset.z), scale, shulkerHeight)); + Vec3d vec3d = new Vec3d(x + offset.x, y + offset.y - shulkerHeight + scale, z - offset.z); + aabb.accept(new HitBoxPart(entityIds[2], AABB.fromInteraction(vec3d, scale, shulkerHeight), vec3d)); } } }; @@ -113,8 +116,10 @@ public class ShulkerHitBox extends AbstractHitBox { ), true); packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityIds[3], List.copyOf(cachedInteractionValues)), true); if (canUseOn) { - aabb.accept(entityIds[2], AABB.fromInteraction(new Vec3d(x + offset.x, y + offset.y, z - offset.z), scale, scale)); - aabb.accept(entityIds[3], AABB.fromInteraction(new Vec3d(x + offset.x + shulkerDirection.stepX() * distance, y + offset.y, z - offset.z + shulkerDirection.stepZ() * distance), scale, scale)); + 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 HitBoxPart(entityIds[2], AABB.fromInteraction(vec3d1, scale, scale), vec3d1)); + aabb.accept(new HitBoxPart(entityIds[3], AABB.fromInteraction(vec3d2, scale, scale), vec3d2)); } } }; @@ -126,11 +131,11 @@ public class ShulkerHitBox extends AbstractHitBox { } } - public Collider createCollider(Direction direction, World world, Vector3f offset, double x, double y, double z, int entityId, BiConsumer aabb) { + public Collider createCollider(Direction direction, World world, Vector3f offset, double x, double y, double z, int entityId, Consumer 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(entityId, ceAABB); + aabb.accept(new HitBoxPart(entityId, ceAABB, new Vec3d(x, y, z))); return new BukkitCollider(level, nmsAABB, x, y, z, this.canBeHitByProjectile(), true, this.blocksBuilding()); } @@ -200,7 +205,12 @@ public class ShulkerHitBox extends AbstractHitBox { } @Override - public void initPacketsAndColliders(int[] entityIds, WorldPosition position, Quaternionf conjugated, BiConsumer packets, Consumer collider, BiConsumer aabb) { + public void initPacketsAndColliders(int[] entityIds, + WorldPosition position, + Quaternionf conjugated, + BiConsumer packets, + Consumer collider, + Consumer aabb) { Vector3f offset = conjugated.transform(new Vector3f(position())); try { double x = position.x(); @@ -251,7 +261,16 @@ public class ShulkerHitBox extends AbstractHitBox { @FunctionalInterface interface DirectionalShulkerSpawner { - void accept(int[] entityIds, World world, double x, double y, double z, float yaw, Vector3f offset, BiConsumer packets, Consumer collider, BiConsumer aabb); + void accept(int[] entityIds, + World world, + double x, + double y, + double z, + float yaw, + Vector3f offset, + BiConsumer packets, + Consumer collider, + Consumer aabb); } @FunctionalInterface @@ -276,10 +295,10 @@ public class ShulkerHitBox extends AbstractHitBox { } } - public static class Factory implements HitBoxFactory { + public static class Factory implements HitBoxConfigFactory { @Override - public HitBox create(Map arguments) { + public HitBoxConfig create(Map 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"); @@ -289,8 +308,8 @@ public class ShulkerHitBox extends AbstractHitBox { 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 ShulkerHitBox( - HitBoxFactory.getSeats(arguments), + return new ShulkerHitBoxConfig( + SeatConfig.fromObj(arguments.get("seats")), position, directionEnum, scale, peek, interactionEntity, interactive, canUseItemOn, blocksBuilding, canBeHitByProjectile ); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/seat/BukkitSeat.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/seat/BukkitSeat.java new file mode 100644 index 000000000..fbe29d1cc --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/seat/BukkitSeat.java @@ -0,0 +1,146 @@ +package net.momirealms.craftengine.bukkit.entity.seat; + +import net.momirealms.craftengine.bukkit.util.EntityUtils; +import net.momirealms.craftengine.bukkit.util.LegacyAttributeUtils; +import net.momirealms.craftengine.bukkit.util.LocationUtils; +import net.momirealms.craftengine.core.entity.seat.Seat; +import net.momirealms.craftengine.core.entity.seat.SeatConfig; +import net.momirealms.craftengine.core.entity.seat.SeatOwner; +import net.momirealms.craftengine.core.util.QuaternionUtils; +import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.craftengine.core.world.WorldPosition; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.NBT; +import org.bukkit.Location; +import org.bukkit.attribute.Attribute; +import org.bukkit.entity.*; +import org.bukkit.persistence.PersistentDataType; +import org.jetbrains.annotations.Nullable; +import org.joml.Vector3f; + +import java.io.IOException; +import java.lang.ref.WeakReference; +import java.util.Objects; + +public class BukkitSeat implements Seat { + private final O owner; + private final SeatConfig seatConfig; + private WeakReference entity; + + public BukkitSeat(O owner, SeatConfig config) { + this.owner = owner; + this.seatConfig = config; + } + + @Override + public O owner() { + return this.owner; + } + + @Override + public SeatConfig config() { + return this.seatConfig; + } + + @Nullable + public Entity getSeatEntity() { + return this.entity == null ? null : this.entity.get(); + } + + @Override + public boolean isOccupied() { + Entity seatEntity = getSeatEntity(); + return seatEntity != null && seatEntity.isValid(); + } + + @Override + public void destroy() { + if (this.entity != null) { + Entity entity = this.entity.get(); + if (entity != null) { + if (entity.isValid()) { + entity.remove(); + } + this.entity = null; + } + } + } + + private float yRot() { + return this.seatConfig.yRot(); + } + + private Vector3f position() { + return this.seatConfig.position(); + } + + private boolean limitPlayerRotation() { + return this.seatConfig.limitPlayerRotation(); + } + + private Location calculateSeatLocation(Location sourceLocation) { + Vector3f offset = QuaternionUtils.toQuaternionf(0, Math.toRadians(180 - sourceLocation.getYaw()), 0).conjugate().transform(new Vector3f(this.position())); + double yaw = this.yRot() + sourceLocation.getYaw(); + if (yaw < -180) yaw += 360; + Location newLocation = sourceLocation.clone(); + newLocation.setYaw((float) yaw); + newLocation.add(offset.x, offset.y + 0.6, -offset.z); + return newLocation; + } + + @Override + public boolean spawnSeat(net.momirealms.craftengine.core.entity.player.Player player, WorldPosition source) { + return spawnSeatEntityForPlayer((Player) player.platformPlayer(), LocationUtils.toLocation(source)); + } + + private boolean spawnSeatEntityForPlayer(Player player, Location sourceLocation) { + // 移除就有的座椅 + this.destroy(); + // 计算座椅的位置 + Location location = this.calculateSeatLocation(sourceLocation); + + CompoundTag extraData = new CompoundTag(); + this.owner.saveCustomData(extraData); + byte[] data; + try { + data = NBT.toBytes(extraData); + } catch (IOException e) { + return false; + } + + // 生成座椅实体 + Entity seatEntity = this.limitPlayerRotation() ? + EntityUtils.spawnEntity(player.getWorld(), VersionHelper.isOrAbove1_20_2() ? location.subtract(0,0.9875,0) : location.subtract(0,0.990625,0), EntityType.ARMOR_STAND, entity -> { + ArmorStand armorStand = (ArmorStand) entity; + if (VersionHelper.isOrAbove1_21_3()) { + Objects.requireNonNull(armorStand.getAttribute(Attribute.MAX_HEALTH)).setBaseValue(0.01); + } else { + LegacyAttributeUtils.setMaxHealth(armorStand); + } + armorStand.setSmall(true); + armorStand.setInvisible(true); + armorStand.setSilent(true); + armorStand.setInvulnerable(true); + armorStand.setArms(false); + armorStand.setCanTick(false); + armorStand.setAI(false); + armorStand.setGravity(false); + armorStand.setPersistent(false); + armorStand.getPersistentDataContainer().set(BukkitSeatManager.SEAT_KEY, PersistentDataType.BOOLEAN, true); + armorStand.getPersistentDataContainer().set(BukkitSeatManager.SEAT_EXTRA_DATA_KEY, PersistentDataType.BYTE_ARRAY, data); + }) : + EntityUtils.spawnEntity(player.getWorld(), VersionHelper.isOrAbove1_20_2() ? location : location.subtract(0,0.25,0), EntityType.ITEM_DISPLAY, entity -> { + ItemDisplay itemDisplay = (ItemDisplay) entity; + itemDisplay.setPersistent(false); + itemDisplay.getPersistentDataContainer().set(BukkitSeatManager.SEAT_KEY, PersistentDataType.BOOLEAN, true); + itemDisplay.getPersistentDataContainer().set(BukkitSeatManager.SEAT_EXTRA_DATA_KEY, PersistentDataType.BYTE_ARRAY, data); + }); + if (!seatEntity.addPassenger(player)) { + seatEntity.remove(); + return false; + } else { + this.entity = new WeakReference<>(seatEntity); + return true; + } + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/seat/BukkitSeatManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/seat/BukkitSeatManager.java new file mode 100644 index 000000000..4a0962335 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/seat/BukkitSeatManager.java @@ -0,0 +1,120 @@ +package net.momirealms.craftengine.bukkit.entity.seat; + +import net.momirealms.craftengine.bukkit.entity.furniture.DismountListener1_20; +import net.momirealms.craftengine.bukkit.entity.furniture.DismountListener1_20_3; +import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; +import net.momirealms.craftengine.bukkit.util.KeyUtils; +import net.momirealms.craftengine.core.entity.seat.SeatManager; +import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.NBT; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.NamespacedKey; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Entity; +import org.bukkit.entity.ItemDisplay; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.player.PlayerInteractAtEntityEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.persistence.PersistentDataType; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; + +public class BukkitSeatManager implements SeatManager { + private static BukkitSeatManager instance; + public static final NamespacedKey SEAT_KEY = KeyUtils.toNamespacedKey(SeatManager.SEAT_KEY); + public static final NamespacedKey SEAT_EXTRA_DATA_KEY = KeyUtils.toNamespacedKey(SeatManager.SEAT_EXTRA_DATA_KEY); + private final BukkitCraftEngine plugin; + private final Listener dismountListener; + + public BukkitSeatManager(BukkitCraftEngine plugin) { + this.plugin = plugin; + this.dismountListener = VersionHelper.isOrAbove1_20_3() ? new DismountListener1_20_3(this::handleDismount) : new DismountListener1_20(this::handleDismount); + instance = this; + } + + public CompoundTag getSeatExtraData(Entity entity) { + if (!isSeatEntityType(entity)) { + throw new IllegalArgumentException("Entity is not a seat"); + } + byte[] bytes = entity.getPersistentDataContainer().get(SEAT_EXTRA_DATA_KEY, PersistentDataType.BYTE_ARRAY); + try { + return NBT.fromBytes(bytes); + } catch (IOException e) { + throw new RuntimeException("Failed to read extra data from seat", e); + } + } + + private void handleDismount(Player player, @NotNull Entity dismounted) { + if (!isSeatEntityType(dismounted)) return; + Location location = dismounted.getLocation(); + this.plugin.scheduler().sync().runDelayed(() -> tryLeavingSeat(player, dismounted), player.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4); + } + + @Override + public void delayedInit() { + Bukkit.getPluginManager().registerEvents(this.dismountListener, this.plugin.javaPlugin()); + } + + @Override + public void disable() { + HandlerList.unregisterAll(this.dismountListener); + for (Player player : Bukkit.getOnlinePlayers()) { + Entity vehicle = player.getVehicle(); + if (vehicle != null) { + tryLeavingSeat(player, vehicle); + } + } + } + + @EventHandler(ignoreCancelled = true) + public void onPlayerQuit(PlayerQuitEvent event) { + Player player = event.getPlayer(); + Entity entity = player.getVehicle(); + if (entity == null) return; + if (this.isSeatEntityType(entity)) { + this.tryLeavingSeat(player, entity); + } + } + + @EventHandler(ignoreCancelled = true) + public void onPlayerDeath(PlayerDeathEvent event) { + Player player = event.getPlayer(); + Entity entity = player.getVehicle(); + if (entity == null) return; + if (this.isSeatEntityType(entity)) { + this.tryLeavingSeat(player, entity); + } + } + + // do not allow players to put item on seats + @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) + public void onInteractArmorStand(PlayerInteractAtEntityEvent event) { + Entity clicked = event.getRightClicked(); + if (clicked instanceof ArmorStand armorStand) { + if (!armorStand.getPersistentDataContainer().has(SEAT_KEY)) return; + event.setCancelled(true); + } + } + + protected boolean isSeatEntityType(Entity entity) { + return (entity instanceof ArmorStand || entity instanceof ItemDisplay); + } + + protected void tryLeavingSeat(@NotNull Player player, @NotNull Entity seat) { + boolean isSeat = seat.getPersistentDataContainer().has(SEAT_KEY); + if (!isSeat) return; + seat.remove(); + } + + public static BukkitSeatManager instance() { + return instance; + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java index e3649d0ff..eb3c19461 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java @@ -4,7 +4,7 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.NetworkItemBuildContext; import net.momirealms.craftengine.core.item.NetworkItemHandler; import net.momirealms.craftengine.core.item.modifier.ArgumentsModifier; import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; @@ -209,15 +209,15 @@ public final class LegacyNetworkItemHandler implements NetworkItemHandler entry : arguments.entrySet()) { builder.withParameter(ContextKey.direct(entry.getKey()), entry.getValue().getAsString()); } - context = ItemBuildContext.of(player, builder); + context = NetworkItemBuildContext.of(player, builder); } else { - context = ItemBuildContext.of(player); + context = NetworkItemBuildContext.of(player); } // 准备阶段 for (ItemDataModifier modifier : customItem.clientBoundDataModifiers()) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java index b9fd28806..e92092a98 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java @@ -185,15 +185,15 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler entry : arguments.entrySet()) { builder.withParameter(ContextKey.direct(entry.getKey()), entry.getValue().getAsString()); } - context = ItemBuildContext.of(player, builder); + context = NetworkItemBuildContext.of(player, builder); } // 准备阶段 CompoundTag tag = new CompoundTag(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java index 7cdccabc5..35ffe93a1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java @@ -3,7 +3,6 @@ package net.momirealms.craftengine.bukkit.item.behavior; import net.momirealms.craftengine.bukkit.block.behavior.StrippableBlockBehavior; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.util.*; import net.momirealms.craftengine.bukkit.world.BukkitExistingBlock; import net.momirealms.craftengine.core.block.BlockStateWrapper; 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 83b4bdef6..603a6d072 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 @@ -12,7 +12,7 @@ import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.core.entity.furniture.AnchorType; import net.momirealms.craftengine.core.entity.furniture.CustomFurniture; import net.momirealms.craftengine.core.entity.furniture.FurnitureExtraData; -import net.momirealms.craftengine.core.entity.furniture.HitBox; +import net.momirealms.craftengine.core.entity.furniture.HitBoxConfig; import net.momirealms.craftengine.core.entity.player.InteractionResult; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.Item; @@ -109,8 +109,8 @@ public class FurnitureItemBehavior extends ItemBehavior { Location furnitureLocation = new Location(world, finalPlacePosition.x(), finalPlacePosition.y(), finalPlacePosition.z(), (float) furnitureYaw, 0); List aabbs = new ArrayList<>(); - for (HitBox hitBox : placement.hitBoxes()) { - hitBox.initShapeForPlacement(finalPlacePosition.x(), finalPlacePosition.y(), finalPlacePosition.z(), (float) furnitureYaw, QuaternionUtils.toQuaternionf(0, Math.toRadians(180 - furnitureYaw), 0).conjugate(), aabbs::add); + 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(), finalPlacePosition.x(), finalPlacePosition.y(), finalPlacePosition.z())) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java index ee55bd30c..c51b012ff 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java @@ -9,6 +9,7 @@ import net.momirealms.craftengine.bukkit.block.entity.renderer.element.BukkitBlo import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; import net.momirealms.craftengine.bukkit.entity.furniture.hitbox.BukkitHitBoxTypes; import net.momirealms.craftengine.bukkit.entity.projectile.BukkitProjectileManager; +import net.momirealms.craftengine.bukkit.entity.seat.BukkitSeatManager; import net.momirealms.craftengine.bukkit.font.BukkitFontManager; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.item.behavior.BukkitItemBehaviors; @@ -209,6 +210,7 @@ public class BukkitCraftEngine extends CraftEngine { super.advancementManager = new BukkitAdvancementManager(this); super.projectileManager = new BukkitProjectileManager(this); super.furnitureManager = new BukkitFurnitureManager(this); + super.seatManager = new BukkitSeatManager(this); super.onPluginEnable(); super.compatibilityManager().onEnable(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugRealStateUsageCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugRealStateUsageCommand.java index c5e6151d4..f375dd3df 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugRealStateUsageCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugRealStateUsageCommand.java @@ -14,7 +14,10 @@ import net.momirealms.craftengine.core.plugin.config.Config; import org.bukkit.command.CommandSender; import org.incendo.cloud.Command; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; public class DebugRealStateUsageCommand extends BukkitCommandFeature { 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 a46a19850..fcceb2a0a 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 @@ -58,7 +58,10 @@ import net.momirealms.craftengine.bukkit.world.BukkitWorldManager; 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; +import net.momirealms.craftengine.core.entity.furniture.HitBoxPart; import net.momirealms.craftengine.core.entity.player.InteractionHand; +import net.momirealms.craftengine.core.entity.seat.Seat; import net.momirealms.craftengine.core.font.FontManager; import net.momirealms.craftengine.core.font.IllegalCharacterProcessResult; import net.momirealms.craftengine.core.item.CustomItem; @@ -92,7 +95,6 @@ import net.momirealms.craftengine.core.world.chunk.Palette; import net.momirealms.craftengine.core.world.chunk.PalettedContainer; import net.momirealms.craftengine.core.world.chunk.packet.BlockEntityData; import net.momirealms.craftengine.core.world.chunk.packet.MCSection; -import net.momirealms.craftengine.core.world.collision.AABB; import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.ListTag; import net.momirealms.sparrow.nbt.Tag; @@ -3635,8 +3637,6 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes float x = buf.readFloat(); float y = buf.readFloat(); float z = buf.readFloat(); - // todo 这个是错误的,这是实体的相对位置而非绝对位置 - Location interactionPoint = new Location(platformPlayer.getWorld(), x, y, z); InteractionHand hand = buf.readVarInt() == 0 ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND; boolean usingSecondaryAction = buf.readBoolean(); if (entityId != furniture.baseEntityId()) { @@ -3655,16 +3655,40 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes return; } - // todo 重构家具时候注意,需要准备加载好的hitbox类,以获取hitbox坐标 - if (!serverPlayer.canInteractPoint(new Vec3d(location.getX(), location.getY(), location.getZ()), 16d)) { + // 先检查碰撞箱部分是否存在 + HitBoxPart hitBoxPart = furniture.hitBoxPartByEntityId(entityId); + if (hitBoxPart == null) return; + Vec3d pos = hitBoxPart.pos(); + // 检测距离 + if (!serverPlayer.canInteractPoint(pos, 16d)) { + return; + } + // 检测 + Location eyeLocation = platformPlayer.getEyeLocation(); + Vector direction = eyeLocation.getDirection(); + Location endLocation = eyeLocation.clone(); + endLocation.add(direction.multiply(serverPlayer.getCachedInteractionRange())); + Optional result = hitBoxPart.aabb().clip(LocationUtils.toVec3d(eyeLocation), LocationUtils.toVec3d(endLocation)); + if (result.isEmpty()) { + return; + } + EntityHitResult hitResult = result.get(); + Vec3d hitLocation = hitResult.hitLocation(); + // 获取正确的交互点 + Location interactionPoint = new Location(platformPlayer.getWorld(), hitLocation.x, hitLocation.y, hitLocation.z); + + HitBox hitbox = furniture.hitBoxByEntityId(entityId); + if (hitbox == null) { return; } - FurnitureInteractEvent interactEvent = new FurnitureInteractEvent(serverPlayer.platformPlayer(), furniture, hand, interactionPoint); + // 触发事件 + FurnitureInteractEvent interactEvent = new FurnitureInteractEvent(serverPlayer.platformPlayer(), furniture, hand, interactionPoint, hitbox); if (EventUtils.fireAndCheckCancel(interactEvent)) { return; } + // 执行事件动作 Item itemInHand = serverPlayer.getItemInHand(InteractionHand.MAIN_HAND); Cancellable cancellable = Cancellable.of(interactEvent::isCancelled, interactEvent::setCancelled); // execute functions @@ -3681,20 +3705,8 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes } // 必须从网络包层面处理,否则无法获取交互的具体实体 - if (serverPlayer.isSecondaryUseActive() && !itemInHand.isEmpty()) { - // try placing another furniture above it - AABB hitBox = furniture.aabbByEntityId(entityId); - if (hitBox == null) return; + if (serverPlayer.isSecondaryUseActive() && !itemInHand.isEmpty() && hitbox.config().canUseItemOn()) { Optional> optionalCustomItem = itemInHand.getCustomItem(); - Location eyeLocation = platformPlayer.getEyeLocation(); - Vector direction = eyeLocation.getDirection(); - Location endLocation = eyeLocation.clone(); - endLocation.add(direction.multiply(serverPlayer.getCachedInteractionRange())); - Optional result = hitBox.clip(LocationUtils.toVec3d(eyeLocation), LocationUtils.toVec3d(endLocation)); - if (result.isEmpty()) { - return; - } - EntityHitResult hitResult = result.get(); if (optionalCustomItem.isPresent() && !optionalCustomItem.get().behaviors().isEmpty()) { for (ItemBehavior behavior : optionalCustomItem.get().behaviors()) { if (behavior instanceof FurnitureItemBehavior) { @@ -3713,11 +3725,11 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes ); } else { if (!serverPlayer.isSecondaryUseActive()) { - furniture.findFirstAvailableSeat(entityId).ifPresent(seatPos -> { - if (furniture.tryOccupySeat(seatPos)) { - furniture.spawnSeatEntityForPlayer(serverPlayer, seatPos); + for (Seat seat : hitbox.seats()) { + if (!seat.isOccupied()) { + seat.spawnSeat(serverPlayer, furniture.position()); } - }); + } } } }; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/PayloadHelper.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/PayloadHelper.java index 08e49166a..716ad2f0d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/PayloadHelper.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/PayloadHelper.java @@ -8,9 +8,9 @@ import net.momirealms.craftengine.bukkit.plugin.network.payload.protocol.ClientC import net.momirealms.craftengine.bukkit.plugin.network.payload.protocol.VisualBlockStatePacket; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.logger.Debugger; -import net.momirealms.craftengine.core.plugin.network.PayloadChannelKeys; import net.momirealms.craftengine.core.plugin.network.ModPacket; import net.momirealms.craftengine.core.plugin.network.NetWorkUser; +import net.momirealms.craftengine.core.plugin.network.PayloadChannelKeys; import net.momirealms.craftengine.core.plugin.network.codec.NetworkCodec; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.WritableRegistry; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LocationUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LocationUtils.java index df658ed90..508daf228 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LocationUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LocationUtils.java @@ -14,7 +14,7 @@ public final class LocationUtils { private LocationUtils() {} public static Location toLocation(WorldPosition position) { - return new Location((World) position.world().platformWorld(), position.x(), position.y(), position.z(), position.xRot(), position.yRot()); + return new Location((World) position.world().platformWorld(), position.x(), position.y(), position.z(), position.yRot(), position.xRot()); } public static WorldPosition toWorldPosition(Location location) { diff --git a/common-files/src/main/resources/config.yml b/common-files/src/main/resources/config.yml index 7809dd0a9..53b288014 100644 --- a/common-files/src/main/resources/config.yml +++ b/common-files/src/main/resources/config.yml @@ -114,7 +114,7 @@ resource-pack: method-2: false # This will increase the resource pack size by 64KB method-3: false # This will increase the resource pack size by 0.67MB method-4: false - method-5: true # This can reduce the resource pack size, also it prevents some software from extracting it + method-5: true # This will reduce the resource pack size, also it prevents some software from extracting it method-6: false # This will increase the resource pack size by a certain percentage method-7: false # Create incorrect crc data diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/sofa.yml b/common-files/src/main/resources/resources/default/configuration/blocks/sofa.yml index 73ffa6029..bffc9246e 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/sofa.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/sofa.yml @@ -35,6 +35,9 @@ items: - type: bouncing_block bounce-height: 0.66 sync-player-position: false + - type: seat_block + seats: + - 0,0,0 state: state: white_bed[facing=west,occupied=false,part=foot] entity-renderer: @@ -79,6 +82,9 @@ items: - type: sofa_block - type: bouncing_block bounce-height: 0.66 + - type: seat_block + seats: + - 0,0,0 0 states: properties: facing: diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java index d835426df..614829cc3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java @@ -646,7 +646,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem // 绑定行为 for (ImmutableBlockState state : states) { if (isEntityBlock) { - state.setBlockEntityType(entityBlockBehavior.blockEntityType()); + state.setBlockEntityType(entityBlockBehavior.blockEntityType(state)); } state.setBehavior(blockBehavior); int internalId = state.customBlockState().registryId(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockBehavior.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockBehavior.java index de57acac4..d1aec1f89 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockBehavior.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockBehavior.java @@ -19,7 +19,7 @@ import java.util.concurrent.Callable; public abstract class BlockBehavior { @SuppressWarnings("unchecked") - public Optional getAs(Class tClass) { + public Optional getAs(Class tClass) { if (tClass.isInstance(this)) { return Optional.of((T) this); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/behavior/EntityBlockBehavior.java b/core/src/main/java/net/momirealms/craftengine/core/block/behavior/EntityBlockBehavior.java index 2eb34bae7..67c2c1e50 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/behavior/EntityBlockBehavior.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/behavior/EntityBlockBehavior.java @@ -7,12 +7,15 @@ import net.momirealms.craftengine.core.block.entity.tick.BlockEntityTicker; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.CEWorld; import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; @ApiStatus.Experimental public interface EntityBlockBehavior { - BlockEntityType blockEntityType(); + @Nullable + BlockEntityType blockEntityType(ImmutableBlockState state); + @Nullable BlockEntity createBlockEntity(BlockPos pos, ImmutableBlockState state); default BlockEntityTicker createSyncBlockEntityTicker(CEWorld level, ImmutableBlockState state, BlockEntityType blockEntityType) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/entity/BlockEntityType.java b/core/src/main/java/net/momirealms/craftengine/core/block/entity/BlockEntityType.java index 4291b6de5..ab69e48bc 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/entity/BlockEntityType.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/entity/BlockEntityType.java @@ -2,5 +2,5 @@ package net.momirealms.craftengine.core.block.entity; import net.momirealms.craftengine.core.util.Key; -public record BlockEntityType(Key id, BlockEntity.Factory factory) { +public record BlockEntityType(Key id) { } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/entity/BlockEntityTypeKeys.java b/core/src/main/java/net/momirealms/craftengine/core/block/entity/BlockEntityTypeKeys.java index 720da9e20..d7ca645e6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/entity/BlockEntityTypeKeys.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/entity/BlockEntityTypeKeys.java @@ -9,4 +9,5 @@ public final class BlockEntityTypeKeys { public static final Key SIMPLE_STORAGE = Key.of("craftengine:simple_storage"); public static final Key SIMPLE_PARTICLE = Key.of("craftengine:simple_particle"); public static final Key WALL_TORCH_PARTICLE = Key.of("craftengine:wall_torch_particle"); + public static final Key SEAT = Key.of("craftengine:seat"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/entity/BlockEntityTypes.java b/core/src/main/java/net/momirealms/craftengine/core/block/entity/BlockEntityTypes.java index 5719f4449..c4b725b06 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/entity/BlockEntityTypes.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/entity/BlockEntityTypes.java @@ -8,8 +8,8 @@ import net.momirealms.craftengine.core.util.ResourceKey; public abstract class BlockEntityTypes { - public static BlockEntityType register(Key id, BlockEntity.Factory factory) { - BlockEntityType type = new BlockEntityType<>(id, factory); + public static BlockEntityType register(Key id) { + BlockEntityType type = new BlockEntityType<>(id); ((WritableRegistry>) BuiltInRegistries.BLOCK_ENTITY_TYPE) .register(ResourceKey.create(Registries.BLOCK_ENTITY_TYPE.location(), id), type); return type; diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/properties/type/DoorHinge.java b/core/src/main/java/net/momirealms/craftengine/core/block/properties/type/DoorHinge.java index 16ef73e49..582710716 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/properties/type/DoorHinge.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/properties/type/DoorHinge.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.core.block.properties.type; public enum DoorHinge { - LEFT, RIGHT + LEFT, + RIGHT } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/properties/type/DoubleBlockHalf.java b/core/src/main/java/net/momirealms/craftengine/core/block/properties/type/DoubleBlockHalf.java index 1823e76dd..1f224faed 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/properties/type/DoubleBlockHalf.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/properties/type/DoubleBlockHalf.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.core.block.properties.type; public enum DoubleBlockHalf { - UPPER, LOWER + LOWER, + UPPER } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/properties/type/SingleBlockHalf.java b/core/src/main/java/net/momirealms/craftengine/core/block/properties/type/SingleBlockHalf.java index 04cee6405..0eee299c2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/properties/type/SingleBlockHalf.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/properties/type/SingleBlockHalf.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.core.block.properties.type; public enum SingleBlockHalf { - TOP, BOTTOM + BOTTOM, + TOP } 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 2b157f1fb..ab16f7a96 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 @@ -70,7 +70,7 @@ public abstract class AbstractFurnitureManager implements FurnitureManager { this.byId.clear(); } - protected abstract HitBox defaultHitBox(); + protected abstract HitBoxConfig defaultHitBox(); protected abstract FurnitureElement.Builder furnitureElementBuilder(); @@ -154,7 +154,7 @@ public abstract class AbstractFurnitureManager implements FurnitureManager { } // add hitboxes - List hitboxes = ResourceConfigUtils.parseConfigAsList(placementArguments.get("hitboxes"), HitBoxTypes::fromMap); + List hitboxes = ResourceConfigUtils.parseConfigAsList(placementArguments.get("hitboxes"), HitBoxTypes::fromMap); if (hitboxes.isEmpty() && externalModel.isEmpty()) { hitboxes = List.of(defaultHitBox()); } @@ -165,7 +165,7 @@ public abstract class AbstractFurnitureManager implements FurnitureManager { placements.put(anchorType, new CustomFurniture.Placement( anchorType, elements.toArray(new FurnitureElement[0]), - hitboxes.toArray(new HitBox[0]), + hitboxes.toArray(new HitBoxConfig[0]), ResourceConfigUtils.getOrDefault(ruleSection.get("rotation"), o -> RotationRule.valueOf(o.toString().toUpperCase(Locale.ENGLISH)), RotationRule.ANY), ResourceConfigUtils.getOrDefault(ruleSection.get("alignment"), o -> AlignmentRule.valueOf(o.toString().toUpperCase(Locale.ENGLISH)), AlignmentRule.CENTER), externalModel, @@ -175,7 +175,7 @@ public abstract class AbstractFurnitureManager implements FurnitureManager { placements.put(anchorType, new CustomFurniture.Placement( anchorType, elements.toArray(new FurnitureElement[0]), - hitboxes.toArray(new HitBox[0]), + hitboxes.toArray(new HitBoxConfig[0]), RotationRule.ANY, AlignmentRule.CENTER, externalModel, diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractHitBox.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractHitBoxConfig.java similarity index 71% rename from core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractHitBox.java rename to core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractHitBoxConfig.java index 11be803c9..d7f8e3021 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractHitBox.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractHitBoxConfig.java @@ -1,15 +1,16 @@ package net.momirealms.craftengine.core.entity.furniture; +import net.momirealms.craftengine.core.entity.seat.SeatConfig; import org.joml.Vector3f; -public abstract class AbstractHitBox implements HitBox { - protected final Seat[] seats; +public abstract class AbstractHitBoxConfig implements HitBoxConfig { + protected final SeatConfig[] seats; protected final Vector3f position; protected final boolean canUseItemOn; protected final boolean blocksBuilding; protected final boolean canBeHitByProjectile; - public AbstractHitBox(Seat[] seats, Vector3f position, boolean canUseItemOn, boolean blocksBuilding, boolean canBeHitByProjectile) { + public AbstractHitBoxConfig(SeatConfig[] seats, Vector3f position, boolean canUseItemOn, boolean blocksBuilding, boolean canBeHitByProjectile) { this.seats = seats; this.position = position; this.canUseItemOn = canUseItemOn; @@ -18,7 +19,7 @@ public abstract class AbstractHitBox implements HitBox { } @Override - public Seat[] seats() { + public SeatConfig[] seats() { return this.seats; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/CustomFurniture.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/CustomFurniture.java index 294e58dda..ad34cf2f3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/CustomFurniture.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/CustomFurniture.java @@ -51,7 +51,7 @@ public interface CustomFurniture { record Placement(AnchorType anchorType, FurnitureElement[] elements, - HitBox[] hitBoxes, + HitBoxConfig[] hitBoxConfigs, RotationRule rotationRule, AlignmentRule alignmentRule, Optional externalModel, 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 691092619..e5a2bcd59 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,12 +1,10 @@ package net.momirealms.craftengine.core.entity.furniture; -import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.world.WorldPosition; import org.jetbrains.annotations.NotNull; -import org.joml.Vector3f; +import org.jetbrains.annotations.Nullable; -import java.util.Optional; import java.util.UUID; public interface Furniture { @@ -18,32 +16,30 @@ public interface Furniture { void destroy(); + void destroyColliders(); + void destroySeats(); - Optional findFirstAvailableSeat(int targetEntityId); - - boolean removeOccupiedSeat(Vector3f seat); - - default boolean removeOccupiedSeat(Seat seat) { - return this.removeOccupiedSeat(seat.offset()); - } - - boolean tryOccupySeat(Seat seat); - UUID uuid(); int baseEntityId(); - @NotNull AnchorType anchorType(); + @Nullable + HitBox hitBoxByEntityId(int id); - @NotNull Key id(); + @Nullable HitBoxPart hitBoxPartByEntityId(int id); - @NotNull CustomFurniture config(); + @NotNull + AnchorType anchorType(); + + @NotNull + Key id(); + + @NotNull + CustomFurniture config(); boolean hasExternalModel(); - void spawnSeatEntityForPlayer(Player player, Seat seat); - FurnitureExtraData extraData(); void setExtraData(FurnitureExtraData extraData); 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 68cf5fa05..e57baec7d 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 @@ -15,8 +15,6 @@ import java.util.Optional; public interface FurnitureManager extends Manageable { Key FURNITURE_KEY = Key.of("craftengine:furniture_id"); Key FURNITURE_EXTRA_DATA_KEY = Key.of("craftengine:furniture_extra_data"); - Key FURNITURE_SEAT_BASE_ENTITY_KEY = Key.of("craftengine:seat_to_base_entity"); - Key FURNITURE_SEAT_VECTOR_3F_KEY = Key.of("craftengine:seat_vector"); Key FURNITURE_COLLISION = Key.of("craftengine:collision"); String FURNITURE_ADMIN_NODE = "craftengine.furniture.admin"; diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBox.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBox.java index cd145a799..961ea7420 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBox.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBox.java @@ -1,33 +1,19 @@ package net.momirealms.craftengine.core.entity.furniture; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.world.WorldPosition; -import net.momirealms.craftengine.core.world.collision.AABB; -import org.joml.Quaternionf; -import org.joml.Vector3f; +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 java.util.function.BiConsumer; -import java.util.function.Consumer; -import java.util.function.Supplier; +import java.util.Optional; -public interface HitBox { +public interface HitBox extends SeatOwner { - Key type(); + Seat[] seats(); - void initPacketsAndColliders(int[] entityId, WorldPosition position, Quaternionf conjugated, - BiConsumer packets, Consumer collider, BiConsumer aabb); + Optional clip(Vec3d min, Vec3d max); - void initShapeForPlacement(double x, double y, double z, float yaw, Quaternionf conjugated, Consumer aabbs); + HitBoxPart[] parts(); - int[] acquireEntityIds(Supplier entityIdSupplier); - - Seat[] seats(); - - Vector3f position(); - - boolean blocksBuilding(); - - boolean canBeHitByProjectile(); - - boolean canUseItemOn(); + HitBoxConfig config(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBoxConfig.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBoxConfig.java new file mode 100644 index 000000000..fdc574861 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBoxConfig.java @@ -0,0 +1,34 @@ +package net.momirealms.craftengine.core.entity.furniture; + +import net.momirealms.craftengine.core.entity.seat.SeatConfig; +import net.momirealms.craftengine.core.util.Key; +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.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Supplier; + +public interface HitBoxConfig { + + Key type(); + + void initPacketsAndColliders(int[] entityId, WorldPosition position, Quaternionf conjugated, + BiConsumer packets, Consumer collider, Consumer aabb); + + void initShapeForPlacement(double x, double y, double z, float yaw, Quaternionf conjugated, Consumer aabbs); + + int[] acquireEntityIds(Supplier entityIdSupplier); + + SeatConfig[] seats(); + + Vector3f position(); + + boolean blocksBuilding(); + + boolean canBeHitByProjectile(); + + boolean canUseItemOn(); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBoxConfigFactory.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBoxConfigFactory.java new file mode 100644 index 000000000..32fb5f355 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBoxConfigFactory.java @@ -0,0 +1,8 @@ +package net.momirealms.craftengine.core.entity.furniture; + +import java.util.Map; + +public interface HitBoxConfigFactory { + + HitBoxConfig create(Map arguments); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBoxFactory.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBoxFactory.java deleted file mode 100644 index 6b85ae871..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBoxFactory.java +++ /dev/null @@ -1,23 +0,0 @@ -package net.momirealms.craftengine.core.entity.furniture; - -import net.momirealms.craftengine.core.util.ResourceConfigUtils; - -import java.util.List; -import java.util.Map; - -public interface HitBoxFactory { - - HitBox create(Map arguments); - - @SuppressWarnings("unchecked") - static Seat[] getSeats(Map arguments) { - List seats = (List) arguments.getOrDefault("seats", List.of()); - return seats.stream() - .map(arg -> { - String[] split = arg.split(" "); - if (split.length == 1) return new Seat(ResourceConfigUtils.getAsVector3f(split[0], "seats"), 0, false); - return new Seat(ResourceConfigUtils.getAsVector3f(split[0], "seats"), Float.parseFloat(split[1]), true); - }) - .toArray(Seat[]::new); - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBoxPart.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBoxPart.java new file mode 100644 index 000000000..cfa336889 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBoxPart.java @@ -0,0 +1,7 @@ +package net.momirealms.craftengine.core.entity.furniture; + +import net.momirealms.craftengine.core.world.Vec3d; +import net.momirealms.craftengine.core.world.collision.AABB; + +public record HitBoxPart(int entityId, AABB aabb, Vec3d pos) { +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBoxTypes.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBoxTypes.java index 2b9a15d99..c005ee619 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBoxTypes.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBoxTypes.java @@ -16,14 +16,14 @@ public class HitBoxTypes { public static final Key HAPPY_GHAST = Key.of("minecraft:happy_ghast"); public static final Key CUSTOM = Key.of("minecraft:custom"); - public static void register(Key key, HitBoxFactory factory) { - ((WritableRegistry) BuiltInRegistries.HITBOX_FACTORY) + public static void register(Key key, HitBoxConfigFactory factory) { + ((WritableRegistry) BuiltInRegistries.HITBOX_FACTORY) .register(ResourceKey.create(Registries.HITBOX_FACTORY.location(), key), factory); } - public static HitBox fromMap(Map arguments) { + public static HitBoxConfig fromMap(Map arguments) { Key type = Optional.ofNullable(arguments.get("type")).map(String::valueOf).map(Key::of).orElse(HitBoxTypes.INTERACTION); - HitBoxFactory factory = BuiltInRegistries.HITBOX_FACTORY.getValue(type); + HitBoxConfigFactory factory = BuiltInRegistries.HITBOX_FACTORY.getValue(type); if (factory == null) { throw new LocalizedResourceConfigException("warning.config.furniture.hitbox.invalid_type", type.toString()); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/Seat.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/Seat.java deleted file mode 100644 index 885333703..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/Seat.java +++ /dev/null @@ -1,23 +0,0 @@ -package net.momirealms.craftengine.core.entity.furniture; - -import org.joml.Vector3f; - -import java.util.Objects; - -public record Seat(Vector3f offset, float yaw, boolean limitPlayerRotation) { - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof Seat seat)) return false; - return Float.compare(yaw, seat.yaw) == 0 && Objects.equals(offset, seat.offset) && limitPlayerRotation == seat.limitPlayerRotation; - } - - @Override - public int hashCode() { - int result = Objects.hashCode(offset); - result = 31 * result + Float.hashCode(yaw); - result = 31 * result + Boolean.hashCode(limitPlayerRotation); - return result; - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/seat/Seat.java b/core/src/main/java/net/momirealms/craftengine/core/entity/seat/Seat.java new file mode 100644 index 000000000..a2aeca7b6 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/seat/Seat.java @@ -0,0 +1,17 @@ +package net.momirealms.craftengine.core.entity.seat; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.world.WorldPosition; + +public interface Seat { + + O owner(); + + SeatConfig config(); + + boolean isOccupied(); + + void destroy(); + + boolean spawnSeat(Player player, WorldPosition source); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/seat/SeatConfig.java b/core/src/main/java/net/momirealms/craftengine/core/entity/seat/SeatConfig.java new file mode 100644 index 000000000..8a27080a2 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/seat/SeatConfig.java @@ -0,0 +1,30 @@ +package net.momirealms.craftengine.core.entity.seat; + +import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import org.joml.Vector3f; + +import java.util.List; + +public record SeatConfig(Vector3f position, float yRot, boolean limitPlayerRotation) { + + public static SeatConfig[] fromObj(Object config) { + if (config instanceof List) { + List seats = MiscUtils.getAsStringList(config); + return seats.stream() + .map(arg -> { + String[] split = arg.split(" "); + if (split.length == 1) return new SeatConfig(ResourceConfigUtils.getAsVector3f(split[0], "seats"), 0, false); + return new SeatConfig(ResourceConfigUtils.getAsVector3f(split[0], "seats"), Float.parseFloat(split[1]), true); + }) + .toArray(SeatConfig[]::new); + } else if (config != null) { + String arg = config.toString(); + String[] split = arg.split(" "); + if (split.length == 1) return new SeatConfig[] {new SeatConfig(ResourceConfigUtils.getAsVector3f(split[0], "seats"), 0, false)}; + return new SeatConfig[] {new SeatConfig(ResourceConfigUtils.getAsVector3f(split[0], "seats"), Float.parseFloat(split[1]), true)}; + } else { + return new SeatConfig[0]; + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/seat/SeatManager.java b/core/src/main/java/net/momirealms/craftengine/core/entity/seat/SeatManager.java new file mode 100644 index 000000000..a121b11a2 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/seat/SeatManager.java @@ -0,0 +1,9 @@ +package net.momirealms.craftengine.core.entity.seat; + +import net.momirealms.craftengine.core.plugin.Manageable; +import net.momirealms.craftengine.core.util.Key; + +public interface SeatManager extends Manageable { + Key SEAT_KEY = Key.of("craftengine:seat"); + Key SEAT_EXTRA_DATA_KEY = Key.of("craftengine:seat_extra_data"); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/seat/SeatOwner.java b/core/src/main/java/net/momirealms/craftengine/core/entity/seat/SeatOwner.java new file mode 100644 index 000000000..a341cb117 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/seat/SeatOwner.java @@ -0,0 +1,8 @@ +package net.momirealms.craftengine.core.entity.seat; + +import net.momirealms.sparrow.nbt.CompoundTag; + +public interface SeatOwner { + + void saveCustomData(CompoundTag data); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/NetworkItemBuildContext.java b/core/src/main/java/net/momirealms/craftengine/core/item/NetworkItemBuildContext.java new file mode 100644 index 000000000..48e45b0cc --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/NetworkItemBuildContext.java @@ -0,0 +1,46 @@ +package net.momirealms.craftengine.core.item; + +import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.context.ContextHolder; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.plugin.text.minimessage.*; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; + +public class NetworkItemBuildContext extends ItemBuildContext { + + public NetworkItemBuildContext(@Nullable Player player, @NotNull ContextHolder contexts) { + super(player, contexts); + } + + @NotNull + public static NetworkItemBuildContext empty() { + return new NetworkItemBuildContext(null, ContextHolder.empty()); + } + + @NotNull + public static NetworkItemBuildContext of(@Nullable Player player, @NotNull ContextHolder contexts) { + return new NetworkItemBuildContext(player, contexts); + } + + @NotNull + public static NetworkItemBuildContext of(@Nullable Player player, @NotNull ContextHolder.Builder builder) { + if (player != null) builder.withParameter(DirectContextParameters.PLAYER, player); + return new NetworkItemBuildContext(player, builder.build()); + } + + @NotNull + public static NetworkItemBuildContext of(@Nullable Player player) { + if (player == null) return new NetworkItemBuildContext(null, ContextHolder.empty()); + return new NetworkItemBuildContext(player, new ContextHolder(Map.of(DirectContextParameters.PLAYER, () -> player))); + } + + @NotNull + protected TagResolver[] getInternalTagResolvers() { + return new TagResolver[]{ShiftTag.INSTANCE, ImageTag.INSTANCE, new I18NTag(this), new L10NTag(this), new NamedArgumentTag(this), + new PlaceholderTag(this), new ExpressionTag(this), new GlobalVariableTag(this)}; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java index e5b116f5d..c72a2f0b2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java @@ -4,6 +4,7 @@ import net.momirealms.craftengine.core.advancement.AdvancementManager; import net.momirealms.craftengine.core.block.BlockManager; import net.momirealms.craftengine.core.entity.furniture.FurnitureManager; import net.momirealms.craftengine.core.entity.projectile.ProjectileManager; +import net.momirealms.craftengine.core.entity.seat.SeatManager; import net.momirealms.craftengine.core.font.FontManager; import net.momirealms.craftengine.core.item.ItemManager; import net.momirealms.craftengine.core.item.recipe.RecipeManager; @@ -76,6 +77,7 @@ public abstract class CraftEngine implements Plugin { protected CompatibilityManager compatibilityManager; protected GlobalVariableManager globalVariableManager; protected ProjectileManager projectileManager; + protected SeatManager seatManager; private final PluginTaskRegistry preLoadTaskRegistry = new PluginTaskRegistry(); private final PluginTaskRegistry postLoadTaskRegistry = new PluginTaskRegistry(); @@ -151,6 +153,7 @@ public abstract class CraftEngine implements Plugin { this.packManager.reload(); this.advancementManager.reload(); this.projectileManager.reload(); + this.seatManager.reload(); if (reloadRecipe) { this.recipeManager.reload(); } @@ -229,6 +232,7 @@ public abstract class CraftEngine implements Plugin { this.fontManager.delayedInit(); this.vanillaLootManager.delayedInit(); this.advancementManager.delayedInit(); + this.seatManager.delayedInit(); this.compatibilityManager.onDelayedEnable(); // reload the plugin try { @@ -263,6 +267,7 @@ public abstract class CraftEngine implements Plugin { if (this.guiManager != null) this.guiManager.disable(); if (this.soundManager != null) this.soundManager.disable(); if (this.vanillaLootManager != null) this.vanillaLootManager.disable(); + if (this.seatManager != null) this.seatManager.disable(); if (this.translationManager != null) this.translationManager.disable(); if (this.globalVariableManager != null) this.globalVariableManager.disable(); if (this.projectileManager != null) this.projectileManager.disable(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/DamageItemFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/DamageItemFunction.java index cf7159b0f..e5cbedec6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/DamageItemFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/DamageItemFunction.java @@ -9,10 +9,7 @@ import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; -import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelector; -import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelectors; import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.ResourceConfigUtils; import java.util.List; import java.util.Map; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/component/ComponentProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/component/ComponentProvider.java index 4dc7d0dd0..3ac802556 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/component/ComponentProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/component/ComponentProvider.java @@ -68,7 +68,7 @@ public sealed interface ComponentProvider extends Function if (context instanceof PlayerOptionalContext playerContext) { Player player = playerContext.player(); if (player != null) { - String content = TranslationManager.instance().miniMessageTranslation(this.key, player.locale()); + String content = TranslationManager.instance().miniMessageTranslation(this.key, player.selectedLocale()); if (content == null) { return Component.text(this.key); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/L10NTag.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/L10NTag.java new file mode 100644 index 000000000..162190afe --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/L10NTag.java @@ -0,0 +1,41 @@ +package net.momirealms.craftengine.core.plugin.text.minimessage; + +import net.kyori.adventure.text.minimessage.ParsingException; +import net.kyori.adventure.text.minimessage.tag.Tag; +import net.kyori.adventure.text.minimessage.tag.resolver.ArgumentQueue; +import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; +import net.momirealms.craftengine.core.plugin.locale.TranslationManager; +import net.momirealms.craftengine.core.util.AdventureHelper; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Locale; + +public class L10NTag implements TagResolver { + private final Context context; + + public L10NTag(Context context) { + this.context = context; + } + + @Override + public @Nullable Tag resolve(@NotNull String name, @NotNull ArgumentQueue arguments, @NotNull net.kyori.adventure.text.minimessage.Context ctx) throws ParsingException { + if (!this.has(name)) { + return null; + } + Locale locale = null; + if (this.context instanceof PlayerOptionalContext playerOptionalContext && playerOptionalContext.isPlayerPresent()) { + locale = playerOptionalContext.player().selectedLocale(); + } + String i18nKey = arguments.popOr("No argument l10n key provided").toString(); + String translation = TranslationManager.instance().miniMessageTranslation(i18nKey, locale); + return Tag.selfClosingInserting(AdventureHelper.miniMessage().deserialize(translation, this.context.tagResolvers())); + } + + @Override + public boolean has(@NotNull String name) { + return "l10n".equals(name); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java b/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java index 68b8d9a62..29b3ae91f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java @@ -5,7 +5,7 @@ import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.block.entity.BlockEntityType; import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfigFactory; import net.momirealms.craftengine.core.block.properties.PropertyFactory; -import net.momirealms.craftengine.core.entity.furniture.HitBoxFactory; +import net.momirealms.craftengine.core.entity.furniture.HitBoxConfigFactory; import net.momirealms.craftengine.core.item.ItemDataModifierFactory; import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; import net.momirealms.craftengine.core.item.equipment.EquipmentFactory; @@ -76,7 +76,7 @@ public class BuiltInRegistries { public static final Registry> PATH_MATCHER_FACTORY = createConstantBoundRegistry(Registries.PATH_MATCHER_FACTORY, 16); public static final Registry RESOLUTION_FACTORY = createConstantBoundRegistry(Registries.RESOLUTION_FACTORY, 16); public static final Registry SMITHING_RESULT_PROCESSOR_FACTORY = createConstantBoundRegistry(Registries.SMITHING_RESULT_PROCESSOR_FACTORY, 16); - public static final Registry HITBOX_FACTORY = createConstantBoundRegistry(Registries.HITBOX_FACTORY, 16); + public static final Registry HITBOX_FACTORY = createConstantBoundRegistry(Registries.HITBOX_FACTORY, 16); public static final Registry RESOURCE_PACK_HOST_FACTORY = createConstantBoundRegistry(Registries.RESOURCE_PACK_HOST_FACTORY, 16); public static final Registry> EVENT_FUNCTION_FACTORY = createConstantBoundRegistry(Registries.EVENT_FUNCTION_FACTORY, 128); public static final Registry> EVENT_CONDITION_FACTORY = createConstantBoundRegistry(Registries.EVENT_CONDITION_FACTORY, 128); diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java b/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java index 1f2522177..787fb1970 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java @@ -5,7 +5,7 @@ import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.block.entity.BlockEntityType; import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfigFactory; import net.momirealms.craftengine.core.block.properties.PropertyFactory; -import net.momirealms.craftengine.core.entity.furniture.HitBoxFactory; +import net.momirealms.craftengine.core.entity.furniture.HitBoxConfigFactory; import net.momirealms.craftengine.core.item.ItemDataModifierFactory; import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; import net.momirealms.craftengine.core.item.equipment.EquipmentFactory; @@ -78,7 +78,7 @@ public class Registries { public static final ResourceKey>> PATH_MATCHER_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("path_matcher_factory")); public static final ResourceKey> RESOLUTION_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("resolution_factory")); public static final ResourceKey> SMITHING_RESULT_PROCESSOR_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("smithing_result_processor_factory")); - public static final ResourceKey> HITBOX_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("hitbox_factory")); + public static final ResourceKey> HITBOX_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("hitbox_factory")); public static final ResourceKey> RESOURCE_PACK_HOST_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("resource_pack_host_factory")); public static final ResourceKey>> EVENT_FUNCTION_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("event_function_factory")); public static final ResourceKey>> EVENT_CONDITION_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("event_condition_factory")); diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/serialization/DefaultBlockEntitySerializer.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/serialization/DefaultBlockEntitySerializer.java index c2eaf3d9a..5c2a49712 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/serialization/DefaultBlockEntitySerializer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/serialization/DefaultBlockEntitySerializer.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.core.world.chunk.serialization; import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.block.behavior.EntityBlockBehavior; import net.momirealms.craftengine.core.block.entity.BlockEntity; import net.momirealms.craftengine.core.block.entity.BlockEntityType; import net.momirealms.craftengine.core.plugin.logger.Debugger; @@ -14,6 +15,7 @@ import net.momirealms.sparrow.nbt.ListTag; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Optional; public final class DefaultBlockEntitySerializer { @@ -41,9 +43,14 @@ public final class DefaultBlockEntitySerializer { BlockPos pos = BlockEntity.readPosAndVerify(data, chunk.chunkPos()); ImmutableBlockState blockState = chunk.getBlockState(pos); if (blockState.blockEntityType() == type) { - BlockEntity blockEntity = type.factory().create(pos, blockState); - blockEntity.loadCustomData(data); - blockEntities.add(blockEntity); + Optional entityBlockBehavior = blockState.behavior().getAs(EntityBlockBehavior.class); + if (entityBlockBehavior.isPresent()) { + BlockEntity blockEntity = entityBlockBehavior.get().createBlockEntity(pos, blockState); + if (blockEntity != null) { + blockEntity.loadCustomData(data); + blockEntities.add(blockEntity); + } + } } } } diff --git a/gradle.properties b/gradle.properties index 8f8eb7284..2917d771f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -39,7 +39,7 @@ zstd_version=1.5.7-4 commons_io_version=2.20.0 commons_lang3_version=3.19.0 sparrow_nbt_version=0.10.6 -sparrow_util_version=0.57 +sparrow_util_version=0.58 fastutil_version=8.5.18 netty_version=4.1.127.Final joml_version=1.10.8