9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-23 17:09:19 +00:00

Merge pull request #71 from jhqwqmc/dev

feat(entity): 实现潜影贝碰撞箱
This commit is contained in:
XiaoMoMi
2025-03-31 21:19:32 +08:00
committed by GitHub
17 changed files with 493 additions and 18 deletions

View File

@@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,21 @@
package net.momirealms.craftengine.bukkit.entity;
import net.momirealms.craftengine.bukkit.util.Reflections;
import java.util.Optional;
public class BaseEntityData<T> extends SimpleEntityData<T> {
public static final BaseEntityData<Byte> SharedFlags = new BaseEntityData<>(0, EntityDataValue.Serializers$BYTE, (byte) 0);
public static final BaseEntityData<Integer> AirSupply = new BaseEntityData<>(1, EntityDataValue.Serializers$INT, 300);
public static final BaseEntityData<Optional<Object>> CustomName = new BaseEntityData<>(2, EntityDataValue.Serializers$OPTIONAL_COMPONENT, Optional.empty());
public static final BaseEntityData<Boolean> CustomNameVisible = new BaseEntityData<>(3, EntityDataValue.Serializers$BOOLEAN, false);
public static final BaseEntityData<Boolean> Silent = new BaseEntityData<>(4, EntityDataValue.Serializers$BOOLEAN, false);
public static final BaseEntityData<Boolean> NoGravity = new BaseEntityData<>(5, EntityDataValue.Serializers$BOOLEAN, false);
public static final BaseEntityData<Object> Pose = new BaseEntityData<>(6, EntityDataValue.Serializers$POSE, Reflections.instance$Pose$STANDING);
public static final BaseEntityData<Integer> TicksFrozen = new BaseEntityData<>(7, EntityDataValue.Serializers$INT, 0);
public BaseEntityData(int id, Object serializer, T defaultValue) {
super(id, serializer, defaultValue);
}
}

View File

@@ -0,0 +1,29 @@
package net.momirealms.craftengine.bukkit.entity;
import java.util.List;
public interface EntityData<T> {
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<Object> list) {
if (!defaultValue().equals(value)) {
list.add(EntityDataValue.create(id(), serializer(), value));
}
}
default void addEntityData(T value, List<Object> list) {
list.add(EntityDataValue.create(id(), serializer(), value));
}
static <T> EntityData<T> of(int id, Object serializer, T defaultValue) {
return new SimpleEntityData<>(id, serializer, defaultValue);
}
}

View File

@@ -0,0 +1,19 @@
package net.momirealms.craftengine.bukkit.entity;
import java.util.List;
import java.util.Optional;
public class LivingEntityData<T> extends BaseEntityData<T> {
public static final LivingEntityData<Byte> LivingEntityFlags = new LivingEntityData<>(8, EntityDataValue.Serializers$BYTE, (byte) 0);
public static final LivingEntityData<Float> Health = new LivingEntityData<>(9, EntityDataValue.Serializers$FLOAT, 1.0f);
public static final LivingEntityData<List<Object>> EffectParticles = new LivingEntityData<>(10, EntityDataValue.Serializers$PARTICLES, List.of());
public static final LivingEntityData<Boolean> EffectAmbience = new LivingEntityData<>(11, EntityDataValue.Serializers$BOOLEAN, false);
public static final LivingEntityData<Integer> ArrowCount = new LivingEntityData<>(12, EntityDataValue.Serializers$INT, 0);
public static final LivingEntityData<Integer> StingerCount = new LivingEntityData<>(13, EntityDataValue.Serializers$INT, 0);
public static final LivingEntityData<Optional<Object>> SleepingPos = new LivingEntityData<>(14, EntityDataValue.Serializers$OPTIONAL_BLOCK_POS, Optional.empty());
public LivingEntityData(int id, Object serializer, T defaultValue) {
super(id, serializer, defaultValue);
}
}

View File

@@ -0,0 +1,10 @@
package net.momirealms.craftengine.bukkit.entity;
public class MobData<T> extends LivingEntityData<T> {
public static final MobData<Byte> MobFlags = new MobData<>(15, EntityDataValue.Serializers$BYTE, (byte) 0);
public MobData(int id, Object serializer, T defaultValue) {
super(id, serializer, defaultValue);
}
}

