From 829c4b24dd5313522d4ec51f7b9a035321f943fc Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Tue, 17 Jun 2025 01:01:16 +0800 Subject: [PATCH] =?UTF-8?q?feat(entity):=20=E5=88=9D=E6=AD=A5=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=E5=BF=AB=E4=B9=90=E6=81=B6=E9=AD=82=E7=A2=B0=E6=92=9E?= =?UTF-8?q?=E7=AE=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../furniture/hitbox/HappyGhastHitBox.java | 80 +++++++++++++++++-- .../core/world/collision/AABB.java | 12 +++ 2 files changed, 85 insertions(+), 7 deletions(-) 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/HappyGhastHitBox.java index 1aeeb4966..aeffee9f6 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/HappyGhastHitBox.java @@ -1,15 +1,21 @@ package net.momirealms.craftengine.bukkit.entity.furniture.hitbox; +import net.momirealms.craftengine.bukkit.entity.data.HappyGhastData; +import net.momirealms.craftengine.bukkit.entity.furniture.BukkitCollider; +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MAttributeHolders; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityTypes; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections; import net.momirealms.craftengine.core.entity.furniture.*; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.MiscUtils; -import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.util.*; +import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.core.world.collision.AABB; import org.joml.Quaternionf; import org.joml.Vector3f; -import java.util.Map; +import java.util.*; import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Supplier; @@ -17,10 +23,16 @@ import java.util.function.Supplier; public class HappyGhastHitBox extends AbstractHitBox { 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) { + public HappyGhastHitBox(Seat[] 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; + HappyGhastData.StaysStill.addEntityDataIfNotDefaultValue(hardCollision, this.cachedValues); + HappyGhastData.MobFlags.addEntityDataIfNotDefaultValue((byte) 0x01, this.cachedValues); // NO AI + HappyGhastData.SharedFlags.addEntityDataIfNotDefaultValue((byte) 0x20, this.cachedValues); // Invisible } @Override @@ -32,12 +44,62 @@ public class HappyGhastHitBox extends AbstractHitBox { return scale; } + public boolean hardCollision() { + return hardCollision; + } + @Override - public void initPacketsAndColliders(int[] entityId, WorldPosition position, Quaternionf conjugated, BiConsumer packets, Consumer collider, BiConsumer aabb) { + public void initPacketsAndColliders(int[] entityIds, WorldPosition position, Quaternionf conjugated, BiConsumer packets, Consumer collider, BiConsumer aabb) { + Vector3f offset = conjugated.transform(new Vector3f(position())); + try { + double x = position.x(); + double y = position.y(); + double z = position.z(); + float yaw = position.xRot(); + packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket( + entityIds[0], UUID.randomUUID(), x + offset.x, y + offset.y, z - offset.z, 0, yaw, + MEntityTypes.HAPPY_GHAST, 0, CoreReflections.instance$Vec3$Zero, 0 + ), true); + packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityIds[0], List.copyOf(this.cachedValues)), true); + if (VersionHelper.isOrAbove1_20_5() && this.scale != 1) { + Object attributeInstance = CoreReflections.constructor$AttributeInstance.newInstance(MAttributeHolders.SCALE, (Consumer) (o) -> {}); + CoreReflections.method$AttributeInstance$setBaseValue.invoke(attributeInstance, this.scale); + packets.accept(NetworkReflections.constructor$ClientboundUpdateAttributesPacket0.newInstance(entityIds[0], Collections.singletonList(attributeInstance)), false); + } + if (this.hardCollision) { + collider.accept(this.createCollider(position.world(), offset, x, y, z, entityIds[0], aabb)); + } + } catch (ReflectiveOperationException e) { + throw new RuntimeException("Failed to construct custom hitbox spawn packet", e); + } + } + + public Collider createCollider(World world, Vector3f offset, double x, double y, double z, int entityId, BiConsumer 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); + return new BukkitCollider(level, nmsAABB, x, y, z, this.canBeHitByProjectile(), true, this.blocksBuilding()); + } + + public AABB createAABB(Vector3f offset, double x, double y, double z) { + double baseSize = 4.0 * this.scale; + double halfSize = baseSize * 0.5; + double minX = x - halfSize + offset.x(); + double maxX = x + halfSize + offset.x(); + double minY = y + offset.y(); + double maxY = y + baseSize + offset.y(); + double minZ = z - halfSize + offset.z(); + double maxZ = z + halfSize + offset.z(); + return new AABB(minX, minY, minZ, maxX, maxY, maxZ); } @Override public void initShapeForPlacement(double x, double y, double z, float yaw, Quaternionf conjugated, Consumer aabbs) { + if (!this.hardCollision) return; + Vector3f offset = conjugated.transform(new Vector3f(position())); + AABB aabb = createAABB(offset, x, y, z); + aabbs.accept(aabb); } @Override @@ -49,14 +111,18 @@ public class HappyGhastHitBox extends AbstractHitBox { @Override public HitBox create(Map arguments) { + if (!VersionHelper.isOrAbove1_21_6()) { + throw new UnsupportedOperationException("HappyGhastHitBox is only supported on 1.21.6+"); + } double scale = ResourceConfigUtils.getAsDouble(arguments.getOrDefault("scale", 1), "scale"); + boolean hardCollision = (boolean) arguments.getOrDefault("hard-collision", false); boolean canUseOn = (boolean) arguments.getOrDefault("can-use-item-on", false); boolean canBeHitByProjectile = (boolean) arguments.getOrDefault("can-be-hit-by-projectile", false); boolean blocksBuilding = (boolean) arguments.getOrDefault("blocks-building", false); return new HappyGhastHitBox( HitBoxFactory.getSeats(arguments), MiscUtils.getAsVector3f(arguments.getOrDefault("position", "0"), "position"), - scale, canUseOn, blocksBuilding, canBeHitByProjectile + scale, canUseOn, blocksBuilding, canBeHitByProjectile, hardCollision ); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/collision/AABB.java b/core/src/main/java/net/momirealms/craftengine/core/world/collision/AABB.java index d0a02fd09..931692fef 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/collision/AABB.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/collision/AABB.java @@ -123,4 +123,16 @@ public class AABB { private static boolean isWithinBounds(double value, double min, double max) { return (value >= min - EPSILON) && (value <= max + EPSILON); } + + @Override + public String toString() { + return "AABB{" + + "minX=" + minX + + ", minY=" + minY + + ", minZ=" + minZ + + ", maxX=" + maxX + + ", maxY=" + maxY + + ", maxZ=" + maxZ + + '}'; + } }