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 10c928c92..04f57f418 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 @@ -251,7 +251,7 @@ public class CraftEngineFurniture { boolean playSound) { Location location = loadedFurniture.location(); loadedFurniture.destroy(); - LootTable lootTable = (LootTable) loadedFurniture.furniture().lootTable(); + LootTable lootTable = (LootTable) loadedFurniture.config().lootTable(); Vec3d vec3d = LocationUtils.toVec3d(location); World world = new BukkitWorld(location.getWorld()); if (dropLoot && lootTable != null) { @@ -268,7 +268,7 @@ public class CraftEngineFurniture { } } if (playSound) { - world.playBlockSound(vec3d, loadedFurniture.furniture().settings().sounds().breakSound()); + world.playBlockSound(vec3d, loadedFurniture.config().settings().sounds().breakSound()); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurniturePlaceEvent.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurniturePlaceEvent.java index be33468a6..76b63d0fb 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurniturePlaceEvent.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurniturePlaceEvent.java @@ -33,12 +33,12 @@ public class FurniturePlaceEvent extends PlayerEvent implements Cancellable { @NotNull public LoadedFurniture furniture() { - return furniture; + return this.furniture; } @NotNull public Location location() { - return location; + return this.location; } @NotNull 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 b8f673fc4..a7a8f24a2 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 @@ -103,10 +103,13 @@ public class BukkitFurnitureManager implements FurnitureManager { if (placementMap == null) { throw new IllegalArgumentException("Missing required parameter 'placement' for furniture " + id); } + for (Map.Entry entry : placementMap.entrySet()) { + // anchor type AnchorType anchorType = AnchorType.valueOf(entry.getKey().toUpperCase(Locale.ENGLISH)); Map placementArguments = MiscUtils.castToMap(entry.getValue(), true); + // furniture display elements List elements = new ArrayList<>(); List> elementConfigs = (List>) placementArguments.getOrDefault("elements", List.of()); for (Map element : elementConfigs) { @@ -124,6 +127,8 @@ public class BukkitFurnitureManager implements FurnitureManager { ); elements.add(furnitureElement); } + + // add hitboxes List> hitboxConfigs = (List>) placementArguments.getOrDefault("hitboxes", List.of()); List hitboxes = new ArrayList<>(); for (Map config : hitboxConfigs) { @@ -132,6 +137,29 @@ public class BukkitFurnitureManager implements FurnitureManager { if (hitboxes.isEmpty()) { hitboxes.add(InteractionHitBox.DEFAULT); } + + // add colliders + List> colliderConfigs = (List>) placementArguments.getOrDefault("colliders", List.of()); + List colliders = new ArrayList<>(); + for (Map config : colliderConfigs) { + if (!config.containsKey("width") && !config.containsKey("height")) { + colliders.add(new Collider( + (boolean) config.getOrDefault("can-be-hit-by-projectile", false), + MiscUtils.getVector3f(config.getOrDefault("position", "0")), + MiscUtils.getVector3f(config.getOrDefault("point-1", "0")), + MiscUtils.getVector3f(config.getOrDefault("point-2", "0")) + )); + } else { + colliders.add(new Collider( + (boolean) config.getOrDefault("can-be-hit-by-projectile", false), + MiscUtils.getVector3f(config.getOrDefault("position", "0")), + MiscUtils.getAsFloat(config.getOrDefault("width", "1")), + MiscUtils.getAsFloat(config.getOrDefault("height", "1")) + )); + } + } + + // rules Map ruleSection = MiscUtils.castToMap(placementArguments.get("rules"), true); if (ruleSection != null) { RotationRule rotationRule = Optional.ofNullable((String) ruleSection.get("rotation")) @@ -143,7 +171,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], + colliders.toArray(new Collider[0]), rotationRule, alignmentRule )); @@ -151,7 +179,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], + colliders.toArray(new Collider[0]), RotationRule.ANY, AlignmentRule.CENTER )); @@ -333,7 +361,7 @@ public class BukkitFurnitureManager implements FurnitureManager { return; } Vector3f seatPos = MiscUtils.getVector3f(vector3f); - furniture.releaseSeat(seatPos); + furniture.removeOccupiedSeat(seatPos); } protected boolean isSeatCarrierType(Entity entity) { 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 fdc49801b..129ac2182 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 @@ -61,7 +61,7 @@ public class LoadedFurniture { fakeEntityIds.add(entityId); element.addSpawnPackets(entityId, this.location.getX(), this.location.getY(), this.location.getZ(), this.location.getYaw(), packets::add); } - for (HitBox hitBox : placement.hitboxes()) { + for (HitBox hitBox : placement.hitBoxes()) { int[] ids = hitBox.acquireEntityIds(Reflections.instance$Entity$ENTITY_COUNTER::incrementAndGet); for (int entityId : ids) { fakeEntityIds.add(entityId); @@ -89,16 +89,11 @@ public class LoadedFurniture { return this.location; } - public void teleport(@NotNull Location location) { - if (location.equals(this.location)) return; - this.location = location; - } - @NotNull public Entity baseEntity() { Entity entity = baseEntity.get(); if (entity == null) { - throw new RuntimeException("Base entity not found"); + throw new RuntimeException("Base entity not found. It might be unloaded."); } return entity; } @@ -128,41 +123,27 @@ public class LoadedFurniture { this.seats.clear(); } - public void addSeatEntity(Entity entity) { - this.seats.add(entity); - } + public Optional findFirstAvailableSeat(int targetEntityId) { + HitBox hitbox = hitBoxes.get(targetEntityId); + if (hitbox == null) return Optional.empty(); - public Optional getAvailableSeat(int clickedEntityId) { - HitBox hitbox = this.hitBoxes.get(clickedEntityId); - if (hitbox == null) - return Optional.empty(); Seat[] seats = hitbox.seats(); - if (ArrayUtils.isEmpty(seats)) { - return Optional.empty(); - } - for (Seat seat : seats) { - if (!this.occupiedSeats.contains(seat.offset())) { - return Optional.of(seat); - } - } - return Optional.empty(); + if (ArrayUtils.isEmpty(seats)) return Optional.empty(); + + return Arrays.stream(seats) + .filter(s -> !occupiedSeats.contains(s.offset())) + .findFirst(); } - public Location getSeatLocation(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; - } - - public boolean releaseSeat(Vector3f seat) { + public boolean removeOccupiedSeat(Vector3f seat) { return this.occupiedSeats.remove(seat); } - public boolean occupySeat(Seat seat) { + public boolean removeOccupiedSeat(Seat seat) { + return this.removeOccupiedSeat(seat.offset()); + } + + public boolean tryOccupySeat(Seat seat) { if (this.occupiedSeats.contains(seat.offset())) { return false; } @@ -170,18 +151,22 @@ public class LoadedFurniture { return true; } + public UUID uuid() { + return this.baseEntity().getUniqueId(); + } + public int baseEntityId() { return this.baseEntityId; } @NotNull public List hitBoxEntityIds() { - return this.hitBoxEntityIds; + return Collections.unmodifiableList(this.hitBoxEntityIds); } @NotNull public List subEntityIds() { - return this.fakeEntityIds; + return Collections.unmodifiableList(this.fakeEntityIds); } @NotNull @@ -190,17 +175,17 @@ public class LoadedFurniture { } @NotNull - public Key furnitureId() { + public Key id() { return this.id; } @NotNull - public CustomFurniture furniture() { + public CustomFurniture config() { return this.furniture; } - public void mountSeat(org.bukkit.entity.Player player, Seat seat) { - Location location = this.getSeatLocation(seat); + public void spawnSeatEntityForPlayer(org.bukkit.entity.Player player, Seat seat) { + Location location = this.calculateSeatLocation(seat); Entity seatEntity = seat.limitPlayerRotation() ? EntityUtils.spawnEntity(player.getWorld(), VersionHelper.isVersionNewerThan1_20_2() ? location.subtract(0,0.9875,0) : location.subtract(0,0.990625,0), EntityType.ARMOR_STAND, entity -> { ArmorStand armorStand = (ArmorStand) entity; @@ -227,7 +212,17 @@ public class LoadedFurniture { 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.addSeatEntity(seatEntity); + this.seats.add(seatEntity); seatEntity.addPassenger(player); } + + 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; + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java index 36a5bb575..2e7fa1d6d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java @@ -587,7 +587,7 @@ public class PacketConsumers { }; private static void handlePickItemFromEntityOnMainThread(Player player, LoadedFurniture furniture) throws Exception { - Key itemId = furniture.furniture().settings().itemId(); + Key itemId = furniture.config().settings().itemId(); if (itemId == null) return; pickItem(player, itemId); } @@ -712,9 +712,9 @@ public class PacketConsumers { } if (player.isSneaking()) return; - furniture.getAvailableSeat(entityId).ifPresent(seatPos -> { - if (furniture.occupySeat(seatPos)) { - furniture.mountSeat(Objects.requireNonNull(player.getPlayer()), seatPos); + furniture.findFirstAvailableSeat(entityId).ifPresent(seatPos -> { + if (furniture.tryOccupySeat(seatPos)) { + furniture.spawnSeatEntityForPlayer(Objects.requireNonNull(player.getPlayer()), seatPos); } }); } 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 index b9db719ca..a5f4b92c8 100644 --- 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 @@ -4,30 +4,37 @@ import org.joml.Vector3f; public class Collider { private final Vector3f position; - private final double width; - private final double height; + private final Vector3f point1; + private final Vector3f point2; private final boolean canBeHitByProjectile; - public Collider(boolean canBeHitByProjectile, double height, Vector3f position, double width) { + public Collider(boolean canBeHitByProjectile, Vector3f position, Vector3f point1, Vector3f point2) { this.canBeHitByProjectile = canBeHitByProjectile; - this.height = height; this.position = position; - this.width = width; + this.point1 = point1; + this.point2 = point2; + } + + public Collider(boolean canBeHitByProjectile, Vector3f position, float width, float height) { + this.canBeHitByProjectile = canBeHitByProjectile; + this.position = position; + this.point1 = new Vector3f(position.x - width / 2, position.y, position.z - width / 2); + this.point2 = new Vector3f(position.x + width / 2, position.y + height, position.z + width / 2); } public boolean canBeHitByProjectile() { return canBeHitByProjectile; } - public double height() { - return height; - } - public Vector3f position() { return position; } - public double width() { - return width; + public Vector3f point1() { + return point1; + } + + public Vector3f point2() { + return point2; } } 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 52f2674a5..b92f2fe51 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 @@ -55,39 +55,7 @@ public class CustomFurniture { return placements.get(anchorType); } - public static class Placement { - private final FurnitureElement[] elements; - private final HitBox[] hitboxes; - private final Collider[] colliders; - private final RotationRule rotationRule; - private final AlignmentRule alignmentRule; - - public Placement(FurnitureElement[] elements, HitBox[] hitboxes, Collider[] colliders, RotationRule rotationRule, AlignmentRule alignmentRule) { - this.elements = elements; - this.hitboxes = hitboxes; - this.colliders = colliders; - this.rotationRule = rotationRule; - this.alignmentRule = alignmentRule; - } - - public HitBox[] hitboxes() { - return hitboxes; - } - - public Collider[] colliders() { - return colliders; - } - - public FurnitureElement[] elements() { - return elements; - } - - public RotationRule rotationRule() { - return rotationRule; - } - - public AlignmentRule alignmentRule() { - return alignmentRule; - } + public record Placement(FurnitureElement[] elements, HitBox[] hitBoxes, Collider[] colliders, + RotationRule rotationRule, AlignmentRule alignmentRule) { } }