mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-21 15:41:38 +01:00
1.19.3 support
This commit is contained in:
parent
7361bf0825
commit
f09fdd862b
@ -7,7 +7,7 @@ adventure = "4.11.0"
|
||||
kotlin = "1.6.20"
|
||||
hydrazine = "1.7.2"
|
||||
dependencyGetter = "v1.0.1"
|
||||
minestomData = "1c1921cd41"
|
||||
minestomData = "76da04ca1d"
|
||||
hephaistos = "2.5.3"
|
||||
jetbrainsAnnotations = "23.0.0"
|
||||
|
||||
|
@ -45,8 +45,8 @@ public final class MinecraftServer {
|
||||
|
||||
public static final ComponentLogger LOGGER = ComponentLogger.logger(MinecraftServer.class);
|
||||
|
||||
public static final String VERSION_NAME = "1.19.2";
|
||||
public static final int PROTOCOL_VERSION = 760;
|
||||
public static final String VERSION_NAME = "1.19.3";
|
||||
public static final int PROTOCOL_VERSION = 761;
|
||||
|
||||
// Threads
|
||||
public static final String THREAD_NAME_BENCHMARK = "Ms-Benchmark";
|
||||
|
@ -14,7 +14,8 @@ public class ArgumentPotionEffect extends ArgumentRegistry<PotionEffect> {
|
||||
|
||||
@Override
|
||||
public String parser() {
|
||||
return "minecraft:mob_effect";
|
||||
// TODO: what replace `minecraft:mob_effect`?
|
||||
return "minecraft:uuid";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
22
src/main/java/net/minestom/server/crypto/ChatBound.java
Normal file
22
src/main/java/net/minestom/server/crypto/ChatBound.java
Normal file
@ -0,0 +1,22 @@
|
||||
package net.minestom.server.crypto;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static net.minestom.server.network.NetworkBuffer.COMPONENT;
|
||||
import static net.minestom.server.network.NetworkBuffer.VAR_INT;
|
||||
|
||||
public record ChatBound(int chatType, Component name, @Nullable Component targetName) implements NetworkBuffer.Writer {
|
||||
public ChatBound(@NotNull NetworkBuffer reader) {
|
||||
this(reader.read(VAR_INT), reader.read(COMPONENT), reader.readOptional(COMPONENT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.write(VAR_INT, chatType);
|
||||
writer.write(COMPONENT, name);
|
||||
writer.writeOptional(COMPONENT, targetName);
|
||||
}
|
||||
}
|
28
src/main/java/net/minestom/server/crypto/FilterMask.java
Normal file
28
src/main/java/net/minestom/server/crypto/FilterMask.java
Normal file
@ -0,0 +1,28 @@
|
||||
package net.minestom.server.crypto;
|
||||
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
import static net.minestom.server.network.NetworkBuffer.LONG_ARRAY;
|
||||
|
||||
public record FilterMask(@NotNull Type type, @NotNull BitSet mask) implements NetworkBuffer.Writer {
|
||||
public FilterMask(@NotNull NetworkBuffer reader) {
|
||||
this(reader.readEnum(Type.class), BitSet.valueOf(reader.read(LONG_ARRAY)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.writeEnum(Type.class, type);
|
||||
if (type == Type.PARTIALLY_FILTERED) {
|
||||
writer.write(LONG_ARRAY, mask.toLongArray());
|
||||
}
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
PASS_THROUGH,
|
||||
FULLY_FILTERED,
|
||||
PARTIALLY_FILTERED
|
||||
}
|
||||
}
|
@ -2,45 +2,47 @@ package net.minestom.server.crypto;
|
||||
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.BitSet;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public record LastSeenMessages(@NotNull List<@NotNull Entry> entries) implements NetworkBuffer.Writer {
|
||||
import static net.minestom.server.network.NetworkBuffer.VAR_INT;
|
||||
|
||||
public record LastSeenMessages(@NotNull List<@NotNull MessageSignature> entries) implements NetworkBuffer.Writer {
|
||||
public LastSeenMessages {
|
||||
entries = List.copyOf(entries);
|
||||
}
|
||||
|
||||
public LastSeenMessages(@NotNull NetworkBuffer reader) {
|
||||
this(reader.readCollection(Entry::new));
|
||||
this(reader.readCollection(MessageSignature::new));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
}
|
||||
|
||||
public record Entry(UUID from, MessageSignature lastSignature) implements NetworkBuffer.Writer {
|
||||
public Entry(@NotNull NetworkBuffer reader) {
|
||||
this(reader.read(NetworkBuffer.UUID), new MessageSignature(reader));
|
||||
public record Packed(@NotNull List<MessageSignature.@NotNull Packed> entries) implements NetworkBuffer.Writer {
|
||||
public static final Packed EMPTY = new Packed(List.of());
|
||||
|
||||
public Packed(@NotNull NetworkBuffer reader) {
|
||||
this(reader.readCollection(MessageSignature.Packed::new));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.write(NetworkBuffer.UUID, from);
|
||||
writer.write(lastSignature);
|
||||
writer.writeCollection(entries);
|
||||
}
|
||||
}
|
||||
|
||||
public record Update(LastSeenMessages lastSeen, @Nullable Entry lastReceived) implements NetworkBuffer.Writer {
|
||||
public record Update(int offset, @NotNull BitSet acknowledged) implements NetworkBuffer.Writer {
|
||||
public Update(@NotNull NetworkBuffer reader) {
|
||||
this(new LastSeenMessages(reader), reader.readOptional(Entry::new));
|
||||
this(reader.read(VAR_INT), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.write(lastSeen);
|
||||
writer.writeOptional(lastReceived);
|
||||
writer.write(VAR_INT, offset);
|
||||
//writer.writeFixedBitSet(acknowledged);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,16 +2,45 @@ package net.minestom.server.crypto;
|
||||
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
|
||||
import static net.minestom.server.network.NetworkBuffer.BYTE_ARRAY;
|
||||
import static net.minestom.server.network.NetworkBuffer.RAW_BYTES;
|
||||
import static net.minestom.server.network.NetworkBuffer.VAR_INT;
|
||||
|
||||
public record MessageSignature(byte @NotNull [] signature) implements NetworkBuffer.Writer {
|
||||
public MessageSignature {
|
||||
if (signature.length != 256) {
|
||||
throw new IllegalArgumentException("Signature must be 256 bytes long");
|
||||
}
|
||||
}
|
||||
|
||||
public MessageSignature(@NotNull NetworkBuffer reader) {
|
||||
this(reader.read(BYTE_ARRAY));
|
||||
this(reader.readBytes(256));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.write(BYTE_ARRAY, signature);
|
||||
writer.write(RAW_BYTES, signature);
|
||||
}
|
||||
|
||||
public record Packed(int id, @UnknownNullability MessageSignature fullSignature) implements NetworkBuffer.Writer {
|
||||
public Packed(@NotNull NetworkBuffer reader) {
|
||||
this(read(reader));
|
||||
}
|
||||
|
||||
private Packed(@NotNull Packed packed) {
|
||||
this(packed.id, packed.fullSignature);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.write(VAR_INT, id + 1);
|
||||
if (id == 0) writer.write(fullSignature);
|
||||
}
|
||||
|
||||
private static Packed read(NetworkBuffer reader) {
|
||||
final int id = reader.read(VAR_INT) - 1;
|
||||
return new Packed(id, id == -1 ? new MessageSignature(reader) : null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,31 @@
|
||||
package net.minestom.server.crypto;
|
||||
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
public final class SignedMessageBody {
|
||||
|
||||
public record Packed(@NotNull String content, @NotNull Instant timeStamp, long salt,
|
||||
LastSeenMessages.@NotNull Packed lastSeen) implements NetworkBuffer.Writer {
|
||||
public Packed {
|
||||
if (content.length() > 256) {
|
||||
throw new IllegalArgumentException("Message content too long");
|
||||
}
|
||||
}
|
||||
|
||||
public Packed(@NotNull NetworkBuffer reader) {
|
||||
this(reader.read(NetworkBuffer.STRING), Instant.ofEpochMilli(reader.read(NetworkBuffer.LONG)),
|
||||
reader.read(NetworkBuffer.LONG), new LastSeenMessages.Packed(reader));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.write(NetworkBuffer.STRING, content);
|
||||
writer.write(NetworkBuffer.LONG, timeStamp.toEpochMilli());
|
||||
writer.write(NetworkBuffer.LONG, salt);
|
||||
writer.write(lastSeen);
|
||||
}
|
||||
}
|
||||
}
|
@ -28,6 +28,10 @@ public final class Metadata {
|
||||
return new MetadataImpl.EntryImpl<>(TYPE_VARINT, value, NetworkBuffer.VAR_INT);
|
||||
}
|
||||
|
||||
public static Entry<Long> Long(long value) {
|
||||
return new MetadataImpl.EntryImpl<>(TYPE_LONG, value, NetworkBuffer.LONG);
|
||||
}
|
||||
|
||||
public static Entry<Float> Float(float value) {
|
||||
return new MetadataImpl.EntryImpl<>(TYPE_FLOAT, value, NetworkBuffer.FLOAT);
|
||||
}
|
||||
@ -97,23 +101,24 @@ public final class Metadata {
|
||||
|
||||
public static final byte TYPE_BYTE = 0;
|
||||
public static final byte TYPE_VARINT = 1;
|
||||
public static final byte TYPE_FLOAT = 2;
|
||||
public static final byte TYPE_STRING = 3;
|
||||
public static final byte TYPE_CHAT = 4;
|
||||
public static final byte TYPE_OPTCHAT = 5;
|
||||
public static final byte TYPE_SLOT = 6;
|
||||
public static final byte TYPE_BOOLEAN = 7;
|
||||
public static final byte TYPE_ROTATION = 8;
|
||||
public static final byte TYPE_POSITION = 9;
|
||||
public static final byte TYPE_OPTPOSITION = 10;
|
||||
public static final byte TYPE_DIRECTION = 11;
|
||||
public static final byte TYPE_OPTUUID = 12;
|
||||
public static final byte TYPE_OPTBLOCKID = 13;
|
||||
public static final byte TYPE_NBT = 14;
|
||||
public static final byte TYPE_PARTICLE = 15;
|
||||
public static final byte TYPE_VILLAGERDATA = 16;
|
||||
public static final byte TYPE_OPTVARINT = 17;
|
||||
public static final byte TYPE_POSE = 18;
|
||||
public static final byte TYPE_LONG = 2;
|
||||
public static final byte TYPE_FLOAT = 3;
|
||||
public static final byte TYPE_STRING = 4;
|
||||
public static final byte TYPE_CHAT = 5;
|
||||
public static final byte TYPE_OPTCHAT = 6;
|
||||
public static final byte TYPE_SLOT = 7;
|
||||
public static final byte TYPE_BOOLEAN = 8;
|
||||
public static final byte TYPE_ROTATION = 9;
|
||||
public static final byte TYPE_POSITION = 10;
|
||||
public static final byte TYPE_OPTPOSITION = 11;
|
||||
public static final byte TYPE_DIRECTION = 12;
|
||||
public static final byte TYPE_OPTUUID = 13;
|
||||
public static final byte TYPE_OPTBLOCKID = 14;
|
||||
public static final byte TYPE_NBT = 15;
|
||||
public static final byte TYPE_PARTICLE = 16;
|
||||
public static final byte TYPE_VILLAGERDATA = 17;
|
||||
public static final byte TYPE_OPTVARINT = 18;
|
||||
public static final byte TYPE_POSE = 19;
|
||||
|
||||
private static final VarHandle NOTIFIED_CHANGES;
|
||||
|
||||
|
@ -932,8 +932,9 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
||||
*/
|
||||
public void setDisplayName(@Nullable Component displayName) {
|
||||
this.displayName = displayName;
|
||||
PacketUtils.broadcastPacket(new PlayerInfoPacket(PlayerInfoPacket.Action.UPDATE_DISPLAY_NAME,
|
||||
new PlayerInfoPacket.UpdateDisplayName(getUuid(), displayName)));
|
||||
// TODO
|
||||
//PacketUtils.broadcastPacket(new PlayerInfoPacket(PlayerInfoPacket.Action.UPDATE_DISPLAY_NAME,
|
||||
// new PlayerInfoPacket.UpdateDisplayName(getUuid(), displayName)));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -961,8 +962,8 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
||||
|
||||
DestroyEntitiesPacket destroyEntitiesPacket = new DestroyEntitiesPacket(getEntityId());
|
||||
|
||||
final PlayerInfoPacket removePlayerPacket = getRemovePlayerToList();
|
||||
final PlayerInfoPacket addPlayerPacket = getAddPlayerToList();
|
||||
final PlayerInfoRemovePacket removePlayerPacket = getRemovePlayerToList();
|
||||
final PlayerInfoUpdatePacket addPlayerPacket = getAddPlayerToList();
|
||||
|
||||
RespawnPacket respawnPacket = new RespawnPacket(getDimensionType().toString(), "minestom:world",
|
||||
0, gameMode, gameMode, false, levelFlat, true);
|
||||
@ -1288,8 +1289,9 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
||||
// Condition to prevent sending the packets before spawning the player
|
||||
if (isActive()) {
|
||||
sendPacket(new ChangeGameStatePacket(ChangeGameStatePacket.Reason.CHANGE_GAMEMODE, gameMode.id()));
|
||||
PacketUtils.broadcastPacket(new PlayerInfoPacket(PlayerInfoPacket.Action.UPDATE_GAMEMODE,
|
||||
new PlayerInfoPacket.UpdateGameMode(getUuid(), gameMode)));
|
||||
// TODO
|
||||
//PacketUtils.broadcastPacket(new PlayerInfoPacket(PlayerInfoPacket.Action.UPDATE_GAMEMODE,
|
||||
// new PlayerInfoPacket.UpdateGameMode(getUuid(), gameMode)));
|
||||
}
|
||||
|
||||
// The client updates their abilities based on the GameMode as follows
|
||||
@ -1789,8 +1791,9 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
||||
*/
|
||||
public void refreshLatency(int latency) {
|
||||
this.latency = latency;
|
||||
PacketUtils.broadcastPacket(new PlayerInfoPacket(PlayerInfoPacket.Action.UPDATE_LATENCY,
|
||||
new PlayerInfoPacket.UpdateLatency(getUuid(), latency)));
|
||||
// TODO
|
||||
//PacketUtils.broadcastPacket(new PlayerInfoPacket(PlayerInfoPacket.Action.UPDATE_LATENCY,
|
||||
// new PlayerInfoPacket.UpdateLatency(getUuid(), latency)));
|
||||
}
|
||||
|
||||
public void refreshOnGround(boolean onGround) {
|
||||
@ -1908,24 +1911,25 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
||||
/**
|
||||
* Gets the packet to add the player from the tab-list.
|
||||
*
|
||||
* @return a {@link PlayerInfoPacket} to add the player
|
||||
* @return a {@link PlayerInfoUpdatePacket} to add the player
|
||||
*/
|
||||
protected @NotNull PlayerInfoPacket getAddPlayerToList() {
|
||||
protected @NotNull PlayerInfoUpdatePacket getAddPlayerToList() {
|
||||
final PlayerSkin skin = this.skin;
|
||||
List<PlayerInfoPacket.AddPlayer.Property> prop = skin != null ?
|
||||
List.of(new PlayerInfoPacket.AddPlayer.Property("textures", skin.textures(), skin.signature())) :
|
||||
List<PlayerInfoUpdatePacket.Property> prop = skin != null ?
|
||||
List.of(new PlayerInfoUpdatePacket.Property("textures", skin.textures(), skin.signature())) :
|
||||
List.of();
|
||||
return new PlayerInfoPacket(PlayerInfoPacket.Action.ADD_PLAYER,
|
||||
new PlayerInfoPacket.AddPlayer(getUuid(), getUsername(), prop, getGameMode(), getLatency(), displayName, null));
|
||||
return new PlayerInfoUpdatePacket(EnumSet.of(PlayerInfoUpdatePacket.Action.ADD_PLAYER, PlayerInfoUpdatePacket.Action.UPDATE_LISTED),
|
||||
List.of(new PlayerInfoUpdatePacket.Entry(getUuid(), getUsername(), prop,
|
||||
true, getLatency(), getGameMode(), displayName)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the packet to remove the player from the tab-list.
|
||||
*
|
||||
* @return a {@link PlayerInfoPacket} to remove the player
|
||||
* @return a {@link PlayerInfoRemovePacket} to remove the player
|
||||
*/
|
||||
protected @NotNull PlayerInfoPacket getRemovePlayerToList() {
|
||||
return new PlayerInfoPacket(PlayerInfoPacket.Action.REMOVE_PLAYER, new PlayerInfoPacket.RemovePlayer(getUuid()));
|
||||
protected @NotNull PlayerInfoRemovePacket getRemovePlayerToList() {
|
||||
return new PlayerInfoRemovePacket(List.of(getUuid()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -32,7 +32,8 @@ public class ChatMessageListener {
|
||||
}
|
||||
|
||||
public static void chatMessageListener(ClientChatMessagePacket packet, Player player) {
|
||||
final String message = packet.message();
|
||||
System.out.println("packet "+packet);
|
||||
final String message = "test";
|
||||
if (!Messenger.canReceiveMessage(player)) {
|
||||
Messenger.sendRejectionMessage(player);
|
||||
return;
|
||||
|
@ -15,9 +15,7 @@ import org.jglrxavpok.hephaistos.nbt.NBTWriter;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
@ -202,6 +200,25 @@ public final class NetworkBuffer {
|
||||
return enumClass.getEnumConstants()[read(VAR_INT)];
|
||||
}
|
||||
|
||||
public <E extends Enum<E>> void writeEnumSet(EnumSet<E> enumSet, Class<E> enumType) {
|
||||
final E[] values = enumType.getEnumConstants();
|
||||
BitSet bitSet = new BitSet(values.length);
|
||||
for (int i = 0; i < values.length; ++i) {
|
||||
bitSet.set(i, enumSet.contains(values[i]));
|
||||
}
|
||||
writeFixedBitSet(bitSet, values.length);
|
||||
}
|
||||
|
||||
private void writeFixedBitSet(BitSet set, int length) {
|
||||
final int setLength = set.length();
|
||||
if (setLength > length) {
|
||||
throw new IllegalArgumentException("BitSet is larger than expected size (" + setLength + ">" + length + ")");
|
||||
} else {
|
||||
final byte[] array = set.toByteArray();
|
||||
write(RAW_BYTES, array);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] readBytes(int length) {
|
||||
byte[] bytes = new byte[length];
|
||||
nioBuffer.get(readIndex, bytes, 0, length);
|
||||
|
@ -58,33 +58,33 @@ public sealed class ClientPacketsHandler permits ClientPacketsHandler.Status, Cl
|
||||
register(0x03, ClientChatAckPacket::new);
|
||||
register(0x04, ClientCommandChatPacket::new);
|
||||
register(0x05, ClientChatMessagePacket::new);
|
||||
register(0x06, ClientChatPreviewPacket::new);
|
||||
register(0x07, ClientStatusPacket::new);
|
||||
register(0x08, ClientSettingsPacket::new);
|
||||
register(0x09, ClientTabCompletePacket::new);
|
||||
register(0x0A, ClientClickWindowButtonPacket::new);
|
||||
register(0x0B, ClientClickWindowPacket::new);
|
||||
register(0x0C, ClientCloseWindowPacket::new);
|
||||
register(0x0D, ClientPluginMessagePacket::new);
|
||||
register(0x0E, ClientEditBookPacket::new);
|
||||
register(0x0F, ClientQueryEntityNbtPacket::new);
|
||||
register(0x10, ClientInteractEntityPacket::new);
|
||||
register(0x11, ClientGenerateStructurePacket::new);
|
||||
register(0x12, ClientKeepAlivePacket::new);
|
||||
register(0x06, ClientStatusPacket::new);
|
||||
register(0x07, ClientSettingsPacket::new);
|
||||
register(0x08, ClientTabCompletePacket::new);
|
||||
register(0x09, ClientClickWindowButtonPacket::new);
|
||||
register(0x0A, ClientClickWindowPacket::new);
|
||||
register(0x0B, ClientCloseWindowPacket::new);
|
||||
register(0x0C, ClientPluginMessagePacket::new);
|
||||
register(0x0D, ClientEditBookPacket::new);
|
||||
register(0x0E, ClientQueryEntityNbtPacket::new);
|
||||
register(0x0F, ClientInteractEntityPacket::new);
|
||||
register(0x10, ClientGenerateStructurePacket::new);
|
||||
register(0x11, ClientKeepAlivePacket::new);
|
||||
// 0x12 packet not used server-side
|
||||
register(0x14, ClientPlayerPositionPacket::new);
|
||||
register(0x15, ClientPlayerPositionAndRotationPacket::new);
|
||||
register(0x16, ClientPlayerRotationPacket::new);
|
||||
register(0x17, ClientPlayerPacket::new);
|
||||
register(0x18, ClientVehicleMovePacket::new);
|
||||
register(0x19, ClientSteerBoatPacket::new);
|
||||
register(0x1A, ClientPickItemPacket::new);
|
||||
register(0x1B, ClientCraftRecipeRequest::new);
|
||||
register(0x1C, ClientPlayerAbilitiesPacket::new);
|
||||
register(0x1D, ClientPlayerDiggingPacket::new);
|
||||
register(0x1E, ClientEntityActionPacket::new);
|
||||
register(0x1F, ClientSteerVehiclePacket::new);
|
||||
register(0x20, ClientPongPacket::new);
|
||||
register(0x13, ClientPlayerPositionPacket::new);
|
||||
register(0x14, ClientPlayerPositionAndRotationPacket::new);
|
||||
register(0x15, ClientPlayerRotationPacket::new);
|
||||
register(0x16, ClientPlayerPacket::new);
|
||||
register(0x17, ClientVehicleMovePacket::new);
|
||||
register(0x18, ClientSteerBoatPacket::new);
|
||||
register(0x19, ClientPickItemPacket::new);
|
||||
register(0x1A, ClientCraftRecipeRequest::new);
|
||||
register(0x1B, ClientPlayerAbilitiesPacket::new);
|
||||
register(0x1C, ClientPlayerDiggingPacket::new);
|
||||
register(0x1D, ClientEntityActionPacket::new);
|
||||
register(0x1E, ClientSteerVehiclePacket::new);
|
||||
register(0x1F, ClientPongPacket::new);
|
||||
register(0x20, ClientChatSessionUpdatePacket::new);
|
||||
register(0x21, ClientSetRecipeBookStatePacket::new);
|
||||
register(0x22, ClientSetDisplayedRecipePacket::new);
|
||||
register(0x23, ClientNameItemPacket::new);
|
||||
|
@ -3,18 +3,13 @@ package net.minestom.server.network.packet.client.login;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.crypto.SaltSignaturePair;
|
||||
import net.minestom.server.crypto.SignatureValidator;
|
||||
import net.minestom.server.extras.MojangAuth;
|
||||
import net.minestom.server.extras.mojangAuth.MojangCrypt;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.network.packet.client.ClientPreplayPacket;
|
||||
import net.minestom.server.network.player.PlayerConnection;
|
||||
import net.minestom.server.network.player.PlayerSocketConnection;
|
||||
import net.minestom.server.utils.Either;
|
||||
import net.minestom.server.utils.InterfaceUtils;
|
||||
import net.minestom.server.utils.async.AsyncUtils;
|
||||
import net.minestom.server.utils.crypto.KeyUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
@ -28,14 +23,14 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.UUID;
|
||||
|
||||
import static net.minestom.server.network.NetworkBuffer.*;
|
||||
import static net.minestom.server.network.NetworkBuffer.BYTE_ARRAY;
|
||||
|
||||
public record EncryptionResponsePacket(byte[] sharedSecret,
|
||||
Either<byte[], SaltSignaturePair> nonceOrSignature) implements ClientPreplayPacket {
|
||||
byte[] encryptedVerifyToken) implements ClientPreplayPacket {
|
||||
private static final Gson GSON = new Gson();
|
||||
|
||||
public EncryptionResponsePacket(@NotNull NetworkBuffer reader) {
|
||||
this(reader.read(BYTE_ARRAY), reader.readEither(networkBuffer -> networkBuffer.read(BYTE_ARRAY), SaltSignaturePair::new));
|
||||
this(reader.read(BYTE_ARRAY), reader.read(BYTE_ARRAY));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -50,15 +45,8 @@ public record EncryptionResponsePacket(byte[] sharedSecret,
|
||||
}
|
||||
|
||||
final boolean hasPublicKey = connection.playerPublicKey() != null;
|
||||
final boolean verificationFailed = nonceOrSignature.map(
|
||||
nonce -> hasPublicKey || !Arrays.equals(socketConnection.getNonce(),
|
||||
MojangCrypt.decryptUsingKey(MojangAuth.getKeyPair().getPrivate(), nonce)),
|
||||
signature -> !hasPublicKey || !SignatureValidator
|
||||
.from(connection.playerPublicKey().publicKey(), KeyUtils.SignatureAlgorithm.SHA256withRSA)
|
||||
.validate(binaryWriter -> {
|
||||
binaryWriter.write(RAW_BYTES, socketConnection.getNonce());
|
||||
binaryWriter.write(LONG, signature.salt());
|
||||
}, signature.signature()));
|
||||
final boolean verificationFailed = hasPublicKey || !Arrays.equals(socketConnection.getNonce(),
|
||||
MojangCrypt.decryptUsingKey(MojangAuth.getKeyPair().getPrivate(), encryptedVerifyToken));
|
||||
|
||||
if (verificationFailed) {
|
||||
MinecraftServer.LOGGER.error("Encryption failed for {}", loginUsername);
|
||||
@ -111,8 +99,7 @@ public record EncryptionResponsePacket(byte[] sharedSecret,
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.write(BYTE_ARRAY, sharedSecret);
|
||||
writer.writeEither(nonceOrSignature, (networkBuffer, bytes) -> networkBuffer.write(BYTE_ARRAY, bytes),
|
||||
InterfaceUtils.flipBiConsumer(SaltSignaturePair::write));
|
||||
writer.write(BYTE_ARRAY, encryptedVerifyToken);
|
||||
}
|
||||
|
||||
private SecretKey getSecretKey() {
|
||||
|
@ -2,9 +2,6 @@ package net.minestom.server.network.packet.client.login;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.crypto.PlayerPublicKey;
|
||||
import net.minestom.server.crypto.SignatureValidator;
|
||||
import net.minestom.server.extras.MojangAuth;
|
||||
import net.minestom.server.extras.bungee.BungeeCordProxy;
|
||||
import net.minestom.server.extras.velocity.VelocityProxy;
|
||||
@ -19,45 +16,22 @@ import net.minestom.server.network.player.PlayerSocketConnection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
import static net.minestom.server.network.NetworkBuffer.*;
|
||||
import static net.minestom.server.network.NetworkBuffer.STRING;
|
||||
import static net.minestom.server.network.NetworkBuffer.UUID;
|
||||
|
||||
public record LoginStartPacket(@NotNull String username,
|
||||
@Nullable PlayerPublicKey publicKey,
|
||||
@Nullable UUID profileId) implements ClientPreplayPacket {
|
||||
private static final Component ALREADY_CONNECTED = Component.text("You are already on this server", NamedTextColor.RED);
|
||||
|
||||
public LoginStartPacket(@NotNull NetworkBuffer reader) {
|
||||
this(reader.read(STRING), reader.readOptional(PlayerPublicKey::new), reader.readOptional(UUID));
|
||||
this(reader.read(STRING), reader.readOptional(UUID));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(@NotNull PlayerConnection connection) {
|
||||
// TODO use uuid
|
||||
// TODO configurable check & messages
|
||||
if (publicKey != null) {
|
||||
if (!SignatureValidator.YGGDRASIL.validate(binaryWriter -> {
|
||||
if (profileId != null) {
|
||||
binaryWriter.write(LONG, profileId.getMostSignificantBits());
|
||||
binaryWriter.write(LONG, profileId.getLeastSignificantBits());
|
||||
} else {
|
||||
MinecraftServer.LOGGER.warn("Profile ID was null for player {}, signature will not match!", username);
|
||||
}
|
||||
binaryWriter.write(LONG, publicKey.expiresAt().toEpochMilli());
|
||||
binaryWriter.write(RAW_BYTES, publicKey.publicKey().getEncoded());
|
||||
}, publicKey.signature())) {
|
||||
connection.sendPacket(new LoginDisconnectPacket(Component.text("Invalid Profile Public Key!")));
|
||||
connection.disconnect();
|
||||
}
|
||||
if (publicKey.expiresAt().isBefore(Instant.now())) {
|
||||
connection.sendPacket(new LoginDisconnectPacket(Component.text("Expired Profile Public Key!")));
|
||||
connection.disconnect();
|
||||
}
|
||||
connection.setPlayerPublicKey(publicKey);
|
||||
}
|
||||
final boolean isSocketConnection = connection instanceof PlayerSocketConnection;
|
||||
// Proxy support (only for socket clients) and cache the login username
|
||||
if (isSocketConnection) {
|
||||
|
@ -1,17 +1,18 @@
|
||||
package net.minestom.server.network.packet.client.play;
|
||||
|
||||
import net.minestom.server.crypto.LastSeenMessages;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.network.packet.client.ClientPacket;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public record ClientChatAckPacket(@NotNull LastSeenMessages.Update update) implements ClientPacket {
|
||||
import static net.minestom.server.network.NetworkBuffer.VAR_INT;
|
||||
|
||||
public record ClientChatAckPacket(int offset) implements ClientPacket {
|
||||
public ClientChatAckPacket(@NotNull NetworkBuffer reader) {
|
||||
this(new LastSeenMessages.Update(reader));
|
||||
this(reader.read(VAR_INT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.write(update);
|
||||
writer.write(VAR_INT, offset);
|
||||
}
|
||||
}
|
||||
|
@ -1,37 +1,42 @@
|
||||
package net.minestom.server.network.packet.client.play;
|
||||
|
||||
import net.minestom.server.crypto.LastSeenMessages;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.crypto.ChatBound;
|
||||
import net.minestom.server.crypto.FilterMask;
|
||||
import net.minestom.server.crypto.MessageSignature;
|
||||
import net.minestom.server.crypto.SignedMessageBody;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.network.packet.client.ClientPacket;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static net.minestom.server.network.NetworkBuffer.*;
|
||||
import java.util.UUID;
|
||||
|
||||
public record ClientChatMessagePacket(@NotNull String message,
|
||||
long timestamp, long salt, @NotNull MessageSignature signature,
|
||||
boolean signedPreview,
|
||||
@NotNull LastSeenMessages.Update lastSeenMessages) implements ClientPacket {
|
||||
public ClientChatMessagePacket {
|
||||
if (message.length() > 256) {
|
||||
throw new IllegalArgumentException("Message cannot be more than 256 characters long.");
|
||||
}
|
||||
}
|
||||
import static net.minestom.server.network.NetworkBuffer.COMPONENT;
|
||||
import static net.minestom.server.network.NetworkBuffer.VAR_INT;
|
||||
|
||||
public record ClientChatMessagePacket(@NotNull UUID sender, int index,
|
||||
@Nullable MessageSignature signature,
|
||||
SignedMessageBody.@NotNull Packed body,
|
||||
@Nullable Component unsignedContent, FilterMask filterMask,
|
||||
@NotNull ChatBound chatBound) implements ClientPacket {
|
||||
|
||||
public ClientChatMessagePacket(@NotNull NetworkBuffer reader) {
|
||||
this(reader.read(STRING),
|
||||
reader.read(LONG), reader.read(LONG), new MessageSignature(reader),
|
||||
reader.read(BOOLEAN),
|
||||
new LastSeenMessages.Update(reader));
|
||||
this(reader.read(NetworkBuffer.UUID), reader.read(VAR_INT),
|
||||
reader.readOptional(MessageSignature::new),
|
||||
new SignedMessageBody.Packed(reader),
|
||||
reader.readOptional(COMPONENT), new FilterMask(reader),
|
||||
new ChatBound(reader));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.write(STRING, message);
|
||||
writer.write(LONG, timestamp);
|
||||
writer.write(LONG, salt);
|
||||
writer.write(signature);
|
||||
writer.write(BOOLEAN, signedPreview);
|
||||
writer.write(lastSeenMessages);
|
||||
writer.write(NetworkBuffer.UUID, sender);
|
||||
writer.write(VAR_INT, index);
|
||||
writer.writeOptional(signature);
|
||||
writer.write(body);
|
||||
writer.writeOptional(COMPONENT, unsignedContent);
|
||||
writer.write(filterMask);
|
||||
writer.write(chatBound);
|
||||
}
|
||||
}
|
||||
|
@ -1,26 +0,0 @@
|
||||
package net.minestom.server.network.packet.client.play;
|
||||
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.network.packet.client.ClientPacket;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static net.minestom.server.network.NetworkBuffer.INT;
|
||||
import static net.minestom.server.network.NetworkBuffer.STRING;
|
||||
|
||||
public record ClientChatPreviewPacket(int queryId, @NotNull String query) implements ClientPacket {
|
||||
public ClientChatPreviewPacket {
|
||||
if (query.length() > 256) {
|
||||
throw new IllegalArgumentException("Query length cannot be greater than 256");
|
||||
}
|
||||
}
|
||||
|
||||
public ClientChatPreviewPacket(@NotNull NetworkBuffer reader) {
|
||||
this(reader.read(INT), reader.read(STRING));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.write(INT, queryId);
|
||||
writer.write(STRING, query);
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package net.minestom.server.network.packet.client.play;
|
||||
|
||||
import net.minestom.server.crypto.PlayerPublicKey;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.network.packet.client.ClientPacket;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public record ClientChatSessionUpdatePacket(@NotNull UUID sessionId,
|
||||
@Nullable PlayerPublicKey publicKey) implements ClientPacket {
|
||||
public ClientChatSessionUpdatePacket(@NotNull NetworkBuffer reader) {
|
||||
this(reader.read(NetworkBuffer.UUID), new PlayerPublicKey(reader));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.write(NetworkBuffer.UUID, sessionId);
|
||||
writer.writeOptional(publicKey);
|
||||
}
|
||||
}
|
@ -6,11 +6,11 @@ import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.network.packet.client.ClientPacket;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static net.minestom.server.network.NetworkBuffer.*;
|
||||
import static net.minestom.server.network.NetworkBuffer.LONG;
|
||||
import static net.minestom.server.network.NetworkBuffer.STRING;
|
||||
|
||||
public record ClientCommandChatPacket(@NotNull String message, long timestamp,
|
||||
long salt, @NotNull ArgumentSignatures signatures,
|
||||
boolean signedPreview,
|
||||
LastSeenMessages.@NotNull Update lastSeenMessages) implements ClientPacket {
|
||||
public ClientCommandChatPacket {
|
||||
if (message.length() > 256) {
|
||||
@ -20,7 +20,8 @@ public record ClientCommandChatPacket(@NotNull String message, long timestamp,
|
||||
|
||||
public ClientCommandChatPacket(@NotNull NetworkBuffer reader) {
|
||||
this(reader.read(STRING), reader.read(LONG),
|
||||
reader.read(LONG), new ArgumentSignatures(reader), reader.read(BOOLEAN), new LastSeenMessages.Update(reader));
|
||||
reader.read(LONG), new ArgumentSignatures(reader),
|
||||
new LastSeenMessages.Update(reader));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -29,7 +30,6 @@ public record ClientCommandChatPacket(@NotNull String message, long timestamp,
|
||||
writer.write(LONG, timestamp);
|
||||
writer.write(LONG, salt);
|
||||
writer.write(signatures);
|
||||
writer.write(BOOLEAN, signedPreview);
|
||||
writer.write(lastSeenMessages);
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,6 @@ public final class ServerPacketIdentifier {
|
||||
public static final int BLOCK_CHANGE = nextPlayId();
|
||||
public static final int BOSS_BAR = nextPlayId();
|
||||
public static final int SERVER_DIFFICULTY = nextPlayId();
|
||||
public static final int CHAT_PREVIEW = nextPlayId();
|
||||
public static final int CLEAR_TITLES = nextPlayId();
|
||||
public static final int TAB_COMPLETE = nextPlayId();
|
||||
public static final int DECLARE_COMMANDS = nextPlayId();
|
||||
@ -34,9 +33,9 @@ public final class ServerPacketIdentifier {
|
||||
public static final int SET_COOLDOWN = nextPlayId();
|
||||
public static final int CUSTOM_CHAT_COMPLETIONS = nextPlayId();
|
||||
public static final int PLUGIN_MESSAGE = nextPlayId();
|
||||
public static final int NAMED_SOUND_EFFECT = nextPlayId();
|
||||
public static final int DELETE_CHAT_MESSAGE = nextPlayId();
|
||||
public static final int DISCONNECT = nextPlayId();
|
||||
public static final int DISGUISED_CHAT = nextPlayId();
|
||||
public static final int ENTITY_STATUS = nextPlayId();
|
||||
public static final int EXPLOSION = nextPlayId();
|
||||
public static final int UNLOAD_CHUNK = nextPlayId();
|
||||
@ -61,12 +60,12 @@ public final class ServerPacketIdentifier {
|
||||
public static final int PING = nextPlayId();
|
||||
public static final int CRAFT_RECIPE_RESPONSE = nextPlayId();
|
||||
public static final int PLAYER_ABILITIES = nextPlayId();
|
||||
public static final int PLAYER_CHAT_HEADER = nextPlayId();
|
||||
public static final int PLAYER_CHAT = nextPlayId();
|
||||
public static final int END_COMBAT_EVENT = nextPlayId();
|
||||
public static final int ENTER_COMBAT_EVENT = nextPlayId();
|
||||
public static final int DEATH_COMBAT_EVENT = nextPlayId();
|
||||
public static final int PLAYER_INFO = nextPlayId();
|
||||
public static final int PLAYER_INFO_REMOVE = nextPlayId();
|
||||
public static final int PLAYER_INFO_UPDATE = nextPlayId();
|
||||
public static final int FACE_PLAYER = nextPlayId();
|
||||
public static final int PLAYER_POSITION_AND_LOOK = nextPlayId();
|
||||
public static final int UNLOCK_RECIPES = nextPlayId();
|
||||
@ -89,7 +88,6 @@ public final class ServerPacketIdentifier {
|
||||
public static final int UPDATE_VIEW_POSITION = nextPlayId();
|
||||
public static final int UPDATE_VIEW_DISTANCE = nextPlayId(); // Not used by the dedicated server
|
||||
public static final int SPAWN_POSITION = nextPlayId();
|
||||
public static final int SET_DISPLAY_CHAT_PREVIEW = nextPlayId();
|
||||
public static final int DISPLAY_SCOREBOARD = nextPlayId();
|
||||
public static final int ENTITY_METADATA = nextPlayId();
|
||||
public static final int ATTACH_ENTITY = nextPlayId();
|
||||
@ -116,6 +114,7 @@ public final class ServerPacketIdentifier {
|
||||
public static final int ENTITY_TELEPORT = nextPlayId();
|
||||
public static final int ADVANCEMENTS = nextPlayId();
|
||||
public static final int ENTITY_PROPERTIES = nextPlayId();
|
||||
public static final int UPDATE_ENABLED_FEATURES = nextPlayId();
|
||||
public static final int ENTITY_EFFECT = nextPlayId();
|
||||
public static final int DECLARE_RECIPES = nextPlayId();
|
||||
public static final int TAGS = nextPlayId();
|
||||
|
@ -1,42 +0,0 @@
|
||||
package net.minestom.server.network.packet.server.play;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.network.packet.server.ComponentHoldingServerPacket;
|
||||
import net.minestom.server.network.packet.server.ServerPacket;
|
||||
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import static net.minestom.server.network.NetworkBuffer.*;
|
||||
|
||||
public record ChatPreviewPacket(int queryId, @Nullable Component preview) implements ComponentHoldingServerPacket {
|
||||
public ChatPreviewPacket(@NotNull NetworkBuffer reader) {
|
||||
this(reader.read(INT), reader.readOptional(COMPONENT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.write(INT, queryId);
|
||||
writer.writeOptional(COMPONENT, preview);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return ServerPacketIdentifier.CHAT_PREVIEW;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Collection<Component> components() {
|
||||
return List.of(preview);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ServerPacket copyWithOperator(@NotNull UnaryOperator<Component> operator) {
|
||||
return new ChatPreviewPacket(queryId, operator.apply(preview));
|
||||
}
|
||||
}
|
@ -7,19 +7,19 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static net.minestom.server.network.NetworkBuffer.*;
|
||||
|
||||
public record ExplosionPacket(float x, float y, float z, float radius, byte @NotNull [] records,
|
||||
public record ExplosionPacket(double x, double y, double z, float radius, byte @NotNull [] records,
|
||||
float playerMotionX, float playerMotionY, float playerMotionZ) implements ServerPacket {
|
||||
public ExplosionPacket(@NotNull NetworkBuffer reader) {
|
||||
this(reader.read(FLOAT), reader.read(FLOAT), reader.read(FLOAT),
|
||||
this(reader.read(DOUBLE), reader.read(DOUBLE), reader.read(DOUBLE),
|
||||
reader.read(FLOAT), reader.readBytes(reader.read(VAR_INT) * 3),
|
||||
reader.read(FLOAT), reader.read(FLOAT), reader.read(FLOAT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.write(FLOAT, x);
|
||||
writer.write(FLOAT, y);
|
||||
writer.write(FLOAT, z);
|
||||
writer.write(DOUBLE, x);
|
||||
writer.write(DOUBLE, y);
|
||||
writer.write(DOUBLE, z);
|
||||
writer.write(FLOAT, radius);
|
||||
writer.write(VAR_INT, records.length / 3); // each record is 3 bytes long
|
||||
writer.write(RAW_BYTES, records);
|
||||
|
@ -31,6 +31,6 @@ public record NamedSoundEffectPacket(String soundName, Source source, int x, int
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return ServerPacketIdentifier.NAMED_SOUND_EFFECT;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -1,29 +0,0 @@
|
||||
package net.minestom.server.network.packet.server.play;
|
||||
|
||||
import net.minestom.server.crypto.MessageSignature;
|
||||
import net.minestom.server.crypto.SignedMessageHeader;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.network.packet.server.ServerPacket;
|
||||
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static net.minestom.server.network.NetworkBuffer.BYTE_ARRAY;
|
||||
|
||||
public record PlayerChatHeaderPacket(@NotNull SignedMessageHeader messageHeader, @NotNull MessageSignature signature,
|
||||
byte[] bodyDigest) implements ServerPacket {
|
||||
public PlayerChatHeaderPacket(@NotNull NetworkBuffer reader) {
|
||||
this(new SignedMessageHeader(reader), new MessageSignature(reader), reader.read(BYTE_ARRAY));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.write(messageHeader);
|
||||
writer.write(signature);
|
||||
writer.write(BYTE_ARRAY, bodyDigest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return ServerPacketIdentifier.PLAYER_CHAT_HEADER;
|
||||
}
|
||||
}
|
@ -1,242 +0,0 @@
|
||||
package net.minestom.server.network.packet.server.play;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.adventure.ComponentHolder;
|
||||
import net.minestom.server.crypto.PlayerPublicKey;
|
||||
import net.minestom.server.entity.GameMode;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.network.packet.server.ComponentHoldingServerPacket;
|
||||
import net.minestom.server.network.packet.server.ServerPacket;
|
||||
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import static net.minestom.server.network.NetworkBuffer.*;
|
||||
|
||||
public record PlayerInfoPacket(@NotNull Action action,
|
||||
@NotNull List<Entry> entries) implements ComponentHoldingServerPacket {
|
||||
public PlayerInfoPacket {
|
||||
entries = List.copyOf(entries);
|
||||
for (Entry entry : entries) {
|
||||
if (!entry.getClass().equals(action.getClazz()))
|
||||
throw new IllegalArgumentException("Invalid entry class for action " + action);
|
||||
}
|
||||
}
|
||||
|
||||
public PlayerInfoPacket(@NotNull Action action, @NotNull Entry entry) {
|
||||
this(action, List.of(entry));
|
||||
}
|
||||
|
||||
public PlayerInfoPacket(@NotNull NetworkBuffer reader) {
|
||||
this(read(reader));
|
||||
}
|
||||
|
||||
private PlayerInfoPacket(PlayerInfoPacket packet) {
|
||||
this(packet.action, packet.entries);
|
||||
}
|
||||
|
||||
private static PlayerInfoPacket read(@NotNull NetworkBuffer reader) {
|
||||
var action = Action.values()[reader.read(VAR_INT)];
|
||||
final int playerInfoCount = reader.read(VAR_INT);
|
||||
List<Entry> entries = new ArrayList<>(playerInfoCount);
|
||||
for (int i = 0; i < playerInfoCount; i++) {
|
||||
final UUID uuid = reader.read(UUID);
|
||||
entries.add(switch (action) {
|
||||
case ADD_PLAYER -> new AddPlayer(uuid, reader);
|
||||
case UPDATE_GAMEMODE -> new UpdateGameMode(uuid, reader);
|
||||
case UPDATE_LATENCY -> new UpdateLatency(uuid, reader);
|
||||
case UPDATE_DISPLAY_NAME -> new UpdateDisplayName(uuid, reader);
|
||||
case REMOVE_PLAYER -> new RemovePlayer(uuid);
|
||||
});
|
||||
}
|
||||
return new PlayerInfoPacket(action, entries);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.write(VAR_INT, action.ordinal());
|
||||
writer.writeCollection(entries, (w, entry) -> {
|
||||
w.write(UUID, entry.uuid());
|
||||
entry.write(w);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return ServerPacketIdentifier.PLAYER_INFO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Collection<Component> components() {
|
||||
switch (this.action) {
|
||||
case ADD_PLAYER, UPDATE_DISPLAY_NAME -> {
|
||||
List<Component> components = new ArrayList<>();
|
||||
for (Entry entry : entries) {
|
||||
if (entry instanceof ComponentHolder) {
|
||||
components.addAll(((ComponentHolder<? extends Entry>) entry).components());
|
||||
}
|
||||
}
|
||||
return components;
|
||||
}
|
||||
default -> {
|
||||
return List.of();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ServerPacket copyWithOperator(@NotNull UnaryOperator<Component> operator) {
|
||||
return switch (action) {
|
||||
case ADD_PLAYER, UPDATE_DISPLAY_NAME -> {
|
||||
List<Entry> entries = new ArrayList<>(this.entries.size());
|
||||
for (Entry entry : this.entries) {
|
||||
if (entry instanceof ComponentHolder) {
|
||||
entries.add(((ComponentHolder<? extends Entry>) entry).copyWithOperator(operator));
|
||||
} else {
|
||||
entries.add(entry);
|
||||
}
|
||||
}
|
||||
yield new PlayerInfoPacket(action, entries);
|
||||
}
|
||||
default -> this;
|
||||
};
|
||||
}
|
||||
|
||||
public enum Action {
|
||||
ADD_PLAYER(AddPlayer.class),
|
||||
UPDATE_GAMEMODE(UpdateGameMode.class),
|
||||
UPDATE_LATENCY(UpdateLatency.class),
|
||||
UPDATE_DISPLAY_NAME(UpdateDisplayName.class),
|
||||
REMOVE_PLAYER(RemovePlayer.class);
|
||||
|
||||
private final Class<? extends Entry> clazz;
|
||||
|
||||
Action(Class<? extends Entry> clazz) {
|
||||
this.clazz = clazz;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Class<? extends Entry> getClazz() {
|
||||
return clazz;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed interface Entry extends NetworkBuffer.Writer
|
||||
permits AddPlayer, UpdateGameMode, UpdateLatency, UpdateDisplayName, RemovePlayer {
|
||||
UUID uuid();
|
||||
}
|
||||
|
||||
public record AddPlayer(UUID uuid, String name, List<Property> properties, GameMode gameMode, int ping,
|
||||
@Nullable Component displayName,
|
||||
@Nullable PlayerPublicKey playerPublicKey) implements Entry, ComponentHolder<AddPlayer> {
|
||||
public AddPlayer {
|
||||
properties = List.copyOf(properties);
|
||||
}
|
||||
|
||||
public AddPlayer(UUID uuid, NetworkBuffer reader) {
|
||||
this(uuid, reader.read(STRING),
|
||||
reader.readCollection(Property::new),
|
||||
GameMode.values()[reader.read(VAR_INT)], reader.read(VAR_INT),
|
||||
reader.read(BOOLEAN) ? reader.read(COMPONENT) : null,
|
||||
reader.read(BOOLEAN) ? new PlayerPublicKey(reader) : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.write(STRING, name);
|
||||
writer.writeCollection(properties);
|
||||
writer.write(VAR_INT, (int) gameMode.id());
|
||||
writer.write(VAR_INT, ping);
|
||||
writer.writeOptional(COMPONENT, displayName);
|
||||
writer.writeOptional(playerPublicKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Collection<Component> components() {
|
||||
return displayName != null ? List.of(displayName) : List.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull AddPlayer copyWithOperator(@NotNull UnaryOperator<Component> operator) {
|
||||
return displayName != null ?
|
||||
new AddPlayer(uuid, name, properties, gameMode, ping, operator.apply(displayName), playerPublicKey) : this;
|
||||
}
|
||||
|
||||
public record Property(@NotNull String name, @NotNull String value,
|
||||
@Nullable String signature) implements NetworkBuffer.Writer {
|
||||
public Property(String name, String value) {
|
||||
this(name, value, null);
|
||||
}
|
||||
|
||||
public Property(@NotNull NetworkBuffer reader) {
|
||||
this(reader.read(STRING), reader.read(STRING),
|
||||
reader.read(BOOLEAN) ? reader.read(STRING) : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.write(STRING, name);
|
||||
writer.write(STRING, value);
|
||||
writer.write(BOOLEAN, signature != null);
|
||||
if (signature != null) writer.write(STRING, signature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public record UpdateGameMode(UUID uuid, GameMode gameMode) implements Entry {
|
||||
public UpdateGameMode(UUID uuid, NetworkBuffer reader) {
|
||||
this(uuid, GameMode.fromId(reader.read(VAR_INT).byteValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.write(VAR_INT, (int) gameMode.id());
|
||||
}
|
||||
}
|
||||
|
||||
public record UpdateLatency(UUID uuid, int ping) implements Entry {
|
||||
public UpdateLatency(UUID uuid, NetworkBuffer reader) {
|
||||
this(uuid, reader.read(VAR_INT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.write(VAR_INT, ping);
|
||||
}
|
||||
}
|
||||
|
||||
public record UpdateDisplayName(@NotNull UUID uuid,
|
||||
@Nullable Component displayName) implements Entry, ComponentHolder<UpdateDisplayName> {
|
||||
public UpdateDisplayName(UUID uuid, NetworkBuffer reader) {
|
||||
this(uuid, reader.read(BOOLEAN) ? reader.read(COMPONENT) : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.write(BOOLEAN, displayName != null);
|
||||
if (displayName != null) writer.write(COMPONENT, displayName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Collection<Component> components() {
|
||||
return displayName != null ? List.of(displayName) : List.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull UpdateDisplayName copyWithOperator(@NotNull UnaryOperator<Component> operator) {
|
||||
return displayName != null ? new UpdateDisplayName(uuid, operator.apply(displayName)) : this;
|
||||
}
|
||||
}
|
||||
|
||||
public record RemovePlayer(@NotNull UUID uuid) implements Entry {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package net.minestom.server.network.packet.server.play;
|
||||
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.network.packet.server.ServerPacket;
|
||||
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public record PlayerInfoRemovePacket(@NotNull List<@NotNull UUID> uuids) implements ServerPacket {
|
||||
public PlayerInfoRemovePacket {
|
||||
uuids = List.copyOf(uuids);
|
||||
}
|
||||
|
||||
public PlayerInfoRemovePacket(@NotNull NetworkBuffer reader) {
|
||||
this(reader.readCollection(NetworkBuffer.UUID));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.writeCollection(NetworkBuffer.UUID, uuids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return ServerPacketIdentifier.PLAYER_INFO_REMOVE;
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
package net.minestom.server.network.packet.server.play;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.entity.GameMode;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.network.packet.server.ServerPacket;
|
||||
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import static net.minestom.server.network.NetworkBuffer.*;
|
||||
|
||||
public record PlayerInfoUpdatePacket(@NotNull EnumSet<@NotNull Action> actions,
|
||||
@NotNull List<@NotNull Entry> entries) implements ServerPacket {
|
||||
public PlayerInfoUpdatePacket {
|
||||
actions = EnumSet.copyOf(actions);
|
||||
entries = List.copyOf(entries);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.writeEnumSet(actions, Action.class);
|
||||
writer.writeCollection(entries, (buffer, entry) -> {
|
||||
buffer.write(NetworkBuffer.UUID, entry.uuid);
|
||||
for (Action action : actions) {
|
||||
action.writer.write(buffer, entry);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return ServerPacketIdentifier.PLAYER_INFO_UPDATE;
|
||||
}
|
||||
|
||||
public record Entry(UUID uuid, String username, List<Property> properties,
|
||||
boolean listed, int latency, GameMode gameMode,
|
||||
@Nullable Component displayName) {
|
||||
public Entry {
|
||||
properties = List.copyOf(properties);
|
||||
}
|
||||
}
|
||||
|
||||
public record Property(@NotNull String name, @NotNull String value,
|
||||
@Nullable String signature) implements NetworkBuffer.Writer {
|
||||
public Property(String name, String value) {
|
||||
this(name, value, null);
|
||||
}
|
||||
|
||||
public Property(@NotNull NetworkBuffer reader) {
|
||||
this(reader.read(STRING), reader.read(STRING),
|
||||
reader.readOptional(STRING));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.write(STRING, name);
|
||||
writer.write(STRING, value);
|
||||
writer.writeOptional(STRING, signature);
|
||||
}
|
||||
}
|
||||
|
||||
public enum Action {
|
||||
ADD_PLAYER((writer, entry) -> {
|
||||
writer.write(STRING, entry.username);
|
||||
writer.writeCollection(entry.properties);
|
||||
}),
|
||||
INITIALIZE_CHAT(null),
|
||||
UPDATE_GAME_MODE((writer, entry) -> writer.write(VAR_INT, entry.gameMode.ordinal())),
|
||||
UPDATE_LISTED((writer, entry) -> writer.write(BOOLEAN, entry.listed)),
|
||||
UPDATE_LATENCY((writer, entry) -> writer.write(VAR_INT, entry.latency)),
|
||||
UPDATE_DISPLAY_NAME((writer, entry) -> writer.writeOptional(COMPONENT, entry.displayName));
|
||||
|
||||
final Writer writer;
|
||||
|
||||
Action(Writer writer) {
|
||||
this.writer = writer;
|
||||
}
|
||||
|
||||
interface Writer {
|
||||
void write(NetworkBuffer writer, Entry entry);
|
||||
}
|
||||
}
|
||||
}
|
@ -10,17 +10,16 @@ import org.jetbrains.annotations.Nullable;
|
||||
import static net.minestom.server.network.NetworkBuffer.*;
|
||||
|
||||
public record ServerDataPacket(@Nullable Component motd, @Nullable String iconBase64,
|
||||
boolean previewsChat, boolean enforcesSecureChat) implements ServerPacket {
|
||||
boolean enforcesSecureChat) implements ServerPacket {
|
||||
public ServerDataPacket(@NotNull NetworkBuffer reader) {
|
||||
this(reader.readOptional(COMPONENT), reader.readOptional(STRING),
|
||||
reader.read(BOOLEAN), reader.read(BOOLEAN));
|
||||
reader.read(BOOLEAN));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.writeOptional(COMPONENT, this.motd);
|
||||
writer.writeOptional(STRING, this.iconBase64);
|
||||
writer.write(BOOLEAN, previewsChat);
|
||||
writer.write(BOOLEAN, enforcesSecureChat);
|
||||
}
|
||||
|
||||
|
@ -1,24 +0,0 @@
|
||||
package net.minestom.server.network.packet.server.play;
|
||||
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.network.packet.server.ServerPacket;
|
||||
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static net.minestom.server.network.NetworkBuffer.BOOLEAN;
|
||||
|
||||
public record SetChatPreviewPacket(boolean enable) implements ServerPacket {
|
||||
public SetChatPreviewPacket(@NotNull NetworkBuffer reader) {
|
||||
this(reader.read(BOOLEAN));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.write(BOOLEAN, enable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return ServerPacketIdentifier.SET_DISPLAY_CHAT_PREVIEW;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user