3
0
Mirror von https://github.com/PaperMC/Velocity.git synchronisiert 2024-11-17 05:20:14 +01:00

Further improvements.

The main component here is the total revamp of the plugin channel identifier system - instead of Legacy/Modern channel IDs, you can have a modern channel or a modern channel paired with a legacy channel, which is much less confusing to work with.
Dieser Commit ist enthalten in:
Andrew Steinborn 2021-04-17 06:04:12 -04:00
Ursprung 0ed8352012
Commit 9645fb59da
32 geänderte Dateien mit 307 neuen und 404 gelöschten Zeilen

Datei anzeigen

@ -11,9 +11,9 @@ import com.google.common.io.ByteArrayDataInput;
import com.velocitypowered.api.event.ResultedEvent;
import com.velocitypowered.api.proxy.connection.Player;
import com.velocitypowered.api.proxy.connection.ServerConnection;
import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
import com.velocitypowered.api.proxy.messages.ChannelMessageSink;
import com.velocitypowered.api.proxy.messages.ChannelMessageSource;
import com.velocitypowered.api.proxy.messages.PluginChannelId;
import java.io.ByteArrayInputStream;
/**
@ -26,7 +26,7 @@ public interface PluginMessageEvent extends ResultedEvent<PluginMessageEvent.For
ChannelMessageSink sink();
ChannelIdentifier channel();
PluginChannelId channel();
byte[] rawMessage();

Datei anzeigen

@ -12,9 +12,9 @@ import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteStreams;
import com.velocitypowered.api.proxy.connection.Player;
import com.velocitypowered.api.proxy.connection.ServerConnection;
import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
import com.velocitypowered.api.proxy.messages.ChannelMessageSink;
import com.velocitypowered.api.proxy.messages.ChannelMessageSource;
import com.velocitypowered.api.proxy.messages.PluginChannelId;
import java.io.ByteArrayInputStream;
import java.util.Arrays;
@ -26,7 +26,7 @@ public final class PluginMessageEventImpl implements PluginMessageEvent {
private final ChannelMessageSource source;
private final ChannelMessageSink target;
private final ChannelIdentifier identifier;
private final PluginChannelId identifier;
private final byte[] data;
private ForwardResult result;
@ -39,7 +39,7 @@ public final class PluginMessageEventImpl implements PluginMessageEvent {
* @param data the payload of the plugin message
*/
public PluginMessageEventImpl(ChannelMessageSource source, ChannelMessageSink target,
ChannelIdentifier identifier, byte[] data) {
PluginChannelId identifier, byte[] data) {
this.source = Preconditions.checkNotNull(source, "source");
this.target = Preconditions.checkNotNull(target, "target");
this.identifier = Preconditions.checkNotNull(identifier, "identifier");
@ -68,7 +68,7 @@ public final class PluginMessageEventImpl implements PluginMessageEvent {
}
@Override
public ChannelIdentifier channel() {
public PluginChannelId channel() {
return identifier;
}

Datei anzeigen

@ -8,7 +8,7 @@
package com.velocitypowered.api.event.player;
import com.velocitypowered.api.proxy.connection.Player;
import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
import com.velocitypowered.api.proxy.messages.PluginChannelId;
import java.util.List;
/**
@ -19,5 +19,5 @@ public interface PlayerChannelRegisterEvent {
Player player();
List<ChannelIdentifier> channels();
List<PluginChannelId> channels();
}

Datei anzeigen

@ -9,7 +9,7 @@ package com.velocitypowered.api.event.player;
import com.google.common.base.Preconditions;
import com.velocitypowered.api.proxy.connection.Player;
import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
import com.velocitypowered.api.proxy.messages.PluginChannelId;
import java.util.List;
/**
@ -19,9 +19,9 @@ import java.util.List;
public final class PlayerChannelRegisterEventImpl implements PlayerChannelRegisterEvent {
private final Player player;
private final List<ChannelIdentifier> channels;
private final List<PluginChannelId> channels;
public PlayerChannelRegisterEventImpl(Player player, List<ChannelIdentifier> channels) {
public PlayerChannelRegisterEventImpl(Player player, List<PluginChannelId> channels) {
this.player = Preconditions.checkNotNull(player, "player");
this.channels = Preconditions.checkNotNull(channels, "channels");
}
@ -32,7 +32,7 @@ public final class PlayerChannelRegisterEventImpl implements PlayerChannelRegist
}
@Override
public List<ChannelIdentifier> channels() {
public List<PluginChannelId> channels() {
return channels;
}

Datei anzeigen

@ -39,7 +39,7 @@ public interface PluginManager {
*
* @return the plugins
*/
Collection<PluginContainer> getPlugins();
Collection<PluginContainer> plugins();
/**
* Checks if a plugin is loaded based on its ID.

Datei anzeigen

@ -1,21 +0,0 @@
/*
* Copyright (C) 2018 Velocity Contributors
*
* The Velocity API is licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in the api top-level directory.
*/
package com.velocitypowered.api.proxy.messages;
/**
* Represents a channel identifier for use with plugin messaging.
*/
public interface ChannelIdentifier {
/**
* Returns the textual representation of this identifier.
*
* @return the textual representation of the identifier
*/
String id();
}

Datei anzeigen

@ -19,5 +19,5 @@ public interface ChannelMessageSink {
* @param data the data to send
* @return whether or not the message could be sent
*/
boolean sendPluginMessage(ChannelIdentifier identifier, byte[] data);
boolean sendPluginMessage(PluginChannelId identifier, byte[] data);
}

Datei anzeigen

@ -10,7 +10,7 @@ package com.velocitypowered.api.proxy.messages;
import com.velocitypowered.api.event.connection.PluginMessageEventImpl;
/**
* Represents an interface to register and unregister {@link ChannelIdentifier}s for the proxy to
* Represents an interface to register and unregister {@link PluginChannelId}s for the proxy to
* listen on.
*/
public interface ChannelRegistrar {
@ -21,12 +21,12 @@ public interface ChannelRegistrar {
*
* @param identifiers the channel identifiers to register
*/
void register(ChannelIdentifier... identifiers);
void register(PluginChannelId... identifiers);
/**
* Removes the intent to listen for the specified channel.
*
* @param identifiers the identifiers to unregister
*/
void unregister(ChannelIdentifier... identifiers);
void unregister(PluginChannelId... identifiers);
}

Datei anzeigen

@ -1,64 +0,0 @@
/*
* Copyright (C) 2018 Velocity Contributors
*
* The Velocity API is licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in the api top-level directory.
*/
package com.velocitypowered.api.proxy.messages;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import java.util.Objects;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Reperesents a legacy channel identifier (for Minecraft 1.12 and below). For modern 1.13 plugin
* messages, please see {@link MinecraftChannelIdentifier}. This class is immutable and safe for
* multi-threaded use.
*/
public final class LegacyChannelIdentifier implements ChannelIdentifier {
private final String name;
/**
* Creates a new legacy channel identifier.
*
* @param name the name for the channel
*/
public LegacyChannelIdentifier(String name) {
Preconditions.checkArgument(!Strings.isNullOrEmpty(name), "provided name is empty");
this.name = name;
}
public String getName() {
return name;
}
@Override
public String toString() {
return name + " (legacy)";
}
@Override
public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
LegacyChannelIdentifier that = (LegacyChannelIdentifier) o;
return Objects.equals(name, that.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
@Override
public String id() {
return this.getName();
}
}

Datei anzeigen

@ -1,114 +0,0 @@
/*
* Copyright (C) 2018 Velocity Contributors
*
* The Velocity API is licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in the api top-level directory.
*/
package com.velocitypowered.api.proxy.messages;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import java.util.Objects;
import java.util.regex.Pattern;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Represents a Minecraft 1.13+ channel identifier. This class is immutable and safe for
* multi-threaded use.
*/
public final class MinecraftChannelIdentifier implements ChannelIdentifier {
private static final Pattern VALID_IDENTIFIER_REGEX = Pattern.compile("[a-z0-9/\\-_]*");
private final String namespace;
private final String name;
private MinecraftChannelIdentifier(String namespace, String name) {
this.namespace = namespace;
this.name = name;
}
/**
* Creates an identifier in the default namespace ({@code minecraft}). Plugins are strongly
* encouraged to provide their own namespace.
*
* @param name the name in the default namespace to use
* @return a new channel identifier
*/
public static MinecraftChannelIdentifier forDefaultNamespace(String name) {
return new MinecraftChannelIdentifier("minecraft", name);
}
/**
* Creates an identifier in the specified namespace.
*
* @param namespace the namespace to use
* @param name the channel name inside the specified namespace
* @return a new channel identifier
*/
public static MinecraftChannelIdentifier create(String namespace, String name) {
Preconditions.checkArgument(!Strings.isNullOrEmpty(namespace), "namespace is null or empty");
Preconditions.checkArgument(name != null, "namespace is null or empty");
Preconditions.checkArgument(VALID_IDENTIFIER_REGEX.matcher(namespace).matches(),
"namespace is not valid");
Preconditions
.checkArgument(VALID_IDENTIFIER_REGEX.matcher(name).matches(), "name is not valid");
return new MinecraftChannelIdentifier(namespace, name);
}
/**
* Creates an channel identifier from the specified Minecraft identifier.
*
* @param identifier the Minecraft identifier
* @return a new channel identifier
*/
public static MinecraftChannelIdentifier from(String identifier) {
int colonPos = identifier.indexOf(':');
if (colonPos == -1) {
throw new IllegalArgumentException("Identifier does not contain a colon.");
}
if (colonPos + 1 == identifier.length()) {
throw new IllegalArgumentException("Identifier is empty.");
}
String namespace = identifier.substring(0, colonPos);
String name = identifier.substring(colonPos + 1);
return create(namespace, name);
}
public String getNamespace() {
return namespace;
}
public String getName() {
return name;
}
@Override
public String toString() {
return namespace + ":" + name + " (modern)";
}
@Override
public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
MinecraftChannelIdentifier that = (MinecraftChannelIdentifier) o;
return Objects.equals(namespace, that.namespace)
&& Objects.equals(name, that.name);
}
@Override
public int hashCode() {
return Objects.hash(namespace, name);
}
@Override
public String id() {
return namespace + ":" + name;
}
}

Datei anzeigen

@ -0,0 +1,55 @@
/*
* Copyright (C) 2018 Velocity Contributors
*
* The Velocity API is licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in the api top-level directory.
*/
package com.velocitypowered.api.proxy.messages;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import java.util.Objects;
import java.util.regex.Pattern;
import net.kyori.adventure.key.Key;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Represents a Minecraft 1.13+ channel identifier.
*/
public final class MinecraftPluginChannelId implements PluginChannelId {
private final Key key;
MinecraftPluginChannelId(Key key) {
this.key = Preconditions.checkNotNull(key, "key");
}
public Key key() {
return key;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
MinecraftPluginChannelId that = (MinecraftPluginChannelId) o;
return key.equals(that.key);
}
@Override
public int hashCode() {
return key.hashCode();
}
@Override
public String toString() {
return key.asString();
}
}

Datei anzeigen

@ -0,0 +1,72 @@
/*
* Copyright (C) 2018 Velocity Contributors
*
* The Velocity API is licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in the api top-level directory.
*/
package com.velocitypowered.api.proxy.messages;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import net.kyori.adventure.key.Key;
/**
* Reperesents a legacy channel identifier (for Minecraft 1.12 and below). For modern 1.13 plugin
* messages, please see {@link MinecraftPluginChannelId}. This class is immutable and safe for
* multi-threaded use.
*/
public final class PairedPluginChannelId implements PluginChannelId {
private final String legacyChannel;
private final Key modernChannelKey;
/**
* Creates a new legacy channel identifier.
*
* @param legacyChannel the name for the legacy channel name
* @param modernChannelKey the modern channel key to use
*/
PairedPluginChannelId(String legacyChannel, Key modernChannelKey) {
Preconditions.checkArgument(!Strings.isNullOrEmpty(legacyChannel), "provided name is empty");
this.legacyChannel = legacyChannel;
this.modernChannelKey = Preconditions.checkNotNull(modernChannelKey, "modernChannelKey");
}
public String legacyChannel() {
return legacyChannel;
}
public Key modernChannelKey() {
return modernChannelKey;
}
@Override
public String toString() {
return legacyChannel + "/" + modernChannelKey.asString();
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
PairedPluginChannelId that = (PairedPluginChannelId) o;
if (!legacyChannel.equals(that.legacyChannel)) {
return false;
}
return modernChannelKey.equals(that.modernChannelKey);
}
@Override
public int hashCode() {
int result = legacyChannel.hashCode();
result = 31 * result + modernChannelKey.hashCode();
return result;
}
}

Datei anzeigen

@ -0,0 +1,41 @@
/*
* Copyright (C) 2018 Velocity Contributors
*
* The Velocity API is licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in the api top-level directory.
*/
package com.velocitypowered.api.proxy.messages;
import net.kyori.adventure.key.Key;
/**
* Represents a channel identifier for use with plugin messaging.
*/
public interface PluginChannelId {
/**
* Wraps the specified Minecraft key so it can be used as a {@link PluginChannelId}.
* If the client is connected using Minecraft 1.12.2 or earlier, use the key as the
* channel name.
*
* @param key the key instance to wrap
* @return a wrapped plugin channel ID
*/
static MinecraftPluginChannelId wrap(Key key) {
return new MinecraftPluginChannelId(key);
}
/**
* Wraps the specified Minecraft key so it can be used as a {@link PluginChannelId},
* with the specified {@code legacyChannel} for clients onnected using Minecraft 1.12.2
* or earlier.
*
* @param legacyChannel the legacy channel name
* @param modernChannelKey the key instance to wrap
* @return a wrapped plugin channel ID
*/
static PairedPluginChannelId withLegacy(String legacyChannel, Key modernChannelKey) {
return new PairedPluginChannelId(legacyChannel, modernChannelKey);
}
}

Datei anzeigen

@ -1,63 +0,0 @@
/*
* Copyright (C) 2018 Velocity Contributors
*
* The Velocity API is licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in the api top-level directory.
*/
package com.velocitypowered.api.proxy.messages;
import static com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier.create;
import static com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier.from;
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test;
class MinecraftChannelIdentifierTest {
@Test
void createAllowsValidNamespaces() {
create("minecraft", "brand");
}
@Test
void createAllowsEmptyName() {
create("minecraft", "");
}
@Test
void createDisallowsNull() {
assertAll(
() -> assertThrows(IllegalArgumentException.class, () -> create(null, "")),
() -> assertThrows(IllegalArgumentException.class, () -> create("", "")),
() -> assertThrows(IllegalArgumentException.class, () -> create("minecraft", null))
);
}
@Test
void fromIdentifierIsCorrect() {
MinecraftChannelIdentifier expected = MinecraftChannelIdentifier.create("velocity", "test");
assertEquals(expected, MinecraftChannelIdentifier.from("velocity:test"));
}
@Test
void createAllowsSlashes() {
create("velocity", "test/test2");
}
@Test
void fromIdentifierThrowsOnBadValues() {
assertAll(
() -> assertThrows(IllegalArgumentException.class, () -> from("")),
() -> assertThrows(IllegalArgumentException.class, () -> from(":")),
() -> assertThrows(IllegalArgumentException.class, () -> from(":a")),
() -> assertThrows(IllegalArgumentException.class, () -> from("a:")),
() -> assertThrows(IllegalArgumentException.class, () -> from("hello:$$$$$$")),
() -> assertThrows(IllegalArgumentException.class, () -> from("hello::"))
);
}
}

Datei anzeigen

@ -277,7 +277,7 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
}
// Register the plugin main classes so that we can fire the proxy initialize event
for (PluginContainer plugin : pluginManager.getPlugins()) {
for (PluginContainer plugin : pluginManager.plugins()) {
Optional<?> instance = plugin.instance();
if (instance.isPresent()) {
try {
@ -289,7 +289,7 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
}
}
logger.info("Loaded {} plugins", pluginManager.getPlugins().size());
logger.info("Loaded {} plugins", pluginManager.plugins().size());
}
public Bootstrap createBootstrap(@Nullable EventLoopGroup group, SocketAddress target) {

Datei anzeigen

@ -270,7 +270,7 @@ public class VelocityCommand implements SimpleCommand {
return;
}
List<PluginContainer> plugins = ImmutableList.copyOf(server.pluginManager().getPlugins());
List<PluginContainer> plugins = ImmutableList.copyOf(server.pluginManager().plugins());
int pluginCount = plugins.size();
if (pluginCount == 0) {

Datei anzeigen

@ -28,7 +28,7 @@ import com.velocitypowered.api.event.command.PlayerAvailableCommandsEventImpl;
import com.velocitypowered.api.event.connection.PluginMessageEvent;
import com.velocitypowered.api.event.connection.PluginMessageEventImpl;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
import com.velocitypowered.api.proxy.messages.PluginChannelId;
import com.velocitypowered.proxy.VelocityServer;
import com.velocitypowered.proxy.connection.MinecraftConnection;
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
@ -160,7 +160,7 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
return true;
}
ChannelIdentifier id = server.channelRegistrar().getFromId(packet.getChannel());
PluginChannelId id = server.channelRegistrar().getFromId(packet.getChannel());
if (id == null) {
return false;
}

Datei anzeigen

@ -19,8 +19,8 @@ package com.velocitypowered.proxy.connection.backend;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.api.proxy.connection.Player;
import com.velocitypowered.api.proxy.messages.LegacyChannelIdentifier;
import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier;
import com.velocitypowered.api.proxy.messages.PairedPluginChannelId;
import com.velocitypowered.api.proxy.messages.PluginChannelId;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.util.UuidUtils;
import com.velocitypowered.proxy.VelocityServer;
@ -40,6 +40,7 @@ import java.net.SocketAddress;
import java.util.Optional;
import java.util.StringJoiner;
import net.kyori.adventure.identity.Identity;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.ComponentSerializer;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
@ -50,10 +51,8 @@ import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
+ "nothing.")
public class BungeeCordMessageResponder {
private static final MinecraftChannelIdentifier MODERN_CHANNEL = MinecraftChannelIdentifier
.create("bungeecord", "main");
private static final LegacyChannelIdentifier LEGACY_CHANNEL =
new LegacyChannelIdentifier("BungeeCord");
private static final PairedPluginChannelId CHANNEL = PluginChannelId
.withLegacy("BungeeCord", Key.key("bungeecord", "main"));
private final VelocityServer proxy;
private final ConnectedPlayer player;
@ -64,8 +63,8 @@ public class BungeeCordMessageResponder {
}
public static boolean isBungeeCordMessage(AbstractPluginMessagePacket<?> message) {
return MODERN_CHANNEL.id().equals(message.getChannel()) || LEGACY_CHANNEL.id()
.equals(message.getChannel());
return CHANNEL.modernChannelKey().asString().equals(message.getChannel())
|| CHANNEL.legacyChannel().equals(message.getChannel());
}
private void processConnect(ByteBufDataInput in) {
@ -293,7 +292,7 @@ public class BungeeCordMessageResponder {
if (target.equals("ALL")) {
try {
for (RegisteredServer rs : proxy.registeredServers()) {
((VelocityRegisteredServer) rs).sendPluginMessage(LEGACY_CHANNEL,
((VelocityRegisteredServer) rs).sendPluginMessage(CHANNEL,
toForward.retainedSlice());
}
} finally {
@ -302,7 +301,7 @@ public class BungeeCordMessageResponder {
} else {
Optional<RegisteredServer> server = proxy.server(target);
if (server.isPresent()) {
((VelocityRegisteredServer) server.get()).sendPluginMessage(LEGACY_CHANNEL, toForward);
((VelocityRegisteredServer) server.get()).sendPluginMessage(CHANNEL, toForward);
} else {
toForward.release();
}
@ -310,8 +309,8 @@ public class BungeeCordMessageResponder {
}
static String getBungeeCordChannel(ProtocolVersion version) {
return version.gte(ProtocolVersion.MINECRAFT_1_13) ? MODERN_CHANNEL.id()
: LEGACY_CHANNEL.id();
return version.gte(ProtocolVersion.MINECRAFT_1_13) ? CHANNEL.modernChannelKey().asString()
: CHANNEL.legacyChannel();
}
// Note: this method will always release the buffer!

Datei anzeigen

@ -20,12 +20,13 @@ package com.velocitypowered.proxy.connection.backend;
import static com.velocitypowered.proxy.VelocityServer.GENERAL_GSON;
import static com.velocitypowered.proxy.connection.forge.legacy.LegacyForgeConstants.HANDSHAKE_HOSTNAME_TOKEN;
import static com.velocitypowered.proxy.network.HandlerNames.HANDLER;
import static com.velocitypowered.proxy.network.PluginMessageUtil.channelIdForVersion;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.api.proxy.connection.ServerConnection;
import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
import com.velocitypowered.api.proxy.messages.PluginChannelId;
import com.velocitypowered.api.proxy.player.ConnectionRequestBuilder;
import com.velocitypowered.api.proxy.server.ServerInfo;
import com.velocitypowered.api.util.GameProfile.Property;
@ -236,7 +237,7 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation,
}
@Override
public boolean sendPluginMessage(ChannelIdentifier identifier, byte[] data) {
public boolean sendPluginMessage(PluginChannelId identifier, byte[] data) {
return sendPluginMessage(identifier, Unpooled.wrappedBuffer(data));
}
@ -246,13 +247,14 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation,
* @param data the data
* @return whether or not the message was sent
*/
public boolean sendPluginMessage(ChannelIdentifier identifier, ByteBuf data) {
public boolean sendPluginMessage(PluginChannelId identifier, ByteBuf data) {
Preconditions.checkNotNull(identifier, "identifier");
Preconditions.checkNotNull(data, "data");
MinecraftConnection mc = ensureConnected();
ServerboundPluginMessagePacket message = new ServerboundPluginMessagePacket(identifier.id(), data);
ServerboundPluginMessagePacket message = new ServerboundPluginMessagePacket(
channelIdForVersion(identifier, mc.getProtocolVersion()), data);
mc.write(message);
return true;
}

Datei anzeigen

@ -32,9 +32,7 @@ import com.velocitypowered.api.event.player.PlayerChatEventImpl;
import com.velocitypowered.api.event.player.PlayerResourcePackStatusEventImpl;
import com.velocitypowered.api.event.player.TabCompleteEventImpl;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
import com.velocitypowered.api.proxy.messages.LegacyChannelIdentifier;
import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier;
import com.velocitypowered.api.proxy.messages.PluginChannelId;
import com.velocitypowered.proxy.VelocityServer;
import com.velocitypowered.proxy.connection.ConnectionTypes;
import com.velocitypowered.proxy.connection.MinecraftConnection;
@ -72,6 +70,7 @@ import java.util.Queue;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import net.kyori.adventure.identity.Identity;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.apache.logging.log4j.LogManager;
@ -218,16 +217,21 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
} else if (PluginMessageUtil.isRegister(packet)) {
List<String> channels = PluginMessageUtil.getChannels(packet);
player.getKnownChannels().addAll(channels);
List<ChannelIdentifier> channelIdentifiers = new ArrayList<>();
for (String channel : channels) {
try {
channelIdentifiers.add(MinecraftChannelIdentifier.from(channel));
} catch (IllegalArgumentException e) {
channelIdentifiers.add(new LegacyChannelIdentifier(channel));
List<PluginChannelId> pluginChannelIds = new ArrayList<>();
if (player.protocolVersion().gte(MINECRAFT_1_13)) {
for (String channel : channels) {
pluginChannelIds.add(PluginChannelId.wrap(Key.key(channel)));
}
} else {
for (String channel : channels) {
pluginChannelIds.add(PluginChannelId.withLegacy(channel,
Key.key(PluginMessageUtil.transformLegacyToModernChannel(channel))));
}
}
server.eventManager().fireAndForget(new PlayerChannelRegisterEventImpl(player,
ImmutableList.copyOf(channelIdentifiers)));
ImmutableList.copyOf(pluginChannelIds)));
backendConn.write(packet.retain());
} else if (PluginMessageUtil.isUnregister(packet)) {
player.getKnownChannels().removeAll(PluginMessageUtil.getChannels(packet));
@ -259,7 +263,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
// appropriately.
loginPluginMessages.add(packet.retain());
} else {
ChannelIdentifier id = server.channelRegistrar().getFromId(packet.getChannel());
PluginChannelId id = server.channelRegistrar().getFromId(packet.getChannel());
if (id == null) {
backendConn.write(packet.retain());
} else {

Datei anzeigen

@ -19,6 +19,7 @@ package com.velocitypowered.proxy.connection.client;
import static com.velocitypowered.api.proxy.player.ConnectionRequestBuilder.Status.ALREADY_CONNECTED;
import static com.velocitypowered.proxy.connection.util.ConnectionRequestResults.plainResult;
import static com.velocitypowered.proxy.network.PluginMessageUtil.channelIdForVersion;
import static java.util.concurrent.CompletableFuture.completedFuture;
import com.google.common.base.Preconditions;
@ -42,7 +43,7 @@ import com.velocitypowered.api.permission.PermissionProvider;
import com.velocitypowered.api.permission.Tristate;
import com.velocitypowered.api.proxy.connection.Player;
import com.velocitypowered.api.proxy.connection.ServerConnection;
import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
import com.velocitypowered.api.proxy.messages.PluginChannelId;
import com.velocitypowered.api.proxy.player.ClientSettings;
import com.velocitypowered.api.proxy.player.ConnectionRequestBuilder;
import com.velocitypowered.api.proxy.server.RegisteredServer;
@ -709,10 +710,11 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
}
@Override
public boolean sendPluginMessage(ChannelIdentifier identifier, byte[] data) {
public boolean sendPluginMessage(PluginChannelId identifier, byte[] data) {
Preconditions.checkNotNull(identifier, "identifier");
Preconditions.checkNotNull(data, "data");
ClientboundPluginMessagePacket message = new ClientboundPluginMessagePacket(identifier.id(),
ClientboundPluginMessagePacket message = new ClientboundPluginMessagePacket(
channelIdForVersion(identifier, connection.getProtocolVersion()),
Unpooled.wrappedBuffer(data));
connection.write(message);
return true;

Datei anzeigen

@ -22,6 +22,9 @@ import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.ImmutableList;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.api.proxy.messages.MinecraftPluginChannelId;
import com.velocitypowered.api.proxy.messages.PairedPluginChannelId;
import com.velocitypowered.api.proxy.messages.PluginChannelId;
import com.velocitypowered.api.util.ProxyVersion;
import com.velocitypowered.proxy.network.packet.AbstractPluginMessagePacket;
import io.netty.buffer.ByteBuf;
@ -174,6 +177,19 @@ public final class PluginMessageUtil {
}
}
public static String channelIdForVersion(PluginChannelId id, ProtocolVersion version) {
if (id instanceof MinecraftPluginChannelId) {
return ((MinecraftPluginChannelId) id).key().asString();
} else if (id instanceof PairedPluginChannelId) {
if (version.gte(ProtocolVersion.MINECRAFT_1_13)) {
return ((PairedPluginChannelId) id).modernChannelKey().asString();
} else {
return ((PairedPluginChannelId) id).legacyChannel();
}
}
throw new IllegalArgumentException("Unknown channel ID " + id.getClass().getName());
}
private static final Pattern INVALID_IDENTIFIER_REGEX = Pattern.compile("[^a-z0-9\\-_]*");
/**

Datei anzeigen

@ -32,9 +32,6 @@ public abstract class AbstractPluginMessagePacket<S extends AbstractPluginMessag
protected static <P extends AbstractPluginMessagePacket<P>> PacketReader<P> decoder(final Factory<P> factory) {
return (buf, version) -> {
String channel = ProtocolUtils.readString(buf);
if (version.gte(ProtocolVersion.MINECRAFT_1_13)) {
channel = transformLegacyToModernChannel(channel);
}
final ByteBuf data;
if (version.gte(ProtocolVersion.MINECRAFT_1_8)) {
data = buf.readRetainedSlice(buf.readableBytes());

Datei anzeigen

@ -201,7 +201,7 @@ public class GS4QueryHandler extends SimpleChannelInboundHandler<DatagramPacket>
private List<QueryResponse.PluginInformation> getRealPluginInformation() {
List<QueryResponse.PluginInformation> result = new ArrayList<>();
for (PluginContainer plugin : server.pluginManager().getPlugins()) {
for (PluginContainer plugin : server.pluginManager().plugins()) {
PluginDescription description = plugin.description();
result.add(QueryResponse.PluginInformation.of(description.name()
.orElse(description.id()), description.version().orElse(null)));

Datei anzeigen

@ -178,7 +178,7 @@ public class VelocityPluginManager implements PluginManager {
}
@Override
public Collection<PluginContainer> getPlugins() {
public Collection<PluginContainer> plugins() {
return Collections.unmodifiableCollection(plugins.values());
}

Datei anzeigen

@ -28,7 +28,7 @@ import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.api.proxy.connection.Player;
import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
import com.velocitypowered.api.proxy.messages.PluginChannelId;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.proxy.server.ServerInfo;
import com.velocitypowered.api.proxy.server.ServerPing;
@ -137,7 +137,7 @@ public class VelocityRegisteredServer implements RegisteredServer, ForwardingAud
}
@Override
public boolean sendPluginMessage(ChannelIdentifier identifier, byte[] data) {
public boolean sendPluginMessage(PluginChannelId identifier, byte[] data) {
return sendPluginMessage(identifier, Unpooled.wrappedBuffer(data));
}
@ -149,7 +149,7 @@ public class VelocityRegisteredServer implements RegisteredServer, ForwardingAud
* @param data the data
* @return whether or not the message was sent
*/
public boolean sendPluginMessage(ChannelIdentifier identifier, ByteBuf data) {
public boolean sendPluginMessage(PluginChannelId identifier, ByteBuf data) {
for (ConnectedPlayer player : players.values()) {
VelocityServerConnection connection = player.getConnectedServer();
if (connection != null && connection.target() == this) {

Datei anzeigen

@ -52,8 +52,7 @@ public enum InformationUtils {
* @return {@link JsonArray} containing zero or more {@link JsonObject}
*/
public static JsonArray collectPluginInfo(ProxyServer proxy) {
List<PluginContainer> allPlugins = ImmutableList.copyOf(
proxy.pluginManager().getPlugins());
List<PluginContainer> allPlugins = ImmutableList.copyOf(proxy.pluginManager().plugins());
JsonArray plugins = new JsonArray();
for (PluginContainer plugin : allPlugins) {
@ -190,7 +189,7 @@ public enum InformationUtils {
if (address instanceof InetSocketAddress) {
InetSocketAddress iaddr = (InetSocketAddress) address;
if (iaddr.isUnresolved()) {
// Greetings form Netty 4aa10db9
// Greetings from Netty 4aa10db9
info.addProperty("host", iaddr.getHostString());
} else {
info.addProperty("host", anonymizeInetAddress(iaddr.getAddress()));

Datei anzeigen

@ -18,55 +18,58 @@
package com.velocitypowered.proxy.util;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
import com.velocitypowered.api.proxy.messages.ChannelRegistrar;
import com.velocitypowered.api.proxy.messages.LegacyChannelIdentifier;
import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier;
import com.velocitypowered.proxy.network.PluginMessageUtil;
import com.velocitypowered.api.proxy.messages.MinecraftPluginChannelId;
import com.velocitypowered.api.proxy.messages.PairedPluginChannelId;
import com.velocitypowered.api.proxy.messages.PluginChannelId;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.checkerframework.checker.nullness.qual.Nullable;
public class VelocityChannelRegistrar implements ChannelRegistrar {
private final Map<String, ChannelIdentifier> identifierMap = new ConcurrentHashMap<>();
private final Map<String, PluginChannelId> byLegacyId = new ConcurrentHashMap<>();
private final Map<String, PluginChannelId> byKey = new ConcurrentHashMap<>();
@Override
public void register(ChannelIdentifier... identifiers) {
for (ChannelIdentifier identifier : identifiers) {
Preconditions.checkArgument(identifier instanceof LegacyChannelIdentifier
|| identifier instanceof MinecraftChannelIdentifier, "identifier is unknown");
public void register(PluginChannelId... identifiers) {
for (PluginChannelId identifier : identifiers) {
Preconditions.checkArgument(identifier instanceof PairedPluginChannelId
|| identifier instanceof MinecraftPluginChannelId, "identifier is unknown");
}
for (ChannelIdentifier identifier : identifiers) {
if (identifier instanceof MinecraftChannelIdentifier) {
identifierMap.put(identifier.id(), identifier);
for (PluginChannelId identifier : identifiers) {
if (identifier instanceof MinecraftPluginChannelId) {
MinecraftPluginChannelId modern = (MinecraftPluginChannelId) identifier;
byLegacyId.put(modern.key().asString(), identifier);
byKey.put(modern.key().asString(), identifier);
} else {
String rewritten = PluginMessageUtil.transformLegacyToModernChannel(identifier.id());
identifierMap.put(identifier.id(), identifier);
identifierMap.put(rewritten, identifier);
PairedPluginChannelId paired = (PairedPluginChannelId) identifier;
byLegacyId.put(paired.legacyChannel(), identifier);
byKey.put(paired.modernChannelKey().asString(), identifier);
}
}
}
@Override
public void unregister(ChannelIdentifier... identifiers) {
for (ChannelIdentifier identifier : identifiers) {
Preconditions.checkArgument(identifier instanceof LegacyChannelIdentifier
|| identifier instanceof MinecraftChannelIdentifier,
public void unregister(PluginChannelId... identifiers) {
for (PluginChannelId identifier : identifiers) {
Preconditions.checkArgument(identifier instanceof PairedPluginChannelId
|| identifier instanceof MinecraftPluginChannelId,
"identifier is unknown");
}
for (ChannelIdentifier identifier : identifiers) {
if (identifier instanceof MinecraftChannelIdentifier) {
identifierMap.remove(identifier.id());
for (PluginChannelId identifier : identifiers) {
if (identifier instanceof MinecraftPluginChannelId) {
MinecraftPluginChannelId modern = (MinecraftPluginChannelId) identifier;
byKey.remove(modern.key().asString(), identifier);
} else {
String rewritten = PluginMessageUtil.transformLegacyToModernChannel(identifier.id());
identifierMap.remove(identifier.id());
identifierMap.remove(rewritten);
PairedPluginChannelId paired = (PairedPluginChannelId) identifier;
byLegacyId.remove(paired.legacyChannel(), identifier);
byKey.remove(paired.modernChannelKey().asString(), identifier);
}
}
}
@ -77,11 +80,7 @@ public class VelocityChannelRegistrar implements ChannelRegistrar {
* @return all legacy channel IDs
*/
public Collection<String> getLegacyChannelIds() {
Collection<String> ids = new HashSet<>();
for (ChannelIdentifier value : identifierMap.values()) {
ids.add(value.id());
}
return ids;
return ImmutableSet.copyOf(this.byLegacyId.keySet());
}
/**
@ -90,19 +89,14 @@ public class VelocityChannelRegistrar implements ChannelRegistrar {
* @return the channel IDs for Minecraft 1.13 and above
*/
public Collection<String> getModernChannelIds() {
Collection<String> ids = new HashSet<>();
for (ChannelIdentifier value : identifierMap.values()) {
if (value instanceof MinecraftChannelIdentifier) {
ids.add(value.id());
} else {
ids.add(PluginMessageUtil.transformLegacyToModernChannel(value.id()));
}
}
return ids;
return ImmutableSet.copyOf(this.byKey.keySet());
}
public @Nullable ChannelIdentifier getFromId(String id) {
return identifierMap.get(id);
public @Nullable PluginChannelId getFromId(String id) {
if (id.indexOf(':') >= 0) {
return byKey.get(id);
}
return byLegacyId.get(id);
}
/**

Datei anzeigen

@ -138,13 +138,12 @@ public class AdventureBossBarManager implements BossBar.Listener {
}
@Override
public void bossBarPercentChanged(@NonNull BossBar bar, float oldPercent, float newPercent) {
public void bossBarProgressChanged(@NonNull BossBar bar, float oldProgress, float newProgress) {
BossBarHolder holder = this.getHandler(bar);
if (holder == null) {
return;
}
ClientboundBossBarPacket packet = holder
.createPercentUpdate(newPercent);
ClientboundBossBarPacket packet = holder.createPercentUpdate(newProgress);
for (ConnectedPlayer player : holder.subscribers) {
player.getConnection().write(packet);
}
@ -170,8 +169,7 @@ public class AdventureBossBarManager implements BossBar.Listener {
if (holder == null) {
return;
}
ClientboundBossBarPacket packet = holder
.createOverlayUpdate(newOverlay);
ClientboundBossBarPacket packet = holder.createOverlayUpdate(newOverlay);
for (ConnectedPlayer player : holder.subscribers) {
player.getConnection().write(packet);
}

Datei anzeigen

@ -39,7 +39,7 @@ public class MockPluginManager implements PluginManager {
}
@Override
public Collection<PluginContainer> getPlugins() {
public Collection<PluginContainer> plugins() {
return ImmutableList.of();
}

Datei anzeigen

@ -58,7 +58,7 @@ public class FakePluginManager implements PluginManager {
}
@Override
public @NonNull Collection<PluginContainer> getPlugins() {
public @NonNull Collection<PluginContainer> plugins() {
return ImmutableList.of(PC_A, PC_B);
}

Datei anzeigen

@ -20,23 +20,18 @@ package com.velocitypowered.proxy.util;
import static org.junit.jupiter.api.Assertions.assertEquals;
import com.google.common.collect.ImmutableSet;
import com.velocitypowered.api.proxy.messages.LegacyChannelIdentifier;
import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier;
import com.velocitypowered.api.proxy.messages.MinecraftPluginChannelId;
import com.velocitypowered.api.proxy.messages.PairedPluginChannelId;
import com.velocitypowered.api.proxy.messages.PluginChannelId;
import net.kyori.adventure.key.Key;
import org.junit.jupiter.api.Test;
class VelocityChannelRegistrarTest {
private static final MinecraftChannelIdentifier MODERN = MinecraftChannelIdentifier
.create("velocity", "test");
private static final LegacyChannelIdentifier SIMPLE_LEGACY =
new LegacyChannelIdentifier("VelocityTest");
private static final MinecraftChannelIdentifier MODERN_SPECIAL_REMAP = MinecraftChannelIdentifier
.create("bungeecord", "main");
private static final LegacyChannelIdentifier SPECIAL_REMAP_LEGACY =
new LegacyChannelIdentifier("BungeeCord");
private static final String SIMPLE_LEGACY_REMAPPED = "legacy:velocitytest";
private static final MinecraftPluginChannelId MODERN = PluginChannelId.wrap(
Key.key("velocity", "moderntest"));
private static final PairedPluginChannelId SIMPLE_LEGACY =
PluginChannelId.withLegacy("VelocityTest", Key.key("velocity", "test"));
@Test
void register() {
@ -45,30 +40,21 @@ class VelocityChannelRegistrarTest {
// Two channels cover the modern channel (velocity:test) and the legacy-mapped channel
// (legacy:velocitytest). Make sure they're what we expect.
assertEquals(ImmutableSet.of(MODERN.id(), SIMPLE_LEGACY_REMAPPED), registrar
.getModernChannelIds());
assertEquals(ImmutableSet.of(SIMPLE_LEGACY.id(), MODERN.id()), registrar
assertEquals(
ImmutableSet.of(MODERN.key().asString(), SIMPLE_LEGACY.modernChannelKey().asString()),
registrar.getModernChannelIds());
assertEquals(
ImmutableSet.of(SIMPLE_LEGACY.legacyChannel(), MODERN.key().asString()), registrar
.getLegacyChannelIds());
}
@Test
void registerSpecialRewrite() {
VelocityChannelRegistrar registrar = new VelocityChannelRegistrar();
registrar.register(SPECIAL_REMAP_LEGACY, MODERN_SPECIAL_REMAP);
// This one, just one channel for the modern case.
assertEquals(ImmutableSet.of(MODERN_SPECIAL_REMAP.id()), registrar.getModernChannelIds());
assertEquals(ImmutableSet.of(MODERN_SPECIAL_REMAP.id(), SPECIAL_REMAP_LEGACY.id()),
registrar.getLegacyChannelIds());
}
@Test
void unregister() {
VelocityChannelRegistrar registrar = new VelocityChannelRegistrar();
registrar.register(MODERN, SIMPLE_LEGACY);
registrar.register(MODERN);
registrar.unregister(SIMPLE_LEGACY);
assertEquals(ImmutableSet.of(MODERN.id()), registrar.getModernChannelIds());
assertEquals(ImmutableSet.of(MODERN.id()), registrar.getLegacyChannelIds());
assertEquals(ImmutableSet.of(MODERN.key().asString()), registrar.getModernChannelIds());
assertEquals(ImmutableSet.of(MODERN.key().asString()), registrar.getLegacyChannelIds());
}
}