diff --git a/api/src/main/java/com/viaversion/viaversion/api/type/types/ByteArrayType.java b/api/src/main/java/com/viaversion/viaversion/api/type/types/ByteArrayType.java index 0d3879b84..701a25b5b 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/type/types/ByteArrayType.java +++ b/api/src/main/java/com/viaversion/viaversion/api/type/types/ByteArrayType.java @@ -42,18 +42,20 @@ public class ByteArrayType extends Type { } @Override - public void write(ByteBuf buffer, byte[] object) throws Exception { - Preconditions.checkArgument(length == -1 || length == object.length, "Length does not match expected length"); - Type.VAR_INT.writePrimitive(buffer, object.length); + public void write(final ByteBuf buffer, final byte[] object) throws Exception { + if (this.length != -1) { + Preconditions.checkArgument(length == object.length, "Length does not match expected length"); + } else { + Type.VAR_INT.writePrimitive(buffer, object.length); + } buffer.writeBytes(object); } @Override - public byte[] read(ByteBuf buffer) throws Exception { - int length = Type.VAR_INT.readPrimitive(buffer); + public byte[] read(final ByteBuf buffer) throws Exception { + final int length = this.length == -1 ? Type.VAR_INT.readPrimitive(buffer) : this.length; Preconditions.checkArgument(buffer.isReadable(length), "Length is fewer than readable bytes"); - Preconditions.checkArgument(this.length == -1 || this.length == length, "Length does not match expected length"); - byte[] array = new byte[length]; + final byte[] array = new byte[length]; buffer.readBytes(array); return array; } @@ -63,5 +65,9 @@ public class ByteArrayType extends Type { public OptionalByteArrayType() { super(Type.BYTE_ARRAY_PRIMITIVE); } + + public OptionalByteArrayType(final int length) { + super(new ByteArrayType(length)); + } } } diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_19_3to1_19_1/ClientboundPackets1_19_3.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_19_3to1_19_1/ClientboundPackets1_19_3.java index 639fff3c3..5803b1514 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_19_3to1_19_1/ClientboundPackets1_19_3.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_19_3to1_19_1/ClientboundPackets1_19_3.java @@ -33,20 +33,20 @@ public enum ClientboundPackets1_19_3 implements ClientboundPacketType { BLOCK_CHANGE, // 0x09 BOSSBAR, // 0x0A SERVER_DIFFICULTY, // 0x0B - CLEAR_TITLES, // 0x0D - TAB_COMPLETE, // 0x0E - DECLARE_COMMANDS, // 0x0F - CLOSE_WINDOW, // 0x10 - WINDOW_ITEMS, // 0x11 - WINDOW_PROPERTY, // 0x12 - SET_SLOT, // 0x13 - COOLDOWN, // 0x14 - CUSTOM_CHAT_COMPLETIONS, // 0x15 - PLUGIN_MESSAGE, // 0x16 - NAMED_SOUND, // 0x17 - DELETE_CHAT_MESSAGE, // 0x18 - DISCONNECT, // 0x19 - DISGUISED_CHAT, + CLEAR_TITLES, // 0x0C + TAB_COMPLETE, // 0x0D + DECLARE_COMMANDS, // 0x0E + CLOSE_WINDOW, // 0x0F + WINDOW_ITEMS, // 0x10 + WINDOW_PROPERTY, // 0x11 + SET_SLOT, // 0x12 + COOLDOWN, // 0x13 + CUSTOM_CHAT_COMPLETIONS, // 0x14 + PLUGIN_MESSAGE, // 0x15 + NAMED_SOUND, // 0x16 + DELETE_CHAT_MESSAGE, // 0x17 + DISCONNECT, // 0x18 + DISGUISED_CHAT, // 0x19 ENTITY_STATUS, // 0x1A EXPLOSION, // 0x1B UNLOAD_CHUNK, // 0x1C @@ -71,12 +71,12 @@ public enum ClientboundPackets1_19_3 implements ClientboundPacketType { PING, // 0x2F CRAFT_RECIPE_RESPONSE, // 0x30 PLAYER_ABILITIES, // 0x31 - PLAYER_CHAT, // 0x33 - COMBAT_END, // 0x34 - COMBAT_ENTER, // 0x35 - COMBAT_KILL, // 0x36 - PLAYER_INFO_REMOVE, // 0x37 - PLAYER_INFO_UPDATE, + PLAYER_CHAT, // 0x32 + COMBAT_END, // 0x33 + COMBAT_ENTER, // 0x34 + COMBAT_KILL, // 0x35 + PLAYER_INFO_REMOVE, // 0x36 + PLAYER_INFO_UPDATE, // 0x37 FACE_PLAYER, // 0x38 PLAYER_POSITION, // 0x39 UNLOCK_RECIPES, // 0x3A @@ -99,33 +99,33 @@ public enum ClientboundPackets1_19_3 implements ClientboundPacketType { UPDATE_VIEW_POSITION, // 0x4B UPDATE_VIEW_DISTANCE, // 0x4C SPAWN_POSITION, // 0x4D - DISPLAY_SCOREBOARD, // 0x4F - ENTITY_METADATA, // 0x50 - ATTACH_ENTITY, // 0x51 - ENTITY_VELOCITY, // 0x52 - ENTITY_EQUIPMENT, // 0x53 - SET_EXPERIENCE, // 0x54 - UPDATE_HEALTH, // 0x55 - SCOREBOARD_OBJECTIVE, // 0x56 - SET_PASSENGERS, // 0x57 - TEAMS, // 0x58 - UPDATE_SCORE, // 0x59 - SET_SIMULATION_DISTANCE, // 0x5A - TITLE_SUBTITLE, // 0x5B - TIME_UPDATE, // 0x5C - TITLE_TEXT, // 0x5D - TITLE_TIMES, // 0x5E - ENTITY_SOUND, // 0x5F - SOUND, // 0x60 - STOP_SOUND, // 0x61 - SYSTEM_CHAT, // 0x62 - TAB_LIST, // 0x63 - NBT_QUERY, // 0x64 - COLLECT_ITEM, // 0x65 - ENTITY_TELEPORT, // 0x66 - ADVANCEMENTS, // 0x67 - ENTITY_PROPERTIES, // 0x68 - UPDATE_ENABLED_FEATURES, + DISPLAY_SCOREBOARD, // 0x4E + ENTITY_METADATA, // 0x4F + ATTACH_ENTITY, // 0x50 + ENTITY_VELOCITY, // 0x51 + ENTITY_EQUIPMENT, // 0x52 + SET_EXPERIENCE, // 0x53 + UPDATE_HEALTH, // 0x54 + SCOREBOARD_OBJECTIVE, // 0x55 + SET_PASSENGERS, // 0x56 + TEAMS, // 0x57 + UPDATE_SCORE, // 0x58 + SET_SIMULATION_DISTANCE, // 0x59 + TITLE_SUBTITLE, // 0x5A + TIME_UPDATE, // 0x5B + TITLE_TEXT, // 0x5C + TITLE_TIMES, // 0x5D + ENTITY_SOUND, // 0x5E + SOUND, // 0x5F + STOP_SOUND, // 0x60 + SYSTEM_CHAT, // 0x61 + TAB_LIST, // 0x62 + NBT_QUERY, // 0x63 + COLLECT_ITEM, // 0x64 + ENTITY_TELEPORT, // 0x65 + ADVANCEMENTS, // 0x66 + ENTITY_PROPERTIES, // 0x67 + UPDATE_ENABLED_FEATURES, // 0x68 ENTITY_EFFECT, // 0x69 DECLARE_RECIPES, // 0x6A TAGS; // 0x6B diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_19_3to1_19_1/Protocol1_19_3To1_19_1.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_19_3to1_19_1/Protocol1_19_3To1_19_1.java index 2cee2b367..f60aa9c2d 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_19_3to1_19_1/Protocol1_19_3To1_19_1.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_19_3to1_19_1/Protocol1_19_3To1_19_1.java @@ -39,25 +39,26 @@ import com.viaversion.viaversion.api.type.types.version.Types1_19_3; import com.viaversion.viaversion.data.entity.EntityTrackerBase; import com.viaversion.viaversion.libs.kyori.adventure.text.Component; import com.viaversion.viaversion.libs.kyori.adventure.text.serializer.gson.GsonComponentSerializer; +import com.viaversion.viaversion.protocols.base.ClientboundLoginPackets; import com.viaversion.viaversion.protocols.base.ServerboundLoginPackets; import com.viaversion.viaversion.protocols.protocol1_19_1to1_19.ClientboundPackets1_19_1; import com.viaversion.viaversion.protocols.protocol1_19_1to1_19.ServerboundPackets1_19_1; import com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1.packets.EntityPackets; import com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1.packets.InventoryPackets; +import com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1.storage.NonceStorage; import com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1.storage.ReceivedMessagesStorage; import com.viaversion.viaversion.rewriter.CommandRewriter; import com.viaversion.viaversion.rewriter.SoundRewriter; import com.viaversion.viaversion.rewriter.StatisticsRewriter; import com.viaversion.viaversion.rewriter.TagRewriter; +import com.viaversion.viaversion.util.CipherUtil; -import java.util.BitSet; import java.util.UUID; public final class Protocol1_19_3To1_19_1 extends AbstractProtocol { public static final MappingData MAPPINGS = new MappingDataBase("1.19", "1.19.3", true); - private static final BitSetType PROFILE_ACTIONS_ENUM_TYPE = new BitSetType(5); - private static final ByteArrayType MESSAGE_SIGNATURE_BYTES_TYPE = new ByteArrayType(256); + private static final ByteArrayType.OptionalByteArrayType OPTIONAL_MESSAGE_SIGNATURE_BYTES_TYPE = new ByteArrayType.OptionalByteArrayType(256); private static final UUID ZERO_UUID = new UUID(0, 0); private static final byte[] EMPTY_BYTES = new byte[0]; private final EntityPackets entityRewriter = new EntityPackets(this); @@ -69,9 +70,6 @@ public final class Protocol1_19_3To1_19_1 extends AbstractProtocol { - final int action = wrapper.read(Type.VAR_INT); - if (action == 4) { // Remove player - // Write into new packet type - final int entries = wrapper.passthrough(Type.VAR_INT); - final UUID[] uuidsToRemove = new UUID[entries]; - for (int i = 0; i < entries; i++) { - uuidsToRemove[i] = wrapper.read(Type.UUID); - } - wrapper.write(Type.UUID_ARRAY, uuidsToRemove); - wrapper.setPacketType(ClientboundPackets1_19_3.PLAYER_INFO_REMOVE); - return; - } - - final BitSet set = new BitSet(5); - if (action == 0) { - // Includes profile key, gamemode, latency, and display name update - also update listed - set.set(0, 5); - } else { - // Update listed added at 3, initialize chat added at index 1 - set.set(action > 2 ? action + 2 : action + 1); - } - - wrapper.write(PROFILE_ACTIONS_ENUM_TYPE, set); - final int entries = wrapper.passthrough(Type.VAR_INT); - for (int i = 0; i < entries; i++) { - wrapper.passthrough(Type.UUID); // UUID - if (action == 0) { // Add player - wrapper.passthrough(Type.STRING); // Player Name - - final int properties = wrapper.passthrough(Type.VAR_INT); - for (int j = 0; j < properties; j++) { - wrapper.passthrough(Type.STRING); // Name - wrapper.passthrough(Type.STRING); // Value - if (wrapper.passthrough(Type.BOOLEAN)) { - wrapper.passthrough(Type.STRING); // Signature - } - } - - final int gamemode = wrapper.read(Type.VAR_INT); - final int ping = wrapper.read(Type.VAR_INT); - final JsonElement displayName = wrapper.read(Type.BOOLEAN) ? wrapper.read(Type.COMPONENT) : null; - final ProfileKey profileKey = wrapper.read(Type.OPTIONAL_PROFILE_KEY); - - // Salvage signed chat - wrapper.write(Type.UUID, UUID.randomUUID()); - wrapper.write(Type.OPTIONAL_PROFILE_KEY, profileKey); - - wrapper.write(Type.VAR_INT, gamemode); - wrapper.write(Type.BOOLEAN, true); // Also update listed - wrapper.write(Type.VAR_INT, ping); - wrapper.write(Type.OPTIONAL_COMPONENT, displayName); - } else if (action == 1 || action == 2) { // Update gamemode/update latency - wrapper.passthrough(Type.VAR_INT); - } else if (action == 3) { // Update display name - final JsonElement displayName = wrapper.passthrough(Type.BOOLEAN) ? wrapper.read(Type.COMPONENT) : null; - wrapper.write(Type.OPTIONAL_COMPONENT, displayName); - } - } - }); - } - }); registerClientbound(ClientboundPackets1_19_1.SERVER_DATA, new PacketRemapper() { @Override public void registerMap() { @@ -215,16 +150,6 @@ public final class Protocol1_19_3To1_19_1 extends AbstractProtocol { final PlayerMessageSignature signature = wrapper.read(Type.PLAYER_MESSAGE_SIGNATURE); - final String plainText = wrapper.read(Type.STRING); - JsonElement component = wrapper.read(Type.OPTIONAL_COMPONENT); - final JsonElement unsignedComponent = wrapper.read(Type.OPTIONAL_COMPONENT); - if (unsignedComponent != null) { - component = unsignedComponent; - } - if (component == null) { - component = GsonComponentSerializer.gson().serializeToTree(Component.text(plainText)); - } - // Store message signature for last seen if (!signature.uuid().equals(ZERO_UUID) && signature.signatureBytes().length != 0) { final ReceivedMessagesStorage messagesStorage = wrapper.user().get(ReceivedMessagesStorage.class); @@ -240,16 +165,27 @@ public final class Protocol1_19_3To1_19_1 extends AbstractProtocol { - final int signatures = wrapper.passthrough(Type.VAR_INT); + final int signatures = wrapper.read(Type.VAR_INT); + wrapper.write(Type.VAR_INT, 0); for (int i = 0; i < signatures; i++) { - wrapper.passthrough(Type.STRING); // Argument name - final byte[] signature = wrapper.read(MESSAGE_SIGNATURE_BYTES_TYPE); - wrapper.write(Type.BYTE_ARRAY_PRIMITIVE, signature); + wrapper.read(Type.STRING); // Argument name + wrapper.read(OPTIONAL_MESSAGE_SIGNATURE_BYTES_TYPE); // Signature } wrapper.write(Type.BOOLEAN, false); // No signed preview @@ -285,10 +221,13 @@ public final class Protocol1_19_3To1_19_1 extends AbstractProtocol { - final byte[] signature = wrapper.read(Type.BOOLEAN) ? wrapper.read(MESSAGE_SIGNATURE_BYTES_TYPE) : null; - wrapper.write(Type.BYTE_ARRAY_PRIMITIVE, signature != null ? signature : EMPTY_BYTES); + // Remove signature + final byte[] signature = wrapper.read(OPTIONAL_MESSAGE_SIGNATURE_BYTES_TYPE); + wrapper.write(Type.BYTE_ARRAY_PRIMITIVE, EMPTY_BYTES); wrapper.write(Type.BOOLEAN, false); // No signed preview final ReceivedMessagesStorage messagesStorage = wrapper.user().get(ReceivedMessagesStorage.class); @@ -301,11 +240,53 @@ public final class Protocol1_19_3To1_19_1 extends AbstractProtocol { + final ProfileKey profileKey = wrapper.read(Type.OPTIONAL_PROFILE_KEY); + wrapper.write(Type.OPTIONAL_PROFILE_KEY, null); + if (profileKey == null) { + wrapper.user().put(new NonceStorage(null)); + } + }); + } + }); + registerClientbound(State.LOGIN, ClientboundLoginPackets.HELLO.getId(), ClientboundLoginPackets.HELLO.getId(), new PacketRemapper() { + @Override + public void registerMap() { + map(Type.STRING); // Server id + handler(wrapper -> { + if (wrapper.user().has(NonceStorage.class)) { + return; + } + final byte[] publicKey = wrapper.passthrough(Type.BYTE_ARRAY_PRIMITIVE); + final byte[] nonce = wrapper.passthrough(Type.BYTE_ARRAY_PRIMITIVE); + wrapper.user().put(new NonceStorage(CipherUtil.encryptNonce(publicKey, nonce))); + }); + } + }); + registerServerbound(State.LOGIN, ServerboundLoginPackets.ENCRYPTION_KEY.getId(), ServerboundLoginPackets.ENCRYPTION_KEY.getId(), new PacketRemapper() { + @Override + public void registerMap() { + map(Type.BYTE_ARRAY_PRIMITIVE); // Keys + handler(wrapper -> { + final NonceStorage nonceStorage = wrapper.user().remove(NonceStorage.class); + if (nonceStorage.nonce() == null) { + return; + } + + final boolean isNonce = wrapper.read(Type.BOOLEAN); + wrapper.write(Type.BOOLEAN, true); + if (!isNonce) { // Should never be true at this point, but /shrug otherwise + wrapper.read(Type.LONG); // Salt + wrapper.read(Type.BYTE_ARRAY_PRIMITIVE); // Signature + wrapper.write(Type.BYTE_ARRAY_PRIMITIVE, nonceStorage.nonce()); + } + }); } }); @@ -334,6 +315,7 @@ public final class Protocol1_19_3To1_19_1 extends AbstractProtocol { + private static final BitSetType PROFILE_ACTIONS_ENUM_TYPE = new BitSetType(6); + public EntityPackets(final Protocol1_19_3To1_19_1 protocol) { super(protocol); } @@ -53,6 +63,13 @@ public final class EntityPackets extends EntityRewriter handler(dimensionDataHandler()); handler(biomeSizeTracker()); handler(worldDataTrackerHandlerByKey()); + handler(wrapper -> { + // Also enable vanilla features + final PacketWrapper enableFeaturesPacket = wrapper.create(ClientboundPackets1_19_3.UPDATE_ENABLED_FEATURES); + enableFeaturesPacket.write(Type.VAR_INT, 1); + enableFeaturesPacket.write(Type.STRING, "minecraft:vanilla"); + enableFeaturesPacket.send(Protocol1_19_3To1_19_1.class); + }); } }); @@ -64,6 +81,72 @@ public final class EntityPackets extends EntityRewriter handler(worldDataTrackerHandlerByKey()); } }); + + protocol.registerClientbound(ClientboundPackets1_19_1.PLAYER_INFO, ClientboundPackets1_19_3.PLAYER_INFO_UPDATE, new PacketRemapper() { + @Override + public void registerMap() { + handler(wrapper -> { + final int action = wrapper.read(Type.VAR_INT); + if (action == 4) { // Remove player + // Write into new packet type + final int entries = wrapper.read(Type.VAR_INT); + final UUID[] uuidsToRemove = new UUID[entries]; + for (int i = 0; i < entries; i++) { + uuidsToRemove[i] = wrapper.read(Type.UUID); + } + wrapper.write(Type.UUID_ARRAY, uuidsToRemove); + wrapper.setPacketType(ClientboundPackets1_19_3.PLAYER_INFO_REMOVE); + return; + } + + final BitSet set = new BitSet(6); + if (action == 0) { + // Includes add player, profile key, gamemode, listed status, latency, and display name + set.set(0, 6); + } else { + // Update listed added at 3, initialize chat added at index 1 + set.set(action == 1 ? action + 1 : action + 2); + } + + wrapper.write(PROFILE_ACTIONS_ENUM_TYPE, set); + final int entries = wrapper.passthrough(Type.VAR_INT); + for (int i = 0; i < entries; i++) { + wrapper.passthrough(Type.UUID); // UUID + if (action == 0) { // Add player + wrapper.passthrough(Type.STRING); // Player Name + + final int properties = wrapper.passthrough(Type.VAR_INT); + for (int j = 0; j < properties; j++) { + wrapper.passthrough(Type.STRING); // Name + wrapper.passthrough(Type.STRING); // Value + if (wrapper.passthrough(Type.BOOLEAN)) { + wrapper.passthrough(Type.STRING); // Signature + } + } + + final int gamemode = wrapper.read(Type.VAR_INT); + final int ping = wrapper.read(Type.VAR_INT); + final JsonElement displayName = wrapper.read(Type.BOOLEAN) ? wrapper.read(Type.COMPONENT) : null; + final ProfileKey profileKey = wrapper.read(Type.OPTIONAL_PROFILE_KEY); + + // Salvage signed chat + wrapper.write(Type.UUID, UUID.randomUUID()); + wrapper.write(Type.OPTIONAL_PROFILE_KEY, profileKey); + + wrapper.write(Type.VAR_INT, gamemode); + wrapper.write(Type.BOOLEAN, true); // Also update listed + wrapper.write(Type.VAR_INT, ping); + wrapper.write(Type.OPTIONAL_COMPONENT, displayName); + } else if (action == 1 || action == 2) { // Update gamemode/update latency + wrapper.passthrough(Type.VAR_INT); + } else if (action == 3) { // Update display name + final JsonElement displayName = wrapper.passthrough(Type.BOOLEAN) ? wrapper.read(Type.COMPONENT) : null; + wrapper.write(Type.OPTIONAL_COMPONENT, displayName); + } + } + }); + } + }); } @Override diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_19_3to1_19_1/packets/InventoryPackets.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_19_3to1_19_1/packets/InventoryPackets.java index 19b989ae7..f4f9cab1b 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_19_3to1_19_1/packets/InventoryPackets.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_19_3to1_19_1/packets/InventoryPackets.java @@ -18,13 +18,11 @@ package com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1.packets; import com.viaversion.viaversion.api.minecraft.item.Item; -import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; import com.viaversion.viaversion.api.protocol.remapper.PacketRemapper; import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.protocols.protocol1_16to1_15_2.data.RecipeRewriter1_16; import com.viaversion.viaversion.protocols.protocol1_18to1_17_1.types.Chunk1_18Type; import com.viaversion.viaversion.protocols.protocol1_19_1to1_19.ClientboundPackets1_19_1; -import com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1.ClientboundPackets1_19_3; import com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1.Protocol1_19_3To1_19_1; import com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1.ServerboundPackets1_19_3; import com.viaversion.viaversion.rewriter.BlockRewriter; @@ -64,12 +62,6 @@ public final class InventoryPackets extends ItemRewriter @Override public void registerMap() { handler(wrapper -> { - // Also enable vanilla features - final PacketWrapper enableFeaturesPacket = wrapper.create(ClientboundPackets1_19_3.UPDATE_ENABLED_FEATURES); - enableFeaturesPacket.write(Type.VAR_INT, 1); - enableFeaturesPacket.write(Type.STRING, "minecraft:vanilla"); - enableFeaturesPacket.send(Protocol1_19_3To1_19_1.class); - final int size = wrapper.passthrough(Type.VAR_INT); for (int i = 0; i < size; i++) { final String type = wrapper.passthrough(Type.STRING).replace("minecraft:", ""); diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_19_3to1_19_1/storage/NonceStorage.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_19_3to1_19_1/storage/NonceStorage.java new file mode 100644 index 000000000..dceed3e00 --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_19_3to1_19_1/storage/NonceStorage.java @@ -0,0 +1,34 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2022 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1.storage; + +import com.viaversion.viaversion.api.connection.StorableObject; +import org.checkerframework.checker.nullness.qual.Nullable; + +public final class NonceStorage implements StorableObject { + + private final byte[] nonce; + + public NonceStorage(final byte @Nullable[] nonce) { + this.nonce = nonce; + } + + public byte @Nullable [] nonce() { + return nonce; + } +}