mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-16 13:11:40 +01:00
Support for velocity modern forwarding
This commit is contained in:
parent
247a328a09
commit
7db94f3a65
@ -54,6 +54,7 @@ import net.minestom.server.utils.validate.Check;
|
||||
import net.minestom.server.world.Difficulty;
|
||||
import net.minestom.server.world.DimensionTypeManager;
|
||||
import net.minestom.server.world.biomes.BiomeManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -227,15 +228,18 @@ public class MinecraftServer {
|
||||
*
|
||||
* @return the server brand name
|
||||
*/
|
||||
@NotNull
|
||||
public static String getBrandName() {
|
||||
return brandName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the server brand name, update the name to all connected players.
|
||||
* Changes the server brand name and send the change to all connected players.
|
||||
*
|
||||
* @param brandName the server brand name
|
||||
* @throws NullPointerException if {@code brandName} is null
|
||||
*/
|
||||
@NotNull
|
||||
public static void setBrandName(String brandName) {
|
||||
Check.notNull(brandName, "The brand name cannot be null");
|
||||
MinecraftServer.brandName = brandName;
|
||||
@ -267,6 +271,7 @@ public class MinecraftServer {
|
||||
*
|
||||
* @return the server difficulty
|
||||
*/
|
||||
@NotNull
|
||||
public static Difficulty getDifficulty() {
|
||||
return difficulty;
|
||||
}
|
||||
@ -276,7 +281,9 @@ public class MinecraftServer {
|
||||
*
|
||||
* @param difficulty the new server difficulty
|
||||
*/
|
||||
public static void setDifficulty(Difficulty difficulty) {
|
||||
@NotNull
|
||||
public static void setDifficulty(@NotNull Difficulty difficulty) {
|
||||
Check.notNull(difficulty, "The server difficulty cannot be null.");
|
||||
MinecraftServer.difficulty = difficulty;
|
||||
|
||||
// The difficulty packet
|
||||
@ -603,7 +610,7 @@ public class MinecraftServer {
|
||||
* @param responseDataConsumer the response data consumer, can be null
|
||||
* @throws IllegalStateException if called before {@link #init()} or if the server is already running
|
||||
*/
|
||||
public void start(String address, int port, ResponseDataConsumer responseDataConsumer) {
|
||||
public void start(@NotNull String address, int port, @Nullable ResponseDataConsumer responseDataConsumer) {
|
||||
Check.stateCondition(!initialized, "#start can only be called after #init");
|
||||
Check.stateCondition(started, "The server is already started");
|
||||
|
||||
@ -632,7 +639,7 @@ public class MinecraftServer {
|
||||
* @param port the server port
|
||||
* @see #start(String, int, ResponseDataConsumer)
|
||||
*/
|
||||
public void start(String address, int port) {
|
||||
public void start(@NotNull String address, int port) {
|
||||
start(address, port, null);
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
*/
|
||||
public class AdvancementManager {
|
||||
|
||||
// root identifier TO its advancement tab
|
||||
// root identifier = its advancement tab
|
||||
private final Map<String, AdvancementTab> advancementTabMap = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
|
@ -3,6 +3,8 @@ package net.minestom.server.advancements;
|
||||
import net.minestom.server.chat.ColoredText;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.item.Material;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Represents an {@link Advancement} which is the root of an {@link AdvancementTab}.
|
||||
@ -12,18 +14,18 @@ import net.minestom.server.item.Material;
|
||||
*/
|
||||
public class AdvancementRoot extends Advancement {
|
||||
|
||||
public AdvancementRoot(ColoredText title, ColoredText description,
|
||||
ItemStack icon, FrameType frameType,
|
||||
public AdvancementRoot(@NotNull ColoredText title, @NotNull ColoredText description,
|
||||
@NotNull ItemStack icon, @NotNull FrameType frameType,
|
||||
float x, float y,
|
||||
String background) {
|
||||
@Nullable String background) {
|
||||
super(title, description, icon, frameType, x, y);
|
||||
setBackground(background);
|
||||
}
|
||||
|
||||
public AdvancementRoot(ColoredText title, ColoredText description,
|
||||
Material icon, FrameType frameType,
|
||||
public AdvancementRoot(@NotNull ColoredText title, @NotNull ColoredText description,
|
||||
@NotNull Material icon, FrameType frameType,
|
||||
float x, float y,
|
||||
String background) {
|
||||
@Nullable String background) {
|
||||
super(title, description, icon, frameType, x, y);
|
||||
setBackground(background);
|
||||
}
|
||||
|
@ -34,7 +34,6 @@ import net.minestom.server.network.PlayerProvider;
|
||||
import net.minestom.server.network.packet.client.ClientPlayPacket;
|
||||
import net.minestom.server.network.packet.client.play.ClientChatMessagePacket;
|
||||
import net.minestom.server.network.packet.server.ServerPacket;
|
||||
import net.minestom.server.network.packet.server.login.JoinGamePacket;
|
||||
import net.minestom.server.network.packet.server.play.*;
|
||||
import net.minestom.server.network.player.NettyPlayerConnection;
|
||||
import net.minestom.server.network.player.PlayerConnection;
|
||||
|
@ -0,0 +1,78 @@
|
||||
package net.minestom.server.extras.velocity;
|
||||
|
||||
import net.minestom.server.utils.binary.BinaryReader;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
public class VelocityProxy {
|
||||
|
||||
public static final String PLAYER_INFO_CHANNEL = "velocity:player_info";
|
||||
|
||||
private static boolean enabled;
|
||||
private static byte[] secret;
|
||||
|
||||
/**
|
||||
* Enables velocity modern forwarding.
|
||||
*
|
||||
* @param secret the forwarding secret,
|
||||
* be sure to do not hardcode it in your code but to retrieve it from a file or anywhere else safe
|
||||
*/
|
||||
public static void enable(@NotNull String secret) {
|
||||
VelocityProxy.enabled = true;
|
||||
VelocityProxy.secret = secret.getBytes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets if velocity modern forwarding is enabled.
|
||||
*
|
||||
* @return true if velocity modern forwarding is enabled
|
||||
*/
|
||||
public static boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public static boolean checkIntegrity(@NotNull BinaryReader reader) {
|
||||
|
||||
if (!enabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final byte[] signature = reader.readBytes(32);
|
||||
|
||||
final byte[] data = reader.getRemainingBytes();
|
||||
|
||||
try {
|
||||
final Mac mac = Mac.getInstance("HmacSHA256");
|
||||
mac.init(new SecretKeySpec(secret, "HmacSHA256"));
|
||||
final byte[] mySignature = mac.doFinal(data);
|
||||
if (!MessageDigest.isEqual(signature, mySignature)) {
|
||||
return false;
|
||||
}
|
||||
} catch (final InvalidKeyException | NoSuchAlgorithmException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
|
||||
/*int version = buf.readVarInt();
|
||||
if (version != SUPPORTED_FORWARDING_VERSION) {
|
||||
throw new IllegalStateException("Unsupported forwarding version " + version + ", wanted " + SUPPORTED_FORWARDING_VERSION);
|
||||
}*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void readProperties(final BinaryReader reader) {
|
||||
final int properties = reader.readVarInt();
|
||||
for (int i1 = 0; i1 < properties; i1++) {
|
||||
final String name = reader.readSizedString();
|
||||
final String value = reader.readSizedString();
|
||||
final String signature = reader.readBoolean() ? reader.readSizedString() : null;
|
||||
System.out.println("test: " + name + " " + value + " " + signature);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -5,6 +5,7 @@ import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.entity.fakeplayer.FakePlayer;
|
||||
import net.minestom.server.listener.manager.PacketConsumer;
|
||||
import net.minestom.server.network.packet.client.login.LoginStartPacket;
|
||||
import net.minestom.server.network.packet.server.login.LoginSuccessPacket;
|
||||
import net.minestom.server.network.packet.server.play.ChatMessagePacket;
|
||||
import net.minestom.server.network.player.PlayerConnection;
|
||||
import net.minestom.server.utils.callback.validator.PlayerValidator;
|
||||
@ -269,4 +270,19 @@ public final class ConnectionManager {
|
||||
this.players.remove(player);
|
||||
this.connectionPlayerMap.remove(connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a {@link LoginSuccessPacket} and change the connection state to {@link ConnectionState#PLAY}.
|
||||
*
|
||||
* @param connection the player connection
|
||||
* @param uuid the uuid of the player
|
||||
* @param username the username of the player
|
||||
*/
|
||||
public void startPlayState(@NotNull PlayerConnection connection, @NotNull UUID uuid, @NotNull String username) {
|
||||
LoginSuccessPacket loginSuccessPacket = new LoginSuccessPacket(uuid, username);
|
||||
connection.sendPacket(loginSuccessPacket);
|
||||
|
||||
connection.setConnectionState(ConnectionState.PLAY);
|
||||
createPlayer(uuid, username, connection);
|
||||
}
|
||||
}
|
||||
|
@ -61,6 +61,7 @@ public class ClientChannel extends SimpleChannelInboundHandler<InboundPacket> {
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
||||
log.info(cause.getMessage());
|
||||
cause.printStackTrace();
|
||||
ctx.close();
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package net.minestom.server.network.packet.client.handler;
|
||||
|
||||
import net.minestom.server.network.packet.client.login.EncryptionResponsePacket;
|
||||
import net.minestom.server.network.packet.client.login.LoginPluginResponsePacket;
|
||||
import net.minestom.server.network.packet.client.login.LoginStartPacket;
|
||||
|
||||
public class ClientLoginPacketsHandler extends ClientPacketsHandler {
|
||||
@ -8,6 +9,7 @@ public class ClientLoginPacketsHandler extends ClientPacketsHandler {
|
||||
public ClientLoginPacketsHandler() {
|
||||
register(0, LoginStartPacket::new);
|
||||
register(1, EncryptionResponsePacket::new);
|
||||
register(2, LoginPluginResponsePacket::new);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import net.minestom.server.chat.ChatColor;
|
||||
import net.minestom.server.chat.ColoredText;
|
||||
import net.minestom.server.network.ConnectionState;
|
||||
import net.minestom.server.network.packet.client.ClientPreplayPacket;
|
||||
import net.minestom.server.network.packet.server.login.LoginDisconnect;
|
||||
import net.minestom.server.network.packet.server.login.LoginDisconnectPacket;
|
||||
import net.minestom.server.network.player.NettyPlayerConnection;
|
||||
import net.minestom.server.network.player.PlayerConnection;
|
||||
import net.minestom.server.utils.binary.BinaryReader;
|
||||
@ -47,7 +47,7 @@ public class HandshakePacket implements ClientPreplayPacket {
|
||||
}
|
||||
} else {
|
||||
// Incorrect client version
|
||||
connection.sendPacket(new LoginDisconnect(INVALID_VERSION_TEXT.toString()));
|
||||
connection.sendPacket(new LoginDisconnectPacket(INVALID_VERSION_TEXT.toString()));
|
||||
connection.disconnect();
|
||||
}
|
||||
break;
|
||||
|
@ -5,9 +5,7 @@ import com.mojang.authlib.exceptions.AuthenticationUnavailableException;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.data.type.array.ByteArrayData;
|
||||
import net.minestom.server.extras.mojangAuth.MojangCrypt;
|
||||
import net.minestom.server.network.ConnectionState;
|
||||
import net.minestom.server.network.packet.client.ClientPreplayPacket;
|
||||
import net.minestom.server.network.packet.server.login.LoginSuccessPacket;
|
||||
import net.minestom.server.network.player.NettyPlayerConnection;
|
||||
import net.minestom.server.network.player.PlayerConnection;
|
||||
import net.minestom.server.utils.binary.BinaryReader;
|
||||
@ -32,17 +30,18 @@ public class EncryptionResponsePacket implements ClientPreplayPacket {
|
||||
if (!(connection instanceof NettyPlayerConnection)) {
|
||||
return;
|
||||
}
|
||||
final NettyPlayerConnection nettyConnection = (NettyPlayerConnection) connection;
|
||||
|
||||
new Thread(THREAD_NAME + " #" + UNIQUE_THREAD_ID.incrementAndGet()) {
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
if (!Arrays.equals(connection.getNonce(), getNonce())) {
|
||||
MinecraftServer.getLOGGER().error(connection.getLoginUsername() + " tried to login with an invalid nonce!");
|
||||
final String loginUsername = nettyConnection.getLoginUsername();
|
||||
if (!Arrays.equals(nettyConnection.getNonce(), getNonce())) {
|
||||
MinecraftServer.getLOGGER().error(loginUsername + " tried to login with an invalid nonce!");
|
||||
return;
|
||||
}
|
||||
if (!connection.getLoginUsername().isEmpty()) {
|
||||
final NettyPlayerConnection nettyConnection = (NettyPlayerConnection) connection;
|
||||
if (!loginUsername.isEmpty()) {
|
||||
|
||||
final byte[] digestedData = MojangCrypt.digestData("", MinecraftServer.getKeyPair().getPublic(), getSecretKey());
|
||||
|
||||
@ -54,7 +53,7 @@ public class EncryptionResponsePacket implements ClientPreplayPacket {
|
||||
}
|
||||
|
||||
final String string3 = new BigInteger(digestedData).toString(16);
|
||||
final GameProfile gameProfile = MinecraftServer.getSessionService().hasJoinedServer(new GameProfile(null, connection.getLoginUsername()), string3);
|
||||
final GameProfile gameProfile = MinecraftServer.getSessionService().hasJoinedServer(new GameProfile(null, loginUsername), string3);
|
||||
nettyConnection.setEncryptionKey(getSecretKey());
|
||||
final int threshold = MinecraftServer.getCompressionThreshold();
|
||||
|
||||
@ -62,11 +61,8 @@ public class EncryptionResponsePacket implements ClientPreplayPacket {
|
||||
nettyConnection.enableCompression(threshold);
|
||||
}
|
||||
|
||||
LoginSuccessPacket loginSuccessPacket = new LoginSuccessPacket(gameProfile.getId(), gameProfile.getName());
|
||||
connection.sendPacket(loginSuccessPacket);
|
||||
MinecraftServer.getLOGGER().info("UUID of player {} is {}", connection.getLoginUsername(), gameProfile.getId());
|
||||
connection.setConnectionState(ConnectionState.PLAY);
|
||||
CONNECTION_MANAGER.createPlayer(gameProfile.getId(), gameProfile.getName(), connection);
|
||||
MinecraftServer.getLOGGER().info("UUID of player {} is {}", loginUsername, gameProfile.getId());
|
||||
CONNECTION_MANAGER.startPlayState(connection, gameProfile.getId(), gameProfile.getName());
|
||||
}
|
||||
} catch (AuthenticationUnavailableException e) {
|
||||
e.printStackTrace();
|
||||
|
@ -0,0 +1,69 @@
|
||||
package net.minestom.server.network.packet.client.login;
|
||||
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.chat.ChatColor;
|
||||
import net.minestom.server.chat.ColoredText;
|
||||
import net.minestom.server.extras.velocity.VelocityProxy;
|
||||
import net.minestom.server.network.ConnectionManager;
|
||||
import net.minestom.server.network.packet.client.ClientPreplayPacket;
|
||||
import net.minestom.server.network.packet.server.login.LoginDisconnectPacket;
|
||||
import net.minestom.server.network.player.NettyPlayerConnection;
|
||||
import net.minestom.server.network.player.PlayerConnection;
|
||||
import net.minestom.server.utils.binary.BinaryReader;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class LoginPluginResponsePacket implements ClientPreplayPacket {
|
||||
|
||||
private final static ConnectionManager CONNECTION_MANAGER = MinecraftServer.getConnectionManager();
|
||||
|
||||
public static final ColoredText INVALID_PROXY_RESPONSE = ColoredText.of(ChatColor.RED, "Invalid proxy response!");
|
||||
|
||||
public int messageId;
|
||||
public boolean successful;
|
||||
public byte[] data;
|
||||
|
||||
@Override
|
||||
public void process(@NotNull PlayerConnection connection) {
|
||||
|
||||
// Proxy support
|
||||
if (connection instanceof NettyPlayerConnection) {
|
||||
final NettyPlayerConnection nettyPlayerConnection = (NettyPlayerConnection) connection;
|
||||
final String channel = nettyPlayerConnection.getPluginRequestChannel(messageId);
|
||||
|
||||
if (channel != null) {
|
||||
boolean success = false;
|
||||
|
||||
// Velocity
|
||||
if (VelocityProxy.isEnabled() && channel.equals(VelocityProxy.PLAYER_INFO_CHANNEL)) {
|
||||
if (data != null) {
|
||||
BinaryReader reader = new BinaryReader(data);
|
||||
success = VelocityProxy.checkIntegrity(reader);
|
||||
}
|
||||
}
|
||||
|
||||
if (success) {
|
||||
// Proxy usage always mean that the server is in offline mode
|
||||
final String username = nettyPlayerConnection.getLoginUsername();
|
||||
final UUID playerUuid = CONNECTION_MANAGER.getPlayerConnectionUuid(connection, username);
|
||||
|
||||
CONNECTION_MANAGER.startPlayState(connection, playerUuid, username);
|
||||
} else {
|
||||
LoginDisconnectPacket disconnectPacket = new LoginDisconnectPacket(INVALID_PROXY_RESPONSE);
|
||||
nettyPlayerConnection.sendPacket(disconnectPacket);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(@NotNull BinaryReader reader) {
|
||||
this.messageId = reader.readVarInt();
|
||||
this.successful = reader.readBoolean();
|
||||
if (successful) {
|
||||
this.data = reader.getRemainingBytes();
|
||||
}
|
||||
}
|
||||
}
|
@ -4,39 +4,74 @@ import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.chat.ChatColor;
|
||||
import net.minestom.server.chat.ColoredText;
|
||||
import net.minestom.server.extras.MojangAuth;
|
||||
import net.minestom.server.extras.velocity.VelocityProxy;
|
||||
import net.minestom.server.network.ConnectionState;
|
||||
import net.minestom.server.network.packet.client.ClientPreplayPacket;
|
||||
import net.minestom.server.network.packet.server.login.EncryptionRequestPacket;
|
||||
import net.minestom.server.network.packet.server.login.LoginDisconnect;
|
||||
import net.minestom.server.network.packet.server.login.LoginSuccessPacket;
|
||||
import net.minestom.server.network.packet.server.login.LoginDisconnectPacket;
|
||||
import net.minestom.server.network.packet.server.login.LoginPluginRequestPacket;
|
||||
import net.minestom.server.network.player.NettyPlayerConnection;
|
||||
import net.minestom.server.network.player.PlayerConnection;
|
||||
import net.minestom.server.utils.binary.BinaryReader;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public class LoginStartPacket implements ClientPreplayPacket {
|
||||
|
||||
private static final String ALREADY_CONNECTED_JSON =
|
||||
ColoredText.of(ChatColor.RED, "You are already on this server").toString();
|
||||
private static final ColoredText ALREADY_CONNECTED_JSON = ColoredText.of(ChatColor.RED, "You are already on this server");
|
||||
|
||||
public String username;
|
||||
|
||||
@Override
|
||||
public void process(@NotNull PlayerConnection connection) {
|
||||
if (MojangAuth.isUsingMojangAuth()) {
|
||||
|
||||
// Cache the login username
|
||||
if (connection instanceof NettyPlayerConnection) {
|
||||
((NettyPlayerConnection) connection).UNSAFE_setLoginUsername(username);
|
||||
}
|
||||
|
||||
// Proxy support (only for netty clients)
|
||||
if (connection instanceof NettyPlayerConnection) {
|
||||
final NettyPlayerConnection nettyPlayerConnection = (NettyPlayerConnection) connection;
|
||||
|
||||
{
|
||||
// Velocity support
|
||||
if (VelocityProxy.isEnabled()) {
|
||||
|
||||
final int messageId = ThreadLocalRandom.current().nextInt();
|
||||
final String channel = VelocityProxy.PLAYER_INFO_CHANNEL;
|
||||
|
||||
nettyPlayerConnection.addPluginRequestEntry(messageId, channel);
|
||||
|
||||
LoginPluginRequestPacket loginPluginRequestPacket = new LoginPluginRequestPacket();
|
||||
loginPluginRequestPacket.messageId = messageId;
|
||||
loginPluginRequestPacket.channel = channel;
|
||||
loginPluginRequestPacket.data = null;
|
||||
connection.sendPacket(loginPluginRequestPacket);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (MojangAuth.isUsingMojangAuth() && connection instanceof NettyPlayerConnection) {
|
||||
// Mojang auth
|
||||
if (CONNECTION_MANAGER.getPlayer(username) != null) {
|
||||
connection.sendPacket(new LoginDisconnect(ALREADY_CONNECTED_JSON));
|
||||
connection.sendPacket(new LoginDisconnectPacket(ALREADY_CONNECTED_JSON));
|
||||
connection.disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
connection.setConnectionState(ConnectionState.LOGIN);
|
||||
connection.setLoginUsername(username);
|
||||
EncryptionRequestPacket encryptionRequestPacket = new EncryptionRequestPacket(connection);
|
||||
connection.sendPacket(encryptionRequestPacket);
|
||||
final NettyPlayerConnection nettyPlayerConnection = (NettyPlayerConnection) connection;
|
||||
|
||||
nettyPlayerConnection.setConnectionState(ConnectionState.LOGIN);
|
||||
EncryptionRequestPacket encryptionRequestPacket = new EncryptionRequestPacket(nettyPlayerConnection);
|
||||
nettyPlayerConnection.sendPacket(encryptionRequestPacket);
|
||||
} else {
|
||||
// Offline
|
||||
final UUID playerUuid = CONNECTION_MANAGER.getPlayerConnectionUuid(connection, username);
|
||||
|
||||
final int threshold = MinecraftServer.getCompressionThreshold();
|
||||
@ -45,11 +80,7 @@ public class LoginStartPacket implements ClientPreplayPacket {
|
||||
((NettyPlayerConnection) connection).enableCompression(threshold);
|
||||
}
|
||||
|
||||
LoginSuccessPacket successPacket = new LoginSuccessPacket(playerUuid, username);
|
||||
connection.sendPacket(successPacket);
|
||||
|
||||
connection.setConnectionState(ConnectionState.PLAY);
|
||||
CONNECTION_MANAGER.createPlayer(playerUuid, username, connection);
|
||||
CONNECTION_MANAGER.startPlayState(connection, playerUuid, username);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,12 @@ package net.minestom.server.network.packet.server;
|
||||
|
||||
public class ServerPacketIdentifier {
|
||||
|
||||
public static final int LOGIN_DISCONNECT = 0x00;
|
||||
public static final int LOGIN_ENCRYPTION_REQUEST = 0x01;
|
||||
public static final int LOGIN_SUCCESS = 0x02;
|
||||
public static final int LOGIN_SET_COMPRESSION = 0x03;
|
||||
public static final int LOGIN_PLUGIN_REQUEST = 0x04;
|
||||
|
||||
public static final int SPAWN_ENTITY = 0x00;
|
||||
public static final int SPAWN_EXPERIENCE_ORB = 0x01;
|
||||
public static final int SPAWN_LIVING_ENTITY = 0x02;
|
||||
|
@ -3,7 +3,8 @@ package net.minestom.server.network.packet.server.login;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.data.type.array.ByteArrayData;
|
||||
import net.minestom.server.network.packet.server.ServerPacket;
|
||||
import net.minestom.server.network.player.PlayerConnection;
|
||||
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
|
||||
import net.minestom.server.network.player.NettyPlayerConnection;
|
||||
import net.minestom.server.utils.binary.BinaryWriter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@ -14,7 +15,7 @@ public class EncryptionRequestPacket implements ServerPacket {
|
||||
public byte[] publicKey;
|
||||
public byte[] nonce = new byte[4];
|
||||
|
||||
public EncryptionRequestPacket(PlayerConnection connection) {
|
||||
public EncryptionRequestPacket(NettyPlayerConnection connection) {
|
||||
ThreadLocalRandom.current().nextBytes(nonce);
|
||||
connection.setNonce(nonce);
|
||||
}
|
||||
@ -29,6 +30,6 @@ public class EncryptionRequestPacket implements ServerPacket {
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return 0x01;
|
||||
return ServerPacketIdentifier.LOGIN_ENCRYPTION_REQUEST;
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +0,0 @@
|
||||
package net.minestom.server.network.packet.server.login;
|
||||
|
||||
import net.minestom.server.network.packet.server.ServerPacket;
|
||||
import net.minestom.server.utils.binary.BinaryWriter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class LoginDisconnect implements ServerPacket {
|
||||
|
||||
private String kickMessage;
|
||||
|
||||
public LoginDisconnect(String kickMessage) {
|
||||
this.kickMessage = kickMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull BinaryWriter writer) {
|
||||
writer.writeSizedString(kickMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package net.minestom.server.network.packet.server.login;
|
||||
|
||||
import net.minestom.server.chat.JsonMessage;
|
||||
import net.minestom.server.network.packet.server.ServerPacket;
|
||||
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
|
||||
import net.minestom.server.utils.binary.BinaryWriter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class LoginDisconnectPacket implements ServerPacket {
|
||||
|
||||
private String kickMessage; // JSON text
|
||||
|
||||
public LoginDisconnectPacket(@NotNull String kickMessage) {
|
||||
this.kickMessage = kickMessage;
|
||||
}
|
||||
|
||||
public LoginDisconnectPacket(@NotNull JsonMessage jsonKickMessage) {
|
||||
this(jsonKickMessage.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull BinaryWriter writer) {
|
||||
writer.writeSizedString(kickMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return ServerPacketIdentifier.LOGIN_DISCONNECT;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package net.minestom.server.network.packet.server.login;
|
||||
|
||||
import net.minestom.server.network.packet.server.ServerPacket;
|
||||
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
|
||||
import net.minestom.server.utils.binary.BinaryWriter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class LoginPluginRequestPacket implements ServerPacket {
|
||||
|
||||
public int messageId;
|
||||
public String channel;
|
||||
public byte[] data;
|
||||
|
||||
@Override
|
||||
public void write(@NotNull BinaryWriter writer) {
|
||||
writer.writeVarInt(messageId);
|
||||
writer.writeSizedString(channel);
|
||||
if (data != null && data.length > 0) {
|
||||
writer.writeBytes(data);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return ServerPacketIdentifier.LOGIN_PLUGIN_REQUEST;
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package net.minestom.server.network.packet.server.login;
|
||||
|
||||
import net.minestom.server.network.packet.server.ServerPacket;
|
||||
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
|
||||
import net.minestom.server.utils.binary.BinaryWriter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@ -24,6 +25,6 @@ public class LoginSuccessPacket implements ServerPacket {
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return 0x02;
|
||||
return ServerPacketIdentifier.LOGIN_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package net.minestom.server.network.packet.server.login;
|
||||
|
||||
import net.minestom.server.network.packet.server.ServerPacket;
|
||||
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
|
||||
import net.minestom.server.utils.binary.BinaryWriter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@ -19,6 +20,6 @@ public class SetCompressionPacket implements ServerPacket {
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return 0x03;
|
||||
return ServerPacketIdentifier.LOGIN_SET_COMPRESSION;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package net.minestom.server.network.packet.server.login;
|
||||
package net.minestom.server.network.packet.server.play;
|
||||
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.entity.GameMode;
|
@ -29,6 +29,7 @@ public class PluginMessagePacket implements ServerPacket {
|
||||
*
|
||||
* @return the current brand name packet
|
||||
*/
|
||||
@NotNull
|
||||
public static PluginMessagePacket getBrandPacket() {
|
||||
PluginMessagePacket brandMessage = new PluginMessagePacket();
|
||||
brandMessage.channel = "minecraft:brand";
|
||||
|
@ -4,9 +4,11 @@ import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.minestom.server.extras.mojangAuth.Decrypter;
|
||||
import net.minestom.server.extras.mojangAuth.Encrypter;
|
||||
import net.minestom.server.extras.mojangAuth.MojangCrypt;
|
||||
import net.minestom.server.network.ConnectionState;
|
||||
import net.minestom.server.network.netty.codec.PacketCompressor;
|
||||
import net.minestom.server.network.packet.server.ServerPacket;
|
||||
import net.minestom.server.network.packet.server.login.SetCompressionPacket;
|
||||
@ -16,6 +18,8 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Represents a networking connection with Netty.
|
||||
@ -30,9 +34,19 @@ public class NettyPlayerConnection extends PlayerConnection {
|
||||
@Getter
|
||||
private boolean compressed = false;
|
||||
|
||||
//Could be null. Only used for Mojang Auth
|
||||
@Getter
|
||||
@Setter
|
||||
private byte[] nonce = new byte[4];
|
||||
|
||||
private String loginUsername;
|
||||
private String serverAddress;
|
||||
private int serverPort;
|
||||
|
||||
// Used for the login plugin request packet, to retrive the channel from a message id,
|
||||
// cleared once the player enters the play state
|
||||
private Map<Integer, String> pluginRequestMap = new ConcurrentHashMap<>();
|
||||
|
||||
public NettyPlayerConnection(@NotNull SocketChannel channel) {
|
||||
super();
|
||||
this.channel = channel;
|
||||
@ -114,6 +128,27 @@ public class NettyPlayerConnection extends PlayerConnection {
|
||||
return channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the username received from the client during connection.
|
||||
* <p>
|
||||
* This value has not been checked and could be anything.
|
||||
*
|
||||
* @return the username given by the client, unchecked
|
||||
*/
|
||||
@Nullable
|
||||
public String getLoginUsername() {
|
||||
return loginUsername;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the internal login username field
|
||||
*
|
||||
* @param loginUsername the new login username field
|
||||
*/
|
||||
public void UNSAFE_setLoginUsername(@NotNull String loginUsername) {
|
||||
this.loginUsername = loginUsername;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the server address that the client used to connect.
|
||||
* <p>
|
||||
@ -137,6 +172,45 @@ public class NettyPlayerConnection extends PlayerConnection {
|
||||
return serverPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an entry to the plugin request map.
|
||||
* <p>
|
||||
* Only working if {@link #getConnectionState()} is {@link net.minestom.server.network.ConnectionState#LOGIN}.
|
||||
*
|
||||
* @param messageId the message id
|
||||
* @param channel the packet channel
|
||||
* @throws IllegalStateException if a messageId with the value {@code messageId} already exists for this connection
|
||||
*/
|
||||
public void addPluginRequestEntry(int messageId, @NotNull String channel) {
|
||||
if (!getConnectionState().equals(ConnectionState.LOGIN)) {
|
||||
return;
|
||||
}
|
||||
Check.stateCondition(pluginRequestMap.containsKey(messageId), "You cannot have two messageId with the same value");
|
||||
this.pluginRequestMap.put(messageId, channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a request channel from a message id, previously cached using {@link #addPluginRequestEntry(int, String)}.
|
||||
* <p>
|
||||
* Be aware that the internal map is cleared once the player enters the play state.
|
||||
*
|
||||
* @param messageId the message id
|
||||
* @return the channel linked to the message id, null if not found
|
||||
*/
|
||||
@Nullable
|
||||
public String getPluginRequestChannel(int messageId) {
|
||||
return pluginRequestMap.get(messageId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setConnectionState(@NotNull ConnectionState connectionState) {
|
||||
super.setConnectionState(connectionState);
|
||||
// Clear the plugin request map (since it is not used anymore)
|
||||
if (connectionState.equals(ConnectionState.PLAY)) {
|
||||
this.pluginRequestMap.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used in {@link net.minestom.server.network.packet.client.handshake.HandshakePacket} to change the internal fields.
|
||||
*
|
||||
|
@ -2,14 +2,13 @@ package net.minestom.server.network.player;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.chat.ChatColor;
|
||||
import net.minestom.server.chat.ColoredText;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.network.ConnectionState;
|
||||
import net.minestom.server.network.packet.server.ServerPacket;
|
||||
import net.minestom.server.network.packet.server.login.LoginDisconnect;
|
||||
import net.minestom.server.network.packet.server.login.LoginDisconnectPacket;
|
||||
import net.minestom.server.network.packet.server.play.DisconnectPacket;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@ -23,14 +22,6 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
public abstract class PlayerConnection {
|
||||
|
||||
private Player player;
|
||||
//Could be null. Only used for Mojang Auth
|
||||
@Getter
|
||||
@Setter
|
||||
private String loginUsername;
|
||||
//Could be null. Only used for Mojang Auth
|
||||
@Getter
|
||||
@Setter
|
||||
private byte[] nonce = new byte[4];
|
||||
private ConnectionState connectionState;
|
||||
private boolean online;
|
||||
|
||||
@ -64,7 +55,7 @@ public abstract class PlayerConnection {
|
||||
if (count > MinecraftServer.getRateLimit()) {
|
||||
// Sent too many packets
|
||||
if (connectionState == ConnectionState.LOGIN) {
|
||||
sendPacket(new LoginDisconnect("Too Many Packets"));
|
||||
sendPacket(new LoginDisconnectPacket("Too Many Packets"));
|
||||
} else {
|
||||
DisconnectPacket disconnectPacket = new DisconnectPacket();
|
||||
disconnectPacket.message = rateLimitKickMessage;
|
||||
|
@ -186,6 +186,8 @@ public class BinaryWriter extends OutputStream {
|
||||
|
||||
/**
|
||||
* Writes a byte array.
|
||||
* <p>
|
||||
* WARNING: it doesn't write the length of {@code bytes}.
|
||||
*
|
||||
* @param bytes the byte array to write
|
||||
*/
|
||||
|
@ -3,6 +3,7 @@ package demo;
|
||||
import demo.blocks.BurningTorchBlock;
|
||||
import demo.blocks.StoneBlock;
|
||||
import demo.blocks.UpdatableBlockDemo;
|
||||
import demo.commands.GamemodeCommand;
|
||||
import demo.commands.TestCommand;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.command.CommandManager;
|
||||
@ -28,6 +29,7 @@ public class Main {
|
||||
|
||||
CommandManager commandManager = MinecraftServer.getCommandManager();
|
||||
commandManager.register(new TestCommand());
|
||||
commandManager.register(new GamemodeCommand());
|
||||
/*commandManager.register(new EntitySelectorCommand());
|
||||
commandManager.register(new HealthCommand());
|
||||
commandManager.register(new SimpleCommand());
|
||||
@ -48,6 +50,8 @@ public class Main {
|
||||
|
||||
PlayerInit.init();
|
||||
|
||||
//VelocityProxy.enable("rBeJJ79W4MVU");
|
||||
|
||||
//MojangAuth.init();
|
||||
|
||||
minecraftServer.start("0.0.0.0", 25565, PlayerInit.getResponseDataConsumer());
|
||||
|
@ -5,6 +5,8 @@ import demo.generator.NoiseTestGenerator;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.benchmark.BenchmarkManager;
|
||||
import net.minestom.server.chat.ColoredText;
|
||||
import net.minestom.server.data.Data;
|
||||
import net.minestom.server.data.NbtDataImpl;
|
||||
import net.minestom.server.entity.*;
|
||||
import net.minestom.server.entity.damage.DamageType;
|
||||
import net.minestom.server.entity.type.monster.EntityZombie;
|
||||
@ -172,7 +174,11 @@ public class PlayerInit {
|
||||
}
|
||||
|
||||
ItemStack itemStack = new ItemStack(Material.DIAMOND_PICKAXE, (byte) 64);
|
||||
Data data = new NbtDataImpl();
|
||||
data.set("test", 51);
|
||||
itemStack.setData(data);
|
||||
player.getInventory().addItemStack(itemStack);
|
||||
System.out.println("test " + data.get("test"));
|
||||
|
||||
//player.getInventory().addItemStack(new ItemStack(Material.STONE, (byte)64));
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user