From 5e6842f911a1c937975656df14a5d04ce9dac2c2 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 31 Mar 2025 12:57:39 +0800 Subject: [PATCH 01/10] =?UTF-8?q?feat(entity):=20=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E6=BD=9C=E5=BD=B1=E8=B4=9D=E7=A2=B0=E6=92=9E=E7=AE=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/entity/BaseEntityData.java | 21 +++ .../craftengine/bukkit/entity/EntityData.java | 29 ++++ .../bukkit/entity/LivingEntityData.java | 19 +++ .../craftengine/bukkit/entity/MobData.java | 10 ++ .../bukkit/entity/ShulkerData.java | 14 ++ .../bukkit/entity/SimpleEntityData.java | 29 ++++ .../entity/furniture/BukkitHitBoxTypes.java | 2 +- ...{BoatHitBox.java => HappyGhastHitBox.java} | 18 ++- .../entity/furniture/ShulkerHitBox.java | 59 ++++++-- .../bukkit/util/DirectionUtils.java | 11 ++ .../craftengine/bukkit/util/Reflections.java | 137 ++++++++++++++++++ 11 files changed, 333 insertions(+), 16 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/BaseEntityData.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/EntityData.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/LivingEntityData.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/MobData.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/ShulkerData.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/SimpleEntityData.java rename bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/{BoatHitBox.java => HappyGhastHitBox.java} (71%) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/BaseEntityData.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/BaseEntityData.java new file mode 100644 index 000000000..1f8736c4c --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/BaseEntityData.java @@ -0,0 +1,21 @@ +package net.momirealms.craftengine.bukkit.entity; + +import net.momirealms.craftengine.bukkit.util.Reflections; + +import java.util.Optional; + +public class BaseEntityData extends SimpleEntityData { + + public static final BaseEntityData SharedFlags = new BaseEntityData<>(0, EntityDataValue.Serializers$BYTE, (byte) 0); + public static final BaseEntityData AirSupply = new BaseEntityData<>(1, EntityDataValue.Serializers$INT, 300); + public static final BaseEntityData> CustomName = new BaseEntityData<>(2, EntityDataValue.Serializers$OPTIONAL_COMPONENT, Optional.empty()); + public static final BaseEntityData CustomNameVisible = new BaseEntityData<>(3, EntityDataValue.Serializers$BOOLEAN, false); + public static final BaseEntityData Silent = new BaseEntityData<>(4, EntityDataValue.Serializers$BOOLEAN, false); + public static final BaseEntityData NoGravity = new BaseEntityData<>(5, EntityDataValue.Serializers$BOOLEAN, false); + public static final BaseEntityData Pose = new BaseEntityData<>(6, EntityDataValue.Serializers$POSE, Reflections.instance$Pose$STANDING); + public static final BaseEntityData TicksFrozen = new BaseEntityData<>(7, EntityDataValue.Serializers$INT, 0); + + public BaseEntityData(int id, Object serializer, T defaultValue) { + super(id, serializer, defaultValue); + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/EntityData.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/EntityData.java new file mode 100644 index 000000000..6a35b9d71 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/EntityData.java @@ -0,0 +1,29 @@ +package net.momirealms.craftengine.bukkit.entity; + +import java.util.List; + +public interface EntityData { + + Object serializer(); + int id(); + T defaultValue(); + + default Object createEntityDataIfNotDefaultValue(T value) { + if (defaultValue().equals(value)) return null; + return EntityDataValue.create(id(), serializer(), value); + } + + default void addEntityDataIfNotDefaultValue(T value, List list) { + if (!defaultValue().equals(value)) { + list.add(EntityDataValue.create(id(), serializer(), value)); + } + } + + default void addEntityData(T value, List list) { + list.add(EntityDataValue.create(id(), serializer(), value)); + } + + static EntityData of(int id, Object serializer, T defaultValue) { + return new SimpleEntityData<>(id, serializer, defaultValue); + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/LivingEntityData.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/LivingEntityData.java new file mode 100644 index 000000000..4efe9a5f0 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/LivingEntityData.java @@ -0,0 +1,19 @@ +package net.momirealms.craftengine.bukkit.entity; + +import java.util.List; +import java.util.Optional; + +public class LivingEntityData extends BaseEntityData { + + public static final LivingEntityData LivingEntityFlags = new LivingEntityData<>(8, EntityDataValue.Serializers$BYTE, (byte) 0); + public static final LivingEntityData Health = new LivingEntityData<>(9, EntityDataValue.Serializers$FLOAT, 1.0f); + public static final LivingEntityData> EffectParticles = new LivingEntityData<>(10, EntityDataValue.Serializers$PARTICLES, List.of()); + public static final LivingEntityData EffectAmbience = new LivingEntityData<>(11, EntityDataValue.Serializers$BOOLEAN, false); + public static final LivingEntityData ArrowCount = new LivingEntityData<>(12, EntityDataValue.Serializers$INT, 0); + public static final LivingEntityData StingerCount = new LivingEntityData<>(13, EntityDataValue.Serializers$INT, 0); + public static final LivingEntityData> SleepingPos = new LivingEntityData<>(14, EntityDataValue.Serializers$OPTIONAL_BLOCK_POS, Optional.empty()); + + public LivingEntityData(int id, Object serializer, T defaultValue) { + super(id, serializer, defaultValue); + } +} \ No newline at end of file diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/MobData.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/MobData.java new file mode 100644 index 000000000..c7093e344 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/MobData.java @@ -0,0 +1,10 @@ +package net.momirealms.craftengine.bukkit.entity; + +public class MobData extends LivingEntityData { + + public static final MobData MobFlags = new MobData<>(15, EntityDataValue.Serializers$BYTE, (byte) 0); + + public MobData(int id, Object serializer, T defaultValue) { + super(id, serializer, defaultValue); + } +} \ No newline at end of file diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/ShulkerData.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/ShulkerData.java new file mode 100644 index 000000000..8353a78e3 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/ShulkerData.java @@ -0,0 +1,14 @@ +package net.momirealms.craftengine.bukkit.entity; + +import net.momirealms.craftengine.bukkit.util.Reflections; + +public class ShulkerData extends MobData { + + public static final ShulkerData AttachFace = new ShulkerData<>(16, EntityDataValue.Serializers$DIRECTION, Reflections.instance$Direction$DOWN); + public static final ShulkerData Peek = new ShulkerData<>(17, EntityDataValue.Serializers$BYTE, (byte) 0); + public static final ShulkerData Color = new ShulkerData<>(18, EntityDataValue.Serializers$BYTE, (byte) 16); + + public ShulkerData(int id, Object serializer, T defaultValue) { + super(id, serializer, defaultValue); + } +} \ No newline at end of file diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/SimpleEntityData.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/SimpleEntityData.java new file mode 100644 index 000000000..f2c079409 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/SimpleEntityData.java @@ -0,0 +1,29 @@ +package net.momirealms.craftengine.bukkit.entity; + +public class SimpleEntityData implements EntityData { + + private final int id; + private final Object serializer; + private final T defaultValue; + + public SimpleEntityData(int id, Object serializer, T defaultValue) { + this.id = id; + this.serializer = serializer; + this.defaultValue = defaultValue; + } + + @Override + public int id() { + return id; + } + + @Override + public Object serializer() { + return serializer; + } + + @Override + public T defaultValue() { + return defaultValue; + } +} 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 index aa689fa40..d089c3110 100644 --- 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 @@ -9,6 +9,6 @@ public class BukkitHitBoxTypes extends HitBoxTypes { static { register(INTERACTION, InteractionHitBox.FACTORY); register(SHULKER, ShulkerHitBox.FACTORY); - register(BOAT, BoatHitBox.FACTORY); + register(BOAT, HappyGhastHitBox.FACTORY); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BoatHitBox.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/HappyGhastHitBox.java similarity index 71% rename from bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BoatHitBox.java rename to bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/HappyGhastHitBox.java index 004ed7131..6b566d4e7 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BoatHitBox.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/HappyGhastHitBox.java @@ -9,11 +9,13 @@ import java.util.Map; import java.util.function.Consumer; import java.util.function.Supplier; -public class BoatHitBox extends AbstractHitBox { +public class HappyGhastHitBox extends AbstractHitBox { public static final Factory FACTORY = new Factory(); + private final double scale; - public BoatHitBox(Seat[] seats, Vector3f position) { + public HappyGhastHitBox(Seat[] seats, Vector3f position, double scale) { super(seats, position); + this.scale = scale; } @Override @@ -21,9 +23,13 @@ public class BoatHitBox extends AbstractHitBox { return HitBoxTypes.BOAT; } + public double scale() { + return scale; + } + @Override public void addSpawnPackets(int[] entityId, double x, double y, double z, float yaw, Consumer packets) { - // 生成无重力船 + // todo 乐魂 } @Override @@ -35,9 +41,11 @@ public class BoatHitBox extends AbstractHitBox { @Override public HitBox create(Map arguments) { - return new BoatHitBox( + double scale = MiscUtils.getAsDouble(arguments.getOrDefault("scale", "1")); + return new HappyGhastHitBox( HitBoxFactory.getSeats(arguments), - MiscUtils.getVector3f(arguments.getOrDefault("position", "0")) + MiscUtils.getVector3f(arguments.getOrDefault("position", "0")), + scale ); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/ShulkerHitBox.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/ShulkerHitBox.java index 262bc35b2..15f19dcdf 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/ShulkerHitBox.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/ShulkerHitBox.java @@ -1,14 +1,19 @@ package net.momirealms.craftengine.bukkit.entity.furniture; +import com.google.common.collect.Lists; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import net.momirealms.craftengine.bukkit.entity.BaseEntityData; +import net.momirealms.craftengine.bukkit.entity.MobData; +import net.momirealms.craftengine.bukkit.entity.ShulkerData; +import net.momirealms.craftengine.bukkit.util.DirectionUtils; +import net.momirealms.craftengine.bukkit.util.MobEffectUtils; +import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.entity.furniture.*; -import net.momirealms.craftengine.core.util.Direction; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.*; import org.joml.Vector3f; -import java.util.Locale; -import java.util.Map; -import java.util.Optional; +import java.util.*; import java.util.function.Consumer; import java.util.function.Supplier; @@ -19,6 +24,7 @@ public class ShulkerHitBox extends AbstractHitBox { private final byte peek; // todo或许还能做个方向,但是会麻烦点,和 yaw 有关 private final Direction direction; + private List cachedValues; public ShulkerHitBox(Seat[] seats, Vector3f position, double scale, byte peek, Direction direction) { super(seats, position); @@ -46,10 +52,43 @@ public class ShulkerHitBox extends AbstractHitBox { @Override public void addSpawnPackets(int[] entityIds, double x, double y, double z, float yaw, Consumer packets) { - // 1.生成假的展示实体 - // 2.生成假的潜影贝 - // 3.潜影贝骑展示实体 - // 4.潜影贝数据设置(隐身,尺寸,peek,方向) + Vector3f offset = QuaternionUtils.toQuaternionf(0f, Math.toRadians(180f - yaw), 0f).conjugate().transform(new Vector3f(position())); + try { + packets.accept(Reflections.constructor$ClientboundAddEntityPacket.newInstance( + entityIds[0], UUID.randomUUID(), x + offset.x, y + offset.y, z - offset.z, 0, yaw, + Reflections.instance$EntityType$SHULKER, 0, Reflections.instance$Vec3$Zero, 0 + )); + packets.accept(Reflections.constructor$ClientboundSetEntityDataPacket.newInstance(entityIds[0], getCachedValues())); + packets.accept(Reflections.constructor$ClientboundAddEntityPacket.newInstance( + entityIds[1], UUID.randomUUID(), x + offset.x, y + offset.y, z - offset.z, 0, yaw, + Reflections.instance$EntityType$ITEM_DISPLAY, 0, Reflections.instance$Vec3$Zero, 0 + )); + ByteBuf byteBuf = Unpooled.buffer(); + Object friendlyByteBuf = Reflections.constructor$FriendlyByteBuf.newInstance(byteBuf); + Reflections.method$FriendlyByteBuf$writeVarInt.invoke(friendlyByteBuf, entityIds[1]); + Reflections.method$FriendlyByteBuf$writeVarIntArray.invoke(friendlyByteBuf, (Object) new int[] {entityIds[0]}); + packets.accept(Reflections.constructor$ClientboundSetPassengersPacket.newInstance(friendlyByteBuf)); + if (VersionHelper.isVersionNewerThan1_20_5()) { + Object attributeInstance = Reflections.constructor$AttributeInstance.newInstance(Reflections.instance$Attributes$SCALE, (Consumer) (o) -> {}); + Reflections.method$AttributeInstance$setBaseValue.invoke(attributeInstance, scale); + packets.accept(Reflections.constructor$ClientboundUpdateAttributesPacket0.newInstance(entityIds[0], Collections.singletonList(attributeInstance))); + } + } catch (ReflectiveOperationException e) { + throw new RuntimeException("Failed to construct shulker hitbox spawn packet", e); + } + } + + private synchronized List getCachedValues() { + if (this.cachedValues == null) { + this.cachedValues = new ArrayList<>(); + ShulkerData.Peek.addEntityDataIfNotDefaultValue(peek, this.cachedValues); + ShulkerData.AttachFace.addEntityDataIfNotDefaultValue(DirectionUtils.toNMSDirection(direction), this.cachedValues); + ShulkerData.NoGravity.addEntityDataIfNotDefaultValue(true, this.cachedValues); + ShulkerData.Silent.addEntityDataIfNotDefaultValue(true, this.cachedValues); + ShulkerData.MobFlags.addEntityDataIfNotDefaultValue((byte) 0x01, this.cachedValues); // 无ai + ShulkerData.SharedFlags.addEntityDataIfNotDefaultValue((byte) 0x20, this.cachedValues); // 不可见 + } + return this.cachedValues; } @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/DirectionUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/DirectionUtils.java index 25d566d1e..1f587764e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/DirectionUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/DirectionUtils.java @@ -29,4 +29,15 @@ public class DirectionUtils { case EAST -> BlockFace.EAST; }; } + + public static Object toNMSDirection(Direction direction) { + return switch (direction) { + case UP -> Reflections.instance$Direction$UP; + case DOWN -> Reflections.instance$Direction$DOWN; + case NORTH -> Reflections.instance$Direction$NORTH; + case SOUTH -> Reflections.instance$Direction$SOUTH; + case WEST -> Reflections.instance$Direction$WEST; + case EAST -> Reflections.instance$Direction$EAST; + }; + } } 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 e6fae8b2d..0be5bcf55 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 @@ -3141,6 +3141,7 @@ public class Reflections { public static final Object instance$MobEffecr$mining_fatigue; public static final Object instance$MobEffecr$haste; + public static final Object instance$MobEffecr$invisibility; // for 1.20.1-1.20.4 static { @@ -3149,6 +3150,8 @@ public class Reflections { instance$MobEffecr$mining_fatigue = method$Registry$get.invoke(instance$BuiltInRegistries$MOB_EFFECT, mining_fatigue); Object haste = method$ResourceLocation$fromNamespaceAndPath.invoke(null, "minecraft", "haste"); instance$MobEffecr$haste = method$Registry$get.invoke(instance$BuiltInRegistries$MOB_EFFECT, haste); + Object invisibility = method$ResourceLocation$fromNamespaceAndPath.invoke(null, "minecraft", "invisibility"); + instance$MobEffecr$invisibility = method$Registry$get.invoke(instance$BuiltInRegistries$MOB_EFFECT, invisibility); } catch (ReflectiveOperationException e) { throw new RuntimeException(e); } @@ -3665,6 +3668,7 @@ public class Reflections { public static final Object instance$EntityType$ITEM_DISPLAY; public static final Object instance$EntityType$FALLING_BLOCK; public static final Object instance$EntityType$INTERACTION; + public static final Object instance$EntityType$SHULKER; static { try { @@ -3676,6 +3680,8 @@ public class Reflections { instance$EntityType$FALLING_BLOCK = Reflections.method$Registry$get.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, fallingBlock); Object interaction = method$ResourceLocation$fromNamespaceAndPath.invoke(null, "minecraft", "interaction"); instance$EntityType$INTERACTION = Reflections.method$Registry$get.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, interaction); + Object shulker = method$ResourceLocation$fromNamespaceAndPath.invoke(null, "minecraft", "shulker"); + instance$EntityType$SHULKER = Reflections.method$Registry$get.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, shulker); } catch (ReflectiveOperationException e) { throw new RuntimeException(e); } @@ -5782,4 +5788,135 @@ public class Reflections { clazz$CraftShulker, clazz$Shulker, 0 ) ); + + public static final Class clazz$Pose = requireNonNull( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("world.entity.Pose"), + BukkitReflectionUtils.assembleMCClass("world.entity.EntityPose") + ) + ); + + public static final Method method$Pose$values = requireNonNull( + ReflectionUtils.getStaticMethod( + clazz$Pose, clazz$Pose.arrayType() + ) + ); + + public static final Object instance$Pose$STANDING; + public static final Object instance$Pose$FALL_FLYING; + public static final Object instance$Pose$SLEEPING; + public static final Object instance$Pose$SWIMMING; + public static final Object instance$Pose$SPIN_ATTACK; + public static final Object instance$Pose$CROUCHING; + public static final Object instance$Pose$LONG_JUMPING; + public static final Object instance$Pose$DYING; + public static final Object instance$Pose$CROAKING; + public static final Object instance$Pose$USING_TONGUE; + public static final Object instance$Pose$SITTING; + public static final Object instance$Pose$ROARING; + public static final Object instance$Pose$SNIFFING; + public static final Object instance$Pose$EMERGING; + public static final Object instance$Pose$DIGGING; + public static final Object instance$Pose$SLIDING; + public static final Object instance$Pose$SHOOTING; + public static final Object instance$Pose$INHALING; + public static final Object[] instance$Poses; + + static { + try { + instance$Poses = (Object[]) method$Pose$values.invoke(null); + instance$Pose$STANDING = instance$Poses[0]; + instance$Pose$FALL_FLYING = instance$Poses[1]; + instance$Pose$SLEEPING = instance$Poses[2]; + instance$Pose$SWIMMING = instance$Poses[3]; + instance$Pose$SPIN_ATTACK = instance$Poses[4]; + instance$Pose$CROUCHING = instance$Poses[5]; + instance$Pose$LONG_JUMPING = instance$Poses[6]; + instance$Pose$DYING = instance$Poses[7]; + instance$Pose$CROAKING = instance$Poses[8]; + instance$Pose$USING_TONGUE = instance$Poses[9]; + instance$Pose$SITTING = instance$Poses[10]; + instance$Pose$ROARING = instance$Poses[11]; + instance$Pose$SNIFFING = instance$Poses[12]; + instance$Pose$EMERGING = instance$Poses[13]; + instance$Pose$DIGGING = instance$Poses[14]; + if (VersionHelper.isVersionNewerThan1_20_3()) { + instance$Pose$SLIDING = instance$Poses[15]; + instance$Pose$SHOOTING = instance$Poses[16]; + instance$Pose$INHALING = instance$Poses[17]; + } else { + instance$Pose$SLIDING = null; + instance$Pose$SHOOTING = null; + instance$Pose$INHALING = null; + } + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + public static final Method method$AttributeInstance$getModifier = requireNonNull( + ReflectionUtils.getMethod( + clazz$AttributeInstance, clazz$AttributeModifier, clazz$ResourceLocation + ) + ); + + public static final Class clazz$Attributes = requireNonNull( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("world.entity.ai.attributes.Attributes"), + BukkitReflectionUtils.assembleMCClass("world.entity.ai.attributes.GenericAttributes") + ) + ); + + // 1.20.5+ + public static final Field field$Attributes$SCALE = + ReflectionUtils.getDeclaredField( + clazz$Attributes, "SCALE" + ); + + // 1.20.5+ + public static final Object instance$Attributes$SCALE = Optional.ofNullable(field$Attributes$SCALE) + .map(it -> { + try { + return it.get(null); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + }) + .orElse(null); + + public static final Constructor constructor$AttributeInstance = requireNonNull( + ReflectionUtils.getConstructor( + clazz$AttributeInstance, clazz$Holder, Consumer.class + ) + ); + + public static final Method method$AttributeInstance$setBaseValue = requireNonNull( + ReflectionUtils.getMethod( + clazz$AttributeInstance, void.class, double.class + ) + ); + + public static final Constructor constructor$MobEffectInstance = requireNonNull( + ReflectionUtils.getConstructor( + clazz$MobEffectInstance, clazz$Holder, int.class, int.class, boolean.class, boolean.class, boolean.class + ) + ); + + public static final Constructor constructor$ClientboundSetPassengersPacket = requireNonNull( + ReflectionUtils.getDeclaredConstructor( + clazz$ClientboundSetPassengersPacket, clazz$FriendlyByteBuf + ) + ); + + public static final Method method$FriendlyByteBuf$writeVarInt = requireNonNull( + ReflectionUtils.getMethod( + clazz$FriendlyByteBuf, clazz$FriendlyByteBuf, new String[]{"writeVarInt", "d", "c"}, int.class + ) + ); + + public static final Method method$FriendlyByteBuf$writeVarIntArray = requireNonNull( + ReflectionUtils.getMethod( + clazz$FriendlyByteBuf, clazz$FriendlyByteBuf, int[].class + ) + ); } From 6365c8e275d5590f863deeab27f6e89c647d57f1 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 31 Mar 2025 13:10:30 +0800 Subject: [PATCH 02/10] =?UTF-8?q?feat(entity):=20=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E6=BD=9C=E5=BD=B1=E8=B4=9D=E7=A2=B0=E6=92=9E=E7=AE=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entity/furniture/ShulkerHitBox.java | 24 +++++++------------ 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/ShulkerHitBox.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/ShulkerHitBox.java index 15f19dcdf..b2266a5c3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/ShulkerHitBox.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/ShulkerHitBox.java @@ -1,13 +1,8 @@ package net.momirealms.craftengine.bukkit.entity.furniture; -import com.google.common.collect.Lists; -import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; -import net.momirealms.craftengine.bukkit.entity.BaseEntityData; -import net.momirealms.craftengine.bukkit.entity.MobData; import net.momirealms.craftengine.bukkit.entity.ShulkerData; import net.momirealms.craftengine.bukkit.util.DirectionUtils; -import net.momirealms.craftengine.bukkit.util.MobEffectUtils; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.entity.furniture.*; import net.momirealms.craftengine.core.util.*; @@ -56,22 +51,21 @@ public class ShulkerHitBox extends AbstractHitBox { try { packets.accept(Reflections.constructor$ClientboundAddEntityPacket.newInstance( entityIds[0], UUID.randomUUID(), x + offset.x, y + offset.y, z - offset.z, 0, yaw, - Reflections.instance$EntityType$SHULKER, 0, Reflections.instance$Vec3$Zero, 0 - )); - packets.accept(Reflections.constructor$ClientboundSetEntityDataPacket.newInstance(entityIds[0], getCachedValues())); - packets.accept(Reflections.constructor$ClientboundAddEntityPacket.newInstance( - entityIds[1], UUID.randomUUID(), x + offset.x, y + offset.y, z - offset.z, 0, yaw, Reflections.instance$EntityType$ITEM_DISPLAY, 0, Reflections.instance$Vec3$Zero, 0 )); - ByteBuf byteBuf = Unpooled.buffer(); - Object friendlyByteBuf = Reflections.constructor$FriendlyByteBuf.newInstance(byteBuf); - Reflections.method$FriendlyByteBuf$writeVarInt.invoke(friendlyByteBuf, entityIds[1]); - Reflections.method$FriendlyByteBuf$writeVarIntArray.invoke(friendlyByteBuf, (Object) new int[] {entityIds[0]}); + packets.accept(Reflections.constructor$ClientboundAddEntityPacket.newInstance( + entityIds[1], UUID.randomUUID(), x + offset.x, y + offset.y, z - offset.z, 0, yaw, + Reflections.instance$EntityType$SHULKER, 0, Reflections.instance$Vec3$Zero, 0 + )); + packets.accept(Reflections.constructor$ClientboundSetEntityDataPacket.newInstance(entityIds[1], getCachedValues())); + Object friendlyByteBuf = Reflections.constructor$FriendlyByteBuf.newInstance(Unpooled.buffer()); + Reflections.method$FriendlyByteBuf$writeVarInt.invoke(friendlyByteBuf, entityIds[0]); + Reflections.method$FriendlyByteBuf$writeVarIntArray.invoke(friendlyByteBuf, (Object) new int[] {entityIds[1]}); packets.accept(Reflections.constructor$ClientboundSetPassengersPacket.newInstance(friendlyByteBuf)); if (VersionHelper.isVersionNewerThan1_20_5()) { Object attributeInstance = Reflections.constructor$AttributeInstance.newInstance(Reflections.instance$Attributes$SCALE, (Consumer) (o) -> {}); Reflections.method$AttributeInstance$setBaseValue.invoke(attributeInstance, scale); - packets.accept(Reflections.constructor$ClientboundUpdateAttributesPacket0.newInstance(entityIds[0], Collections.singletonList(attributeInstance))); + packets.accept(Reflections.constructor$ClientboundUpdateAttributesPacket0.newInstance(entityIds[1], Collections.singletonList(attributeInstance))); } } catch (ReflectiveOperationException e) { throw new RuntimeException("Failed to construct shulker hitbox spawn packet", e); From 0804b17073a14b07496b6d825532d90560bfa7fd Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 31 Mar 2025 16:22:29 +0800 Subject: [PATCH 03/10] =?UTF-8?q?fix(bukkit):=20=E4=BF=AE=E5=A4=8D1.20~1.2?= =?UTF-8?q?0.4=E5=90=AF=E5=8A=A8=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/bukkit/util/Reflections.java | 21 +++++-------------- 1 file changed, 5 insertions(+), 16 deletions(-) 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 0be5bcf55..59fda7a65 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 @@ -5779,7 +5779,8 @@ public class Reflections { public static final Class clazz$Shulker = requireNonNull( ReflectionUtils.getClazz( - BukkitReflectionUtils.assembleMCClass("world.entity.monster.Shulker") + BukkitReflectionUtils.assembleMCClass("world.entity.monster.Shulker"), + BukkitReflectionUtils.assembleMCClass("world.entity.monster.EntityShulker") ) ); @@ -5854,12 +5855,6 @@ public class Reflections { } } - public static final Method method$AttributeInstance$getModifier = requireNonNull( - ReflectionUtils.getMethod( - clazz$AttributeInstance, clazz$AttributeModifier, clazz$ResourceLocation - ) - ); - public static final Class clazz$Attributes = requireNonNull( ReflectionUtils.getClazz( BukkitReflectionUtils.assembleMCClass("world.entity.ai.attributes.Attributes"), @@ -5884,11 +5879,11 @@ public class Reflections { }) .orElse(null); - public static final Constructor constructor$AttributeInstance = requireNonNull( + // 1.20.5+ + public static final Constructor constructor$AttributeInstance = ReflectionUtils.getConstructor( clazz$AttributeInstance, clazz$Holder, Consumer.class - ) - ); + ); public static final Method method$AttributeInstance$setBaseValue = requireNonNull( ReflectionUtils.getMethod( @@ -5896,12 +5891,6 @@ public class Reflections { ) ); - public static final Constructor constructor$MobEffectInstance = requireNonNull( - ReflectionUtils.getConstructor( - clazz$MobEffectInstance, clazz$Holder, int.class, int.class, boolean.class, boolean.class, boolean.class - ) - ); - public static final Constructor constructor$ClientboundSetPassengersPacket = requireNonNull( ReflectionUtils.getDeclaredConstructor( clazz$ClientboundSetPassengersPacket, clazz$FriendlyByteBuf From ab3b4db541aba327fc8c83be06c55522bde11335 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 31 Mar 2025 17:16:40 +0800 Subject: [PATCH 04/10] =?UTF-8?q?refactor(bukkit):=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E5=B1=9E=E6=80=A7=E7=9B=B8=E5=85=B3=E5=8F=8D=E5=B0=84=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entity/furniture/ShulkerHitBox.java | 2 +- .../craftengine/bukkit/util/Reflections.java | 24 ++++++------------- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/ShulkerHitBox.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/ShulkerHitBox.java index b2266a5c3..37261b4ea 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/ShulkerHitBox.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/ShulkerHitBox.java @@ -63,7 +63,7 @@ public class ShulkerHitBox extends AbstractHitBox { Reflections.method$FriendlyByteBuf$writeVarIntArray.invoke(friendlyByteBuf, (Object) new int[] {entityIds[1]}); packets.accept(Reflections.constructor$ClientboundSetPassengersPacket.newInstance(friendlyByteBuf)); if (VersionHelper.isVersionNewerThan1_20_5()) { - Object attributeInstance = Reflections.constructor$AttributeInstance.newInstance(Reflections.instance$Attributes$SCALE, (Consumer) (o) -> {}); + Object attributeInstance = Reflections.constructor$AttributeInstance.newInstance(Reflections.instance$Holder$Attribute$scale, (Consumer) (o) -> {}); Reflections.method$AttributeInstance$setBaseValue.invoke(attributeInstance, scale); packets.accept(Reflections.constructor$ClientboundUpdateAttributesPacket0.newInstance(entityIds[1], Collections.singletonList(attributeInstance))); } 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 59fda7a65..f86339c9a 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 @@ -2808,6 +2808,7 @@ public class Reflections { public static final Object instance$Holder$Attribute$block_break_speed; public static final Object instance$Holder$Attribute$block_interaction_range; + public static final Object instance$Holder$Attribute$scale; static { try { @@ -2821,9 +2822,15 @@ public class Reflections { @SuppressWarnings("unchecked") Optional blockInteractionRangeHolder = (Optional) method$Registry$getHolder0.invoke(instance$BuiltInRegistries$ATTRIBUTE, block_interaction_range); instance$Holder$Attribute$block_interaction_range = blockInteractionRangeHolder.orElse(null); + + Object scale = method$ResourceLocation$fromNamespaceAndPath.invoke(null, "minecraft", VersionHelper.isVersionNewerThan1_21_2() ? "scale" : "generic.scale"); + @SuppressWarnings("unchecked") + Optional scaleHolder = (Optional) method$Registry$getHolder0.invoke(instance$BuiltInRegistries$ATTRIBUTE, scale); + instance$Holder$Attribute$scale = scaleHolder.orElse(null); } else { instance$Holder$Attribute$block_break_speed = null; instance$Holder$Attribute$block_interaction_range = null; + instance$Holder$Attribute$scale = null; } } catch (ReflectiveOperationException e) { throw new RuntimeException(e); @@ -5862,23 +5869,6 @@ public class Reflections { ) ); - // 1.20.5+ - public static final Field field$Attributes$SCALE = - ReflectionUtils.getDeclaredField( - clazz$Attributes, "SCALE" - ); - - // 1.20.5+ - public static final Object instance$Attributes$SCALE = Optional.ofNullable(field$Attributes$SCALE) - .map(it -> { - try { - return it.get(null); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - }) - .orElse(null); - // 1.20.5+ public static final Constructor constructor$AttributeInstance = ReflectionUtils.getConstructor( From bf54dad0a48c17181bc2d8ee2ff65685e71991c6 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 31 Mar 2025 18:14:49 +0800 Subject: [PATCH 05/10] =?UTF-8?q?feat(furniture):=20=E7=A7=BB=E9=99=A4?= =?UTF-8?q?=E7=A2=B0=E6=92=9E=E7=AE=B1=E5=AE=9E=E4=BD=93=E7=BA=B9=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bukkit/loader/src/main/resources/config.yml | 3 + .../textures/entity/shulker/shulker.png | Bin 0 -> 1493 bytes .../core/pack/AbstractPackManager.java | 103 ++++++++++++++++++ .../core/plugin/config/ConfigManager.java | 12 ++ 4 files changed, 118 insertions(+) create mode 100644 bukkit/loader/src/main/resources/internal/textures/entity/shulker/shulker.png diff --git a/bukkit/loader/src/main/resources/config.yml b/bukkit/loader/src/main/resources/config.yml index 5624e7bd8..7dc8f070f 100644 --- a/bukkit/loader/src/main/resources/config.yml +++ b/bukkit/loader/src/main/resources/config.yml @@ -140,6 +140,9 @@ furniture: - "xxx:invalid_furniture" # Whether to hide the entity containing metadata hide-base-entity: true + # Removed collision box entity texture + removed-collision-box-entity-texture-1_20_2: true + removed-collision-box-entity-texture-1_20: false image: # Prevent players from using images set in minecraft:default font diff --git a/bukkit/loader/src/main/resources/internal/textures/entity/shulker/shulker.png b/bukkit/loader/src/main/resources/internal/textures/entity/shulker/shulker.png new file mode 100644 index 0000000000000000000000000000000000000000..b6c9cade65e26d91b8960d68a50230ea2405b91c GIT binary patch literal 1493 zcmbu9{WsGK7{I^Gdt9!rbiB5_oNMVtb>+4Y5v#@WI*iTGPR0ylM)kF**=;sSzD2(3 zj@!Bww`k->yJ%AyP9v6dMG6tJS}5-B{TJ?Y&hvbp=cng<&U4Pg#RUbJ7+Dzs0APX% z^b65&|G#N~(A26X_KXHvnIQqbKwXc`lxBE}!-o0uNqkMawzl?m{`Tuhkz$}i)=}Id zW;N8O-x5)U*+L;hD9jMTnJ}CI!|5~_Ea7-Xb z5(p9n{6xMWLBLPo^W*uN6})&JkHq7}@wg-|C!WJ4aycXphsfc?aX17HCx!zOKz1}6 zi~-qEY%m%Gqd*W3f{`E?0Wu?*%y1?%jL8gPGI2~gj!qAz(}U==U>Y4ur(tQd!!+6< z+P^~myL2`1V}t~S{^z98`acnnz+(V_4h7@q6NW!C8!=lhbT_UAhn@G|k?Y(&@GRBZ zRUw~uyN9_HHKYbbac_C1t}{_ubBmuHEIW)pa7m?caAEQJcWYRjUoURf*8- zde)%r@%Mql<&9MCt(#()c_Y)Bl!S44mSco0PCbSwi{^Tihlub7J~E}|l+MVcnzAQ< zQkRb8-#fGNCDuh!vXz2xKq_OK0!s;?iN!g9+xlm9(i!zBU znFya2wi2M5q}boI-t@(sF~MhV8#BESvz2Xk!O5rZaqNWk^@*;%94MMTIphkQL(I@-D)-SaIl z9$}vNUeY*YY$K61X5sNax73ev#TR>*7n=KZ#=;u(mG0fr05W!d(=hL=bAg`BvD@8V ztmL?Myzn5)w0lvN*hl@WJcsLV=2=gdE}Q^5{2c#kNeUaNygdOVL9 zt=d=f(dwy`(Q(DQ*t~0N3sYa@Wb%tsPBhbRJ5=8o>cN&dZ9+)BVa>WWA7S#AUhe^i-A?@F`bvK+mI|!O>5t-p+g2Of{HkvNJ}L z^-kJL^3SCM8T$Djt9mUx_+X*gS{S{+vMJZvMG z@)j|vIF$QnWgDPFdf@XGO_nh3Uy<3^<+}IIsY6-!=L zSu-%d6qp$w&)r-zHfcO>*1&x%NpnNHz5+fQ9xU>;@EIRuq*XAc8vN@nJ#?HPdYBe= z--$L_SZsNce%3(SQ2!`^>^)kQ)p^nCllMXYfLVt|6V#r_6ID(xy*AdGiau}1n6wb} z<=*gZ~e_$^Ph7X%2Odm^(AXMqeQ&n W$6`k3g9ObB12FzUes#X2)BgZLH}CTR literal 0 HcmV?d00001 diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java index f0193f44b..0dc67af88 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java @@ -27,6 +27,9 @@ import org.jetbrains.annotations.NotNull; import org.yaml.snakeyaml.LoaderOptions; import org.yaml.snakeyaml.Yaml; +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; import java.io.*; import java.lang.reflect.Constructor; import java.lang.reflect.Method; @@ -36,6 +39,7 @@ import java.nio.file.attribute.BasicFileAttributes; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.*; +import java.util.List; import java.util.concurrent.TimeUnit; import java.util.function.BiConsumer; import java.util.function.Consumer; @@ -50,6 +54,7 @@ public abstract class AbstractPackManager implements PackManager { public static final Set VANILLA_ITEM_TEXTURES = new HashSet<>(); public static final Set VANILLA_BLOCK_TEXTURES = new HashSet<>(); public static final Set VANILLA_FONT_TEXTURES = new HashSet<>(); + public static final List SHULKER_PNG = new ArrayList<>(1); private final CraftEngine plugin; private final BiConsumer eventDispatcher; @@ -85,6 +90,8 @@ public abstract class AbstractPackManager implements PackManager { loadInternalList("internal/textures/block/_list.json", VANILLA_BLOCK_TEXTURES::add); loadInternalList("internal/textures/item/_list.json", VANILLA_ITEM_TEXTURES::add); loadInternalList("internal/textures/font/_list.json", VANILLA_FONT_TEXTURES::add); + + loadInternalPng("internal/textures/entity/shulker/shulker.png", SHULKER_PNG::add); } private void loadInternalData(String path, BiConsumer callback) { @@ -118,6 +125,16 @@ public abstract class AbstractPackManager implements PackManager { } } + private void loadInternalPng(String path, Consumer callback) { + try (InputStream inputStream = this.plugin.resourceStream(path)) { + if (inputStream != null) { + callback.accept(inputStream.readAllBytes()); + } + } catch (IOException e) { + this.plugin.logger().warn("Failed to load " + path, e); + } + } + @Override public Path resourcePackPath() { return this.plugin.dataFolderPath() @@ -482,6 +499,7 @@ public abstract class AbstractPackManager implements PackManager { this.generateCustomSounds(generatedPackPath); this.generateClientLang(generatedPackPath); this.generateEquipments(generatedPackPath); + this.generateShulker(generatedPackPath); Path zipFile = resourcePackPath(); try { @@ -512,6 +530,91 @@ public abstract class AbstractPackManager implements PackManager { } } + private void generateShulker(Path generatedPackPath) { + try { + if (ConfigManager.removedCollisionBoxEntityTextureLegacy()) { + File shulkerFile = generatedPackPath.resolve("assets/minecraft/textures/entity/shulker/shulker.png").toFile(); + File parentDir = shulkerFile.getParentFile(); + if (!parentDir.exists()) { + if (parentDir.mkdirs()) { + if (!shulkerFile.exists()) { + try (OutputStream out = new FileOutputStream(shulkerFile)) { + out.write(SHULKER_PNG.get(0)); + } + } else { + this.modifyShulker(shulkerFile, shulkerFile); + } + } else { + this.plugin.logger().warn("Failed to create parent directories for: " + shulkerFile.getAbsolutePath()); + } + } + } + if (ConfigManager.removedCollisionBoxEntityTexture()) { + File shulkerFile = generatedPackPath.resolve("assets/minecraft/textures/entity/shulker/shulker.png").toFile(); + File packMetaFile = generatedPackPath.resolve("pack.mcmeta").toFile(); + File overlaysFile = generatedPackPath.resolve("1_20_2_ce/assets/minecraft/textures/entity/shulker/shulker.png").toFile(); + boolean modifyPackMetaFile = false; + if (!shulkerFile.exists() && packMetaFile.exists()) { + File parentDir = overlaysFile.getParentFile(); + if (parentDir.mkdirs()) { + try (OutputStream out = new FileOutputStream(overlaysFile)) { + out.write(SHULKER_PNG.get(0)); + } + modifyPackMetaFile = true; + } else { + this.plugin.logger().warn("Failed to create parent directories for: " + overlaysFile.getAbsolutePath()); + } + } else if (packMetaFile.exists()) { + this.modifyShulker(shulkerFile, overlaysFile); + modifyPackMetaFile = true; + } + if (modifyPackMetaFile) { + JsonObject packMcmeta = GsonHelper.readJsonFile(packMetaFile.toPath()).getAsJsonObject(); + JsonArray entries = packMcmeta.getAsJsonObject("overlays").getAsJsonArray("entries"); + JsonObject entrie = new JsonObject(); + JsonObject formats = new JsonObject(); + formats.addProperty("min_inclusive", 16); + formats.addProperty("max_inclusive", 34); + entrie.add("formats", formats); + entrie.addProperty("directory", "1_20_2_ce"); + entries.add(entrie); + GsonHelper.writeJsonFile(packMcmeta, packMetaFile.toPath()); + } + } + } catch (IOException e) { + this.plugin.logger().warn("Error creating shulker.png", e); + } + } + + private void modifyShulker(File shulkerFile, File saveFile) throws IOException { + BufferedImage originalImage = ImageIO.read(shulkerFile); + BufferedImage argbImage; + if (originalImage.getType() == BufferedImage.TYPE_INT_ARGB) { + argbImage = originalImage; + } else { + argbImage = new BufferedImage( + originalImage.getWidth(), + originalImage.getHeight(), + BufferedImage.TYPE_INT_ARGB + ); + Graphics2D g = argbImage.createGraphics(); + g.drawImage(originalImage, 0, 0, null); + g.dispose(); + } + int startX = 0; + int startY = argbImage.getHeight() - 12; + int width = 24; + int heightRegion = 12; + for (int y = startY; y < startY + heightRegion; y++) { + for (int x = startX; x < startX + width; x++) { + int pixel = argbImage.getRGB(x, y); + int transparentPixel = pixel & 0x00FFFFFF; + argbImage.setRGB(x, y, transparentPixel); + } + } + ImageIO.write(argbImage, "PNG", saveFile); + } + private void generateEquipments(Path generatedPackPath) { for (EquipmentGeneration generator : this.plugin.itemManager().equipmentsToGenerate()) { EquipmentData equipmentData = generator.modernData(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigManager.java index 46586334c..6cf57a455 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigManager.java @@ -104,6 +104,8 @@ public class ConfigManager implements Reloadable { protected boolean furniture$remove_invalid_furniture_on_chunk_load$enable; protected Set furniture$remove_invalid_furniture_on_chunk_load$list; protected boolean furniture$hide_base_entity; + protected boolean furniture$removed_collision_box_entity_texture_1_20_2; + protected boolean furniture$removed_collision_box_entity_texture_1_20; protected boolean block$sound_system$enable; protected boolean recipe$enable; @@ -260,6 +262,8 @@ public class ConfigManager implements Reloadable { furniture$remove_invalid_furniture_on_chunk_load$enable = config.getBoolean("furniture.remove-invalid-furniture-on-chunk-load.enable", false); furniture$remove_invalid_furniture_on_chunk_load$list = new HashSet<>(config.getStringList("furniture.remove-invalid-furniture-on-chunk-load.list")); furniture$hide_base_entity = config.getBoolean("furniture.hide-base-entity", true); + furniture$removed_collision_box_entity_texture_1_20_2 = config.getBoolean("furniture.removed-collision-box-entity-texture-1_20_2", true); + furniture$removed_collision_box_entity_texture_1_20 = config.getBoolean("furniture.removed-collision-box-entity-texture-1_20", false); // block block$sound_system$enable = config.getBoolean("block.sound-system.enable", true); @@ -553,6 +557,14 @@ public class ConfigManager implements Reloadable { return instance().furniture$hide_base_entity; } + public static boolean removedCollisionBoxEntityTexture() { + return instance().furniture$removed_collision_box_entity_texture_1_20_2; + } + + public static boolean removedCollisionBoxEntityTextureLegacy() { + return instance().furniture$removed_collision_box_entity_texture_1_20; + } + public YamlDocument loadOrCreateYamlData(String fileName) { File file = new File(this.plugin.dataFolderFile(), fileName); if (!file.exists()) { From 2587fcd0550965e3982748e2242e2849c05f9983 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 31 Mar 2025 18:22:20 +0800 Subject: [PATCH 06/10] =?UTF-8?q?feat(furniture):=20=E7=A7=BB=E9=99=A4?= =?UTF-8?q?=E7=A2=B0=E6=92=9E=E7=AE=B1=E5=AE=9E=E4=BD=93=E7=BA=B9=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/pack/AbstractPackManager.java | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java index 0dc67af88..d3e66c8ab 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java @@ -550,35 +550,35 @@ public abstract class AbstractPackManager implements PackManager { } } if (ConfigManager.removedCollisionBoxEntityTexture()) { - File shulkerFile = generatedPackPath.resolve("assets/minecraft/textures/entity/shulker/shulker.png").toFile(); - File packMetaFile = generatedPackPath.resolve("pack.mcmeta").toFile(); File overlaysFile = generatedPackPath.resolve("1_20_2_ce/assets/minecraft/textures/entity/shulker/shulker.png").toFile(); - boolean modifyPackMetaFile = false; - if (!shulkerFile.exists() && packMetaFile.exists()) { - File parentDir = overlaysFile.getParentFile(); - if (parentDir.mkdirs()) { + File parentDir = overlaysFile.getParentFile(); + if (parentDir.mkdirs()) { + File shulkerFile = generatedPackPath.resolve("assets/minecraft/textures/entity/shulker/shulker.png").toFile(); + File packMetaFile = generatedPackPath.resolve("pack.mcmeta").toFile(); + boolean modifyPackMetaFile = false; + if (!shulkerFile.exists() && packMetaFile.exists()) { try (OutputStream out = new FileOutputStream(overlaysFile)) { out.write(SHULKER_PNG.get(0)); } modifyPackMetaFile = true; - } else { - this.plugin.logger().warn("Failed to create parent directories for: " + overlaysFile.getAbsolutePath()); + } else if (packMetaFile.exists()) { + this.modifyShulker(shulkerFile, overlaysFile); + modifyPackMetaFile = true; } - } else if (packMetaFile.exists()) { - this.modifyShulker(shulkerFile, overlaysFile); - modifyPackMetaFile = true; - } - if (modifyPackMetaFile) { - JsonObject packMcmeta = GsonHelper.readJsonFile(packMetaFile.toPath()).getAsJsonObject(); - JsonArray entries = packMcmeta.getAsJsonObject("overlays").getAsJsonArray("entries"); - JsonObject entrie = new JsonObject(); - JsonObject formats = new JsonObject(); - formats.addProperty("min_inclusive", 16); - formats.addProperty("max_inclusive", 34); - entrie.add("formats", formats); - entrie.addProperty("directory", "1_20_2_ce"); - entries.add(entrie); - GsonHelper.writeJsonFile(packMcmeta, packMetaFile.toPath()); + if (modifyPackMetaFile) { + JsonObject packMcmeta = GsonHelper.readJsonFile(packMetaFile.toPath()).getAsJsonObject(); + JsonArray entries = packMcmeta.getAsJsonObject("overlays").getAsJsonArray("entries"); + JsonObject entrie = new JsonObject(); + JsonObject formats = new JsonObject(); + formats.addProperty("min_inclusive", 16); + formats.addProperty("max_inclusive", 34); + entrie.add("formats", formats); + entrie.addProperty("directory", "1_20_2_ce"); + entries.add(entrie); + GsonHelper.writeJsonFile(packMcmeta, packMetaFile.toPath()); + } + } else { + this.plugin.logger().warn("Failed to create parent directories for: " + overlaysFile.getAbsolutePath()); } } } catch (IOException e) { From 8033fb1ca655e86c7b43fb6ca9830819158bec40 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 31 Mar 2025 18:36:02 +0800 Subject: [PATCH 07/10] =?UTF-8?q?feat(furniture):=20=E7=A7=BB=E9=99=A4?= =?UTF-8?q?=E7=A2=B0=E6=92=9E=E7=AE=B1=E5=AE=9E=E4=BD=93=E7=BA=B9=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/pack/AbstractPackManager.java | 68 ++++++++----------- 1 file changed, 29 insertions(+), 39 deletions(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java index d3e66c8ab..c6394fc05 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java @@ -534,51 +534,41 @@ public abstract class AbstractPackManager implements PackManager { try { if (ConfigManager.removedCollisionBoxEntityTextureLegacy()) { File shulkerFile = generatedPackPath.resolve("assets/minecraft/textures/entity/shulker/shulker.png").toFile(); - File parentDir = shulkerFile.getParentFile(); - if (!parentDir.exists()) { - if (parentDir.mkdirs()) { - if (!shulkerFile.exists()) { - try (OutputStream out = new FileOutputStream(shulkerFile)) { - out.write(SHULKER_PNG.get(0)); - } - } else { - this.modifyShulker(shulkerFile, shulkerFile); - } - } else { - this.plugin.logger().warn("Failed to create parent directories for: " + shulkerFile.getAbsolutePath()); + shulkerFile.getParentFile().mkdirs(); + if (!shulkerFile.exists()) { + try (OutputStream out = new FileOutputStream(shulkerFile)) { + out.write(SHULKER_PNG.get(0)); } + } else { + this.modifyShulker(shulkerFile, shulkerFile); } } if (ConfigManager.removedCollisionBoxEntityTexture()) { File overlaysFile = generatedPackPath.resolve("1_20_2_ce/assets/minecraft/textures/entity/shulker/shulker.png").toFile(); - File parentDir = overlaysFile.getParentFile(); - if (parentDir.mkdirs()) { - File shulkerFile = generatedPackPath.resolve("assets/minecraft/textures/entity/shulker/shulker.png").toFile(); - File packMetaFile = generatedPackPath.resolve("pack.mcmeta").toFile(); - boolean modifyPackMetaFile = false; - if (!shulkerFile.exists() && packMetaFile.exists()) { - try (OutputStream out = new FileOutputStream(overlaysFile)) { - out.write(SHULKER_PNG.get(0)); - } - modifyPackMetaFile = true; - } else if (packMetaFile.exists()) { - this.modifyShulker(shulkerFile, overlaysFile); - modifyPackMetaFile = true; + overlaysFile.getParentFile().mkdirs(); + File shulkerFile = generatedPackPath.resolve("assets/minecraft/textures/entity/shulker/shulker.png").toFile(); + File packMetaFile = generatedPackPath.resolve("pack.mcmeta").toFile(); + boolean modifyPackMetaFile = false; + if (!shulkerFile.exists() && packMetaFile.exists()) { + try (OutputStream out = new FileOutputStream(overlaysFile)) { + out.write(SHULKER_PNG.get(0)); } - if (modifyPackMetaFile) { - JsonObject packMcmeta = GsonHelper.readJsonFile(packMetaFile.toPath()).getAsJsonObject(); - JsonArray entries = packMcmeta.getAsJsonObject("overlays").getAsJsonArray("entries"); - JsonObject entrie = new JsonObject(); - JsonObject formats = new JsonObject(); - formats.addProperty("min_inclusive", 16); - formats.addProperty("max_inclusive", 34); - entrie.add("formats", formats); - entrie.addProperty("directory", "1_20_2_ce"); - entries.add(entrie); - GsonHelper.writeJsonFile(packMcmeta, packMetaFile.toPath()); - } - } else { - this.plugin.logger().warn("Failed to create parent directories for: " + overlaysFile.getAbsolutePath()); + modifyPackMetaFile = true; + } else if (packMetaFile.exists()) { + this.modifyShulker(shulkerFile, overlaysFile); + modifyPackMetaFile = true; + } + if (modifyPackMetaFile) { + JsonObject packMcmeta = GsonHelper.readJsonFile(packMetaFile.toPath()).getAsJsonObject(); + JsonArray entries = packMcmeta.getAsJsonObject("overlays").getAsJsonArray("entries"); + JsonObject entrie = new JsonObject(); + JsonObject formats = new JsonObject(); + formats.addProperty("min_inclusive", 16); + formats.addProperty("max_inclusive", 34); + entrie.add("formats", formats); + entrie.addProperty("directory", "1_20_2_ce"); + entries.add(entrie); + GsonHelper.writeJsonFile(packMcmeta, packMetaFile.toPath()); } } } catch (IOException e) { From 225da1ca9726c90a88cd189e5d2a7664f12a612c Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 31 Mar 2025 19:41:13 +0800 Subject: [PATCH 08/10] =?UTF-8?q?fix(bukkit):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E7=8E=A9=E5=AE=B6=E4=B8=8B=E5=BA=A7=E4=BD=8D=E4=BC=9A=E5=9C=A8?= =?UTF-8?q?=E5=AE=B6=E5=85=B7=E9=87=8C=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../furniture/BukkitFurnitureManager.java | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) 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 a7a8f24a2..02ec11299 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 @@ -362,9 +362,51 @@ public class BukkitFurnitureManager implements FurnitureManager { } Vector3f seatPos = MiscUtils.getVector3f(vector3f); furniture.removeOccupiedSeat(seatPos); + + Location vehicleLocation = vehicle.getLocation(); + Location originalLocation = vehicleLocation.clone(); + originalLocation.setY(furniture.location().getY()); + Location targetLocation = originalLocation.clone().add(vehicleLocation.getDirection()); + if (!isSafeLocation(targetLocation)) { + targetLocation = findSafeLocationNearby(originalLocation); + if (targetLocation == null) return; + } + targetLocation.setYaw(player.getLocation().getYaw()); + targetLocation.setPitch(player.getLocation().getPitch()); + player.teleport(targetLocation); } protected boolean isSeatCarrierType(Entity entity) { return (entity instanceof ArmorStand || entity instanceof ItemDisplay); } + + 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(); + } + + @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; + } } From aaccfc7c48d64feb0c9929ecc6fcfc538dcfeda8 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 31 Mar 2025 20:24:51 +0800 Subject: [PATCH 09/10] =?UTF-8?q?fix(bukkit):=20=E5=8F=AF=E4=BB=A5?= =?UTF-8?q?=E8=BA=B2=E9=81=BF=E4=B8=8B=E7=A2=B0=E6=92=9E=E5=AE=9E=E4=BD=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../furniture/BukkitFurnitureManager.java | 17 +++++++++++++++++ .../craftengine/bukkit/util/Reflections.java | 18 ++++++++++++++++++ 2 files changed, 35 insertions(+) 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 02ec11299..9772d52a9 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,8 +1,10 @@ package net.momirealms.craftengine.bukkit.entity.furniture; import net.momirealms.craftengine.bukkit.nms.CollisionEntity; +import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.util.EntityUtils; +import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.entity.furniture.*; import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.pack.Pack; @@ -388,6 +390,7 @@ public class BukkitFurnitureManager implements FurnitureManager { int z = location.getBlockZ(); if (!world.getBlockAt(x, y - 1, z).getType().isSolid()) return false; if (!world.getBlockAt(x, y, z).isPassable()) return false; + if (isEntityBlocking(location)) return false; return world.getBlockAt(x, y + 1, z).isPassable(); } @@ -409,4 +412,18 @@ public class BukkitFurnitureManager implements FurnitureManager { } return null; } + + private boolean isEntityBlocking(Location location) { + World world = location.getWorld(); + if (world == null) return true; + try { + Collection nearbyEntities = world.getNearbyEntities(location, 0.5, 2, 0.5); + for (Entity bukkitEntity : nearbyEntities) { + if (bukkitEntity instanceof Player) continue; + Object nmsEntity = Reflections.method$CraftEntity$getHandle.invoke(bukkitEntity); + return (boolean) Reflections.method$Entity$canBeCollidedWith.invoke(nmsEntity); + } + } catch (Exception ignored) {} + return false; + } } 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 f86339c9a..54a5dfa74 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 @@ -5898,4 +5898,22 @@ public class Reflections { clazz$FriendlyByteBuf, clazz$FriendlyByteBuf, int[].class ) ); + + public static final Method method$Entity$canBeCollidedWith = requireNonNull( + VersionHelper.isVersionNewerThan1_20_5() + ? ReflectionUtils.getMethod(clazz$Entity, boolean.class, new String[]{"canBeCollidedWith"}) + : VersionHelper.isVersionNewerThan1_20_3() + ? ReflectionUtils.getMethod(clazz$Entity, boolean.class, new String[]{"bz"}) + : VersionHelper.isVersionNewerThan1_20_2() + ? ReflectionUtils.getMethod(clazz$Entity, boolean.class, new String[]{"bx"}) + : VersionHelper.isVersionNewerThan1_20() + ? ReflectionUtils.getMethod(clazz$Entity, boolean.class, new String[]{"bu"}) + : ReflectionUtils.getMethod(clazz$Entity, boolean.class, new String[]{"canBeCollidedWith", "bu", "bx", "bz"}) + ); + + public static final Method method$CraftEntity$getHandle = requireNonNull( + ReflectionUtils.getMethod( + clazz$CraftEntity, clazz$Entity, 0 + ) + ); } From 1d513569d96ef79037ad0fc6032e40350c0077c5 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 31 Mar 2025 20:25:41 +0800 Subject: [PATCH 10/10] =?UTF-8?q?build:=20=E6=9B=B4=E6=96=B0=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 69e99ac8b..f88d4b1f6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] project_version=0.0.41 -config_version=18 +config_version=19 lang_version=3 project_group=net.momirealms latest_minecraft_version=1.21.4