Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,29 @@ public interface PlayerCommonConnection extends WritablePlayerCookieConnection,
* @return the client option value of the player
*/
<T> T getClientOption(ClientOption<T> type);

/**
* Gets the player's estimated ping in milliseconds.
* <p>
* In Vanilla this value represents a weighted average of the response time
* to application layer ping packets sent. This value does not represent the
* network round trip time and as such may have less granularity and be
* impacted by other sources. For these reasons it <b>should not</b> be used
* for anti-cheat purposes. Its recommended use is only as a
* <b>qualitative</b> indicator of connection quality (Vanilla uses it for
* this purpose in the tab list).
*
* @return player ping
*/
int getPing();

/**
* Gets the player's most recent measured ping.
* <p>
* This differs from {@link #getPing()} as it represents an average of ping over time,
* whereas this represents simply the most recent ping.
*
* @return player's most recent ping
*/
int getLastPing();
}
1 change: 1 addition & 0 deletions paper-api/src/main/java/org/bukkit/entity/Player.java
Original file line number Diff line number Diff line change
Expand Up @@ -3359,6 +3359,7 @@ default <T> void spawnParticle(Particle particle, Location location, int count,
*/
java.util.Locale locale();
// Paper end

/**
* Gets the player's estimated ping in milliseconds.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,10 @@ index 21d50675bfe90c2276890779eb23de58ac915b9a..7be34e37562875313b8e43357921b5fe
}
}
diff --git a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
index 079ab378920c0e52ef4e42ef20b37bd389f40870..b8a4b4cc02a2fc6b70f4b840796eed501aad6239 100644
index 0fd13e18902991d7ad4cbed0222d91cb71229d7a..a3768425e63722c8b0a99579a680f4cd9a9055c2 100644
--- a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
@@ -39,12 +39,13 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
@@ -39,13 +39,14 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
protected final MinecraftServer server;
public final Connection connection; // Paper
private final boolean transferred;
Expand All @@ -117,33 +117,36 @@ index 079ab378920c0e52ef4e42ef20b37bd389f40870..b8a4b4cc02a2fc6b70f4b840796eed50
private boolean closed = false;
- private int latency;
+ private volatile int latency; // Paper - improve keepalives - make volatile
public int lastLatency; // Paper - Keep most recent latency in millis
+ private final io.papermc.paper.util.KeepAlive keepAlive; // Paper - improve keepalives
private volatile boolean suspendFlushingOnServerThread = false;
// CraftBukkit start
public final org.bukkit.craftbukkit.CraftServer cserver;
@@ -61,13 +62,14 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
@@ -62,7 +63,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
public ServerCommonPacketListenerImpl(MinecraftServer server, Connection connection, CommonListenerCookie cookie) {
this.server = server;
this.connection = connection;
- this.keepAliveTime = Util.getMillis();
+ //this.keepAliveTime = Util.getMillis(); // Paper - improve keepalives
this.latency = cookie.latency();
this.lastLatency = this.latency; // Paper - Keep most recent latency in millis
this.transferred = cookie.transferred();
// Paper start
@@ -70,6 +71,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
this.playerBrand = cookie.brandName();
this.cserver = server.server;
this.pluginMessagerChannels = cookie.channels();
+ this.keepAlive = cookie.keepAlive();
// Paper end
}

@@ -100,13 +102,41 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
@@ -102,14 +104,42 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack

@Override
public void handleKeepAlive(ServerboundKeepAlivePacket packet) {
- if (this.keepAlivePending && packet.getId() == this.keepAliveChallenge) {
- int i = (int)(Util.getMillis() - this.keepAliveTime);
- this.latency = (this.latency * 3 + i) / 4;
- this.lastLatency = i; // Paper - Keep most recent latency in millis
- this.keepAlivePending = false;
- } else if (!this.isSingleplayerOwner()) {
- this.disconnectAsync(TIMEOUT_DISCONNECTION_MESSAGE, io.papermc.paper.connection.DisconnectionReason.TIMEOUT); // Paper - add proper async disconnect
Expand All @@ -159,6 +162,7 @@ index 079ab378920c0e52ef4e42ef20b37bd389f40870..b8a4b4cc02a2fc6b70f4b840796eed50
+ this.keepAlive.pingCalculator5s.update(response);
+
+ this.latency = this.keepAlive.pingCalculator5s.getAvgLatencyMS();
+ this.lastLatency = (int) java.util.concurrent.TimeUnit.NANOSECONDS.toMillis(response.latencyNS()); // Paper - Keep most recent latency in millis
+ return;
+ }
+
Expand All @@ -185,7 +189,7 @@ index 079ab378920c0e52ef4e42ef20b37bd389f40870..b8a4b4cc02a2fc6b70f4b840796eed50
}

@Override
@@ -233,20 +263,23 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
@@ -236,20 +266,23 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
protected void keepConnectionAlive() {
Profiler.get().push("keepAlive");
long millis = Util.getMillis();
Expand Down Expand Up @@ -223,7 +227,7 @@ index 079ab378920c0e52ef4e42ef20b37bd389f40870..b8a4b4cc02a2fc6b70f4b840796eed50
}
}

@@ -427,6 +460,6 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
@@ -430,6 +463,6 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
}

protected CommonListenerCookie createCookie(ClientInformation clientInformation) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@
private final boolean transferred;
private long keepAliveTime;
private boolean keepAlivePending;
@@ -46,6 +_,17 @@
@@ -45,15 +_,39 @@
private long closedListenerTime;
private boolean closed = false;
private int latency;
+ public int lastLatency; // Paper - Keep most recent latency in millis
private volatile boolean suspendFlushingOnServerThread = false;
+ // CraftBukkit start
+ public final org.bukkit.craftbukkit.CraftServer cserver;
Expand All @@ -27,9 +29,10 @@

public ServerCommonPacketListenerImpl(MinecraftServer server, Connection connection, CommonListenerCookie cookie) {
this.server = server;
@@ -53,7 +_,18 @@
this.connection = connection;
this.keepAliveTime = Util.getMillis();
this.latency = cookie.latency();
+ this.lastLatency = this.latency; // Paper - Keep most recent latency in millis
this.transferred = cookie.transferred();
+ // Paper start
+ this.playerBrand = cookie.brandName();
Expand All @@ -46,8 +49,11 @@

private void close() {
if (!this.closed) {
@@ -83,7 +_,7 @@
@@ -81,9 +_,10 @@
if (this.keepAlivePending && packet.getId() == this.keepAliveChallenge) {
int i = (int)(Util.getMillis() - this.keepAliveTime);
this.latency = (this.latency * 3 + i) / 4;
+ this.lastLatency = i; // Paper - Keep most recent latency in millis
this.keepAlivePending = false;
} else if (!this.isSingleplayerOwner()) {
- this.disconnect(TIMEOUT_DISCONNECTION_MESSAGE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,26 @@

public abstract class PaperCommonConnection<T extends ServerCommonPacketListenerImpl> extends ReadablePlayerCookieConnectionImpl implements PlayerCommonConnection {

protected final T handle;
protected final T packetListener;

public PaperCommonConnection(final T serverConfigurationPacketListenerImpl) {
super(serverConfigurationPacketListenerImpl.connection);
this.handle = serverConfigurationPacketListenerImpl;
public PaperCommonConnection(final T packetListener) {
super(packetListener.connection);
this.packetListener = packetListener;
}

@Override
public void sendReportDetails(final Map<String, String> details) {
this.handle.send(new ClientboundCustomReportDetailsPacket(details));
this.packetListener.send(new ClientboundCustomReportDetailsPacket(details));
}

@Override
public void sendLinks(final ServerLinks links) {
this.handle.send(new ClientboundServerLinksPacket(((CraftServerLinks) links).getServerLinks().untrust()));
this.packetListener.send(new ClientboundServerLinksPacket(((CraftServerLinks) links).getServerLinks().untrust()));
}

@Override
public void transfer(final String host, final int port) {
this.handle.send(new ClientboundTransferPacket(host, port));
this.packetListener.send(new ClientboundTransferPacket(host, port));
}

@Override
Expand Down Expand Up @@ -72,32 +72,32 @@ public <T> T getClientOption(ClientOption<T> type) {

@Override
public void disconnect(final Component component) {
this.handle.disconnect(PaperAdventure.asVanilla(component), DisconnectionReason.UNKNOWN);
this.packetListener.disconnect(PaperAdventure.asVanilla(component), DisconnectionReason.UNKNOWN);
}

@Override
public boolean isTransferred() {
return this.handle.isTransferred();
return this.packetListener.isTransferred();
}

@Override
public SocketAddress getAddress() {
return this.handle.connection.channel.remoteAddress();
return this.packetListener.connection.channel.remoteAddress();
}

@Override
public InetSocketAddress getClientAddress() {
return (InetSocketAddress) this.handle.connection.getRemoteAddress();
return (InetSocketAddress) this.packetListener.connection.getRemoteAddress();
}

@Override
public @Nullable InetSocketAddress getVirtualHost() {
return this.handle.connection.virtualHost;
return this.packetListener.connection.virtualHost;
}

@Override
public @Nullable InetSocketAddress getHAProxyAddress() {
return this.handle.connection.haProxyAddress instanceof final InetSocketAddress inetSocketAddress ? inetSocketAddress : null;
return this.packetListener.connection.haProxyAddress instanceof final InetSocketAddress inetSocketAddress ? inetSocketAddress : null;
}

@Override
Expand All @@ -107,7 +107,17 @@ public void storeCookie(final NamespacedKey key, final byte[] value) {
Preconditions.checkArgument(value.length <= 5120, "Cookie value too large, must be smaller than 5120 bytes");
Preconditions.checkState(this.canStoreCookie(), "Can only store cookie in CONFIGURATION or PLAY protocol.");

this.handle.send(new ClientboundStoreCookiePacket(CraftNamespacedKey.toMinecraft(key), value));
this.packetListener.send(new ClientboundStoreCookiePacket(CraftNamespacedKey.toMinecraft(key), value));
}

@Override
public int getPing() {
return this.packetListener.latency();
}

@Override
public int getLastPing() {
return this.packetListener.lastLatency;
}

public abstract ClientInformation getClientInformation();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public PaperPlayerConfigurationConnection(final ServerConfigurationPacketListene

@Override
public ClientInformation getClientInformation() {
return this.handle.clientInformation;
return this.packetListener.clientInformation;
}

@Override
Expand All @@ -61,39 +61,39 @@ public void sendResourcePacks(final ResourcePackRequest request) {
final ResourcePackInfo pack = iter.next();
packs.add(new ClientboundResourcePackPushPacket(pack.id(), pack.uri().toASCIIString(), pack.hash(), request.required(), iter.hasNext() ? Optional.empty() : Optional.ofNullable(prompt)));
if (request.callback() != ResourcePackCallback.noOp()) {
this.handle.packCallbacks.put(pack.id(), request.callback()); // just override if there is a previously existing callback
this.packetListener.packCallbacks.put(pack.id(), request.callback()); // just override if there is a previously existing callback
}
}
packs.forEach(this.handle::send);
packs.forEach(this.packetListener::send);
}

@Override
public void removeResourcePacks(final UUID id, final UUID... others) {
net.kyori.adventure.util.MonkeyBars.nonEmptyArrayToList(pack -> new ClientboundResourcePackPopPacket(Optional.of(pack)), id, others).forEach(this.handle::send);
net.kyori.adventure.util.MonkeyBars.nonEmptyArrayToList(pack -> new ClientboundResourcePackPopPacket(Optional.of(pack)), id, others).forEach(this.packetListener::send);
}

@Override
public void clearResourcePacks() {
this.handle.send(new ClientboundResourcePackPopPacket(Optional.empty()));
this.packetListener.send(new ClientboundResourcePackPopPacket(Optional.empty()));
}

@Override
public void showDialog(final DialogLike dialog) {
this.handle.send(new ClientboundShowDialogPacket(PaperDialog.bukkitToMinecraftHolder((Dialog) dialog)));
this.packetListener.send(new ClientboundShowDialogPacket(PaperDialog.bukkitToMinecraftHolder((Dialog) dialog)));
}

@Override
public void closeDialog() {
this.handle.send(ClientboundClearDialogPacket.INSTANCE);
this.packetListener.send(ClientboundClearDialogPacket.INSTANCE);
}

@Override
public Pointers pointers() {
if (this.adventurePointers == null) {
this.adventurePointers = Pointers.builder()
.withDynamic(Identity.NAME, () -> this.handle.getOwner().name())
.withDynamic(Identity.UUID, () -> this.handle.getOwner().id())
.withDynamic(Identity.LOCALE, () -> Objects.requireNonNullElse(Translator.parseLocale(this.handle.clientInformation.language()), Locale.US))
.withDynamic(Identity.NAME, () -> this.packetListener.getOwner().name())
.withDynamic(Identity.UUID, () -> this.packetListener.getOwner().id())
.withDynamic(Identity.LOCALE, () -> Objects.requireNonNullElse(Translator.parseLocale(this.packetListener.clientInformation.language()), Locale.US))
.build();
}

Expand All @@ -107,40 +107,40 @@ public Audience getAudience() {

@Override
public PlayerProfile getProfile() {
return CraftPlayerProfile.asBukkitCopy(this.handle.getOwner());
return CraftPlayerProfile.asBukkitCopy(this.packetListener.getOwner());
}

@Override
public void clearChat() {
this.handle.send(ClientboundResetChatPacket.INSTANCE);
this.packetListener.send(ClientboundResetChatPacket.INSTANCE);
}

@Override
public void completeReconfiguration() {
final ConfigurationTask task = this.handle.currentTask;
final ConfigurationTask task = this.packetListener.currentTask;
if (task != null) {
// This means that the player is going through the normal configuration process, or is already returning to the game phase.
// Be safe and just ignore, as many plugins may call this.
return;
}

this.handle.returnToWorld();
this.packetListener.returnToWorld();
}

@Override
public Set<String> channels() {
return this.handle.pluginMessagerChannels;
return this.packetListener.pluginMessagerChannels;
}

@Override
public void sendPluginMessage(final Plugin source, final String channel, final byte[] message) {
StandardMessenger.validatePluginMessage(this.handle.cserver.getMessenger(), source, channel, message);
StandardMessenger.validatePluginMessage(this.packetListener.cserver.getMessenger(), source, channel, message);

if (this.channels().contains(channel)) {
@SuppressWarnings("deprecation") // "not an API method" does not apply to us
Identifier id = Identifier.parse(StandardMessenger.validateAndCorrectChannel(channel));
ClientboundCustomPayloadPacket packet = new ClientboundCustomPayloadPacket(new DiscardedPayload(id, message));
this.handle.send(packet);
this.packetListener.send(packet);
}
}

Expand All @@ -151,6 +151,6 @@ public Set<String> getListeningPluginChannels() {

@Override
public boolean isConnected() {
return this.handle.connection.isConnected();
return this.packetListener.connection.isConnected();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,26 @@

public class PaperPlayerGameConnection extends PaperCommonConnection<ServerGamePacketListenerImpl> implements PlayerGameConnection {

public PaperPlayerGameConnection(final ServerGamePacketListenerImpl serverConfigurationPacketListenerImpl) {
super(serverConfigurationPacketListenerImpl);
public PaperPlayerGameConnection(final ServerGamePacketListenerImpl packetListener) {
super(packetListener);
}

@Override
public ClientInformation getClientInformation() {
return this.handle.player.clientInformation();
return this.packetListener.player.clientInformation();
}

@Override
public void reenterConfiguration() {
if (HorriblePlayerLoginEventHack.warnReenterConfiguration(this.handle.connection)) {
if (HorriblePlayerLoginEventHack.warnReenterConfiguration(this.packetListener.connection)) {
return;
}
this.handle.switchToConfig();
this.packetListener.switchToConfig();
}

@Override
public Player getPlayer() {
return this.handle.getCraftPlayer();
return this.packetListener.getCraftPlayer();
}

@Override
Expand Down
Loading