diff --git a/example/src/main/java/org/geysermc/mcprotocollib/protocol/example/MinecraftProtocolTest.java b/example/src/main/java/org/geysermc/mcprotocollib/protocol/example/MinecraftProtocolTest.java index 5e33ee68f..916ee3898 100644 --- a/example/src/main/java/org/geysermc/mcprotocollib/protocol/example/MinecraftProtocolTest.java +++ b/example/src/main/java/org/geysermc/mcprotocollib/protocol/example/MinecraftProtocolTest.java @@ -220,7 +220,7 @@ private static void login() { @Override public void packetReceived(Session session, Packet packet) { if (packet instanceof ClientboundLoginPacket) { - session.send(new ServerboundChatPacket("Hello, this is a test of MCProtocolLib.", Instant.now().toEpochMilli(), 0L, null, 0, new BitSet())); + session.send(new ServerboundChatPacket("Hello, this is a test of MCProtocolLib.", Instant.now().toEpochMilli(), 0L, null, 0, new BitSet(), 0)); } else if (packet instanceof ClientboundSystemChatPacket systemChatPacket) { Component message = systemChatPacket.getContent(); log.info("Received Message: {}", message); diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6466a2731..22585f8d9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,8 +7,7 @@ cloudburstnbt = "3.0.0.Final" slf4j = "2.0.9" math = "2.0" fastutil-maps = "8.5.3" -netty = "4.1.103.Final" -netty-io_uring = "0.0.24.Final" +netty = "4.2.1.Final" gson = "2.11.0" minecraftauth = "4.1.1" checkerframework = "3.42.0" @@ -37,7 +36,6 @@ fastutil-int2object-maps = { module = "com.nukkitx.fastutil:fastutil-int-object- fastutil-int2int-maps = { module = "com.nukkitx.fastutil:fastutil-int-int-maps", version.ref = "fastutil-maps" } netty-all = { module = "io.netty:netty-all", version.ref = "netty" } -netty-incubator-transport-native-io_uring = { module = "io.netty.incubator:netty-incubator-transport-native-io_uring", version.ref = "netty-io_uring" } gson = { module = "com.google.code.gson:gson", version.ref = "gson" } @@ -57,4 +55,3 @@ lombok = { module = "io.freefair.gradle:lombok-plugin", version.ref = "lombok-pl adventure = ["adventure-text-serializer-gson", "adventure-text-serializer-json-legacy-impl"] math = ["math-api", "math-immutable"] fastutil = ["fastutil-object2int-maps", "fastutil-int2object-maps", "fastutil-int2int-maps"] -netty = ["netty-all", "netty-incubator-transport-native-io_uring"] diff --git a/protocol/build.gradle.kts b/protocol/build.gradle.kts index 6de81ae68..a4f524a4a 100644 --- a/protocol/build.gradle.kts +++ b/protocol/build.gradle.kts @@ -3,7 +3,7 @@ plugins { jacoco } -version = "1.21.4-SNAPSHOT" +version = "1.21.5-SNAPSHOT" description = "MCProtocolLib is a simple library for communicating with Minecraft clients and servers." dependencies { @@ -29,7 +29,7 @@ dependencies { api(libs.bundles.fastutil) // Netty - api(libs.bundles.netty) + api(libs.netty.all) // Checker Framework api(libs.checkerframework.qual) diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/network/BuiltinFlags.java b/protocol/src/main/java/org/geysermc/mcprotocollib/network/BuiltinFlags.java index cdd590eed..dae7be0ca 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/network/BuiltinFlags.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/network/BuiltinFlags.java @@ -1,5 +1,7 @@ package org.geysermc.mcprotocollib.network; +import io.netty.buffer.ByteBufAllocator; + import java.net.InetSocketAddress; /** @@ -46,6 +48,12 @@ public class BuiltinFlags { */ public static final Flag WRITE_TIMEOUT = new Flag<>("write-timeout", Integer.class); + /** + * The netty allocator to use. + * Used by both server and client + */ + public static final Flag ALLOCATOR = new Flag<>("allocator", ByteBufAllocator.class); + private BuiltinFlags() { } } diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/network/helper/TransportHelper.java b/protocol/src/main/java/org/geysermc/mcprotocollib/network/helper/TransportHelper.java index 7c7e4a072..30b2f05b0 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/network/helper/TransportHelper.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/network/helper/TransportHelper.java @@ -2,34 +2,39 @@ import io.netty.channel.ChannelFactory; import io.netty.channel.EventLoopGroup; +import io.netty.channel.MultiThreadIoEventLoopGroup; import io.netty.channel.epoll.Epoll; import io.netty.channel.epoll.EpollDatagramChannel; import io.netty.channel.epoll.EpollEventLoopGroup; +import io.netty.channel.epoll.EpollIoHandler; import io.netty.channel.epoll.EpollServerSocketChannel; import io.netty.channel.epoll.EpollSocketChannel; import io.netty.channel.kqueue.KQueue; import io.netty.channel.kqueue.KQueueDatagramChannel; import io.netty.channel.kqueue.KQueueEventLoopGroup; +import io.netty.channel.kqueue.KQueueIoHandler; import io.netty.channel.kqueue.KQueueServerSocketChannel; import io.netty.channel.kqueue.KQueueSocketChannel; import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.nio.NioIoHandler; import io.netty.channel.socket.DatagramChannel; import io.netty.channel.socket.ServerSocketChannel; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioDatagramChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; -import io.netty.incubator.channel.uring.IOUring; -import io.netty.incubator.channel.uring.IOUringDatagramChannel; -import io.netty.incubator.channel.uring.IOUringEventLoopGroup; -import io.netty.incubator.channel.uring.IOUringServerSocketChannel; -import io.netty.incubator.channel.uring.IOUringSocketChannel; +import io.netty.channel.uring.IoUring; +import io.netty.channel.uring.IoUringDatagramChannel; +import io.netty.channel.uring.IoUringIoHandler; +import io.netty.channel.uring.IoUringServerSocketChannel; +import io.netty.channel.uring.IoUringSocketChannel; import java.util.concurrent.ThreadFactory; -import java.util.function.Function; +import java.util.function.BiFunction; public class TransportHelper { public static final TransportHelper.TransportType TRANSPORT_TYPE = TransportHelper.determineTransportMethod(); + public static final boolean NEW_NETTY = isClassAvailable("io.netty.channel.MultiThreadIoEventLoopGroup"); public enum TransportMethod { NIO, EPOLL, KQUEUE, IO_URING @@ -42,24 +47,28 @@ public record TransportType(TransportMethod method, ChannelFactory socketChannelFactory, Class datagramChannelClass, ChannelFactory datagramChannelFactory, - Function eventLoopGroupFactory, + BiFunction eventLoopGroupFactory, boolean supportsTcpFastOpenServer, boolean supportsTcpFastOpenClient) { } + @SuppressWarnings("deprecation") private static TransportType determineTransportMethod() { - if (isClassAvailable("io.netty.incubator.channel.uring.IOUring") && IOUring.isAvailable()) { + if (isClassAvailable("io.netty.channel.uring.IoUring") + && IoUring.isAvailable() + && Boolean.getBoolean("Mcpl.io_uring") + ) { return new TransportType( TransportMethod.IO_URING, - IOUringServerSocketChannel.class, - IOUringServerSocketChannel::new, - IOUringSocketChannel.class, - IOUringSocketChannel::new, - IOUringDatagramChannel.class, - IOUringDatagramChannel::new, - factory -> new IOUringEventLoopGroup(0, factory), - IOUring.isTcpFastOpenServerSideAvailable(), - IOUring.isTcpFastOpenClientSideAvailable() + IoUringServerSocketChannel.class, + IoUringServerSocketChannel::new, + IoUringSocketChannel.class, + IoUringSocketChannel::new, + IoUringDatagramChannel.class, + IoUringDatagramChannel::new, + (threads, factory) -> new MultiThreadIoEventLoopGroup(threads, factory, IoUringIoHandler.newFactory()), + IoUring.isTcpFastOpenServerSideAvailable(), + IoUring.isTcpFastOpenClientSideAvailable() ); } @@ -72,7 +81,8 @@ private static TransportType determineTransportMethod() { EpollSocketChannel::new, EpollDatagramChannel.class, EpollDatagramChannel::new, - factory -> new EpollEventLoopGroup(0, factory), + NEW_NETTY ? (threads, factory) -> + new MultiThreadIoEventLoopGroup(threads, factory, EpollIoHandler.newFactory()) : EpollEventLoopGroup::new, Epoll.isTcpFastOpenServerSideAvailable(), Epoll.isTcpFastOpenClientSideAvailable() ); @@ -87,7 +97,8 @@ private static TransportType determineTransportMethod() { KQueueSocketChannel::new, KQueueDatagramChannel.class, KQueueDatagramChannel::new, - factory -> new KQueueEventLoopGroup(0, factory), + NEW_NETTY ? (threads, factory) -> + new MultiThreadIoEventLoopGroup(threads, factory, KQueueIoHandler.newFactory()) : KQueueEventLoopGroup::new, KQueue.isTcpFastOpenServerSideAvailable(), KQueue.isTcpFastOpenClientSideAvailable() ); @@ -101,7 +112,8 @@ private static TransportType determineTransportMethod() { NioSocketChannel::new, NioDatagramChannel.class, NioDatagramChannel::new, - factory -> new NioEventLoopGroup(0, factory), + NEW_NETTY ? (threads, factory) -> + new MultiThreadIoEventLoopGroup(threads, factory, NioIoHandler.newFactory()) : NioEventLoopGroup::new, false, false ); diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/network/netty/PacketEncryptorCodec.java b/protocol/src/main/java/org/geysermc/mcprotocollib/network/netty/PacketEncryptorCodec.java index d6a24d980..9c90b2de1 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/network/netty/PacketEncryptorCodec.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/network/netty/PacketEncryptorCodec.java @@ -47,6 +47,7 @@ protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) t try { config.encryption().decrypt(heapBuf.array(), baseOffset, inBytes, heapBuf.array(), baseOffset); out.add(heapBuf); + if (in.hasArray()) in.readerIndex(inBytes); // This is required as otherwise the ByteBuf doesn't know it has been read } catch (Exception e) { heapBuf.release(); throw e; diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/network/server/NetworkServer.java b/protocol/src/main/java/org/geysermc/mcprotocollib/network/server/NetworkServer.java index 16572c1a2..a3e9b3984 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/network/server/NetworkServer.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/network/server/NetworkServer.java @@ -1,6 +1,7 @@ package org.geysermc.mcprotocollib.network.server; import io.netty.bootstrap.ServerBootstrap; +import io.netty.buffer.ByteBufAllocator; import io.netty.channel.Channel; import io.netty.channel.ChannelFactory; import io.netty.channel.ChannelFutureListener; @@ -86,11 +87,11 @@ protected ChannelFactory getChannelFactory() { } protected EventLoopGroup createBossEventLoopGroup() { - return TransportHelper.TRANSPORT_TYPE.eventLoopGroupFactory().apply(null); + return TransportHelper.TRANSPORT_TYPE.eventLoopGroupFactory().apply(0, null); } protected EventLoopGroup createWorkerEventLoopGroup() { - return TransportHelper.TRANSPORT_TYPE.eventLoopGroupFactory().apply(null); + return TransportHelper.TRANSPORT_TYPE.eventLoopGroupFactory().apply(0, null); } protected void setOptions(ServerBootstrap bootstrap) { @@ -100,6 +101,8 @@ protected void setOptions(ServerBootstrap bootstrap) { if (getGlobalFlag(BuiltinFlags.TCP_FAST_OPEN, false) && TransportHelper.TRANSPORT_TYPE.supportsTcpFastOpenServer()) { bootstrap.option(ChannelOption.TCP_FASTOPEN, 3); } + + bootstrap.option(ChannelOption.ALLOCATOR, getGlobalFlag(BuiltinFlags.ALLOCATOR, ByteBufAllocator.DEFAULT)); } protected ChannelHandler getChannelHandler() { diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/network/session/ClientNetworkSession.java b/protocol/src/main/java/org/geysermc/mcprotocollib/network/session/ClientNetworkSession.java index 9cd4df2be..3335aae6b 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/network/session/ClientNetworkSession.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/network/session/ClientNetworkSession.java @@ -1,6 +1,7 @@ package org.geysermc.mcprotocollib.network.session; import io.netty.bootstrap.Bootstrap; +import io.netty.buffer.ByteBufAllocator; import io.netty.channel.Channel; import io.netty.channel.ChannelFactory; import io.netty.channel.ChannelHandler; @@ -100,6 +101,8 @@ protected void setOptions(Bootstrap bootstrap) { if (getFlag(BuiltinFlags.TCP_FAST_OPEN, false) && TransportHelper.TRANSPORT_TYPE.supportsTcpFastOpenClient()) { bootstrap.option(ChannelOption.TCP_FASTOPEN_CONNECT, true); } + + bootstrap.option(ChannelOption.ALLOCATOR, getFlag(BuiltinFlags.ALLOCATOR, ByteBufAllocator.DEFAULT)); } protected ChannelHandler getChannelHandler() { @@ -124,7 +127,7 @@ private static void createEventLoopGroup() { return; } - EVENT_LOOP_GROUP = TransportHelper.TRANSPORT_TYPE.eventLoopGroupFactory().apply(newThreadFactory()); + EVENT_LOOP_GROUP = TransportHelper.TRANSPORT_TYPE.eventLoopGroupFactory().apply(0, newThreadFactory()); Runtime.getRuntime().addShutdownHook(new Thread( () -> EVENT_LOOP_GROUP.shutdownGracefully(SHUTDOWN_QUIET_PERIOD_MS, SHUTDOWN_TIMEOUT_MS, TimeUnit.MILLISECONDS))); diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/codec/MinecraftCodec.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/codec/MinecraftCodec.java index 5aa68c308..371e4ac27 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/codec/MinecraftCodec.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/codec/MinecraftCodec.java @@ -54,6 +54,7 @@ import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundStopSoundPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundSystemChatPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundTabListPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundTestInstanceBlockStatus; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundTickingStatePacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundTickingStepPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundUpdateAdvancementsPacket; @@ -92,8 +93,7 @@ import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.player.ClientboundSetExperiencePacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.player.ClientboundSetHealthPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.player.ClientboundSetHeldSlotPacket; -import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddEntityPacket; -import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddExperienceOrbPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundAddEntityPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.inventory.ClientboundContainerClosePacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.inventory.ClientboundContainerSetContentPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.inventory.ClientboundContainerSetDataPacket; @@ -186,8 +186,10 @@ import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundMoveVehiclePacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundPaddleBoatPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundPlayerInputPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundSetTestBlockPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundSignUpdatePacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundTeleportToEntityPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundTestInstanceBlockActionPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosRotPacket; @@ -216,8 +218,8 @@ public class MinecraftCodec { public static final PacketCodec CODEC = PacketCodec.builder() - .protocolVersion(769) - .minecraftVersion("1.21.4") + .protocolVersion(770) + .minecraftVersion("1.21.5") .state(ProtocolState.HANDSHAKE, MinecraftPacketRegistry.builder() .registerServerboundPacket(ClientIntentionPacket.class, ClientIntentionPacket::new) ) @@ -267,7 +269,6 @@ public class MinecraftCodec { ).state(ProtocolState.GAME, MinecraftPacketRegistry.builder() .registerClientboundPacket(ClientboundDelimiterPacket.class, ClientboundDelimiterPacket::new) .registerClientboundPacket(ClientboundAddEntityPacket.class, ClientboundAddEntityPacket::new) - .registerClientboundPacket(ClientboundAddExperienceOrbPacket.class, ClientboundAddExperienceOrbPacket::new) .registerClientboundPacket(ClientboundAnimatePacket.class, ClientboundAnimatePacket::new) .registerClientboundPacket(ClientboundAwardStatsPacket.class, ClientboundAwardStatsPacket::new) .registerClientboundPacket(ClientboundBlockChangedAckPacket.class, ClientboundBlockChangedAckPacket::new) @@ -385,6 +386,7 @@ public class MinecraftCodec { .registerClientboundPacket(ClientboundTagQueryPacket.class, ClientboundTagQueryPacket::new) .registerClientboundPacket(ClientboundTakeItemEntityPacket.class, ClientboundTakeItemEntityPacket::new) .registerClientboundPacket(ClientboundTeleportEntityPacket.class, ClientboundTeleportEntityPacket::new) + .registerClientboundPacket(ClientboundTestInstanceBlockStatus.class, ClientboundTestInstanceBlockStatus::new) .registerClientboundPacket(ClientboundTickingStatePacket.class, ClientboundTickingStatePacket::new) .registerClientboundPacket(ClientboundTickingStepPacket.class, ClientboundTickingStepPacket::new) .registerClientboundPacket(ClientboundTransferPacket.class, ClientboundTransferPacket::new) @@ -453,9 +455,11 @@ public class MinecraftCodec { .registerServerboundPacket(ServerboundSetCreativeModeSlotPacket.class, ServerboundSetCreativeModeSlotPacket::new) .registerServerboundPacket(ServerboundSetJigsawBlockPacket.class, ServerboundSetJigsawBlockPacket::new) .registerServerboundPacket(ServerboundSetStructureBlockPacket.class, ServerboundSetStructureBlockPacket::new) + .registerServerboundPacket(ServerboundSetTestBlockPacket.class, ServerboundSetTestBlockPacket::new) .registerServerboundPacket(ServerboundSignUpdatePacket.class, ServerboundSignUpdatePacket::new) .registerServerboundPacket(ServerboundSwingPacket.class, ServerboundSwingPacket::new) .registerServerboundPacket(ServerboundTeleportToEntityPacket.class, ServerboundTeleportToEntityPacket::new) + .registerServerboundPacket(ServerboundTestInstanceBlockActionPacket.class, ServerboundTestInstanceBlockActionPacket::new) .registerServerboundPacket(ServerboundUseItemOnPacket.class, ServerboundUseItemOnPacket::new) .registerServerboundPacket(ServerboundUseItemPacket.class, ServerboundUseItemPacket::new) ) diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/codec/MinecraftTypes.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/codec/MinecraftTypes.java index 26060c452..acfca5704 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/codec/MinecraftTypes.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/codec/MinecraftTypes.java @@ -5,6 +5,7 @@ import io.netty.buffer.ByteBufInputStream; import io.netty.buffer.ByteBufOutputStream; import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.Unpooled; import lombok.NoArgsConstructor; import net.kyori.adventure.key.Key; import net.kyori.adventure.text.Component; @@ -48,26 +49,29 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.SnifferState; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.VillagerData; -import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.WolfVariant; import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.BlockBreakStage; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerSpawnInfo; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.VillagerTrade; +import org.geysermc.mcprotocollib.protocol.data.game.item.HashedStack; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponent; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemTypes; import org.geysermc.mcprotocollib.protocol.data.game.level.LightUpdateData; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.TestInstanceBlockEntity; import org.geysermc.mcprotocollib.protocol.data.game.level.event.LevelEvent; import org.geysermc.mcprotocollib.protocol.data.game.level.event.LevelEventType; import org.geysermc.mcprotocollib.protocol.data.game.level.event.UnknownLevelEvent; import org.geysermc.mcprotocollib.protocol.data.game.level.particle.BlockParticleData; import org.geysermc.mcprotocollib.protocol.data.game.level.particle.DustColorTransitionParticleData; import org.geysermc.mcprotocollib.protocol.data.game.level.particle.DustParticleData; -import org.geysermc.mcprotocollib.protocol.data.game.level.particle.EntityEffectParticleData; +import org.geysermc.mcprotocollib.protocol.data.game.level.particle.ColorParticleData; import org.geysermc.mcprotocollib.protocol.data.game.level.particle.ItemParticleData; import org.geysermc.mcprotocollib.protocol.data.game.level.particle.Particle; import org.geysermc.mcprotocollib.protocol.data.game.level.particle.ParticleData; @@ -80,6 +84,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.particle.positionsource.EntityPositionSource; import org.geysermc.mcprotocollib.protocol.data.game.level.particle.positionsource.PositionSource; import org.geysermc.mcprotocollib.protocol.data.game.level.particle.positionsource.PositionSourceType; +import org.geysermc.mcprotocollib.protocol.data.game.level.sound.BuiltinSound; import org.geysermc.mcprotocollib.protocol.data.game.level.sound.CustomSound; import org.geysermc.mcprotocollib.protocol.data.game.level.sound.Sound; import org.geysermc.mcprotocollib.protocol.data.game.level.sound.SoundCategory; @@ -111,8 +116,10 @@ import java.util.BitSet; import java.util.EnumSet; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.UUID; import java.util.function.BiConsumer; import java.util.function.Function; @@ -327,7 +334,11 @@ public static long[] readLongArray(ByteBuf buf, ToIntFunction reader) { } long[] l = new long[length]; - for (int index = 0; index < length; index++) { + return readFixedSizeLongArray(buf, l); + } + + public static long[] readFixedSizeLongArray(ByteBuf buf, long[] l) { + for (int index = 0; index < l.length; index++) { l[index] = buf.readLong(); } @@ -340,6 +351,10 @@ public static void writeLongArray(ByteBuf buf, long[] l) { public static void writeLongArray(ByteBuf buf, long[] l, ObjIntConsumer writer) { writer.accept(buf, l.length); + MinecraftTypes.writeFixedSizeLongArray(buf, l); + } + + public static void writeFixedSizeLongArray(ByteBuf buf, long[] l) { for (long value : l) { buf.writeLong(value); } @@ -413,21 +428,36 @@ public static void writeAnyTag(ByteBuf buf, @Nullable Object tag) { @Nullable public static ItemStack readOptionalItemStack(ByteBuf buf) { + return MinecraftTypes.readOptionalItemStack(buf, false); + } + + public static void writeOptionalItemStack(ByteBuf buf, ItemStack item) { + MinecraftTypes.writeOptionalItemStack(buf, item, false); + } + + @Nullable + public static ItemStack readOptionalItemStack(ByteBuf buf, boolean untrusted) { int count = MinecraftTypes.readVarInt(buf); if (count <= 0) { return null; } int item = MinecraftTypes.readVarInt(buf); - return new ItemStack(item, count, MinecraftTypes.readDataComponentPatch(buf)); + DataComponents components; + try { + components = MinecraftTypes.readDataComponentPatch(buf, untrusted); + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException("Exception while reading components for item " + item, e); + } + return new ItemStack(item, count, components); } - public static void writeOptionalItemStack(ByteBuf buf, ItemStack item) { + public static void writeOptionalItemStack(ByteBuf buf, ItemStack item, boolean untrusted) { boolean empty = item == null || item.getAmount() <= 0; MinecraftTypes.writeVarInt(buf, !empty ? item.getAmount() : 0); if (!empty) { MinecraftTypes.writeVarInt(buf, item.getId()); - MinecraftTypes.writeDataComponentPatch(buf, item.getDataComponentsPatch()); + MinecraftTypes.writeDataComponentPatch(buf, item.getDataComponentsPatch(), untrusted); } } @@ -441,7 +471,7 @@ public static void writeItemStack(ByteBuf buf, @NotNull ItemStack item) { } @Nullable - public static DataComponents readDataComponentPatch(ByteBuf buf) { + public static DataComponents readDataComponentPatch(ByteBuf buf, boolean untrusted) { int nonNullComponents = MinecraftTypes.readVarInt(buf); int nullComponents = MinecraftTypes.readVarInt(buf); if (nonNullComponents == 0 && nullComponents == 0) { @@ -449,14 +479,23 @@ public static DataComponents readDataComponentPatch(ByteBuf buf) { } Map, DataComponent> dataComponents = new HashMap<>(); - for (int k = 0; k < nonNullComponents; k++) { - DataComponentType dataComponentType = DataComponentTypes.from(MinecraftTypes.readVarInt(buf)); - DataComponent dataComponent = dataComponentType.readDataComponent(buf); - dataComponents.put(dataComponentType, dataComponent); + if (untrusted) { + for (int k = 0; k < nonNullComponents; k++) { + DataComponentType dataComponentType = DataComponentTypes.read(buf); + MinecraftTypes.readVarInt(buf); + DataComponent dataComponent = dataComponentType.readDataComponent(buf); + dataComponents.put(dataComponentType, dataComponent); + } + } else { + for (int k = 0; k < nonNullComponents; k++) { + DataComponentType dataComponentType = DataComponentTypes.read(buf); + DataComponent dataComponent = dataComponentType.readDataComponent(buf); + dataComponents.put(dataComponentType, dataComponent); + } } for (int k = 0; k < nullComponents; k++) { - DataComponentType dataComponentType = DataComponentTypes.from(MinecraftTypes.readVarInt(buf)); + DataComponentType dataComponentType = DataComponentTypes.read(buf); DataComponent dataComponent = dataComponentType.readNullDataComponent(); dataComponents.put(dataComponentType, dataComponent); } @@ -464,7 +503,7 @@ public static DataComponents readDataComponentPatch(ByteBuf buf) { return new DataComponents(dataComponents); } - public static void writeDataComponentPatch(ByteBuf buf, DataComponents dataComponents) { + public static void writeDataComponentPatch(ByteBuf buf, DataComponents dataComponents, boolean untrusted) { if (dataComponents == null) { MinecraftTypes.writeVarInt(buf, 0); MinecraftTypes.writeVarInt(buf, 0); @@ -482,10 +521,23 @@ public static void writeDataComponentPatch(ByteBuf buf, DataComponents dataCompo MinecraftTypes.writeVarInt(buf, i); MinecraftTypes.writeVarInt(buf, j); - for (DataComponent component : dataComponents.getDataComponents().values()) { - if (component.getValue() != null) { - MinecraftTypes.writeVarInt(buf, component.getType().getId()); - component.write(buf); + if (untrusted) { + for (DataComponent component : dataComponents.getDataComponents().values()) { + if (component.getValue() != null) { + MinecraftTypes.writeVarInt(buf, component.getType().getId()); + + ByteBuf buf2 = Unpooled.buffer(); + component.write(buf2); + MinecraftTypes.writeVarInt(buf, buf2.readableBytes()); + buf.writeBytes(buf2); + } + } + } else { + for (DataComponent component : dataComponents.getDataComponents().values()) { + if (component.getValue() != null) { + MinecraftTypes.writeVarInt(buf, component.getType().getId()); + component.write(buf); + } } } @@ -497,39 +549,103 @@ public static void writeDataComponentPatch(ByteBuf buf, DataComponents dataCompo } } - @NotNull - public static ItemStack readTradeItemStack(ByteBuf buf) { - int item = MinecraftTypes.readVarInt(buf); + public static HashedStack readHashedStack(ByteBuf buf) { + int id = MinecraftTypes.readVarInt(buf); int count = MinecraftTypes.readVarInt(buf); - int componentsLength = MinecraftTypes.readVarInt(buf); - Map, DataComponent> dataComponents = new HashMap<>(); - for (int i = 0; i < componentsLength; i++) { - DataComponentType dataComponentType = DataComponentTypes.from(MinecraftTypes.readVarInt(buf)); - DataComponent dataComponent = dataComponentType.readDataComponent(buf); - dataComponents.put(dataComponentType, dataComponent); + Map, Integer> addedComponents = new HashMap<>(); + int length = MinecraftTypes.readVarInt(buf); + for (int i = 0; i < length; i++) { + addedComponents.put(DataComponentTypes.from(MinecraftTypes.readVarInt(buf)), buf.readInt()); + } + + Set> removedComponents = new HashSet<>(); + length = MinecraftTypes.readVarInt(buf); + for (int i = 0; i < length; i++) { + removedComponents.add(DataComponentTypes.from(MinecraftTypes.readVarInt(buf))); } - return new ItemStack(item, count, new DataComponents(dataComponents)); + return new HashedStack(id, count, addedComponents, removedComponents); } - public static void writeTradeItemStack(ByteBuf buf, @NotNull ItemStack item) { - MinecraftTypes.writeVarInt(buf, item.getId()); - MinecraftTypes.writeVarInt(buf, item.getAmount()); + public static void writeHashedStack(ByteBuf buf, HashedStack hashedStack) { + MinecraftTypes.writeVarInt(buf, hashedStack.id()); + MinecraftTypes.writeVarInt(buf, hashedStack.count()); - DataComponents dataComponents = item.getDataComponentsPatch(); - if (dataComponents == null) { - MinecraftTypes.writeVarInt(buf, 0); - return; + MinecraftTypes.writeVarInt(buf, hashedStack.addedComponents().size()); + for (Map.Entry, Integer> entry : hashedStack.addedComponents().entrySet()) { + MinecraftTypes.writeVarInt(buf, entry.getKey().getId()); + buf.writeInt(entry.getValue()); } - MinecraftTypes.writeVarInt(buf, dataComponents.getDataComponents().size()); - for (DataComponent component : dataComponents.getDataComponents().values()) { - MinecraftTypes.writeVarInt(buf, component.getType().getId()); - component.write(buf); + MinecraftTypes.writeVarInt(buf, hashedStack.removedComponents().size()); + for (DataComponentType entry : hashedStack.removedComponents()) { + MinecraftTypes.writeVarInt(buf, entry.getId()); } } + public static VillagerTrade.ItemCost readItemCost(ByteBuf buf) { + int item = MinecraftTypes.readVarInt(buf); + int count = MinecraftTypes.readVarInt(buf); + return new VillagerTrade.ItemCost(item, count, MinecraftTypes.readExactComponentMatcher(buf)); + } + + public static void writeItemCost(ByteBuf buf, VillagerTrade.ItemCost itemCost) { + MinecraftTypes.writeVarInt(buf, itemCost.itemId()); + MinecraftTypes.writeVarInt(buf, itemCost.count()); + MinecraftTypes.writeExactComponentMatcher(buf, itemCost.components()); + } + + public static Map, DataComponent> readExactComponentMatcher(ByteBuf buf) { + Map, DataComponent> dataComponents = new HashMap<>(); + int length = MinecraftTypes.readVarInt(buf); + for (int i = 0; i < length; i++) { + DataComponentType type = DataComponentTypes.from(MinecraftTypes.readVarInt(buf)); + dataComponents.put(type, type.readDataComponent(buf)); + } + return dataComponents; + } + + public static void writeExactComponentMatcher(ByteBuf buf, Map, DataComponent> dataComponents) { + MinecraftTypes.writeVarInt(buf, dataComponents.size()); + for (Map.Entry, DataComponent> entry : dataComponents.entrySet()) { + MinecraftTypes.writeVarInt(buf, entry.getKey().getId()); + entry.getValue().write(buf); + } + } + + public static TestInstanceBlockEntity readTestBlockEntity(ByteBuf buf) { + Key test = MinecraftTypes.readNullable(buf, MinecraftTypes::readResourceLocation); + Vector3i size = MinecraftTypes.readVec3i(buf); + int rotation = MinecraftTypes.readVarInt(buf); + boolean ignoreEntities = buf.readBoolean(); + int status = MinecraftTypes.readVarInt(buf); + Component errorMessage = MinecraftTypes.readNullable(buf, MinecraftTypes::readComponent); + return new TestInstanceBlockEntity(test, size, rotation, ignoreEntities, status, errorMessage); + } + + public static void writeTestBlockEntity(ByteBuf buf, TestInstanceBlockEntity testBlockEntity) { + MinecraftTypes.writeNullable(buf, testBlockEntity.test(), MinecraftTypes::writeResourceLocation); + MinecraftTypes.writeVec3i(buf, testBlockEntity.size()); + MinecraftTypes.writeVarInt(buf, testBlockEntity.rotation()); + buf.writeBoolean(testBlockEntity.ignoreEntities()); + MinecraftTypes.writeVarInt(buf, testBlockEntity.status()); + MinecraftTypes.writeNullable(buf, testBlockEntity.errorMessage(), MinecraftTypes::writeComponent); + } + + public static Vector3i readVec3i(ByteBuf buf) { + int x = MinecraftTypes.readVarInt(buf); + int y = MinecraftTypes.readVarInt(buf); + int z = MinecraftTypes.readVarInt(buf); + return Vector3i.from(x, y, z); + } + + public static void writeVec3i(ByteBuf buf, Vector3i vec) { + MinecraftTypes.writeVarInt(buf, vec.getX()); + MinecraftTypes.writeVarInt(buf, vec.getY()); + MinecraftTypes.writeVarInt(buf, vec.getZ()); + } + public static Vector3i readPosition(ByteBuf buf) { long val = buf.readLong(); @@ -594,42 +710,22 @@ public static void writePose(ByteBuf buf, Pose pose) { MinecraftTypes.writeEnum(buf, pose); } - public static Holder readWolfVariant(ByteBuf buf) { - return MinecraftTypes.readHolder(buf, input -> { - Key wildTexture = MinecraftTypes.readResourceLocation(input); - Key tameTexture = MinecraftTypes.readResourceLocation(input); - Key angryTexture = MinecraftTypes.readResourceLocation(input); - Key biomeLocation = null; - int[] biomeHolders = null; - - int length = MinecraftTypes.readVarInt(input) - 1; - if (length == -1) { - biomeLocation = MinecraftTypes.readResourceLocation(input); - } else { - biomeHolders = new int[length]; - for (int j = 0; j < length; j++) { - biomeHolders[j] = MinecraftTypes.readVarInt(input); - } - } - return new WolfVariant(wildTexture, tameTexture, angryTexture, biomeLocation, biomeHolders); - }); + public static Holder readChickenVariant(ByteBuf buf) { + if (buf.readBoolean()) { + return Holder.ofId(MinecraftTypes.readVarInt(buf)); + } else { + return Holder.ofCustom(MinecraftTypes.readResourceLocation(buf)); + } } - public static void writeWolfVariant(ByteBuf buf, Holder variantHolder) { - MinecraftTypes.writeHolder(buf, variantHolder, (output, variant) -> { - MinecraftTypes.writeResourceLocation(output, variant.wildTexture()); - MinecraftTypes.writeResourceLocation(output, variant.tameTexture()); - MinecraftTypes.writeResourceLocation(output, variant.angryTexture()); - if (variant.biomeLocation() != null) { - MinecraftTypes.writeVarInt(output, 0); - MinecraftTypes.writeResourceLocation(output, variant.biomeLocation()); - } else { - MinecraftTypes.writeVarInt(output, variant.biomeHolders().length + 1); - for (int holder : variant.biomeHolders()) { - MinecraftTypes.writeVarInt(output, holder); - } - } - }); + public static void writeChickenVariant(ByteBuf buf, Holder variant) { + if (variant.isId()) { + buf.writeBoolean(true); + MinecraftTypes.writeVarInt(buf, variant.id()); + } else { + buf.writeBoolean(false); + MinecraftTypes.writeResourceLocation(buf, variant.custom()); + } } public static Holder readPaintingVariant(ByteBuf buf) { @@ -797,8 +893,8 @@ public static ParticleData readParticleData(ByteBuf buf, ParticleType type) { float scale = buf.readFloat(); yield new DustColorTransitionParticleData(color, scale, newColor); } - case ENTITY_EFFECT -> new EntityEffectParticleData(buf.readInt()); - case ITEM -> new ItemParticleData(MinecraftTypes.readOptionalItemStack(buf)); + case ENTITY_EFFECT, TINTED_LEAVES -> new ColorParticleData(buf.readInt()); + case ITEM -> new ItemParticleData(MinecraftTypes.readItemStack(buf)); case SCULK_CHARGE -> new SculkChargeParticleData(buf.readFloat()); case SHRIEK -> new ShriekParticleData(MinecraftTypes.readVarInt(buf)); case TRAIL -> new TrailParticleData(Vector3d.from(buf.readDouble(), buf.readDouble(), buf.readDouble()), buf.readInt(), MinecraftTypes.readVarInt(buf)); @@ -825,12 +921,12 @@ public static void writeParticleData(ByteBuf buf, ParticleType type, ParticleDat buf.writeFloat(dustData.getScale()); } case ENTITY_EFFECT -> { - EntityEffectParticleData entityEffectData = (EntityEffectParticleData) data; + ColorParticleData entityEffectData = (ColorParticleData) data; buf.writeInt(entityEffectData.getColor()); } case ITEM -> { ItemParticleData itemData = (ItemParticleData) data; - MinecraftTypes.writeOptionalItemStack(buf, itemData.getItemStack()); + MinecraftTypes.writeItemStack(buf, itemData.getItemStack()); } case SCULK_CHARGE -> { SculkChargeParticleData sculkData = (SculkChargeParticleData) data; @@ -1181,7 +1277,10 @@ public static SlotDisplay readSlotDisplay(ByteBuf buf) { case ITEM -> display = new ItemSlotDisplay(MinecraftTypes.readVarInt(buf)); case ITEM_STACK -> display = new ItemStackSlotDisplay(MinecraftTypes.readItemStack(buf)); case TAG -> display = new TagSlotDisplay(MinecraftTypes.readResourceLocation(buf)); - case SMITHING_TRIM -> display = new SmithingTrimDemoSlotDisplay(MinecraftTypes.readSlotDisplay(buf), MinecraftTypes.readSlotDisplay(buf), MinecraftTypes.readSlotDisplay(buf)); + case SMITHING_TRIM -> { + display = new SmithingTrimDemoSlotDisplay(MinecraftTypes.readSlotDisplay(buf), MinecraftTypes.readSlotDisplay(buf), + MinecraftTypes.readHolder(buf, ItemTypes::readTrimPattern)); + } case WITH_REMAINDER -> display = new WithRemainderSlotDisplay(MinecraftTypes.readSlotDisplay(buf), MinecraftTypes.readSlotDisplay(buf)); case COMPOSITE -> display = new CompositeSlotDisplay(MinecraftTypes.readList(buf, MinecraftTypes::readSlotDisplay)); default -> throw new IllegalStateException("Unexpected value: " + type); @@ -1200,7 +1299,7 @@ public static void writeSlotDisplay(ByteBuf buf, SlotDisplay display) { MinecraftTypes.writeSlotDisplay(buf, smithingSlotDisplay.base()); MinecraftTypes.writeSlotDisplay(buf, smithingSlotDisplay.material()); - MinecraftTypes.writeSlotDisplay(buf, smithingSlotDisplay.pattern()); + MinecraftTypes.writeHolder(buf, smithingSlotDisplay.pattern(), ItemTypes::writeTrimPattern); } case WITH_REMAINDER -> { WithRemainderSlotDisplay remainderSlotDisplay = (WithRemainderSlotDisplay) display; @@ -1216,15 +1315,11 @@ public static DataPalette readDataPalette(ByteBuf buf, PaletteType paletteType) int bitsPerEntry = buf.readByte() & 0xFF; Palette palette = MinecraftTypes.readPalette(buf, paletteType, bitsPerEntry); BitStorage storage; - if (!(palette instanceof SingletonPalette)) { - storage = new BitStorage(bitsPerEntry, paletteType.getStorageSize(), MinecraftTypes.readLongArray(buf)); - } else { - // Eat up - can be seen on Hypixel as of 1.19.0 - int length = MinecraftTypes.readVarInt(buf); - for (int i = 0; i < length; i++) { - buf.readLong(); - } + if (palette instanceof SingletonPalette) { storage = null; + } else { + storage = new BitStorage(bitsPerEntry, paletteType.getStorageSize()); + MinecraftTypes.readFixedSizeLongArray(buf, storage.getData()); } return new DataPalette(palette, storage, paletteType); @@ -1242,7 +1337,6 @@ public static void writeDataPalette(ByteBuf buf, DataPalette palette) { if (palette.getPalette() instanceof SingletonPalette) { buf.writeByte(0); // Bits per entry MinecraftTypes.writeVarInt(buf, palette.getPalette().idToState(0)); - MinecraftTypes.writeVarInt(buf, 0); // Data length return; } @@ -1257,7 +1351,7 @@ public static void writeDataPalette(ByteBuf buf, DataPalette palette) { } long[] data = palette.getStorage().getData(); - MinecraftTypes.writeLongArray(buf, data); + MinecraftTypes.writeFixedSizeLongArray(buf, data); } private static Palette readPalette(ByteBuf buf, PaletteType paletteType, int bitsPerEntry) { @@ -1346,6 +1440,19 @@ public static void writeProperty(ByteBuf buf, GameProfile.Property property) { MinecraftTypes.writeNullable(buf, property.getSignature(), MinecraftTypes::writeString); } + public static Sound readSound(ByteBuf buf) { + return MinecraftTypes.readById(buf, BuiltinSound::from, MinecraftTypes::readSoundEvent); + } + + public static void writeSound(ByteBuf buf, Sound sound) { + if (sound instanceof CustomSound) { + MinecraftTypes.writeVarInt(buf, 0); + MinecraftTypes.writeSoundEvent(buf, sound); + } else { + MinecraftTypes.writeVarInt(buf, ((BuiltinSound)sound).ordinal() + 1); + } + } + public static T readById(ByteBuf buf, IntFunction registry, Function custom) { int id = MinecraftTypes.readVarInt(buf); if (id == 0) { diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/command/CommandParser.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/command/CommandParser.java index 7d541705e..5115d7089 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/command/CommandParser.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/command/CommandParser.java @@ -48,6 +48,7 @@ public enum CommandParser { RESOURCE_OR_TAG_KEY, RESOURCE, RESOURCE_KEY, + RESOURCE_SELECTOR, TEMPLATE_MIRROR, TEMPLATE_ROTATION, HEIGHTMAP, diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/command/CommandType.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/command/CommandType.java index 2afb4ece6..31fffc6af 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/command/CommandType.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/command/CommandType.java @@ -8,6 +8,6 @@ public enum CommandType { private static final CommandType[] VALUES = values(); public static CommandType from(int id) { - return VALUES[id]; + return id >= 0 && id < VALUES.length ? VALUES[id] : VALUES[0]; } } diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/entity/EntityEvent.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/entity/EntityEvent.java index 21d9488e4..1a37060a6 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/entity/EntityEvent.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/entity/EntityEvent.java @@ -67,7 +67,9 @@ public enum EntityEvent { SNIFFER_MAKE_SOUND, ARMADILLO_PEEKING, LIVING_EQUIPMENT_BREAK_BODY, - SHAKE; + SHAKE, + DROWN_PARTICLES, + SADDLE_BREAK; private static final EntityEvent[] VALUES = values(); diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/entity/EquipmentSlot.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/entity/EquipmentSlot.java index 7f0b4ce54..5561301a7 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/entity/EquipmentSlot.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/entity/EquipmentSlot.java @@ -7,11 +7,26 @@ public enum EquipmentSlot { LEGGINGS, CHESTPLATE, HELMET, - BODY; + BODY, + SADDLE; private static final EquipmentSlot[] VALUES = values(); - public static EquipmentSlot from(int id) { + public static EquipmentSlot fromEnumOrdinal(int id) { return VALUES[id]; } + + public static EquipmentSlot fromId(int networkId) { + return switch (networkId) { + case 0 -> MAIN_HAND; + case 1 -> BOOTS; + case 2 -> LEGGINGS; + case 3 -> CHESTPLATE; + case 4 -> HELMET; + case 5 -> OFF_HAND; + case 6 -> BODY; + case 7 -> SADDLE; + default -> throw new IllegalStateException("Unexpected equipment slot id: " + networkId); + }; + } } diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/entity/metadata/MetadataTypes.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/entity/metadata/MetadataTypes.java index a2d8fec9d..ba43ef47a 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/entity/metadata/MetadataTypes.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/entity/metadata/MetadataTypes.java @@ -34,32 +34,36 @@ public class MetadataTypes { public static final LongMetadataType LONG = register(id -> new LongMetadataType(id, MinecraftTypes::readVarLong, MinecraftTypes::writeVarLong, LongEntityMetadata::new)); public static final FloatMetadataType FLOAT = register(id -> new FloatMetadataType(id, ByteBuf::readFloat, ByteBuf::writeFloat, FloatEntityMetadata::new)); public static final MetadataType STRING = register(id -> new MetadataType<>(id, MinecraftTypes::readString, MinecraftTypes::writeString, ObjectEntityMetadata::new)); - public static final MetadataType CHAT = register(id -> new MetadataType<>(id, MinecraftTypes::readComponent, MinecraftTypes::writeComponent, ObjectEntityMetadata::new)); - public static final MetadataType> OPTIONAL_CHAT = register(id -> new MetadataType<>(id, optionalReader(MinecraftTypes::readComponent), optionalWriter(MinecraftTypes::writeComponent), ObjectEntityMetadata::new)); - public static final MetadataType ITEM = register(id -> new MetadataType<>(id, MinecraftTypes::readOptionalItemStack, MinecraftTypes::writeOptionalItemStack, ObjectEntityMetadata::new)); + public static final MetadataType COMPONENT = register(id -> new MetadataType<>(id, MinecraftTypes::readComponent, MinecraftTypes::writeComponent, ObjectEntityMetadata::new)); + public static final MetadataType> OPTIONAL_COMPONENT = register(id -> new MetadataType<>(id, optionalReader(MinecraftTypes::readComponent), optionalWriter(MinecraftTypes::writeComponent), ObjectEntityMetadata::new)); + public static final MetadataType ITEM_STACK = register(id -> new MetadataType<>(id, MinecraftTypes::readOptionalItemStack, MinecraftTypes::writeOptionalItemStack, ObjectEntityMetadata::new)); public static final BooleanMetadataType BOOLEAN = register(id -> new BooleanMetadataType(id, ByteBuf::readBoolean, ByteBuf::writeBoolean, BooleanEntityMetadata::new)); - public static final MetadataType ROTATION = register(id -> new MetadataType<>(id, MinecraftTypes::readRotation, MinecraftTypes::writeRotation, ObjectEntityMetadata::new)); - public static final MetadataType POSITION = register(id -> new MetadataType<>(id, MinecraftTypes::readPosition, MinecraftTypes::writePosition, ObjectEntityMetadata::new)); - public static final MetadataType> OPTIONAL_POSITION = register(id -> new MetadataType<>(id, optionalReader(MinecraftTypes::readPosition), optionalWriter(MinecraftTypes::writePosition), ObjectEntityMetadata::new)); + public static final MetadataType ROTATIONS = register(id -> new MetadataType<>(id, MinecraftTypes::readRotation, MinecraftTypes::writeRotation, ObjectEntityMetadata::new)); + public static final MetadataType BLOCK_POS = register(id -> new MetadataType<>(id, MinecraftTypes::readPosition, MinecraftTypes::writePosition, ObjectEntityMetadata::new)); + public static final MetadataType> OPTIONAL_BLOCK_POS = register(id -> new MetadataType<>(id, optionalReader(MinecraftTypes::readPosition), optionalWriter(MinecraftTypes::writePosition), ObjectEntityMetadata::new)); public static final MetadataType DIRECTION = register(id -> new MetadataType<>(id, MinecraftTypes::readDirection, MinecraftTypes::writeDirection, ObjectEntityMetadata::new)); - public static final MetadataType> OPTIONAL_UUID = register(id -> new MetadataType<>(id, optionalReader(MinecraftTypes::readUUID), optionalWriter(MinecraftTypes::writeUUID), ObjectEntityMetadata::new)); + public static final MetadataType> OPTIONAL_LIVING_ENTITY_REFERENCE = register(id -> new MetadataType<>(id, optionalReader(MinecraftTypes::readUUID), optionalWriter(MinecraftTypes::writeUUID), ObjectEntityMetadata::new)); public static final IntMetadataType BLOCK_STATE = register(id -> new IntMetadataType(id, MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntEntityMetadata::new)); public static final IntMetadataType OPTIONAL_BLOCK_STATE = register(id -> new IntMetadataType(id, MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntEntityMetadata::new)); - public static final MetadataType NBT_TAG = register(id -> new MetadataType<>(id, MinecraftTypes::readCompoundTag, MinecraftTypes::writeAnyTag, ObjectEntityMetadata::new)); + public static final MetadataType COMPOUND_TAG = register(id -> new MetadataType<>(id, MinecraftTypes::readCompoundTag, MinecraftTypes::writeAnyTag, ObjectEntityMetadata::new)); public static final MetadataType PARTICLE = register(id -> new MetadataType<>(id, MinecraftTypes::readParticle, MinecraftTypes::writeParticle, ObjectEntityMetadata::new)); public static final MetadataType> PARTICLES = register(id -> new MetadataType<>(id, listReader(MinecraftTypes::readParticle), listWriter(MinecraftTypes::writeParticle), ObjectEntityMetadata::new)); public static final MetadataType VILLAGER_DATA = register(id -> new MetadataType<>(id, MinecraftTypes::readVillagerData, MinecraftTypes::writeVillagerData, ObjectEntityMetadata::new)); - public static final OptionalIntMetadataType OPTIONAL_VARINT = register(id -> new OptionalIntMetadataType(id, ObjectEntityMetadata::new)); + public static final OptionalIntMetadataType OPTIONAL_UNSIGNED_INT = register(id -> new OptionalIntMetadataType(id, ObjectEntityMetadata::new)); public static final MetadataType POSE = register(id -> new MetadataType<>(id, MinecraftTypes::readPose, MinecraftTypes::writePose, ObjectEntityMetadata::new)); public static final IntMetadataType CAT_VARIANT = register(id -> new IntMetadataType(id, MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntEntityMetadata::new)); - public static final MetadataType> WOLF_VARIANT = register(id -> new MetadataType<>(id, MinecraftTypes::readWolfVariant, MinecraftTypes::writeWolfVariant, ObjectEntityMetadata::new)); + public static final IntMetadataType COW_VARIANT = register(id -> new IntMetadataType(id, MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntEntityMetadata::new)); + public static final IntMetadataType WOLF_VARIANT = register(id -> new IntMetadataType(id, MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntEntityMetadata::new)); + public static final IntMetadataType WOLF_SOUND_VARIANT = register(id -> new IntMetadataType(id, MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntEntityMetadata::new)); public static final IntMetadataType FROG_VARIANT = register(id -> new IntMetadataType(id, MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntEntityMetadata::new)); + public static final IntMetadataType PIG_VARIANT = register(id -> new IntMetadataType(id, MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntEntityMetadata::new)); + public static final IntMetadataType CHICKEN_VARIANT = register(id -> new IntMetadataType(id, MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntEntityMetadata::new)); public static final MetadataType> OPTIONAL_GLOBAL_POS = register(id -> new MetadataType<>(id, optionalReader(MinecraftTypes::readGlobalPos), optionalWriter(MinecraftTypes::writeGlobalPos), ObjectEntityMetadata::new)); public static final MetadataType> PAINTING_VARIANT = register(id -> new MetadataType<>(id, MinecraftTypes::readPaintingVariant, MinecraftTypes::writePaintingVariant, ObjectEntityMetadata::new)); public static final MetadataType SNIFFER_STATE = register(id -> new MetadataType<>(id, MinecraftTypes::readSnifferState, MinecraftTypes::writeSnifferState, ObjectEntityMetadata::new)); public static final MetadataType ARMADILLO_STATE = register(id -> new MetadataType<>(id, MinecraftTypes::readArmadilloState, MinecraftTypes::writeArmadilloState, ObjectEntityMetadata::new)); public static final MetadataType VECTOR3 = register(id -> new MetadataType<>(id, MinecraftTypes::readRotation, MinecraftTypes::writeRotation, ObjectEntityMetadata::new)); - public static final MetadataType QUATERNION =register(id -> new MetadataType<>(id, MinecraftTypes::readQuaternion, MinecraftTypes::writeQuaternion, ObjectEntityMetadata::new)); + public static final MetadataType QUATERNION = register(id -> new MetadataType<>(id, MinecraftTypes::readQuaternion, MinecraftTypes::writeQuaternion, ObjectEntityMetadata::new)); public static > T register(Int2ObjectFunction factory) { T value = factory.apply(VALUES.size()); diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/entity/metadata/WolfVariant.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/entity/metadata/WolfVariant.java deleted file mode 100644 index f9da4024d..000000000 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/entity/metadata/WolfVariant.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.geysermc.mcprotocollib.protocol.data.game.entity.metadata; - -import net.kyori.adventure.key.Key; -import org.jetbrains.annotations.Nullable; - -public record WolfVariant(Key wildTexture, Key tameTexture, Key angryTexture, - @Nullable Key biomeLocation, int @Nullable [] biomeHolders) { -} 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 18474d900..d7f3603e7 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 @@ -102,7 +102,8 @@ public enum EntityType { PIGLIN_BRUTE, PILLAGER, POLAR_BEAR, - POTION(true), + SPLASH_POTION(true), + LINGERING_POTION(true), PUFFERFISH, RABBIT, RAVAGER, diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/inventory/ContainerActionType.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/inventory/ContainerActionType.java index 9c1990075..955491f3f 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/inventory/ContainerActionType.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/inventory/ContainerActionType.java @@ -12,6 +12,6 @@ public enum ContainerActionType { private static final ContainerActionType[] VALUES = values(); public static ContainerActionType from(int id) { - return VALUES[id]; + return id >= 0 && id < VALUES.length ? VALUES[id] : VALUES[0]; } } diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/inventory/VillagerTrade.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/inventory/VillagerTrade.java index 3c9c13664..c237e8e50 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/inventory/VillagerTrade.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/inventory/VillagerTrade.java @@ -5,18 +5,25 @@ import lombok.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponent; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; + +import java.util.Map; @Data @AllArgsConstructor public class VillagerTrade { - private final @NonNull ItemStack firstInput; - private final @Nullable ItemStack secondInput; - private final @Nullable ItemStack output; - private final boolean tradeDisabled; - private final int numUses; + private final @NonNull ItemCost itemCostA; + private final @NonNull ItemStack result; + private final @Nullable ItemCost itemCostB; + private final boolean outOfStock; + private final int uses; private final int maxUses; private final int xp; - private final int specialPrice; + private final int specialPriceDiff; private final float priceMultiplier; private final int demand; + + public record ItemCost(int itemId, int count, Map, DataComponent> components) { + } } diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/HashedStack.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/HashedStack.java new file mode 100644 index 000000000..d7353b1e3 --- /dev/null +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/HashedStack.java @@ -0,0 +1,9 @@ +package org.geysermc.mcprotocollib.protocol.data.game.item; + +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; + +import java.util.Map; +import java.util.Set; + +public record HashedStack(int id, int count, Map, Integer> addedComponents, Set> removedComponents) { +} diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/AdventureModePredicate.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/AdventureModePredicate.java index d60e7bd6e..b1f2b6192 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/AdventureModePredicate.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/AdventureModePredicate.java @@ -12,11 +12,9 @@ @Builder(toBuilder = true) public class AdventureModePredicate { private final List predicates; - private final boolean showInTooltip; - public AdventureModePredicate(List predicates, boolean showInTooltip) { + public AdventureModePredicate(List predicates) { this.predicates = List.copyOf(predicates); - this.showInTooltip = showInTooltip; } @Data @@ -25,11 +23,13 @@ public static class BlockPredicate { private final @Nullable HolderSet blocks; private final @Nullable List properties; private final @Nullable NbtMap nbt; + private final DataComponentMatchers components; - public BlockPredicate(@Nullable HolderSet blocks, @Nullable List properties, @Nullable NbtMap nbt) { + public BlockPredicate(@Nullable HolderSet blocks, @Nullable List properties, @Nullable NbtMap nbt, DataComponentMatchers components) { this.blocks = blocks; this.properties = properties != null ? List.copyOf(properties) : null; this.nbt = nbt; + this.components = components; } } diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/ArmorTrim.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/ArmorTrim.java index b9f7a0a27..7a379d899 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/ArmorTrim.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/ArmorTrim.java @@ -8,19 +8,18 @@ import java.util.Map; @Builder(toBuilder = true) -public record ArmorTrim(Holder material, Holder pattern, boolean showInTooltip) { +public record ArmorTrim(Holder material, Holder pattern) { @Builder(toBuilder = true) - public record TrimMaterial(String assetName, int ingredientId, Map overrideArmorAssets, Component description) { - public TrimMaterial(String assetName, int ingredientId, Map overrideArmorAssets, Component description) { - this.assetName = assetName; - this.ingredientId = ingredientId; - this.overrideArmorAssets = Map.copyOf(overrideArmorAssets); + public record TrimMaterial(String assetBase, Map assetOverrides, Component description) { + public TrimMaterial(String assetBase, Map assetOverrides, Component description) { + this.assetBase = assetBase; + this.assetOverrides = Map.copyOf(assetOverrides); this.description = description; } } @Builder(toBuilder = true) - public record TrimPattern(Key assetId, int templateItemId, Component description, boolean decal) { + public record TrimPattern(Key assetId, Component description, boolean decal) { } } diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/BlocksAttacks.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/BlocksAttacks.java new file mode 100644 index 000000000..c6d4323f5 --- /dev/null +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/BlocksAttacks.java @@ -0,0 +1,31 @@ +package org.geysermc.mcprotocollib.protocol.data.game.item.component; + +import lombok.Builder; +import net.kyori.adventure.key.Key; +import org.geysermc.mcprotocollib.protocol.data.game.level.sound.Sound; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +@Builder(toBuilder = true) +public record BlocksAttacks(float blockDelaySeconds, float disableCooldownScale, List damageReductions, + ItemDamageFunction itemDamage, @Nullable Key bypassedBy, @Nullable Sound blockSound, @Nullable Sound disableSound) { + public BlocksAttacks(float blockDelaySeconds, float disableCooldownScale, List damageReductions, + ItemDamageFunction itemDamage, @Nullable Key bypassedBy, @Nullable Sound blockSound, @Nullable Sound disableSound) { + this.blockDelaySeconds = blockDelaySeconds; + this.disableCooldownScale = disableCooldownScale; + this.damageReductions = List.copyOf(damageReductions); + this.itemDamage = itemDamage; + this.bypassedBy = bypassedBy; + this.blockSound = blockSound; + this.disableSound = disableSound; + } + + @Builder(toBuilder = true) + public record DamageReduction(float horizontalBlockingAngle, @Nullable HolderSet type, float base, float factor) { + } + + @Builder(toBuilder = true) + public record ItemDamageFunction(float threshold, float base, float factor) { + } +} diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/Consumable.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/Consumable.java index 0100fb875..3f01218cc 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/Consumable.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/Consumable.java @@ -25,7 +25,8 @@ public enum ItemUseAnimation { CROSSBOW, SPYGLASS, TOOT_HORN, - BRUSH; + BRUSH, + BUNDLE; private static final ItemUseAnimation[] VALUES = values(); diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/DataComponentMatchers.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/DataComponentMatchers.java new file mode 100644 index 000000000..6e76704ee --- /dev/null +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/DataComponentMatchers.java @@ -0,0 +1,9 @@ +package org.geysermc.mcprotocollib.protocol.data.game.item.component; + +import lombok.Builder; + +import java.util.Map; + +@Builder(toBuilder = true) +public record DataComponentMatchers(Map, DataComponent> exactMatchers, int[] partialMatchers) { +} diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/DataComponentTypes.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/DataComponentTypes.java index 250f548d8..07878074e 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/DataComponentTypes.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/DataComponentTypes.java @@ -10,10 +10,12 @@ import org.geysermc.mcprotocollib.auth.GameProfile; import org.geysermc.mcprotocollib.protocol.codec.MinecraftTypes; import org.geysermc.mcprotocollib.protocol.data.game.Holder; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.PaintingVariant; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import org.geysermc.mcprotocollib.protocol.data.game.item.component.type.BooleanDataComponent; import org.geysermc.mcprotocollib.protocol.data.game.item.component.type.IntDataComponent; import org.geysermc.mcprotocollib.protocol.data.game.item.component.type.ObjectDataComponent; +import org.geysermc.mcprotocollib.protocol.data.game.level.sound.Sound; import java.util.ArrayList; import java.util.List; @@ -26,7 +28,7 @@ public class DataComponentTypes { public static final IntComponentType MAX_STACK_SIZE = register(id -> new IntComponentType(id, "max_stack_size", MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntDataComponent::new)); public static final IntComponentType MAX_DAMAGE = register(id -> new IntComponentType(id, "max_damage", MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntDataComponent::new)); public static final IntComponentType DAMAGE = register(id -> new IntComponentType(id, "damage", MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntDataComponent::new)); - public static final DataComponentType UNBREAKABLE = register(id -> new DataComponentType<>(id, "unbreakable", ItemTypes::readUnbreakable, ItemTypes::writeUnbreakable, ObjectDataComponent::new)); + public static final DataComponentType UNBREAKABLE = register(id -> new DataComponentType<>(id, "unbreakable", unitReader(), unitWriter(), ObjectDataComponent::new)); public static final DataComponentType CUSTOM_NAME = register(id -> new DataComponentType<>(id, "custom_name", MinecraftTypes::readComponent, MinecraftTypes::writeComponent, ObjectDataComponent::new)); public static final DataComponentType ITEM_NAME = register(id -> new DataComponentType<>(id, "item_name", MinecraftTypes::readComponent, MinecraftTypes::writeComponent, ObjectDataComponent::new)); public static final DataComponentType ITEM_MODEL = register(id -> new DataComponentType<>(id, "item_model", MinecraftTypes::readResourceLocation, MinecraftTypes::writeResourceLocation, ObjectDataComponent::new)); @@ -37,26 +39,27 @@ public class DataComponentTypes { public static final DataComponentType CAN_BREAK = register(id -> new DataComponentType<>(id, "can_break", ItemTypes::readAdventureModePredicate, ItemTypes::writeAdventureModePredicate, ObjectDataComponent::new)); public static final DataComponentType ATTRIBUTE_MODIFIERS = register(id -> new DataComponentType<>(id, "attribute_modifiers", ItemTypes::readItemAttributeModifiers, ItemTypes::writeItemAttributeModifiers, ObjectDataComponent::new)); public static final DataComponentType CUSTOM_MODEL_DATA = register(id -> new DataComponentType<>(id, "custom_model_data", ItemTypes::readCustomModelData, ItemTypes::writeCustomModelData, ObjectDataComponent::new)); - public static final DataComponentType HIDE_ADDITIONAL_TOOLTIP = register(id -> new DataComponentType<>(id, "hide_additional_tooltip", unitReader(), unitWriter(), ObjectDataComponent::new)); - public static final DataComponentType HIDE_TOOLTIP = register(id -> new DataComponentType<>(id, "hide_tooltip", unitReader(), unitWriter(), ObjectDataComponent::new)); + public static final DataComponentType TOOLTIP_DISPLAY = register(id -> new DataComponentType<>(id, "tooltip_display", ItemTypes::readTooltipDisplay, ItemTypes::writeTooltipDisplay, ObjectDataComponent::new)); public static final IntComponentType REPAIR_COST = register(id -> new IntComponentType(id, "repair_cost", MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntDataComponent::new)); public static final DataComponentType CREATIVE_SLOT_LOCK = register(id -> new DataComponentType<>(id, "creative_slot_lock", unitReader(), unitWriter(), ObjectDataComponent::new)); public static final BooleanComponentType ENCHANTMENT_GLINT_OVERRIDE = register(id -> new BooleanComponentType(id, "enchantment_glint_override", ByteBuf::readBoolean, ByteBuf::writeBoolean, BooleanDataComponent::new)); - public static final DataComponentType INTANGIBLE_PROJECTILE = register(id -> new DataComponentType<>(id, "intangible_projectile", MinecraftTypes::readCompoundTag, MinecraftTypes::writeAnyTag, ObjectDataComponent::new)); + public static final DataComponentType INTANGIBLE_PROJECTILE = register(id -> new DataComponentType<>(id, "intangible_projectile", emptyNbtReader(), emptyNbtWriter(), ObjectDataComponent::new)); public static final DataComponentType FOOD = register(id -> new DataComponentType<>(id, "food", ItemTypes::readFoodProperties, ItemTypes::writeFoodProperties, ObjectDataComponent::new)); public static final DataComponentType CONSUMABLE = register(id -> new DataComponentType<>(id, "consumable", ItemTypes::readConsumable, ItemTypes::writeConsumable, ObjectDataComponent::new)); public static final DataComponentType USE_REMAINDER = register(id -> new DataComponentType<>(id, "use_remainder", MinecraftTypes::readItemStack, MinecraftTypes::writeItemStack, ObjectDataComponent::new)); public static final DataComponentType USE_COOLDOWN = register(id -> new DataComponentType<>(id, "use_cooldown", ItemTypes::readUseCooldown, ItemTypes::writeUseCooldown, ObjectDataComponent::new)); public static final DataComponentType DAMAGE_RESISTANT = register(id -> new DataComponentType<>(id, "damage_resistant", MinecraftTypes::readResourceLocation, MinecraftTypes::writeResourceLocation, ObjectDataComponent::new)); public static final DataComponentType TOOL = register(id -> new DataComponentType<>(id, "tool", ItemTypes::readToolData, ItemTypes::writeToolData, ObjectDataComponent::new)); + public static final DataComponentType WEAPON = register(id -> new DataComponentType<>(id, "weapon", ItemTypes::readWeapon, ItemTypes::writeWeapon, ObjectDataComponent::new)); public static final IntComponentType ENCHANTABLE = register(id -> new IntComponentType(id, "enchantable", MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntDataComponent::new)); public static final DataComponentType EQUIPPABLE = register(id -> new DataComponentType<>(id, "equippable", ItemTypes::readEquippable, ItemTypes::writeEquippable, ObjectDataComponent::new)); public static final DataComponentType REPAIRABLE = register(id -> new DataComponentType<>(id, "repairable", MinecraftTypes::readHolderSet, MinecraftTypes::writeHolderSet, ObjectDataComponent::new)); public static final DataComponentType GLIDER = register(id -> new DataComponentType<>(id, "glider", unitReader(), unitWriter(), ObjectDataComponent::new)); public static final DataComponentType TOOLTIP_STYLE = register(id -> new DataComponentType<>(id, "tooltip_style", MinecraftTypes::readResourceLocation, MinecraftTypes::writeResourceLocation, ObjectDataComponent::new)); public static final DataComponentType> DEATH_PROTECTION = register(id -> new DataComponentType<>(id, "death_protection", listReader(ItemTypes::readConsumeEffect), listWriter(ItemTypes::writeConsumeEffect), ObjectDataComponent::new)); + public static final DataComponentType BLOCKS_ATTACKS = register(id -> new DataComponentType<>(id, "blocks_attacks", ItemTypes::readBlocksAttacks, ItemTypes::writeBlocksAttacks, ObjectDataComponent::new)); public static final DataComponentType STORED_ENCHANTMENTS = register(id -> new DataComponentType<>(id, "stored_enchantments", ItemTypes::readItemEnchantments, ItemTypes::writeItemEnchantments, ObjectDataComponent::new)); - public static final DataComponentType DYED_COLOR = register(id -> new DataComponentType<>(id, "dyed_color", ItemTypes::readDyedItemColor, ItemTypes::writeDyedItemColor, ObjectDataComponent::new)); + public static final IntComponentType DYED_COLOR = register(id -> new IntComponentType(id, "dyed_color", ByteBuf::readInt, ByteBuf::writeInt, IntDataComponent::new)); public static final IntComponentType MAP_COLOR = register(id -> new IntComponentType(id, "map_color", ByteBuf::readInt, ByteBuf::writeInt, IntDataComponent::new)); public static final IntComponentType MAP_ID = register(id -> new IntComponentType(id, "map_id", MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntDataComponent::new)); public static final DataComponentType MAP_DECORATIONS = register(id -> new DataComponentType<>(id, "map_decorations", MinecraftTypes::readCompoundTag, MinecraftTypes::writeAnyTag, ObjectDataComponent::new)); @@ -64,6 +67,7 @@ public class DataComponentTypes { public static final DataComponentType> CHARGED_PROJECTILES = register(id -> new DataComponentType<>(id, "charged_projectiles", listReader(MinecraftTypes::readItemStack), listWriter(MinecraftTypes::writeItemStack), ObjectDataComponent::new)); public static final DataComponentType> BUNDLE_CONTENTS = register(id -> new DataComponentType<>(id, "bundle_contents", listReader(MinecraftTypes::readItemStack), listWriter(MinecraftTypes::writeItemStack), ObjectDataComponent::new)); public static final DataComponentType POTION_CONTENTS = register(id -> new DataComponentType<>(id, "potion_contents", ItemTypes::readPotionContents, ItemTypes::writePotionContents, ObjectDataComponent::new)); + public static final DataComponentType POTION_DURATION_SCALE = register(id -> new DataComponentType<>(id, "potion_duration_scale", ByteBuf::readFloat, ByteBuf::writeFloat, ObjectDataComponent::new)); public static final DataComponentType> SUSPICIOUS_STEW_EFFECTS = register(id -> new DataComponentType<>(id, "suspicious_stew_effects", listReader(ItemTypes::readStewEffect), listWriter(ItemTypes::writeStewEffect), ObjectDataComponent::new)); public static final DataComponentType WRITABLE_BOOK_CONTENT = register(id -> new DataComponentType<>(id, "writable_book_content", ItemTypes::readWritableBookContent, ItemTypes::writeWritableBookContent, ObjectDataComponent::new)); public static final DataComponentType WRITTEN_BOOK_CONTENT = register(id -> new DataComponentType<>(id, "written_book_content", ItemTypes::readWrittenBookContent, ItemTypes::writeWrittenBookContent, ObjectDataComponent::new)); @@ -72,9 +76,11 @@ public class DataComponentTypes { public static final DataComponentType ENTITY_DATA = register(id -> new DataComponentType<>(id, "entity_data", MinecraftTypes::readCompoundTag, MinecraftTypes::writeAnyTag, ObjectDataComponent::new)); public static final DataComponentType BUCKET_ENTITY_DATA = register(id -> new DataComponentType<>(id, "bucket_entity_data", MinecraftTypes::readCompoundTag, MinecraftTypes::writeAnyTag, ObjectDataComponent::new)); public static final DataComponentType BLOCK_ENTITY_DATA = register(id -> new DataComponentType<>(id, "block_entity_data", MinecraftTypes::readCompoundTag, MinecraftTypes::writeAnyTag, ObjectDataComponent::new)); - public static final DataComponentType> INSTRUMENT = register(id -> new DataComponentType<>(id, "instrument", ItemTypes::readInstrument, ItemTypes::writeInstrument, ObjectDataComponent::new)); + public static final DataComponentType INSTRUMENT = register(id -> new DataComponentType<>(id, "instrument", ItemTypes::readInstrumentComponent, ItemTypes::writeInstrumentComponent, ObjectDataComponent::new)); + public static final DataComponentType PROVIDES_TRIM_MATERIAL = register(id -> new DataComponentType<>(id, "provides_trim_material", ItemTypes::readProvidesTrimMaterial, ItemTypes::writeProvidesTrimMaterial, ObjectDataComponent::new)); public static final IntComponentType OMINOUS_BOTTLE_AMPLIFIER = register(id -> new IntComponentType(id, "ominous_bottle_amplifier", MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntDataComponent::new)); public static final DataComponentType JUKEBOX_PLAYABLE = register(id -> new DataComponentType<>(id, "jukebox_playable", ItemTypes::readJukeboxPlayable, ItemTypes::writeJukeboxPlayable, ObjectDataComponent::new)); + public static final DataComponentType PROVIDES_BANNER_PATTERNS = register(id -> new DataComponentType<>(id, "provides_banner_patterns", MinecraftTypes::readResourceLocation, MinecraftTypes::writeResourceLocation, ObjectDataComponent::new)); public static final DataComponentType> RECIPES = register(id -> new DataComponentType<>(id, "recipes", ItemTypes::readRecipes, ItemTypes::writeRecipes, ObjectDataComponent::new)); public static final DataComponentType LODESTONE_TRACKER = register(id -> new DataComponentType<>(id, "lodestone_tracker", ItemTypes::readLodestoneTarget, ItemTypes::writeLodestoneTarget, ObjectDataComponent::new)); public static final DataComponentType FIREWORK_EXPLOSION = register(id -> new DataComponentType<>(id, "firework_explosion", ItemTypes::readFireworkExplosion, ItemTypes::writeFireworkExplosion, ObjectDataComponent::new)); @@ -89,6 +95,31 @@ public class DataComponentTypes { public static final DataComponentType> BEES = register(id -> new DataComponentType<>(id, "bees", listReader(ItemTypes::readBeehiveOccupant), listWriter(ItemTypes::writeBeehiveOccupant), ObjectDataComponent::new)); public static final DataComponentType LOCK = register(id -> new DataComponentType<>(id, "lock", MinecraftTypes::readCompoundTag, MinecraftTypes::writeAnyTag, ObjectDataComponent::new)); public static final DataComponentType CONTAINER_LOOT = register(id -> new DataComponentType<>(id, "container_loot", MinecraftTypes::readCompoundTag, MinecraftTypes::writeAnyTag, ObjectDataComponent::new)); + public static final DataComponentType BREAK_SOUND = register(id -> new DataComponentType<>(id, "break_sound", MinecraftTypes::readSound, MinecraftTypes::writeSound, ObjectDataComponent::new)); + public static final IntComponentType VILLAGER_VARIANT = register(id -> new IntComponentType(id, "villager/variant", MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntDataComponent::new)); + public static final IntComponentType WOLF_VARIANT = register(id -> new IntComponentType(id, "wolf/variant", MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntDataComponent::new)); + public static final IntComponentType WOLF_SOUND_VARIANT = register(id -> new IntComponentType(id, "wolf/sound_variant", MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntDataComponent::new)); + public static final IntComponentType WOLF_COLLAR = register(id -> new IntComponentType(id, "wolf/collar", MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntDataComponent::new)); + public static final IntComponentType FOX_VARIANT = register(id -> new IntComponentType(id, "fox/variant", MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntDataComponent::new)); + public static final IntComponentType SALMON_SIZE = register(id -> new IntComponentType(id, "salmon/size", MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntDataComponent::new)); + public static final IntComponentType PARROT_VARIANT = register(id -> new IntComponentType(id, "parrot/variant", MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntDataComponent::new)); + public static final IntComponentType TROPICAL_FISH_PATTERN = register(id -> new IntComponentType(id, "tropical_fish/pattern", MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntDataComponent::new)); + public static final IntComponentType TROPICAL_FISH_BASE_COLOR = register(id -> new IntComponentType(id, "tropical_fish/base_color", MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntDataComponent::new)); + public static final IntComponentType TROPICAL_FISH_PATTERN_COLOR = register(id -> new IntComponentType(id, "tropical_fish/pattern_color", MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntDataComponent::new)); + public static final IntComponentType MOOSHROOM_VARIANT = register(id -> new IntComponentType(id, "mooshroom/variant", MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntDataComponent::new)); + public static final IntComponentType RABBIT_VARIANT = register(id -> new IntComponentType(id, "rabbit/variant", MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntDataComponent::new)); + public static final IntComponentType PIG_VARIANT = register(id -> new IntComponentType(id, "pig/variant", MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntDataComponent::new)); + public static final IntComponentType COW_VARIANT = register(id -> new IntComponentType(id, "cow/variant", MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntDataComponent::new)); + public static final DataComponentType> CHICKEN_VARIANT = register(id -> new DataComponentType<>(id, "chicken/variant", MinecraftTypes::readChickenVariant, MinecraftTypes::writeChickenVariant, ObjectDataComponent::new)); + public static final IntComponentType FROG_VARIANT = register(id -> new IntComponentType(id, "frog/variant", MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntDataComponent::new)); + public static final IntComponentType HORSE_VARIANT = register(id -> new IntComponentType(id, "horse/variant", MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntDataComponent::new)); + public static final DataComponentType> PAINTING_VARIANT = register(id -> new DataComponentType<>(id, "painting/variant", MinecraftTypes::readPaintingVariant, MinecraftTypes::writePaintingVariant, ObjectDataComponent::new)); + public static final IntComponentType LLAMA_VARIANT = register(id -> new IntComponentType(id, "llama/variant", MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntDataComponent::new)); + public static final IntComponentType AXOLOTL_VARIANT = register(id -> new IntComponentType(id, "axolotl/variant", MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntDataComponent::new)); + public static final IntComponentType CAT_VARIANT = register(id -> new IntComponentType(id, "cat/variant", MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntDataComponent::new)); + public static final IntComponentType CAT_COLLAR = register(id -> new IntComponentType(id, "cat/collar", MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntDataComponent::new)); + public static final IntComponentType SHEEP_COLOR = register(id -> new IntComponentType(id, "sheep/color", MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntDataComponent::new)); + public static final IntComponentType SHULKER_COLOR = register(id -> new IntComponentType(id, "shulker/color", MinecraftTypes::readVarInt, MinecraftTypes::writeVarInt, IntDataComponent::new)); public static > T register(Int2ObjectFunction factory) { T value = factory.apply(VALUES.size()); @@ -126,6 +157,17 @@ private static DataComponentType.Writer unitWriter() { }; } + private static DataComponentType.Reader emptyNbtReader() { + return (input) -> { + MinecraftTypes.readAnyTag(input); + return Unit.INSTANCE; + }; + } + + private static DataComponentType.Writer emptyNbtWriter() { + return (output, value) -> MinecraftTypes.writeAnyTag(output, NbtMap.EMPTY); + } + public static DataComponentType read(ByteBuf in) { int id = MinecraftTypes.readVarInt(in); if (id >= VALUES.size()) { @@ -139,6 +181,10 @@ public static DataComponentType from(int id) { return VALUES.get(id); } + public static DataComponentType fromKey(Key key) { + return VALUES.stream().filter(component -> component.getKey().equals(key)).findFirst().orElse(null); + } + public static int size() { return VALUES.size(); } diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/DataComponents.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/DataComponents.java index 5fba63e13..55151fb99 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/DataComponents.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/DataComponents.java @@ -2,12 +2,22 @@ import lombok.AllArgsConstructor; import lombok.Data; -import lombok.NonNull; import org.jetbrains.annotations.Nullable; import java.util.HashMap; import java.util.Map; +/** + * Wrapper around a map of data components and their respective values. + * + *

This map can either be a complete data component map, or a data component patch to another map. The meaning of {@code null} values in the map depends on if the map + * is a patch or full map. If the map:

+ * + *
    + *
  • Is a full map, {@code null} means an absence of the component in the map. {@link DataComponents#put(DataComponentType, Object)} should not be used with {@code null} values, rather {@link DataComponents#remove(DataComponentType)} should be used.
  • + *
  • Is a patch, {@code null} can mean an absence of the component in the patch, or that the component should be removed from a map the patch is applied to. Use {@link DataComponents#contains(DataComponentType)}, which returns {@code true} for the latter, to check which is the case.
  • + *
+ */ @Data @AllArgsConstructor public class DataComponents { @@ -25,8 +35,13 @@ public T getOrDefault(DataComponentType type, T def) { return value != null ? value : def; } - public void put(DataComponentType type, @NonNull T value) { - if (type instanceof IntComponentType intType) { + /** + * @param value should only be {@code null} if this map is a patch to another map and specifying the removal of the specific component. + */ + public void put(DataComponentType type, @Nullable T value) { + if (value == null) { + dataComponents.put(type, type.readNullDataComponent()); + } else if (type instanceof IntComponentType intType) { dataComponents.put(intType, intType.primitiveFactory.createPrimitive(intType, (Integer) value)); } else if (type instanceof BooleanComponentType boolType) { dataComponents.put(boolType, boolType.primitiveFactory.createPrimitive(boolType, (Boolean) value)); @@ -35,6 +50,16 @@ public void put(DataComponentType type, @NonNull T value) { } } + public boolean contains(DataComponentType component) { + return dataComponents.containsKey(component); + } + + @SuppressWarnings("unchecked") + public @Nullable T remove(DataComponentType component) { + DataComponent removed = (DataComponent) dataComponents.remove(component); + return removed == null ? null : removed.getValue(); + } + public DataComponents clone() { return new DataComponents(new HashMap<>(dataComponents)); } diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/DyedItemColor.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/DyedItemColor.java deleted file mode 100644 index e0a2b72db..000000000 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/DyedItemColor.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.geysermc.mcprotocollib.protocol.data.game.item.component; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; - -@Data -@AllArgsConstructor -@Builder(toBuilder = true) -public class DyedItemColor { - private final int rgb; - private final boolean showInTooltip; -} diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/Equippable.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/Equippable.java index 208759d81..c5171632f 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/Equippable.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/Equippable.java @@ -8,5 +8,6 @@ @Builder(toBuilder = true) public record Equippable(EquipmentSlot slot, Sound equipSound, @Nullable Key model, @Nullable Key cameraOverlay, - @Nullable HolderSet allowedEntities, boolean dispensable, boolean swappable, boolean damageOnHurt) { + @Nullable HolderSet allowedEntities, boolean dispensable, boolean swappable, boolean damageOnHurt, + boolean equipOnInteract) { } diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/Instrument.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/Instrument.java deleted file mode 100644 index d436412fc..000000000 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/Instrument.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.geysermc.mcprotocollib.protocol.data.game.item.component; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import net.kyori.adventure.text.Component; -import org.geysermc.mcprotocollib.protocol.data.game.level.sound.Sound; - -@Data -@AllArgsConstructor -@Builder(toBuilder = true) -public class Instrument { - private final Sound soundEvent; - private final float useDuration; - private final float range; - private final Component description; -} diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/InstrumentComponent.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/InstrumentComponent.java new file mode 100644 index 000000000..e3d49b2bf --- /dev/null +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/InstrumentComponent.java @@ -0,0 +1,16 @@ +package org.geysermc.mcprotocollib.protocol.data.game.item.component; + +import lombok.Builder; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.text.Component; +import org.geysermc.mcprotocollib.protocol.data.game.Holder; +import org.geysermc.mcprotocollib.protocol.data.game.level.sound.Sound; +import org.jetbrains.annotations.Nullable; + +@Builder(toBuilder = true) +public record InstrumentComponent(@Nullable Holder instrumentHolder, @Nullable Key instrumentLocation) { + + @Builder(toBuilder = true) + public record Instrument(Sound soundEvent, float useDuration, float range, Component description) { + } +} diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/ItemAttributeModifiers.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/ItemAttributeModifiers.java index e5489a8a6..3f505cf5c 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/ItemAttributeModifiers.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/ItemAttributeModifiers.java @@ -13,11 +13,9 @@ @With public class ItemAttributeModifiers { private final List modifiers; - private final boolean showInTooltip; - public ItemAttributeModifiers(List modifiers, boolean showInTooltip) { + public ItemAttributeModifiers(List modifiers) { this.modifiers = List.copyOf(modifiers); - this.showInTooltip = showInTooltip; } @Data @@ -48,7 +46,8 @@ public enum EquipmentSlotGroup { CHEST, HEAD, ARMOR, - BODY; + BODY, + SADDLE; private static final EquipmentSlotGroup[] VALUES = values(); diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/ItemEnchantments.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/ItemEnchantments.java index 5f3aec174..a8ec17880 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/ItemEnchantments.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/ItemEnchantments.java @@ -9,10 +9,8 @@ @With public class ItemEnchantments { private final Map enchantments; - private final boolean showInTooltip; - public ItemEnchantments(Map enchantments, boolean showInTooltip) { + public ItemEnchantments(Map enchantments) { this.enchantments = Map.copyOf(enchantments); - this.showInTooltip = showInTooltip; } } 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 0684bf556..d57de37a2 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 @@ -5,6 +5,7 @@ import net.kyori.adventure.key.Key; import net.kyori.adventure.text.Component; import org.cloudburstmc.nbt.NbtList; +import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtType; import org.geysermc.mcprotocollib.auth.GameProfile; import org.geysermc.mcprotocollib.protocol.codec.MinecraftTypes; @@ -12,8 +13,6 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.Effect; import org.geysermc.mcprotocollib.protocol.data.game.entity.EquipmentSlot; import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.ModifierOperation; -import org.geysermc.mcprotocollib.protocol.data.game.level.sound.BuiltinSound; -import org.geysermc.mcprotocollib.protocol.data.game.level.sound.CustomSound; import org.geysermc.mcprotocollib.protocol.data.game.level.sound.Sound; import java.util.ArrayList; @@ -37,14 +36,6 @@ public static void writeFilterable(ByteBuf buf, Filterable filterable, Bi MinecraftTypes.writeNullable(buf, filterable.getOptional(), writer); } - public static Unbreakable readUnbreakable(ByteBuf buf) { - return new Unbreakable(buf.readBoolean()); - } - - public static void writeUnbreakable(ByteBuf buf, Unbreakable unbreakable) { - buf.writeBoolean(unbreakable.isInTooltip()); - } - public static ItemEnchantments readItemEnchantments(ByteBuf buf) { Map enchantments = new HashMap<>(); int enchantmentCount = MinecraftTypes.readVarInt(buf); @@ -52,7 +43,7 @@ public static ItemEnchantments readItemEnchantments(ByteBuf buf) { enchantments.put(MinecraftTypes.readVarInt(buf), MinecraftTypes.readVarInt(buf)); } - return new ItemEnchantments(enchantments, buf.readBoolean()); + return new ItemEnchantments(enchantments); } public static void writeItemEnchantments(ByteBuf buf, ItemEnchantments itemEnchantments) { @@ -61,41 +52,34 @@ public static void writeItemEnchantments(ByteBuf buf, ItemEnchantments itemEncha MinecraftTypes.writeVarInt(buf, entry.getKey()); MinecraftTypes.writeVarInt(buf, entry.getValue()); } - - buf.writeBoolean(itemEnchantments.isShowInTooltip()); } public static AdventureModePredicate readAdventureModePredicate(ByteBuf buf) { - List predicates = MinecraftTypes.readList(buf, ItemTypes::readBlockPredicate); - return new AdventureModePredicate(predicates, buf.readBoolean()); + return new AdventureModePredicate(MinecraftTypes.readList(buf, ItemTypes::readBlockPredicate)); } public static void writeAdventureModePredicate(ByteBuf buf, AdventureModePredicate adventureModePredicate) { - MinecraftTypes.writeVarInt(buf, adventureModePredicate.getPredicates().size()); - for (AdventureModePredicate.BlockPredicate predicate : adventureModePredicate.getPredicates()) { - ItemTypes.writeBlockPredicate(buf, predicate); - } - - buf.writeBoolean(adventureModePredicate.isShowInTooltip()); + MinecraftTypes.writeList(buf, adventureModePredicate.getPredicates(), ItemTypes::writeBlockPredicate); } public static AdventureModePredicate.BlockPredicate readBlockPredicate(ByteBuf buf) { - HolderSet holderSet = MinecraftTypes.readNullable(buf, MinecraftTypes::readHolderSet); + HolderSet blocks = MinecraftTypes.readNullable(buf, MinecraftTypes::readHolderSet); List propertyMatchers = MinecraftTypes.readNullable(buf, (input) -> { - List matchers = new ArrayList<>(); - int matcherCount = MinecraftTypes.readVarInt(input); - for (int i = 0; i < matcherCount; i++) { - String name = MinecraftTypes.readString(input); - if (input.readBoolean()) { - matchers.add(new AdventureModePredicate.PropertyMatcher(name, MinecraftTypes.readString(input), null, null)); + return MinecraftTypes.readList(input, input2 -> { + String name = MinecraftTypes.readString(input2); + if (input2.readBoolean()) { + return new AdventureModePredicate.PropertyMatcher(name, MinecraftTypes.readString(input2), null, null); } else { - matchers.add(new AdventureModePredicate.PropertyMatcher(name, null, MinecraftTypes.readString(input), MinecraftTypes.readString(input))); + return new AdventureModePredicate.PropertyMatcher(name, null, MinecraftTypes.readString(input2), MinecraftTypes.readString(input2)); } - } - return matchers; + }); }); - return new AdventureModePredicate.BlockPredicate(holderSet, propertyMatchers, MinecraftTypes.readNullable(buf, MinecraftTypes::readCompoundTag)); + NbtMap nbt = MinecraftTypes.readNullable(buf, MinecraftTypes::readCompoundTag); + + DataComponentMatchers components = ItemTypes.readDataComponentMatchers(buf); + + return new AdventureModePredicate.BlockPredicate(blocks, propertyMatchers, nbt, components); } public static void writeBlockPredicate(ByteBuf buf, AdventureModePredicate.BlockPredicate blockPredicate) { @@ -116,6 +100,28 @@ public static void writeBlockPredicate(ByteBuf buf, AdventureModePredicate.Block }); MinecraftTypes.writeNullable(buf, blockPredicate.getNbt(), MinecraftTypes::writeAnyTag); + + ItemTypes.writeDataComponentMatchers(buf, blockPredicate.getComponents()); + } + + public static DataComponentMatchers readDataComponentMatchers(ByteBuf buf) { + Map, DataComponent> exactMatchers = MinecraftTypes.readExactComponentMatcher(buf); + + int[] partialMatchers = new int[MinecraftTypes.readVarInt(buf)]; + for (int i = 0; i < partialMatchers.length; i++) { + partialMatchers[i] = MinecraftTypes.readVarInt(buf); + } + + return new DataComponentMatchers(exactMatchers, partialMatchers); + } + + public static void writeDataComponentMatchers(ByteBuf buf, DataComponentMatchers matchers) { + MinecraftTypes.writeExactComponentMatcher(buf, matchers.exactMatchers()); + + MinecraftTypes.writeVarInt(buf, matchers.partialMatchers().length); + for (int id : matchers.partialMatchers()) { + MinecraftTypes.writeVarInt(buf, id); + } } public static ToolData readToolData(ByteBuf buf) { @@ -129,7 +135,8 @@ public static ToolData readToolData(ByteBuf buf) { float defaultMiningSpeed = buf.readFloat(); int damagePerBlock = MinecraftTypes.readVarInt(buf); - return new ToolData(rules, defaultMiningSpeed, damagePerBlock); + boolean canDestroyBlocksInCreative = buf.readBoolean(); + return new ToolData(rules, defaultMiningSpeed, damagePerBlock, canDestroyBlocksInCreative); } public static void writeToolData(ByteBuf buf, ToolData data) { @@ -141,35 +148,81 @@ public static void writeToolData(ByteBuf buf, ToolData data) { buf.writeFloat(data.getDefaultMiningSpeed()); MinecraftTypes.writeVarInt(buf, data.getDamagePerBlock()); + buf.writeBoolean(data.isCanDestroyBlocksInCreative()); + } + + public static Weapon readWeapon(ByteBuf buf) { + int damagePerAttack = MinecraftTypes.readVarInt(buf); + float disableBlockingForSeconds = buf.readFloat(); + return new Weapon(damagePerAttack, disableBlockingForSeconds); + } + + public static void writeWeapon(ByteBuf buf, Weapon weapon) { + MinecraftTypes.writeVarInt(buf, weapon.itemDamagePerAttack()); + buf.writeFloat(weapon.disableBlockingForSeconds()); } public static Equippable readEquippable(ByteBuf buf) { - EquipmentSlot slot = EquipmentSlot.from(MinecraftTypes.readVarInt(buf)); - Sound equipSound = MinecraftTypes.readById(buf, BuiltinSound::from, MinecraftTypes::readSoundEvent); + EquipmentSlot slot = EquipmentSlot.fromId(MinecraftTypes.readVarInt(buf)); + Sound equipSound = MinecraftTypes.readSound(buf); Key model = MinecraftTypes.readNullable(buf, MinecraftTypes::readResourceLocation); Key cameraOverlay = MinecraftTypes.readNullable(buf, MinecraftTypes::readResourceLocation); HolderSet allowedEntities = MinecraftTypes.readNullable(buf, MinecraftTypes::readHolderSet); boolean dispensable = buf.readBoolean(); boolean swappable = buf.readBoolean(); boolean damageOnHurt = buf.readBoolean(); - return new Equippable(slot, equipSound, model, cameraOverlay, allowedEntities, dispensable, swappable, damageOnHurt); + boolean equipOnInteract = buf.readBoolean(); + return new Equippable(slot, equipSound, model, cameraOverlay, allowedEntities, dispensable, swappable, damageOnHurt, equipOnInteract); } public static void writeEquippable(ByteBuf buf, Equippable equippable) { MinecraftTypes.writeVarInt(buf, equippable.slot().ordinal()); - if (equippable.equipSound() instanceof CustomSound) { - MinecraftTypes.writeVarInt(buf, 0); - MinecraftTypes.writeSoundEvent(buf, equippable.equipSound()); - } else { - MinecraftTypes.writeVarInt(buf, ((BuiltinSound) equippable.equipSound()).ordinal() + 1); - } - + MinecraftTypes.writeSound(buf, equippable.equipSound()); MinecraftTypes.writeNullable(buf, equippable.model(), MinecraftTypes::writeResourceLocation); MinecraftTypes.writeNullable(buf, equippable.cameraOverlay(), MinecraftTypes::writeResourceLocation); MinecraftTypes.writeNullable(buf, equippable.allowedEntities(), MinecraftTypes::writeHolderSet); buf.writeBoolean(equippable.dispensable()); buf.writeBoolean(equippable.swappable()); buf.writeBoolean(equippable.damageOnHurt()); + buf.writeBoolean(equippable.equipOnInteract()); + } + + public static BlocksAttacks readBlocksAttacks(ByteBuf buf) { + float blockDelaySeconds = buf.readFloat(); + float disableCooldownScale = buf.readFloat(); + + List damageReductions = MinecraftTypes.readList(buf, (input) -> { + float horizontalBlockingAngle = input.readFloat(); + HolderSet type = MinecraftTypes.readNullable(input, MinecraftTypes::readHolderSet); + float base = input.readFloat(); + float factor = input.readFloat(); + return new BlocksAttacks.DamageReduction(horizontalBlockingAngle, type, base, factor); + }); + + BlocksAttacks.ItemDamageFunction itemDamage = new BlocksAttacks.ItemDamageFunction(buf.readFloat(), buf.readFloat(), buf.readFloat()); + Key bypassedBy = MinecraftTypes.readNullable(buf, MinecraftTypes::readResourceLocation); + Sound blockSound = MinecraftTypes.readNullable(buf, MinecraftTypes::readSound); + Sound disableSound = MinecraftTypes.readNullable(buf, MinecraftTypes::readSound); + return new BlocksAttacks(blockDelaySeconds, disableCooldownScale, damageReductions, itemDamage, bypassedBy, blockSound, disableSound); + } + + public static void writeBlocksAttacks(ByteBuf buf, BlocksAttacks blocksAttacks) { + buf.writeFloat(blocksAttacks.blockDelaySeconds()); + buf.writeFloat(blocksAttacks.disableCooldownScale()); + + MinecraftTypes.writeList(buf, blocksAttacks.damageReductions(), (output, entry) -> { + output.writeFloat(entry.horizontalBlockingAngle()); + MinecraftTypes.writeNullable(output, entry.type(), MinecraftTypes::writeHolderSet); + output.writeFloat(entry.base()); + output.writeFloat(entry.factor()); + }); + + buf.writeFloat(blocksAttacks.itemDamage().threshold()); + buf.writeFloat(blocksAttacks.itemDamage().base()); + buf.writeFloat(blocksAttacks.itemDamage().factor()); + MinecraftTypes.writeNullable(buf, blocksAttacks.bypassedBy(), MinecraftTypes::writeResourceLocation); + MinecraftTypes.writeNullable(buf, blocksAttacks.blockSound(), MinecraftTypes::writeSound); + MinecraftTypes.writeNullable(buf, blocksAttacks.disableSound(), MinecraftTypes::writeSound); } public static ItemAttributeModifiers readItemAttributeModifiers(ByteBuf buf) { @@ -185,7 +238,7 @@ public static ItemAttributeModifiers readItemAttributeModifiers(ByteBuf buf) { return new ItemAttributeModifiers.Entry(attribute, modifier, slot); }); - return new ItemAttributeModifiers(modifiers, buf.readBoolean()); + return new ItemAttributeModifiers(modifiers); } public static void writeItemAttributeModifiers(ByteBuf buf, ItemAttributeModifiers modifiers) { @@ -196,8 +249,17 @@ public static void writeItemAttributeModifiers(ByteBuf buf, ItemAttributeModifie MinecraftTypes.writeVarInt(output, entry.getModifier().getOperation().ordinal()); MinecraftTypes.writeVarInt(output, entry.getSlot().ordinal()); }); + } - buf.writeBoolean(modifiers.isShowInTooltip()); + public static TooltipDisplay readTooltipDisplay(ByteBuf buf) { + boolean hideTooltip = buf.readBoolean(); + List> hiddenComponents = MinecraftTypes.readList(buf, input -> DataComponentTypes.from(MinecraftTypes.readVarInt(input))); + return new TooltipDisplay(hideTooltip, hiddenComponents); + } + + public static void writeTooltipDisplay(ByteBuf buf, TooltipDisplay tooltipDisplay) { + buf.writeBoolean(tooltipDisplay.hideTooltip()); + MinecraftTypes.writeList(buf, tooltipDisplay.hiddenComponents(), (output, entry) -> MinecraftTypes.writeVarInt(output, entry.getId())); } public static CustomModelData readCustomModelData(ByteBuf buf) { @@ -215,15 +277,6 @@ public static void writeCustomModelData(ByteBuf buf, CustomModelData modelData) MinecraftTypes.writeList(buf, modelData.colors(), ByteBuf::writeInt); } - public static DyedItemColor readDyedItemColor(ByteBuf buf) { - return new DyedItemColor(buf.readInt(), buf.readBoolean()); - } - - public static void writeDyedItemColor(ByteBuf buf, DyedItemColor itemColor) { - buf.writeInt(itemColor.getRgb()); - buf.writeBoolean(itemColor.isShowInTooltip()); - } - public static PotionContents readPotionContents(ByteBuf buf) { int potionId = buf.readBoolean() ? MinecraftTypes.readVarInt(buf) : -1; int customColor = buf.readBoolean() ? buf.readInt() : -1; @@ -269,7 +322,7 @@ public static void writeFoodProperties(ByteBuf buf, FoodProperties properties) { public static Consumable readConsumable(ByteBuf buf) { float consumeSeconds = buf.readFloat(); Consumable.ItemUseAnimation animation = Consumable.ItemUseAnimation.from(MinecraftTypes.readVarInt(buf)); - Sound sound = MinecraftTypes.readById(buf, BuiltinSound::from, MinecraftTypes::readSoundEvent); + Sound sound = MinecraftTypes.readSound(buf); boolean hasConsumeParticles = buf.readBoolean(); List onConsumeEffects = MinecraftTypes.readList(buf, ItemTypes::readConsumeEffect); return new Consumable(consumeSeconds, animation, sound, hasConsumeParticles, onConsumeEffects); @@ -278,13 +331,7 @@ public static Consumable readConsumable(ByteBuf buf) { public static void writeConsumable(ByteBuf buf, Consumable consumable) { buf.writeFloat(consumable.consumeSeconds()); MinecraftTypes.writeVarInt(buf, consumable.animation().ordinal()); - if (consumable.sound() instanceof CustomSound) { - MinecraftTypes.writeVarInt(buf, 0); - MinecraftTypes.writeSoundEvent(buf, consumable.sound()); - } else { - MinecraftTypes.writeVarInt(buf, ((BuiltinSound) consumable.sound()).ordinal() + 1); - } - + MinecraftTypes.writeSound(buf, consumable.sound()); buf.writeBoolean(consumable.hasConsumeParticles()); MinecraftTypes.writeList(buf, consumable.onConsumeEffects(), ItemTypes::writeConsumeEffect); } @@ -295,7 +342,7 @@ public static ConsumeEffect readConsumeEffect(ByteBuf buf) { case 1 -> new ConsumeEffect.RemoveEffects(MinecraftTypes.readHolderSet(buf)); case 2 -> new ConsumeEffect.ClearAllEffects(); case 3 -> new ConsumeEffect.TeleportRandomly(buf.readFloat()); - case 4 -> new ConsumeEffect.PlaySound(MinecraftTypes.readById(buf, BuiltinSound::from, MinecraftTypes::readSoundEvent)); + case 4 -> new ConsumeEffect.PlaySound(MinecraftTypes.readSound(buf)); default -> throw new IllegalStateException("Unexpected value: " + MinecraftTypes.readVarInt(buf)); }; } @@ -315,12 +362,7 @@ public static void writeConsumeEffect(ByteBuf buf, ConsumeEffect consumeEffect) buf.writeFloat(teleportRandomly.diameter()); } else if (consumeEffect instanceof ConsumeEffect.PlaySound playSound) { MinecraftTypes.writeVarInt(buf, 4); - if (playSound.sound() instanceof CustomSound) { - MinecraftTypes.writeVarInt(buf, 0); - MinecraftTypes.writeSoundEvent(buf, playSound.sound()); - } else { - MinecraftTypes.writeVarInt(buf, ((BuiltinSound) playSound.sound()).ordinal() + 1); - } + MinecraftTypes.writeSound(buf, playSound.sound()); } } @@ -403,36 +445,32 @@ public static void writeWrittenBookContent(ByteBuf buf, WrittenBookContent conte public static ArmorTrim readArmorTrim(ByteBuf buf) { Holder material = MinecraftTypes.readHolder(buf, ItemTypes::readTrimMaterial); Holder pattern = MinecraftTypes.readHolder(buf, ItemTypes::readTrimPattern); - boolean showInTooltip = buf.readBoolean(); - return new ArmorTrim(material, pattern, showInTooltip); + return new ArmorTrim(material, pattern); } public static void writeArmorTrim(ByteBuf buf, ArmorTrim trim) { MinecraftTypes.writeHolder(buf, trim.material(), ItemTypes::writeTrimMaterial); MinecraftTypes.writeHolder(buf, trim.pattern(), ItemTypes::writeTrimPattern); - buf.writeBoolean(trim.showInTooltip()); } public static ArmorTrim.TrimMaterial readTrimMaterial(ByteBuf buf) { - String assetName = MinecraftTypes.readString(buf); - int ingredientId = MinecraftTypes.readVarInt(buf); + String assetBase = MinecraftTypes.readString(buf); - Map overrideArmorMaterials = new HashMap<>(); + Map assetOverrides = new HashMap<>(); int overrideCount = MinecraftTypes.readVarInt(buf); for (int i = 0; i < overrideCount; i++) { - overrideArmorMaterials.put(MinecraftTypes.readResourceLocation(buf), MinecraftTypes.readString(buf)); + assetOverrides.put(MinecraftTypes.readResourceLocation(buf), MinecraftTypes.readString(buf)); } Component description = MinecraftTypes.readComponent(buf); - return new ArmorTrim.TrimMaterial(assetName, ingredientId, overrideArmorMaterials, description); + return new ArmorTrim.TrimMaterial(assetBase, assetOverrides, description); } public static void writeTrimMaterial(ByteBuf buf, ArmorTrim.TrimMaterial material) { - MinecraftTypes.writeString(buf, material.assetName()); - MinecraftTypes.writeVarInt(buf, material.ingredientId()); + MinecraftTypes.writeString(buf, material.assetBase()); - MinecraftTypes.writeVarInt(buf, material.overrideArmorAssets().size()); - for (Map.Entry entry : material.overrideArmorAssets().entrySet()) { + MinecraftTypes.writeVarInt(buf, material.assetOverrides().size()); + for (Map.Entry entry : material.assetOverrides().entrySet()) { MinecraftTypes.writeResourceLocation(buf, entry.getKey()); MinecraftTypes.writeString(buf, entry.getValue()); } @@ -442,42 +480,70 @@ public static void writeTrimMaterial(ByteBuf buf, ArmorTrim.TrimMaterial materia public static ArmorTrim.TrimPattern readTrimPattern(ByteBuf buf) { Key assetId = MinecraftTypes.readResourceLocation(buf); - int templateItemId = MinecraftTypes.readVarInt(buf); Component description = MinecraftTypes.readComponent(buf); boolean decal = buf.readBoolean(); - return new ArmorTrim.TrimPattern(assetId, templateItemId, description, decal); + return new ArmorTrim.TrimPattern(assetId, description, decal); } public static void writeTrimPattern(ByteBuf buf, ArmorTrim.TrimPattern pattern) { MinecraftTypes.writeResourceLocation(buf, pattern.assetId()); - MinecraftTypes.writeVarInt(buf, pattern.templateItemId()); MinecraftTypes.writeComponent(buf, pattern.description()); buf.writeBoolean(pattern.decal()); } - public static Holder readInstrument(ByteBuf buf) { - return MinecraftTypes.readHolder(buf, (input) -> { - Sound soundEvent = MinecraftTypes.readById(input, BuiltinSound::from, MinecraftTypes::readSoundEvent); - float useDuration = input.readFloat(); - float range = input.readFloat(); - Component description = MinecraftTypes.readComponent(input); - return new Instrument(soundEvent, useDuration, range, description); - }); + public static InstrumentComponent readInstrumentComponent(ByteBuf buf) { + Holder instrumentHolder = null; + Key instrumentLocation = null; + if (buf.readBoolean()) { + instrumentHolder = MinecraftTypes.readHolder(buf, ItemTypes::readInstrument); + } else { + instrumentLocation = MinecraftTypes.readResourceLocation(buf); + } + return new InstrumentComponent(instrumentHolder, instrumentLocation); } - public static void writeInstrument(ByteBuf buf, Holder instrumentHolder) { - MinecraftTypes.writeHolder(buf, instrumentHolder, (output, instrument) -> { - if (instrument.getSoundEvent() instanceof CustomSound) { - MinecraftTypes.writeVarInt(buf, 0); - MinecraftTypes.writeSoundEvent(buf, instrument.getSoundEvent()); - } else { - MinecraftTypes.writeVarInt(buf, ((BuiltinSound) instrument.getSoundEvent()).ordinal() + 1); - } + public static void writeInstrumentComponent(ByteBuf buf, InstrumentComponent instrumentComponent) { + buf.writeBoolean(instrumentComponent.instrumentHolder() != null); + if (instrumentComponent.instrumentHolder() != null) { + MinecraftTypes.writeHolder(buf, instrumentComponent.instrumentHolder(), ItemTypes::writeInstrument); + } else { + MinecraftTypes.writeResourceLocation(buf, instrumentComponent.instrumentLocation()); + } + } - buf.writeFloat(instrument.getUseDuration()); - buf.writeFloat(instrument.getRange()); - MinecraftTypes.writeComponent(buf, instrument.getDescription()); - }); + public static InstrumentComponent.Instrument readInstrument(ByteBuf buf) { + Sound soundEvent = MinecraftTypes.readSound(buf); + float useDuration = buf.readFloat(); + float range = buf.readFloat(); + Component description = MinecraftTypes.readComponent(buf); + return new InstrumentComponent.Instrument(soundEvent, useDuration, range, description); + } + + public static void writeInstrument(ByteBuf buf, InstrumentComponent.Instrument instrument) { + MinecraftTypes.writeSound(buf, instrument.soundEvent()); + buf.writeFloat(instrument.useDuration()); + buf.writeFloat(instrument.range()); + MinecraftTypes.writeComponent(buf, instrument.description()); + } + + public static ProvidesTrimMaterial readProvidesTrimMaterial(ByteBuf buf) { + Holder instrumentHolder = null; + Key instrumentLocation = null; + if (buf.readBoolean()) { + instrumentHolder = MinecraftTypes.readHolder(buf, ItemTypes::readTrimMaterial); + } else { + instrumentLocation = MinecraftTypes.readResourceLocation(buf); + } + return new ProvidesTrimMaterial(instrumentHolder, instrumentLocation); + } + + public static void writeProvidesTrimMaterial(ByteBuf buf, ProvidesTrimMaterial trimMaterial) { + buf.writeBoolean(trimMaterial.materialHolder() != null); + if (trimMaterial.materialHolder() != null) { + MinecraftTypes.writeHolder(buf, trimMaterial.materialHolder(), ItemTypes::writeTrimMaterial); + } else { + MinecraftTypes.writeResourceLocation(buf, trimMaterial.materialLocation()); + } } public static NbtList readRecipes(ByteBuf buf) { @@ -496,8 +562,7 @@ public static JukeboxPlayable readJukeboxPlayable(ByteBuf buf) { } else { songLocation = MinecraftTypes.readResourceLocation(buf); } - boolean showInTooltip = buf.readBoolean(); - return new JukeboxPlayable(songHolder, songLocation, showInTooltip); + return new JukeboxPlayable(songHolder, songLocation); } public static void writeJukeboxPlayable(ByteBuf buf, JukeboxPlayable playable) { @@ -507,11 +572,10 @@ public static void writeJukeboxPlayable(ByteBuf buf, JukeboxPlayable playable) { } else { MinecraftTypes.writeResourceLocation(buf, playable.songLocation()); } - buf.writeBoolean(playable.showInTooltip()); } public static JukeboxPlayable.JukeboxSong readJukeboxSong(ByteBuf buf) { - Sound soundEvent = MinecraftTypes.readById(buf, BuiltinSound::from, MinecraftTypes::readSoundEvent); + Sound soundEvent = MinecraftTypes.readSound(buf); Component description = MinecraftTypes.readComponent(buf); float lengthInSeconds = buf.readFloat(); int comparatorOutput = MinecraftTypes.readVarInt(buf); @@ -519,12 +583,7 @@ public static JukeboxPlayable.JukeboxSong readJukeboxSong(ByteBuf buf) { } public static void writeJukeboxSong(ByteBuf buf, JukeboxPlayable.JukeboxSong song) { - if (song.soundEvent() instanceof CustomSound) { - MinecraftTypes.writeVarInt(buf, 0); - MinecraftTypes.writeSoundEvent(buf, song.soundEvent()); - } else { - MinecraftTypes.writeVarInt(buf, ((BuiltinSound) song.soundEvent()).ordinal() + 1); - } + MinecraftTypes.writeSound(buf, song.soundEvent()); MinecraftTypes.writeComponent(buf, song.description()); buf.writeFloat(song.lengthInSeconds()); MinecraftTypes.writeVarInt(buf, song.comparatorOutput()); diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/JukeboxPlayable.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/JukeboxPlayable.java index 4cc84126a..f9f4fce94 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/JukeboxPlayable.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/JukeboxPlayable.java @@ -8,7 +8,7 @@ import org.jetbrains.annotations.Nullable; @Builder(toBuilder = true) -public record JukeboxPlayable(@Nullable Holder songHolder, @Nullable Key songLocation, boolean showInTooltip) { +public record JukeboxPlayable(@Nullable Holder songHolder, @Nullable Key songLocation) { @Builder(toBuilder = true) public record JukeboxSong(Sound soundEvent, Component description, float lengthInSeconds, int comparatorOutput) { diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/ProvidesTrimMaterial.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/ProvidesTrimMaterial.java new file mode 100644 index 000000000..af43e72f3 --- /dev/null +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/ProvidesTrimMaterial.java @@ -0,0 +1,10 @@ +package org.geysermc.mcprotocollib.protocol.data.game.item.component; + +import lombok.Builder; +import net.kyori.adventure.key.Key; +import org.geysermc.mcprotocollib.protocol.data.game.Holder; +import org.jetbrains.annotations.Nullable; + +@Builder(toBuilder = true) +public record ProvidesTrimMaterial(@Nullable Holder materialHolder, @Nullable Key materialLocation) { +} diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/ToolData.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/ToolData.java index fa6e6aab1..3a39e9a74 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/ToolData.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/ToolData.java @@ -14,11 +14,13 @@ public class ToolData { private final List rules; private final float defaultMiningSpeed; private final int damagePerBlock; + private final boolean canDestroyBlocksInCreative; - public ToolData(List rules, float defaultMiningSpeed, int damagePerBlock) { + public ToolData(List rules, float defaultMiningSpeed, int damagePerBlock, boolean canDestroyBlocksInCreative) { this.rules = List.copyOf(rules); this.defaultMiningSpeed = defaultMiningSpeed; this.damagePerBlock = damagePerBlock; + this.canDestroyBlocksInCreative = canDestroyBlocksInCreative; } @Data diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/TooltipDisplay.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/TooltipDisplay.java new file mode 100644 index 000000000..ca317d8d9 --- /dev/null +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/TooltipDisplay.java @@ -0,0 +1,13 @@ +package org.geysermc.mcprotocollib.protocol.data.game.item.component; + +import lombok.Builder; + +import java.util.List; + +@Builder(toBuilder = true) +public record TooltipDisplay(boolean hideTooltip, List> hiddenComponents) { + public TooltipDisplay(boolean hideTooltip, List> hiddenComponents) { + this.hideTooltip = hideTooltip; + this.hiddenComponents = List.copyOf(hiddenComponents); + } +} diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/Unbreakable.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/Unbreakable.java deleted file mode 100644 index 89b46b4a6..000000000 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/Unbreakable.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.geysermc.mcprotocollib.protocol.data.game.item.component; - -import lombok.AllArgsConstructor; -import lombok.Data; - -@Data -@AllArgsConstructor -public class Unbreakable { - private boolean inTooltip; -} diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/Weapon.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/Weapon.java new file mode 100644 index 000000000..cce5fa460 --- /dev/null +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/item/component/Weapon.java @@ -0,0 +1,7 @@ +package org.geysermc.mcprotocollib.protocol.data.game.item.component; + +import lombok.Builder; + +@Builder(toBuilder = true) +public record Weapon(int itemDamagePerAttack, float disableBlockingForSeconds) { +} diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/level/HeightmapTypes.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/level/HeightmapTypes.java new file mode 100644 index 000000000..ff4028e03 --- /dev/null +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/level/HeightmapTypes.java @@ -0,0 +1,16 @@ +package org.geysermc.mcprotocollib.protocol.data.game.level; + +public enum HeightmapTypes { + WORLD_SURFACE_WG, + WORLD_SURFACE, + OCEAN_FLOOR_WG, + OCEAN_FLOOR, + MOTION_BLOCKING, + MOTION_BLOCKING_NO_LEAVES; + + private static final HeightmapTypes[] VALUES = values(); + + public static HeightmapTypes from(int id) { + return VALUES[id]; + } +} diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/level/block/BlockEntityType.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/level/block/BlockEntityType.java index 2c4c88267..11ad5e936 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/level/block/BlockEntityType.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/level/block/BlockEntityType.java @@ -47,7 +47,9 @@ public enum BlockEntityType { DECORATED_POT, CRAFTER, TRIAL_SPAWNER, - VAULT; + VAULT, + TEST_BLOCK, + TEST_INSTANCE_BLOCK; private static final BlockEntityType[] VALUES = values(); diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/level/block/TestInstanceBlockEntity.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/level/block/TestInstanceBlockEntity.java new file mode 100644 index 000000000..c287a782d --- /dev/null +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/level/block/TestInstanceBlockEntity.java @@ -0,0 +1,10 @@ +package org.geysermc.mcprotocollib.protocol.data.game.level.block; + +import net.kyori.adventure.key.Key; +import net.kyori.adventure.text.Component; +import org.cloudburstmc.math.vector.Vector3i; +import org.jetbrains.annotations.Nullable; + +public record TestInstanceBlockEntity(@Nullable Key test, Vector3i size, int rotation, boolean ignoreEntities, + int status, @Nullable Component errorMessage) { +} diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/level/notify/GameEvent.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/level/notify/GameEvent.java index 83132eb0d..9e9610f2e 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/level/notify/GameEvent.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/level/notify/GameEvent.java @@ -1,18 +1,18 @@ package org.geysermc.mcprotocollib.protocol.data.game.level.notify; public enum GameEvent { - INVALID_BED, - START_RAIN, - STOP_RAIN, - CHANGE_GAMEMODE, - ENTER_CREDITS, - DEMO_MESSAGE, - ARROW_HIT_PLAYER, - RAIN_STRENGTH, - THUNDER_STRENGTH, - PUFFERFISH_STING_SOUND, - AFFECTED_BY_ELDER_GUARDIAN, - ENABLE_RESPAWN_SCREEN, + NO_RESPAWN_BLOCK_AVAILABLE, + START_RAINING, + STOP_RAINING, + CHANGE_GAME_MODE, + WIN_GAME, + DEMO_EVENT, + PLAY_ARROW_HIT_SOUND, + RAIN_LEVEL_CHANGE, + THUNDER_LEVEL_CHANGE, + PUFFER_FISH_STING, + GUARDIAN_ELDER_EFFECT, + IMMEDIATE_RESPAWN, LIMITED_CRAFTING, LEVEL_CHUNKS_LOAD_START; diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/level/particle/EntityEffectParticleData.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/level/particle/ColorParticleData.java similarity index 74% rename from protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/level/particle/EntityEffectParticleData.java rename to protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/level/particle/ColorParticleData.java index f442f75e2..7d58a1662 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/level/particle/EntityEffectParticleData.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/level/particle/ColorParticleData.java @@ -5,6 +5,6 @@ @Data @AllArgsConstructor -public class EntityEffectParticleData implements ParticleData { +public class ColorParticleData implements ParticleData { private final int color; } diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/level/particle/ParticleType.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/level/particle/ParticleType.java index 5805571cb..568d67a2c 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/level/particle/ParticleType.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/level/particle/ParticleType.java @@ -36,6 +36,7 @@ public enum ParticleType { INFESTED, CHERRY_LEAVES, PALE_OAK_LEAVES, + TINTED_LEAVES, SCULK_SOUL, SCULK_CHARGE, SCULK_CHARGE_POP, @@ -112,7 +113,8 @@ public enum ParticleType { OMINOUS_SPAWNING, RAID_OMEN, TRIAL_OMEN, - BLOCK_CRUMBLE; + BLOCK_CRUMBLE, + FIREFLY; private static final ParticleType[] VALUES = values(); diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/level/sound/BuiltinSound.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/level/sound/BuiltinSound.java index 5bf03a1e9..89477d961 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/level/sound/BuiltinSound.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/level/sound/BuiltinSound.java @@ -234,6 +234,8 @@ public enum BuiltinSound implements Sound { ITEM_BUNDLE_INSERT("item.bundle.insert"), ITEM_BUNDLE_INSERT_FAIL("item.bundle.insert_fail"), ITEM_BUNDLE_REMOVE_ONE("item.bundle.remove_one"), + BLOCK_CACTUS_FLOWER_BREAK("block.cactus_flower.break"), + BLOCK_CACTUS_FLOWER_PLACE("block.cactus_flower.place"), BLOCK_CAKE_ADD_CANDLE("block.cake.add_candle"), BLOCK_CALCITE_BREAK("block.calcite.break"), BLOCK_CALCITE_STEP("block.calcite.step"), @@ -413,6 +415,7 @@ public enum BuiltinSound implements Sound { ITEM_CROSSBOW_QUICK_CHARGE_2("item.crossbow.quick_charge_2"), ITEM_CROSSBOW_QUICK_CHARGE_3("item.crossbow.quick_charge_3"), ITEM_CROSSBOW_SHOOT("item.crossbow.shoot"), + BLOCK_DEADBUSH_IDLE("block.deadbush.idle"), BLOCK_DECORATED_POT_BREAK("block.decorated_pot.break"), BLOCK_DECORATED_POT_FALL("block.decorated_pot.fall"), BLOCK_DECORATED_POT_HIT("block.decorated_pot.hit"), @@ -538,6 +541,7 @@ public enum BuiltinSound implements Sound { BLOCK_FENCE_GATE_CLOSE("block.fence_gate.close"), BLOCK_FENCE_GATE_OPEN("block.fence_gate.open"), ITEM_FIRECHARGE_USE("item.firecharge.use"), + BLOCK_FIREFLY_BUSH_IDLE("block.firefly_bush.idle"), ENTITY_FIREWORK_ROCKET_BLAST("entity.firework_rocket.blast"), ENTITY_FIREWORK_ROCKET_BLAST_FAR("entity.firework_rocket.blast_far"), ENTITY_FIREWORK_ROCKET_LARGE_BLAST("entity.firework_rocket.large_blast"), @@ -777,6 +781,11 @@ public enum BuiltinSound implements Sound { ENTITY_ILLUSIONER_PREPARE_BLINDNESS("entity.illusioner.prepare_blindness"), ENTITY_ILLUSIONER_PREPARE_MIRROR("entity.illusioner.prepare_mirror"), ITEM_INK_SAC_USE("item.ink_sac.use"), + BLOCK_IRON_BREAK("block.iron.break"), + BLOCK_IRON_STEP("block.iron.step"), + BLOCK_IRON_PLACE("block.iron.place"), + BLOCK_IRON_HIT("block.iron.hit"), + BLOCK_IRON_FALL("block.iron.fall"), BLOCK_IRON_DOOR_CLOSE("block.iron_door.close"), BLOCK_IRON_DOOR_OPEN("block.iron_door.open"), ENTITY_IRON_GOLEM_ATTACK("entity.iron_golem.attack"), @@ -809,6 +818,11 @@ public enum BuiltinSound implements Sound { BLOCK_LAVA_AMBIENT("block.lava.ambient"), BLOCK_LAVA_EXTINGUISH("block.lava.extinguish"), BLOCK_LAVA_POP("block.lava.pop"), + BLOCK_LEAF_LITTER_BREAK("block.leaf_litter.break"), + BLOCK_LEAF_LITTER_STEP("block.leaf_litter.step"), + BLOCK_LEAF_LITTER_PLACE("block.leaf_litter.place"), + BLOCK_LEAF_LITTER_HIT("block.leaf_litter.hit"), + BLOCK_LEAF_LITTER_FALL("block.leaf_litter.fall"), ENTITY_LEASH_KNOT_BREAK("entity.leash_knot.break"), ENTITY_LEASH_KNOT_PLACE("entity.leash_knot.place"), BLOCK_LEVER_CLICK("block.lever.click"), @@ -1223,6 +1237,8 @@ public enum BuiltinSound implements Sound { BLOCK_SAND_HIT("block.sand.hit"), BLOCK_SAND_PLACE("block.sand.place"), BLOCK_SAND_STEP("block.sand.step"), + BLOCK_SAND_IDLE("block.sand.idle"), + BLOCK_SAND_WIND("block.sand.wind"), BLOCK_SCAFFOLDING_BREAK("block.scaffolding.break"), BLOCK_SCAFFOLDING_FALL("block.scaffolding.fall"), BLOCK_SCAFFOLDING_HIT("block.scaffolding.hit"), @@ -1599,15 +1615,50 @@ public enum BuiltinSound implements Sound { ITEM_WOLF_ARMOR_CRACK("item.wolf_armor.crack"), ITEM_WOLF_ARMOR_DAMAGE("item.wolf_armor.damage"), ITEM_WOLF_ARMOR_REPAIR("item.wolf_armor.repair"), + ENTITY_WOLF_SHAKE("entity.wolf.shake"), + ENTITY_WOLF_STEP("entity.wolf.step"), ENTITY_WOLF_AMBIENT("entity.wolf.ambient"), ENTITY_WOLF_DEATH("entity.wolf.death"), ENTITY_WOLF_GROWL("entity.wolf.growl"), - ENTITY_WOLF_HOWL("entity.wolf.howl"), ENTITY_WOLF_HURT("entity.wolf.hurt"), ENTITY_WOLF_PANT("entity.wolf.pant"), - ENTITY_WOLF_SHAKE("entity.wolf.shake"), - ENTITY_WOLF_STEP("entity.wolf.step"), ENTITY_WOLF_WHINE("entity.wolf.whine"), + ENTITY_WOLF_PUGLIN_AMBIENT("entity.wolf_puglin.ambient"), + ENTITY_WOLF_PUGLIN_DEATH("entity.wolf_puglin.death"), + ENTITY_WOLF_PUGLIN_GROWL("entity.wolf_puglin.growl"), + ENTITY_WOLF_PUGLIN_HURT("entity.wolf_puglin.hurt"), + ENTITY_WOLF_PUGLIN_PANT("entity.wolf_puglin.pant"), + ENTITY_WOLF_PUGLIN_WHINE("entity.wolf_puglin.whine"), + ENTITY_WOLF_SAD_AMBIENT("entity.wolf_sad.ambient"), + ENTITY_WOLF_SAD_DEATH("entity.wolf_sad.death"), + ENTITY_WOLF_SAD_GROWL("entity.wolf_sad.growl"), + ENTITY_WOLF_SAD_HURT("entity.wolf_sad.hurt"), + ENTITY_WOLF_SAD_PANT("entity.wolf_sad.pant"), + ENTITY_WOLF_SAD_WHINE("entity.wolf_sad.whine"), + ENTITY_WOLF_ANGRY_AMBIENT("entity.wolf_angry.ambient"), + ENTITY_WOLF_ANGRY_DEATH("entity.wolf_angry.death"), + ENTITY_WOLF_ANGRY_GROWL("entity.wolf_angry.growl"), + ENTITY_WOLF_ANGRY_HURT("entity.wolf_angry.hurt"), + ENTITY_WOLF_ANGRY_PANT("entity.wolf_angry.pant"), + ENTITY_WOLF_ANGRY_WHINE("entity.wolf_angry.whine"), + ENTITY_WOLF_GRUMPY_AMBIENT("entity.wolf_grumpy.ambient"), + ENTITY_WOLF_GRUMPY_DEATH("entity.wolf_grumpy.death"), + ENTITY_WOLF_GRUMPY_GROWL("entity.wolf_grumpy.growl"), + ENTITY_WOLF_GRUMPY_HURT("entity.wolf_grumpy.hurt"), + ENTITY_WOLF_GRUMPY_PANT("entity.wolf_grumpy.pant"), + ENTITY_WOLF_GRUMPY_WHINE("entity.wolf_grumpy.whine"), + ENTITY_WOLF_BIG_AMBIENT("entity.wolf_big.ambient"), + ENTITY_WOLF_BIG_DEATH("entity.wolf_big.death"), + ENTITY_WOLF_BIG_GROWL("entity.wolf_big.growl"), + ENTITY_WOLF_BIG_HURT("entity.wolf_big.hurt"), + ENTITY_WOLF_BIG_PANT("entity.wolf_big.pant"), + ENTITY_WOLF_BIG_WHINE("entity.wolf_big.whine"), + ENTITY_WOLF_CUTE_AMBIENT("entity.wolf_cute.ambient"), + ENTITY_WOLF_CUTE_DEATH("entity.wolf_cute.death"), + ENTITY_WOLF_CUTE_GROWL("entity.wolf_cute.growl"), + ENTITY_WOLF_CUTE_HURT("entity.wolf_cute.hurt"), + ENTITY_WOLF_CUTE_PANT("entity.wolf_cute.pant"), + ENTITY_WOLF_CUTE_WHINE("entity.wolf_cute.whine"), BLOCK_WOODEN_DOOR_CLOSE("block.wooden_door.close"), BLOCK_WOODEN_DOOR_OPEN("block.wooden_door.open"), BLOCK_WOODEN_TRAPDOOR_CLOSE("block.wooden_trapdoor.close"), diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/recipe/display/slot/SmithingTrimDemoSlotDisplay.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/recipe/display/slot/SmithingTrimDemoSlotDisplay.java index 2529432ef..b49a9562e 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/recipe/display/slot/SmithingTrimDemoSlotDisplay.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/recipe/display/slot/SmithingTrimDemoSlotDisplay.java @@ -1,6 +1,9 @@ package org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot; -public record SmithingTrimDemoSlotDisplay(SlotDisplay base, SlotDisplay material, SlotDisplay pattern) implements SlotDisplay { +import org.geysermc.mcprotocollib.protocol.data.game.Holder; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.ArmorTrim; + +public record SmithingTrimDemoSlotDisplay(SlotDisplay base, SlotDisplay material, Holder pattern) implements SlotDisplay { @Override public RecipeSlotType getType() { return RecipeSlotType.SMITHING_TRIM; diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/scoreboard/CollisionRule.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/scoreboard/CollisionRule.java index 318304046..2f766f83d 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/scoreboard/CollisionRule.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/scoreboard/CollisionRule.java @@ -1,33 +1,14 @@ package org.geysermc.mcprotocollib.protocol.data.game.scoreboard; -import java.util.HashMap; -import java.util.Map; - public enum CollisionRule { - ALWAYS("always"), - NEVER("never"), - PUSH_OTHER_TEAMS("pushOtherTeams"), - PUSH_OWN_TEAM("pushOwnTeam"); - - private final String name; - - CollisionRule(String name) { - this.name = name; - } + ALWAYS, + NEVER, + PUSH_OTHER_TEAMS, + PUSH_OWN_TEAM; - public String getName() { - return this.name; - } - - private static final Map VALUES = new HashMap<>(); - - public static CollisionRule from(String name) { - return VALUES.get(name); - } + private static final CollisionRule[] VALUES = values(); - static { - for (CollisionRule rule : values()) { - VALUES.put(rule.getName(), rule); - } + public static CollisionRule from(int id) { + return id >= 0 && id < VALUES.length ? VALUES[id] : VALUES[0]; } } diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/scoreboard/NameTagVisibility.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/scoreboard/NameTagVisibility.java index 3190916df..8b2b21d96 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/scoreboard/NameTagVisibility.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/data/game/scoreboard/NameTagVisibility.java @@ -1,33 +1,14 @@ package org.geysermc.mcprotocollib.protocol.data.game.scoreboard; -import java.util.HashMap; -import java.util.Map; - public enum NameTagVisibility { - ALWAYS("always"), - NEVER("never"), - HIDE_FOR_OTHER_TEAMS("hideForOtherTeams"), - HIDE_FOR_OWN_TEAM("hideForOwnTeam"); - - private final String name; - - NameTagVisibility(String name) { - this.name = name; - } + ALWAYS, + NEVER, + HIDE_FOR_OTHER_TEAMS, + HIDE_FOR_OWN_TEAM; - public String getName() { - return this.name; - } - - private static final Map VALUES = new HashMap<>(); - - public static NameTagVisibility from(String name) { - return VALUES.get(name); - } + private static final NameTagVisibility[] VALUES = values(); - static { - for (NameTagVisibility option : values()) { - VALUES.put(option.getName(), option); - } + public static NameTagVisibility from(int id) { + return id >= 0 && id < VALUES.length ? VALUES[id] : VALUES[0]; } } diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/ClientboundCommandsPacket.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/ClientboundCommandsPacket.java index 199042351..1dac88b07 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/ClientboundCommandsPacket.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/ClientboundCommandsPacket.java @@ -136,7 +136,7 @@ public ClientboundCommandsPacket(ByteBuf in) { } case SCORE_HOLDER -> properties = new ScoreHolderProperties(in.readBoolean()); case TIME -> properties = new TimeProperties(in.readInt()); - case RESOURCE_OR_TAG, RESOURCE_OR_TAG_KEY, RESOURCE, RESOURCE_KEY -> properties = new ResourceProperties(MinecraftTypes.readResourceLocation(in)); + case RESOURCE_OR_TAG, RESOURCE_OR_TAG_KEY, RESOURCE, RESOURCE_KEY, RESOURCE_SELECTOR -> properties = new ResourceProperties(MinecraftTypes.readResourceLocation(in)); default -> { } } @@ -287,7 +287,7 @@ public void serialize(ByteBuf out) { } case SCORE_HOLDER -> out.writeBoolean(((ScoreHolderProperties) node.getProperties()).isAllowMultiple()); case TIME -> out.writeInt(((TimeProperties) node.getProperties()).getMin()); - case RESOURCE_OR_TAG, RESOURCE_OR_TAG_KEY, RESOURCE, RESOURCE_KEY -> MinecraftTypes.writeResourceLocation(out, ((ResourceProperties) node.getProperties()).getRegistryKey()); + case RESOURCE_OR_TAG, RESOURCE_OR_TAG_KEY, RESOURCE, RESOURCE_KEY, RESOURCE_SELECTOR -> MinecraftTypes.writeResourceLocation(out, ((ResourceProperties) node.getProperties()).getRegistryKey()); default -> { } } diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/ClientboundPlayerChatPacket.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/ClientboundPlayerChatPacket.java index ea28a4127..3999d48c5 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/ClientboundPlayerChatPacket.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/ClientboundPlayerChatPacket.java @@ -21,6 +21,7 @@ @With @AllArgsConstructor public class ClientboundPlayerChatPacket implements MinecraftPacket { + private final int globalIndex; private final UUID sender; private final int index; private final byte @Nullable [] messageSignature; @@ -35,6 +36,7 @@ public class ClientboundPlayerChatPacket implements MinecraftPacket { private final @Nullable Component targetName; public ClientboundPlayerChatPacket(ByteBuf in) { + this.globalIndex = MinecraftTypes.readVarInt(in); this.sender = MinecraftTypes.readUUID(in); this.index = MinecraftTypes.readVarInt(in); this.messageSignature = MinecraftTypes.readNullable(in, buf -> { @@ -62,6 +64,7 @@ public ClientboundPlayerChatPacket(ByteBuf in) { @Override public void serialize(ByteBuf out) { + MinecraftTypes.writeVarInt(out, this.globalIndex); MinecraftTypes.writeUUID(out, this.sender); MinecraftTypes.writeVarInt(out, this.index); MinecraftTypes.writeNullable(out, this.messageSignature, ByteBuf::writeBytes); diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/ClientboundTestInstanceBlockStatus.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/ClientboundTestInstanceBlockStatus.java new file mode 100644 index 000000000..dc7e76d1b --- /dev/null +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/ClientboundTestInstanceBlockStatus.java @@ -0,0 +1,35 @@ +package org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound; + +import io.netty.buffer.ByteBuf; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.With; +import net.kyori.adventure.text.Component; +import org.cloudburstmc.math.vector.Vector3i; +import org.geysermc.mcprotocollib.protocol.codec.MinecraftPacket; +import org.geysermc.mcprotocollib.protocol.codec.MinecraftTypes; +import org.jetbrains.annotations.Nullable; + +@Data +@With +@AllArgsConstructor +public class ClientboundTestInstanceBlockStatus implements MinecraftPacket { + private final Component status; + private final @Nullable Vector3i size; + + public ClientboundTestInstanceBlockStatus(ByteBuf in) { + this.status = MinecraftTypes.readComponent(in); + this.size = MinecraftTypes.readNullable(in, MinecraftTypes::readVec3i); + } + + @Override + public void serialize(ByteBuf out) { + MinecraftTypes.writeComponent(out, this.status); + MinecraftTypes.writeNullable(out, this.size, MinecraftTypes::writeVec3i); + } + + @Override + public boolean shouldRunOnGameThread() { + return true; + } +} diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/ClientboundUpdateAdvancementsPacket.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/ClientboundUpdateAdvancementsPacket.java index 8b4061bca..92c3ce839 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/ClientboundUpdateAdvancementsPacket.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/ClientboundUpdateAdvancementsPacket.java @@ -29,6 +29,7 @@ public class ClientboundUpdateAdvancementsPacket implements MinecraftPacket { private final @NonNull Advancement[] advancements; private final @NonNull String[] removedAdvancements; private final @NonNull Map> progress; + private final boolean showAdvancements; public Map getProgress(@NonNull String advancementId) { return this.progress.get(advancementId); @@ -95,6 +96,8 @@ public ClientboundUpdateAdvancementsPacket(ByteBuf in) { this.progress.put(advancementId, advancementProgress); } + + this.showAdvancements = in.readBoolean(); } @Override @@ -165,6 +168,8 @@ public void serialize(ByteBuf out) { } } } + + out.writeBoolean(this.showAdvancements); } @Override diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/entity/spawn/ClientboundAddEntityPacket.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/entity/ClientboundAddEntityPacket.java similarity index 99% rename from protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/entity/spawn/ClientboundAddEntityPacket.java rename to protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/entity/ClientboundAddEntityPacket.java index 64002e4d5..9998e1849 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/entity/spawn/ClientboundAddEntityPacket.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/entity/ClientboundAddEntityPacket.java @@ -1,4 +1,4 @@ -package org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.spawn; +package org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity; import io.netty.buffer.ByteBuf; import lombok.AllArgsConstructor; diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/entity/ClientboundSetEquipmentPacket.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/entity/ClientboundSetEquipmentPacket.java index 688efcece..8b5c7c283 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/entity/ClientboundSetEquipmentPacket.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/entity/ClientboundSetEquipmentPacket.java @@ -27,7 +27,7 @@ public ClientboundSetEquipmentPacket(ByteBuf in) { List list = new ArrayList<>(); while (hasNextEntry) { byte rawSlot = in.readByte(); - EquipmentSlot slot = EquipmentSlot.from(rawSlot & 127); + EquipmentSlot slot = EquipmentSlot.fromEnumOrdinal(rawSlot & 127); ItemStack item = MinecraftTypes.readOptionalItemStack(in); list.add(new Equipment(slot, item)); hasNextEntry = (rawSlot & 128) == 128; diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/entity/spawn/ClientboundAddExperienceOrbPacket.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/entity/spawn/ClientboundAddExperienceOrbPacket.java deleted file mode 100644 index 65e5a87b1..000000000 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/entity/spawn/ClientboundAddExperienceOrbPacket.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.spawn; - -import io.netty.buffer.ByteBuf; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.With; -import org.geysermc.mcprotocollib.protocol.codec.MinecraftPacket; -import org.geysermc.mcprotocollib.protocol.codec.MinecraftTypes; - -@Data -@With -@AllArgsConstructor -public class ClientboundAddExperienceOrbPacket implements MinecraftPacket { - private final int entityId; - private final double x; - private final double y; - private final double z; - private final int exp; - - public ClientboundAddExperienceOrbPacket(ByteBuf in) { - this.entityId = MinecraftTypes.readVarInt(in); - this.x = in.readDouble(); - this.y = in.readDouble(); - this.z = in.readDouble(); - this.exp = in.readShort(); - } - - @Override - public void serialize(ByteBuf out) { - MinecraftTypes.writeVarInt(out, this.entityId); - out.writeDouble(this.x); - out.writeDouble(this.y); - out.writeDouble(this.z); - out.writeShort(this.exp); - } - - @Override - public boolean shouldRunOnGameThread() { - return true; - } -} diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/inventory/ClientboundMerchantOffersPacket.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/inventory/ClientboundMerchantOffersPacket.java index 9abceabc3..93632aa5a 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/inventory/ClientboundMerchantOffersPacket.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/inventory/ClientboundMerchantOffersPacket.java @@ -10,41 +10,41 @@ import org.geysermc.mcprotocollib.protocol.data.game.inventory.VillagerTrade; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; +import java.util.List; + @Data @With @AllArgsConstructor public class ClientboundMerchantOffersPacket implements MinecraftPacket { private final int containerId; - private final @NonNull VillagerTrade[] trades; + private final @NonNull List offers; private final int villagerLevel; - private final int experience; - private final boolean regularVillager; + private final int villagerXp; + private final boolean showProgress; private final boolean canRestock; public ClientboundMerchantOffersPacket(ByteBuf in) { this.containerId = MinecraftTypes.readVarInt(in); - int size = MinecraftTypes.readVarInt(in); - this.trades = new VillagerTrade[size]; - for (int i = 0; i < trades.length; i++) { - ItemStack firstInput = MinecraftTypes.readTradeItemStack(in); - ItemStack output = MinecraftTypes.readOptionalItemStack(in); - ItemStack secondInput = MinecraftTypes.readNullable(in, MinecraftTypes::readTradeItemStack); + this.offers = MinecraftTypes.readList(in, input -> { + VillagerTrade.ItemCost baseCostA = MinecraftTypes.readItemCost(in); + ItemStack result = MinecraftTypes.readItemStack(in); + VillagerTrade.ItemCost costB = MinecraftTypes.readNullable(in, MinecraftTypes::readItemCost); - boolean tradeDisabled = in.readBoolean(); - int numUses = in.readInt(); + boolean outOfStock = in.readBoolean(); + int uses = in.readInt(); int maxUses = in.readInt(); int xp = in.readInt(); - int specialPrice = in.readInt(); + int specialPriceDiff = in.readInt(); float priceMultiplier = in.readFloat(); int demand = in.readInt(); - this.trades[i] = new VillagerTrade(firstInput, secondInput, output, tradeDisabled, numUses, maxUses, xp, specialPrice, priceMultiplier, demand); - } + return new VillagerTrade(baseCostA, result, costB, outOfStock, uses, maxUses, xp, specialPriceDiff, priceMultiplier, demand); + }); this.villagerLevel = MinecraftTypes.readVarInt(in); - this.experience = MinecraftTypes.readVarInt(in); - this.regularVillager = in.readBoolean(); + this.villagerXp = MinecraftTypes.readVarInt(in); + this.showProgress = in.readBoolean(); this.canRestock = in.readBoolean(); } @@ -52,24 +52,23 @@ public ClientboundMerchantOffersPacket(ByteBuf in) { public void serialize(ByteBuf out) { MinecraftTypes.writeVarInt(out, this.containerId); - MinecraftTypes.writeVarInt(out, this.trades.length); - for (VillagerTrade trade : this.trades) { - MinecraftTypes.writeTradeItemStack(out, trade.getFirstInput()); - MinecraftTypes.writeOptionalItemStack(out, trade.getOutput()); - MinecraftTypes.writeNullable(out, trade.getSecondInput(), MinecraftTypes::writeTradeItemStack); + MinecraftTypes.writeList(out, this.offers, (output, offer) -> { + MinecraftTypes.writeItemCost(out, offer.getItemCostA()); + MinecraftTypes.writeItemStack(out, offer.getResult()); + MinecraftTypes.writeNullable(out, offer.getItemCostB(), MinecraftTypes::writeItemCost); - out.writeBoolean(trade.isTradeDisabled()); - out.writeInt(trade.getNumUses()); - out.writeInt(trade.getMaxUses()); - out.writeInt(trade.getXp()); - out.writeInt(trade.getSpecialPrice()); - out.writeFloat(trade.getPriceMultiplier()); - out.writeInt(trade.getDemand()); - } + out.writeBoolean(offer.isOutOfStock()); + out.writeInt(offer.getUses()); + out.writeInt(offer.getMaxUses()); + out.writeInt(offer.getXp()); + out.writeInt(offer.getSpecialPriceDiff()); + out.writeFloat(offer.getPriceMultiplier()); + out.writeInt(offer.getDemand()); + }); MinecraftTypes.writeVarInt(out, this.villagerLevel); - MinecraftTypes.writeVarInt(out, this.experience); - out.writeBoolean(this.regularVillager); + MinecraftTypes.writeVarInt(out, this.villagerXp); + out.writeBoolean(this.showProgress); out.writeBoolean(this.canRestock); } diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/level/ClientboundBlockEventPacket.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/level/ClientboundBlockEventPacket.java index 0966fce54..191967cf1 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/level/ClientboundBlockEventPacket.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/level/ClientboundBlockEventPacket.java @@ -39,16 +39,16 @@ public class ClientboundBlockEventPacket implements MinecraftPacket { // Do we really want these hardcoded values? private static final int NOTE_BLOCK = 109; private static final int STICKY_PISTON = 128; - private static final int PISTON = 135; - private static final int MOB_SPAWNER = 182; - private static final int CHEST = 185; - private static final int ENDER_CHEST = 365; - private static final int TRAPPED_CHEST = 434; - private static final int END_GATEWAY = 631; - private static final int SHULKER_BOX_LOWER = 641; - private static final int SHULKER_BOX_HIGHER = 657; - private static final int BELL = 811; - private static final int DECORATED_POT = 1083; + private static final int PISTON = 138; + private static final int MOB_SPAWNER = 185; + private static final int CHEST = 188; + private static final int ENDER_CHEST = 369; + private static final int TRAPPED_CHEST = 438; + private static final int END_GATEWAY = 635; + private static final int SHULKER_BOX_LOWER = 645; + private static final int SHULKER_BOX_HIGHER = 661; + private static final int BELL = 815; + private static final int DECORATED_POT = 1091; private static final Logger log = LoggerFactory.getLogger(ClientboundBlockEventPacket.class); private final @NonNull Vector3i position; diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/level/ClientboundGameEventPacket.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/level/ClientboundGameEventPacket.java index c4c2cb4c0..17b95c2f7 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/level/ClientboundGameEventPacket.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/level/ClientboundGameEventPacket.java @@ -28,21 +28,21 @@ public ClientboundGameEventPacket(ByteBuf in) { this.notification = GameEvent.from(in.readUnsignedByte()); float value = in.readFloat(); // TODO: Handle this in MinecraftTypes - if (this.notification == GameEvent.AFFECTED_BY_ELDER_GUARDIAN) { + if (this.notification == GameEvent.GUARDIAN_ELDER_EFFECT) { this.value = new ElderGuardianEffectValue(value); - } else if (this.notification == GameEvent.CHANGE_GAMEMODE) { + } else if (this.notification == GameEvent.CHANGE_GAME_MODE) { this.value = GameMode.byId((int) value); - } else if (this.notification == GameEvent.DEMO_MESSAGE) { + } else if (this.notification == GameEvent.DEMO_EVENT) { this.value = DemoMessageValue.from((int) value); - } else if (this.notification == GameEvent.ENTER_CREDITS) { + } else if (this.notification == GameEvent.WIN_GAME) { this.value = EnterCreditsValue.from((int) value); - } else if (this.notification == GameEvent.ENABLE_RESPAWN_SCREEN) { + } else if (this.notification == GameEvent.IMMEDIATE_RESPAWN) { this.value = RespawnScreenValue.from((int) value); } else if (this.notification == GameEvent.LIMITED_CRAFTING) { this.value = LimitedCraftingValue.from((int) value); - } else if (this.notification == GameEvent.RAIN_STRENGTH) { + } else if (this.notification == GameEvent.RAIN_LEVEL_CHANGE) { this.value = new RainStrengthValue(value); - } else if (this.notification == GameEvent.THUNDER_STRENGTH) { + } else if (this.notification == GameEvent.THUNDER_LEVEL_CHANGE) { this.value = new ThunderStrengthValue(value); } else { this.value = null; diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/level/ClientboundLevelChunkWithLightPacket.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/level/ClientboundLevelChunkWithLightPacket.java index 076007492..9a5326baa 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/level/ClientboundLevelChunkWithLightPacket.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/level/ClientboundLevelChunkWithLightPacket.java @@ -8,10 +8,14 @@ import org.cloudburstmc.nbt.NbtMap; import org.geysermc.mcprotocollib.protocol.codec.MinecraftPacket; import org.geysermc.mcprotocollib.protocol.codec.MinecraftTypes; +import org.geysermc.mcprotocollib.protocol.data.game.level.HeightmapTypes; import org.geysermc.mcprotocollib.protocol.data.game.level.LightUpdateData; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityInfo; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; +import java.util.EnumMap; +import java.util.Map; + @Data @With @AllArgsConstructor @@ -19,14 +23,20 @@ public class ClientboundLevelChunkWithLightPacket implements MinecraftPacket { private final int x; private final int z; private final byte @NonNull [] chunkData; - private final @NonNull NbtMap heightMaps; + private final @NonNull Map heightMaps; private final @NonNull BlockEntityInfo @NonNull [] blockEntities; private final @NonNull LightUpdateData lightData; public ClientboundLevelChunkWithLightPacket(ByteBuf in) { this.x = in.readInt(); this.z = in.readInt(); - this.heightMaps = MinecraftTypes.readCompoundTagOrThrow(in); + + this.heightMaps = new EnumMap<>(HeightmapTypes.class); + int length = MinecraftTypes.readVarInt(in); + for (int i = 0; i < length; i++) { + this.heightMaps.put(HeightmapTypes.from(MinecraftTypes.readVarInt(in)), MinecraftTypes.readLongArray(in)); + } + this.chunkData = MinecraftTypes.readByteArray(in); this.blockEntities = new BlockEntityInfo[MinecraftTypes.readVarInt(in)]; @@ -47,7 +57,13 @@ public ClientboundLevelChunkWithLightPacket(ByteBuf in) { public void serialize(ByteBuf out) { out.writeInt(this.x); out.writeInt(this.z); - MinecraftTypes.writeAnyTag(out, this.heightMaps); + + MinecraftTypes.writeVarInt(out, this.heightMaps.size()); + for (Map.Entry entry : this.heightMaps.entrySet()) { + MinecraftTypes.writeVarInt(out, entry.getKey().ordinal()); + MinecraftTypes.writeLongArray(out, entry.getValue()); + } + MinecraftTypes.writeVarInt(out, this.chunkData.length); out.writeBytes(this.chunkData); diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/scoreboard/ClientboundSetPlayerTeamPacket.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/scoreboard/ClientboundSetPlayerTeamPacket.java index 440beca6b..17649e485 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/scoreboard/ClientboundSetPlayerTeamPacket.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/scoreboard/ClientboundSetPlayerTeamPacket.java @@ -115,8 +115,8 @@ public ClientboundSetPlayerTeamPacket(ByteBuf in) { byte flags = in.readByte(); this.friendlyFire = (flags & 0x1) != 0; this.seeFriendlyInvisibles = (flags & 0x2) != 0; - this.nameTagVisibility = NameTagVisibility.from(MinecraftTypes.readString(in)); - this.collisionRule = CollisionRule.from(MinecraftTypes.readString(in)); + this.nameTagVisibility = NameTagVisibility.from(MinecraftTypes.readVarInt(in)); + this.collisionRule = CollisionRule.from(MinecraftTypes.readVarInt(in)); this.color = TeamColor.VALUES[MinecraftTypes.readVarInt(in)]; @@ -150,8 +150,8 @@ public void serialize(ByteBuf out) { if (this.action == TeamAction.CREATE || this.action == TeamAction.UPDATE) { MinecraftTypes.writeComponent(out, this.displayName); out.writeByte((this.friendlyFire ? 0x1 : 0x0) | (this.seeFriendlyInvisibles ? 0x2 : 0x0)); - MinecraftTypes.writeString(out, this.nameTagVisibility == null ? "" : this.nameTagVisibility.getName()); - MinecraftTypes.writeString(out, this.collisionRule == null ? "" : this.collisionRule.getName()); + MinecraftTypes.writeVarInt(out, this.nameTagVisibility.ordinal()); + MinecraftTypes.writeVarInt(out, this.collisionRule.ordinal()); MinecraftTypes.writeVarInt(out, this.color.ordinal()); MinecraftTypes.writeComponent(out, this.prefix); MinecraftTypes.writeComponent(out, this.suffix); diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/serverbound/ServerboundChatCommandSignedPacket.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/serverbound/ServerboundChatCommandSignedPacket.java index ee4cc4799..cb8ac64f4 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/serverbound/ServerboundChatCommandSignedPacket.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/serverbound/ServerboundChatCommandSignedPacket.java @@ -22,6 +22,7 @@ public class ServerboundChatCommandSignedPacket implements MinecraftPacket { private final List signatures; private final int offset; private final BitSet acknowledgedMessages; + private final byte checksum; public ServerboundChatCommandSignedPacket(ByteBuf in) { this.command = MinecraftTypes.readString(in); @@ -37,6 +38,7 @@ public ServerboundChatCommandSignedPacket(ByteBuf in) { this.offset = MinecraftTypes.readVarInt(in); this.acknowledgedMessages = MinecraftTypes.readFixedBitSet(in, 20); + this.checksum = in.readByte(); } @Override @@ -52,5 +54,6 @@ public void serialize(ByteBuf out) { MinecraftTypes.writeVarInt(out, this.offset); MinecraftTypes.writeFixedBitSet(out, this.acknowledgedMessages, 20); + out.writeByte(this.checksum); } } diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/serverbound/ServerboundChatPacket.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/serverbound/ServerboundChatPacket.java index d6631f6da..e38422305 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/serverbound/ServerboundChatPacket.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/serverbound/ServerboundChatPacket.java @@ -21,6 +21,7 @@ public class ServerboundChatPacket implements MinecraftPacket { private final byte @Nullable [] signature; private final int offset; private final BitSet acknowledgedMessages; + private final int checksum; public ServerboundChatPacket(ByteBuf in) { this.message = MinecraftTypes.readString(in); @@ -34,6 +35,7 @@ public ServerboundChatPacket(ByteBuf in) { this.offset = MinecraftTypes.readVarInt(in); this.acknowledgedMessages = MinecraftTypes.readFixedBitSet(in, 20); + this.checksum = in.readByte(); } @Override @@ -45,5 +47,6 @@ public void serialize(ByteBuf out) { MinecraftTypes.writeVarInt(out, this.offset); MinecraftTypes.writeFixedBitSet(out, this.acknowledgedMessages, 20); + out.writeByte(this.checksum); } } diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/serverbound/inventory/ServerboundContainerClickPacket.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/serverbound/inventory/ServerboundContainerClickPacket.java index e0408e3bc..8d76d7256 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/serverbound/inventory/ServerboundContainerClickPacket.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/serverbound/inventory/ServerboundContainerClickPacket.java @@ -18,7 +18,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.inventory.MoveToHotbarAction; import org.geysermc.mcprotocollib.protocol.data.game.inventory.ShiftClickItemAction; import org.geysermc.mcprotocollib.protocol.data.game.inventory.SpreadItemAction; -import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.data.game.item.HashedStack; import java.util.Map; @@ -32,18 +32,18 @@ public class ServerboundContainerClickPacket implements MinecraftPacket { private final int slot; private final @NonNull ContainerActionType action; private final @NonNull ContainerAction param; - private final @Nullable ItemStack carriedItem; - private final @NonNull Int2ObjectMap<@Nullable ItemStack> changedSlots; + private final @Nullable HashedStack carriedItem; + private final @NonNull Int2ObjectMap<@Nullable HashedStack> changedSlots; public ServerboundContainerClickPacket(int containerId, int stateId, int slot, @NonNull ContainerActionType action, @NonNull ContainerAction param, - @Nullable ItemStack carriedItem, @NonNull Map changedSlots) { + @Nullable HashedStack carriedItem, @NonNull Map changedSlots) { this(containerId, stateId, slot, action, param, carriedItem, new Int2ObjectOpenHashMap<>(changedSlots)); } public ServerboundContainerClickPacket(int containerId, int stateId, int slot, @NonNull ContainerActionType action, @NonNull ContainerAction param, - @Nullable ItemStack carriedItem, @NonNull Int2ObjectMap<@Nullable ItemStack> changedSlots) { + @Nullable HashedStack carriedItem, @NonNull Int2ObjectMap<@Nullable HashedStack> changedSlots) { if ((param == DropItemAction.LEFT_CLICK_OUTSIDE_NOT_HOLDING || param == DropItemAction.RIGHT_CLICK_OUTSIDE_NOT_HOLDING) && slot != -CLICK_OUTSIDE_NOT_HOLDING_SLOT) { throw new IllegalArgumentException("Slot must be " + CLICK_OUTSIDE_NOT_HOLDING_SLOT @@ -87,11 +87,11 @@ public ServerboundContainerClickPacket(ByteBuf in) { this.changedSlots = new Int2ObjectOpenHashMap<>(changedItemsSize); for (int i = 0; i < changedItemsSize; i++) { int key = in.readShort(); - ItemStack value = MinecraftTypes.readOptionalItemStack(in); + HashedStack value = MinecraftTypes.readNullable(in, MinecraftTypes::readHashedStack); this.changedSlots.put(key, value); } - this.carriedItem = MinecraftTypes.readOptionalItemStack(in); + this.carriedItem = MinecraftTypes.readNullable(in, MinecraftTypes::readHashedStack); } @Override @@ -109,12 +109,12 @@ public void serialize(ByteBuf out) { out.writeByte(this.action.ordinal()); MinecraftTypes.writeVarInt(out, this.changedSlots.size()); - for (Int2ObjectMap.Entry pair : this.changedSlots.int2ObjectEntrySet()) { + for (Int2ObjectMap.Entry pair : this.changedSlots.int2ObjectEntrySet()) { out.writeShort(pair.getIntKey()); - MinecraftTypes.writeOptionalItemStack(out, pair.getValue()); + MinecraftTypes.writeNullable(out, pair.getValue(), MinecraftTypes::writeHashedStack); } - MinecraftTypes.writeOptionalItemStack(out, this.carriedItem); + MinecraftTypes.writeNullable(out, this.carriedItem, MinecraftTypes::writeHashedStack); } @Override diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/serverbound/inventory/ServerboundSetCreativeModeSlotPacket.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/serverbound/inventory/ServerboundSetCreativeModeSlotPacket.java index 26be4f1bb..82f82a23a 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/serverbound/inventory/ServerboundSetCreativeModeSlotPacket.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/serverbound/inventory/ServerboundSetCreativeModeSlotPacket.java @@ -18,13 +18,13 @@ public class ServerboundSetCreativeModeSlotPacket implements MinecraftPacket { public ServerboundSetCreativeModeSlotPacket(ByteBuf in) { this.slot = in.readShort(); - this.clickedItem = MinecraftTypes.readOptionalItemStack(in); + this.clickedItem = MinecraftTypes.readOptionalItemStack(in, true); } @Override public void serialize(ByteBuf out) { out.writeShort(this.slot); - MinecraftTypes.writeOptionalItemStack(out, this.clickedItem); + MinecraftTypes.writeOptionalItemStack(out, this.clickedItem, true); } @Override diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/serverbound/inventory/ServerboundSetStructureBlockPacket.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/serverbound/inventory/ServerboundSetStructureBlockPacket.java index 62a88701e..4ee42d8ce 100644 --- a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/serverbound/inventory/ServerboundSetStructureBlockPacket.java +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/serverbound/inventory/ServerboundSetStructureBlockPacket.java @@ -20,6 +20,7 @@ public class ServerboundSetStructureBlockPacket implements MinecraftPacket { private static final int FLAG_IGNORE_ENTITIES = 0x01; private static final int FLAG_SHOW_AIR = 0x02; private static final int FLAG_SHOW_BOUNDING_BOX = 0x04; + private static final int FLAG_STRICT = 0x08; private final @NonNull Vector3i position; private final @NonNull UpdateStructureBlockAction action; @@ -35,6 +36,7 @@ public class ServerboundSetStructureBlockPacket implements MinecraftPacket { private final boolean ignoreEntities; private final boolean showAir; private final boolean showBoundingBox; + private final boolean strict; public ServerboundSetStructureBlockPacket(ByteBuf in) { this.position = MinecraftTypes.readPosition(in); @@ -53,6 +55,7 @@ public ServerboundSetStructureBlockPacket(ByteBuf in) { this.ignoreEntities = (flags & FLAG_IGNORE_ENTITIES) != 0; this.showAir = (flags & FLAG_SHOW_AIR) != 0; this.showBoundingBox = (flags & FLAG_SHOW_BOUNDING_BOX) != 0; + this.strict = (flags & FLAG_STRICT) != 0; } @Override @@ -86,6 +89,10 @@ public void serialize(ByteBuf out) { flags |= FLAG_SHOW_BOUNDING_BOX; } + if (this.strict) { + flags |= FLAG_STRICT; + } + out.writeByte(flags); } diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/serverbound/level/ServerboundSetTestBlockPacket.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/serverbound/level/ServerboundSetTestBlockPacket.java new file mode 100644 index 000000000..f1647af33 --- /dev/null +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/serverbound/level/ServerboundSetTestBlockPacket.java @@ -0,0 +1,36 @@ +package org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level; + +import io.netty.buffer.ByteBuf; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.With; +import org.cloudburstmc.math.vector.Vector3i; +import org.geysermc.mcprotocollib.protocol.codec.MinecraftPacket; +import org.geysermc.mcprotocollib.protocol.codec.MinecraftTypes; + +@Data +@With +@AllArgsConstructor +public class ServerboundSetTestBlockPacket implements MinecraftPacket { + private final Vector3i position; + private final int mode; + private final String message; + + public ServerboundSetTestBlockPacket(ByteBuf in) { + this.position = MinecraftTypes.readPosition(in); + this.mode = MinecraftTypes.readVarInt(in); + this.message = MinecraftTypes.readString(in); + } + + @Override + public void serialize(ByteBuf out) { + MinecraftTypes.writePosition(out, this.position); + MinecraftTypes.writeVarInt(out, this.mode); + MinecraftTypes.writeString(out, this.message); + } + + @Override + public boolean shouldRunOnGameThread() { + return true; + } +} diff --git a/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/serverbound/level/ServerboundTestInstanceBlockActionPacket.java b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/serverbound/level/ServerboundTestInstanceBlockActionPacket.java new file mode 100644 index 000000000..f73db6f7a --- /dev/null +++ b/protocol/src/main/java/org/geysermc/mcprotocollib/protocol/packet/ingame/serverbound/level/ServerboundTestInstanceBlockActionPacket.java @@ -0,0 +1,37 @@ +package org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level; + +import io.netty.buffer.ByteBuf; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.With; +import org.cloudburstmc.math.vector.Vector3i; +import org.geysermc.mcprotocollib.protocol.codec.MinecraftPacket; +import org.geysermc.mcprotocollib.protocol.codec.MinecraftTypes; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.TestInstanceBlockEntity; + +@Data +@With +@AllArgsConstructor +public class ServerboundTestInstanceBlockActionPacket implements MinecraftPacket { + private final Vector3i pos; + private final int action; + private final TestInstanceBlockEntity data; + + public ServerboundTestInstanceBlockActionPacket(ByteBuf in) { + this.pos = MinecraftTypes.readPosition(in); + this.action = MinecraftTypes.readVarInt(in); + this.data = MinecraftTypes.readTestBlockEntity(in); + } + + @Override + public void serialize(ByteBuf out) { + MinecraftTypes.writePosition(out, this.pos); + MinecraftTypes.writeVarInt(out, this.action); + MinecraftTypes.writeTestBlockEntity(out, this.data); + } + + @Override + public boolean shouldRunOnGameThread() { + return true; + } +} diff --git a/protocol/src/main/resources/networkCodec.nbt b/protocol/src/main/resources/networkCodec.nbt index 00853fc3c..3c048c134 100644 Binary files a/protocol/src/main/resources/networkCodec.nbt and b/protocol/src/main/resources/networkCodec.nbt differ diff --git a/protocol/src/test/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/level/ClientboundLevelChunkWithLightPacketTest.java b/protocol/src/test/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/level/ClientboundLevelChunkWithLightPacketTest.java index f4a52ca0a..0c1bc300b 100644 --- a/protocol/src/test/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/level/ClientboundLevelChunkWithLightPacketTest.java +++ b/protocol/src/test/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/level/ClientboundLevelChunkWithLightPacketTest.java @@ -1,6 +1,5 @@ package org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level; -import org.cloudburstmc.nbt.NbtMap; import org.geysermc.mcprotocollib.protocol.data.game.level.LightUpdateData; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityInfo; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; @@ -9,17 +8,18 @@ import java.util.BitSet; import java.util.Collections; +import java.util.Map; public class ClientboundLevelChunkWithLightPacketTest extends PacketTest { @BeforeEach public void setup() { this.setPackets( new ClientboundLevelChunkWithLightPacket(0, 0, - new byte[0], NbtMap.EMPTY, new BlockEntityInfo[0], + new byte[0], Map.of(), new BlockEntityInfo[0], new LightUpdateData(new BitSet(), new BitSet(), new BitSet(), new BitSet(), Collections.emptyList(), Collections.emptyList()) ), new ClientboundLevelChunkWithLightPacket(1, 1, - new byte[256], NbtMap.EMPTY, new BlockEntityInfo[]{ + new byte[256], Map.of(), new BlockEntityInfo[]{ new BlockEntityInfo(1, 0, 1, BlockEntityType.CHEST, null) }, new LightUpdateData(new BitSet(), new BitSet(), new BitSet(), new BitSet(), Collections.emptyList(), Collections.emptyList()) ) diff --git a/protocol/src/test/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/level/ClientboundSetEntityDataPacketTest.java b/protocol/src/test/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/level/ClientboundSetEntityDataPacketTest.java index 4e6062561..caf39f69c 100644 --- a/protocol/src/test/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/level/ClientboundSetEntityDataPacketTest.java +++ b/protocol/src/test/java/org/geysermc/mcprotocollib/protocol/packet/ingame/clientbound/level/ClientboundSetEntityDataPacketTest.java @@ -31,10 +31,10 @@ public void setup() { new IntEntityMetadata(2, MetadataTypes.INT, 555), new FloatEntityMetadata(3, MetadataTypes.FLOAT, 3.0f), new LongEntityMetadata(8, MetadataTypes.LONG, 123456789L), - new ObjectEntityMetadata<>(5, MetadataTypes.POSITION, Vector3i.from(0, 1, 0)), + new ObjectEntityMetadata<>(5, MetadataTypes.BLOCK_POS, Vector3i.from(0, 1, 0)), new ObjectEntityMetadata<>(2, MetadataTypes.BLOCK_STATE, 60), new ObjectEntityMetadata<>(6, MetadataTypes.DIRECTION, Direction.EAST), - new ObjectEntityMetadata<>(7, MetadataTypes.OPTIONAL_VARINT, OptionalInt.of(1038)) + new ObjectEntityMetadata<>(7, MetadataTypes.OPTIONAL_UNSIGNED_INT, OptionalInt.of(1038)) }), new ClientboundSetEntityDataPacket(700, new EntityMetadata[]{ // Boxed variation test