From 23bcfc7b201376539f46e2da06649575e8a3b51e Mon Sep 17 00:00:00 2001 From: BoomEaro <21033866+BoomEaro@users.noreply.github.com> Date: Wed, 6 Dec 2023 18:21:54 +0200 Subject: [PATCH 1/7] Add support for 1.20.3 --- build.gradle | 1 + .../limbo/connection/ClientConnection.java | 9 ++ .../limbo/connection/PacketSnapshots.java | 34 +++++- .../ua/nanit/limbo/protocol/ByteMessage.java | 58 ++++++++- .../ua/nanit/limbo/protocol/NbtMessage.java | 30 +++++ .../protocol/packets/play/PacketBossBar.java | 2 +- .../packets/play/PacketChatMessage.java | 9 +- .../packets/play/PacketEmptyChunk.java | 47 ++++++++ .../packets/play/PacketGameEvent.java | 25 ++++ .../packets/play/PacketPlayerListHeader.java | 13 ++- .../packets/play/PacketTitleSetSubTitle.java | 7 +- .../packets/play/PacketTitleSetTitle.java | 7 +- .../nanit/limbo/protocol/registry/State.java | 61 ++++++---- .../limbo/protocol/registry/Version.java | 3 +- .../ua/nanit/limbo/server/data/BossBar.java | 10 +- .../ua/nanit/limbo/server/data/Title.java | 18 +-- .../ua/nanit/limbo/util/NbtMessageUtil.java | 110 ++++++++++++++++++ 17 files changed, 381 insertions(+), 63 deletions(-) create mode 100644 src/main/java/ua/nanit/limbo/protocol/NbtMessage.java create mode 100644 src/main/java/ua/nanit/limbo/protocol/packets/play/PacketEmptyChunk.java create mode 100644 src/main/java/ua/nanit/limbo/protocol/packets/play/PacketGameEvent.java create mode 100644 src/main/java/ua/nanit/limbo/util/NbtMessageUtil.java diff --git a/build.gradle b/build.gradle index b406842f..3e340d3e 100644 --- a/build.gradle +++ b/build.gradle @@ -28,6 +28,7 @@ dependencies { implementation 'io.netty:netty-all:4.1.99.Final' implementation 'net.kyori:adventure-nbt:4.14.0' implementation 'com.grack:nanojson:1.8' + implementation 'com.google.code.gson:gson:2.10.1' } buildConfig { diff --git a/src/main/java/ua/nanit/limbo/connection/ClientConnection.java b/src/main/java/ua/nanit/limbo/connection/ClientConnection.java index 717f2ac9..13f8207d 100644 --- a/src/main/java/ua/nanit/limbo/connection/ClientConnection.java +++ b/src/main/java/ua/nanit/limbo/connection/ClientConnection.java @@ -30,6 +30,7 @@ import ua.nanit.limbo.connection.pipeline.PacketEncoder; import ua.nanit.limbo.protocol.ByteMessage; import ua.nanit.limbo.protocol.Packet; +import ua.nanit.limbo.protocol.PacketSnapshot; import ua.nanit.limbo.protocol.packets.login.PacketDisconnect; import ua.nanit.limbo.protocol.packets.play.PacketKeepAlive; import ua.nanit.limbo.protocol.registry.State; @@ -175,6 +176,14 @@ public void spawnPlayer() { if (PacketSnapshots.PACKET_HEADER_AND_FOOTER != null && clientVersion.moreOrEqual(Version.V1_8)) writePacket(PacketSnapshots.PACKET_HEADER_AND_FOOTER); + if (clientVersion.moreOrEqual(Version.V1_20_3)) { + sendPacket(PacketSnapshots.PACKET_START_WAITING_CHUNKS); + + for (PacketSnapshot chunk : PacketSnapshots.PACKETS_EMPTY_CHUNKS) { + sendPacket(chunk); + } + } + sendKeepAlive(); }; diff --git a/src/main/java/ua/nanit/limbo/connection/PacketSnapshots.java b/src/main/java/ua/nanit/limbo/connection/PacketSnapshots.java index b52ef262..0c82723f 100644 --- a/src/main/java/ua/nanit/limbo/connection/PacketSnapshots.java +++ b/src/main/java/ua/nanit/limbo/connection/PacketSnapshots.java @@ -25,9 +25,12 @@ import ua.nanit.limbo.protocol.packets.play.*; import ua.nanit.limbo.server.LimboServer; import ua.nanit.limbo.server.data.Title; +import ua.nanit.limbo.util.NbtMessageUtil; import ua.nanit.limbo.util.UuidUtil; +import java.util.ArrayList; import java.util.Collections; +import java.util.List; import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; @@ -59,6 +62,9 @@ public final class PacketSnapshots { public static PacketSnapshot PACKET_REGISTRY_DATA; public static PacketSnapshot PACKET_FINISH_CONFIGURATION; + public static List PACKETS_EMPTY_CHUNKS; + public static PacketSnapshot PACKET_START_WAITING_CHUNKS; + private PacketSnapshots() { } public static void initPackets(LimboServer server) { @@ -121,8 +127,8 @@ public static void initPackets(LimboServer server) { if (server.getConfig().isUseHeaderAndFooter()) { PacketPlayerListHeader header = new PacketPlayerListHeader(); - header.setHeader(server.getConfig().getPlayerListHeader()); - header.setFooter(server.getConfig().getPlayerListFooter()); + header.setHeader(NbtMessageUtil.create(server.getConfig().getPlayerListHeader())); + header.setFooter(NbtMessageUtil.create(server.getConfig().getPlayerListFooter())); PACKET_HEADER_AND_FOOTER = PacketSnapshot.of(header); } @@ -135,7 +141,7 @@ public static void initPackets(LimboServer server) { if (server.getConfig().isUseJoinMessage()) { PacketChatMessage joinMessage = new PacketChatMessage(); - joinMessage.setJsonData(server.getConfig().getJoinMessage()); + joinMessage.setMessage(NbtMessageUtil.create(server.getConfig().getJoinMessage())); joinMessage.setPosition(PacketChatMessage.PositionLegacy.SYSTEM_MESSAGE); joinMessage.setSender(UUID.randomUUID()); PACKET_JOIN_MESSAGE = PacketSnapshot.of(joinMessage); @@ -188,5 +194,27 @@ public static void initPackets(LimboServer server) { PACKET_REGISTRY_DATA = PacketSnapshot.of(packetRegistryData); PACKET_FINISH_CONFIGURATION = PacketSnapshot.of(new PacketFinishConfiguration()); + + PacketGameEvent packetGameEvent = new PacketGameEvent(); + packetGameEvent.setType((byte) 13); // Waiting for chunks type + packetGameEvent.setValue(0); + PACKET_START_WAITING_CHUNKS = PacketSnapshot.of(packetGameEvent); + + int chunkXOffset = (int) 0 >> 4; // Default x position is 0 + int chunkZOffset = (int) 0 >> 4; // Default z position is 0 + int chunkEdgeSize = 1; // TODO Make configurable? + + List emptyChunks = new ArrayList<>(); + // Make multiple chunks for edges + for (int chunkX = chunkXOffset - chunkEdgeSize; chunkX <= chunkXOffset + chunkEdgeSize; ++chunkX) { + for (int chunkZ = chunkZOffset - chunkEdgeSize; chunkZ <= chunkZOffset + chunkEdgeSize; ++chunkZ) { + PacketEmptyChunk packetEmptyChunk = new PacketEmptyChunk(); + packetEmptyChunk.setX(chunkX); + packetEmptyChunk.setZ(chunkZ); + + emptyChunks.add(PacketSnapshot.of(packetEmptyChunk)); + } + } + PACKETS_EMPTY_CHUNKS = emptyChunks; } } diff --git a/src/main/java/ua/nanit/limbo/protocol/ByteMessage.java b/src/main/java/ua/nanit/limbo/protocol/ByteMessage.java index 65fe318e..543bcf04 100644 --- a/src/main/java/ua/nanit/limbo/protocol/ByteMessage.java +++ b/src/main/java/ua/nanit/limbo/protocol/ByteMessage.java @@ -21,9 +21,8 @@ import io.netty.handler.codec.DecoderException; import io.netty.handler.codec.EncoderException; import io.netty.util.ByteProcessor; -import net.kyori.adventure.nbt.BinaryTagIO; -import net.kyori.adventure.nbt.BinaryTagTypes; -import net.kyori.adventure.nbt.CompoundBinaryTag; +import net.kyori.adventure.nbt.*; +import ua.nanit.limbo.protocol.registry.Version; import java.io.IOException; import java.io.InputStream; @@ -194,16 +193,63 @@ public void writeCompoundTag(CompoundBinaryTag compoundTag) { } } - public void writeNamelessCompoundTag(CompoundBinaryTag compoundTag) { + public void writeNamelessCompoundTag(BinaryTag binaryTag) { try (ByteBufOutputStream stream = new ByteBufOutputStream(buf)) { - stream.writeByte(10); // CompoundTag ID - BinaryTagTypes.COMPOUND.write(compoundTag, stream); + stream.writeByte(binaryTag.type().id()); + + // TODO Find a way to improve this... + if (binaryTag instanceof CompoundBinaryTag) { + CompoundBinaryTag tag = (CompoundBinaryTag) binaryTag; + tag.type().write(tag, stream); + } + else if (binaryTag instanceof ByteBinaryTag) { + ByteBinaryTag tag = (ByteBinaryTag) binaryTag; + tag.type().write(tag, stream); + } + else if (binaryTag instanceof ShortBinaryTag) { + ShortBinaryTag tag = (ShortBinaryTag) binaryTag; + tag.type().write(tag, stream); + } + else if (binaryTag instanceof IntBinaryTag) { + IntBinaryTag tag = (IntBinaryTag) binaryTag; + tag.type().write(tag, stream); + } + else if (binaryTag instanceof LongBinaryTag) { + LongBinaryTag tag = (LongBinaryTag) binaryTag; + tag.type().write(tag, stream); + } + else if (binaryTag instanceof DoubleBinaryTag) { + DoubleBinaryTag tag = (DoubleBinaryTag) binaryTag; + tag.type().write(tag, stream); + } + else if (binaryTag instanceof StringBinaryTag) { + StringBinaryTag tag = (StringBinaryTag) binaryTag; + tag.type().write(tag, stream); + } + else if (binaryTag instanceof ListBinaryTag) { + ListBinaryTag tag = (ListBinaryTag) binaryTag; + tag.type().write(tag, stream); + } + else if (binaryTag instanceof EndBinaryTag) { + EndBinaryTag tag = (EndBinaryTag) binaryTag; + tag.type().write(tag, stream); + } + } catch (IOException e) { throw new EncoderException("Cannot write NBT CompoundTag"); } } + public void writeNbtMessage(NbtMessage nbtMessage, Version version) { + if (version.moreOrEqual(Version.V1_20_3)) { + writeNamelessCompoundTag(nbtMessage.getTag()); + } + else { + writeString(nbtMessage.getJson()); + } + } + public > void writeEnumSet(EnumSet enumset, Class oclass) { E[] enums = oclass.getEnumConstants(); BitSet bits = new BitSet(enums.length); diff --git a/src/main/java/ua/nanit/limbo/protocol/NbtMessage.java b/src/main/java/ua/nanit/limbo/protocol/NbtMessage.java new file mode 100644 index 00000000..92fab995 --- /dev/null +++ b/src/main/java/ua/nanit/limbo/protocol/NbtMessage.java @@ -0,0 +1,30 @@ +package ua.nanit.limbo.protocol; + +import net.kyori.adventure.nbt.BinaryTag; + +public class NbtMessage { + + private String json; + private BinaryTag tag; + + public NbtMessage(String json, BinaryTag tag) { + this.json = json; + this.tag = tag; + } + + public String getJson() { + return json; + } + + public void setJson(String json) { + this.json = json; + } + + public BinaryTag getTag() { + return tag; + } + + public void setTag(BinaryTag tag) { + this.tag = tag; + } +} diff --git a/src/main/java/ua/nanit/limbo/protocol/packets/play/PacketBossBar.java b/src/main/java/ua/nanit/limbo/protocol/packets/play/PacketBossBar.java index 68201a72..44f2de9c 100644 --- a/src/main/java/ua/nanit/limbo/protocol/packets/play/PacketBossBar.java +++ b/src/main/java/ua/nanit/limbo/protocol/packets/play/PacketBossBar.java @@ -49,7 +49,7 @@ public void setFlags(int flags) { public void encode(ByteMessage msg, Version version) { msg.writeUuid(uuid); msg.writeVarInt(0); // Create bossbar - msg.writeString(bossBar.getText()); + msg.writeNbtMessage(bossBar.getText(), version); msg.writeFloat(bossBar.getHealth()); msg.writeVarInt(bossBar.getColor().getIndex()); msg.writeVarInt(bossBar.getDivision().getIndex()); diff --git a/src/main/java/ua/nanit/limbo/protocol/packets/play/PacketChatMessage.java b/src/main/java/ua/nanit/limbo/protocol/packets/play/PacketChatMessage.java index 2883ac9c..7fa72995 100644 --- a/src/main/java/ua/nanit/limbo/protocol/packets/play/PacketChatMessage.java +++ b/src/main/java/ua/nanit/limbo/protocol/packets/play/PacketChatMessage.java @@ -18,6 +18,7 @@ package ua.nanit.limbo.protocol.packets.play; import ua.nanit.limbo.protocol.ByteMessage; +import ua.nanit.limbo.protocol.NbtMessage; import ua.nanit.limbo.protocol.PacketOut; import ua.nanit.limbo.protocol.registry.Version; @@ -25,12 +26,12 @@ public class PacketChatMessage implements PacketOut { - private String jsonData; + private NbtMessage message; private PositionLegacy position; private UUID sender; - public void setJsonData(String jsonData) { - this.jsonData = jsonData; + public void setMessage(NbtMessage message) { + this.message = message; } public void setPosition(PositionLegacy position) { @@ -43,7 +44,7 @@ public void setSender(UUID sender) { @Override public void encode(ByteMessage msg, Version version) { - msg.writeString(jsonData); + msg.writeNbtMessage(message, version); if (version.moreOrEqual(Version.V1_19_1)) { msg.writeBoolean(position.index == PositionLegacy.ACTION_BAR.index); } else if (version.moreOrEqual(Version.V1_19)) { diff --git a/src/main/java/ua/nanit/limbo/protocol/packets/play/PacketEmptyChunk.java b/src/main/java/ua/nanit/limbo/protocol/packets/play/PacketEmptyChunk.java new file mode 100644 index 00000000..ed10346b --- /dev/null +++ b/src/main/java/ua/nanit/limbo/protocol/packets/play/PacketEmptyChunk.java @@ -0,0 +1,47 @@ +package ua.nanit.limbo.protocol.packets.play; + +import net.kyori.adventure.nbt.CompoundBinaryTag; +import net.kyori.adventure.nbt.LongArrayBinaryTag; +import ua.nanit.limbo.protocol.ByteMessage; +import ua.nanit.limbo.protocol.PacketOut; +import ua.nanit.limbo.protocol.registry.Version; + +public class PacketEmptyChunk implements PacketOut { + + private int x; + private int z; + + public void setX(int x) { + this.x = x; + } + + public void setZ(int z) { + this.z = z; + } + + @Override + public void encode(ByteMessage msg, Version version) { + msg.writeInt(x); + msg.writeInt(z); + + LongArrayBinaryTag longArrayTag = LongArrayBinaryTag.longArrayBinaryTag(new long[37]); + CompoundBinaryTag tag = CompoundBinaryTag.builder() + .put("MOTION_BLOCKING", longArrayTag).build(); + CompoundBinaryTag rootTag = CompoundBinaryTag.builder() + .put("root", tag).build(); + msg.writeNamelessCompoundTag(rootTag); + + byte[] sectionData = new byte[]{0, 0, 0, 0, 0, 0, 1, 0}; + msg.writeVarInt(sectionData.length * 16); + for (int i = 0; i < 16; i++) { + msg.writeBytes(sectionData); + } + + msg.writeVarInt(0); + + byte[] lightData = new byte[]{1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 3, -1, -1, 0, 0}; + msg.ensureWritable(lightData.length); + msg.writeBytes(lightData, 1, lightData.length - 1); + } + +} diff --git a/src/main/java/ua/nanit/limbo/protocol/packets/play/PacketGameEvent.java b/src/main/java/ua/nanit/limbo/protocol/packets/play/PacketGameEvent.java new file mode 100644 index 00000000..511223bd --- /dev/null +++ b/src/main/java/ua/nanit/limbo/protocol/packets/play/PacketGameEvent.java @@ -0,0 +1,25 @@ +package ua.nanit.limbo.protocol.packets.play; + +import ua.nanit.limbo.protocol.ByteMessage; +import ua.nanit.limbo.protocol.PacketOut; +import ua.nanit.limbo.protocol.registry.Version; + +public class PacketGameEvent implements PacketOut { + + private byte type; + private float value; + + public void setType(byte type) { + this.type = type; + } + + public void setValue(float value) { + this.value = value; + } + + @Override + public void encode(ByteMessage msg, Version version) { + msg.writeByte(type); + msg.writeFloat(value); + } +} diff --git a/src/main/java/ua/nanit/limbo/protocol/packets/play/PacketPlayerListHeader.java b/src/main/java/ua/nanit/limbo/protocol/packets/play/PacketPlayerListHeader.java index 2fe062ca..8bfb0083 100644 --- a/src/main/java/ua/nanit/limbo/protocol/packets/play/PacketPlayerListHeader.java +++ b/src/main/java/ua/nanit/limbo/protocol/packets/play/PacketPlayerListHeader.java @@ -18,25 +18,26 @@ package ua.nanit.limbo.protocol.packets.play; import ua.nanit.limbo.protocol.ByteMessage; +import ua.nanit.limbo.protocol.NbtMessage; import ua.nanit.limbo.protocol.PacketOut; import ua.nanit.limbo.protocol.registry.Version; public class PacketPlayerListHeader implements PacketOut { - private String header; - private String footer; + private NbtMessage header; + private NbtMessage footer; - public void setHeader(String header) { + public void setHeader(NbtMessage header) { this.header = header; } - public void setFooter(String footer) { + public void setFooter(NbtMessage footer) { this.footer = footer; } @Override public void encode(ByteMessage msg, Version version) { - msg.writeString(header); - msg.writeString(footer); + msg.writeNbtMessage(header, version); + msg.writeNbtMessage(footer, version); } } diff --git a/src/main/java/ua/nanit/limbo/protocol/packets/play/PacketTitleSetSubTitle.java b/src/main/java/ua/nanit/limbo/protocol/packets/play/PacketTitleSetSubTitle.java index 1800eaff..621e6d2d 100644 --- a/src/main/java/ua/nanit/limbo/protocol/packets/play/PacketTitleSetSubTitle.java +++ b/src/main/java/ua/nanit/limbo/protocol/packets/play/PacketTitleSetSubTitle.java @@ -18,20 +18,21 @@ package ua.nanit.limbo.protocol.packets.play; import ua.nanit.limbo.protocol.ByteMessage; +import ua.nanit.limbo.protocol.NbtMessage; import ua.nanit.limbo.protocol.PacketOut; import ua.nanit.limbo.protocol.registry.Version; public class PacketTitleSetSubTitle implements PacketOut { - private String subtitle; + private NbtMessage subtitle; - public void setSubtitle(String subtitle) { + public void setSubtitle(NbtMessage subtitle) { this.subtitle = subtitle; } @Override public void encode(ByteMessage msg, Version version) { - msg.writeString(subtitle); + msg.writeNbtMessage(subtitle, version); } } diff --git a/src/main/java/ua/nanit/limbo/protocol/packets/play/PacketTitleSetTitle.java b/src/main/java/ua/nanit/limbo/protocol/packets/play/PacketTitleSetTitle.java index 6961201b..23989606 100644 --- a/src/main/java/ua/nanit/limbo/protocol/packets/play/PacketTitleSetTitle.java +++ b/src/main/java/ua/nanit/limbo/protocol/packets/play/PacketTitleSetTitle.java @@ -18,20 +18,21 @@ package ua.nanit.limbo.protocol.packets.play; import ua.nanit.limbo.protocol.ByteMessage; +import ua.nanit.limbo.protocol.NbtMessage; import ua.nanit.limbo.protocol.PacketOut; import ua.nanit.limbo.protocol.registry.Version; public class PacketTitleSetTitle implements PacketOut { - private String title; + private NbtMessage title; - public void setTitle(String title) { + public void setTitle(NbtMessage title) { this.title = title; } @Override public void encode(ByteMessage msg, Version version) { - msg.writeString(title); + msg.writeNbtMessage(title, version); } } diff --git a/src/main/java/ua/nanit/limbo/protocol/registry/State.java b/src/main/java/ua/nanit/limbo/protocol/registry/State.java index 7bf92623..f8564f70 100644 --- a/src/main/java/ua/nanit/limbo/protocol/registry/State.java +++ b/src/main/java/ua/nanit/limbo/protocol/registry/State.java @@ -66,7 +66,7 @@ public enum State { ); serverBound.register( PacketLoginAcknowledged::new, - map(0x03, V1_20_2, V1_20_2) + map(0x03, V1_20_2, V1_20_3) ); clientBound.register(PacketDisconnect::new, map(0x00, Version.getMin(), Version.getMax()) @@ -83,36 +83,36 @@ public enum State { { clientBound.register( PacketPluginMessage::new, - map(0x00, V1_20_2, V1_20_2) + map(0x00, V1_20_2, V1_20_3) ); clientBound.register( PacketDisconnect::new, - map(0x01, V1_20_2, V1_20_2) + map(0x01, V1_20_2, V1_20_3) ); clientBound.register( PacketFinishConfiguration::new, - map(0x02, V1_20_2, V1_20_2) + map(0x02, V1_20_2, V1_20_3) ); clientBound.register( PacketKeepAlive::new, - map(0x03, V1_20_2, V1_20_2) + map(0x03, V1_20_2, V1_20_3) ); clientBound.register( PacketRegistryData::new, - map(0x05, V1_20_2, V1_20_2) + map(0x05, V1_20_2, V1_20_3) ); serverBound.register( PacketPluginMessage::new, - map(0x01, V1_20_2, V1_20_2) + map(0x01, V1_20_2, V1_20_3) ); serverBound.register( PacketFinishConfiguration::new, - map(0x02, V1_20_2, V1_20_2) + map(0x02, V1_20_2, V1_20_3) ); serverBound.register( PacketKeepAlive::new, - map(0x03, V1_20_2, V1_20_2) + map(0x03, V1_20_2, V1_20_3) ); } }, @@ -131,7 +131,8 @@ public enum State { map(0x12, V1_19_1, V1_19_1), map(0x11, V1_19_3, V1_19_3), map(0x12, V1_19_4, V1_20), - map(0x14, V1_20_2, V1_20_2) + map(0x14, V1_20_2, V1_20_2), + map(0x15, V1_20_3, V1_20_3) ); clientBound.register(PacketDeclareCommands::new, @@ -143,7 +144,7 @@ public enum State { map(0x0F, V1_19, V1_19_1), map(0x0E, V1_19_3, V1_19_3), map(0x10, V1_19_4, V1_20), - map(0x11, V1_20_2, V1_20_2) + map(0x11, V1_20_2, V1_20_3) ); clientBound.register(PacketJoinGame::new, map(0x01, V1_7_2, V1_8), @@ -157,7 +158,7 @@ public enum State { map(0x25, V1_19_1, V1_19_1), map(0x24, V1_19_3, V1_19_3), map(0x28, V1_19_4, V1_20), - map(0x29, V1_20_2, V1_20_2) + map(0x29, V1_20_2, V1_20_3) ); clientBound.register(PacketPluginMessage::new, map(0x19, V1_13, V1_13_2), @@ -170,7 +171,7 @@ public enum State { map(0x16, V1_19_1, V1_19_1), map(0x15, V1_19_3, V1_19_3), map(0x17, V1_19_4, V1_20), - map(0x18, V1_20_2, V1_20_2) + map(0x18, V1_20_2, V1_20_3) ); clientBound.register(PacketPlayerAbilities::new, map(0x39, V1_7_2, V1_8), @@ -186,7 +187,7 @@ public enum State { map(0x31, V1_19_1, V1_19_1), map(0x30, V1_19_3, V1_19_3), map(0x34, V1_19_4, V1_20), - map(0x36, V1_20_2, V1_20_2) + map(0x36, V1_20_2, V1_20_3) ); clientBound.register(PacketPlayerPositionAndLook::new, map(0x08, V1_7_2, V1_8), @@ -202,7 +203,7 @@ public enum State { map(0x39, V1_19_1, V1_19_1), map(0x38, V1_19_3, V1_19_3), map(0x3C, V1_19_4, V1_20), - map(0x3E, V1_20_2, V1_20_2) + map(0x3E, V1_20_2, V1_20_3) ); clientBound.register(PacketKeepAlive::new, map(0x00, V1_7_2, V1_8), @@ -217,7 +218,7 @@ public enum State { map(0x20, V1_19_1, V1_19_1), map(0x1F, V1_19_3, V1_19_3), map(0x23, V1_19_4, V1_20), - map(0x24, V1_20_2, V1_20_2) + map(0x24, V1_20_2, V1_20_3) ); clientBound.register(PacketChatMessage::new, map(0x02, V1_7_2, V1_8), @@ -230,7 +231,8 @@ public enum State { map(0x62, V1_19_1, V1_19_1), map(0x60, V1_19_3, V1_19_3), map(0x64, V1_19_4, V1_20), - map(0x67, V1_20_2, V1_20_2) + map(0x67, V1_20_2, V1_20_2), + map(0x69, V1_20_3, V1_20_3) ); clientBound.register(PacketBossBar::new, map(0x0C, V1_9, V1_14_4), @@ -239,7 +241,7 @@ public enum State { map(0x0D, V1_17, V1_18_2), map(0x0A, V1_19, V1_19_3), map(0x0B, V1_19_4, V1_20), - map(0x0A, V1_20_2, V1_20_2) + map(0x0A, V1_20_2, V1_20_3) ); clientBound.register(PacketPlayerInfo::new, map(0x38, V1_7_2, V1_8), @@ -255,7 +257,7 @@ public enum State { map(0x37, V1_19_1, V1_19_1), map(0x36, V1_19_3, V1_19_3), map(0x3A, V1_19_4, V1_20), - map(0x3C, V1_20_2, V1_20_2) + map(0x3C, V1_20_2, V1_20_3) ); clientBound.register(PacketTitleLegacy::new, map(0x45, V1_8, V1_11_1), @@ -272,7 +274,8 @@ public enum State { map(0x5D, V1_19_1, V1_19_1), map(0x5B, V1_19_3, V1_19_3), map(0x5F, V1_19_4, V1_20), - map(0x61, V1_20_2, V1_20_2) + map(0x61, V1_20_2, V1_20_2), + map(0x63, V1_20_3, V1_20_3) ); clientBound.register(PacketTitleSetSubTitle::new, map(0x57, V1_17, V1_17_1), @@ -280,7 +283,8 @@ public enum State { map(0x5B, V1_19_1, V1_19_1), map(0x59, V1_19_3, V1_19_3), map(0x5D, V1_19_4, V1_20), - map(0x5F, V1_20_2, V1_20_2) + map(0x5F, V1_20_2, V1_20_2), + map(0x61, V1_20_3, V1_20_3) ); clientBound.register(PacketTitleTimes::new, map(0x5A, V1_17, V1_17_1), @@ -288,7 +292,8 @@ public enum State { map(0x5E, V1_19_1, V1_19_1), map(0x5C, V1_19_3, V1_19_3), map(0x60, V1_19_4, V1_20), - map(0x62, V1_20_2, V1_20_2) + map(0x62, V1_20_2, V1_20_2), + map(0x64, V1_20_3, V1_20_3) ); clientBound.register(PacketPlayerListHeader::new, map(0x47, V1_8, V1_8), @@ -306,12 +311,20 @@ public enum State { map(0x63, V1_19_1, V1_19_1), map(0x61, V1_19_3, V1_19_3), map(0x65, V1_19_4, V1_20), - map(0x68, V1_20_2, V1_20_2) + map(0x68, V1_20_2, V1_20_2), + map(0x6A, V1_20_3, V1_20_3) ); clientBound.register(PacketSpawnPosition::new, map(0x4C, V1_19_3, V1_19_3), map(0x50, V1_19_4, V1_20), - map(0x52, V1_20_2, V1_20_2) + map(0x52, V1_20_2, V1_20_2), + map(0x54, V1_20_3, V1_20_3) + ); + clientBound.register(PacketGameEvent::new, + map(0x20, V1_20_3, V1_20_3) + ); + clientBound.register(PacketEmptyChunk::new, + map(0x25, V1_20_3, V1_20_3) ); } }; diff --git a/src/main/java/ua/nanit/limbo/protocol/registry/Version.java b/src/main/java/ua/nanit/limbo/protocol/registry/Version.java index 0857ba53..3418c4b9 100644 --- a/src/main/java/ua/nanit/limbo/protocol/registry/Version.java +++ b/src/main/java/ua/nanit/limbo/protocol/registry/Version.java @@ -70,7 +70,8 @@ public enum Version { V1_19_4(762), V1_20(763), // 1.20.1 has same protocol number - V1_20_2(764); + V1_20_2(764), + V1_20_3(765); private static final Map VERSION_MAP; private static final Version MAX; diff --git a/src/main/java/ua/nanit/limbo/server/data/BossBar.java b/src/main/java/ua/nanit/limbo/server/data/BossBar.java index aeeab118..c178772b 100644 --- a/src/main/java/ua/nanit/limbo/server/data/BossBar.java +++ b/src/main/java/ua/nanit/limbo/server/data/BossBar.java @@ -21,18 +21,20 @@ import org.spongepowered.configurate.ConfigurationNode; import org.spongepowered.configurate.serialize.SerializationException; import org.spongepowered.configurate.serialize.TypeSerializer; +import ua.nanit.limbo.protocol.NbtMessage; import ua.nanit.limbo.util.Colors; +import ua.nanit.limbo.util.NbtMessageUtil; import java.lang.reflect.Type; public class BossBar { - private String text; + private NbtMessage text; private float health; private Color color; private Division division; - public String getText() { + public NbtMessage getText() { return text; } @@ -48,7 +50,7 @@ public Division getDivision() { return division; } - public void setText(String text) { + public void setText(NbtMessage text) { this.text = text; } @@ -110,7 +112,7 @@ public static class Serializer implements TypeSerializer { public BossBar deserialize(Type type, ConfigurationNode node) throws SerializationException { BossBar bossBar = new BossBar(); - bossBar.setText(Colors.of(node.node("text").getString(""))); + bossBar.setText(NbtMessageUtil.create(Colors.of(node.node("text").getString("")))); bossBar.setHealth(node.node("health").getFloat()); if (bossBar.getHealth() < 0 || bossBar.getHealth() > 1) diff --git a/src/main/java/ua/nanit/limbo/server/data/Title.java b/src/main/java/ua/nanit/limbo/server/data/Title.java index 190e8277..120e7143 100644 --- a/src/main/java/ua/nanit/limbo/server/data/Title.java +++ b/src/main/java/ua/nanit/limbo/server/data/Title.java @@ -20,23 +20,25 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.configurate.ConfigurationNode; import org.spongepowered.configurate.serialize.TypeSerializer; +import ua.nanit.limbo.protocol.NbtMessage; import ua.nanit.limbo.util.Colors; +import ua.nanit.limbo.util.NbtMessageUtil; import java.lang.reflect.Type; public class Title { - private String title; - private String subtitle; + private NbtMessage title; + private NbtMessage subtitle; private int fadeIn; private int stay; private int fadeOut; - public String getTitle() { + public NbtMessage getTitle() { return title; } - public String getSubtitle() { + public NbtMessage getSubtitle() { return subtitle; } @@ -52,11 +54,11 @@ public int getFadeOut() { return fadeOut; } - public void setTitle(String title) { + public void setTitle(NbtMessage title) { this.title = title; } - public void setSubtitle(String subtitle) { + public void setSubtitle(NbtMessage subtitle) { this.subtitle = subtitle; } @@ -77,8 +79,8 @@ public static class Serializer implements TypeSerializer { @Override public Title deserialize(Type type, ConfigurationNode node) { Title title = new Title(); - title.setTitle(Colors.of(node.node("title").getString(""))); - title.setSubtitle(Colors.of(node.node("subtitle").getString(""))); + title.setTitle(NbtMessageUtil.create(Colors.of(node.node("title").getString("")))); + title.setSubtitle(NbtMessageUtil.create(Colors.of(node.node("subtitle").getString("")))); title.setFadeIn(node.node("fadeIn").getInt(10)); title.setStay(node.node("stay").getInt(100)); title.setFadeOut(node.node("fadeOut").getInt(10)); diff --git a/src/main/java/ua/nanit/limbo/util/NbtMessageUtil.java b/src/main/java/ua/nanit/limbo/util/NbtMessageUtil.java new file mode 100644 index 00000000..06e66be0 --- /dev/null +++ b/src/main/java/ua/nanit/limbo/util/NbtMessageUtil.java @@ -0,0 +1,110 @@ +package ua.nanit.limbo.util; + +import com.google.gson.*; +import net.kyori.adventure.nbt.*; +import ua.nanit.limbo.protocol.NbtMessage; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public class NbtMessageUtil { + + public static NbtMessage create(String json) { + BinaryTag compoundBinaryTag = fromJson(JsonParser.parseString(json)); + + return new NbtMessage(json, compoundBinaryTag); + } + + public static BinaryTag fromJson(JsonElement json) { + if (json instanceof JsonPrimitive) { + JsonPrimitive jsonPrimitive = (JsonPrimitive) json; + if (jsonPrimitive.isNumber()) { + Number number = json.getAsNumber(); + + if (number instanceof Byte) { + return ByteBinaryTag.byteBinaryTag((Byte) number); + } else if (number instanceof Short) { + return ShortBinaryTag.shortBinaryTag((Short) number); + } else if (number instanceof Integer) { + return IntBinaryTag.intBinaryTag((Integer) number); + } else if (number instanceof Long) { + return LongBinaryTag.longBinaryTag((Long) number); + } else if (number instanceof Float) { + return FloatBinaryTag.floatBinaryTag((Float) number); + } else if (number instanceof Double) { + return DoubleBinaryTag.doubleBinaryTag((Double) number); + } + } else if (jsonPrimitive.isString()) { + return StringBinaryTag.stringBinaryTag(jsonPrimitive.getAsString()); + } else if (jsonPrimitive.isBoolean()) { + return ByteBinaryTag.byteBinaryTag(jsonPrimitive.getAsBoolean() ? (byte) 1 : (byte) 0); + } else { + throw new IllegalArgumentException("Unknown JSON primitive: " + jsonPrimitive); + } + } else if (json instanceof JsonObject) { + CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder(); + for (Map.Entry<String, JsonElement> property : ((JsonObject) json).entrySet()) { + builder.put(property.getKey(), fromJson(property.getValue())); + } + + return builder.build(); + } else if (json instanceof JsonArray) { + List<JsonElement> jsonArray = ((JsonArray) json).asList(); + + if (jsonArray.isEmpty()) { + return ListBinaryTag.listBinaryTag(EndBinaryTag.endBinaryTag().type(), Collections.emptyList()); + } + + BinaryTagType tagByteType = ByteBinaryTag.ZERO.type(); + BinaryTagType tagIntType = IntBinaryTag.intBinaryTag(0).type(); + BinaryTagType tagLongType = LongBinaryTag.longBinaryTag(0).type(); + + BinaryTag listTag; + BinaryTagType listType = fromJson(jsonArray.get(0)).type(); + if (listType.equals(tagByteType)) { + byte[] bytes = new byte[jsonArray.size()]; + for (int i = 0; i < bytes.length; i++) { + bytes[i] = (Byte) ((JsonPrimitive) jsonArray.get(i)).getAsNumber(); + } + + listTag = ByteArrayBinaryTag.byteArrayBinaryTag(bytes); + } else if (listType.equals(tagIntType)) { + int[] ints = new int[jsonArray.size()]; + for (int i = 0; i < ints.length; i++) { + ints[i] = (Integer) ((JsonPrimitive) jsonArray.get(i)).getAsNumber(); + } + + listTag = IntArrayBinaryTag.intArrayBinaryTag(ints); + } else if (listType.equals(tagLongType)) { + long[] longs = new long[jsonArray.size()]; + for (int i = 0; i < longs.length; i++) { + longs[i] = (Long) ((JsonPrimitive) jsonArray.get(i)).getAsNumber(); + } + + listTag = LongArrayBinaryTag.longArrayBinaryTag(longs); + } else { + List<BinaryTag> tagItems = new ArrayList<>(jsonArray.size()); + + for (JsonElement jsonEl : jsonArray) { + BinaryTag subTag = fromJson(jsonEl); + if (subTag.type() != listType) { + throw new IllegalArgumentException("Cannot convert mixed JsonArray to Tag"); + } + + tagItems.add(subTag); + } + + listTag = ListBinaryTag.listBinaryTag(listType, tagItems); + } + + return listTag; + } else if (json instanceof JsonNull) { + return EndBinaryTag.endBinaryTag(); + } + + throw new IllegalArgumentException("Unknown JSON element: " + json); + } + +} From 4fd038935654869ab3cdc3fc4eda82eae501bce8 Mon Sep 17 00:00:00 2001 From: BoomEaro <21033866+BoomEaro@users.noreply.github.com> Date: Wed, 6 Dec 2023 18:22:57 +0200 Subject: [PATCH 2/7] Bump netty 4.1.101.Final --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 3e340d3e..31b136a3 100644 --- a/build.gradle +++ b/build.gradle @@ -25,7 +25,7 @@ dependencies { testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.3' implementation 'org.spongepowered:configurate-yaml:4.1.2' - implementation 'io.netty:netty-all:4.1.99.Final' + implementation 'io.netty:netty-all:4.1.101.Final' implementation 'net.kyori:adventure-nbt:4.14.0' implementation 'com.grack:nanojson:1.8' implementation 'com.google.code.gson:gson:2.10.1' From f2574261736c1ecf358960a27c52871ea5552881 Mon Sep 17 00:00:00 2001 From: BoomEaro <21033866+BoomEaro@users.noreply.github.com> Date: Wed, 6 Dec 2023 18:37:28 +0200 Subject: [PATCH 3/7] Use writePacket method --- src/main/java/ua/nanit/limbo/connection/ClientConnection.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/ua/nanit/limbo/connection/ClientConnection.java b/src/main/java/ua/nanit/limbo/connection/ClientConnection.java index 13f8207d..a11f46b3 100644 --- a/src/main/java/ua/nanit/limbo/connection/ClientConnection.java +++ b/src/main/java/ua/nanit/limbo/connection/ClientConnection.java @@ -177,10 +177,10 @@ public void spawnPlayer() { writePacket(PacketSnapshots.PACKET_HEADER_AND_FOOTER); if (clientVersion.moreOrEqual(Version.V1_20_3)) { - sendPacket(PacketSnapshots.PACKET_START_WAITING_CHUNKS); + writePacket(PacketSnapshots.PACKET_START_WAITING_CHUNKS); for (PacketSnapshot chunk : PacketSnapshots.PACKETS_EMPTY_CHUNKS) { - sendPacket(chunk); + writePacket(chunk); } } From dfa6cf3862efa7fef757df6ca99db4acdda535ff Mon Sep 17 00:00:00 2001 From: Max <nanitmix@gmail.com> Date: Sat, 30 Dec 2023 13:44:29 +0200 Subject: [PATCH 4/7] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 73a95106..441eedc6 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Symbol `X` means all minor versions. - [x] 1.17.X - [x] 1.18.X - [x] 1.19.X -- [x] 1.20-1.20.2 +- [x] 1.20-1.20.4 The server **doesn't** support snapshots. From 6919420916e8597398daac1d7217edbda29aff9f Mon Sep 17 00:00:00 2001 From: Nan1t <imnanit@gmail.com> Date: Sat, 30 Dec 2023 13:46:08 +0200 Subject: [PATCH 5/7] Update version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 31b136a3..6851014d 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { } group 'ru.nanit' -version '1.6' +version '1.7' compileJava { options.encoding = "UTF-8" From 0489f883d12db40a8f4fc39ffe63639e44ace078 Mon Sep 17 00:00:00 2001 From: Max <nanitmix@gmail.com> Date: Sat, 30 Dec 2023 13:56:17 +0200 Subject: [PATCH 6/7] Update README.md --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 441eedc6..46ce9091 100644 --- a/README.md +++ b/README.md @@ -78,8 +78,6 @@ Then add your tokens to `tokens` list. Feel free to create a pull request if you found some bug or optimization opportunity, or if you want to add some functionality that is suitable for a limbo server and won't significantly load the server. -All PRs should target the `dev` branch to keep the `main` branch stable and clean. - ### Building Required software: From 72774fbff95e62d70e67e5d136a7448389be1f29 Mon Sep 17 00:00:00 2001 From: Max <nanitmix@gmail.com> Date: Sat, 30 Dec 2023 13:56:44 +0200 Subject: [PATCH 7/7] Delete .github directory --- .github/FUNDING.yml | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index be367b94..00000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1 +0,0 @@ -ko_fi: nanit \ No newline at end of file