mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-23 08:59:27 +00:00
@@ -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 |
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user