From 31a6f490e3351a46fe46d2d5814bcd38c90ebbaa Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Mon, 31 Mar 2025 04:02:28 +0800 Subject: [PATCH] refactor furniture framework --- .../furniture/BukkitFurnitureElement.java | 67 +++++++++++++++ .../furniture/BukkitFurnitureManager.java | 42 ++++----- .../entity/furniture/BukkitHitBoxTypes.java | 12 +++ .../entity/furniture/InteractionHitBox.java | 81 +++++++++++++++++ .../entity/furniture/LoadedFurniture.java | 86 +++++-------------- .../bukkit/item/ItemEventListener.java | 1 - .../bukkit/plugin/BukkitCraftEngine.java | 2 + .../plugin/command/feature/TestCommand.java | 23 +++-- .../craftengine/bukkit/util/Reflections.java | 27 ++++-- .../bukkit/world/BukkitWorldManager.java | 2 - .../furniture/AbstractFurnitureElement.java | 60 +++++++++++++ .../core/entity/furniture/AbstractHitBox.java | 15 ++++ .../core/entity/furniture/Collider.java | 33 +++++++ .../entity/furniture/CustomFurniture.java | 20 +++-- .../entity/furniture/FurnitureElement.java | 48 +++-------- .../core/entity/furniture/HitBox.java | 31 ++----- .../core/entity/furniture/HitBoxFactory.java | 23 +++++ .../core/entity/furniture/HitBoxTypes.java | 31 +++++++ .../plugin/locale/ClientLangMangerImpl.java | 1 - .../core/plugin/locale/I18NData.java | 1 - .../MiniMessageTranslationRegistry.java | 1 - .../core/registry/BuiltInRegistries.java | 2 + .../craftengine/core/registry/Registries.java | 2 + gradle.properties | 2 +- 24 files changed, 431 insertions(+), 182 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureElement.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitHitBoxTypes.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/InteractionHitBox.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractFurnitureElement.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractHitBox.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/entity/furniture/Collider.java create 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/HitBoxTypes.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureElement.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureElement.java new file mode 100644 index 000000000..7763fae88 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureElement.java @@ -0,0 +1,67 @@ +package net.momirealms.craftengine.bukkit.entity.furniture; + +import net.momirealms.craftengine.bukkit.entity.DisplayEntityData; +import net.momirealms.craftengine.bukkit.item.BukkitItemManager; +import net.momirealms.craftengine.bukkit.util.Reflections; +import net.momirealms.craftengine.core.entity.furniture.AbstractFurnitureElement; +import net.momirealms.craftengine.core.entity.furniture.Billboard; +import net.momirealms.craftengine.core.entity.furniture.ItemDisplayContext; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.QuaternionUtils; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.joml.Quaternionf; +import org.joml.Vector3f; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.function.Consumer; + +public class BukkitFurnitureElement extends AbstractFurnitureElement { + private List cachedValues; + + public BukkitFurnitureElement(Key item, + Billboard billboard, + ItemDisplayContext transform, + Vector3f scale, + Vector3f translation, + Vector3f offset, + Quaternionf rotation) { + super(item, billboard, transform, scale, translation, offset, rotation); + } + + @Override + public void addSpawnPackets(int entityId, double x, double y, double z, float yaw, Consumer packets) { + try { + Vector3f offset = QuaternionUtils.toQuaternionf(0, Math.toRadians(180 - yaw), 0).conjugate().transform(new Vector3f(position())); + packets.accept(Reflections.constructor$ClientboundAddEntityPacket.newInstance( + entityId, UUID.randomUUID(), x + offset.x, y + offset.y, z - offset.z, 0, yaw, + Reflections.instance$EntityType$ITEM_DISPLAY, 0, Reflections.instance$Vec3$Zero, 0 + )); + packets.accept(Reflections.constructor$ClientboundSetEntityDataPacket.newInstance(entityId, getCachedValues())); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("Failed to construct element spawn packet", e); + } + } + + private synchronized List getCachedValues() { + if (this.cachedValues == null) { + this.cachedValues = new ArrayList<>(); + Item item = BukkitItemManager.instance().createWrappedItem(item(), null); + if (item == null) { + CraftEngine.instance().logger().warn("Failed to create furniture element for " + item() + " because item " + item() + " not found"); + item = BukkitItemManager.instance().wrap(new ItemStack(Material.STONE)); + } + DisplayEntityData.DisplayedItem.addEntityDataIfNotDefaultValue(item.getLiteralObject(), this.cachedValues); + DisplayEntityData.Scale.addEntityDataIfNotDefaultValue(scale(), this.cachedValues); + DisplayEntityData.RotationLeft.addEntityDataIfNotDefaultValue(rotation(), this.cachedValues); + DisplayEntityData.BillboardConstraints.addEntityDataIfNotDefaultValue(billboard().id(), this.cachedValues); + DisplayEntityData.Translation.addEntityDataIfNotDefaultValue(translation(), this.cachedValues); + DisplayEntityData.DisplayType.addEntityDataIfNotDefaultValue(transform().id(), this.cachedValues); + } + return this.cachedValues; + } +} 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 96129b367..0b29a6ecd 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,5 +1,6 @@ package net.momirealms.craftengine.bukkit.entity.furniture; +import net.momirealms.craftengine.bukkit.nms.CollisionEntity; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.util.EntityUtils; import net.momirealms.craftengine.core.entity.furniture.*; @@ -115,7 +116,7 @@ public class BukkitFurnitureManager implements FurnitureManager { } ItemDisplayContext transform = ItemDisplayContext.valueOf(element.getOrDefault("transform", "NONE").toString().toUpperCase(Locale.ENGLISH)); Billboard billboard = Billboard.valueOf(element.getOrDefault("billboard", "FIXED").toString().toUpperCase(Locale.ENGLISH)); - FurnitureElement furnitureElement = new FurnitureElement(Key.of(key), billboard, transform, + FurnitureElement furnitureElement = new BukkitFurnitureElement(Key.of(key), billboard, transform, MiscUtils.getVector3f(element.getOrDefault("scale", "1")), MiscUtils.getVector3f(element.getOrDefault("translation", "0")), MiscUtils.getVector3f(element.getOrDefault("position", "0")), @@ -126,32 +127,10 @@ public class BukkitFurnitureManager implements FurnitureManager { List> hitboxConfigs = (List>) placementArguments.getOrDefault("hitboxes", List.of()); List hitboxes = new ArrayList<>(); for (Map config : hitboxConfigs) { - List seats = (List) config.getOrDefault("seats", List.of()); - Seat[] seatArray = seats.stream() - .map(arg -> { - String[] split = arg.split(" "); - if (split.length == 1) return new Seat(MiscUtils.getVector3f(split[0]), 0, false); - return new Seat(MiscUtils.getVector3f(split[0]), Float.parseFloat(split[1]), true); - }) - .toArray(Seat[]::new); - Vector3f position = MiscUtils.getVector3f(config.getOrDefault("position", "0")); - float width = MiscUtils.getAsFloat(config.getOrDefault("width", "1")); - float height = MiscUtils.getAsFloat(config.getOrDefault("height", "1")); - HitBox hitBox = new HitBox( - position, - new Vector3f(width, height, width), - seatArray, - (boolean) config.getOrDefault("interactive", true) - ); - hitboxes.add(hitBox); + hitboxes.add(HitBoxTypes.fromMap(config)); } if (hitboxes.isEmpty()) { - hitboxes.add(new HitBox( - new Vector3f(), - new Vector3f(1,1,1), - new Seat[0], - true - )); + hitboxes.add(InteractionHitBox.DEFAULT); } Map ruleSection = MiscUtils.castToMap(placementArguments.get("rules"), true); if (ruleSection != null) { @@ -164,6 +143,7 @@ public class BukkitFurnitureManager implements FurnitureManager { placements.put(anchorType, new CustomFurniture.Placement( elements.toArray(new FurnitureElement[0]), hitboxes.toArray(new HitBox[0]), + new Collider[0], rotationRule, alignmentRule )); @@ -171,6 +151,7 @@ public class BukkitFurnitureManager implements FurnitureManager { placements.put(anchorType, new CustomFurniture.Placement( elements.toArray(new FurnitureElement[0]), hitboxes.toArray(new HitBox[0]), + new Collider[0], RotationRule.ANY, AlignmentRule.CENTER )); @@ -222,6 +203,13 @@ public class BukkitFurnitureManager implements FurnitureManager { tryLeavingSeat(player, vehicle); } } +// for (World world : Bukkit.getWorlds()) { +// for (Entity entity : world.getEntities()) { +// if (entity instanceof CollisionEntity) { +// entity.remove(); +// } +// } +// } } @Override @@ -252,6 +240,10 @@ public class BukkitFurnitureManager implements FurnitureManager { for (int sub : furniture.interactionEntityIds()) { this.furnitureByInteractionEntityId.remove(sub); } + } else if (entity instanceof Interaction interaction) { + if (interaction instanceof CollisionEntity) { + entity.remove(); + } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitHitBoxTypes.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitHitBoxTypes.java new file mode 100644 index 000000000..55d5035a0 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitHitBoxTypes.java @@ -0,0 +1,12 @@ +package net.momirealms.craftengine.bukkit.entity.furniture; + +import net.momirealms.craftengine.core.entity.furniture.HitBoxTypes; + +public class BukkitHitBoxTypes extends HitBoxTypes { + + public static void init() {} + + static { + register(INTERACTION, InteractionHitBox.FACTORY); + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/InteractionHitBox.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/InteractionHitBox.java new file mode 100644 index 000000000..a2b1231ab --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/InteractionHitBox.java @@ -0,0 +1,81 @@ +package net.momirealms.craftengine.bukkit.entity.furniture; + +import net.momirealms.craftengine.bukkit.entity.InteractionEntityData; +import net.momirealms.craftengine.bukkit.util.Reflections; +import net.momirealms.craftengine.core.entity.furniture.*; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.QuaternionUtils; +import org.joml.Vector3f; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.function.Consumer; + +public class InteractionHitBox extends AbstractHitBox { + public static final Factory FACTORY = new Factory(); + public static final InteractionHitBox DEFAULT = new InteractionHitBox(new Seat[0], new Vector3f(), new Vector3f(1,1,1), true); + private final Vector3f position; + private final Vector3f size; + private final boolean responsive; + private final List cachedValues = new ArrayList<>(); + + public InteractionHitBox(Seat[] seats, Vector3f position, Vector3f size, boolean responsive) { + super(seats); + this.position = position; + this.size = size; + this.responsive = responsive; + InteractionEntityData.Height.addEntityDataIfNotDefaultValue(size.y, cachedValues); + InteractionEntityData.Width.addEntityDataIfNotDefaultValue(size.x, cachedValues); + InteractionEntityData.Responsive.addEntityDataIfNotDefaultValue(responsive, cachedValues); + } + + public boolean responsive() { + return responsive; + } + + public Vector3f position() { + return position; + } + + public Vector3f size() { + return size; + } + + @Override + public Key type() { + return HitBoxTypes.INTERACTION; + } + + @Override + public void addSpawnPackets(int entityId, double x, double y, double z, float yaw, Consumer packets) { + Vector3f offset = QuaternionUtils.toQuaternionf(0f, Math.toRadians(180f - yaw), 0f).conjugate().transform(new Vector3f(position())); + try { + packets.accept(Reflections.constructor$ClientboundAddEntityPacket.newInstance( + entityId, UUID.randomUUID(), x + offset.x, y + offset.y, z - offset.z, 0, yaw, + Reflections.instance$EntityType$INTERACTION, 0, Reflections.instance$Vec3$Zero, 0 + )); + packets.accept(Reflections.constructor$ClientboundSetEntityDataPacket.newInstance(entityId, List.copyOf(this.cachedValues))); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("Failed to construct hitbox spawn packet", e); + } + } + + public static class Factory implements HitBoxFactory { + + @Override + public HitBox create(Map arguments) { + Vector3f position = MiscUtils.getVector3f(arguments.getOrDefault("position", "0")); + float width = MiscUtils.getAsFloat(arguments.getOrDefault("width", "1")); + float height = MiscUtils.getAsFloat(arguments.getOrDefault("height", "1")); + return new InteractionHitBox( + HitBoxFactory.getSeats(arguments), + position, + new Vector3f(width, height, width), + (boolean) arguments.getOrDefault("interactive", true) + ); + } + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java index 564769812..8fbbc5a40 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java @@ -1,13 +1,9 @@ package net.momirealms.craftengine.bukkit.entity.furniture; -import net.momirealms.craftengine.bukkit.entity.DisplayEntityData; -import net.momirealms.craftengine.bukkit.entity.InteractionEntityData; -import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.util.EntityUtils; import net.momirealms.craftengine.bukkit.util.LegacyAttributeUtils; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.entity.furniture.*; -import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.ArrayUtils; import net.momirealms.craftengine.core.util.Key; @@ -19,7 +15,6 @@ import org.bukkit.entity.ArmorStand; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.ItemDisplay; -import org.bukkit.inventory.ItemStack; import org.bukkit.persistence.PersistentDataType; import org.jetbrains.annotations.NotNull; import org.joml.Vector3f; @@ -35,8 +30,6 @@ public class LoadedFurniture { private final Map hitBoxes; // location private Location location; - // cached spawn packet - private Object cachedSpawnPacket; // base entity private final WeakReference baseEntity; private final int baseEntityId; @@ -48,6 +41,9 @@ public class LoadedFurniture { private final Set occupiedSeats = Collections.synchronizedSet(new HashSet<>()); private final Vector seats = new Vector<>(); + // cached spawn packet + private Object cachedSpawnPacket; + public LoadedFurniture(Entity baseEntity, CustomFurniture furniture, AnchorType anchorType) { @@ -60,77 +56,39 @@ public class LoadedFurniture { this.hitBoxes = new HashMap<>(); this.elements = new HashMap<>(); List entityIds = new ArrayList<>(); - List interactionEntityIds = new ArrayList<>(); + List hitBoxEntityIds = new ArrayList<>(); CustomFurniture.Placement placement = furniture.getPlacement(anchorType); for (FurnitureElement element : placement.elements()) { int entityId = Reflections.instance$Entity$ENTITY_COUNTER.incrementAndGet(); entityIds.add(entityId); this.elements.put(entityId, element); } - for (HitBox hitBox : placement.hitbox()) { + for (HitBox hitBox : placement.hitboxes()) { int entityId = Reflections.instance$Entity$ENTITY_COUNTER.incrementAndGet(); entityIds.add(entityId); - interactionEntityIds.add(entityId); + hitBoxEntityIds.add(entityId); this.hitBoxes.put(entityId, hitBox); } this.subEntityIds = entityIds; - this.interactionEntityIds = interactionEntityIds; - this.resetSpawnPackets(); + this.interactionEntityIds = hitBoxEntityIds; } - private void resetSpawnPackets() { - try { - List packets = new ArrayList<>(); - for (Map.Entry entry : elements.entrySet()) { - int entityId = entry.getKey(); - FurnitureElement element = entry.getValue(); - Item item = BukkitItemManager.instance().createWrappedItem(element.item(), null); - if (item == null) { - CraftEngine.instance().logger().warn("Failed to create furniture element for " + id + " because item " + element.item() + " not found"); - continue; + public synchronized Object spawnPacket() { + if (this.cachedSpawnPacket == null) { + try { + List packets = new ArrayList<>(); + for (Map.Entry entry : this.elements.entrySet()) { + entry.getValue().addSpawnPackets(entry.getKey(), this.location.getX(), this.location.getY(), this.location.getZ(), this.location.getYaw(), packets::add); } - item.load(); - - Vector3f offset = QuaternionUtils.toQuaternionf(0, Math.toRadians(180 - this.location.getYaw()), 0).conjugate().transform(new Vector3f(element.offset())); - Object addEntityPacket = Reflections.constructor$ClientboundAddEntityPacket.newInstance( - entityId, UUID.randomUUID(), this.location.getX() + offset.x, this.location.getY() + offset.y, this.location.getZ() - offset.z, 0, this.location.getYaw(), - Reflections.instance$EntityType$ITEM_DISPLAY, 0, Reflections.instance$Vec3$Zero, 0 - ); - - ArrayList values = new ArrayList<>(); - DisplayEntityData.DisplayedItem.addEntityDataIfNotDefaultValue(item.getLiteralObject(), values); - DisplayEntityData.Scale.addEntityDataIfNotDefaultValue(element.scale(), values); - DisplayEntityData.RotationLeft.addEntityDataIfNotDefaultValue(element.rotation(), values); - DisplayEntityData.BillboardConstraints.addEntityDataIfNotDefaultValue(element.billboard().id(), values); - DisplayEntityData.Translation.addEntityDataIfNotDefaultValue(element.translation(), values); - DisplayEntityData.DisplayType.addEntityDataIfNotDefaultValue(element.transform().id(), values); - Object setDataPacket = Reflections.constructor$ClientboundSetEntityDataPacket.newInstance(entityId, values); - - packets.add(addEntityPacket); - packets.add(setDataPacket); + for (Map.Entry entry : this.hitBoxes.entrySet()) { + entry.getValue().addSpawnPackets(entry.getKey(), this.location.getX(), this.location.getY(), this.location.getZ(), this.location.getYaw(), packets::add); + } + this.cachedSpawnPacket = Reflections.constructor$ClientboundBundlePacket.newInstance(packets); + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to init spawn packets for furniture " + id, e); } - for (Map.Entry entry : hitBoxes.entrySet()) { - int entityId = entry.getKey(); - HitBox hitBox = entry.getValue(); - Vector3f offset = QuaternionUtils.toQuaternionf(0, Math.toRadians(180 - this.location.getYaw()), 0).conjugate().transform(new Vector3f(hitBox.offset())); - Object addEntityPacket = Reflections.constructor$ClientboundAddEntityPacket.newInstance( - entityId, UUID.randomUUID(), this.location.getX() + offset.x, this.location.getY() + offset.y, this.location.getZ() - offset.z, 0, this.location.getYaw(), - Reflections.instance$EntityType$INTERACTION, 0, Reflections.instance$Vec3$Zero, 0 - ); - - ArrayList values = new ArrayList<>(); - InteractionEntityData.Height.addEntityDataIfNotDefaultValue(hitBox.size().y, values); - InteractionEntityData.Width.addEntityDataIfNotDefaultValue(hitBox.size().x, values); - InteractionEntityData.Responsive.addEntityDataIfNotDefaultValue(hitBox.responsive(), values); - Object setDataPacket = Reflections.constructor$ClientboundSetEntityDataPacket.newInstance(entityId, values); - - packets.add(addEntityPacket); - packets.add(setDataPacket); - } - this.cachedSpawnPacket = Reflections.constructor$ClientboundBundlePacket.newInstance(packets); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to init spawn packets for furniture " + id, e); } + return this.cachedSpawnPacket; } @NotNull @@ -274,8 +232,4 @@ public class LoadedFurniture { this.addSeatEntity(seatEntity); seatEntity.addPassenger(player); } - - public @NotNull Object spawnPacket() { - return cachedSpawnPacket; - } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ItemEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ItemEventListener.java index 6ed73e652..d99707c35 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ItemEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ItemEventListener.java @@ -15,7 +15,6 @@ import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.context.UseOnContext; import net.momirealms.craftengine.core.util.Direction; -import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.world.BlockHitResult; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.Vec3d; 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 70d315817..61ca30da6 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 @@ -6,6 +6,7 @@ import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.block.behavior.BukkitBlockBehaviors; import net.momirealms.craftengine.bukkit.compatibility.papi.PlaceholderAPIUtils; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; +import net.momirealms.craftengine.bukkit.entity.furniture.BukkitHitBoxTypes; import net.momirealms.craftengine.bukkit.font.BukkitImageManager; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.item.behavior.BukkitItemBehaviors; @@ -142,6 +143,7 @@ public class BukkitCraftEngine extends CraftEngine { } BukkitBlockBehaviors.init(); BukkitItemBehaviors.init(); + BukkitHitBoxTypes.init(); super.packManager = new BukkitPackManager(this); super.senderFactory = new BukkitSenderFactory(this); super.itemManager = new BukkitItemManager(this); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java index 0aa002af8..f10fc7d27 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java @@ -1,15 +1,16 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; +import net.momirealms.craftengine.bukkit.nms.CollisionEntity; +import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; +import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; -import net.momirealms.craftengine.core.registry.Holder; -import net.momirealms.craftengine.core.util.Key; +import org.bukkit.Location; import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; import org.incendo.cloud.Command; -import java.util.List; - public class TestCommand extends BukkitCommandFeature { public TestCommand(CraftEngineCommandManager commandManager, CraftEngine plugin) { @@ -19,10 +20,18 @@ public class TestCommand extends BukkitCommandFeature { @Override public Command.Builder assembleCommand(org.incendo.cloud.CommandManager manager, Command.Builder builder) { return builder + .senderType(Player.class) .handler(context -> { - List> holders = plugin().itemManager().tagToItems(Key.of("minecraft:planks")); - for (Holder holder : holders) { - context.sender().sendMessage(holder.registeredName()); + Player player = context.sender(); + Location location = player.getLocation(); + try { + Object level = Reflections.field$CraftWorld$ServerLevel.get(player.getWorld()); + Object aabb = FastNMS.INSTANCE.constructor$AABB(location.getBlockX(), location.getBlockY(), location.getBlockZ(), + location.getBlockX() + 1, location.getBlockY() + 1, location.getBlockZ() + 1); + CollisionEntity nmsEntity = FastNMS.INSTANCE.createCollisionEntity(level, aabb, location.getBlockX() + 0.5, location.getBlockY(), location.getBlockZ() + 0.5, true, false); + FastNMS.INSTANCE.method$LevelWriter$addFreshEntity(level, nmsEntity); + } catch (Exception e) { + e.printStackTrace(); } }); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index d859d3bf8..e6fae8b2d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -2426,6 +2426,12 @@ public class Reflections { ) ); + public static final Constructor constructor$AABB = requireNonNull( + ReflectionUtils.getConstructor( + clazz$AABB, double.class, double.class, double.class, double.class, double.class, double.class + ) + ); + public static final Class clazz$BlockGetter = requireNonNull( ReflectionUtils.getClazz( BukkitReflectionUtils.assembleMCClass("world.level.BlockGetter"), @@ -5753,22 +5759,27 @@ public class Reflections { ) ); - public static final Field field$Level$random = requireNonNull( - ReflectionUtils.getDeclaredField( - clazz$Level, clazz$RandomSource, 0 + public static final Field field$Entity$boundingBox = requireNonNull( + ReflectionUtils.getInstanceDeclaredField( + clazz$Entity, clazz$AABB, 0 ) ); - public static final Class clazz$Mth = requireNonNull( + public static final Class clazz$CraftShulker = requireNonNull( ReflectionUtils.getClazz( - BukkitReflectionUtils.assembleMCClass("util.Mth"), - BukkitReflectionUtils.assembleMCClass("util.MathHelper") + BukkitReflectionUtils.assembleCBClass("entity.CraftShulker") ) ); - public static final Method method$nextInt = requireNonNull( + public static final Class clazz$Shulker = requireNonNull( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("world.entity.monster.Shulker") + ) + ); + + public static final Method method$CraftShulker$getHandle = requireNonNull( ReflectionUtils.getMethod( - clazz$Mth, int.class, clazz$RandomSource, int.class, int.class + clazz$CraftShulker, clazz$Shulker, 0 ) ); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java index 001dc1754..2125528ce 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java @@ -395,6 +395,4 @@ public class BukkitWorldManager implements WorldManager, Listener { } ceChunk.load(); } - - } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractFurnitureElement.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractFurnitureElement.java new file mode 100644 index 000000000..426907463 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractFurnitureElement.java @@ -0,0 +1,60 @@ +package net.momirealms.craftengine.core.entity.furniture; + +import net.momirealms.craftengine.core.util.Key; +import org.joml.Quaternionf; +import org.joml.Vector3f; + +public abstract class AbstractFurnitureElement implements FurnitureElement { + private final Key item; + private final Billboard billboard; + private final ItemDisplayContext transform; + private final Vector3f scale; + private final Vector3f translation; + private final Vector3f offset; + private final Quaternionf rotation; + + public AbstractFurnitureElement(Key item, Billboard billboard, ItemDisplayContext transform, Vector3f scale, Vector3f translation, Vector3f offset, Quaternionf rotation) { + this.billboard = billboard; + this.transform = transform; + this.scale = scale; + this.translation = translation; + this.item = item; + this.rotation = rotation; + this.offset = offset; + } + + @Override + public Quaternionf rotation() { + return rotation; + } + + @Override + public Key item() { + return item; + } + + @Override + public Billboard billboard() { + return billboard; + } + + @Override + public ItemDisplayContext transform() { + return transform; + } + + @Override + public Vector3f scale() { + return scale; + } + + @Override + public Vector3f translation() { + return translation; + } + + @Override + public Vector3f position() { + return offset; + } +} 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/AbstractHitBox.java new file mode 100644 index 000000000..e7958a1c7 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractHitBox.java @@ -0,0 +1,15 @@ +package net.momirealms.craftengine.core.entity.furniture; + +public abstract class AbstractHitBox implements HitBox { + protected final Seat[] seats; + + public AbstractHitBox(Seat[] seats) { + this.seats = seats; + } + + @Override + public Seat[] seats() { + return seats; + } + +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/Collider.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/Collider.java new file mode 100644 index 000000000..b9db719ca --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/Collider.java @@ -0,0 +1,33 @@ +package net.momirealms.craftengine.core.entity.furniture; + +import org.joml.Vector3f; + +public class Collider { + private final Vector3f position; + private final double width; + private final double height; + private final boolean canBeHitByProjectile; + + public Collider(boolean canBeHitByProjectile, double height, Vector3f position, double width) { + this.canBeHitByProjectile = canBeHitByProjectile; + this.height = height; + this.position = position; + this.width = width; + } + + public boolean canBeHitByProjectile() { + return canBeHitByProjectile; + } + + public double height() { + return height; + } + + public Vector3f position() { + return position; + } + + public double width() { + return width; + } +} 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 eb4a1b681..52f2674a5 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 @@ -11,6 +11,7 @@ public class CustomFurniture { private final Key id; private final FurnitureSettings settings; private final EnumMap placements; + private final AnchorType anyType; @Nullable private final LootTable lootTable; @@ -22,6 +23,7 @@ public class CustomFurniture { this.settings = settings; this.placements = placements; this.lootTable = lootTable; + this.anyType = placements.keySet().stream().findFirst().orElse(null); } public Key id() { @@ -42,7 +44,7 @@ public class CustomFurniture { } public AnchorType getAnyPlacement() { - return placements.keySet().stream().findFirst().orElse(null); + return this.anyType; } public boolean isAllowedPlacement(AnchorType anchorType) { @@ -55,19 +57,25 @@ public class CustomFurniture { public static class Placement { private final FurnitureElement[] elements; - private final HitBox[] hitbox; + private final HitBox[] hitboxes; + private final Collider[] colliders; private final RotationRule rotationRule; private final AlignmentRule alignmentRule; - public Placement(FurnitureElement[] elements, HitBox[] hitbox, RotationRule rotationRule, AlignmentRule alignmentRule) { + public Placement(FurnitureElement[] elements, HitBox[] hitboxes, Collider[] colliders, RotationRule rotationRule, AlignmentRule alignmentRule) { this.elements = elements; - this.hitbox = hitbox; + this.hitboxes = hitboxes; + this.colliders = colliders; this.rotationRule = rotationRule; this.alignmentRule = alignmentRule; } - public HitBox[] hitbox() { - return hitbox; + public HitBox[] hitboxes() { + return hitboxes; + } + + public Collider[] colliders() { + return colliders; } public FurnitureElement[] elements() { diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureElement.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureElement.java index 5e48e9c21..335e57b1e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureElement.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureElement.java @@ -4,50 +4,22 @@ import net.momirealms.craftengine.core.util.Key; import org.joml.Quaternionf; import org.joml.Vector3f; -public class FurnitureElement { - private final Key item; - private final Billboard billboard; - private final ItemDisplayContext transform; - private final Vector3f scale; - private final Vector3f translation; - private final Vector3f offset; - private final Quaternionf rotation; +import java.util.function.Consumer; - public FurnitureElement(Key item, Billboard billboard, ItemDisplayContext transform, Vector3f scale, Vector3f translation, Vector3f offset, Quaternionf rotation) { - this.billboard = billboard; - this.transform = transform; - this.scale = scale; - this.translation = translation; - this.item = item; - this.rotation = rotation; - this.offset = offset; - } +public interface FurnitureElement { + Quaternionf rotation(); - public Quaternionf rotation() { - return rotation; - } + Key item(); - public Key item() { - return item; - } + Billboard billboard(); - public Billboard billboard() { - return billboard; - } + ItemDisplayContext transform(); - public ItemDisplayContext transform() { - return transform; - } + Vector3f scale(); - public Vector3f scale() { - return scale; - } + Vector3f translation(); - public Vector3f translation() { - return translation; - } + Vector3f position(); - public Vector3f offset() { - return offset; - } + void addSpawnPackets(int entityId, double x, double y, double z, float yaw, Consumer packets); } 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 1ec2c1c82..3b77677b3 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,14 @@ package net.momirealms.craftengine.core.entity.furniture; -import org.joml.Vector3f; +import net.momirealms.craftengine.core.util.Key; -public class HitBox { - private final Vector3f position; - private final Vector3f size; - private final Seat[] seats; - private final boolean responsive; +import java.util.function.Consumer; - public HitBox(Vector3f position, Vector3f size, Seat[] seats, boolean responsive) { - this.position = position; - this.size = size; - this.seats = seats; - this.responsive = responsive; - } +public interface HitBox { - public boolean responsive() { - return responsive; - } + Key type(); - public Seat[] seats() { - return seats; - } + void addSpawnPackets(int entityId, double x, double y, double z, float yaw, Consumer packets); - public Vector3f offset() { - return position; - } - - public Vector3f size() { - return size; - } + Seat[] seats(); } 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 new file mode 100644 index 000000000..54a4f6c39 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBoxFactory.java @@ -0,0 +1,23 @@ +package net.momirealms.craftengine.core.entity.furniture; + +import net.momirealms.craftengine.core.util.MiscUtils; + +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(MiscUtils.getVector3f(split[0]), 0, false); + return new Seat(MiscUtils.getVector3f(split[0]), Float.parseFloat(split[1]), true); + }) + .toArray(Seat[]::new); + } +} 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 new file mode 100644 index 000000000..994bef69b --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBoxTypes.java @@ -0,0 +1,31 @@ +package net.momirealms.craftengine.core.entity.furniture; + +import net.momirealms.craftengine.core.registry.BuiltInRegistries; +import net.momirealms.craftengine.core.registry.Holder; +import net.momirealms.craftengine.core.registry.Registries; +import net.momirealms.craftengine.core.registry.WritableRegistry; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceKey; + +import java.util.Map; +import java.util.Optional; + +public class HitBoxTypes { + public static final Key INTERACTION = Key.of("minecraft:interaction"); + public static final Key SHULKER = Key.of("minecraft:shulker"); + + public static void register(Key key, HitBoxFactory factory) { + Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.HITBOX_FACTORY) + .registerForHolder(new ResourceKey<>(Registries.HITBOX_FACTORY.location(), key)); + holder.bindValue(factory); + } + + public static HitBox fromMap(Map arguments) { + Key type = Optional.ofNullable((String) arguments.get("type")).map(Key::of).orElse(HitBoxTypes.INTERACTION); + HitBoxFactory factory = BuiltInRegistries.HITBOX_FACTORY.getValue(type); + if (factory == null) { + throw new IllegalArgumentException("Unknown hitbox type: " + type); + } + return factory.create(arguments); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/ClientLangMangerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/ClientLangMangerImpl.java index 510e08095..01f7c138e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/ClientLangMangerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/ClientLangMangerImpl.java @@ -1,7 +1,6 @@ package net.momirealms.craftengine.core.plugin.locale; import net.momirealms.craftengine.core.pack.Pack; -import net.momirealms.craftengine.core.plugin.Plugin; import net.momirealms.craftengine.core.util.Key; import java.nio.file.Path; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/I18NData.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/I18NData.java index da79432a2..e2702a7da 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/I18NData.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/I18NData.java @@ -1,7 +1,6 @@ package net.momirealms.craftengine.core.plugin.locale; import net.momirealms.craftengine.core.block.BlockStateParser; -import net.momirealms.craftengine.core.block.BlockStateVariantProvider; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.plugin.CraftEngine; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MiniMessageTranslationRegistry.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MiniMessageTranslationRegistry.java index f614a8fbb..d3254a129 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MiniMessageTranslationRegistry.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MiniMessageTranslationRegistry.java @@ -3,7 +3,6 @@ package net.momirealms.craftengine.core.plugin.locale; import net.kyori.adventure.key.Key; import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.translation.Translator; -import net.momirealms.craftengine.core.plugin.CraftEngine; import org.jetbrains.annotations.NotNull; import java.util.Locale; 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 a1c907c9d..8d2ed047b 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 @@ -3,6 +3,7 @@ package net.momirealms.craftengine.core.registry; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.block.properties.PropertyFactory; +import net.momirealms.craftengine.core.entity.furniture.HitBoxFactory; import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; import net.momirealms.craftengine.core.item.recipe.CustomSmithingTransformRecipe; import net.momirealms.craftengine.core.item.recipe.RecipeFactory; @@ -45,6 +46,7 @@ public class BuiltInRegistries { public static final Registry PATH_MATCHER_FACTORY = createRegistry(Registries.PATH_MATCHER_FACTORY); public static final Registry RESOLUTION_FACTORY = createRegistry(Registries.RESOLUTION_FACTORY); public static final Registry SMITHING_RESULT_PROCESSOR_FACTORY = createRegistry(Registries.SMITHING_RESULT_PROCESSOR_FACTORY); + public static final Registry HITBOX_FACTORY = createRegistry(Registries.HITBOX_FACTORY); private static Registry createRegistry(ResourceKey> key) { return new MappedRegistry<>(key); 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 3d766235f..7ae6e2fdb 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 @@ -3,6 +3,7 @@ package net.momirealms.craftengine.core.registry; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.block.properties.PropertyFactory; +import net.momirealms.craftengine.core.entity.furniture.HitBoxFactory; import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; import net.momirealms.craftengine.core.item.recipe.CustomSmithingTransformRecipe; import net.momirealms.craftengine.core.item.recipe.RecipeFactory; @@ -46,4 +47,5 @@ public class Registries { public static final ResourceKey> PATH_MATCHER_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("path_matcher_factory")); public static final ResourceKey> RESOLUTION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("resolution_factory")); public static final ResourceKey> SMITHING_RESULT_PROCESSOR_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("smithing_result_processor_factory")); + public static final ResourceKey> HITBOX_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("hitbox_factory")); } diff --git a/gradle.properties b/gradle.properties index be79c2ef3..0141385e1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -49,7 +49,7 @@ mojang_brigadier_version=1.0.18 byte_buddy_version=1.15.11 snake_yaml_version=2.3 anti_grief_version=0.13 -nms_helper_version=0.12 +nms_helper_version=0.19 # Ignite Dependencies mixinextras_version=0.4.1 mixin_version=0.15.2+mixin.0.8.7