Merge branch 'master' into acquirable

This commit is contained in:
TheMode 2021-04-15 09:13:20 +02:00
commit 56cc33fcfa
12 changed files with 320 additions and 60 deletions

View File

@ -128,7 +128,7 @@ dependencies {
api 'io.netty:netty-codec:4.1.63.Final'
api 'io.netty:netty-transport-native-epoll:4.1.63.Final:linux-x86_64'
api 'io.netty:netty-transport-native-kqueue:4.1.63.Final:osx-x86_64'
api 'io.netty.incubator:netty-incubator-transport-native-io_uring:0.0.4.Final:linux-x86_64'
api 'io.netty.incubator:netty-incubator-transport-native-io_uring:0.0.5.Final:linux-x86_64'
// https://mvnrepository.com/artifact/org.apache.commons/commons-text
compile group: 'org.apache.commons', name: 'commons-text', version: '1.9'

View File

@ -626,7 +626,9 @@ public final class MinecraftServer {
* Gets the consumer executed to show server-list data.
*
* @return the response data consumer
* @deprecated listen to the {@link net.minestom.server.event.server.ServerListPingEvent} instead
*/
@Deprecated
public static ResponseDataConsumer getResponseDataConsumer() {
checkInitStatus(responseDataConsumer);
return responseDataConsumer;
@ -752,15 +754,30 @@ public final class MinecraftServer {
* @param port the server port
* @param responseDataConsumer the response data consumer, can be null
* @throws IllegalStateException if called before {@link #init()} or if the server is already running
* @deprecated use {@link #start(String, int)} and listen to the {@link net.minestom.server.event.server.ServerListPingEvent} event instead of ResponseDataConsumer
*/
@Deprecated
public void start(@NotNull String address, int port, @Nullable ResponseDataConsumer responseDataConsumer) {
MinecraftServer.responseDataConsumer = responseDataConsumer;
start(address, port);
}
/**
* Starts the server.
* <p>
* It should be called after {@link #init()} and probably your own initialization code.
*
* @param address the server address
* @param port the server port
* @throws IllegalStateException if called before {@link #init()} or if the server is already running
*/
public void start(@NotNull String address, int port) {
Check.stateCondition(!initialized, "#start can only be called after #init");
Check.stateCondition(started, "The server is already started");
MinecraftServer.started = true;
LOGGER.info("Starting Minestom server.");
MinecraftServer.responseDataConsumer = responseDataConsumer;
updateManager.start();
@ -788,17 +805,6 @@ public final class MinecraftServer {
MinestomTerminal.start();
}
/**
* Starts the server.
*
* @param address the server address
* @param port the server port
* @see #start(String, int, ResponseDataConsumer)
*/
public void start(@NotNull String address, int port) {
start(address, port, null);
}
/**
* Stops this server properly (saves if needed, kicking players, etc.)
*/

View File

@ -0,0 +1,61 @@
package net.minestom.server.event.server;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.event.Event;
import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.ping.ResponseData;
import org.jetbrains.annotations.NotNull;
/**
* Called when a {@link PlayerConnection} sends a status packet,
* usually to display information on the server list.
*/
public class ServerListPingEvent extends Event implements CancellableEvent {
private boolean cancelled = false;
private final ResponseData responseData;
private final PlayerConnection connection;
public ServerListPingEvent(ResponseData responseData, PlayerConnection connection) {
this.responseData = responseData;
this.connection = connection;
}
/**
* ResponseData being returned.
*
* @return the response data being returned
*/
public @NotNull ResponseData getResponseData() {
return responseData;
}
/**
* PlayerConnection of received packet.
*
* Note that the player has not joined the server at this time.
*
* @return the playerConnection.
*/
public @NotNull PlayerConnection getConnection() {
return connection;
}
@Override
public boolean isCancelled() {
return cancelled;
}
/**
* Cancelling this event will cause you server to appear offline in the vanilla server list.
*
* @param cancel true if the event should be cancelled, false otherwise
*/
@Override
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
}

View File

@ -81,7 +81,6 @@ public class HandshakePacket implements ClientPreplayPacket {
nettyPlayerConnection.UNSAFE_setBungeeUuid(playerUuid);
nettyPlayerConnection.UNSAFE_setBungeeSkin(playerSkin);
} else {
nettyPlayerConnection.sendPacket(new LoginDisconnectPacket(INVALID_BUNGEE_FORWARDING));
nettyPlayerConnection.disconnect();
@ -93,6 +92,11 @@ public class HandshakePacket implements ClientPreplayPacket {
}
}
if (connection instanceof NettyPlayerConnection) {
// Give to the connection the server info that the client used
((NettyPlayerConnection) connection).refreshServerInformation(serverAddress, serverPort, protocolVersion);
}
switch (nextState) {
case 1:
connection.setConnectionState(ConnectionState.STATUS);
@ -100,11 +104,6 @@ public class HandshakePacket implements ClientPreplayPacket {
case 2:
if (protocolVersion == MinecraftServer.PROTOCOL_VERSION) {
connection.setConnectionState(ConnectionState.LOGIN);
if (connection instanceof NettyPlayerConnection) {
// Give to the connection the server info that the client used
((NettyPlayerConnection) connection).refreshServerInformation(serverAddress, serverPort);
}
} else {
// Incorrect client version
connection.sendPacket(new LoginDisconnectPacket(INVALID_VERSION_TEXT));

View File

@ -2,6 +2,7 @@ package net.minestom.server.network.packet.client.status;
import net.kyori.adventure.text.Component;
import net.minestom.server.MinecraftServer;
import net.minestom.server.event.server.ServerListPingEvent;
import net.minestom.server.network.packet.client.ClientPreplayPacket;
import net.minestom.server.network.packet.server.handshake.ResponsePacket;
import net.minestom.server.network.player.PlayerConnection;
@ -29,10 +30,16 @@ public class StatusRequestPacket implements ClientPreplayPacket {
if (consumer != null)
consumer.accept(connection, responseData);
ResponsePacket responsePacket = new ResponsePacket();
responsePacket.jsonResponse = responseData.build().toString();
// Call event
ServerListPingEvent statusRequestEvent = new ServerListPingEvent(responseData, connection);
MinecraftServer.getGlobalEventHandler().callCancellableEvent(ServerListPingEvent.class, statusRequestEvent,
() -> {
ResponsePacket responsePacket = new ResponsePacket();
responsePacket.jsonResponse = responseData.build().toString();
connection.sendPacket(responsePacket);
});
connection.sendPacket(responsePacket);
}
@Override

View File

@ -51,6 +51,7 @@ public class NettyPlayerConnection extends PlayerConnection {
private String loginUsername;
private String serverAddress;
private int serverPort;
private int protocolVersion;
// Used for the login plugin request packet, to retrieve the channel from a message id,
// cleared once the player enters the play state
@ -228,6 +229,7 @@ public class NettyPlayerConnection extends PlayerConnection {
this.remoteAddress = remoteAddress;
}
@Override
public void disconnect() {
this.channel.close();
@ -266,8 +268,8 @@ public class NettyPlayerConnection extends PlayerConnection {
*
* @return the server address used
*/
@Nullable
public String getServerAddress() {
@Override
public @Nullable String getServerAddress() {
return serverAddress;
}
@ -278,10 +280,36 @@ public class NettyPlayerConnection extends PlayerConnection {
*
* @return the server port used
*/
@Override
public int getServerPort() {
return serverPort;
}
/**
* Gets the protocol version of a client.
*
* @return protocol version of client.
*/
@Override
public int getProtocolVersion() {
return protocolVersion;
}
/**
* Used in {@link net.minestom.server.network.packet.client.handshake.HandshakePacket} to change the internal fields.
*
* @param serverAddress the server address which the client used
* @param serverPort the server port which the client used
* @param protocolVersion the protocol version which the client used
*/
public void refreshServerInformation(@Nullable String serverAddress, int serverPort, int protocolVersion) {
this.serverAddress = serverAddress;
this.serverPort = serverPort;
this.protocolVersion = protocolVersion;
}
@Nullable
public UUID getBungeeUuid() {
return bungeeUuid;
@ -339,16 +367,6 @@ public class NettyPlayerConnection extends PlayerConnection {
}
}
/**
* Used in {@link net.minestom.server.network.packet.client.handshake.HandshakePacket} to change the internal fields.
*
* @param serverAddress the server address which the client used
* @param serverPort the server port which the client used
*/
public void refreshServerInformation(@Nullable String serverAddress, int serverPort) {
this.serverAddress = serverAddress;
this.serverPort = serverPort;
}
@NotNull
public ByteBuf getTickBuffer() {

View File

@ -117,6 +117,40 @@ public abstract class PlayerConnection {
@NotNull
public abstract SocketAddress getRemoteAddress();
/**
* Gets protocol version of client.
*
* @return the protocol version
*/
public int getProtocolVersion() {
return MinecraftServer.PROTOCOL_VERSION;
}
/**
* Gets the server address that the client used to connect.
* <p>
* WARNING: it is given by the client, it is possible for it to be wrong.
*
* @return the server address used
*/
public @Nullable String getServerAddress() {
return MinecraftServer.getNettyServer().getAddress();
}
/**
* Gets the server port that the client used to connect.
* <p>
* WARNING: it is given by the client, it is possible for it to be wrong.
*
* @return the server port used
*/
public int getServerPort() {
return MinecraftServer.getNettyServer().getPort();
}
/**
* Forcing the player to disconnect.
*/

View File

@ -15,8 +15,7 @@ import java.util.UUID;
/**
* Represents the data sent to the player when refreshing the server list.
*
* <p>Filled by {@link ResponseDataConsumer} and specified in {@link
* net.minestom.server.MinecraftServer#start(String, int, ResponseDataConsumer)}.
* <p>Edited by listening to the {@link net.minestom.server.event.server.ServerListPingEvent}.
*/
public class ResponseData {
private final List<PingPlayer> pingPlayers;
@ -55,6 +54,15 @@ public class ResponseData {
this.version = version;
}
/**
* Get the version name for the response.
*
* @return the version name for the response.
*/
public String getVersion() {
return version;
}
/**
* Sets the response protocol version.
*
@ -64,6 +72,15 @@ public class ResponseData {
this.protocol = protocol;
}
/**
* Get the response protocol version.
*
* @return the response protocol version.
*/
public int getProtocol() {
return protocol;
}
/**
* Sets the response maximum player count.
*
@ -73,6 +90,15 @@ public class ResponseData {
this.maxPlayer = maxPlayer;
}
/**
* Get the response maximum player count.
*
* @return the response maximum player count.
*/
public int getMaxPlayer() {
return maxPlayer;
}
/**
* Sets the response online count.
*
@ -82,6 +108,15 @@ public class ResponseData {
this.online = online;
}
/**
* Get the response online count.
*
* @return the response online count.
*/
public int getOnline() {
return online;
}
/**
* Adds some players to the response.
*
@ -109,9 +144,19 @@ public class ResponseData {
* @param uuid The unique identifier of the player.
*/
public void addPlayer(String name, UUID uuid) {
PingPlayer pingPlayer = new PingPlayer();
pingPlayer.name = name;
pingPlayer.uuid = uuid;
PingPlayer pingPlayer = PingPlayer.of(name, uuid);
this.pingPlayers.add(pingPlayer);
}
/**
* Adds a player to the response.
* <p>
* {@link UUID#randomUUID()} is used as the player's UUID.
*
* @param name The name of the player.
*/
public void addPlayer(String name) {
PingPlayer pingPlayer = PingPlayer.of(name, UUID.randomUUID());
this.pingPlayers.add(pingPlayer);
}
@ -123,6 +168,15 @@ public class ResponseData {
this.pingPlayers.clear();
}
/**
* Get the list of the response players.
*
* @return the list of the response players.
*/
public List<PingPlayer> getPlayers() {
return pingPlayers;
}
/**
* Sets the response description.
*
@ -143,8 +197,19 @@ public class ResponseData {
this.description = description;
}
/**
* Get the response description
*
* @return the response description
*/
public Component getDescription() {
return description;
}
/**
* Sets the response favicon.
* <p>
* MUST start with "data:image/png;base64,"
*
* @param favicon The favicon for the response data.
*/
@ -152,6 +217,16 @@ public class ResponseData {
this.favicon = favicon;
}
/**
* Get the response favicon.
*
* @return the response favicon.
*/
public String getFavicon() {
return favicon;
}
/**
* Converts the response data into a {@link JsonObject}.
*
@ -193,8 +268,26 @@ public class ResponseData {
/**
* Represents a player line in the server list hover.
*/
private static class PingPlayer {
private String name;
private UUID uuid;
public static class PingPlayer {
private static @NotNull PingPlayer of(@NotNull String name, @NotNull UUID uuid) {
return new PingPlayer(name, uuid);
}
private final String name;
private final UUID uuid;
private PingPlayer(@NotNull String name, @NotNull UUID uuid) {
this.name = name;
this.uuid = uuid;
}
public @NotNull String getName() {
return name;
}
public @NotNull UUID getUuid() {
return uuid;
}
}
}

View File

@ -7,15 +7,18 @@ import net.minestom.server.network.player.PlayerConnection;
*
* <p>Can be specified in {@link net.minestom.server.MinecraftServer#start(String, int,
* ResponseDataConsumer)}.
*
* @deprecated listen to the {@link net.minestom.server.event.server.ServerListPingEvent} instead
*/
@FunctionalInterface
@Deprecated
public interface ResponseDataConsumer {
/**
* A method to fill the data of the response.
*
* @param playerConnection The player connection to which the response should be sent.
* @param responseData The data for the response.
*/
void accept(PlayerConnection playerConnection, ResponseData responseData);
/**
* A method to fill the data of the response.
*
* @param playerConnection The player connection to which the response should be sent.
* @param responseData The data for the response.
*/
void accept(PlayerConnection playerConnection, ResponseData responseData);
}

View File

@ -17,11 +17,11 @@ public class MinestomTerminal {
private static final CommandManager COMMAND_MANAGER = MinecraftServer.getCommandManager();
private static final String PROMPT = "> ";
private static volatile Terminal terminal;
private static volatile boolean running = false;
@ApiStatus.Internal
public static void start() {
Terminal terminal = null;
try {
terminal = TerminalBuilder.terminal();
} catch (IOException e) {
@ -47,6 +47,13 @@ public class MinestomTerminal {
@ApiStatus.Internal
public static void stop() {
running = false;
if (terminal != null) {
try {
terminal.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

View File

@ -6,16 +6,21 @@ import demo.blocks.UpdatableBlockDemo;
import demo.commands.*;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextColor;
import net.minestom.server.MinecraftServer;
import net.minestom.server.command.CommandManager;
import net.minestom.server.event.server.ServerListPingEvent;
import net.minestom.server.extras.optifine.OptifineSupport;
import net.minestom.server.instance.block.BlockManager;
import net.minestom.server.instance.block.rule.vanilla.RedstonePlacementRule;
import net.minestom.server.ping.ResponseData;
import net.minestom.server.storage.StorageManager;
import net.minestom.server.storage.systems.FileStorageSystem;
import net.minestom.server.utils.time.TimeUnit;
import net.minestom.server.utils.time.UpdateOption;
import java.util.UUID;
public class Main {
@ -59,6 +64,41 @@ public class Main {
MinecraftServer.getSchedulerManager().buildShutdownTask(() -> System.out.println("Good night")).schedule();
MinecraftServer.getGlobalEventHandler().addEventCallback(ServerListPingEvent.class, event -> {
ResponseData responseData = event.getResponseData();
responseData.setMaxPlayer(0);
responseData.setOnline(MinecraftServer.getConnectionManager().getOnlinePlayers().size());
responseData.addPlayer("The first line is separated from the others", UUID.randomUUID());
responseData.addPlayer("Could be a name, or a message", UUID.randomUUID());
responseData.addPlayer("IP test: " + event.getConnection().getRemoteAddress().toString(), UUID.randomUUID());
responseData.addPlayer("Use " + (char)0x00a7 + "7section characters", UUID.randomUUID());
responseData.addPlayer((char)0x00a7 + "7" + (char)0x00a7 + "ofor formatting" + (char)0x00a7 + "r: (" + (char)0x00a7 + "6char" + (char)0x00a7 + "r)" + (char)0x00a7 + "90x00a7", UUID.randomUUID());
responseData.addPlayer("Connection Info:");
String ip = event.getConnection().getServerAddress();
responseData.addPlayer((char)0x00a7 + "8- " + (char)0x00a7 +"7IP: " + (char)0x00a7 + "e" + (ip != null ? ip : "???"));
responseData.addPlayer((char)0x00a7 + "8- " + (char)0x00a7 +"7PORT: " + (char)0x00a7 + "e" + event.getConnection().getServerPort());
responseData.addPlayer((char)0x00a7 + "8- " + (char)0x00a7 +"7VERSION: " + (char)0x00a7 + "e" + event.getConnection().getProtocolVersion());
// Check if client supports RGB color
if (event.getConnection().getProtocolVersion() >= 713) { // Snapshot 20w17a
responseData.setDescription(Component.text("You can do ")
.append(Component.text("RGB", TextColor.color(0x66b3ff)))
.append(Component.text(" color here")));
} else {
responseData.setDescription(Component.text("You can do ")
.append(Component.text("RGB", NamedTextColor.nearestTo(TextColor.color(0x66b3ff))))
.append(Component.text(" color here,"))
.append(Component.newline())
.append(Component.text("if you are on 1.16 or up"))
);
}
});
PlayerInit.init();
OptifineSupport.enable();
@ -68,7 +108,7 @@ public class Main {
//MojangAuth.init();
minecraftServer.start("0.0.0.0", 25565, PlayerInit.getResponseDataConsumer());
minecraftServer.start("0.0.0.0", 25565);
//Runtime.getRuntime().addShutdownHook(new Thread(MinecraftServer::stopCleanly));
}

View File

@ -4,6 +4,7 @@ import com.google.common.util.concurrent.AtomicDouble;
import demo.generator.ChunkGeneratorDemo;
import demo.generator.NoiseTestGenerator;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.TextColor;
import net.minestom.server.MinecraftServer;
import net.minestom.server.adventure.audience.Audiences;
import net.minestom.server.chat.ColoredText;
@ -292,14 +293,5 @@ public class PlayerInit {
});
}
public static ResponseDataConsumer getResponseDataConsumer() {
return (playerConnection, responseData) -> {
responseData.setMaxPlayer(0);
responseData.setOnline(MinecraftServer.getConnectionManager().getOnlinePlayers().size());
responseData.addPlayer("A name", UUID.randomUUID());
responseData.addPlayer("Could be some message", UUID.randomUUID());
responseData.setDescription("IP test: " + playerConnection.getRemoteAddress());
};
}
}