diff --git a/protocol/build.gradle.kts b/protocol/build.gradle.kts index 09bb99206..3de44b97a 100644 --- a/protocol/build.gradle.kts +++ b/protocol/build.gradle.kts @@ -5,7 +5,7 @@ plugins { jacoco } -version = "26.1-SNAPSHOT" +version = "26.1-feature-custom-entities-SNAPSHOT" description = "MCProtocolLib is a simple library for communicating with Minecraft clients and servers." dependencies { diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/entity/type/BuiltinEntityType.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/entity/type/BuiltinEntityType.java new file mode 100644 index 000000000..fd2dd8781 --- /dev/null +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/entity/type/BuiltinEntityType.java @@ -0,0 +1,181 @@ +package org.geysermc.mcprotocollib.protocol.data.game.entity.type; + +import lombok.Getter; + +public enum BuiltinEntityType implements EntityType { + ACACIA_BOAT, + ACACIA_CHEST_BOAT, + ALLAY, + AREA_EFFECT_CLOUD, + ARMADILLO, + ARMOR_STAND, + ARROW(true), + AXOLOTL, + BAMBOO_CHEST_RAFT, + BAMBOO_RAFT, + BAT, + BEE, + BIRCH_BOAT, + BIRCH_CHEST_BOAT, + BLAZE, + BLOCK_DISPLAY, + BOGGED, + BREEZE, + BREEZE_WIND_CHARGE(true), + CAMEL, + CAMEL_HUSK, + CAT, + CAVE_SPIDER, + CHERRY_BOAT, + CHERRY_CHEST_BOAT, + CHEST_MINECART, + CHICKEN, + COD, + COPPER_GOLEM, + COMMAND_BLOCK_MINECART, + COW, + CREAKING, + CREEPER, + DARK_OAK_BOAT, + DARK_OAK_CHEST_BOAT, + DOLPHIN, + DONKEY, + DRAGON_FIREBALL(true), + DROWNED, + EGG(true), + ELDER_GUARDIAN, + ENDERMAN, + ENDERMITE, + ENDER_DRAGON, + ENDER_PEARL(true), + END_CRYSTAL, + EVOKER, + EVOKER_FANGS, + EXPERIENCE_BOTTLE(true), + EXPERIENCE_ORB, + EYE_OF_ENDER, + FALLING_BLOCK, + FIREBALL(true), + FIREWORK_ROCKET(true), + FOX, + FROG, + FURNACE_MINECART, + GHAST, + HAPPY_GHAST, + GIANT, + GLOW_ITEM_FRAME, + GLOW_SQUID, + GOAT, + GUARDIAN, + HOGLIN, + HOPPER_MINECART, + HORSE, + HUSK, + ILLUSIONER, + INTERACTION, + IRON_GOLEM, + ITEM, + ITEM_DISPLAY, + ITEM_FRAME, + JUNGLE_BOAT, + JUNGLE_CHEST_BOAT, + LEASH_KNOT, + LIGHTNING_BOLT, + LLAMA, + LLAMA_SPIT(true), + MAGMA_CUBE, + MANGROVE_BOAT, + MANGROVE_CHEST_BOAT, + MANNEQUIN, + MARKER, + MINECART, + MOOSHROOM, + MULE, + NAUTILUS, + OAK_BOAT, + OAK_CHEST_BOAT, + OCELOT, + OMINOUS_ITEM_SPAWNER, + PAINTING, + PALE_OAK_BOAT, + PALE_OAK_CHEST_BOAT, + PANDA, + PARCHED, + PARROT, + PHANTOM, + PIG, + PIGLIN, + PIGLIN_BRUTE, + PILLAGER, + POLAR_BEAR, + SPLASH_POTION(true), + LINGERING_POTION(true), + PUFFERFISH, + RABBIT, + RAVAGER, + SALMON, + SHEEP, + SHULKER, + SHULKER_BULLET(true), + SILVERFISH, + SKELETON, + SKELETON_HORSE, + SLIME, + SMALL_FIREBALL(true), + SNIFFER, + SNOWBALL(true), + SNOW_GOLEM, + SPAWNER_MINECART, + SPECTRAL_ARROW(true), + SPIDER, + SPRUCE_BOAT, + SPRUCE_CHEST_BOAT, + SQUID, + STRAY, + STRIDER, + TADPOLE, + TEXT_DISPLAY, + TNT, + TNT_MINECART, + TRADER_LLAMA, + TRIDENT(true), + TROPICAL_FISH, + TURTLE, + VEX, + VILLAGER, + VINDICATOR, + WANDERING_TRADER, + WARDEN, + WIND_CHARGE(true), + WITCH, + WITHER, + WITHER_SKELETON, + WITHER_SKULL(true), + WOLF, + ZOGLIN, + ZOMBIE, + ZOMBIE_HORSE, + ZOMBIE_NAUTILUS, + ZOMBIE_VILLAGER, + ZOMBIFIED_PIGLIN, + PLAYER, + FISHING_BOBBER(true); + + @Getter + private final boolean projectile; + + BuiltinEntityType() { + this.projectile = false; + } + + BuiltinEntityType(boolean projectile) { + this.projectile = projectile; + } + + public static final BuiltinEntityType[] VALUES = values(); + + @Override + public int id() { + return ordinal(); + } +} diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/entity/type/BuiltinPaintingType.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/entity/type/BuiltinPaintingType.java new file mode 100644 index 000000000..9dfec884c --- /dev/null +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/entity/type/BuiltinPaintingType.java @@ -0,0 +1,61 @@ +package org.geysermc.mcprotocollib.protocol.data.game.entity.type; + +public enum BuiltinPaintingType implements PaintingType { + KEBAB, + AZTEC, + ALBAN, + AZTEC2, + BOMB, + PLANT, + WASTELAND, + POOL, + COURBET, + SEA, + SUNSET, + CREEBET, + WANDERER, + GRAHAM, + MATCH, + BUST, + STAGE, + VOID, + SKULL_AND_ROSES, + WITHER, + FIGHTERS, + POINTER, + PIGSCENE, + BURNING_SKULL, + SKELETON, + EARTH, + WIND, + WATER, + FIRE, + DONKEY_KONG, + BAROQUE, + HUMBLE, + MEDITATIVE, + PRAIRIE_RIDE, + UNPACKED, + BACKYARD, + BOUQUET, + CAVEBIRD, + CHANGING, + COTAN, + ENDBOSS, + FERN, + FINDING, + LOWMIST, + ORB, + OWLEMONS, + PASSAGE, + POND, + SUNFLOWERS, + TIDES; + + public static final BuiltinPaintingType[] VALUES = values(); + + @Override + public int id() { + return ordinal(); + } +} diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/entity/type/EntityType.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/entity/type/EntityType.java index ef5df4f1d..68edf3645 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/entity/type/EntityType.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/entity/type/EntityType.java @@ -1,180 +1,26 @@ package org.geysermc.mcprotocollib.protocol.data.game.entity.type; -import lombok.Getter; +public interface EntityType { -public enum EntityType { - ACACIA_BOAT, - ACACIA_CHEST_BOAT, - ALLAY, - AREA_EFFECT_CLOUD, - ARMADILLO, - ARMOR_STAND, - ARROW(true), - AXOLOTL, - BAMBOO_CHEST_RAFT, - BAMBOO_RAFT, - BAT, - BEE, - BIRCH_BOAT, - BIRCH_CHEST_BOAT, - BLAZE, - BLOCK_DISPLAY, - BOGGED, - BREEZE, - BREEZE_WIND_CHARGE(true), - CAMEL, - CAMEL_HUSK, - CAT, - CAVE_SPIDER, - CHERRY_BOAT, - CHERRY_CHEST_BOAT, - CHEST_MINECART, - CHICKEN, - COD, - COPPER_GOLEM, - COMMAND_BLOCK_MINECART, - COW, - CREAKING, - CREEPER, - DARK_OAK_BOAT, - DARK_OAK_CHEST_BOAT, - DOLPHIN, - DONKEY, - DRAGON_FIREBALL(true), - DROWNED, - EGG(true), - ELDER_GUARDIAN, - ENDERMAN, - ENDERMITE, - ENDER_DRAGON, - ENDER_PEARL(true), - END_CRYSTAL, - EVOKER, - EVOKER_FANGS, - EXPERIENCE_BOTTLE(true), - EXPERIENCE_ORB, - EYE_OF_ENDER, - FALLING_BLOCK, - FIREBALL(true), - FIREWORK_ROCKET(true), - FOX, - FROG, - FURNACE_MINECART, - GHAST, - HAPPY_GHAST, - GIANT, - GLOW_ITEM_FRAME, - GLOW_SQUID, - GOAT, - GUARDIAN, - HOGLIN, - HOPPER_MINECART, - HORSE, - HUSK, - ILLUSIONER, - INTERACTION, - IRON_GOLEM, - ITEM, - ITEM_DISPLAY, - ITEM_FRAME, - JUNGLE_BOAT, - JUNGLE_CHEST_BOAT, - LEASH_KNOT, - LIGHTNING_BOLT, - LLAMA, - LLAMA_SPIT(true), - MAGMA_CUBE, - MANGROVE_BOAT, - MANGROVE_CHEST_BOAT, - MANNEQUIN, - MARKER, - MINECART, - MOOSHROOM, - MULE, - NAUTILUS, - OAK_BOAT, - OAK_CHEST_BOAT, - OCELOT, - OMINOUS_ITEM_SPAWNER, - PAINTING, - PALE_OAK_BOAT, - PALE_OAK_CHEST_BOAT, - PANDA, - PARCHED, - PARROT, - PHANTOM, - PIG, - PIGLIN, - PIGLIN_BRUTE, - PILLAGER, - POLAR_BEAR, - SPLASH_POTION(true), - LINGERING_POTION(true), - PUFFERFISH, - RABBIT, - RAVAGER, - SALMON, - SHEEP, - SHULKER, - SHULKER_BULLET(true), - SILVERFISH, - SKELETON, - SKELETON_HORSE, - SLIME, - SMALL_FIREBALL(true), - SNIFFER, - SNOWBALL(true), - SNOW_GOLEM, - SPAWNER_MINECART, - SPECTRAL_ARROW(true), - SPIDER, - SPRUCE_BOAT, - SPRUCE_CHEST_BOAT, - SQUID, - STRAY, - STRIDER, - TADPOLE, - TEXT_DISPLAY, - TNT, - TNT_MINECART, - TRADER_LLAMA, - TRIDENT(true), - TROPICAL_FISH, - TURTLE, - VEX, - VILLAGER, - VINDICATOR, - WANDERING_TRADER, - WARDEN, - WIND_CHARGE(true), - WITCH, - WITHER, - WITHER_SKELETON, - WITHER_SKULL(true), - WOLF, - ZOGLIN, - ZOMBIE, - ZOMBIE_HORSE, - ZOMBIE_NAUTILUS, - ZOMBIE_VILLAGER, - ZOMBIFIED_PIGLIN, - PLAYER, - FISHING_BOBBER(true); + int id(); - @Getter - private final boolean projectile; + boolean isProjectile(); - EntityType() { - this.projectile = false; + static EntityType from(int id) { + if (id < 0 || id >= BuiltinEntityType.VALUES.length) { + return new Custom(id); + } + return BuiltinEntityType.VALUES[id]; } - EntityType(boolean projectile) { - this.projectile = projectile; + default boolean is(EntityType type) { + return id() == type.id(); } - private static final EntityType[] VALUES = values(); - - public static EntityType from(int id) { - return VALUES[id]; + record Custom(int id) implements EntityType { + @Override + public boolean isProjectile() { + return false; + } } } diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/entity/type/PaintingType.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/entity/type/PaintingType.java index fa86e9355..b8e750503 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/entity/type/PaintingType.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/entity/type/PaintingType.java @@ -1,60 +1,16 @@ package org.geysermc.mcprotocollib.protocol.data.game.entity.type; -public enum PaintingType { - KEBAB, - AZTEC, - ALBAN, - AZTEC2, - BOMB, - PLANT, - WASTELAND, - POOL, - COURBET, - SEA, - SUNSET, - CREEBET, - WANDERER, - GRAHAM, - MATCH, - BUST, - STAGE, - VOID, - SKULL_AND_ROSES, - WITHER, - FIGHTERS, - POINTER, - PIGSCENE, - BURNING_SKULL, - SKELETON, - EARTH, - WIND, - WATER, - FIRE, - DONKEY_KONG, - BAROQUE, - HUMBLE, - MEDITATIVE, - PRAIRIE_RIDE, - UNPACKED, - BACKYARD, - BOUQUET, - CAVEBIRD, - CHANGING, - COTAN, - ENDBOSS, - FERN, - FINDING, - LOWMIST, - ORB, - OWLEMONS, - PASSAGE, - POND, - SUNFLOWERS, - TIDES; +public interface PaintingType { - private static final PaintingType[] VALUES = values(); + int id(); - public static PaintingType from(int id) { - return VALUES[id]; + static PaintingType from(int id) { + if (id < 0 || id >= BuiltinPaintingType.values().length) { + return new Custom(id); + } + return BuiltinPaintingType.VALUES[id]; + } + + record Custom(int id) implements PaintingType { } } diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/ItemTypes.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/ItemTypes.java index 6b4946e24..d34ccf3c9 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/ItemTypes.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/ItemTypes.java @@ -623,7 +623,7 @@ public static void writeTrimPattern(ByteBuf buf, ArmorTrim.TrimPattern pattern) buf.writeBoolean(pattern.decal()); } - public static > TypedEntityData readTypedEntityData(ByteBuf buf, Function reader) { + public static TypedEntityData readTypedEntityData(ByteBuf buf, Function reader) { return new TypedEntityData<>(reader.apply(buf), MinecraftTypes.readCompoundTag(buf)); } @@ -637,7 +637,7 @@ public static EntityType readEntityType(ByteBuf buf) { } public static void writeEntityType(ByteBuf buf, EntityType state) { - MinecraftTypes.writeVarInt(buf, state.ordinal()); + MinecraftTypes.writeVarInt(buf, state.id()); } public static BlockEntityType readBlockEntityType(ByteBuf buf) { diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/ClientboundAwardStatsPacket.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/ClientboundAwardStatsPacket.java index cb25cd1c5..1b3f25aa2 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/ClientboundAwardStatsPacket.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/ClientboundAwardStatsPacket.java @@ -76,10 +76,10 @@ public void serialize(ByteBuf out) { statisticId = ((DropItemStatistic) statistic).getId(); } else if (statistic instanceof KillEntityStatistic) { category = StatisticCategory.KILL_ENTITY; - statisticId = ((KillEntityStatistic) statistic).getEntity().ordinal(); + statisticId = ((KillEntityStatistic) statistic).getEntity().id(); } else if (statistic instanceof KilledByEntityStatistic) { category = StatisticCategory.KILLED_BY_ENTITY; - statisticId = ((KilledByEntityStatistic) statistic).getEntity().ordinal(); + statisticId = ((KilledByEntityStatistic) statistic).getEntity().id(); } else if (statistic instanceof CustomStatistic) { category = StatisticCategory.CUSTOM; statisticId = ((CustomStatistic) statistic).ordinal(); diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/entity/ClientboundAddEntityPacket.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/entity/ClientboundAddEntityPacket.java index bc17d3e1d..48fb8249f 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/entity/ClientboundAddEntityPacket.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/entity/ClientboundAddEntityPacket.java @@ -15,6 +15,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.object.ObjectData; import org.geysermc.mcprotocollib.protocol.data.game.entity.object.ProjectileData; import org.geysermc.mcprotocollib.protocol.data.game.entity.object.WardenData; +import org.geysermc.mcprotocollib.protocol.data.game.entity.type.BuiltinEntityType; import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; import java.util.UUID; @@ -66,15 +67,15 @@ public ClientboundAddEntityPacket(ByteBuf in) { this.headYaw = in.readByte() * 360 / 256f; int data = MinecraftTypes.readVarInt(in); - if (this.type == EntityType.MINECART) { + if (this.type == BuiltinEntityType.MINECART) { this.data = MinecartType.from(data); - } else if (this.type == EntityType.ITEM_FRAME || this.type == EntityType.GLOW_ITEM_FRAME || this.type == EntityType.PAINTING) { + } else if (this.type == BuiltinEntityType.ITEM_FRAME || this.type == BuiltinEntityType.GLOW_ITEM_FRAME || this.type == BuiltinEntityType.PAINTING) { this.data = Direction.VALUES[data]; - } else if (this.type == EntityType.FALLING_BLOCK) { + } else if (this.type == BuiltinEntityType.FALLING_BLOCK) { this.data = new FallingBlockData(data & 65535, data >> 16); - } else if (this.type.isProjectile()) { + } else if (type.isProjectile()) { this.data = new ProjectileData(data); - } else if (this.type == EntityType.WARDEN) { + } else if (this.type == BuiltinEntityType.WARDEN) { this.data = new WardenData(data); } else { if (data == 0) { @@ -89,7 +90,7 @@ public ClientboundAddEntityPacket(ByteBuf in) { public void serialize(ByteBuf out) { MinecraftTypes.writeVarInt(out, this.entityId); MinecraftTypes.writeUUID(out, this.uuid); - MinecraftTypes.writeVarInt(out, this.type.ordinal()); + MinecraftTypes.writeVarInt(out, this.type.id()); out.writeDouble(this.x); out.writeDouble(this.y); out.writeDouble(this.z);