View File

@@ -0,0 +1,14 @@
package net.momirealms.craftengine.bukkit.entity;
import net.momirealms.craftengine.bukkit.util.Reflections;
public class ShulkerData<T> extends MobData<T> {
public static final ShulkerData<Object> AttachFace = new ShulkerData<>(16, EntityDataValue.Serializers$DIRECTION, Reflections.instance$Direction$DOWN);
public static final ShulkerData<Byte> Peek = new ShulkerData<>(17, EntityDataValue.Serializers$BYTE, (byte) 0);
public static final ShulkerData<Byte> Color = new ShulkerData<>(18, EntityDataValue.Serializers$BYTE, (byte) 16);
public ShulkerData(int id, Object serializer, T defaultValue) {
super(id, serializer, defaultValue);
}
}

View File

@@ -0,0 +1,29 @@
package net.momirealms.craftengine.bukkit.entity;
public class SimpleEntityData<T> implements EntityData<T> {
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;
}
}

View File

@@ -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;
@@ -362,9 +364,66 @@ 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;
if (isEntityBlocking(location)) 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;
}
private boolean isEntityBlocking(Location location) {
World world = location.getWorld();
if (world == null) return true;
try {
Collection<Entity> 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;
}
}

View File

@@ -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);
}
}

View File

@@ -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<Object> packets) {
// 生成无重力船
// todo 乐魂
}
@Override
@@ -35,9 +41,11 @@ public class BoatHitBox extends AbstractHitBox {
@Override
public HitBox create(Map<String, Object> 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
);
}
}

View File

@@ -1,14 +1,14 @@
package net.momirealms.craftengine.bukkit.entity.furniture;
import io.netty.buffer.Unpooled;
import net.momirealms.craftengine.bukkit.entity.ShulkerData;
import net.momirealms.craftengine.bukkit.util.DirectionUtils;
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 +19,7 @@ public class ShulkerHitBox extends AbstractHitBox {
private final byte peek;
// todo或许还能做个方向但是会麻烦点和 yaw 有关
private final Direction direction;
private List<Object> cachedValues;
public ShulkerHitBox(Seat[] seats, Vector3f position, double scale, byte peek, Direction direction) {
super(seats, position);
@@ -46,10 +47,42 @@ public class ShulkerHitBox extends AbstractHitBox {
@Override
public void addSpawnPackets(int[] entityIds, double x, double y, double z, float yaw, Consumer<Object> 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$ITEM_DISPLAY, 0, Reflections.instance$Vec3$Zero, 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$Holder$Attribute$scale, (Consumer<?>) (o) -> {});
Reflections.method$AttributeInstance$setBaseValue.invoke(attributeInstance, scale);
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);
}
}
private synchronized List<Object> 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

View File

@@ -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;
};
}
}

View File

@@ -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<Object> blockInteractionRangeHolder = (Optional<Object>) 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<Object> scaleHolder = (Optional<Object>) 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);
@@ -3141,6 +3148,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 +3157,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 +3675,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 +3687,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);
}
@@ -5773,7 +5786,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")
)
);
@@ -5782,4 +5796,124 @@ 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 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 Constructor<?> constructor$AttributeInstance =
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$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
)
);
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
)
);
}

View File

@@ -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<Key> VANILLA_ITEM_TEXTURES = new HashSet<>();
public static final Set<Key> VANILLA_BLOCK_TEXTURES = new HashSet<>();
public static final Set<Key> VANILLA_FONT_TEXTURES = new HashSet<>();
public static final List<byte[]> SHULKER_PNG = new ArrayList<>(1);
private final CraftEngine plugin;
private final BiConsumer<Path, Path> 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<Key, JsonObject> callback) {
@@ -118,6 +125,16 @@ public abstract class AbstractPackManager implements PackManager {
}
}
private void loadInternalPng(String path, Consumer<byte[]> 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,81 @@ 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();
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();
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));
}
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) {
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();

View File

@@ -104,6 +104,8 @@ public class ConfigManager implements Reloadable {
protected boolean furniture$remove_invalid_furniture_on_chunk_load$enable;
protected Set<String> 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()) {

View File

@@ -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