Merge pull request #316 from thiccaxe/server-list-ping-update

Updated Server List Ping
This commit is contained in:
TheMode 2021-06-13 14:58:05 +02:00 committed by GitHub
commit 6cd3952fb5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 189 additions and 16 deletions

View File

@ -0,0 +1,128 @@
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.utils.time.TimeUnit;
import net.minestom.server.utils.time.UpdateOption;
import org.jetbrains.annotations.NotNull;
/**
* Called when a {@link PlayerConnection} sends a ping packet,
* usually after the status packet. Only used in versions since the netty rewrite; 1.7+
*
* @see ServerListPingEvent
*/
public class ClientPingServerEvent extends Event implements CancellableEvent {
private static final UpdateOption DEFAULT_DELAY = new UpdateOption(0, TimeUnit.MILLISECOND);
private final PlayerConnection connection;
private long payload;
private boolean cancelled = false;
private UpdateOption delay;
/**
* Creates a new client ping server event with 0 delay
*
* @param connection the player connection
* @param payload the payload the client sent
*/
public ClientPingServerEvent(@NotNull PlayerConnection connection, long payload) {
this.connection = connection;
this.payload = payload;
this.delay = DEFAULT_DELAY;
}
/**
* Creates a new client ping server event with 0 delay
*
* @param connection the player connection
* @param payload the payload the client sent
*/
public ClientPingServerEvent(@NotNull PlayerConnection connection, long payload, UpdateOption delay) {
this.connection = connection;
this.payload = payload;
this.delay = delay;
}
/**
* PlayerConnection of received packet. Note that the player has not joined the server
* at this time.
*
* @return the connection.
*/
public @NotNull PlayerConnection getConnection() {
return connection;
}
/**
* Payload of received packet. May be any number; vanilla uses a system dependant time value.
*
* @return the payload
*/
public long getPayload() {
return payload;
}
/**
* Sets the payload to respond with.
*
* Note: This should be the same as the client sent, however vanilla 1.17 seems to be OK with a different payload.
* @param payload the payload
*/
public void setPayload(long payload) {
this.payload = payload;
}
/**
* Gets the delay until minestom will send the ping response packet.
*
* @return the delay
*/
public @NotNull UpdateOption getDelay() {
return delay;
}
/**
* Adds to the delay until minestom will send the ping response packet.
*
* @param delay the delay
*/
public void addDelay(@NotNull UpdateOption delay) {
this.delay = new UpdateOption(this.delay.toMilliseconds() + delay.toMilliseconds(), TimeUnit.MILLISECOND);
}
/**
* Sets the delay until minestom will send the ping response packet.
*
* @param delay the delay
*/
public void setDelay(@NotNull UpdateOption delay) {
this.delay = delay;
}
/**
* Clears the delay until minestom will send the ping response packet.
*/
public void noDelay() {
this.delay = DEFAULT_DELAY;
}
@Override
public boolean isCancelled() {
return cancelled;
}
/**
* Cancelling this event will cause the 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

@ -1,5 +1,8 @@
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.ClientPingServerEvent;
import net.minestom.server.network.packet.client.ClientPreplayPacket;
import net.minestom.server.network.packet.server.status.PongPacket;
import net.minestom.server.network.player.PlayerConnection;
@ -15,9 +18,22 @@ public class PingPacket implements ClientPreplayPacket {
@Override
public void process(@NotNull PlayerConnection connection) {
PongPacket pongPacket = new PongPacket(number);
connection.sendPacket(pongPacket);
connection.disconnect();
final ClientPingServerEvent clientPingEvent = new ClientPingServerEvent(connection, number);
MinecraftServer.getGlobalEventHandler().callEvent(ClientPingServerEvent.class, clientPingEvent);
if (clientPingEvent.isCancelled()) {
connection.disconnect();
} else {
if (clientPingEvent.getDelay().toMilliseconds() == 0) {
connection.sendPacket(new PongPacket(clientPingEvent.getPayload()));
connection.disconnect();
} else {
MinecraftServer.getSchedulerManager().buildTask(() -> {
connection.sendPacket(new PongPacket(clientPingEvent.getPayload()));
connection.disconnect();
}).delay(clientPingEvent.getDelay()).schedule();
}
}
}
@Override

View File

@ -29,6 +29,7 @@ public class ResponseData {
private int online;
private Component description;
private String favicon;
private boolean playersHidden;
/**
* Constructs a new {@link ResponseData}.
@ -41,6 +42,7 @@ public class ResponseData {
this.maxPlayer = this.online + 1;
this.description = DEFAULT_DESCRIPTION;
this.favicon = "";
this.playersHidden = false;
}
/**
@ -294,6 +296,25 @@ public class ResponseData {
return this.entries;
}
/**
* Sets whether the players are hidden or not.
* In the vanilla client, `???` will be displayed where the online and maximum players would be.
*
* @param playersHidden if the players are hidden
*/
public void setPlayersHidden(boolean playersHidden) {
this.playersHidden = playersHidden;
}
/**
* Returns if the players are hidden or not.
*
* @return if the players are hidden
*/
public boolean arePlayersHidden() {
return playersHidden;
}
/**
* Converts the response data into a {@link JsonObject}.
*

View File

@ -109,22 +109,25 @@ public enum ServerListPingType {
versionObject.addProperty("name", data.getVersion());
versionObject.addProperty("protocol", data.getProtocol());
// players info
final JsonObject playersObject = new JsonObject();
playersObject.addProperty("max", data.getMaxPlayer());
playersObject.addProperty("online", data.getOnline());
JsonObject playersObject = null;
if (!data.arePlayersHidden()) {
// players info
playersObject = new JsonObject();
playersObject.addProperty("max", data.getMaxPlayer());
playersObject.addProperty("online", data.getOnline());
// individual players
final JsonArray sampleArray = new JsonArray();
for (NamedAndIdentified entry : data.getEntries()) {
JsonObject playerObject = new JsonObject();
playerObject.addProperty("name", SECTION.serialize(entry.getName()));
playerObject.addProperty("id", entry.getUuid().toString());
sampleArray.add(playerObject);
// individual players
final JsonArray sampleArray = new JsonArray();
for (NamedAndIdentified entry : data.getEntries()) {
JsonObject playerObject = new JsonObject();
playerObject.addProperty("name", SECTION.serialize(entry.getName()));
playerObject.addProperty("id", entry.getUuid().toString());
sampleArray.add(playerObject);
}
playersObject.add("sample", sampleArray);
}
playersObject.add("sample", sampleArray);
final JsonObject jsonObject = new JsonObject();
jsonObject.add("version", versionObject);
jsonObject.add("players", playersObject);

View File

@ -6,6 +6,7 @@ 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.Style;
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.format.TextDecoration;
import net.minestom.server.MinecraftServer;
@ -86,6 +87,9 @@ public class Main {
.append(Component.text(" VERSION: ", NamedTextColor.GRAY))
.append(Component.text(event.getConnection().getProtocolVersion()))));
}
responseData.addEntry(NamedAndIdentified.named(Component.text("Time", NamedTextColor.YELLOW)
.append(Component.text(": ", NamedTextColor.GRAY))
.append(Component.text(System.currentTimeMillis(), Style.style(TextDecoration.ITALIC)))));
// components will be converted the legacy section sign format so they are displayed in the client
responseData.addEntry(NamedAndIdentified.named(Component.text("You can use ").append(Component.text("styling too!", NamedTextColor.RED, TextDecoration.BOLD))));
@ -93,6 +97,7 @@ public class Main {
// the data will be automatically converted to the correct format on response, so you can do RGB and it'll be downsampled!
// on legacy versions, colors will be converted to the section format so it'll work there too
responseData.setDescription(Component.text("This is a Minestom Server", TextColor.color(0x66b3ff)));
//responseData.setPlayersHidden(true);
});
PlayerInit.init();