From 3e053d63b42aa142c7086241940052eb90354628 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Fri, 21 Feb 2020 18:36:10 -0500 Subject: [PATCH 01/10] Allow ping passthrough for descriptions too --- .../proxy/config/PingPassthroughMode.java | 1 + .../proxy/config/VelocityConfiguration.java | 19 +++++++++++-------- .../client/StatusSessionHandler.java | 18 ++++++++++++++++++ 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/config/PingPassthroughMode.java b/proxy/src/main/java/com/velocitypowered/proxy/config/PingPassthroughMode.java index 89ed3ad8e..1ef700f57 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/config/PingPassthroughMode.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/config/PingPassthroughMode.java @@ -3,5 +3,6 @@ package com.velocitypowered.proxy.config; public enum PingPassthroughMode { DISABLED, MODS, + DESCRIPTION, ALL } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java b/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java index 467363daf..7ab59d446 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java @@ -90,14 +90,17 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi @Comment({ "Should Velocity pass server list ping requests to a backend server?", "Available options:", - "- \"disabled\": No pass-through will be done. The velocity.toml and server-icon.png", - " will determine the initial server list ping response.", - "- \"mods\": Passes only the mod list from your backend server into the response.", - " The first server in your try list (or forced host) with a mod list will be", - " used. If no backend servers can be contacted, Velocity will not display any", - " mod information.", - "- \"all\": Passes everything from the backend server into the response. The Velocity", - " configuration is used if no servers could be contacted." + "- \"disabled\": No pass-through will be done. The velocity.toml and server-icon.png", + " will determine the initial server list ping response.", + "- \"mods\": Passes only the mod list from your backend server into the response.", + " The first server in your try list (or forced host) with a mod list will be", + " used. If no backend servers can be contacted, Velocity will not display any", + " mod information.", + "- \"description\": Uses the description and mod list from the backend server. The first", + " server in the try (or forced host) list that responds is used for the", + " description and mod list.", + "- \"all\": Passes everything from the backend server into the response. The Velocity", + " configuration is used if no servers could be contacted." }) @ConfigKey("ping-passthrough") private PingPassthroughMode pingPassthrough = PingPassthroughMode.DISABLED; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/StatusSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/StatusSessionHandler.java index 613271733..5fbbac0de 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/StatusSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/StatusSessionHandler.java @@ -97,6 +97,24 @@ public class StatusSessionHandler implements MinecraftSessionHandler { } return fallback; }); + case DESCRIPTION: + return pingResponses.thenApply(responses -> { + // Find the first non-fallback. If it includes a modlist, add it too. + for (ServerPing response : responses) { + if (response == fallback) { + continue; + } + + return new ServerPing( + fallback.getVersion(), + fallback.getPlayers().orElse(null), + response.getDescription(), + fallback.getFavicon().orElse(null), + response.getModinfo().orElse(null) + ); + } + return fallback; + }); default: // Not possible, but covered for completeness. return CompletableFuture.completedFuture(fallback); From 65acb13dca65b282aa1742745603717608f71a0f Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Fri, 21 Feb 2020 18:51:41 -0500 Subject: [PATCH 02/10] Checkstyle --- .../velocitypowered/proxy/config/VelocityConfiguration.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java b/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java index 7ab59d446..bd9a02501 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java @@ -94,12 +94,12 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi " will determine the initial server list ping response.", "- \"mods\": Passes only the mod list from your backend server into the response.", " The first server in your try list (or forced host) with a mod list will be", - " used. If no backend servers can be contacted, Velocity will not display any", + " used. If no backend servers can be contacted, Velocity won't display any", " mod information.", "- \"description\": Uses the description and mod list from the backend server. The first", " server in the try (or forced host) list that responds is used for the", " description and mod list.", - "- \"all\": Passes everything from the backend server into the response. The Velocity", + "- \"all\": Uses the backend server's response as the proxy response. The Velocity", " configuration is used if no servers could be contacted." }) @ConfigKey("ping-passthrough") From ae7f0143de26b6e0b8a7b7942f6485e21b933eac Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Fri, 28 Feb 2020 16:54:25 -0500 Subject: [PATCH 03/10] Do not trim the args for string-based command APIs --- .../proxy/command/VelocityCommandManager.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommandManager.java b/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommandManager.java index 0195645ea..4b85bdef6 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommandManager.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommandManager.java @@ -57,7 +57,7 @@ public class VelocityCommandManager implements CommandManager { int firstSpace = cmdLine.indexOf(' '); if (firstSpace != -1) { alias = cmdLine.substring(0, firstSpace); - args = cmdLine.substring(firstSpace).trim(); + args = cmdLine.substring(firstSpace); } RawCommand command = commands.get(alias.toLowerCase(Locale.ENGLISH)); if (command == null) { @@ -107,7 +107,7 @@ public class VelocityCommandManager implements CommandManager { } String alias = cmdLine.substring(0, firstSpace); - String args = cmdLine.substring(firstSpace).trim(); + String args = cmdLine.substring(firstSpace); RawCommand command = commands.get(alias.toLowerCase(Locale.ENGLISH)); if (command == null) { // No such command, so we can't offer any tab complete suggestions. @@ -167,7 +167,7 @@ public class VelocityCommandManager implements CommandManager { if (line.isEmpty()) { return new String[0]; } - return line.split(" ", -1); + return line.trim().split(" ", -1); } @Override From c54ea6201261fca9d2e5ad6631fcd1ad7359be59 Mon Sep 17 00:00:00 2001 From: kashike Date: Sun, 29 Mar 2020 16:13:43 -0700 Subject: [PATCH 04/10] update text to 3.0.3 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 0ff6be509..2e57eb060 100644 --- a/build.gradle +++ b/build.gradle @@ -20,7 +20,7 @@ allprojects { ext { // dependency versions - textVersion = '3.0.2' + textVersion = '3.0.3' junitVersion = '5.3.0-M1' slf4jVersion = '1.7.25' log4jVersion = '2.11.2' From 5089da07fc159799ee11c28b0b517e2f8cf84b25 Mon Sep 17 00:00:00 2001 From: Gabik21 Date: Thu, 2 Apr 2020 17:46:24 +0200 Subject: [PATCH 05/10] Don't send ping update twice VelocityTabListEntry#setLatency calls the update method, which constructs a new packet and sends it to the client. The backend packet we are processing also reaches the client, therefore we are sending the same packet twice. VelocityTabListEntry#setLatencyInternal is the correct method here. --- .../velocitypowered/proxy/tablist/VelocityTabListLegacy.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/tablist/VelocityTabListLegacy.java b/proxy/src/main/java/com/velocitypowered/proxy/tablist/VelocityTabListLegacy.java index b1e5c2610..9a5118496 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/tablist/VelocityTabListLegacy.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/tablist/VelocityTabListLegacy.java @@ -68,7 +68,7 @@ public class VelocityTabListLegacy extends VelocityTabList { if (nameMapping.containsKey(strippedName)) { // ADD_PLAYER also used for updating ping VelocityTabListEntry entry = entries.get(nameMapping.get(strippedName)); if (entry != null) { - entry.setLatency(item.getLatency()); + entry.setLatencyInternal(item.getLatency()); } } else { UUID uuid = UUID.randomUUID(); // Use a fake uuid to preserve function of custom entries From 2217e8a5c9232dfc86bbed0a17d7ec23c068ef90 Mon Sep 17 00:00:00 2001 From: Gabik21 Date: Tue, 7 Apr 2020 12:17:02 +0200 Subject: [PATCH 06/10] Fix 1.7 tablist behaving weird with colored names The 1.7 tablist packet only contains three types of information: - Name of the tablist entry (limited to 16 characters including colors) - Ping of the entry - If this entry needs to be added or removed (client accepts duplicates as 'ping update') The previous logic was trying to preserve parity with GameProfile#getName returning a stripped down name to have a 'real' username. That is fundamentally broken, because entries with duplicate content, but different colors are very common, especially with custom tablists. For packets coming from a native 1.7 server we just won't define the displayname anymore, as there is no such thing as a 'displayname', because tablist entries are not bound to any player. Using the Velocity Tablist API to modify existing entries will work, though the backend server will completely loose control over the entry. Custom entries added over the Velocity Tablist API will work, but are cut off by the 16 character limitation. This commit only fixes the bug, where entries are incorrectly handled with their stripped name, a lot of the things explained above were already implemented correctly. --- .../proxy/tablist/VelocityTabListLegacy.java | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/tablist/VelocityTabListLegacy.java b/proxy/src/main/java/com/velocitypowered/proxy/tablist/VelocityTabListLegacy.java index b1e5c2610..3eabf11e8 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/tablist/VelocityTabListLegacy.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/tablist/VelocityTabListLegacy.java @@ -60,29 +60,25 @@ public class VelocityTabListLegacy extends VelocityTabList { Item item = packet.getItems().get(0); // Only one item per packet in 1.7 - Component displayName = LegacyComponentSerializer.legacy().deserialize(item.getName()); - String strippedName = PlainComponentSerializer.INSTANCE.serialize(displayName); - switch (packet.getAction()) { case PlayerListItem.ADD_PLAYER: - if (nameMapping.containsKey(strippedName)) { // ADD_PLAYER also used for updating ping - VelocityTabListEntry entry = entries.get(nameMapping.get(strippedName)); + if (nameMapping.containsKey(item.getName())) { // ADD_PLAYER also used for updating ping + VelocityTabListEntry entry = entries.get(nameMapping.get(item.getName())); if (entry != null) { entry.setLatency(item.getLatency()); } } else { UUID uuid = UUID.randomUUID(); // Use a fake uuid to preserve function of custom entries - nameMapping.put(strippedName, uuid); + nameMapping.put(item.getName(), uuid); entries.put(uuid, (VelocityTabListEntry) TabListEntry.builder() .tabList(this) - .profile(new GameProfile(uuid, strippedName, ImmutableList.of())) - .displayName(displayName) + .profile(new GameProfile(uuid, item.getName(), ImmutableList.of())) .latency(item.getLatency()) .build()); } break; case PlayerListItem.REMOVE_PLAYER: - UUID removedUuid = nameMapping.remove(strippedName); + UUID removedUuid = nameMapping.remove(item.getName()); if (removedUuid != null) { entries.remove(removedUuid); } From d4e51e2d0738eda85edd965275b6ae143bb05411 Mon Sep 17 00:00:00 2001 From: Crypnotic Date: Sun, 9 Feb 2020 13:40:15 -0600 Subject: [PATCH 07/10] Add cleanServerName to VelocityConfiguration to remove quotes and other unforeseen characters from server names before registration --- .../proxy/config/VelocityConfiguration.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java b/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java index bd9a02501..806ef44ce 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java @@ -508,7 +508,7 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi Map servers = new HashMap<>(); for (Map.Entry entry : toml.entrySet()) { if (entry.getValue() instanceof String) { - servers.put(entry.getKey(), (String) entry.getValue()); + servers.put(cleanServerName(entry.getKey()), (String) entry.getValue()); } else { if (!entry.getKey().equalsIgnoreCase("try")) { throw new IllegalArgumentException( @@ -542,6 +542,19 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi this.attemptConnectionOrder = attemptConnectionOrder; } + /** + * TOML requires keys to match a regex of {@code [A-Za-z0-9_-]} unless it is wrapped in + * quotes; however, the TOML parser returns the key with the quotes so we need to clean the + * server name before we pass it onto server registration to keep proper server name behavior. + * + * @param name the server name to clean + * + * @return the cleaned server name + */ + private String cleanServerName(String name) { + return name.replace("\"", ""); + } + @Override public String toString() { return "Servers{" From 55818ce5eb8292005d9701fa4cd174337ef01569 Mon Sep 17 00:00:00 2001 From: Hugo Manrique Date: Fri, 13 Mar 2020 18:17:06 +0100 Subject: [PATCH 08/10] Remove tasks from lookup map upon completion --- .../com/velocitypowered/proxy/scheduler/VelocityScheduler.java | 1 + 1 file changed, 1 insertion(+) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/scheduler/VelocityScheduler.java b/proxy/src/main/java/com/velocitypowered/proxy/scheduler/VelocityScheduler.java index 0bd4bcd3d..f0605f0b6 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/scheduler/VelocityScheduler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/scheduler/VelocityScheduler.java @@ -187,6 +187,7 @@ public class VelocityScheduler implements Scheduler { } catch (Exception e) { Log.logger.error("Exception in task {} by plugin {}", runnable, plugin, e); } finally { + onFinish(); currentTaskThread = null; } }); From 2c2eca35484d0b5927eb8650de23596728798ca0 Mon Sep 17 00:00:00 2001 From: Hugo Manrique Date: Fri, 13 Mar 2020 18:52:15 +0100 Subject: [PATCH 09/10] Only finish non-repeating tasks --- .../velocitypowered/proxy/scheduler/VelocityScheduler.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/scheduler/VelocityScheduler.java b/proxy/src/main/java/com/velocitypowered/proxy/scheduler/VelocityScheduler.java index f0605f0b6..1bec0d119 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/scheduler/VelocityScheduler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/scheduler/VelocityScheduler.java @@ -3,7 +3,6 @@ package com.velocitypowered.proxy.scheduler; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; -import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.Multimap; import com.google.common.collect.Multimaps; @@ -187,7 +186,9 @@ public class VelocityScheduler implements Scheduler { } catch (Exception e) { Log.logger.error("Exception in task {} by plugin {}", runnable, plugin, e); } finally { - onFinish(); + if (repeat == 0) { + onFinish(); + } currentTaskThread = null; } }); From 6ed61848e9883d4db21e1c546f6820d708f28950 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Mon, 17 Feb 2020 19:34:22 -0500 Subject: [PATCH 10/10] Upon connection exception, discard all incoming packets instead --- .../velocitypowered/proxy/protocol/netty/MinecraftDecoder.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftDecoder.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftDecoder.java index 55da0dd78..0204aefb3 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftDecoder.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftDecoder.java @@ -2,17 +2,14 @@ package com.velocitypowered.proxy.protocol.netty; import com.google.common.base.Preconditions; import com.velocitypowered.api.network.ProtocolVersion; -import com.velocitypowered.proxy.network.Connections; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.StateRegistry; import com.velocitypowered.proxy.util.except.QuietException; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.handler.codec.CorruptedFrameException; import io.netty.handler.codec.MessageToMessageDecoder; -import io.netty.util.ReferenceCountUtil; import java.util.List; public class MinecraftDecoder extends MessageToMessageDecoder {