mirror of
https://github.com/PaperMC/Velocity.git
synced 2026-02-17 14:37:43 +01:00
Merge branch 'dev/2.0.0' into 2/new-registry
This commit is contained in:
@@ -5,9 +5,14 @@ plugins {
|
||||
id 'checkstyle'
|
||||
}
|
||||
|
||||
apply plugin: 'org.cadixdev.licenser'
|
||||
apply from: '../gradle/checkstyle.gradle'
|
||||
apply plugin: 'com.github.johnrengelman.shadow'
|
||||
|
||||
license {
|
||||
header = project.rootProject.file('HEADER.txt')
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
@@ -32,6 +37,7 @@ jar {
|
||||
attributes 'Implementation-Version': version
|
||||
attributes 'Implementation-Vendor': "Velocity Contributors"
|
||||
attributes 'Multi-Release': 'true'
|
||||
attributes 'Add-Opens': 'java.base/java.lang'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy;
|
||||
|
||||
import com.velocitypowered.proxy.config.VelocityConfiguration;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
@@ -9,7 +25,6 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bstats.MetricsBase;
|
||||
@@ -88,17 +103,17 @@ public class Metrics {
|
||||
Metrics metrics = new Metrics(logger, 4752, metricsConfig.isEnabled());
|
||||
|
||||
metrics.addCustomChart(
|
||||
new SingleLineChart("players", server::getPlayerCount)
|
||||
new SingleLineChart("players", server::countConnectedPlayers)
|
||||
);
|
||||
metrics.addCustomChart(
|
||||
new SingleLineChart("managed_servers", () -> server.getAllServers().size())
|
||||
new SingleLineChart("managed_servers", () -> server.registeredServers().size())
|
||||
);
|
||||
metrics.addCustomChart(
|
||||
new SimplePie("online_mode",
|
||||
() -> server.getConfiguration().isOnlineMode() ? "online" : "offline")
|
||||
() -> server.configuration().isOnlineMode() ? "online" : "offline")
|
||||
);
|
||||
metrics.addCustomChart(new SimplePie("velocity_version",
|
||||
() -> server.getVersion().getVersion()));
|
||||
() -> server.version().getVersion()));
|
||||
|
||||
metrics.addCustomChart(new DrilldownPie("java_version", () -> {
|
||||
Map<String, Map<String, Integer>> map = new HashMap<>();
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy;
|
||||
|
||||
import io.netty.util.ResourceLeakDetector;
|
||||
@@ -67,7 +84,7 @@ public class Velocity {
|
||||
|
||||
double bootTime = (System.currentTimeMillis() - startTime) / 1000d;
|
||||
logger.info("Done ({}s)!", new DecimalFormat("#.##").format(bootTime));
|
||||
server.getConsoleCommandSource().start();
|
||||
server.consoleCommandSource().start();
|
||||
|
||||
// If we don't have a console available (because SimpleTerminalConsole returned), then we still
|
||||
// need to wait, otherwise the JVM will reap us as no non-daemon threads will be active once the
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
@@ -6,9 +23,9 @@ import com.google.common.collect.ImmutableList;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.velocitypowered.api.event.EventManager;
|
||||
import com.velocitypowered.api.event.lifecycle.ProxyInitializeEvent;
|
||||
import com.velocitypowered.api.event.lifecycle.ProxyReloadEvent;
|
||||
import com.velocitypowered.api.event.lifecycle.ProxyShutdownEvent;
|
||||
import com.velocitypowered.api.event.lifecycle.ProxyInitializeEventImpl;
|
||||
import com.velocitypowered.api.event.lifecycle.ProxyReloadEventImpl;
|
||||
import com.velocitypowered.api.event.lifecycle.ProxyShutdownEventImpl;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.api.plugin.PluginContainer;
|
||||
import com.velocitypowered.api.plugin.PluginManager;
|
||||
@@ -37,6 +54,7 @@ import com.velocitypowered.proxy.scheduler.VelocityScheduler;
|
||||
import com.velocitypowered.proxy.server.ServerMap;
|
||||
import com.velocitypowered.proxy.util.AddressUtil;
|
||||
import com.velocitypowered.proxy.util.EncryptionUtils;
|
||||
import com.velocitypowered.proxy.util.FileSystemUtils;
|
||||
import com.velocitypowered.proxy.util.VelocityChannelRegistrar;
|
||||
import com.velocitypowered.proxy.util.bossbar.AdventureBossBarManager;
|
||||
import com.velocitypowered.proxy.util.ratelimit.Ratelimiter;
|
||||
@@ -61,6 +79,7 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@@ -73,7 +92,11 @@ import java.util.function.IntFunction;
|
||||
import java.util.stream.Collectors;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.audience.ForwardingAudience;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.translation.GlobalTranslator;
|
||||
import net.kyori.adventure.translation.TranslationRegistry;
|
||||
import net.kyori.adventure.util.UTF8ResourceBundleControl;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.asynchttpclient.AsyncHttpClient;
|
||||
@@ -138,12 +161,12 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
|
||||
}
|
||||
|
||||
@Override
|
||||
public VelocityConfiguration getConfiguration() {
|
||||
public VelocityConfiguration configuration() {
|
||||
return this.configuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProxyVersion getVersion() {
|
||||
public ProxyVersion version() {
|
||||
Package pkg = VelocityServer.class.getPackage();
|
||||
String implName;
|
||||
String implVersion;
|
||||
@@ -162,7 +185,7 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
|
||||
}
|
||||
|
||||
@Override
|
||||
public VelocityCommandManager getCommandManager() {
|
||||
public VelocityCommandManager commandManager() {
|
||||
return commandManager;
|
||||
}
|
||||
|
||||
@@ -173,9 +196,11 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
|
||||
@EnsuresNonNull({"serverKeyPair", "servers", "pluginManager", "eventManager", "scheduler",
|
||||
"console", "cm", "configuration"})
|
||||
void start() {
|
||||
logger.info("Booting up {} {}...", getVersion().getName(), getVersion().getVersion());
|
||||
logger.info("Booting up {} {}...", version().getName(), version().getVersion());
|
||||
console.setupStreams();
|
||||
|
||||
registerTranslations();
|
||||
|
||||
serverKeyPair = EncryptionUtils.createRsaKeyPair(1024);
|
||||
|
||||
cm.logChannelInformation();
|
||||
@@ -197,7 +222,7 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
|
||||
|
||||
// Go ahead and fire the proxy initialization event. We block since plugins should have a chance
|
||||
// to fully initialize before we accept any connections to the server.
|
||||
eventManager.fire(new ProxyInitializeEvent()).join();
|
||||
eventManager.fire(new ProxyInitializeEventImpl()).join();
|
||||
|
||||
// init console permissions after plugins are loaded
|
||||
console.setupPermissions();
|
||||
@@ -219,6 +244,47 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
|
||||
Metrics.VelocityMetrics.startMetrics(this, configuration.getMetrics());
|
||||
}
|
||||
|
||||
private void registerTranslations() {
|
||||
final TranslationRegistry translationRegistry = TranslationRegistry
|
||||
.create(Key.key("velocity", "translations"));
|
||||
translationRegistry.defaultLocale(Locale.US);
|
||||
try {
|
||||
FileSystemUtils.visitResources(VelocityServer.class, path -> {
|
||||
logger.info("Loading localizations...");
|
||||
|
||||
try {
|
||||
Files.walk(path).forEach(file -> {
|
||||
if (!Files.isRegularFile(file)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String filename = com.google.common.io.Files
|
||||
.getNameWithoutExtension(file.getFileName().toString());
|
||||
String localeName = filename.replace("messages_", "")
|
||||
.replace("messages", "")
|
||||
.replace('_', '-');
|
||||
Locale locale;
|
||||
if (localeName.isEmpty()) {
|
||||
locale = Locale.US;
|
||||
} else {
|
||||
locale = Locale.forLanguageTag(localeName);
|
||||
}
|
||||
|
||||
translationRegistry.registerAll(locale,
|
||||
ResourceBundle.getBundle("com/velocitypowered/proxy/l10n/messages",
|
||||
locale, UTF8ResourceBundleControl.get()), false);
|
||||
});
|
||||
} catch (IOException e) {
|
||||
logger.error("Encountered an I/O error whilst loading translations", e);
|
||||
}
|
||||
}, "com", "velocitypowered", "proxy", "l10n");
|
||||
} catch (IOException e) {
|
||||
logger.error("Encountered an I/O error whilst loading translations", e);
|
||||
return;
|
||||
}
|
||||
GlobalTranslator.get().addSource(translationRegistry);
|
||||
}
|
||||
|
||||
@SuppressFBWarnings("DM_EXIT")
|
||||
private void doStartupConfigLoad() {
|
||||
try {
|
||||
@@ -260,19 +326,19 @@ 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()) {
|
||||
Optional<?> instance = plugin.getInstance();
|
||||
for (PluginContainer plugin : pluginManager.plugins()) {
|
||||
Optional<?> instance = plugin.instance();
|
||||
if (instance.isPresent()) {
|
||||
try {
|
||||
eventManager.register(instance.get(), instance.get());
|
||||
eventManager.registerInternally(plugin, instance.get());
|
||||
} catch (Exception e) {
|
||||
logger.error("Unable to register plugin listener for {}",
|
||||
plugin.getDescription().getName().orElse(plugin.getDescription().getId()), e);
|
||||
plugin.description().name().orElse(plugin.description().id()), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Loaded {} plugins", pluginManager.getPlugins().size());
|
||||
logger.info("Loaded {} plugins", pluginManager.plugins().size());
|
||||
}
|
||||
|
||||
public Bootstrap createBootstrap(@Nullable EventLoopGroup group, SocketAddress target) {
|
||||
@@ -310,15 +376,15 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
|
||||
Optional<RegisteredServer> rs = servers.getServer(entry.getKey());
|
||||
if (!rs.isPresent()) {
|
||||
servers.register(newInfo);
|
||||
} else if (!rs.get().getServerInfo().equals(newInfo)) {
|
||||
for (Player player : rs.get().getPlayersConnected()) {
|
||||
} else if (!rs.get().serverInfo().equals(newInfo)) {
|
||||
for (Player player : rs.get().connectedPlayers()) {
|
||||
if (!(player instanceof ConnectedPlayer)) {
|
||||
throw new IllegalStateException("ConnectedPlayer not found for player " + player
|
||||
+ " in server " + rs.get().getServerInfo().getName());
|
||||
+ " in server " + rs.get().serverInfo().name());
|
||||
}
|
||||
evacuate.add((ConnectedPlayer) player);
|
||||
}
|
||||
servers.unregister(rs.get().getServerInfo());
|
||||
servers.unregister(rs.get().serverInfo());
|
||||
servers.register(newInfo);
|
||||
}
|
||||
}
|
||||
@@ -373,7 +439,7 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
|
||||
|
||||
ipAttemptLimiter = Ratelimiters.createWithMilliseconds(newConfiguration.getLoginRatelimit());
|
||||
this.configuration = newConfiguration;
|
||||
eventManager.fireAndForget(new ProxyReloadEvent());
|
||||
eventManager.fireAndForget(new ProxyReloadEventImpl());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -424,7 +490,7 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
|
||||
}
|
||||
|
||||
try {
|
||||
eventManager.fire(new ProxyShutdownEvent()).get(10, TimeUnit.SECONDS);
|
||||
eventManager.fire(new ProxyShutdownEventImpl()).get(10, TimeUnit.SECONDS);
|
||||
} catch (TimeoutException e) {
|
||||
timedOut = true;
|
||||
} catch (ExecutionException e) {
|
||||
@@ -501,9 +567,9 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
|
||||
if (configuration.isOnlineMode() && configuration.isOnlineModeKickExistingPlayers()) {
|
||||
return true;
|
||||
}
|
||||
String lowerName = connection.getUsername().toLowerCase(Locale.US);
|
||||
String lowerName = connection.username().toLowerCase(Locale.US);
|
||||
return !(connectionsByName.containsKey(lowerName)
|
||||
|| connectionsByUuid.containsKey(connection.getUniqueId()));
|
||||
|| connectionsByUuid.containsKey(connection.id()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -512,25 +578,25 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
|
||||
* @return {@code true} if we registered the connection, {@code false} if not
|
||||
*/
|
||||
public boolean registerConnection(ConnectedPlayer connection) {
|
||||
String lowerName = connection.getUsername().toLowerCase(Locale.US);
|
||||
String lowerName = connection.username().toLowerCase(Locale.US);
|
||||
|
||||
if (!this.configuration.isOnlineModeKickExistingPlayers()) {
|
||||
if (connectionsByName.putIfAbsent(lowerName, connection) != null) {
|
||||
return false;
|
||||
}
|
||||
if (connectionsByUuid.putIfAbsent(connection.getUniqueId(), connection) != null) {
|
||||
if (connectionsByUuid.putIfAbsent(connection.id(), connection) != null) {
|
||||
connectionsByName.remove(lowerName, connection);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
ConnectedPlayer existing = connectionsByUuid.get(connection.getUniqueId());
|
||||
ConnectedPlayer existing = connectionsByUuid.get(connection.id());
|
||||
if (existing != null) {
|
||||
existing.disconnect(Component.translatable("multiplayer.disconnect.duplicate_login"));
|
||||
}
|
||||
|
||||
// We can now replace the entries as needed.
|
||||
connectionsByName.put(lowerName, connection);
|
||||
connectionsByUuid.put(connection.getUniqueId(), connection);
|
||||
connectionsByUuid.put(connection.id(), connection);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -541,8 +607,8 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
|
||||
* @param connection the connection to unregister
|
||||
*/
|
||||
public void unregisterConnection(ConnectedPlayer connection) {
|
||||
connectionsByName.remove(connection.getUsername().toLowerCase(Locale.US), connection);
|
||||
connectionsByUuid.remove(connection.getUniqueId(), connection);
|
||||
connectionsByName.remove(connection.username().toLowerCase(Locale.US), connection);
|
||||
connectionsByUuid.remove(connection.id(), connection);
|
||||
bossBarManager.onDisconnect(connection);
|
||||
}
|
||||
|
||||
@@ -562,7 +628,7 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
|
||||
public Collection<Player> matchPlayer(String partialName) {
|
||||
Objects.requireNonNull(partialName);
|
||||
|
||||
return getAllPlayers().stream().filter(p -> p.getUsername()
|
||||
return connectedPlayers().stream().filter(p -> p.username()
|
||||
.regionMatches(true, 0, partialName, 0, partialName.length()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
@@ -571,28 +637,28 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
|
||||
public Collection<RegisteredServer> matchServer(String partialName) {
|
||||
Objects.requireNonNull(partialName);
|
||||
|
||||
return getAllServers().stream().filter(s -> s.getServerInfo().getName()
|
||||
return registeredServers().stream().filter(s -> s.serverInfo().name()
|
||||
.regionMatches(true, 0, partialName, 0, partialName.length()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Player> getAllPlayers() {
|
||||
public Collection<Player> connectedPlayers() {
|
||||
return ImmutableList.copyOf(connectionsByUuid.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPlayerCount() {
|
||||
public int countConnectedPlayers() {
|
||||
return connectionsByUuid.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<RegisteredServer> getServer(String name) {
|
||||
public Optional<RegisteredServer> server(String name) {
|
||||
return servers.getServer(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<RegisteredServer> getAllServers() {
|
||||
public Collection<RegisteredServer> registeredServers() {
|
||||
return servers.getAllServers();
|
||||
}
|
||||
|
||||
@@ -607,44 +673,35 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
|
||||
}
|
||||
|
||||
@Override
|
||||
public VelocityConsole getConsoleCommandSource() {
|
||||
public VelocityConsole consoleCommandSource() {
|
||||
return console;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginManager getPluginManager() {
|
||||
public PluginManager pluginManager() {
|
||||
return pluginManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventManager getEventManager() {
|
||||
public EventManager eventManager() {
|
||||
return eventManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VelocityScheduler getScheduler() {
|
||||
public VelocityScheduler scheduler() {
|
||||
return scheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VelocityChannelRegistrar getChannelRegistrar() {
|
||||
public VelocityChannelRegistrar channelRegistrar() {
|
||||
return channelRegistrar;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocketAddress getBoundAddress() {
|
||||
if (configuration == null) {
|
||||
throw new IllegalStateException(
|
||||
"No configuration"); // even though you'll never get the chance... heh, heh
|
||||
}
|
||||
return configuration.getBind();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Iterable<? extends Audience> audiences() {
|
||||
Collection<Audience> audiences = new ArrayList<>(this.getPlayerCount() + 1);
|
||||
Collection<Audience> audiences = new ArrayList<>(this.countConnectedPlayers() + 1);
|
||||
audiences.add(this.console);
|
||||
audiences.addAll(this.getAllPlayers());
|
||||
audiences.addAll(this.connectedPlayers());
|
||||
return audiences;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.command;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.command;
|
||||
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.command;
|
||||
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.command;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
@@ -17,6 +34,7 @@ import com.velocitypowered.api.command.RawCommand;
|
||||
import com.velocitypowered.api.command.SimpleCommand;
|
||||
import com.velocitypowered.api.event.command.CommandExecuteEvent;
|
||||
import com.velocitypowered.api.event.command.CommandExecuteEvent.CommandResult;
|
||||
import com.velocitypowered.api.event.command.CommandExecuteEventImpl;
|
||||
import com.velocitypowered.proxy.event.VelocityEventManager;
|
||||
import com.velocitypowered.proxy.util.BrigadierUtils;
|
||||
import java.util.Iterator;
|
||||
@@ -38,13 +56,13 @@ public class VelocityCommandManager implements CommandManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandMeta.Builder metaBuilder(final String alias) {
|
||||
public CommandMeta.Builder createMetaBuilder(final String alias) {
|
||||
Preconditions.checkNotNull(alias, "alias");
|
||||
return new VelocityCommandMeta.Builder(alias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandMeta.Builder metaBuilder(final BrigadierCommand command) {
|
||||
public CommandMeta.Builder createMetaBuilder(final BrigadierCommand command) {
|
||||
Preconditions.checkNotNull(command, "command");
|
||||
return new VelocityCommandMeta.Builder(command.getNode().getName());
|
||||
}
|
||||
@@ -52,7 +70,7 @@ public class VelocityCommandManager implements CommandManager {
|
||||
@Override
|
||||
public void register(final BrigadierCommand command) {
|
||||
Preconditions.checkNotNull(command, "command");
|
||||
register(metaBuilder(command).build(), command);
|
||||
register(createMetaBuilder(command).build(), command);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -60,7 +78,7 @@ public class VelocityCommandManager implements CommandManager {
|
||||
Preconditions.checkNotNull(meta, "meta");
|
||||
Preconditions.checkNotNull(command, "command");
|
||||
|
||||
Iterator<String> aliasIterator = meta.getAliases().iterator();
|
||||
Iterator<String> aliasIterator = meta.aliases().iterator();
|
||||
String primaryAlias = aliasIterator.next();
|
||||
|
||||
LiteralCommandNode<CommandSource> node = null;
|
||||
@@ -76,7 +94,7 @@ public class VelocityCommandManager implements CommandManager {
|
||||
}
|
||||
|
||||
if (!(command instanceof BrigadierCommand)) {
|
||||
for (CommandNode<CommandSource> hint : meta.getHints()) {
|
||||
for (CommandNode<CommandSource> hint : meta.hints()) {
|
||||
node.addChild(BrigadierUtils.wrapForHinting(hint, node.getCommand()));
|
||||
}
|
||||
}
|
||||
@@ -100,7 +118,7 @@ public class VelocityCommandManager implements CommandManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires a {@link CommandExecuteEvent}.
|
||||
* Fires a {@link CommandExecuteEventImpl}.
|
||||
*
|
||||
* @param source the source to execute the command for
|
||||
* @param cmdLine the command to execute
|
||||
@@ -110,7 +128,7 @@ public class VelocityCommandManager implements CommandManager {
|
||||
final String cmdLine) {
|
||||
Preconditions.checkNotNull(source, "source");
|
||||
Preconditions.checkNotNull(cmdLine, "cmdLine");
|
||||
return eventManager.fire(new CommandExecuteEvent(source, cmdLine));
|
||||
return eventManager.fire(new CommandExecuteEventImpl(source, cmdLine));
|
||||
}
|
||||
|
||||
private boolean executeImmediately0(final CommandSource source, final String cmdLine) {
|
||||
@@ -142,11 +160,11 @@ public class VelocityCommandManager implements CommandManager {
|
||||
Preconditions.checkNotNull(cmdLine, "cmdLine");
|
||||
|
||||
return callCommandEvent(source, cmdLine).thenApplyAsync(event -> {
|
||||
CommandResult commandResult = event.getResult();
|
||||
CommandResult commandResult = event.result();
|
||||
if (commandResult.isForwardToServer() || !commandResult.isAllowed()) {
|
||||
return false;
|
||||
}
|
||||
return executeImmediately0(source, commandResult.getCommand().orElse(event.getCommand()));
|
||||
return executeImmediately0(source, commandResult.modifiedCommand().orElse(event.rawCommand()));
|
||||
}, eventManager.getAsyncExecutor());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.command;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
@@ -59,12 +76,12 @@ final class VelocityCommandMeta implements CommandMeta {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getAliases() {
|
||||
public Collection<String> aliases() {
|
||||
return aliases;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<CommandNode<CommandSource>> getHints() {
|
||||
public Collection<CommandNode<CommandSource>> hints() {
|
||||
return hints;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.command;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.command;
|
||||
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.command.builtin;
|
||||
|
||||
import com.velocitypowered.api.proxy.ProxyServer;
|
||||
@@ -14,8 +31,8 @@ class BuiltinCommandUtil {
|
||||
}
|
||||
|
||||
static List<RegisteredServer> sortedServerList(ProxyServer proxy) {
|
||||
List<RegisteredServer> servers = new ArrayList<>(proxy.getAllServers());
|
||||
servers.sort(Comparator.comparing(RegisteredServer::getServerInfo));
|
||||
List<RegisteredServer> servers = new ArrayList<>(proxy.registeredServers());
|
||||
servers.sort(Comparator.comparing(RegisteredServer::serverInfo));
|
||||
return Collections.unmodifiableList(servers);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.command.builtin;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TranslatableComponent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
public class CommandMessages {
|
||||
|
||||
public static final TranslatableComponent PLAYERS_ONLY = Component.translatable(
|
||||
"velocity.command.players-only", NamedTextColor.RED);
|
||||
public static final TranslatableComponent SERVER_DOES_NOT_EXIST = Component.translatable(
|
||||
"velocity.command.server-does-not-exist", NamedTextColor.RED);
|
||||
}
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.command.builtin;
|
||||
|
||||
import static com.mojang.brigadier.arguments.StringArgumentType.getString;
|
||||
@@ -20,6 +37,7 @@ import java.util.Optional;
|
||||
import net.kyori.adventure.identity.Identity;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.TranslatableComponent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
public class GlistCommand {
|
||||
@@ -39,14 +57,14 @@ public class GlistCommand {
|
||||
LiteralCommandNode<CommandSource> totalNode = LiteralArgumentBuilder
|
||||
.<CommandSource>literal("glist")
|
||||
.requires(source ->
|
||||
source.getPermissionValue("velocity.command.glist") == Tristate.TRUE)
|
||||
source.evaluatePermission("velocity.command.glist") == Tristate.TRUE)
|
||||
.executes(this::totalCount)
|
||||
.build();
|
||||
ArgumentCommandNode<CommandSource, String> serverNode = RequiredArgumentBuilder
|
||||
.<CommandSource, String>argument(SERVER_ARG, StringArgumentType.string())
|
||||
.suggests((context, builder) -> {
|
||||
for (RegisteredServer server : server.getAllServers()) {
|
||||
builder.suggest(server.getServerInfo().getName());
|
||||
for (RegisteredServer server : server.registeredServers()) {
|
||||
builder.suggest(server.serverInfo().name());
|
||||
}
|
||||
builder.suggest("all");
|
||||
return builder.buildFuture();
|
||||
@@ -54,18 +72,14 @@ public class GlistCommand {
|
||||
.executes(this::serverCount)
|
||||
.build();
|
||||
totalNode.addChild(serverNode);
|
||||
server.getCommandManager().register(new BrigadierCommand(totalNode));
|
||||
server.commandManager().register(new BrigadierCommand(totalNode));
|
||||
}
|
||||
|
||||
private int totalCount(final CommandContext<CommandSource> context) {
|
||||
final CommandSource source = context.getSource();
|
||||
sendTotalProxyCount(source);
|
||||
source.sendMessage(Identity.nil(),
|
||||
Component.text().content("To view all players on servers, use ")
|
||||
.color(NamedTextColor.YELLOW)
|
||||
.append(Component.text("/glist all", NamedTextColor.DARK_AQUA))
|
||||
.append(Component.text(".", NamedTextColor.YELLOW))
|
||||
.build());
|
||||
Component.translatable("velocity.command.glist-view-all", NamedTextColor.YELLOW));
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -78,10 +92,10 @@ public class GlistCommand {
|
||||
}
|
||||
sendTotalProxyCount(source);
|
||||
} else {
|
||||
Optional<RegisteredServer> registeredServer = server.getServer(serverName);
|
||||
Optional<RegisteredServer> registeredServer = server.server(serverName);
|
||||
if (!registeredServer.isPresent()) {
|
||||
source.sendMessage(Identity.nil(),
|
||||
Component.text("Server " + serverName + " doesn't exist.", NamedTextColor.RED));
|
||||
CommandMessages.SERVER_DOES_NOT_EXIST.args(Component.text(serverName)));
|
||||
return -1;
|
||||
}
|
||||
sendServerPlayers(source, registeredServer.get(), false);
|
||||
@@ -90,21 +104,22 @@ public class GlistCommand {
|
||||
}
|
||||
|
||||
private void sendTotalProxyCount(CommandSource target) {
|
||||
target.sendMessage(Identity.nil(), Component.text()
|
||||
.content("There are ").color(NamedTextColor.YELLOW)
|
||||
.append(Component.text(server.getAllPlayers().size(), NamedTextColor.GREEN))
|
||||
.append(Component.text(" player(s) online.", NamedTextColor.YELLOW))
|
||||
.build());
|
||||
int online = server.countConnectedPlayers();
|
||||
TranslatableComponent msg = online == 1
|
||||
? Component.translatable("velocity.command.glist-player-singular")
|
||||
: Component.translatable("velocity.command.glist-player-plural");
|
||||
target.sendMessage(msg.color(NamedTextColor.YELLOW)
|
||||
.args(Component.text(Integer.toString(online), NamedTextColor.GREEN)));
|
||||
}
|
||||
|
||||
private void sendServerPlayers(CommandSource target, RegisteredServer server, boolean fromAll) {
|
||||
List<Player> onServer = ImmutableList.copyOf(server.getPlayersConnected());
|
||||
List<Player> onServer = ImmutableList.copyOf(server.connectedPlayers());
|
||||
if (onServer.isEmpty() && fromAll) {
|
||||
return;
|
||||
}
|
||||
|
||||
TextComponent.Builder builder = Component.text()
|
||||
.append(Component.text("[" + server.getServerInfo().getName() + "] ",
|
||||
.append(Component.text("[" + server.serverInfo().name() + "] ",
|
||||
NamedTextColor.DARK_AQUA))
|
||||
.append(Component.text("(" + onServer.size() + ")", NamedTextColor.GRAY))
|
||||
.append(Component.text(": "))
|
||||
@@ -112,7 +127,7 @@ public class GlistCommand {
|
||||
|
||||
for (int i = 0; i < onServer.size(); i++) {
|
||||
Player player = onServer.get(i);
|
||||
builder.append(Component.text(player.getUsername()));
|
||||
builder.append(Component.text(player.username()));
|
||||
|
||||
if (i + 1 < onServer.size()) {
|
||||
builder.append(Component.text(", "));
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.command.builtin;
|
||||
|
||||
import static net.kyori.adventure.text.event.HoverEvent.showText;
|
||||
@@ -18,6 +35,7 @@ import java.util.stream.Stream;
|
||||
import net.kyori.adventure.identity.Identity;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.TranslatableComponent;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
@@ -36,8 +54,7 @@ public class ServerCommand implements SimpleCommand {
|
||||
final String[] args = invocation.arguments();
|
||||
|
||||
if (!(source instanceof Player)) {
|
||||
source.sendMessage(Identity.nil(), Component.text("Only players may run this command.",
|
||||
NamedTextColor.RED));
|
||||
source.sendMessage(Identity.nil(), CommandMessages.PLAYERS_ONLY);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -45,10 +62,10 @@ public class ServerCommand implements SimpleCommand {
|
||||
if (args.length == 1) {
|
||||
// Trying to connect to a server.
|
||||
String serverName = args[0];
|
||||
Optional<RegisteredServer> toConnect = server.getServer(serverName);
|
||||
Optional<RegisteredServer> toConnect = server.server(serverName);
|
||||
if (!toConnect.isPresent()) {
|
||||
player.sendMessage(Identity.nil(),
|
||||
Component.text("Server " + serverName + " doesn't exist.", NamedTextColor.RED));
|
||||
player.sendMessage(Identity.nil(), CommandMessages.SERVER_DOES_NOT_EXIST
|
||||
.args(Component.text(serverName)));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -59,21 +76,25 @@ public class ServerCommand implements SimpleCommand {
|
||||
}
|
||||
|
||||
private void outputServerInformation(Player executor) {
|
||||
String currentServer = executor.getCurrentServer().map(ServerConnection::getServerInfo)
|
||||
.map(ServerInfo::getName).orElse("<unknown>");
|
||||
executor.sendMessage(Identity.nil(), Component.text(
|
||||
"You are currently connected to " + currentServer + ".", NamedTextColor.YELLOW));
|
||||
String currentServer = executor.connectedServer().map(ServerConnection::serverInfo)
|
||||
.map(ServerInfo::name).orElse("<unknown>");
|
||||
executor.sendMessage(Identity.nil(), Component.translatable(
|
||||
"velocity.command.server-current-server",
|
||||
NamedTextColor.YELLOW,
|
||||
Component.text(currentServer)));
|
||||
|
||||
List<RegisteredServer> servers = BuiltinCommandUtil.sortedServerList(server);
|
||||
if (servers.size() > MAX_SERVERS_TO_LIST) {
|
||||
executor.sendMessage(Identity.nil(), Component.text(
|
||||
"Too many servers to list. Tab-complete to show all servers.", NamedTextColor.RED));
|
||||
executor.sendMessage(Identity.nil(), Component.translatable(
|
||||
"velocity.command.server-too-many", NamedTextColor.RED));
|
||||
return;
|
||||
}
|
||||
|
||||
// Assemble the list of servers as components
|
||||
TextComponent.Builder serverListBuilder = Component.text().content("Available servers: ")
|
||||
.color(NamedTextColor.YELLOW);
|
||||
TextComponent.Builder serverListBuilder = Component.text()
|
||||
.append(Component.translatable("velocity.command.server-available",
|
||||
NamedTextColor.YELLOW))
|
||||
.append(Component.space());
|
||||
for (int i = 0; i < servers.size(); i++) {
|
||||
RegisteredServer rs = servers.get(i);
|
||||
serverListBuilder.append(formatServerComponent(currentServer, rs));
|
||||
@@ -86,20 +107,34 @@ public class ServerCommand implements SimpleCommand {
|
||||
}
|
||||
|
||||
private TextComponent formatServerComponent(String currentPlayerServer, RegisteredServer server) {
|
||||
ServerInfo serverInfo = server.getServerInfo();
|
||||
TextComponent serverTextComponent = Component.text(serverInfo.getName());
|
||||
ServerInfo serverInfo = server.serverInfo();
|
||||
TextComponent serverTextComponent = Component.text(serverInfo.name());
|
||||
|
||||
String playersText = server.getPlayersConnected().size() + " player(s) online";
|
||||
if (serverInfo.getName().equals(currentPlayerServer)) {
|
||||
int connectedPlayers = server.connectedPlayers().size();
|
||||
TranslatableComponent playersTextComponent;
|
||||
if (connectedPlayers == 1) {
|
||||
playersTextComponent = Component.translatable("velocity.command.server-tooltip-player-online");
|
||||
} else {
|
||||
playersTextComponent = Component.translatable("velocity.command.server-tooltip-players-online");
|
||||
}
|
||||
playersTextComponent = playersTextComponent.args(Component.text(connectedPlayers));
|
||||
|
||||
if (serverInfo.name().equals(currentPlayerServer)) {
|
||||
serverTextComponent = serverTextComponent.color(NamedTextColor.GREEN)
|
||||
.hoverEvent(
|
||||
showText(Component.text("Currently connected to this server\n" + playersText))
|
||||
showText(
|
||||
Component.translatable("velocity.command.server-tooltip-current-server")
|
||||
.append(Component.newline())
|
||||
.append(playersTextComponent))
|
||||
);
|
||||
} else {
|
||||
serverTextComponent = serverTextComponent.color(NamedTextColor.GRAY)
|
||||
.clickEvent(ClickEvent.runCommand("/server " + serverInfo.getName()))
|
||||
.clickEvent(ClickEvent.runCommand("/server " + serverInfo.name()))
|
||||
.hoverEvent(
|
||||
showText(Component.text("Click to connect to this server\n" + playersText))
|
||||
showText(
|
||||
Component.translatable("velocity.command.server-tooltip-offer-connect-server")
|
||||
.append(Component.newline())
|
||||
.append(playersTextComponent))
|
||||
);
|
||||
}
|
||||
return serverTextComponent;
|
||||
@@ -108,8 +143,8 @@ public class ServerCommand implements SimpleCommand {
|
||||
@Override
|
||||
public List<String> suggest(final SimpleCommand.Invocation invocation) {
|
||||
final String[] currentArgs = invocation.arguments();
|
||||
Stream<String> possibilities = server.getAllServers().stream()
|
||||
.map(rs -> rs.getServerInfo().getName());
|
||||
Stream<String> possibilities = server.registeredServers().stream()
|
||||
.map(rs -> rs.serverInfo().name());
|
||||
|
||||
if (currentArgs.length == 0) {
|
||||
return possibilities.collect(Collectors.toList());
|
||||
@@ -124,6 +159,6 @@ public class ServerCommand implements SimpleCommand {
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(final SimpleCommand.Invocation invocation) {
|
||||
return invocation.source().getPermissionValue("velocity.command.server") != Tristate.FALSE;
|
||||
return invocation.source().evaluatePermission("velocity.command.server") != Tristate.FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.command.builtin;
|
||||
|
||||
import com.velocitypowered.api.command.RawCommand;
|
||||
@@ -24,6 +41,6 @@ public class ShutdownCommand implements RawCommand {
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(final Invocation invocation) {
|
||||
return invocation.source() == server.getConsoleCommandSource();
|
||||
return invocation.source() == server.consoleCommandSource();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.command.builtin;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
import com.google.gson.JsonArray;
|
||||
@@ -20,7 +36,6 @@ import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
import com.velocitypowered.api.util.ProxyVersion;
|
||||
import com.velocitypowered.proxy.VelocityServer;
|
||||
import com.velocitypowered.proxy.util.InformationUtils;
|
||||
|
||||
import java.net.ConnectException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@@ -31,10 +46,10 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.kyori.adventure.identity.Identity;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.TranslatableComponent;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
@@ -166,24 +181,22 @@ public class VelocityCommand implements SimpleCommand {
|
||||
public void execute(CommandSource source, String @NonNull [] args) {
|
||||
try {
|
||||
if (server.reloadConfiguration()) {
|
||||
source.sendMessage(Identity.nil(), Component.text(
|
||||
"Configuration reloaded.", NamedTextColor.GREEN));
|
||||
source.sendMessage(Component.translatable("velocity.command.reload-success",
|
||||
NamedTextColor.GREEN));
|
||||
} else {
|
||||
source.sendMessage(Identity.nil(), Component.text(
|
||||
"Unable to reload your configuration. Check the console for more details.",
|
||||
source.sendMessage(Component.translatable("velocity.command.reload-failure",
|
||||
NamedTextColor.RED));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Unable to reload configuration", e);
|
||||
source.sendMessage(Identity.nil(), Component.text(
|
||||
"Unable to reload your configuration. Check the console for more details.",
|
||||
source.sendMessage(Component.translatable("velocity.command.reload-failure",
|
||||
NamedTextColor.RED));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(final CommandSource source, final String @NonNull [] args) {
|
||||
return source.getPermissionValue("velocity.command.reload") == Tristate.TRUE;
|
||||
return source.evaluatePermission("velocity.command.reload") == Tristate.TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,41 +216,43 @@ public class VelocityCommand implements SimpleCommand {
|
||||
return;
|
||||
}
|
||||
|
||||
ProxyVersion version = server.getVersion();
|
||||
ProxyVersion version = server.version();
|
||||
|
||||
TextComponent velocity = Component.text().content(version.getName() + " ")
|
||||
Component velocity = Component.text().content(version.getName() + " ")
|
||||
.decoration(TextDecoration.BOLD, true)
|
||||
.color(VELOCITY_COLOR)
|
||||
.append(Component.text(version.getVersion()).decoration(TextDecoration.BOLD, false))
|
||||
.build();
|
||||
TextComponent copyright = Component
|
||||
.text("Copyright 2018-2021 " + version.getVendor() + ". " + version.getName()
|
||||
+ " is freely licensed under the terms of the MIT License.");
|
||||
source.sendMessage(Identity.nil(), velocity);
|
||||
source.sendMessage(Identity.nil(), copyright);
|
||||
Component copyright = Component
|
||||
.translatable("velocity.command.version-copyright",
|
||||
Component.text(version.getVendor()),
|
||||
Component.text(version.getName()));
|
||||
source.sendMessage(velocity);
|
||||
source.sendMessage(copyright);
|
||||
|
||||
if (version.getName().equals("Velocity")) {
|
||||
TextComponent velocityWebsite = Component.text()
|
||||
.content("Visit the ")
|
||||
.append(Component.text().content("Velocity website")
|
||||
TextComponent embellishment = Component.text()
|
||||
.append(Component.text().content("velocitypowered.com")
|
||||
.color(NamedTextColor.GREEN)
|
||||
.decoration(TextDecoration.UNDERLINED, true)
|
||||
.clickEvent(
|
||||
ClickEvent.openUrl("https://www.velocitypowered.com"))
|
||||
.build())
|
||||
.append(Component.text(" or the "))
|
||||
.append(Component.text().content("Velocity GitHub")
|
||||
.append(Component.text(" - "))
|
||||
.append(Component.text().content("GitHub")
|
||||
.color(NamedTextColor.GREEN)
|
||||
.decoration(TextDecoration.UNDERLINED, true)
|
||||
.clickEvent(ClickEvent.openUrl(
|
||||
"https://github.com/VelocityPowered/Velocity"))
|
||||
.build())
|
||||
.build();
|
||||
source.sendMessage(Identity.nil(), velocityWebsite);
|
||||
source.sendMessage(Identity.nil(), embellishment);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(final CommandSource source, final String @NonNull [] args) {
|
||||
return source.getPermissionValue("velocity.command.info") != Tristate.FALSE;
|
||||
return source.evaluatePermission("velocity.command.info") != Tristate.FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,20 +271,21 @@ public class VelocityCommand implements SimpleCommand {
|
||||
return;
|
||||
}
|
||||
|
||||
List<PluginContainer> plugins = ImmutableList.copyOf(server.getPluginManager().getPlugins());
|
||||
List<PluginContainer> plugins = ImmutableList.copyOf(server.pluginManager().plugins());
|
||||
int pluginCount = plugins.size();
|
||||
|
||||
if (pluginCount == 0) {
|
||||
source.sendMessage(Identity.nil(), Component.text(
|
||||
"No plugins installed.", NamedTextColor.YELLOW));
|
||||
source.sendMessage(Component.translatable("velocity.command.no-plugins",
|
||||
NamedTextColor.YELLOW));
|
||||
return;
|
||||
}
|
||||
|
||||
TextComponent.Builder output = Component.text().content("Plugins: ")
|
||||
TranslatableComponent.Builder output = Component.translatable()
|
||||
.key("velocity.command.plugins-list")
|
||||
.color(NamedTextColor.YELLOW);
|
||||
for (int i = 0; i < pluginCount; i++) {
|
||||
PluginContainer plugin = plugins.get(i);
|
||||
output.append(componentForPlugin(plugin.getDescription()));
|
||||
output.append(componentForPlugin(plugin.description()));
|
||||
if (i + 1 < pluginCount) {
|
||||
output.append(Component.text(", "));
|
||||
}
|
||||
@@ -279,37 +295,43 @@ public class VelocityCommand implements SimpleCommand {
|
||||
}
|
||||
|
||||
private TextComponent componentForPlugin(PluginDescription description) {
|
||||
String pluginInfo = description.getName().orElse(description.getId())
|
||||
+ description.getVersion().map(v -> " " + v).orElse("");
|
||||
String pluginInfo = description.name().orElse(description.id())
|
||||
+ description.version().map(v -> " " + v).orElse("");
|
||||
|
||||
TextComponent.Builder hoverText = Component.text().content(pluginInfo);
|
||||
|
||||
description.getUrl().ifPresent(url -> {
|
||||
description.url().ifPresent(url -> {
|
||||
hoverText.append(Component.newline());
|
||||
hoverText.append(Component.text("Website: " + url));
|
||||
hoverText.append(Component.translatable(
|
||||
"velocity.command.plugin-tooltip-website",
|
||||
Component.text(url)));
|
||||
});
|
||||
if (!description.getAuthors().isEmpty()) {
|
||||
if (!description.authors().isEmpty()) {
|
||||
hoverText.append(Component.newline());
|
||||
if (description.getAuthors().size() == 1) {
|
||||
hoverText.append(Component.text("Author: " + description.getAuthors().get(0)));
|
||||
if (description.authors().size() == 1) {
|
||||
hoverText.append(Component.translatable("velocity.command.plugin-tooltip-author",
|
||||
Component.text(description.authors().get(0))));
|
||||
} else {
|
||||
hoverText.append(Component.text("Authors: " + Joiner.on(", ")
|
||||
.join(description.getAuthors())));
|
||||
hoverText.append(
|
||||
Component.translatable("velocity.command.plugin-tooltip-authors",
|
||||
Component.text(String.join(", ", description.authors()))
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
description.getDescription().ifPresent(pdesc -> {
|
||||
description.description().ifPresent(pdesc -> {
|
||||
hoverText.append(Component.newline());
|
||||
hoverText.append(Component.newline());
|
||||
hoverText.append(Component.text(pdesc));
|
||||
});
|
||||
|
||||
return Component.text(description.getId(), NamedTextColor.GRAY)
|
||||
return Component.text(description.id(), NamedTextColor.GRAY)
|
||||
.hoverEvent(HoverEvent.showText(hoverText.build()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(final CommandSource source, final String @NonNull [] args) {
|
||||
return source.getPermissionValue("velocity.command.plugins") == Tristate.TRUE;
|
||||
return source.evaluatePermission("velocity.command.plugins") == Tristate.TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,39 +351,39 @@ public class VelocityCommand implements SimpleCommand {
|
||||
return;
|
||||
}
|
||||
|
||||
Collection<RegisteredServer> allServers = ImmutableSet.copyOf(server.getAllServers());
|
||||
Collection<RegisteredServer> allServers = ImmutableSet.copyOf(server.registeredServers());
|
||||
JsonObject servers = new JsonObject();
|
||||
for (RegisteredServer iter : allServers) {
|
||||
servers.add(iter.getServerInfo().getName(),
|
||||
servers.add(iter.serverInfo().name(),
|
||||
InformationUtils.collectServerInfo(iter));
|
||||
}
|
||||
JsonArray connectOrder = new JsonArray();
|
||||
List<String> attemptedConnectionOrder = ImmutableList.copyOf(
|
||||
server.getConfiguration().getAttemptConnectionOrder());
|
||||
for (int i = 0; i < attemptedConnectionOrder.size(); i++) {
|
||||
connectOrder.add(attemptedConnectionOrder.get(i));
|
||||
server.configuration().getAttemptConnectionOrder());
|
||||
for (String s : attemptedConnectionOrder) {
|
||||
connectOrder.add(s);
|
||||
}
|
||||
|
||||
JsonObject proxyConfig = InformationUtils.collectProxyConfig(server.getConfiguration());
|
||||
JsonObject proxyConfig = InformationUtils.collectProxyConfig(server.configuration());
|
||||
proxyConfig.add("servers", servers);
|
||||
proxyConfig.add("connectOrder", connectOrder);
|
||||
proxyConfig.add("forcedHosts",
|
||||
InformationUtils.collectForcedHosts(server.getConfiguration()));
|
||||
InformationUtils.collectForcedHosts(server.configuration()));
|
||||
|
||||
JsonObject dump = new JsonObject();
|
||||
dump.add("versionInfo", InformationUtils.collectProxyInfo(server.getVersion()));
|
||||
dump.add("versionInfo", InformationUtils.collectProxyInfo(server.version()));
|
||||
dump.add("platform", InformationUtils.collectEnvironmentInfo());
|
||||
dump.add("config", proxyConfig);
|
||||
dump.add("plugins", InformationUtils.collectPluginInfo(server));
|
||||
|
||||
source.sendMessage(Component.text().content("Uploading gathered information...").build());
|
||||
source.sendMessage(Component.translatable("velocity.command.dump-uploading"));
|
||||
AsyncHttpClient httpClient = ((VelocityServer) server).getAsyncHttpClient();
|
||||
|
||||
BoundRequestBuilder request =
|
||||
httpClient.preparePost("https://dump.velocitypowered.com/documents");
|
||||
request.setHeader("Content-Type", "text/plain");
|
||||
request.addHeader("User-Agent", server.getVersion().getName() + "/"
|
||||
+ server.getVersion().getVersion());
|
||||
request.addHeader("User-Agent", server.version().getName() + "/"
|
||||
+ server.version().getVersion());
|
||||
request.setBody(
|
||||
InformationUtils.toHumanReadableString(dump).getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
@@ -370,12 +392,8 @@ public class VelocityCommand implements SimpleCommand {
|
||||
try {
|
||||
Response response = future.get();
|
||||
if (response.getStatusCode() != 200) {
|
||||
source.sendMessage(Component.text()
|
||||
.content("An error occurred while communicating with the Velocity servers. "
|
||||
+ "The servers may be temporarily unavailable or there is an issue "
|
||||
+ "with your network settings. You can find more information in the "
|
||||
+ "log or console of your Velocity server.")
|
||||
.color(NamedTextColor.RED).build());
|
||||
source.sendMessage(Component.translatable("velocity.command.dump-send-error",
|
||||
NamedTextColor.RED));
|
||||
logger.error("Invalid status code while POST-ing Velocity dump: "
|
||||
+ response.getStatusCode());
|
||||
logger.error("Headers: \n--------------BEGIN HEADERS--------------\n"
|
||||
@@ -390,62 +408,35 @@ public class VelocityCommand implements SimpleCommand {
|
||||
}
|
||||
String url = "https://dump.velocitypowered.com/"
|
||||
+ key.get("key").getAsString() + ".json";
|
||||
source.sendMessage(Component.text()
|
||||
.content("Created an anonymised report containing useful information about "
|
||||
+ "this proxy. If a developer requested it, you may share the "
|
||||
+ "following link with them:")
|
||||
source.sendMessage(Component.translatable("velocity.command.dump-success")
|
||||
.append(Component.newline())
|
||||
.append(Component.text(">> " + url)
|
||||
.color(NamedTextColor.GREEN)
|
||||
.clickEvent(ClickEvent.openUrl(url)))
|
||||
.append(Component.newline())
|
||||
.append(Component.text("Note: This link is only valid for a few days")
|
||||
.color(NamedTextColor.GRAY)
|
||||
).build());
|
||||
} catch (InterruptedException e) {
|
||||
source.sendMessage(Component.text()
|
||||
.content("Could not complete the request, the command was interrupted."
|
||||
+ "Please refer to the proxy-log or console for more information.")
|
||||
.color(NamedTextColor.RED).build());
|
||||
logger.error("Failed to complete dump command, "
|
||||
+ "the executor was interrupted: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
} catch (ExecutionException e) {
|
||||
TextComponent.Builder message = Component.text()
|
||||
.content("An error occurred while attempting to upload the gathered "
|
||||
+ "information to the Velocity servers.")
|
||||
.append(Component.newline())
|
||||
.color(NamedTextColor.RED);
|
||||
if (e.getCause() instanceof UnknownHostException
|
||||
|| e.getCause() instanceof ConnectException) {
|
||||
message.append(Component.text(
|
||||
"Likely cause: Invalid system DNS settings or no internet connection"));
|
||||
}
|
||||
source.sendMessage(message
|
||||
.append(Component.newline()
|
||||
.append(Component.text(
|
||||
"Error details can be found in the proxy log / console"))
|
||||
).build());
|
||||
|
||||
logger.error("Failed to complete dump command, "
|
||||
+ "the executor encountered an Exception: " + e.getCause().getMessage());
|
||||
e.getCause().printStackTrace();
|
||||
.append(Component.translatable("velocity.command.dump-will-expire",
|
||||
NamedTextColor.GRAY)));
|
||||
} catch (JsonParseException e) {
|
||||
source.sendMessage(Component.text()
|
||||
.content("An error occurred on the Velocity-servers and the dump could not "
|
||||
+ "be completed. Please contact the Velocity staff about this problem. "
|
||||
+ "If you do, provide the details about this error from the Velocity "
|
||||
+ "console or server log.")
|
||||
.color(NamedTextColor.RED).build());
|
||||
source.sendMessage(Component.translatable("velocity.command.dump-server-error"));
|
||||
logger.error("Invalid response from the Velocity servers: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
} catch (Exception e) {
|
||||
Component message = Component.translatable("velocity.command.dump-send-error")
|
||||
.append(Component.newline())
|
||||
.color(NamedTextColor.RED);
|
||||
if (e.getCause() instanceof UnknownHostException
|
||||
|| e.getCause() instanceof ConnectException) {
|
||||
message = message.append(Component.translatable("velocity.command.dump-offline"));
|
||||
}
|
||||
source.sendMessage(message);
|
||||
logger.error("Failed to complete dump command", Throwables.getRootCause(e));
|
||||
}
|
||||
}, MoreExecutors.directExecutor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(final CommandSource source, final String @NonNull [] args) {
|
||||
return source.getPermissionValue("velocity.command.plugins") == Tristate.TRUE;
|
||||
return source.evaluatePermission("velocity.command.plugins") == Tristate.TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.config;
|
||||
|
||||
public enum PingPassthroughMode {
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.config;
|
||||
|
||||
public enum PlayerInfoForwarding {
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.config;
|
||||
|
||||
import com.electronwill.nightconfig.core.CommentedConfig;
|
||||
@@ -11,12 +28,10 @@ import com.google.gson.annotations.Expose;
|
||||
import com.velocitypowered.api.proxy.config.ProxyConfig;
|
||||
import com.velocitypowered.api.util.Favicon;
|
||||
import com.velocitypowered.proxy.util.AddressUtil;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@@ -27,10 +42,10 @@ import java.nio.file.StandardCopyOption;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
@@ -57,25 +72,23 @@ public class VelocityConfiguration implements ProxyConfig {
|
||||
@Expose private final Advanced advanced;
|
||||
@Expose private final Query query;
|
||||
private final Metrics metrics;
|
||||
private final Messages messages;
|
||||
private net.kyori.adventure.text.@MonotonicNonNull Component motdAsComponent;
|
||||
private @Nullable Favicon favicon;
|
||||
|
||||
private VelocityConfiguration(Servers servers, ForcedHosts forcedHosts, Advanced advanced,
|
||||
Query query, Metrics metrics, Messages messages) {
|
||||
Query query, Metrics metrics) {
|
||||
this.servers = servers;
|
||||
this.forcedHosts = forcedHosts;
|
||||
this.advanced = advanced;
|
||||
this.query = query;
|
||||
this.metrics = metrics;
|
||||
this.messages = messages;
|
||||
}
|
||||
|
||||
private VelocityConfiguration(String bind, String motd, int showMaxPlayers, boolean onlineMode,
|
||||
boolean preventClientProxyConnections, boolean announceForge,
|
||||
PlayerInfoForwarding playerInfoForwardingMode, byte[] forwardingSecret,
|
||||
boolean onlineModeKickExistingPlayers, PingPassthroughMode pingPassthrough, Servers servers,
|
||||
ForcedHosts forcedHosts, Advanced advanced, Query query, Metrics metrics, Messages messages) {
|
||||
ForcedHosts forcedHosts, Advanced advanced, Query query, Metrics metrics) {
|
||||
this.bind = bind;
|
||||
this.motd = motd;
|
||||
this.showMaxPlayers = showMaxPlayers;
|
||||
@@ -91,7 +104,6 @@ public class VelocityConfiguration implements ProxyConfig {
|
||||
this.advanced = advanced;
|
||||
this.query = query;
|
||||
this.metrics = metrics;
|
||||
this.messages = messages;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -358,10 +370,6 @@ public class VelocityConfiguration implements ProxyConfig {
|
||||
return advanced.isLogCommandExecutions();
|
||||
}
|
||||
|
||||
public Messages getMessages() {
|
||||
return messages;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return MoreObjects.toStringHelper(this)
|
||||
@@ -435,7 +443,6 @@ public class VelocityConfiguration implements ProxyConfig {
|
||||
CommentedConfig advancedConfig = config.get("advanced");
|
||||
CommentedConfig queryConfig = config.get("query");
|
||||
CommentedConfig metricsConfig = config.get("metrics");
|
||||
CommentedConfig messagesConfig = config.get("messages");
|
||||
PlayerInfoForwarding forwardingMode = config.getEnumOrElse("player-info-forwarding-mode",
|
||||
PlayerInfoForwarding.NONE);
|
||||
PingPassthroughMode pingPassthroughMode = config.getEnumOrElse("ping-passthrough",
|
||||
@@ -455,8 +462,8 @@ public class VelocityConfiguration implements ProxyConfig {
|
||||
motd,
|
||||
maxPlayers,
|
||||
onlineMode,
|
||||
announceForge,
|
||||
preventClientProxyConnections,
|
||||
announceForge,
|
||||
forwardingMode,
|
||||
forwardingSecret,
|
||||
kickExisting,
|
||||
@@ -465,8 +472,7 @@ public class VelocityConfiguration implements ProxyConfig {
|
||||
new ForcedHosts(forcedHostsConfig),
|
||||
new Advanced(advancedConfig),
|
||||
new Query(queryConfig),
|
||||
new Metrics(metricsConfig),
|
||||
new Messages(messagesConfig, defaultConfig.get("messages"))
|
||||
new Metrics(metricsConfig)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -573,9 +579,11 @@ public class VelocityConfiguration implements ProxyConfig {
|
||||
Map<String, List<String>> forcedHosts = new HashMap<>();
|
||||
for (UnmodifiableConfig.Entry entry : config.entrySet()) {
|
||||
if (entry.getValue() instanceof String) {
|
||||
forcedHosts.put(entry.getKey(), ImmutableList.of(entry.getValue()));
|
||||
forcedHosts.put(entry.getKey().toLowerCase(Locale.ROOT),
|
||||
ImmutableList.of(entry.getValue()));
|
||||
} else if (entry.getValue() instanceof List) {
|
||||
forcedHosts.put(entry.getKey(), ImmutableList.copyOf((List<String>) entry.getValue()));
|
||||
forcedHosts.put(entry.getKey().toLowerCase(Locale.ROOT),
|
||||
ImmutableList.copyOf((List<String>) entry.getValue()));
|
||||
} else {
|
||||
throw new IllegalStateException(
|
||||
"Invalid value of type " + entry.getValue().getClass() + " in forced hosts!");
|
||||
@@ -778,73 +786,4 @@ public class VelocityConfiguration implements ProxyConfig {
|
||||
return enabled;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Messages {
|
||||
|
||||
private final CommentedConfig toml;
|
||||
private final CommentedConfig defaultToml;
|
||||
|
||||
private final String kickPrefix;
|
||||
private final String disconnectPrefix;
|
||||
private final String onlineModeOnly;
|
||||
private final String noAvailableServers;
|
||||
private final String alreadyConnected;
|
||||
private final String movedToNewServerPrefix;
|
||||
private final String genericConnectionError;
|
||||
|
||||
private Messages(CommentedConfig toml, CommentedConfig defaultToml) {
|
||||
this.toml = toml;
|
||||
this.defaultToml = defaultToml;
|
||||
this.kickPrefix = getString("kick-prefix");
|
||||
this.disconnectPrefix = getString("disconnect-prefix");
|
||||
this.onlineModeOnly = getString("online-mode-only");
|
||||
this.noAvailableServers = getString("no-available-servers");
|
||||
this.alreadyConnected = getString("already-connected");
|
||||
this.movedToNewServerPrefix = getString("moved-to-new-server-prefix");
|
||||
this.genericConnectionError = getString("generic-connection-error");
|
||||
}
|
||||
|
||||
private String getString(String path) {
|
||||
String def = defaultToml.getOrElse(path, "");
|
||||
if (toml == null) {
|
||||
return def;
|
||||
}
|
||||
return toml.getOrElse(path, def);
|
||||
}
|
||||
|
||||
public Component getKickPrefix(String server) {
|
||||
return deserialize(String.format(kickPrefix, server));
|
||||
}
|
||||
|
||||
public Component getDisconnectPrefix(String server) {
|
||||
return deserialize(String.format(disconnectPrefix, server));
|
||||
}
|
||||
|
||||
public Component getOnlineModeOnly() {
|
||||
return deserialize(onlineModeOnly);
|
||||
}
|
||||
|
||||
public Component getNoAvailableServers() {
|
||||
return deserialize(noAvailableServers);
|
||||
}
|
||||
|
||||
public Component getAlreadyConnected() {
|
||||
return deserialize(alreadyConnected);
|
||||
}
|
||||
|
||||
public Component getMovedToNewServerPrefix() {
|
||||
return deserialize(movedToNewServerPrefix);
|
||||
}
|
||||
|
||||
public Component getGenericConnectionError() {
|
||||
return deserialize(genericConnectionError);
|
||||
}
|
||||
|
||||
private Component deserialize(String str) {
|
||||
if (str.startsWith("{")) {
|
||||
return GsonComponentSerializer.gson().deserialize(str);
|
||||
}
|
||||
return LegacyComponentSerializer.legacyAmpersand().deserialize(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.connection;
|
||||
|
||||
import com.velocitypowered.api.util.GameProfile;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.connection;
|
||||
|
||||
import com.velocitypowered.proxy.connection.backend.BackendConnectionPhases;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.connection;
|
||||
|
||||
import static com.velocitypowered.proxy.network.HandlerNames.CIPHER_DECODER;
|
||||
@@ -25,7 +42,7 @@ import com.velocitypowered.proxy.network.packet.clientbound.ClientboundSetCompre
|
||||
import com.velocitypowered.proxy.network.pipeline.MinecraftCipherDecoder;
|
||||
import com.velocitypowered.proxy.network.pipeline.MinecraftCipherEncoder;
|
||||
import com.velocitypowered.proxy.network.pipeline.MinecraftCompressDecoder;
|
||||
import com.velocitypowered.proxy.network.pipeline.MinecraftCompressEncoder;
|
||||
import com.velocitypowered.proxy.network.pipeline.MinecraftCompressorAndLengthEncoder;
|
||||
import com.velocitypowered.proxy.network.pipeline.MinecraftDecoder;
|
||||
import com.velocitypowered.proxy.network.pipeline.MinecraftEncoder;
|
||||
import com.velocitypowered.proxy.util.except.QuietDecoderException;
|
||||
@@ -391,18 +408,19 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter {
|
||||
} else {
|
||||
MinecraftCompressDecoder decoder = (MinecraftCompressDecoder) channel.pipeline()
|
||||
.get(COMPRESSION_DECODER);
|
||||
MinecraftCompressEncoder encoder = (MinecraftCompressEncoder) channel.pipeline()
|
||||
.get(COMPRESSION_ENCODER);
|
||||
MinecraftCompressorAndLengthEncoder encoder =
|
||||
(MinecraftCompressorAndLengthEncoder) channel.pipeline().get(COMPRESSION_ENCODER);
|
||||
if (decoder != null && encoder != null) {
|
||||
decoder.setThreshold(threshold);
|
||||
encoder.setThreshold(threshold);
|
||||
} else {
|
||||
int level = server.getConfiguration().getCompressionLevel();
|
||||
int level = server.configuration().getCompressionLevel();
|
||||
VelocityCompressor compressor = Natives.compress.get().create(level);
|
||||
|
||||
encoder = new MinecraftCompressEncoder(threshold, compressor);
|
||||
encoder = new MinecraftCompressorAndLengthEncoder(threshold, compressor);
|
||||
decoder = new MinecraftCompressDecoder(threshold, compressor);
|
||||
|
||||
channel.pipeline().remove(FRAME_ENCODER);
|
||||
channel.pipeline().addBefore(MINECRAFT_DECODER, COMPRESSION_DECODER, decoder);
|
||||
channel.pipeline().addBefore(MINECRAFT_ENCODER, COMPRESSION_ENCODER, encoder);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.connection;
|
||||
|
||||
public interface MinecraftConnectionAssociation {
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.connection;
|
||||
|
||||
import com.velocitypowered.proxy.network.packet.Packet;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.connection;
|
||||
|
||||
public class VelocityConstants {
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.connection.backend;
|
||||
|
||||
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.connection.backend;
|
||||
|
||||
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.connection.backend;
|
||||
|
||||
import static com.velocitypowered.proxy.connection.backend.BungeeCordMessageResponder.getBungeeCordChannel;
|
||||
@@ -7,10 +24,11 @@ import com.mojang.brigadier.builder.ArgumentBuilder;
|
||||
import com.mojang.brigadier.tree.CommandNode;
|
||||
import com.mojang.brigadier.tree.RootCommandNode;
|
||||
import com.velocitypowered.api.command.CommandSource;
|
||||
import com.velocitypowered.api.event.command.PlayerAvailableCommandsEvent;
|
||||
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;
|
||||
@@ -41,17 +59,21 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
||||
private static final Logger logger = LogManager.getLogger(BackendPlaySessionHandler.class);
|
||||
private static final boolean BACKPRESSURE_LOG = Boolean
|
||||
.getBoolean("velocity.log-server-backpressure");
|
||||
private static final int MAXIMUM_PACKETS_TO_FLUSH = Integer
|
||||
.getInteger("velocity.max-packets-per-flush", 8192);
|
||||
|
||||
private final VelocityServer server;
|
||||
private final VelocityServerConnection serverConn;
|
||||
private final ClientPlaySessionHandler playerSessionHandler;
|
||||
private final MinecraftConnection playerConnection;
|
||||
private final BungeeCordMessageResponder bungeecordMessageResponder;
|
||||
private boolean exceptionTriggered = false;
|
||||
private int packetsFlushed;
|
||||
|
||||
BackendPlaySessionHandler(VelocityServer server, VelocityServerConnection serverConn) {
|
||||
this.server = server;
|
||||
this.serverConn = serverConn;
|
||||
this.playerConnection = serverConn.getPlayer().getConnection();
|
||||
this.playerConnection = serverConn.player().getConnection();
|
||||
|
||||
MinecraftSessionHandler psh = playerConnection.getSessionHandler();
|
||||
if (!(psh instanceof ClientPlaySessionHandler)) {
|
||||
@@ -61,14 +83,14 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
||||
this.playerSessionHandler = (ClientPlaySessionHandler) psh;
|
||||
|
||||
this.bungeecordMessageResponder = new BungeeCordMessageResponder(server,
|
||||
serverConn.getPlayer());
|
||||
serverConn.player());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void activated() {
|
||||
serverConn.getServer().addPlayer(serverConn.getPlayer());
|
||||
serverConn.target().addPlayer(serverConn.player());
|
||||
|
||||
if (server.getConfiguration().isBungeePluginChannelEnabled()) {
|
||||
if (server.configuration().isBungeePluginChannelEnabled()) {
|
||||
MinecraftConnection serverMc = serverConn.ensureConnected();
|
||||
serverMc.write(PluginMessageUtil.constructChannelsPacket(serverMc.getProtocolVersion(),
|
||||
ImmutableList.of(getBungeeCordChannel(serverMc.getProtocolVersion())),
|
||||
@@ -95,7 +117,7 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
||||
@Override
|
||||
public boolean handle(ClientboundDisconnectPacket packet) {
|
||||
serverConn.disconnect();
|
||||
serverConn.getPlayer().handleConnectionException(serverConn.getServer(), packet, true);
|
||||
serverConn.player().handleConnectionException(serverConn.target(), packet, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -115,7 +137,7 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!serverConn.getPlayer().canForwardPluginMessage(serverConn.ensureConnected()
|
||||
if (!serverConn.player().canForwardPluginMessage(serverConn.ensureConnected()
|
||||
.getProtocolVersion(), packet)) {
|
||||
return true;
|
||||
}
|
||||
@@ -123,36 +145,36 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
||||
// We need to specially handle REGISTER and UNREGISTER packets. Later on, we'll write them to
|
||||
// the client.
|
||||
if (PluginMessageUtil.isRegister(packet)) {
|
||||
serverConn.getPlayer().getKnownChannels().addAll(PluginMessageUtil.getChannels(packet));
|
||||
serverConn.player().getKnownChannels().addAll(PluginMessageUtil.getChannels(packet));
|
||||
return false;
|
||||
} else if (PluginMessageUtil.isUnregister(packet)) {
|
||||
serverConn.getPlayer().getKnownChannels().removeAll(PluginMessageUtil.getChannels(packet));
|
||||
serverConn.player().getKnownChannels().removeAll(PluginMessageUtil.getChannels(packet));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (PluginMessageUtil.isMcBrand(packet)) {
|
||||
AbstractPluginMessagePacket<?> rewritten = PluginMessageUtil.rewriteMinecraftBrand(packet,
|
||||
server.getVersion(), playerConnection.getProtocolVersion(), ClientboundPluginMessagePacket.FACTORY);
|
||||
server.version(), playerConnection.getProtocolVersion(), ClientboundPluginMessagePacket.FACTORY);
|
||||
playerConnection.write(rewritten);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (serverConn.getPhase().handle(serverConn, serverConn.getPlayer(), packet)) {
|
||||
if (serverConn.getPhase().handle(serverConn, serverConn.player(), packet)) {
|
||||
// Handled.
|
||||
return true;
|
||||
}
|
||||
|
||||
ChannelIdentifier id = server.getChannelRegistrar().getFromId(packet.getChannel());
|
||||
PluginChannelId id = server.channelRegistrar().getFromId(packet.getChannel());
|
||||
if (id == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
byte[] copy = ByteBufUtil.getBytes(packet.content());
|
||||
PluginMessageEvent event = new PluginMessageEvent(serverConn, serverConn.getPlayer(), id,
|
||||
PluginMessageEvent event = new PluginMessageEventImpl(serverConn, serverConn.player(), id,
|
||||
copy);
|
||||
server.getEventManager().fire(event)
|
||||
server.eventManager().fire(event)
|
||||
.thenAcceptAsync(pme -> {
|
||||
if (pme.getResult().isAllowed() && !playerConnection.isClosed()) {
|
||||
if (pme.result().isAllowed() && !playerConnection.isClosed()) {
|
||||
ClientboundPluginMessagePacket copied = new ClientboundPluginMessagePacket(packet.getChannel(),
|
||||
Unpooled.wrappedBuffer(copy));
|
||||
playerConnection.write(copied);
|
||||
@@ -173,18 +195,18 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
||||
|
||||
@Override
|
||||
public boolean handle(ClientboundPlayerListItemPacket packet) {
|
||||
serverConn.getPlayer().getTabList().processBackendPacket(packet);
|
||||
serverConn.player().tabList().processBackendPacket(packet);
|
||||
return false; //Forward packet to player
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(ClientboundAvailableCommandsPacket commands) {
|
||||
RootCommandNode<CommandSource> rootNode = commands.getRootNode();
|
||||
if (server.getConfiguration().isAnnounceProxyCommands()) {
|
||||
if (server.configuration().isAnnounceProxyCommands()) {
|
||||
// Inject commands from the proxy.
|
||||
RootCommandNode<CommandSource> dispatcherRootNode =
|
||||
(RootCommandNode<CommandSource>)
|
||||
filterNode(server.getCommandManager().getDispatcher().getRoot());
|
||||
filterNode(server.commandManager().getDispatcher().getRoot());
|
||||
assert dispatcherRootNode != null : "Filtering root node returned null.";
|
||||
Collection<CommandNode<CommandSource>> proxyNodes = dispatcherRootNode.getChildren();
|
||||
for (CommandNode<CommandSource> node : proxyNodes) {
|
||||
@@ -196,8 +218,8 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
||||
}
|
||||
}
|
||||
|
||||
server.getEventManager().fire(
|
||||
new PlayerAvailableCommandsEvent(serverConn.getPlayer(), rootNode))
|
||||
server.eventManager().fire(
|
||||
new PlayerAvailableCommandsEventImpl(serverConn.player(), rootNode))
|
||||
.thenAcceptAsync(event -> playerConnection.write(commands), playerConnection.eventLoop())
|
||||
.exceptionally((ex) -> {
|
||||
logger.error("Exception while handling available commands for {}", playerConnection, ex);
|
||||
@@ -220,7 +242,7 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
||||
} else {
|
||||
if (source.getRequirement() != null) {
|
||||
try {
|
||||
if (!source.getRequirement().test(serverConn.getPlayer())) {
|
||||
if (!source.getRequirement().test(serverConn.player())) {
|
||||
return null;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
@@ -256,22 +278,31 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
||||
((AbstractPluginMessagePacket<?>) packet).retain();
|
||||
}
|
||||
playerConnection.delayedWrite(packet);
|
||||
if (++packetsFlushed >= MAXIMUM_PACKETS_TO_FLUSH) {
|
||||
playerConnection.flush();
|
||||
packetsFlushed = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleUnknown(ByteBuf buf) {
|
||||
playerConnection.delayedWrite(buf.retain());
|
||||
if (++packetsFlushed >= MAXIMUM_PACKETS_TO_FLUSH) {
|
||||
playerConnection.flush();
|
||||
packetsFlushed = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readCompleted() {
|
||||
playerConnection.flush();
|
||||
packetsFlushed = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exception(Throwable throwable) {
|
||||
exceptionTriggered = true;
|
||||
serverConn.getPlayer().handleConnectionException(serverConn.getServer(), throwable,
|
||||
serverConn.player().handleConnectionException(serverConn.target(), throwable,
|
||||
!(throwable instanceof ReadTimeoutException));
|
||||
}
|
||||
|
||||
@@ -281,14 +312,14 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
||||
|
||||
@Override
|
||||
public void disconnected() {
|
||||
serverConn.getServer().removePlayer(serverConn.getPlayer());
|
||||
serverConn.target().removePlayer(serverConn.player());
|
||||
if (!serverConn.isGracefulDisconnect() && !exceptionTriggered) {
|
||||
if (server.getConfiguration().isFailoverOnUnexpectedServerDisconnect()) {
|
||||
serverConn.getPlayer().handleConnectionException(serverConn.getServer(),
|
||||
if (server.configuration().isFailoverOnUnexpectedServerDisconnect()) {
|
||||
serverConn.player().handleConnectionException(serverConn.target(),
|
||||
ClientboundDisconnectPacket.create(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR,
|
||||
ProtocolVersion.MINECRAFT_1_16), true);
|
||||
} else {
|
||||
serverConn.getPlayer().disconnect(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR);
|
||||
serverConn.player().disconnect(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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;
|
||||
@@ -23,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;
|
||||
@@ -33,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;
|
||||
@@ -47,13 +63,13 @@ public class BungeeCordMessageResponder {
|
||||
}
|
||||
|
||||
public static boolean isBungeeCordMessage(AbstractPluginMessagePacket<?> message) {
|
||||
return MODERN_CHANNEL.getId().equals(message.getChannel()) || LEGACY_CHANNEL.getId()
|
||||
.equals(message.getChannel());
|
||||
return CHANNEL.modernChannelKey().asString().equals(message.getChannel())
|
||||
|| CHANNEL.legacyChannel().equals(message.getChannel());
|
||||
}
|
||||
|
||||
private void processConnect(ByteBufDataInput in) {
|
||||
String serverName = in.readUTF();
|
||||
proxy.getServer(serverName).ifPresent(server -> player.createConnectionRequest(server)
|
||||
proxy.server(serverName).ifPresent(server -> player.createConnectionRequest(server)
|
||||
.fireAndForget());
|
||||
}
|
||||
|
||||
@@ -62,7 +78,7 @@ public class BungeeCordMessageResponder {
|
||||
String serverName = in.readUTF();
|
||||
|
||||
Optional<Player> referencedPlayer = proxy.getPlayer(playerName);
|
||||
Optional<RegisteredServer> referencedServer = proxy.getServer(serverName);
|
||||
Optional<RegisteredServer> referencedServer = proxy.server(serverName);
|
||||
if (referencedPlayer.isPresent() && referencedServer.isPresent()) {
|
||||
referencedPlayer.get().createConnectionRequest(referencedServer.get()).fireAndForget();
|
||||
}
|
||||
@@ -73,7 +89,7 @@ public class BungeeCordMessageResponder {
|
||||
ByteBufDataOutput out = new ByteBufDataOutput(buf);
|
||||
out.writeUTF("IP");
|
||||
|
||||
SocketAddress address = player.getRemoteAddress();
|
||||
SocketAddress address = player.remoteAddress();
|
||||
if (address instanceof InetSocketAddress) {
|
||||
InetSocketAddress serverInetAddr = (InetSocketAddress) address;
|
||||
out.writeUTF(serverInetAddr.getHostString());
|
||||
@@ -93,12 +109,12 @@ public class BungeeCordMessageResponder {
|
||||
if (target.equals("ALL")) {
|
||||
out.writeUTF("PlayerCount");
|
||||
out.writeUTF("ALL");
|
||||
out.writeInt(proxy.getPlayerCount());
|
||||
out.writeInt(proxy.countConnectedPlayers());
|
||||
} else {
|
||||
proxy.getServer(target).ifPresent(rs -> {
|
||||
int playersOnServer = rs.getPlayersConnected().size();
|
||||
proxy.server(target).ifPresent(rs -> {
|
||||
int playersOnServer = rs.connectedPlayers().size();
|
||||
out.writeUTF("PlayerCount");
|
||||
out.writeUTF(rs.getServerInfo().getName());
|
||||
out.writeUTF(rs.serverInfo().name());
|
||||
out.writeInt(playersOnServer);
|
||||
});
|
||||
}
|
||||
@@ -120,18 +136,18 @@ public class BungeeCordMessageResponder {
|
||||
out.writeUTF("ALL");
|
||||
|
||||
StringJoiner joiner = new StringJoiner(", ");
|
||||
for (Player online : proxy.getAllPlayers()) {
|
||||
joiner.add(online.getUsername());
|
||||
for (Player online : proxy.connectedPlayers()) {
|
||||
joiner.add(online.username());
|
||||
}
|
||||
out.writeUTF(joiner.toString());
|
||||
} else {
|
||||
proxy.getServer(target).ifPresent(info -> {
|
||||
proxy.server(target).ifPresent(info -> {
|
||||
out.writeUTF("PlayerList");
|
||||
out.writeUTF(info.getServerInfo().getName());
|
||||
out.writeUTF(info.serverInfo().name());
|
||||
|
||||
StringJoiner joiner = new StringJoiner(", ");
|
||||
for (Player online : info.getPlayersConnected()) {
|
||||
joiner.add(online.getUsername());
|
||||
for (Player online : info.connectedPlayers()) {
|
||||
joiner.add(online.username());
|
||||
}
|
||||
out.writeUTF(joiner.toString());
|
||||
});
|
||||
@@ -146,8 +162,8 @@ public class BungeeCordMessageResponder {
|
||||
|
||||
private void processGetServers() {
|
||||
StringJoiner joiner = new StringJoiner(", ");
|
||||
for (RegisteredServer server : proxy.getAllServers()) {
|
||||
joiner.add(server.getServerInfo().getName());
|
||||
for (RegisteredServer server : proxy.registeredServers()) {
|
||||
joiner.add(server.serverInfo().name());
|
||||
}
|
||||
|
||||
ByteBuf buf = Unpooled.buffer();
|
||||
@@ -185,7 +201,7 @@ public class BungeeCordMessageResponder {
|
||||
ByteBufDataOutput out = new ByteBufDataOutput(buf);
|
||||
|
||||
out.writeUTF("GetServer");
|
||||
out.writeUTF(player.ensureAndGetCurrentServer().getServerInfo().getName());
|
||||
out.writeUTF(player.ensureAndGetCurrentServer().serverInfo().name());
|
||||
|
||||
sendResponseOnConnection(buf);
|
||||
}
|
||||
@@ -195,7 +211,7 @@ public class BungeeCordMessageResponder {
|
||||
ByteBufDataOutput out = new ByteBufDataOutput(buf);
|
||||
|
||||
out.writeUTF("UUID");
|
||||
out.writeUTF(UuidUtils.toUndashed(player.getUniqueId()));
|
||||
out.writeUTF(UuidUtils.toUndashed(player.id()));
|
||||
|
||||
sendResponseOnConnection(buf);
|
||||
}
|
||||
@@ -206,8 +222,8 @@ public class BungeeCordMessageResponder {
|
||||
ByteBufDataOutput out = new ByteBufDataOutput(buf);
|
||||
|
||||
out.writeUTF("UUIDOther");
|
||||
out.writeUTF(player.getUsername());
|
||||
out.writeUTF(UuidUtils.toUndashed(player.getUniqueId()));
|
||||
out.writeUTF(player.username());
|
||||
out.writeUTF(UuidUtils.toUndashed(player.id()));
|
||||
|
||||
sendResponseOnConnection(buf);
|
||||
});
|
||||
@@ -219,8 +235,8 @@ public class BungeeCordMessageResponder {
|
||||
ByteBufDataOutput out = new ByteBufDataOutput(buf);
|
||||
|
||||
out.writeUTF("IPOther");
|
||||
out.writeUTF(player.getUsername());
|
||||
SocketAddress address = player.getRemoteAddress();
|
||||
out.writeUTF(player.username());
|
||||
SocketAddress address = player.remoteAddress();
|
||||
if (address instanceof InetSocketAddress) {
|
||||
InetSocketAddress serverInetAddr = (InetSocketAddress) address;
|
||||
out.writeUTF(serverInetAddr.getHostString());
|
||||
@@ -235,13 +251,13 @@ public class BungeeCordMessageResponder {
|
||||
}
|
||||
|
||||
private void processServerIp(ByteBufDataInput in) {
|
||||
proxy.getServer(in.readUTF()).ifPresent(info -> {
|
||||
proxy.server(in.readUTF()).ifPresent(info -> {
|
||||
ByteBuf buf = Unpooled.buffer();
|
||||
ByteBufDataOutput out = new ByteBufDataOutput(buf);
|
||||
|
||||
out.writeUTF("ServerIP");
|
||||
out.writeUTF(info.getServerInfo().getName());
|
||||
SocketAddress address = info.getServerInfo().getAddress();
|
||||
out.writeUTF(info.serverInfo().name());
|
||||
SocketAddress address = info.serverInfo().address();
|
||||
if (address instanceof InetSocketAddress) {
|
||||
InetSocketAddress serverInetAddr = (InetSocketAddress) address;
|
||||
out.writeUTF(serverInetAddr.getHostString());
|
||||
@@ -275,17 +291,17 @@ public class BungeeCordMessageResponder {
|
||||
ByteBuf toForward = in.unwrap().copy();
|
||||
if (target.equals("ALL")) {
|
||||
try {
|
||||
for (RegisteredServer rs : proxy.getAllServers()) {
|
||||
((VelocityRegisteredServer) rs).sendPluginMessage(LEGACY_CHANNEL,
|
||||
for (RegisteredServer rs : proxy.registeredServers()) {
|
||||
((VelocityRegisteredServer) rs).sendPluginMessage(CHANNEL,
|
||||
toForward.retainedSlice());
|
||||
}
|
||||
} finally {
|
||||
toForward.release();
|
||||
}
|
||||
} else {
|
||||
Optional<RegisteredServer> server = proxy.getServer(target);
|
||||
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();
|
||||
}
|
||||
@@ -293,8 +309,8 @@ public class BungeeCordMessageResponder {
|
||||
}
|
||||
|
||||
static String getBungeeCordChannel(ProtocolVersion version) {
|
||||
return version.gte(ProtocolVersion.MINECRAFT_1_13) ? MODERN_CHANNEL.getId()
|
||||
: LEGACY_CHANNEL.getId();
|
||||
return version.gte(ProtocolVersion.MINECRAFT_1_13) ? CHANNEL.modernChannelKey().asString()
|
||||
: CHANNEL.legacyChannel();
|
||||
}
|
||||
|
||||
// Note: this method will always release the buffer!
|
||||
@@ -311,7 +327,7 @@ public class BungeeCordMessageResponder {
|
||||
}
|
||||
|
||||
boolean process(AbstractPluginMessagePacket<?> message) {
|
||||
if (!proxy.getConfiguration().isBungeePluginChannelEnabled()) {
|
||||
if (!proxy.configuration().isBungeePluginChannelEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.connection.backend;
|
||||
|
||||
import com.velocitypowered.api.util.GameProfile;
|
||||
@@ -33,8 +50,8 @@ import net.kyori.adventure.text.TextComponent;
|
||||
|
||||
public class LoginSessionHandler implements MinecraftSessionHandler {
|
||||
|
||||
private static final TextComponent MODERN_IP_FORWARDING_FAILURE = Component
|
||||
.text("Your server did not send a forwarding request to the proxy. Is it set up correctly?");
|
||||
private static final Component MODERN_IP_FORWARDING_FAILURE = Component
|
||||
.translatable("velocity.error.modern-forwarding-failed");
|
||||
|
||||
private final VelocityServer server;
|
||||
private final VelocityServerConnection serverConn;
|
||||
@@ -56,12 +73,12 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
|
||||
@Override
|
||||
public boolean handle(ClientboundLoginPluginMessagePacket packet) {
|
||||
MinecraftConnection mc = serverConn.ensureConnected();
|
||||
VelocityConfiguration configuration = server.getConfiguration();
|
||||
VelocityConfiguration configuration = server.configuration();
|
||||
if (configuration.getPlayerInfoForwardingMode() == PlayerInfoForwarding.MODERN && packet
|
||||
.getChannel().equals(VelocityConstants.VELOCITY_IP_FORWARDING_CHANNEL)) {
|
||||
ByteBuf forwardingData = createForwardingData(configuration.getForwardingSecret(),
|
||||
cleanRemoteAddress(serverConn.getPlayer().getRemoteAddress()),
|
||||
serverConn.getPlayer().getGameProfile());
|
||||
cleanRemoteAddress(serverConn.player().remoteAddress()),
|
||||
serverConn.player().gameProfile());
|
||||
ServerboundLoginPluginResponsePacket response = new ServerboundLoginPluginResponsePacket(
|
||||
packet.getId(), true, forwardingData);
|
||||
mc.write(response);
|
||||
@@ -76,7 +93,7 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
|
||||
|
||||
@Override
|
||||
public boolean handle(ClientboundDisconnectPacket packet) {
|
||||
resultFuture.complete(ConnectionRequestResults.forDisconnect(packet, serverConn.getServer()));
|
||||
resultFuture.complete(ConnectionRequestResults.forDisconnect(packet, serverConn.target()));
|
||||
serverConn.disconnect();
|
||||
return true;
|
||||
}
|
||||
@@ -89,10 +106,10 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
|
||||
|
||||
@Override
|
||||
public boolean handle(ClientboundServerLoginSuccessPacket packet) {
|
||||
if (server.getConfiguration().getPlayerInfoForwardingMode() == PlayerInfoForwarding.MODERN
|
||||
if (server.configuration().getPlayerInfoForwardingMode() == PlayerInfoForwarding.MODERN
|
||||
&& !informationForwarded) {
|
||||
resultFuture.complete(ConnectionRequestResults.forDisconnect(MODERN_IP_FORWARDING_FAILURE,
|
||||
serverConn.getServer()));
|
||||
serverConn.target()));
|
||||
serverConn.disconnect();
|
||||
return true;
|
||||
}
|
||||
@@ -116,7 +133,7 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
|
||||
|
||||
@Override
|
||||
public void disconnected() {
|
||||
if (server.getConfiguration().getPlayerInfoForwardingMode() == PlayerInfoForwarding.LEGACY) {
|
||||
if (server.configuration().getPlayerInfoForwardingMode() == PlayerInfoForwarding.LEGACY) {
|
||||
resultFuture.completeExceptionally(
|
||||
new QuietRuntimeException("The connection to the remote server was unexpectedly closed.\n"
|
||||
+ "This is usually because the remote server does not have BungeeCord IP forwarding "
|
||||
|
||||
@@ -1,10 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.connection.backend;
|
||||
|
||||
import static com.velocitypowered.proxy.connection.backend.BackendConnectionPhases.IN_TRANSITION;
|
||||
import static com.velocitypowered.proxy.connection.forge.legacy.LegacyForgeHandshakeBackendPhase.HELLO;
|
||||
|
||||
import com.velocitypowered.api.event.player.ServerConnectedEvent;
|
||||
import com.velocitypowered.api.event.player.ServerPostConnectEvent;
|
||||
import com.velocitypowered.api.event.player.ServerConnectedEventImpl;
|
||||
import com.velocitypowered.api.event.player.ServerPostConnectEventImpl;
|
||||
import com.velocitypowered.proxy.VelocityServer;
|
||||
import com.velocitypowered.proxy.connection.ConnectionTypes;
|
||||
import com.velocitypowered.proxy.connection.MinecraftConnection;
|
||||
@@ -68,9 +85,9 @@ public class TransitionSessionHandler implements MinecraftSessionHandler {
|
||||
@Override
|
||||
public boolean handle(ClientboundJoinGamePacket packet) {
|
||||
MinecraftConnection smc = serverConn.ensureConnected();
|
||||
VelocityServerConnection existingConnection = serverConn.getPlayer().getConnectedServer();
|
||||
VelocityServerConnection existingConnection = serverConn.player().getConnectedServer();
|
||||
|
||||
final ConnectedPlayer player = serverConn.getPlayer();
|
||||
final ConnectedPlayer player = serverConn.player();
|
||||
|
||||
if (existingConnection != null) {
|
||||
// Shut down the existing server connection.
|
||||
@@ -83,10 +100,10 @@ public class TransitionSessionHandler implements MinecraftSessionHandler {
|
||||
|
||||
// The goods are in hand! We got JoinGame. Let's transition completely to the new state.
|
||||
smc.setAutoReading(false);
|
||||
server.getEventManager()
|
||||
.fire(new ServerConnectedEvent(player, serverConn.getServer(),
|
||||
existingConnection != null ? existingConnection.getServer() : null))
|
||||
.whenCompleteAsync((x, error) -> {
|
||||
server.eventManager()
|
||||
.fire(new ServerConnectedEventImpl(player, serverConn.target(),
|
||||
existingConnection != null ? existingConnection.target() : null))
|
||||
.thenRunAsync(() -> {
|
||||
// Make sure we can still transition (player might have disconnected here).
|
||||
if (!serverConn.isActive()) {
|
||||
// Connection is obsolete.
|
||||
@@ -112,17 +129,17 @@ public class TransitionSessionHandler implements MinecraftSessionHandler {
|
||||
smc.setAutoReading(true);
|
||||
|
||||
// Now set the connected server.
|
||||
serverConn.getPlayer().setConnectedServer(serverConn);
|
||||
serverConn.player().setConnectedServer(serverConn);
|
||||
|
||||
// We're done! :)
|
||||
server.getEventManager().fireAndForget(new ServerPostConnectEvent(player,
|
||||
existingConnection == null ? null : existingConnection.getServer()));
|
||||
resultFuture.complete(ConnectionRequestResults.successful(serverConn.getServer()));
|
||||
server.eventManager().fireAndForget(new ServerPostConnectEventImpl(player,
|
||||
existingConnection == null ? null : existingConnection.target()));
|
||||
resultFuture.complete(ConnectionRequestResults.successful(serverConn.target()));
|
||||
}, smc.eventLoop())
|
||||
.exceptionally(exc -> {
|
||||
logger.error("Unable to switch to new server {} for {}",
|
||||
serverConn.getServerInfo().getName(),
|
||||
player.getUsername(), exc);
|
||||
serverConn.serverInfo().name(),
|
||||
player.username(), exc);
|
||||
player.disconnect(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR);
|
||||
resultFuture.completeExceptionally(exc);
|
||||
return null;
|
||||
@@ -141,9 +158,9 @@ public class TransitionSessionHandler implements MinecraftSessionHandler {
|
||||
if (connection.getType() == ConnectionTypes.LEGACY_FORGE
|
||||
&& !serverConn.getPhase().consideredComplete()) {
|
||||
resultFuture.complete(ConnectionRequestResults.forUnsafeDisconnect(packet,
|
||||
serverConn.getServer()));
|
||||
serverConn.target()));
|
||||
} else {
|
||||
resultFuture.complete(ConnectionRequestResults.forDisconnect(packet, serverConn.getServer()));
|
||||
resultFuture.complete(ConnectionRequestResults.forDisconnect(packet, serverConn.target()));
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -151,35 +168,35 @@ public class TransitionSessionHandler implements MinecraftSessionHandler {
|
||||
|
||||
@Override
|
||||
public boolean handle(ClientboundPluginMessagePacket packet) {
|
||||
if (!serverConn.getPlayer().canForwardPluginMessage(serverConn.ensureConnected()
|
||||
if (!serverConn.player().canForwardPluginMessage(serverConn.ensureConnected()
|
||||
.getProtocolVersion(), packet)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (PluginMessageUtil.isRegister(packet)) {
|
||||
serverConn.getPlayer().getKnownChannels().addAll(PluginMessageUtil.getChannels(packet));
|
||||
serverConn.player().getKnownChannels().addAll(PluginMessageUtil.getChannels(packet));
|
||||
} else if (PluginMessageUtil.isUnregister(packet)) {
|
||||
serverConn.getPlayer().getKnownChannels().removeAll(PluginMessageUtil.getChannels(packet));
|
||||
serverConn.player().getKnownChannels().removeAll(PluginMessageUtil.getChannels(packet));
|
||||
}
|
||||
|
||||
// We always need to handle plugin messages, for Forge compatibility.
|
||||
if (serverConn.getPhase().handle(serverConn, serverConn.getPlayer(), packet)) {
|
||||
if (serverConn.getPhase().handle(serverConn, serverConn.player(), packet)) {
|
||||
// Handled, but check the server connection phase.
|
||||
if (serverConn.getPhase() == HELLO) {
|
||||
VelocityServerConnection existingConnection = serverConn.getPlayer().getConnectedServer();
|
||||
VelocityServerConnection existingConnection = serverConn.player().getConnectedServer();
|
||||
if (existingConnection != null && existingConnection.getPhase() != IN_TRANSITION) {
|
||||
// Indicate that this connection is "in transition"
|
||||
existingConnection.setConnectionPhase(IN_TRANSITION);
|
||||
|
||||
// Tell the player that we're leaving and we just aren't coming back.
|
||||
existingConnection.getPhase().onDepartForNewServer(existingConnection,
|
||||
serverConn.getPlayer());
|
||||
serverConn.player());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
serverConn.getPlayer().getConnection().write(packet.retain());
|
||||
serverConn.player().getConnection().write(packet.retain());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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;
|
||||
@@ -74,7 +92,7 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation,
|
||||
CompletableFuture<Impl> result = new CompletableFuture<>();
|
||||
// Note: we use the event loop for the connection the player is on. This reduces context
|
||||
// switches.
|
||||
SocketAddress destinationAddress = registeredServer.getServerInfo().getAddress();
|
||||
SocketAddress destinationAddress = registeredServer.serverInfo().address();
|
||||
server.createBootstrap(proxyPlayer.getConnection().eventLoop(), destinationAddress)
|
||||
.handler(server.getBackendChannelInitializer())
|
||||
.connect(destinationAddress)
|
||||
@@ -100,27 +118,27 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation,
|
||||
return result;
|
||||
}
|
||||
|
||||
private String getHandshakeRemoteAddress() {
|
||||
return proxyPlayer.getVirtualHost().map(InetSocketAddress::getHostString).orElse("");
|
||||
private String playerConnectedHostname() {
|
||||
return proxyPlayer.connectedHostname().map(InetSocketAddress::getHostString).orElse("");
|
||||
}
|
||||
|
||||
private String createLegacyForwardingAddress(UnaryOperator<List<Property>> propertiesTransform) {
|
||||
// BungeeCord IP forwarding is simply a special injection after the "address" in the handshake,
|
||||
// separated by \0 (the null byte). In order, you send the original host, the player's IP, their
|
||||
// UUID (undashed), and if you are in online-mode, their login properties (from Mojang).
|
||||
SocketAddress playerRemoteAddress = proxyPlayer.getRemoteAddress();
|
||||
SocketAddress playerRemoteAddress = proxyPlayer.remoteAddress();
|
||||
if (!(playerRemoteAddress instanceof InetSocketAddress)) {
|
||||
return getHandshakeRemoteAddress();
|
||||
return playerConnectedHostname();
|
||||
}
|
||||
StringBuilder data = new StringBuilder()
|
||||
.append(getHandshakeRemoteAddress())
|
||||
.append(playerConnectedHostname())
|
||||
.append('\0')
|
||||
.append(((InetSocketAddress) proxyPlayer.getRemoteAddress()).getHostString())
|
||||
.append(((InetSocketAddress) proxyPlayer.remoteAddress()).getHostString())
|
||||
.append('\0')
|
||||
.append(proxyPlayer.getGameProfile().getUndashedId())
|
||||
.append(proxyPlayer.gameProfile().getUndashedId())
|
||||
.append('\0');
|
||||
GENERAL_GSON
|
||||
.toJson(propertiesTransform.apply(proxyPlayer.getGameProfile().getProperties()), data);
|
||||
.toJson(propertiesTransform.apply(proxyPlayer.gameProfile().getProperties()), data);
|
||||
return data.toString();
|
||||
}
|
||||
|
||||
@@ -140,36 +158,37 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation,
|
||||
|
||||
private void startHandshake() {
|
||||
final MinecraftConnection mc = ensureConnected();
|
||||
PlayerInfoForwarding forwardingMode = server.getConfiguration().getPlayerInfoForwardingMode();
|
||||
PlayerInfoForwarding forwardingMode = server.configuration().getPlayerInfoForwardingMode();
|
||||
|
||||
// Initiate the handshake.
|
||||
ProtocolVersion protocolVersion = proxyPlayer.getConnection().getProtocolVersion();
|
||||
ServerboundHandshakePacket handshake = new ServerboundHandshakePacket();
|
||||
handshake.setNextStatus(StateRegistry.LOGIN_ID);
|
||||
handshake.setProtocolVersion(protocolVersion);
|
||||
if (forwardingMode == PlayerInfoForwarding.LEGACY) {
|
||||
handshake.setServerAddress(createLegacyForwardingAddress());
|
||||
} else if (forwardingMode == PlayerInfoForwarding.BUNGEEGUARD) {
|
||||
byte[] secret = server.getConfiguration().getForwardingSecret();
|
||||
handshake.setServerAddress(createBungeeGuardForwardingAddress(secret));
|
||||
} else if (proxyPlayer.getConnection().getType() == ConnectionTypes.LEGACY_FORGE) {
|
||||
handshake.setServerAddress(getHandshakeRemoteAddress() + HANDSHAKE_HOSTNAME_TOKEN);
|
||||
} else {
|
||||
handshake.setServerAddress(getHandshakeRemoteAddress());
|
||||
}
|
||||
|
||||
SocketAddress destinationAddr = registeredServer.getServerInfo().getAddress();
|
||||
if (destinationAddr instanceof InetSocketAddress) {
|
||||
handshake.setPort(((InetSocketAddress) destinationAddr).getPort());
|
||||
}
|
||||
String address = getHandshakeAddressField(forwardingMode);
|
||||
SocketAddress destinationAddr = registeredServer.serverInfo().address();
|
||||
int port = destinationAddr instanceof InetSocketAddress
|
||||
? ((InetSocketAddress) destinationAddr).getPort() : 0;
|
||||
ServerboundHandshakePacket handshake = new ServerboundHandshakePacket(protocolVersion,
|
||||
address, port, StateRegistry.LOGIN_ID);
|
||||
mc.delayedWrite(handshake);
|
||||
|
||||
mc.setProtocolVersion(protocolVersion);
|
||||
mc.setState(StateRegistry.LOGIN);
|
||||
mc.delayedWrite(new ServerboundServerLoginPacket(proxyPlayer.getUsername()));
|
||||
mc.delayedWrite(new ServerboundServerLoginPacket(proxyPlayer.username()));
|
||||
mc.flush();
|
||||
}
|
||||
|
||||
private String getHandshakeAddressField(PlayerInfoForwarding forwardingMode) {
|
||||
if (forwardingMode == PlayerInfoForwarding.LEGACY) {
|
||||
return createLegacyForwardingAddress();
|
||||
} else if (forwardingMode == PlayerInfoForwarding.BUNGEEGUARD) {
|
||||
byte[] secret = server.configuration().getForwardingSecret();
|
||||
return createBungeeGuardForwardingAddress(secret);
|
||||
} else if (proxyPlayer.getConnection().getType() == ConnectionTypes.LEGACY_FORGE) {
|
||||
return playerConnectedHostname() + HANDSHAKE_HOSTNAME_TOKEN;
|
||||
} else {
|
||||
return playerConnectedHostname();
|
||||
}
|
||||
}
|
||||
|
||||
public @Nullable MinecraftConnection getConnection() {
|
||||
return connection;
|
||||
}
|
||||
@@ -187,17 +206,17 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation,
|
||||
}
|
||||
|
||||
@Override
|
||||
public VelocityRegisteredServer getServer() {
|
||||
public VelocityRegisteredServer target() {
|
||||
return registeredServer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerInfo getServerInfo() {
|
||||
return registeredServer.getServerInfo();
|
||||
public ServerInfo serverInfo() {
|
||||
return registeredServer.serverInfo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectedPlayer getPlayer() {
|
||||
public ConnectedPlayer player() {
|
||||
return proxyPlayer;
|
||||
}
|
||||
|
||||
@@ -214,12 +233,12 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation,
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[server connection] " + proxyPlayer.getGameProfile().getName() + " -> "
|
||||
+ registeredServer.getServerInfo().getName();
|
||||
return "[server connection] " + proxyPlayer.gameProfile().getName() + " -> "
|
||||
+ registeredServer.serverInfo().name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sendPluginMessage(ChannelIdentifier identifier, byte[] data) {
|
||||
public boolean sendPluginMessage(PluginChannelId identifier, byte[] data) {
|
||||
return sendPluginMessage(identifier, Unpooled.wrappedBuffer(data));
|
||||
}
|
||||
|
||||
@@ -229,13 +248,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.getId(), data);
|
||||
ServerboundPluginMessagePacket message = new ServerboundPluginMessagePacket(
|
||||
channelIdForVersion(identifier, mc.getProtocolVersion()), data);
|
||||
mc.write(message);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.connection.client;
|
||||
|
||||
import com.velocitypowered.proxy.connection.backend.VelocityServerConnection;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.connection.client;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.connection.client;
|
||||
|
||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_13;
|
||||
@@ -8,14 +25,14 @@ import static com.velocitypowered.proxy.network.PluginMessageUtil.constructChann
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.velocitypowered.api.event.command.CommandExecuteEvent.CommandResult;
|
||||
import com.velocitypowered.api.event.connection.PluginMessageEvent;
|
||||
import com.velocitypowered.api.event.player.PlayerChannelRegisterEvent;
|
||||
import com.velocitypowered.api.event.connection.PluginMessageEventImpl;
|
||||
import com.velocitypowered.api.event.player.PlayerChannelRegisterEventImpl;
|
||||
import com.velocitypowered.api.event.player.PlayerChatEvent;
|
||||
import com.velocitypowered.api.event.player.PlayerResourcePackStatusEvent;
|
||||
import com.velocitypowered.api.event.player.TabCompleteEvent;
|
||||
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;
|
||||
@@ -53,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;
|
||||
@@ -86,10 +104,10 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
|
||||
@Override
|
||||
public void activated() {
|
||||
Collection<String> channels = server.getChannelRegistrar().getChannelsForProtocol(player
|
||||
.getProtocolVersion());
|
||||
Collection<String> channels = server.channelRegistrar().getChannelsForProtocol(player
|
||||
.protocolVersion());
|
||||
if (!channels.isEmpty()) {
|
||||
AbstractPluginMessagePacket<?> register = constructChannelsPacket(player.getProtocolVersion(),
|
||||
AbstractPluginMessagePacket<?> register = constructChannelsPacket(player.protocolVersion(),
|
||||
channels, ClientboundPluginMessagePacket.FACTORY);
|
||||
player.getConnection().write(register);
|
||||
player.getKnownChannels().addAll(channels);
|
||||
@@ -139,29 +157,28 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
String msg = packet.getMessage();
|
||||
if (msg.startsWith("/")) {
|
||||
String originalCommand = msg.substring(1);
|
||||
server.getCommandManager().callCommandEvent(player, msg.substring(1))
|
||||
server.commandManager().callCommandEvent(player, msg.substring(1))
|
||||
.thenComposeAsync(event -> processCommandExecuteResult(originalCommand,
|
||||
event.getResult()))
|
||||
event.result()))
|
||||
.whenComplete((ignored, throwable) -> {
|
||||
if (server.getConfiguration().isLogCommandExecutions()) {
|
||||
if (server.configuration().isLogCommandExecutions()) {
|
||||
logger.info("{} -> executed command /{}", player, originalCommand);
|
||||
}
|
||||
})
|
||||
.exceptionally(e -> {
|
||||
logger.info("Exception occurred while running command for {}",
|
||||
player.getUsername(), e);
|
||||
player.sendMessage(Identity.nil(),
|
||||
Component.text("An error occurred while running this command.",
|
||||
NamedTextColor.RED));
|
||||
player.username(), e);
|
||||
player.sendMessage(Component.translatable("velocity.command.generic-error",
|
||||
NamedTextColor.RED));
|
||||
return null;
|
||||
});
|
||||
} else {
|
||||
PlayerChatEvent event = new PlayerChatEvent(player, msg);
|
||||
server.getEventManager().fire(event)
|
||||
PlayerChatEvent event = new PlayerChatEventImpl(player, msg);
|
||||
server.eventManager().fire(event)
|
||||
.thenAcceptAsync(pme -> {
|
||||
PlayerChatEvent.ChatResult chatResult = pme.getResult();
|
||||
PlayerChatEventImpl.ChatResult chatResult = pme.result();
|
||||
if (chatResult.isAllowed()) {
|
||||
Optional<String> eventMsg = pme.getResult().getMessage();
|
||||
Optional<String> eventMsg = pme.result().modifiedMessage();
|
||||
if (eventMsg.isPresent()) {
|
||||
smc.write(new ServerboundChatPacket(eventMsg.get()));
|
||||
} else {
|
||||
@@ -199,23 +216,28 @@ 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.getEventManager().fireAndForget(new PlayerChannelRegisterEvent(player,
|
||||
ImmutableList.copyOf(channelIdentifiers)));
|
||||
|
||||
server.eventManager().fireAndForget(new PlayerChannelRegisterEventImpl(player,
|
||||
ImmutableList.copyOf(pluginChannelIds)));
|
||||
backendConn.write(packet.retain());
|
||||
} else if (PluginMessageUtil.isUnregister(packet)) {
|
||||
player.getKnownChannels().removeAll(PluginMessageUtil.getChannels(packet));
|
||||
backendConn.write(packet.retain());
|
||||
} else if (PluginMessageUtil.isMcBrand(packet)) {
|
||||
backendConn.write(PluginMessageUtil
|
||||
.rewriteMinecraftBrand(packet, server.getVersion(), player.getProtocolVersion(), ServerboundPluginMessagePacket.FACTORY));
|
||||
.rewriteMinecraftBrand(packet, server.version(), player.protocolVersion(), ServerboundPluginMessagePacket.FACTORY));
|
||||
} else if (BungeeCordMessageResponder.isBungeeCordMessage(packet)) {
|
||||
return true;
|
||||
} else {
|
||||
@@ -240,14 +262,14 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
// appropriately.
|
||||
loginPluginMessages.add(packet.retain());
|
||||
} else {
|
||||
ChannelIdentifier id = server.getChannelRegistrar().getFromId(packet.getChannel());
|
||||
PluginChannelId id = server.channelRegistrar().getFromId(packet.getChannel());
|
||||
if (id == null) {
|
||||
backendConn.write(packet.retain());
|
||||
} else {
|
||||
byte[] copy = ByteBufUtil.getBytes(packet.content());
|
||||
PluginMessageEvent event = new PluginMessageEvent(player, serverConn, id, copy);
|
||||
server.getEventManager().fire(event).thenAcceptAsync(pme -> {
|
||||
if (pme.getResult().isAllowed()) {
|
||||
PluginMessageEvent event = new PluginMessageEventImpl(player, serverConn, id, copy);
|
||||
server.eventManager().fire(event).thenAcceptAsync(pme -> {
|
||||
if (pme.result().isAllowed()) {
|
||||
ServerboundPluginMessagePacket message = new ServerboundPluginMessagePacket(packet.getChannel(),
|
||||
Unpooled.wrappedBuffer(copy));
|
||||
backendConn.write(message);
|
||||
@@ -269,7 +291,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
|
||||
@Override
|
||||
public boolean handle(ServerboundResourcePackResponsePacket packet) {
|
||||
server.getEventManager().fireAndForget(new PlayerResourcePackStatusEvent(player,
|
||||
server.eventManager().fireAndForget(new PlayerResourcePackStatusEventImpl(player,
|
||||
packet.getStatus()));
|
||||
return false;
|
||||
}
|
||||
@@ -312,7 +334,8 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
|
||||
@Override
|
||||
public void exception(Throwable throwable) {
|
||||
player.disconnect(server.getConfiguration().getMessages().getGenericConnectionError());
|
||||
player.disconnect(Component.translatable("velocity.error.player-connection-error",
|
||||
NamedTextColor.RED));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -353,7 +376,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
player.getPhase().onFirstJoin(player);
|
||||
} else {
|
||||
// Clear tab list to avoid duplicate entries
|
||||
player.getTabList().clearAll();
|
||||
player.tabList().clearAll();
|
||||
if (player.getConnection().getType() == ConnectionTypes.LEGACY_FORGE) {
|
||||
this.doSafeClientServerSwitch(joinGame);
|
||||
} else {
|
||||
@@ -385,9 +408,9 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
}
|
||||
|
||||
// Clear any title from the previous server.
|
||||
if (player.getProtocolVersion().gte(MINECRAFT_1_8)) {
|
||||
if (player.protocolVersion().gte(MINECRAFT_1_8)) {
|
||||
player.getConnection()
|
||||
.delayedWrite(ClientboundTitlePacket.reset(player.getProtocolVersion()));
|
||||
.delayedWrite(ClientboundTitlePacket.reset(player.protocolVersion()));
|
||||
}
|
||||
|
||||
// Flush everything
|
||||
@@ -406,7 +429,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
// to perform entity ID rewrites, eliminating potential issues from rewriting packets and
|
||||
// improving compatibility with mods.
|
||||
int sentOldDim = joinGame.getDimension();
|
||||
if (player.getProtocolVersion().lt(MINECRAFT_1_16)) {
|
||||
if (player.protocolVersion().lt(MINECRAFT_1_16)) {
|
||||
// Before Minecraft 1.16, we could not switch to the same dimension without sending an
|
||||
// additional respawn. On older versions of Minecraft this forces the client to perform
|
||||
// garbage collection which adds additional latency.
|
||||
@@ -458,8 +481,8 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
}
|
||||
|
||||
String commandLabel = command.substring(0, commandEndPosition);
|
||||
if (!server.getCommandManager().hasCommand(commandLabel)) {
|
||||
if (player.getProtocolVersion().lt(MINECRAFT_1_13)) {
|
||||
if (!server.commandManager().hasCommand(commandLabel)) {
|
||||
if (player.protocolVersion().lt(MINECRAFT_1_13)) {
|
||||
// Outstanding tab completes are recorded for use with 1.12 clients and below to provide
|
||||
// additional tab completion support.
|
||||
outstandingTabComplete = packet;
|
||||
@@ -467,7 +490,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
return false;
|
||||
}
|
||||
|
||||
server.getCommandManager().offerSuggestions(player, command)
|
||||
server.commandManager().offerSuggestions(player, command)
|
||||
.thenAcceptAsync(suggestions -> {
|
||||
if (suggestions.isEmpty()) {
|
||||
return;
|
||||
@@ -496,7 +519,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
}
|
||||
|
||||
private boolean handleRegularTabComplete(ServerboundTabCompleteRequestPacket packet) {
|
||||
if (player.getProtocolVersion().lt(MINECRAFT_1_13)) {
|
||||
if (player.protocolVersion().lt(MINECRAFT_1_13)) {
|
||||
// Outstanding tab completes are recorded for use with 1.12 clients and below to provide
|
||||
// additional tab completion support.
|
||||
outstandingTabComplete = packet;
|
||||
@@ -526,9 +549,9 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
private void finishCommandTabComplete(ServerboundTabCompleteRequestPacket request,
|
||||
ClientboundTabCompleteResponsePacket response) {
|
||||
String command = request.getCommand().substring(1);
|
||||
server.getCommandManager().offerSuggestions(player, command)
|
||||
server.commandManager().offerSuggestions(player, command)
|
||||
.thenAcceptAsync(offers -> {
|
||||
boolean legacy = player.getProtocolVersion().lt(MINECRAFT_1_13);
|
||||
boolean legacy = player.protocolVersion().lt(MINECRAFT_1_13);
|
||||
try {
|
||||
for (String offer : offers) {
|
||||
offer = legacy && !offer.startsWith("/") ? "/" + offer : offer;
|
||||
@@ -541,7 +564,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
player.getConnection().write(response);
|
||||
} catch (Exception e) {
|
||||
logger.error("Unable to provide tab list completions for {} for command '{}'",
|
||||
player.getUsername(),
|
||||
player.username(),
|
||||
command, e);
|
||||
}
|
||||
}, player.getConnection().eventLoop())
|
||||
@@ -559,10 +582,10 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
for (Offer offer : response.getOffers()) {
|
||||
offers.add(offer.getText());
|
||||
}
|
||||
server.getEventManager().fire(new TabCompleteEvent(player, request.getCommand(), offers))
|
||||
server.eventManager().fire(new TabCompleteEventImpl(player, request.getCommand(), offers))
|
||||
.thenAcceptAsync(e -> {
|
||||
response.getOffers().clear();
|
||||
for (String s : e.getSuggestions()) {
|
||||
for (String s : e.suggestions()) {
|
||||
response.getOffers().add(new Offer(s));
|
||||
}
|
||||
player.getConnection().write(response);
|
||||
@@ -582,12 +605,12 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
}
|
||||
|
||||
MinecraftConnection smc = player.ensureAndGetCurrentServer().ensureConnected();
|
||||
String commandToRun = result.getCommand().orElse(originalCommand);
|
||||
String commandToRun = result.modifiedCommand().orElse(originalCommand);
|
||||
if (result.isForwardToServer()) {
|
||||
return CompletableFuture.runAsync(() -> smc.write(new ServerboundChatPacket("/"
|
||||
+ commandToRun)), smc.eventLoop());
|
||||
} else {
|
||||
return server.getCommandManager().executeImmediately(player, commandToRun)
|
||||
return server.commandManager().executeImmediately(player, commandToRun)
|
||||
.thenAcceptAsync(hasRun -> {
|
||||
if (!hasRun) {
|
||||
smc.write(new ServerboundChatPacket("/" + commandToRun));
|
||||
|
||||
@@ -1,14 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.connection.client;
|
||||
|
||||
import com.velocitypowered.api.proxy.player.PlayerSettings;
|
||||
import com.velocitypowered.api.proxy.player.ClientSettings;
|
||||
import com.velocitypowered.api.proxy.player.SkinParts;
|
||||
import com.velocitypowered.proxy.network.packet.serverbound.ServerboundClientSettingsPacket;
|
||||
import java.util.Locale;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class ClientSettingsWrapper implements PlayerSettings {
|
||||
public class ClientSettingsWrapper implements ClientSettings {
|
||||
|
||||
static final PlayerSettings DEFAULT = new ClientSettingsWrapper(
|
||||
static final ClientSettings DEFAULT = new ClientSettingsWrapper(
|
||||
new ServerboundClientSettingsPacket("en_US", (byte) 10, 0, true, (short) 127, 1));
|
||||
|
||||
private final ServerboundClientSettingsPacket settings;
|
||||
|
||||
@@ -1,35 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.velocitypowered.api.event.player.DisconnectEvent;
|
||||
import com.velocitypowered.api.event.player.DisconnectEvent.LoginStatus;
|
||||
import com.velocitypowered.api.event.player.DisconnectEventImpl;
|
||||
import com.velocitypowered.api.event.player.KickedFromServerEvent;
|
||||
import com.velocitypowered.api.event.player.KickedFromServerEvent.DisconnectPlayer;
|
||||
import com.velocitypowered.api.event.player.KickedFromServerEvent.Notify;
|
||||
import com.velocitypowered.api.event.player.KickedFromServerEvent.RedirectPlayer;
|
||||
import com.velocitypowered.api.event.player.KickedFromServerEvent.ServerKickResult;
|
||||
import com.velocitypowered.api.event.player.PlayerModInfoEvent;
|
||||
import com.velocitypowered.api.event.player.PlayerSettingsChangedEvent;
|
||||
import com.velocitypowered.api.event.player.KickedFromServerEventImpl;
|
||||
import com.velocitypowered.api.event.player.PlayerClientSettingsChangedEventImpl;
|
||||
import com.velocitypowered.api.event.player.PlayerModInfoEventImpl;
|
||||
import com.velocitypowered.api.event.player.ServerPreConnectEvent;
|
||||
import com.velocitypowered.api.event.player.ServerPreConnectEventImpl;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.api.permission.PermissionFunction;
|
||||
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.player.PlayerSettings;
|
||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
import com.velocitypowered.api.util.GameProfile;
|
||||
import com.velocitypowered.api.util.ModInfo;
|
||||
import com.velocitypowered.proxy.VelocityServer;
|
||||
import com.velocitypowered.proxy.config.VelocityConfiguration;
|
||||
import com.velocitypowered.proxy.connection.MinecraftConnection;
|
||||
import com.velocitypowered.proxy.connection.MinecraftConnectionAssociation;
|
||||
import com.velocitypowered.proxy.connection.backend.VelocityServerConnection;
|
||||
@@ -42,7 +62,6 @@ import com.velocitypowered.proxy.network.StateRegistry;
|
||||
import com.velocitypowered.proxy.network.packet.AbstractPluginMessagePacket;
|
||||
import com.velocitypowered.proxy.network.packet.clientbound.ClientboundChatPacket;
|
||||
import com.velocitypowered.proxy.network.packet.clientbound.ClientboundDisconnectPacket;
|
||||
import com.velocitypowered.proxy.network.packet.clientbound.ClientboundHeaderAndFooterPacket;
|
||||
import com.velocitypowered.proxy.network.packet.clientbound.ClientboundKeepAlivePacket;
|
||||
import com.velocitypowered.proxy.network.packet.clientbound.ClientboundPluginMessagePacket;
|
||||
import com.velocitypowered.proxy.network.packet.clientbound.ClientboundResourcePackRequestPacket;
|
||||
@@ -60,6 +79,7 @@ import java.net.SocketAddress;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
@@ -75,6 +95,9 @@ import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.plain.PlainComponentSerializer;
|
||||
import net.kyori.adventure.title.Title;
|
||||
import net.kyori.adventure.title.Title.Times;
|
||||
import net.kyori.adventure.translation.GlobalTranslator;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
@@ -103,7 +126,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
private final boolean onlineMode;
|
||||
private @Nullable VelocityServerConnection connectedServer;
|
||||
private @Nullable VelocityServerConnection connectionInFlight;
|
||||
private @Nullable PlayerSettings settings;
|
||||
private @Nullable ClientSettings settings;
|
||||
private @Nullable ModInfo modInfo;
|
||||
private Component playerListHeader = Component.empty();
|
||||
private Component playerListFooter = Component.empty();
|
||||
@@ -138,17 +161,17 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
public String username() {
|
||||
return profile.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getUniqueId() {
|
||||
public UUID id() {
|
||||
return profile.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<ServerConnection> getCurrentServer() {
|
||||
public Optional<ServerConnection> connectedServer() {
|
||||
return Optional.ofNullable(connectedServer);
|
||||
}
|
||||
|
||||
@@ -165,7 +188,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameProfile getGameProfile() {
|
||||
public GameProfile gameProfile() {
|
||||
return profile;
|
||||
}
|
||||
|
||||
@@ -174,7 +197,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPing() {
|
||||
public long ping() {
|
||||
return this.ping;
|
||||
}
|
||||
|
||||
@@ -183,38 +206,38 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOnlineMode() {
|
||||
public boolean onlineMode() {
|
||||
return onlineMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlayerSettings getPlayerSettings() {
|
||||
public ClientSettings clientSettings() {
|
||||
return settings == null ? ClientSettingsWrapper.DEFAULT : this.settings;
|
||||
}
|
||||
|
||||
void setPlayerSettings(ServerboundClientSettingsPacket settings) {
|
||||
ClientSettingsWrapper cs = new ClientSettingsWrapper(settings);
|
||||
this.settings = cs;
|
||||
server.getEventManager().fireAndForget(new PlayerSettingsChangedEvent(this, cs));
|
||||
server.eventManager().fireAndForget(new PlayerClientSettingsChangedEventImpl(this, cs));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<ModInfo> getModInfo() {
|
||||
public Optional<ModInfo> modInfo() {
|
||||
return Optional.ofNullable(modInfo);
|
||||
}
|
||||
|
||||
public void setModInfo(ModInfo modInfo) {
|
||||
this.modInfo = modInfo;
|
||||
server.getEventManager().fireAndForget(new PlayerModInfoEvent(this, modInfo));
|
||||
server.eventManager().fireAndForget(new PlayerModInfoEventImpl(this, modInfo));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocketAddress getRemoteAddress() {
|
||||
public SocketAddress remoteAddress() {
|
||||
return connection.getRemoteAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<InetSocketAddress> getVirtualHost() {
|
||||
public Optional<InetSocketAddress> connectedHostname() {
|
||||
return Optional.ofNullable(virtualHost);
|
||||
}
|
||||
|
||||
@@ -228,18 +251,25 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolVersion getProtocolVersion() {
|
||||
public ProtocolVersion protocolVersion() {
|
||||
return connection.getProtocolVersion();
|
||||
}
|
||||
|
||||
public Component translateMessage(Component message) {
|
||||
Locale locale = this.settings == null ? Locale.getDefault() : this.settings.getLocale();
|
||||
return GlobalTranslator.render(message, locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(@NonNull Identity identity, @NonNull Component message,
|
||||
@NonNull MessageType type) {
|
||||
Preconditions.checkNotNull(message, "message");
|
||||
Preconditions.checkNotNull(type, "type");
|
||||
|
||||
Component translated = translateMessage(message);
|
||||
|
||||
connection.write(new ClientboundChatPacket(
|
||||
ProtocolUtils.getJsonChatSerializer(this.getProtocolVersion()).serialize(message),
|
||||
ProtocolUtils.getJsonChatSerializer(this.protocolVersion()).serialize(translated),
|
||||
type == MessageType.CHAT
|
||||
? ClientboundChatPacket.CHAT_TYPE
|
||||
: ClientboundChatPacket.SYSTEM_TYPE,
|
||||
@@ -249,18 +279,21 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
|
||||
@Override
|
||||
public void sendActionBar(net.kyori.adventure.text.@NonNull Component message) {
|
||||
ProtocolVersion playerVersion = getProtocolVersion();
|
||||
Component translated = translateMessage(message);
|
||||
|
||||
ProtocolVersion playerVersion = protocolVersion();
|
||||
if (playerVersion.gte(ProtocolVersion.MINECRAFT_1_11)) {
|
||||
// Use the title packet instead.
|
||||
connection.write(new ClientboundTitlePacket(
|
||||
ClientboundTitlePacket.SET_ACTION_BAR,
|
||||
ProtocolUtils.getJsonChatSerializer(playerVersion).serialize(message)
|
||||
ProtocolUtils.getJsonChatSerializer(playerVersion).serialize(translated)
|
||||
));
|
||||
} else {
|
||||
// Due to issues with action bar packets, we'll need to convert the text message into a
|
||||
// legacy message and then inject the legacy text into a component... yuck!
|
||||
JsonObject object = new JsonObject();
|
||||
object.addProperty("text", LegacyComponentSerializer.legacySection().serialize(message));
|
||||
object.addProperty("text", LegacyComponentSerializer.legacySection()
|
||||
.serialize(translated));
|
||||
connection.write(new ClientboundChatPacket(
|
||||
object.toString(),
|
||||
ClientboundChatPacket.GAME_INFO_TYPE,
|
||||
@@ -287,24 +320,24 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showTitle(net.kyori.adventure.title.@NonNull Title title) {
|
||||
if (this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
|
||||
public void showTitle(@NonNull Title title) {
|
||||
if (this.protocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
|
||||
GsonComponentSerializer serializer = ProtocolUtils.getJsonChatSerializer(this
|
||||
.getProtocolVersion());
|
||||
.protocolVersion());
|
||||
|
||||
connection.delayedWrite(new ClientboundTitlePacket(
|
||||
ClientboundTitlePacket.SET_TITLE,
|
||||
serializer.serialize(title.title())
|
||||
serializer.serialize(translateMessage(title.title()))
|
||||
));
|
||||
|
||||
connection.delayedWrite(new ClientboundTitlePacket(
|
||||
ClientboundTitlePacket.SET_SUBTITLE,
|
||||
serializer.serialize(title.subtitle())
|
||||
serializer.serialize(translateMessage(title.subtitle()))
|
||||
));
|
||||
|
||||
net.kyori.adventure.title.Title.Times times = title.times();
|
||||
Times times = title.times();
|
||||
if (times != null) {
|
||||
connection.delayedWrite(ClientboundTitlePacket.times(this.getProtocolVersion(), times));
|
||||
connection.delayedWrite(ClientboundTitlePacket.times(this.protocolVersion(), times));
|
||||
}
|
||||
|
||||
connection.flush();
|
||||
@@ -313,28 +346,28 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
|
||||
@Override
|
||||
public void clearTitle() {
|
||||
if (this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
|
||||
connection.write(ClientboundTitlePacket.hide(this.getProtocolVersion()));
|
||||
if (this.protocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
|
||||
connection.write(ClientboundTitlePacket.hide(this.protocolVersion()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetTitle() {
|
||||
if (this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
|
||||
connection.write(ClientboundTitlePacket.reset(this.getProtocolVersion()));
|
||||
if (this.protocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
|
||||
connection.write(ClientboundTitlePacket.reset(this.protocolVersion()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hideBossBar(@NonNull BossBar bar) {
|
||||
if (this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_9) >= 0) {
|
||||
if (this.protocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_9) >= 0) {
|
||||
this.server.getBossBarManager().removeBossBar(this, bar);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showBossBar(@NonNull BossBar bar) {
|
||||
if (this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_9) >= 0) {
|
||||
if (this.protocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_9) >= 0) {
|
||||
this.server.getBossBarManager().addBossBar(this, bar);
|
||||
}
|
||||
}
|
||||
@@ -350,7 +383,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
}
|
||||
|
||||
@Override
|
||||
public VelocityTabList getTabList() {
|
||||
public VelocityTabList tabList() {
|
||||
return tabList;
|
||||
}
|
||||
|
||||
@@ -369,9 +402,11 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
* @param duringLogin whether the disconnect happened during login
|
||||
*/
|
||||
public void disconnect0(Component reason, boolean duringLogin) {
|
||||
Component translated = this.translateMessage(reason);
|
||||
|
||||
logger.info("{} has disconnected: {}", this,
|
||||
LegacyComponentSerializer.legacySection().serialize(reason));
|
||||
connection.closeWith(ClientboundDisconnectPacket.create(reason, this.getProtocolVersion()));
|
||||
LegacyComponentSerializer.legacySection().serialize(translated));
|
||||
connection.closeWith(ClientboundDisconnectPacket.create(translated, this.protocolVersion()));
|
||||
}
|
||||
|
||||
public @Nullable VelocityServerConnection getConnectedServer() {
|
||||
@@ -410,18 +445,18 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
wrapped = cause;
|
||||
}
|
||||
}
|
||||
String userMessage;
|
||||
if (connectedServer != null && connectedServer.getServerInfo().equals(server.getServerInfo())) {
|
||||
userMessage = "Your connection to " + server.getServerInfo().getName() + " encountered an "
|
||||
+ "error.";
|
||||
|
||||
Component friendlyError;
|
||||
if (connectedServer != null && connectedServer.serverInfo().equals(server.serverInfo())) {
|
||||
friendlyError = Component.translatable("velocity.error.connected-server-error",
|
||||
Component.text(server.serverInfo().name()));
|
||||
} else {
|
||||
logger.error("{}: unable to connect to server {}", this, server.getServerInfo().getName(),
|
||||
logger.error("{}: unable to connect to server {}", this, server.serverInfo().name(),
|
||||
wrapped);
|
||||
userMessage = "Unable to connect to " + server.getServerInfo().getName() + ". Try again "
|
||||
+ "later.";
|
||||
friendlyError = Component.translatable("velocity.error.connecting-server-error",
|
||||
Component.text(server.serverInfo().name()));
|
||||
}
|
||||
handleConnectionException(server, null, Component.text(userMessage,
|
||||
NamedTextColor.RED), safe);
|
||||
handleConnectionException(server, null, friendlyError.color(NamedTextColor.RED), safe);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -437,26 +472,22 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
return;
|
||||
}
|
||||
|
||||
VelocityConfiguration.Messages messages = this.server.getConfiguration().getMessages();
|
||||
Component disconnectReason = GsonComponentSerializer.gson().deserialize(disconnect.getReason());
|
||||
String plainTextReason = PASS_THRU_TRANSLATE.serialize(disconnectReason);
|
||||
if (connectedServer != null && connectedServer.getServerInfo().equals(server.getServerInfo())) {
|
||||
logger.error("{}: kicked from server {}: {}", this, server.getServerInfo().getName(),
|
||||
if (connectedServer != null && connectedServer.serverInfo().equals(server.serverInfo())) {
|
||||
logger.error("{}: kicked from server {}: {}", this, server.serverInfo().name(),
|
||||
plainTextReason);
|
||||
handleConnectionException(server, disconnectReason, Component.text()
|
||||
.append(messages.getKickPrefix(server.getServerInfo().getName())
|
||||
.colorIfAbsent(NamedTextColor.RED))
|
||||
.color(NamedTextColor.RED)
|
||||
.append(disconnectReason)
|
||||
.build(), safe);
|
||||
handleConnectionException(server, disconnectReason,
|
||||
Component.translatable("velocity.error.moved-to-new-server", NamedTextColor.RED,
|
||||
Component.text(server.serverInfo().name()),
|
||||
disconnectReason), safe);
|
||||
} else {
|
||||
logger.error("{}: disconnected while connecting to {}: {}", this,
|
||||
server.getServerInfo().getName(), plainTextReason);
|
||||
handleConnectionException(server, disconnectReason, Component.text()
|
||||
.append(messages.getDisconnectPrefix(server.getServerInfo().getName())
|
||||
.colorIfAbsent(NamedTextColor.RED))
|
||||
.append(disconnectReason)
|
||||
.build(), safe);
|
||||
server.serverInfo().name(), plainTextReason);
|
||||
handleConnectionException(server, disconnectReason,
|
||||
Component.translatable("velocity.error.cant-connect", NamedTextColor.RED,
|
||||
Component.text(server.serverInfo().name()),
|
||||
disconnectReason), safe);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -475,7 +506,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean kickedFromCurrent = connectedServer == null || connectedServer.getServer().equals(rs);
|
||||
boolean kickedFromCurrent = connectedServer == null || connectedServer.target().equals(rs);
|
||||
ServerKickResult result;
|
||||
if (kickedFromCurrent) {
|
||||
Optional<RegisteredServer> next = getNextServerToTry(rs);
|
||||
@@ -483,19 +514,19 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
.orElseGet(() -> DisconnectPlayer.create(friendlyReason));
|
||||
} else {
|
||||
// If we were kicked by going to another server, the connection should not be in flight
|
||||
if (connectionInFlight != null && connectionInFlight.getServer().equals(rs)) {
|
||||
if (connectionInFlight != null && connectionInFlight.target().equals(rs)) {
|
||||
resetInFlightConnection();
|
||||
}
|
||||
result = Notify.create(friendlyReason);
|
||||
}
|
||||
KickedFromServerEvent originalEvent = new KickedFromServerEvent(this, rs, kickReason,
|
||||
KickedFromServerEvent originalEvent = new KickedFromServerEventImpl(this, rs, kickReason,
|
||||
!kickedFromCurrent, result);
|
||||
handleKickEvent(originalEvent, friendlyReason, kickedFromCurrent);
|
||||
}
|
||||
|
||||
private void handleKickEvent(KickedFromServerEvent originalEvent, Component friendlyReason,
|
||||
boolean kickedFromCurrent) {
|
||||
server.getEventManager().fire(originalEvent)
|
||||
server.eventManager().fire(originalEvent)
|
||||
.thenAcceptAsync(event -> {
|
||||
// There can't be any connection in flight now.
|
||||
connectionInFlight = null;
|
||||
@@ -511,49 +542,51 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getResult() instanceof DisconnectPlayer) {
|
||||
DisconnectPlayer res = (DisconnectPlayer) event.getResult();
|
||||
disconnect(res.getReason());
|
||||
} else if (event.getResult() instanceof RedirectPlayer) {
|
||||
RedirectPlayer res = (RedirectPlayer) event.getResult();
|
||||
if (event.result() instanceof DisconnectPlayer) {
|
||||
DisconnectPlayer res = (DisconnectPlayer) event.result();
|
||||
disconnect(res.message());
|
||||
} else if (event.result() instanceof RedirectPlayer) {
|
||||
RedirectPlayer res = (RedirectPlayer) event.result();
|
||||
createConnectionRequest(res.getServer())
|
||||
.connect()
|
||||
.whenCompleteAsync((status, throwable) -> {
|
||||
if (throwable != null) {
|
||||
handleConnectionException(status != null ? status.getAttemptedConnection()
|
||||
handleConnectionException(status != null ? status.finalTarget()
|
||||
: res.getServer(), throwable, true);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (status.getStatus()) {
|
||||
switch (status.status()) {
|
||||
// Impossible/nonsensical cases
|
||||
case ALREADY_CONNECTED:
|
||||
case CONNECTION_IN_PROGRESS:
|
||||
// Fatal case
|
||||
case CONNECTION_CANCELLED:
|
||||
disconnect(status.getReason().orElse(res.getMessage()));
|
||||
disconnect(status.failureReason().orElse(res.message()));
|
||||
break;
|
||||
case SERVER_DISCONNECTED:
|
||||
Component reason = status.getReason()
|
||||
Component reason = status.failureReason()
|
||||
.orElse(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR);
|
||||
handleConnectionException(res.getServer(), ClientboundDisconnectPacket.create(reason,
|
||||
getProtocolVersion()), ((Impl) status).isSafe());
|
||||
protocolVersion()), ((Impl) status).isSafe());
|
||||
break;
|
||||
case SUCCESS:
|
||||
sendMessage(Identity.nil(), server.getConfiguration().getMessages()
|
||||
.getMovedToNewServerPrefix().append(friendlyReason));
|
||||
sendMessage(Component.translatable("velocity.error.moved-to-new-server",
|
||||
NamedTextColor.RED,
|
||||
Component.text(originalEvent.server().serverInfo().name()),
|
||||
friendlyReason));
|
||||
break;
|
||||
default:
|
||||
// The only remaining value is successful (no need to do anything!)
|
||||
break;
|
||||
}
|
||||
}, connection.eventLoop());
|
||||
} else if (event.getResult() instanceof Notify) {
|
||||
Notify res = (Notify) event.getResult();
|
||||
} else if (event.result() instanceof Notify) {
|
||||
Notify res = (Notify) event.result();
|
||||
if (event.kickedDuringServerConnect() && previouslyConnected) {
|
||||
sendMessage(Identity.nil(), res.getMessage());
|
||||
sendMessage(Identity.nil(), res.message());
|
||||
} else {
|
||||
disconnect(res.getMessage());
|
||||
disconnect(res.message());
|
||||
}
|
||||
} else {
|
||||
// In case someone gets creative, assume we want to disconnect the player.
|
||||
@@ -582,31 +615,33 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
*/
|
||||
private Optional<RegisteredServer> getNextServerToTry(@Nullable RegisteredServer current) {
|
||||
if (serversToTry == null) {
|
||||
String virtualHostStr = getVirtualHost().map(InetSocketAddress::getHostString).orElse("");
|
||||
serversToTry = server.getConfiguration().getForcedHosts().getOrDefault(virtualHostStr,
|
||||
String virtualHostStr = connectedHostname().map(InetSocketAddress::getHostString)
|
||||
.orElse("")
|
||||
.toLowerCase(Locale.ROOT);
|
||||
serversToTry = server.configuration().getForcedHosts().getOrDefault(virtualHostStr,
|
||||
Collections.emptyList());
|
||||
}
|
||||
|
||||
if (serversToTry.isEmpty()) {
|
||||
serversToTry = server.getConfiguration().getAttemptConnectionOrder();
|
||||
serversToTry = server.configuration().getAttemptConnectionOrder();
|
||||
}
|
||||
|
||||
for (int i = tryIndex; i < serversToTry.size(); i++) {
|
||||
String toTryName = serversToTry.get(i);
|
||||
if ((connectedServer != null && hasSameName(connectedServer.getServer(), toTryName))
|
||||
|| (connectionInFlight != null && hasSameName(connectionInFlight.getServer(), toTryName))
|
||||
if ((connectedServer != null && hasSameName(connectedServer.target(), toTryName))
|
||||
|| (connectionInFlight != null && hasSameName(connectionInFlight.target(), toTryName))
|
||||
|| (current != null && hasSameName(current, toTryName))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
tryIndex = i;
|
||||
return server.getServer(toTryName);
|
||||
return server.server(toTryName);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private static boolean hasSameName(RegisteredServer server, String name) {
|
||||
return server.getServerInfo().getName().equalsIgnoreCase(name);
|
||||
return server.serverInfo().name().equalsIgnoreCase(name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -649,12 +684,12 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
connectedServer.disconnect();
|
||||
}
|
||||
|
||||
Optional<Player> connectedPlayer = server.getPlayer(this.getUniqueId());
|
||||
Optional<Player> connectedPlayer = server.getPlayer(this.id());
|
||||
server.unregisterConnection(this);
|
||||
|
||||
DisconnectEvent.LoginStatus status;
|
||||
DisconnectEventImpl.LoginStatus status;
|
||||
if (connectedPlayer.isPresent()) {
|
||||
if (!connectedPlayer.get().getCurrentServer().isPresent()) {
|
||||
if (!connectedPlayer.get().connectedServer().isPresent()) {
|
||||
status = LoginStatus.PRE_SERVER_JOIN;
|
||||
} else {
|
||||
status = connectedPlayer.get() == this ? LoginStatus.SUCCESSFUL_LOGIN
|
||||
@@ -665,8 +700,8 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
LoginStatus.CANCELLED_BY_USER;
|
||||
}
|
||||
|
||||
DisconnectEvent event = new DisconnectEvent(this, status);
|
||||
server.getEventManager().fire(event).whenComplete((val, ex) -> {
|
||||
DisconnectEvent event = new DisconnectEventImpl(this, status);
|
||||
server.eventManager().fire(event).whenComplete((val, ex) -> {
|
||||
if (ex == null) {
|
||||
this.teardownFuture.complete(null);
|
||||
} else {
|
||||
@@ -681,19 +716,20 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[connected player] " + profile.getName() + " (" + getRemoteAddress() + ")";
|
||||
return "[connected player] " + profile.getName() + " (" + remoteAddress() + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tristate getPermissionValue(String permission) {
|
||||
return permissionFunction.getPermissionValue(permission);
|
||||
public Tristate evaluatePermission(String permission) {
|
||||
return permissionFunction.evaluatePermission(permission);
|
||||
}
|
||||
|
||||
@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.getId(),
|
||||
ClientboundPluginMessagePacket message = new ClientboundPluginMessagePacket(
|
||||
channelIdForVersion(identifier, connection.getProtocolVersion()),
|
||||
Unpooled.wrappedBuffer(data));
|
||||
connection.write(message);
|
||||
return true;
|
||||
@@ -711,7 +747,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
public void sendResourcePack(String url) {
|
||||
Preconditions.checkNotNull(url, "url");
|
||||
|
||||
if (this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
|
||||
if (this.protocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
|
||||
connection.write(new ClientboundResourcePackRequestPacket(url, ""));
|
||||
}
|
||||
}
|
||||
@@ -722,7 +758,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
Preconditions.checkNotNull(hash, "hash");
|
||||
Preconditions.checkArgument(hash.length == 20, "Hash length is not 20");
|
||||
|
||||
if (this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
|
||||
if (this.protocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
|
||||
connection.write(new ClientboundResourcePackRequestPacket(url, ByteBufUtil.hexDump(hash)));
|
||||
}
|
||||
}
|
||||
@@ -794,7 +830,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
private class IdentityImpl implements Identity {
|
||||
@Override
|
||||
public @NonNull UUID uuid() {
|
||||
return ConnectedPlayer.this.getUniqueId();
|
||||
return ConnectedPlayer.this.id();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -807,7 +843,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegisteredServer getServer() {
|
||||
public RegisteredServer target() {
|
||||
return toConnect;
|
||||
}
|
||||
|
||||
@@ -818,7 +854,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
&& !connectedServer.hasCompletedJoin())) {
|
||||
return Optional.of(ConnectionRequestBuilder.Status.CONNECTION_IN_PROGRESS);
|
||||
}
|
||||
if (connectedServer != null && connectedServer.getServer().equals(server)) {
|
||||
if (connectedServer != null && connectedServer.target().equals(server)) {
|
||||
return Optional.of(ALREADY_CONNECTED);
|
||||
}
|
||||
return Optional.empty();
|
||||
@@ -835,11 +871,11 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
return completedFuture(plainResult(initialCheck.get(), toConnect));
|
||||
}
|
||||
|
||||
ServerPreConnectEvent event = new ServerPreConnectEvent(ConnectedPlayer.this,
|
||||
ServerPreConnectEvent event = new ServerPreConnectEventImpl(ConnectedPlayer.this,
|
||||
toConnect);
|
||||
return server.getEventManager().fire(event)
|
||||
return server.eventManager().fire(event)
|
||||
.thenComposeAsync(newEvent -> {
|
||||
Optional<RegisteredServer> newDest = newEvent.getResult().getServer();
|
||||
Optional<RegisteredServer> newDest = newEvent.result().target();
|
||||
if (!newDest.isPresent()) {
|
||||
return completedFuture(
|
||||
plainResult(ConnectionRequestBuilder.Status.CONNECTION_CANCELLED, toConnect)
|
||||
@@ -856,8 +892,10 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
VelocityServerConnection con = new VelocityServerConnection(vrs,
|
||||
ConnectedPlayer.this, server);
|
||||
connectionInFlight = con;
|
||||
return con.connect().whenCompleteAsync((result, throwable) ->
|
||||
this.resetIfInFlightIs(con), connection.eventLoop());
|
||||
return con.connect().thenApplyAsync((result) -> {
|
||||
this.resetIfInFlightIs(con);
|
||||
return result;
|
||||
}, connection.eventLoop());
|
||||
}, connection.eventLoop());
|
||||
});
|
||||
}
|
||||
@@ -874,9 +912,13 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
.whenCompleteAsync((status, throwable) -> {
|
||||
if (status != null && !status.isSuccessful()) {
|
||||
if (!status.isSafe()) {
|
||||
handleConnectionException(status.getAttemptedConnection(), throwable, false);
|
||||
handleConnectionException(status.finalTarget(), throwable, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (throwable != null) {
|
||||
logger.error("Exception during connect; status = {}", status, throwable);
|
||||
}
|
||||
}, connection.eventLoop())
|
||||
.thenApply(x -> x);
|
||||
}
|
||||
@@ -887,12 +929,12 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
.whenCompleteAsync((status, throwable) -> {
|
||||
if (throwable != null) {
|
||||
// TODO: The exception handling from this is not very good. Find a better way.
|
||||
handleConnectionException(status != null ? status.getAttemptedConnection()
|
||||
handleConnectionException(status != null ? status.finalTarget()
|
||||
: toConnect, throwable, true);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (status.getStatus()) {
|
||||
switch (status.status()) {
|
||||
case ALREADY_CONNECTED:
|
||||
sendMessage(Identity.nil(), ConnectionMessages.ALREADY_CONNECTED);
|
||||
break;
|
||||
@@ -903,10 +945,10 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
// Ignored; the plugin probably already handled this.
|
||||
break;
|
||||
case SERVER_DISCONNECTED:
|
||||
Component reason = status.getReason()
|
||||
Component reason = status.failureReason()
|
||||
.orElse(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR);
|
||||
handleConnectionException(toConnect, ClientboundDisconnectPacket.create(reason,
|
||||
getProtocolVersion()), status.isSafe());
|
||||
protocolVersion()), status.isSafe());
|
||||
break;
|
||||
default:
|
||||
// The only remaining value is successful (no need to do anything!)
|
||||
|
||||
@@ -1,8 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.connection.client;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.velocitypowered.api.event.connection.ConnectionHandshakeEvent;
|
||||
import com.velocitypowered.api.event.connection.ConnectionHandshakeEventImpl;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.api.proxy.connection.InboundConnection;
|
||||
import com.velocitypowered.proxy.VelocityServer;
|
||||
@@ -53,7 +70,10 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler {
|
||||
@Override
|
||||
public boolean handle(LegacyHandshakePacket packet) {
|
||||
connection.closeWith(LegacyDisconnectPacket
|
||||
.from(Component.text("Your client is old, please upgrade!", NamedTextColor.RED)));
|
||||
.from(Component.text(
|
||||
"Your client is extremely old. Please update to a newer version of Minecraft.",
|
||||
NamedTextColor.RED)
|
||||
));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -105,7 +125,7 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler {
|
||||
|
||||
InetAddress address = ((InetSocketAddress) connection.getRemoteAddress()).getAddress();
|
||||
if (!server.getIpAttemptLimiter().attempt(address)) {
|
||||
ic.disconnectQuietly(Component.text("You are logging in too fast, try again later."));
|
||||
ic.disconnectQuietly(Component.translatable("velocity.error.logging-in-too-fast"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -113,13 +133,14 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler {
|
||||
|
||||
// If the proxy is configured for modern forwarding, we must deny connections from 1.12.2
|
||||
// and lower, otherwise IP information will never get forwarded.
|
||||
if (server.getConfiguration().getPlayerInfoForwardingMode() == PlayerInfoForwarding.MODERN
|
||||
if (server.configuration().getPlayerInfoForwardingMode() == PlayerInfoForwarding.MODERN
|
||||
&& handshake.getProtocolVersion().lt(ProtocolVersion.MINECRAFT_1_13)) {
|
||||
ic.disconnectQuietly(Component.text("This server is only compatible with 1.13 and above."));
|
||||
ic.disconnectQuietly(Component.translatable(
|
||||
"velocity.error.modern-forwarding-needs-new-client"));
|
||||
return;
|
||||
}
|
||||
|
||||
server.getEventManager().fireAndForget(new ConnectionHandshakeEvent(ic));
|
||||
server.eventManager().fireAndForget(new ConnectionHandshakeEventImpl(ic));
|
||||
connection.setSessionHandler(new LoginSessionHandler(server, connection, ic));
|
||||
}
|
||||
|
||||
@@ -187,12 +208,12 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getRemoteAddress() {
|
||||
public InetSocketAddress remoteAddress() {
|
||||
return (InetSocketAddress) connection.getRemoteAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<InetSocketAddress> getVirtualHost() {
|
||||
public Optional<InetSocketAddress> connectedHostname() {
|
||||
return Optional.ofNullable(ping.getVhost());
|
||||
}
|
||||
|
||||
@@ -202,7 +223,7 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolVersion getProtocolVersion() {
|
||||
public ProtocolVersion protocolVersion() {
|
||||
return ProtocolVersion.LEGACY;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.connection.client;
|
||||
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.connection.client;
|
||||
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
@@ -7,9 +24,11 @@ import com.velocitypowered.proxy.connection.MinecraftConnectionAssociation;
|
||||
import com.velocitypowered.proxy.network.packet.clientbound.ClientboundDisconnectPacket;
|
||||
import com.velocitypowered.proxy.network.packet.serverbound.ServerboundHandshakePacket;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import net.kyori.adventure.translation.GlobalTranslator;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@@ -30,12 +49,12 @@ public final class InitialInboundConnection implements InboundConnection,
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getRemoteAddress() {
|
||||
public InetSocketAddress remoteAddress() {
|
||||
return (InetSocketAddress) connection.getRemoteAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<InetSocketAddress> getVirtualHost() {
|
||||
public Optional<InetSocketAddress> connectedHostname() {
|
||||
return Optional.of(InetSocketAddress.createUnresolved(cleanedAddress, handshake.getPort()));
|
||||
}
|
||||
|
||||
@@ -45,7 +64,7 @@ public final class InitialInboundConnection implements InboundConnection,
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolVersion getProtocolVersion() {
|
||||
public ProtocolVersion protocolVersion() {
|
||||
return connection.getProtocolVersion();
|
||||
}
|
||||
|
||||
@@ -59,9 +78,11 @@ public final class InitialInboundConnection implements InboundConnection,
|
||||
* @param reason the reason for disconnecting
|
||||
*/
|
||||
public void disconnect(Component reason) {
|
||||
Component translated = GlobalTranslator.render(reason, Locale.getDefault());
|
||||
|
||||
logger.info("{} has disconnected: {}", this,
|
||||
LegacyComponentSerializer.legacySection().serialize(reason));
|
||||
connection.closeWith(ClientboundDisconnectPacket.create(reason, getProtocolVersion()));
|
||||
LegacyComponentSerializer.legacySection().serialize(translated));
|
||||
connection.closeWith(ClientboundDisconnectPacket.create(translated, protocolVersion()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -69,6 +90,7 @@ public final class InitialInboundConnection implements InboundConnection,
|
||||
* @param reason the reason for disconnecting
|
||||
*/
|
||||
public void disconnectQuietly(Component reason) {
|
||||
connection.closeWith(ClientboundDisconnectPacket.create(reason, getProtocolVersion()));
|
||||
Component translated = GlobalTranslator.render(reason, Locale.getDefault());
|
||||
connection.closeWith(ClientboundDisconnectPacket.create(translated, protocolVersion()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.connection.client;
|
||||
|
||||
import static com.google.common.net.UrlEscapers.urlFormParameterEscaper;
|
||||
@@ -8,15 +25,19 @@ import static com.velocitypowered.proxy.util.EncryptionUtils.decryptRsa;
|
||||
import static com.velocitypowered.proxy.util.EncryptionUtils.generateServerId;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.velocitypowered.api.event.permission.PermissionsSetupEvent;
|
||||
import com.velocitypowered.api.event.player.DisconnectEvent;
|
||||
import com.velocitypowered.api.event.permission.PermissionsSetupEventImpl;
|
||||
import com.velocitypowered.api.event.player.DisconnectEvent.LoginStatus;
|
||||
import com.velocitypowered.api.event.player.DisconnectEventImpl;
|
||||
import com.velocitypowered.api.event.player.GameProfileRequestEvent;
|
||||
import com.velocitypowered.api.event.player.LoginEvent;
|
||||
import com.velocitypowered.api.event.player.GameProfileRequestEventImpl;
|
||||
import com.velocitypowered.api.event.player.LoginEventImpl;
|
||||
import com.velocitypowered.api.event.player.PlayerChooseInitialServerEvent;
|
||||
import com.velocitypowered.api.event.player.PostLoginEvent;
|
||||
import com.velocitypowered.api.event.player.PlayerChooseInitialServerEventImpl;
|
||||
import com.velocitypowered.api.event.player.PostLoginEventImpl;
|
||||
import com.velocitypowered.api.event.player.PreLoginEvent;
|
||||
import com.velocitypowered.api.event.player.PreLoginEvent.PreLoginComponentResult;
|
||||
import com.velocitypowered.api.event.player.PreLoginEventImpl;
|
||||
import com.velocitypowered.api.permission.PermissionFunction;
|
||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
import com.velocitypowered.api.util.GameProfile;
|
||||
import com.velocitypowered.api.util.UuidUtils;
|
||||
@@ -26,7 +47,6 @@ import com.velocitypowered.proxy.config.VelocityConfiguration;
|
||||
import com.velocitypowered.proxy.connection.MinecraftConnection;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.network.StateRegistry;
|
||||
import com.velocitypowered.proxy.network.packet.clientbound.ClientboundDisconnectPacket;
|
||||
import com.velocitypowered.proxy.network.packet.clientbound.ClientboundEncryptionRequestPacket;
|
||||
import com.velocitypowered.proxy.network.packet.clientbound.ClientboundServerLoginSuccessPacket;
|
||||
import com.velocitypowered.proxy.network.packet.clientbound.ClientboundSetCompressionPacket;
|
||||
@@ -44,6 +64,7 @@ import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.asynchttpclient.ListenableFuture;
|
||||
@@ -102,7 +123,7 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
|
||||
String url = String.format(MOJANG_HASJOINED_URL,
|
||||
urlFormParameterEscaper().escape(login.getUsername()), serverId);
|
||||
|
||||
if (server.getConfiguration().shouldPreventClientProxyConnections()) {
|
||||
if (server.configuration().shouldPreventClientProxyConnections()) {
|
||||
url += "&ip=" + urlFormParameterEscaper().escape(playerIp);
|
||||
}
|
||||
|
||||
@@ -130,7 +151,8 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
|
||||
GameProfile.class), true);
|
||||
} else if (profileResponse.getStatusCode() == 204) {
|
||||
// Apparently an offline-mode user logged onto this online-mode proxy.
|
||||
inbound.disconnect(server.getConfiguration().getMessages().getOnlineModeOnly());
|
||||
inbound.disconnect(Component.translatable("velocity.error.online-mode-only",
|
||||
NamedTextColor.RED));
|
||||
} else {
|
||||
// Something else went wrong
|
||||
logger.error(
|
||||
@@ -158,24 +180,23 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
|
||||
if (login == null) {
|
||||
throw new IllegalStateException("No ServerLogin packet received yet.");
|
||||
}
|
||||
PreLoginEvent event = new PreLoginEvent(inbound, login.getUsername());
|
||||
server.getEventManager().fire(event)
|
||||
PreLoginEvent event = new PreLoginEventImpl(inbound, login.getUsername());
|
||||
server.eventManager().fire(event)
|
||||
.thenRunAsync(() -> {
|
||||
if (mcConnection.isClosed()) {
|
||||
// The player was disconnected
|
||||
return;
|
||||
}
|
||||
|
||||
PreLoginComponentResult result = event.getResult();
|
||||
Optional<Component> disconnectReason = result.getReason();
|
||||
PreLoginComponentResult result = event.result();
|
||||
Optional<Component> disconnectReason = result.denialReason();
|
||||
if (disconnectReason.isPresent()) {
|
||||
// The component is guaranteed to be provided if the connection was denied.
|
||||
mcConnection.closeWith(ClientboundDisconnectPacket.create(disconnectReason.get(),
|
||||
inbound.getProtocolVersion()));
|
||||
inbound.disconnect(disconnectReason.get());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!result.isForceOfflineMode() && (server.getConfiguration().isOnlineMode() || result
|
||||
if (!result.isForceOfflineMode() && (server.configuration().isOnlineMode() || result
|
||||
.isOnlineModeAllowed())) {
|
||||
// Request encryption.
|
||||
ClientboundEncryptionRequestPacket request = generateEncryptionRequest();
|
||||
@@ -204,34 +225,45 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
|
||||
private void initializePlayer(GameProfile profile, boolean onlineMode) {
|
||||
// Some connection types may need to alter the game profile.
|
||||
profile = mcConnection.getType().addGameProfileTokensIfRequired(profile,
|
||||
server.getConfiguration().getPlayerInfoForwardingMode());
|
||||
GameProfileRequestEvent profileRequestEvent = new GameProfileRequestEvent(inbound, profile,
|
||||
server.configuration().getPlayerInfoForwardingMode());
|
||||
GameProfileRequestEvent profileRequestEvent = new GameProfileRequestEventImpl(inbound, profile,
|
||||
onlineMode);
|
||||
final GameProfile finalProfile = profile;
|
||||
|
||||
server.getEventManager().fire(profileRequestEvent).thenComposeAsync(profileEvent -> {
|
||||
server.eventManager().fire(profileRequestEvent).thenComposeAsync(profileEvent -> {
|
||||
if (mcConnection.isClosed()) {
|
||||
// The player disconnected after we authenticated them.
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
// Initiate a regular connection and move over to it.
|
||||
ConnectedPlayer player = new ConnectedPlayer(server, profileEvent.getGameProfile(),
|
||||
mcConnection, inbound.getVirtualHost().orElse(null), onlineMode);
|
||||
ConnectedPlayer player = new ConnectedPlayer(server, profileEvent.gameProfile(),
|
||||
mcConnection, inbound.connectedHostname().orElse(null), onlineMode);
|
||||
this.connectedPlayer = player;
|
||||
if (!server.canRegisterConnection(player)) {
|
||||
player.disconnect0(server.getConfiguration().getMessages().getAlreadyConnected(), true);
|
||||
player.disconnect0(Component.translatable("velocity.error.already-connected-proxy",
|
||||
NamedTextColor.RED), true);
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
logger.info("{} has connected", player);
|
||||
|
||||
return server.getEventManager()
|
||||
.fire(new PermissionsSetupEvent(player, ConnectedPlayer.DEFAULT_PERMISSIONS))
|
||||
return server.eventManager()
|
||||
.fire(new PermissionsSetupEventImpl(player, ConnectedPlayer.DEFAULT_PERMISSIONS))
|
||||
.thenAcceptAsync(event -> {
|
||||
if (!mcConnection.isClosed()) {
|
||||
// wait for permissions to load, then set the players permission function
|
||||
player.setPermissionFunction(event.createFunction(player));
|
||||
final PermissionFunction function = event.createFunction(player);
|
||||
if (function == null) {
|
||||
logger.error(
|
||||
"A plugin permission provider {} provided an invalid permission function"
|
||||
+ " for player {}. This is a bug in the plugin, not in Velocity. Falling"
|
||||
+ " back to the default permission function.",
|
||||
event.provider().getClass().getName(),
|
||||
player.username());
|
||||
} else {
|
||||
player.setPermissionFunction(function);
|
||||
}
|
||||
completeLoginProtocolPhaseAndInitialize(player);
|
||||
}
|
||||
}, mcConnection.eventLoop());
|
||||
@@ -242,43 +274,47 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
|
||||
}
|
||||
|
||||
private void completeLoginProtocolPhaseAndInitialize(ConnectedPlayer player) {
|
||||
int threshold = server.getConfiguration().getCompressionThreshold();
|
||||
int threshold = server.configuration().getCompressionThreshold();
|
||||
if (threshold >= 0 && mcConnection.getProtocolVersion().gte(MINECRAFT_1_8)) {
|
||||
mcConnection.write(new ClientboundSetCompressionPacket(threshold));
|
||||
mcConnection.setCompressionThreshold(threshold);
|
||||
}
|
||||
VelocityConfiguration configuration = server.getConfiguration();
|
||||
UUID playerUniqueId = player.getUniqueId();
|
||||
VelocityConfiguration configuration = server.configuration();
|
||||
UUID playerUniqueId = player.id();
|
||||
if (configuration.getPlayerInfoForwardingMode() == PlayerInfoForwarding.NONE) {
|
||||
playerUniqueId = UuidUtils.generateOfflinePlayerUuid(player.getUsername());
|
||||
playerUniqueId = UuidUtils.generateOfflinePlayerUuid(player.username());
|
||||
}
|
||||
mcConnection.write(new ClientboundServerLoginSuccessPacket(playerUniqueId, player.getUsername()));
|
||||
mcConnection.write(new ClientboundServerLoginSuccessPacket(playerUniqueId, player.username()));
|
||||
|
||||
mcConnection.setAssociation(player);
|
||||
mcConnection.setState(StateRegistry.PLAY);
|
||||
|
||||
server.getEventManager().fire(new LoginEvent(player))
|
||||
server.eventManager().fire(new LoginEventImpl(player))
|
||||
.thenAcceptAsync(event -> {
|
||||
if (mcConnection.isClosed()) {
|
||||
// The player was disconnected
|
||||
server.getEventManager().fireAndForget(new DisconnectEvent(player,
|
||||
server.eventManager().fireAndForget(new DisconnectEventImpl(player,
|
||||
LoginStatus.CANCELLED_BY_USER_BEFORE_COMPLETE));
|
||||
return;
|
||||
}
|
||||
|
||||
Optional<Component> reason = event.getResult().getReason();
|
||||
Optional<Component> reason = event.result().reason();
|
||||
if (reason.isPresent()) {
|
||||
player.disconnect0(reason.get(), true);
|
||||
} else {
|
||||
if (!server.registerConnection(player)) {
|
||||
player.disconnect0(server.getConfiguration().getMessages()
|
||||
.getAlreadyConnected(), true);
|
||||
player.disconnect0(Component.translatable("velocity.error.already-connected-proxy"),
|
||||
true);
|
||||
return;
|
||||
}
|
||||
|
||||
mcConnection.setSessionHandler(new InitialConnectSessionHandler(player));
|
||||
server.getEventManager().fire(new PostLoginEvent(player))
|
||||
.thenRun(() -> connectToInitialServer(player));
|
||||
server.eventManager().fire(new PostLoginEventImpl(player))
|
||||
.thenCompose((ignored) -> connectToInitialServer(player))
|
||||
.exceptionally((ex) -> {
|
||||
logger.error("Exception while connecting {} to initial server", player, ex);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}, mcConnection.eventLoop())
|
||||
.exceptionally((ex) -> {
|
||||
@@ -287,25 +323,21 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
|
||||
});
|
||||
}
|
||||
|
||||
private void connectToInitialServer(ConnectedPlayer player) {
|
||||
private CompletableFuture<Void> connectToInitialServer(ConnectedPlayer player) {
|
||||
Optional<RegisteredServer> initialFromConfig = player.getNextServerToTry();
|
||||
PlayerChooseInitialServerEvent event = new PlayerChooseInitialServerEvent(player,
|
||||
PlayerChooseInitialServerEvent event = new PlayerChooseInitialServerEventImpl(player,
|
||||
initialFromConfig.orElse(null));
|
||||
|
||||
server.getEventManager().fire(event)
|
||||
return server.eventManager().fire(event)
|
||||
.thenRunAsync(() -> {
|
||||
Optional<RegisteredServer> toTry = event.getInitialServer();
|
||||
Optional<RegisteredServer> toTry = event.initialServer();
|
||||
if (!toTry.isPresent()) {
|
||||
player.disconnect0(server.getConfiguration().getMessages()
|
||||
.getNoAvailableServers(), true);
|
||||
player.disconnect0(Component.translatable("velocity.error.no-available-servers",
|
||||
NamedTextColor.RED), true);
|
||||
return;
|
||||
}
|
||||
player.createConnectionRequest(toTry.get()).fireAndForget();
|
||||
}, mcConnection.eventLoop())
|
||||
.exceptionally((ex) -> {
|
||||
logger.error("Exception while connecting {} to initial server", player, ex);
|
||||
return null;
|
||||
});
|
||||
}, mcConnection.eventLoop());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,8 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.connection.client;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.spotify.futures.CompletableFutures;
|
||||
import com.velocitypowered.api.event.connection.ProxyPingEvent;
|
||||
import com.velocitypowered.api.event.connection.ProxyPingEventImpl;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.api.proxy.connection.InboundConnection;
|
||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
@@ -25,6 +42,7 @@ import io.netty.buffer.ByteBuf;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
@@ -50,18 +68,18 @@ public class StatusSessionHandler implements MinecraftSessionHandler {
|
||||
|
||||
@Override
|
||||
public void activated() {
|
||||
if (server.getConfiguration().isShowPingRequests()) {
|
||||
if (server.configuration().isShowPingRequests()) {
|
||||
logger.info("{} is pinging the server with version {}", this.inbound,
|
||||
this.connection.getProtocolVersion());
|
||||
}
|
||||
}
|
||||
|
||||
private ServerPing constructLocalPing(ProtocolVersion version) {
|
||||
VelocityConfiguration configuration = server.getConfiguration();
|
||||
VelocityConfiguration configuration = server.configuration();
|
||||
return new ServerPing(
|
||||
new ServerPing.Version(version.getProtocol(),
|
||||
new ServerPing.Version(version.protocol(),
|
||||
"Velocity " + ProtocolVersion.SUPPORTED_VERSION_STRING),
|
||||
new ServerPing.Players(server.getPlayerCount(), configuration.getShowMaxPlayers(),
|
||||
new ServerPing.Players(server.countConnectedPlayers(), configuration.getShowMaxPlayers(),
|
||||
ImmutableList.of()),
|
||||
configuration.getMotd(),
|
||||
configuration.getFavicon().orElse(null),
|
||||
@@ -74,7 +92,7 @@ public class StatusSessionHandler implements MinecraftSessionHandler {
|
||||
ServerPing fallback = constructLocalPing(pingingVersion);
|
||||
List<CompletableFuture<ServerPing>> pings = new ArrayList<>();
|
||||
for (String s : servers) {
|
||||
Optional<RegisteredServer> rs = server.getServer(s);
|
||||
Optional<RegisteredServer> rs = server.server(s);
|
||||
if (!rs.isPresent()) {
|
||||
continue;
|
||||
}
|
||||
@@ -106,7 +124,7 @@ public class StatusSessionHandler implements MinecraftSessionHandler {
|
||||
if (response == fallback) {
|
||||
continue;
|
||||
}
|
||||
Optional<ModInfo> modInfo = response.getModinfo();
|
||||
Optional<ModInfo> modInfo = response.modInfo();
|
||||
if (modInfo.isPresent()) {
|
||||
return fallback.asBuilder().mods(modInfo.get()).build();
|
||||
}
|
||||
@@ -121,16 +139,16 @@ public class StatusSessionHandler implements MinecraftSessionHandler {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (response.getDescription() == null) {
|
||||
if (response.description() == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return new ServerPing(
|
||||
fallback.getVersion(),
|
||||
fallback.getPlayers().orElse(null),
|
||||
response.getDescription(),
|
||||
fallback.getFavicon().orElse(null),
|
||||
response.getModinfo().orElse(null)
|
||||
fallback.version(),
|
||||
fallback.players().orElse(null),
|
||||
response.description(),
|
||||
fallback.favicon().orElse(null),
|
||||
response.modInfo().orElse(null)
|
||||
);
|
||||
}
|
||||
return fallback;
|
||||
@@ -142,7 +160,7 @@ public class StatusSessionHandler implements MinecraftSessionHandler {
|
||||
}
|
||||
|
||||
private CompletableFuture<ServerPing> getInitialPing() {
|
||||
VelocityConfiguration configuration = server.getConfiguration();
|
||||
VelocityConfiguration configuration = server.configuration();
|
||||
ProtocolVersion shownVersion = ProtocolVersion.isSupported(connection.getProtocolVersion())
|
||||
? connection.getProtocolVersion() : ProtocolVersion.MAXIMUM_VERSION;
|
||||
PingPassthroughMode passthrough = configuration.getPingPassthrough();
|
||||
@@ -150,10 +168,11 @@ public class StatusSessionHandler implements MinecraftSessionHandler {
|
||||
if (passthrough == PingPassthroughMode.DISABLED) {
|
||||
return CompletableFuture.completedFuture(constructLocalPing(shownVersion));
|
||||
} else {
|
||||
String virtualHostStr = inbound.getVirtualHost().map(InetSocketAddress::getHostString)
|
||||
String virtualHostStr = inbound.connectedHostname().map(InetSocketAddress::getHostString)
|
||||
.map(str -> str.toLowerCase(Locale.ROOT))
|
||||
.orElse("");
|
||||
List<String> serversToTry = server.getConfiguration().getForcedHosts().getOrDefault(
|
||||
virtualHostStr, server.getConfiguration().getAttemptConnectionOrder());
|
||||
List<String> serversToTry = server.configuration().getForcedHosts().getOrDefault(
|
||||
virtualHostStr, server.configuration().getAttemptConnectionOrder());
|
||||
return attemptPingPassthrough(configuration.getPingPassthrough(), serversToTry, shownVersion);
|
||||
}
|
||||
}
|
||||
@@ -165,9 +184,9 @@ public class StatusSessionHandler implements MinecraftSessionHandler {
|
||||
}
|
||||
this.pingReceived = true;
|
||||
getInitialPing()
|
||||
.thenCompose(ping -> server.getEventManager().fire(new ProxyPingEvent(inbound, ping)))
|
||||
.thenCompose(ping -> server.eventManager().fire(new ProxyPingEventImpl(inbound, ping)))
|
||||
.thenAcceptAsync(event -> connection.closeWith(
|
||||
LegacyDisconnectPacket.fromServerPing(event.getPing(), packet.getVersion())),
|
||||
LegacyDisconnectPacket.fromServerPing(event.ping(), packet.getVersion())),
|
||||
connection.eventLoop())
|
||||
.exceptionally((ex) -> {
|
||||
logger.error("Exception while handling legacy ping {}", packet, ex);
|
||||
@@ -190,12 +209,12 @@ public class StatusSessionHandler implements MinecraftSessionHandler {
|
||||
this.pingReceived = true;
|
||||
|
||||
getInitialPing()
|
||||
.thenCompose(ping -> server.getEventManager().fire(new ProxyPingEvent(inbound, ping)))
|
||||
.thenCompose(ping -> server.eventManager().fire(new ProxyPingEventImpl(inbound, ping)))
|
||||
.thenAcceptAsync(
|
||||
(event) -> {
|
||||
StringBuilder json = new StringBuilder();
|
||||
VelocityServer.getPingGsonInstance(connection.getProtocolVersion())
|
||||
.toJson(event.getPing(), json);
|
||||
.toJson(event.ping(), json);
|
||||
connection.write(new ClientboundStatusResponsePacket(json));
|
||||
},
|
||||
connection.eventLoop())
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.connection.forge.legacy;
|
||||
|
||||
import com.velocitypowered.api.util.GameProfile;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.connection.forge.legacy;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.connection.forge.legacy;
|
||||
|
||||
import com.velocitypowered.proxy.connection.ConnectionTypes;
|
||||
@@ -43,7 +60,7 @@ public enum LegacyForgeHandshakeBackendPhase implements BackendConnectionPhase {
|
||||
if (mc != null) {
|
||||
mc.setType(ConnectionTypes.LEGACY_FORGE);
|
||||
}
|
||||
connection.getPlayer().sendLegacyForgeHandshakeResetPacket();
|
||||
connection.player().sendLegacyForgeHandshakeResetPacket();
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.connection.forge.legacy;
|
||||
|
||||
import com.velocitypowered.api.util.ModInfo;
|
||||
@@ -76,7 +93,7 @@ public enum LegacyForgeHandshakeClientPhase implements ClientConnectionPhase {
|
||||
AbstractPluginMessagePacket<?> message,
|
||||
MinecraftConnection backendConn) {
|
||||
// Read the mod list if we haven't already.
|
||||
if (!player.getModInfo().isPresent()) {
|
||||
if (!player.modInfo().isPresent()) {
|
||||
List<ModInfo.Mod> mods = LegacyForgeUtil.readModList(message);
|
||||
if (!mods.isEmpty()) {
|
||||
player.setModInfo(new ModInfo("FML", mods));
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.connection.forge.legacy;
|
||||
|
||||
import static com.velocitypowered.proxy.connection.forge.legacy.LegacyForgeConstants.FORGE_LEGACY_HANDSHAKE_CHANNEL;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.connection.registry;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.connection.registry;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
@@ -1,13 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.connection.registry;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.kyori.adventure.nbt.BinaryTagTypes;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
|
||||
@@ -1,17 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.connection.util;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.TranslatableComponent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
public class ConnectionMessages {
|
||||
|
||||
public static final TextComponent ALREADY_CONNECTED = Component
|
||||
.text("You are already connected to this server!", NamedTextColor.RED);
|
||||
public static final TextComponent IN_PROGRESS = Component
|
||||
.text("You are already connecting to a server!", NamedTextColor.RED);
|
||||
public static final TextComponent INTERNAL_SERVER_CONNECTION_ERROR = Component
|
||||
.text("An internal server connection error occurred.", NamedTextColor.RED);
|
||||
public static final TranslatableComponent ALREADY_CONNECTED = Component
|
||||
.translatable("velocity.error.already-connected", NamedTextColor.RED);
|
||||
public static final TranslatableComponent IN_PROGRESS = Component
|
||||
.translatable("velocity.error.already-connecting", NamedTextColor.RED);
|
||||
public static final TranslatableComponent INTERNAL_SERVER_CONNECTION_ERROR = Component
|
||||
.translatable("velocity.error.internal-server-connection-error", NamedTextColor.RED);
|
||||
|
||||
private ConnectionMessages() {
|
||||
throw new AssertionError();
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.connection.util;
|
||||
|
||||
import com.velocitypowered.api.proxy.player.ConnectionRequestBuilder;
|
||||
@@ -67,17 +84,17 @@ public class ConnectionRequestResults {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Status getStatus() {
|
||||
public Status status() {
|
||||
return status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Component> getReason() {
|
||||
public Optional<Component> failureReason() {
|
||||
return Optional.ofNullable(component);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegisteredServer getAttemptedConnection() {
|
||||
public RegisteredServer finalTarget() {
|
||||
return attemptedConnection;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.connection.util;
|
||||
|
||||
import com.velocitypowered.api.util.GameProfile;
|
||||
|
||||
@@ -1,16 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.console;
|
||||
|
||||
import static com.velocitypowered.api.permission.PermissionFunction.ALWAYS_TRUE;
|
||||
|
||||
import com.velocitypowered.api.command.ConsoleCommandSource;
|
||||
import com.velocitypowered.api.event.permission.PermissionsSetupEvent;
|
||||
import com.velocitypowered.api.event.permission.PermissionsSetupEventImpl;
|
||||
import com.velocitypowered.api.permission.PermissionFunction;
|
||||
import com.velocitypowered.api.permission.Tristate;
|
||||
import com.velocitypowered.proxy.VelocityServer;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import net.kyori.adventure.identity.Identity;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import net.kyori.adventure.translation.GlobalTranslator;
|
||||
import net.minecrell.terminalconsole.SimpleTerminalConsole;
|
||||
import org.apache.logging.log4j.Level;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
@@ -34,13 +55,13 @@ public final class VelocityConsole extends SimpleTerminalConsole implements Cons
|
||||
|
||||
@Override
|
||||
public void sendMessage(@NonNull Identity identity, @NonNull Component message) {
|
||||
logger.info(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection()
|
||||
.serialize(message));
|
||||
Component translated = GlobalTranslator.render(message, Locale.getDefault());
|
||||
logger.info(LegacyComponentSerializer.legacySection().serialize(translated));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Tristate getPermissionValue(@NonNull String permission) {
|
||||
return this.permissionFunction.getPermissionValue(permission);
|
||||
public @NonNull Tristate evaluatePermission(@NonNull String permission) {
|
||||
return this.permissionFunction.evaluatePermission(permission);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,9 +76,17 @@ public final class VelocityConsole extends SimpleTerminalConsole implements Cons
|
||||
* Sets up permissions for the console.
|
||||
*/
|
||||
public void setupPermissions() {
|
||||
PermissionsSetupEvent event = new PermissionsSetupEvent(this, s -> ALWAYS_TRUE);
|
||||
PermissionsSetupEvent event = new PermissionsSetupEventImpl(this, s -> ALWAYS_TRUE);
|
||||
// we can safely block here, this is before any listeners fire
|
||||
this.permissionFunction = this.server.getEventManager().fire(event).join().createFunction(this);
|
||||
this.permissionFunction = this.server.eventManager().fire(event).join().createFunction(this);
|
||||
if (this.permissionFunction == null) {
|
||||
logger.error(
|
||||
"A plugin permission provider {} provided an invalid permission function"
|
||||
+ " for the console. This is a bug in the plugin, not in Velocity. Falling"
|
||||
+ " back to the default permission function.",
|
||||
event.provider().getClass().getName());
|
||||
this.permissionFunction = ALWAYS_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -66,7 +95,7 @@ public final class VelocityConsole extends SimpleTerminalConsole implements Cons
|
||||
.appName("Velocity")
|
||||
.completer((reader, parsedLine, list) -> {
|
||||
try {
|
||||
List<String> offers = this.server.getCommandManager()
|
||||
List<String> offers = this.server.commandManager()
|
||||
.offerSuggestions(this, parsedLine.line())
|
||||
.join(); // Console doesn't get harmed much by this...
|
||||
for (String offer : offers) {
|
||||
@@ -87,8 +116,9 @@ public final class VelocityConsole extends SimpleTerminalConsole implements Cons
|
||||
@Override
|
||||
protected void runCommand(String command) {
|
||||
try {
|
||||
if (!this.server.getCommandManager().execute(this, command).join()) {
|
||||
sendMessage(Component.text("Command not found.", NamedTextColor.RED));
|
||||
if (!this.server.commandManager().execute(this, command).join()) {
|
||||
sendMessage(Component.translatable("velocity.command.command-does-not-exist",
|
||||
NamedTextColor.RED));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("An error occurred while running this command.", e);
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.event;
|
||||
|
||||
import com.velocitypowered.api.event.EventTask;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.event;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
@@ -302,7 +319,23 @@ public class VelocityEventManager implements EventManager {
|
||||
if (plugin == listener) {
|
||||
throw new IllegalArgumentException("The plugin main instance is automatically registered.");
|
||||
}
|
||||
registerInternally(pluginContainer, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <E> void register(final Object plugin, final Class<E> eventClass,
|
||||
final short order, final EventHandler<E> handler) {
|
||||
final PluginContainer pluginContainer = ensurePlugin(plugin);
|
||||
requireNonNull(eventClass, "eventClass");
|
||||
requireNonNull(handler, "handler");
|
||||
|
||||
final HandlerRegistration registration = new HandlerRegistration(pluginContainer, order,
|
||||
eventClass, handler, (EventHandler<Object>) handler, AsyncType.SOMETIMES);
|
||||
register(Collections.singletonList(registration));
|
||||
}
|
||||
|
||||
public void registerInternally(final PluginContainer pluginContainer, final Object listener) {
|
||||
final Class<?> targetClass = listener.getClass();
|
||||
final Map<String, MethodHandlerInfo> collected = new HashMap<>();
|
||||
collectMethods(targetClass, collected);
|
||||
@@ -325,19 +358,6 @@ public class VelocityEventManager implements EventManager {
|
||||
register(registrations);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <E> void register(final Object plugin, final Class<E> eventClass,
|
||||
final short order, final EventHandler<E> handler) {
|
||||
final PluginContainer pluginContainer = ensurePlugin(plugin);
|
||||
requireNonNull(eventClass, "eventClass");
|
||||
requireNonNull(handler, "handler");
|
||||
|
||||
final HandlerRegistration registration = new HandlerRegistration(pluginContainer, order,
|
||||
eventClass, handler, (EventHandler<Object>) handler, AsyncType.SOMETIMES);
|
||||
register(Collections.singletonList(registration));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterListeners(final Object plugin) {
|
||||
final PluginContainer pluginContainer = ensurePlugin(plugin);
|
||||
@@ -578,7 +598,7 @@ public class VelocityEventManager implements EventManager {
|
||||
private static void logHandlerException(
|
||||
final HandlerRegistration registration, final Throwable t) {
|
||||
logger.error("Couldn't pass {} to {}", registration.eventType.getSimpleName(),
|
||||
registration.plugin.getDescription().getId(), t);
|
||||
registration.plugin.description().id(), t);
|
||||
}
|
||||
|
||||
public boolean shutdown() throws InterruptedException {
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network;
|
||||
|
||||
import static com.velocitypowered.proxy.network.HandlerNames.FLOW_HANDLER;
|
||||
@@ -31,10 +48,10 @@ public class BackendChannelInitializer extends ChannelInitializer<Channel> {
|
||||
@Override
|
||||
protected void initChannel(Channel ch) throws Exception {
|
||||
ch.pipeline()
|
||||
.addLast(READ_TIMEOUT,
|
||||
new ReadTimeoutHandler(server.getConfiguration().getReadTimeout(),
|
||||
TimeUnit.MILLISECONDS))
|
||||
.addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder())
|
||||
.addLast(READ_TIMEOUT,
|
||||
new ReadTimeoutHandler(server.configuration().getReadTimeout(),
|
||||
TimeUnit.MILLISECONDS))
|
||||
.addLast(FRAME_ENCODER, MinecraftVarintLengthEncoder.INSTANCE)
|
||||
.addLast(MINECRAFT_DECODER,
|
||||
new MinecraftDecoder(PacketDirection.CLIENTBOUND))
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
|
||||
@@ -1,9 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network;
|
||||
|
||||
import static org.asynchttpclient.Dsl.asyncHttpClient;
|
||||
import static org.asynchttpclient.Dsl.config;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.velocitypowered.api.event.lifecycle.network.ListenerBoundEventImpl;
|
||||
import com.velocitypowered.api.event.lifecycle.network.ListenerClosedEventImpl;
|
||||
import com.velocitypowered.api.network.ListenerType;
|
||||
import com.velocitypowered.natives.util.Natives;
|
||||
import com.velocitypowered.proxy.VelocityServer;
|
||||
import com.velocitypowered.proxy.network.pipeline.GS4QueryHandler;
|
||||
@@ -35,7 +55,7 @@ public final class ConnectionManager {
|
||||
private static final WriteBufferWaterMark SERVER_WRITE_MARK = new WriteBufferWaterMark(1 << 20,
|
||||
1 << 21);
|
||||
private static final Logger LOGGER = LogManager.getLogger(ConnectionManager.class);
|
||||
private final Map<SocketAddress, Channel> endpoints = new HashMap<>();
|
||||
private final Map<SocketAddress, Endpoint> endpoints = new HashMap<>();
|
||||
private final TransportType transportType;
|
||||
private final EventLoopGroup bossGroup;
|
||||
private final EventLoopGroup workerGroup;
|
||||
@@ -67,7 +87,7 @@ public final class ConnectionManager {
|
||||
this.resolver = new SeparatePoolInetNameResolver(GlobalEventExecutor.INSTANCE);
|
||||
this.httpClient = asyncHttpClient(config()
|
||||
.setEventLoopGroup(this.workerGroup)
|
||||
.setUserAgent(server.getVersion().getName() + "/" + server.getVersion().getVersion())
|
||||
.setUserAgent(server.version().getName() + "/" + server.version().getVersion())
|
||||
.addRequestFilter(new RequestFilter() {
|
||||
@Override
|
||||
public <T> FilterContext<T> filter(FilterContext<T> ctx) {
|
||||
@@ -102,7 +122,7 @@ public final class ConnectionManager {
|
||||
if (address instanceof InetSocketAddress) {
|
||||
bootstrap.childOption(ChannelOption.TCP_NODELAY, true)
|
||||
.childOption(ChannelOption.IP_TOS, 0x18);
|
||||
if (transportType == TransportType.EPOLL && server.getConfiguration().useTcpFastOpen()) {
|
||||
if (transportType == TransportType.EPOLL && server.configuration().useTcpFastOpen()) {
|
||||
bootstrap.option(EpollChannelOption.TCP_FASTOPEN, 3);
|
||||
}
|
||||
}
|
||||
@@ -111,8 +131,12 @@ public final class ConnectionManager {
|
||||
.addListener((ChannelFutureListener) future -> {
|
||||
final Channel channel = future.channel();
|
||||
if (future.isSuccess()) {
|
||||
this.endpoints.put(address, channel);
|
||||
this.endpoints.put(address, new Endpoint(channel, ListenerType.MINECRAFT));
|
||||
LOGGER.info("Listening on {}", channel.localAddress());
|
||||
|
||||
// Fire the proxy bound event after the socket is bound
|
||||
server.eventManager().fireAndForget(
|
||||
new ListenerBoundEventImpl(address, ListenerType.MINECRAFT));
|
||||
} else {
|
||||
LOGGER.error("Can't bind to {}", address, future.cause());
|
||||
}
|
||||
@@ -136,8 +160,12 @@ public final class ConnectionManager {
|
||||
.addListener((ChannelFutureListener) future -> {
|
||||
final Channel channel = future.channel();
|
||||
if (future.isSuccess()) {
|
||||
this.endpoints.put(address, channel);
|
||||
this.endpoints.put(address, new Endpoint(channel, ListenerType.QUERY));
|
||||
LOGGER.info("Listening for GS4 query on {}", channel.localAddress());
|
||||
|
||||
// Fire the proxy bound event after the socket is bound
|
||||
server.eventManager().fireAndForget(
|
||||
new ListenerBoundEventImpl(address, ListenerType.QUERY));
|
||||
} else {
|
||||
LOGGER.error("Can't bind to {}", bootstrap.config().localAddress(), future.cause());
|
||||
}
|
||||
@@ -156,10 +184,10 @@ public final class ConnectionManager {
|
||||
.channelFactory(this.transportType.getClientChannelFactory(target))
|
||||
.option(ChannelOption.TCP_NODELAY, true)
|
||||
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS,
|
||||
this.server.getConfiguration().getConnectTimeout())
|
||||
this.server.configuration().getConnectTimeout())
|
||||
.group(group == null ? this.workerGroup : group)
|
||||
.resolver(this.resolver.asGroup());
|
||||
if (transportType == TransportType.EPOLL && server.getConfiguration().useTcpFastOpen()) {
|
||||
if (transportType == TransportType.EPOLL && server.configuration().useTcpFastOpen()) {
|
||||
bootstrap.option(EpollChannelOption.TCP_FASTOPEN_CONNECT, true);
|
||||
}
|
||||
return bootstrap;
|
||||
@@ -171,7 +199,14 @@ public final class ConnectionManager {
|
||||
* @param oldBind the endpoint to close
|
||||
*/
|
||||
public void close(SocketAddress oldBind) {
|
||||
Channel serverChannel = endpoints.remove(oldBind);
|
||||
Endpoint endpoint = endpoints.remove(oldBind);
|
||||
|
||||
// Fire proxy close event to notify plugins of socket close. We block since plugins
|
||||
// should have a chance to be notified before the server stops accepting connections.
|
||||
server.eventManager().fire(new ListenerClosedEventImpl(oldBind, endpoint.getType())).join();
|
||||
|
||||
Channel serverChannel = endpoint.getChannel();
|
||||
|
||||
Preconditions.checkState(serverChannel != null, "Endpoint %s not registered", oldBind);
|
||||
LOGGER.info("Closing endpoint {}", serverChannel.localAddress());
|
||||
serverChannel.close().syncUninterruptibly();
|
||||
@@ -181,10 +216,17 @@ public final class ConnectionManager {
|
||||
* Closes all endpoints.
|
||||
*/
|
||||
public void shutdown() {
|
||||
for (final Channel endpoint : this.endpoints.values()) {
|
||||
for (final Map.Entry<SocketAddress, Endpoint> entry : this.endpoints.entrySet()) {
|
||||
final SocketAddress address = entry.getKey();
|
||||
final Endpoint endpoint = entry.getValue();
|
||||
|
||||
// Fire proxy close event to notify plugins of socket close. We block since plugins
|
||||
// should have a chance to be notified before the server stops accepting connections.
|
||||
server.eventManager().fire(new ListenerClosedEventImpl(address, endpoint.getType())).join();
|
||||
|
||||
try {
|
||||
LOGGER.info("Closing endpoint {}", endpoint.localAddress());
|
||||
endpoint.close().sync();
|
||||
LOGGER.info("Closing endpoint {}", address);
|
||||
endpoint.getChannel().close().sync();
|
||||
} catch (final InterruptedException e) {
|
||||
LOGGER.info("Interrupted whilst closing endpoint", e);
|
||||
Thread.currentThread().interrupt();
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.velocitypowered.api.network.ListenerType;
|
||||
import io.netty.channel.Channel;
|
||||
|
||||
/**
|
||||
* Represents a listener endpoint.
|
||||
*/
|
||||
public final class Endpoint {
|
||||
private final Channel channel;
|
||||
private final ListenerType type;
|
||||
|
||||
public Endpoint(Channel channel, ListenerType type) {
|
||||
this.channel = Preconditions.checkNotNull(channel, "channel");
|
||||
this.type = Preconditions.checkNotNull(type, "type");
|
||||
}
|
||||
|
||||
public Channel getChannel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
public ListenerType getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network;
|
||||
|
||||
public class HandlerNames {
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
@@ -5,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.KeyedPluginChannelId;
|
||||
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;
|
||||
@@ -157,6 +177,19 @@ public final class PluginMessageUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public static String channelIdForVersion(PluginChannelId id, ProtocolVersion version) {
|
||||
if (id instanceof KeyedPluginChannelId) {
|
||||
return ((KeyedPluginChannelId) 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\\-_]*");
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
@@ -15,7 +32,6 @@ import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.handler.codec.CorruptedFrameException;
|
||||
import io.netty.handler.codec.DecoderException;
|
||||
import io.netty.handler.codec.EncoderException;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
@@ -23,7 +39,6 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import net.kyori.adventure.nbt.BinaryTagIO;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
@@ -44,7 +59,15 @@ public enum ProtocolUtils {
|
||||
|
||||
private static final int DEFAULT_MAX_STRING_SIZE = 65536; // 64KiB
|
||||
private static final QuietDecoderException BAD_VARINT_CACHED =
|
||||
new QuietDecoderException("Bad varint decoded");
|
||||
new QuietDecoderException("Bad VarInt decoded");
|
||||
private static final int[] VARINT_EXACT_BYTE_LENGTHS = new int[33];
|
||||
|
||||
static {
|
||||
for (int i = 0; i <= 32; ++i) {
|
||||
VARINT_EXACT_BYTE_LENGTHS[i] = (int) Math.ceil((31d - (i - 1)) / 7d);
|
||||
}
|
||||
VARINT_EXACT_BYTE_LENGTHS[32] = 1; // Special case for the number 0.
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a Minecraft-style VarInt from the specified {@code buf}.
|
||||
@@ -54,7 +77,7 @@ public enum ProtocolUtils {
|
||||
public static int readVarInt(ByteBuf buf) {
|
||||
int read = readVarIntSafely(buf);
|
||||
if (read == Integer.MIN_VALUE) {
|
||||
throw MinecraftDecoder.DEBUG ? new CorruptedFrameException("Bad varint decoded")
|
||||
throw MinecraftDecoder.DEBUG ? new CorruptedFrameException("Bad VarInt decoded")
|
||||
: BAD_VARINT_CACHED;
|
||||
}
|
||||
return read;
|
||||
@@ -80,29 +103,73 @@ public enum ProtocolUtils {
|
||||
return Integer.MIN_VALUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the exact byte size of {@code value} if it were encoded as a VarInt.
|
||||
* @param value the value to encode
|
||||
* @return the byte size of {@code value} if encoded as a VarInt
|
||||
*/
|
||||
public static int varIntBytes(int value) {
|
||||
return VARINT_EXACT_BYTE_LENGTHS[Integer.numberOfLeadingZeros(value)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a Minecraft-style VarInt to the specified {@code buf}.
|
||||
* @param buf the buffer to read from
|
||||
* @param value the integer to write
|
||||
*/
|
||||
public static void writeVarInt(ByteBuf buf, int value) {
|
||||
while (true) {
|
||||
if ((value & 0xFFFFFF80) == 0) {
|
||||
buf.writeByte(value);
|
||||
return;
|
||||
}
|
||||
|
||||
buf.writeByte(value & 0x7F | 0x80);
|
||||
value >>>= 7;
|
||||
// Peel the one and two byte count cases explicitly as they are the most common VarInt sizes
|
||||
// that the proxy will write, to improve inlining.
|
||||
if ((value & (0xFFFFFFFF << 7)) == 0) {
|
||||
buf.writeByte(value);
|
||||
} else if ((value & (0xFFFFFFFF << 14)) == 0) {
|
||||
int w = (value & 0x7F | 0x80) << 8 | (value >>> 7);
|
||||
buf.writeShort(w);
|
||||
} else {
|
||||
writeVarIntFull(buf, value);
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeVarIntFull(ByteBuf buf, int value) {
|
||||
// See https://steinborn.me/posts/performance/how-fast-can-you-write-a-varint/
|
||||
if ((value & (0xFFFFFFFF << 7)) == 0) {
|
||||
buf.writeByte(value);
|
||||
} else if ((value & (0xFFFFFFFF << 14)) == 0) {
|
||||
int w = (value & 0x7F | 0x80) << 8 | (value >>> 7);
|
||||
buf.writeShort(w);
|
||||
} else if ((value & (0xFFFFFFFF << 21)) == 0) {
|
||||
int w = (value & 0x7F | 0x80) << 16 | ((value >>> 7) & 0x7F | 0x80) << 8 | (value >>> 14);
|
||||
buf.writeMedium(w);
|
||||
} else if ((value & (0xFFFFFFFF << 28)) == 0) {
|
||||
int w = (value & 0x7F | 0x80) << 24 | (((value >>> 7) & 0x7F | 0x80) << 16)
|
||||
| ((value >>> 14) & 0x7F | 0x80) << 8 | (value >>> 21);
|
||||
buf.writeInt(w);
|
||||
} else {
|
||||
int w = (value & 0x7F | 0x80) << 24 | ((value >>> 7) & 0x7F | 0x80) << 16
|
||||
| ((value >>> 14) & 0x7F | 0x80) << 8 | ((value >>> 21) & 0x7F | 0x80);
|
||||
buf.writeInt(w);
|
||||
buf.writeByte(value >>> 28);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the specified {@code value} as a 21-bit Minecraft VarInt to the specified {@code buf}.
|
||||
* The upper 11 bits will be discarded.
|
||||
* @param buf the buffer to read from
|
||||
* @param value the integer to write
|
||||
*/
|
||||
public static void write21BitVarInt(ByteBuf buf, int value) {
|
||||
// See https://steinborn.me/posts/performance/how-fast-can-you-write-a-varint/
|
||||
int w = (value & 0x7F | 0x80) << 16 | ((value >>> 7) & 0x7F | 0x80) << 8 | (value >>> 14);
|
||||
buf.writeMedium(w);
|
||||
}
|
||||
|
||||
public static String readString(ByteBuf buf) {
|
||||
return readString(buf, DEFAULT_MAX_STRING_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a VarInt length-prefixed string from the {@code buf}, making sure to not go over
|
||||
* Reads a VarInt length-prefixed UTF-8 string from the {@code buf}, making sure to not go over
|
||||
* {@code cap} size.
|
||||
* @param buf the buffer to read from
|
||||
* @param cap the maximum size of the string, in UTF-8 character length
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network;
|
||||
|
||||
import static com.velocitypowered.proxy.network.HandlerNames.FRAME_DECODER;
|
||||
@@ -36,11 +53,11 @@ public class ServerChannelInitializer extends ChannelInitializer<Channel> {
|
||||
@Override
|
||||
protected void initChannel(final Channel ch) {
|
||||
ch.pipeline()
|
||||
.addLast(READ_TIMEOUT,
|
||||
new ReadTimeoutHandler(this.server.getConfiguration().getReadTimeout(),
|
||||
TimeUnit.MILLISECONDS))
|
||||
.addLast(LEGACY_PING_DECODER, new LegacyPingDecoder())
|
||||
.addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder())
|
||||
.addLast(READ_TIMEOUT,
|
||||
new ReadTimeoutHandler(this.server.configuration().getReadTimeout(),
|
||||
TimeUnit.MILLISECONDS))
|
||||
.addLast(LEGACY_PING_ENCODER, LegacyPingEncoder.INSTANCE)
|
||||
.addLast(FRAME_ENCODER, MinecraftVarintLengthEncoder.INSTANCE)
|
||||
.addLast(MINECRAFT_DECODER, new MinecraftDecoder(PacketDirection.SERVERBOUND))
|
||||
@@ -50,7 +67,7 @@ public class ServerChannelInitializer extends ChannelInitializer<Channel> {
|
||||
connection.setSessionHandler(new HandshakeSessionHandler(connection, this.server));
|
||||
ch.pipeline().addLast(HandlerNames.HANDLER, connection);
|
||||
|
||||
if (this.server.getConfiguration().isProxyProtocol()) {
|
||||
if (this.server.configuration().isProxyProtocol()) {
|
||||
ch.pipeline().addFirst(new HAProxyMessageDecoder());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network;
|
||||
|
||||
import static com.google.common.collect.Iterables.getLast;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network;
|
||||
|
||||
import com.velocitypowered.proxy.util.concurrent.VelocityNettyThreadFactory;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network.buffer;
|
||||
|
||||
import com.google.common.io.ByteArrayDataInput;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network.buffer;
|
||||
|
||||
import com.google.common.io.ByteArrayDataOutput;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network.buffer;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network.packet;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network.packet;
|
||||
|
||||
import static com.velocitypowered.proxy.network.PluginMessageUtil.transformLegacyToModernChannel;
|
||||
@@ -15,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());
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network.packet;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
@@ -12,6 +29,7 @@ public abstract class AbstractStatusPingPacket implements Packet {
|
||||
return factory.apply(randomId);
|
||||
};
|
||||
}
|
||||
|
||||
protected static <P extends AbstractStatusPingPacket> PacketWriter<P> encoder() {
|
||||
return (buf, packet, version) -> buf.writeLong(packet.getRandomId());
|
||||
}
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network.packet;
|
||||
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network.packet;
|
||||
|
||||
public enum PacketDirection {
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network.packet;
|
||||
|
||||
import com.velocitypowered.proxy.network.packet.clientbound.ClientboundAvailableCommandsPacket;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network.packet;
|
||||
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network.packet;
|
||||
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network.packet.clientbound;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network.packet.clientbound;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network.packet.clientbound;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network.packet.clientbound;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
@@ -14,13 +31,13 @@ import net.kyori.adventure.text.Component;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class ClientboundDisconnectPacket implements Packet {
|
||||
public static final PacketReader<ClientboundDisconnectPacket> DECODER = PacketReader.method(ClientboundDisconnectPacket::new);
|
||||
public static final PacketWriter<ClientboundDisconnectPacket> ENCODER = PacketWriter.deprecatedEncode();
|
||||
public static final PacketReader<ClientboundDisconnectPacket> DECODER = (buf, version) ->
|
||||
new ClientboundDisconnectPacket(ProtocolUtils.readString(buf));
|
||||
public static final PacketWriter<ClientboundDisconnectPacket> ENCODER = (out, packet, version) -> {
|
||||
ProtocolUtils.writeString(out, packet.reason);
|
||||
};
|
||||
|
||||
private @Nullable String reason;
|
||||
|
||||
public ClientboundDisconnectPacket() {
|
||||
}
|
||||
private final String reason;
|
||||
|
||||
public ClientboundDisconnectPacket(String reason) {
|
||||
this.reason = Preconditions.checkNotNull(reason, "reason");
|
||||
@@ -33,23 +50,6 @@ public class ClientboundDisconnectPacket implements Packet {
|
||||
return reason;
|
||||
}
|
||||
|
||||
public void setReason(@Nullable String reason) {
|
||||
this.reason = reason;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, PacketDirection direction, ProtocolVersion version) {
|
||||
reason = ProtocolUtils.readString(buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolVersion version) {
|
||||
if (reason == null) {
|
||||
throw new IllegalStateException("No reason specified.");
|
||||
}
|
||||
ProtocolUtils.writeString(buf, reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(PacketHandler handler) {
|
||||
return handler.handle(this);
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network.packet.clientbound;
|
||||
|
||||
import static com.velocitypowered.proxy.connection.VelocityConstants.EMPTY_BYTE_ARRAY;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network.packet.clientbound;
|
||||
|
||||
import static com.velocitypowered.proxy.network.ProtocolUtils.writeString;
|
||||
@@ -5,6 +22,7 @@ import static com.velocitypowered.proxy.network.ProtocolUtils.writeString;
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.network.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.network.packet.Packet;
|
||||
import com.velocitypowered.proxy.network.packet.PacketHandler;
|
||||
import com.velocitypowered.proxy.network.packet.PacketReader;
|
||||
@@ -12,8 +30,11 @@ import com.velocitypowered.proxy.network.packet.PacketWriter;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public class ClientboundHeaderAndFooterPacket implements Packet {
|
||||
public static final PacketReader<ClientboundHeaderAndFooterPacket> DECODER = PacketReader.method(ClientboundHeaderAndFooterPacket::new);
|
||||
public static final PacketWriter<ClientboundHeaderAndFooterPacket> ENCODER = PacketWriter.deprecatedEncode();
|
||||
public static final PacketReader<ClientboundHeaderAndFooterPacket> DECODER = PacketReader.unsupported();
|
||||
public static final PacketWriter<ClientboundHeaderAndFooterPacket> ENCODER = (out, packet, version) -> {
|
||||
writeString(out, packet.header);
|
||||
writeString(out, packet.footer);
|
||||
};
|
||||
|
||||
private static final String EMPTY_COMPONENT = "{\"translate\":\"\"}";
|
||||
private static final ClientboundHeaderAndFooterPacket RESET
|
||||
@@ -31,12 +52,6 @@ public class ClientboundHeaderAndFooterPacket implements Packet {
|
||||
this.footer = Preconditions.checkNotNull(footer, "footer");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolVersion version) {
|
||||
writeString(buf, header);
|
||||
writeString(buf, footer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(PacketHandler handler) {
|
||||
return handler.handle(this);
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network.packet.clientbound;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network.packet.clientbound;
|
||||
|
||||
import com.velocitypowered.proxy.network.packet.AbstractKeepAlivePacket;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network.packet.clientbound;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network.packet.clientbound;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
@@ -188,12 +205,12 @@ public class ClientboundPlayerListItemPacket implements Packet {
|
||||
}
|
||||
|
||||
public static Item from(TabListEntry entry) {
|
||||
return new Item(entry.getProfile().getId())
|
||||
.setName(entry.getProfile().getName())
|
||||
.setProperties(entry.getProfile().getProperties())
|
||||
.setLatency(entry.getLatency())
|
||||
.setGameMode(entry.getGameMode())
|
||||
.setDisplayName(entry.getDisplayName().orElse(null));
|
||||
return new Item(entry.gameProfile().getId())
|
||||
.setName(entry.gameProfile().getName())
|
||||
.setProperties(entry.gameProfile().getProperties())
|
||||
.setLatency(entry.ping())
|
||||
.setGameMode(entry.gameMode())
|
||||
.setDisplayName(entry.displayName().orElse(null));
|
||||
}
|
||||
|
||||
public @Nullable UUID getUuid() {
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network.packet.clientbound;
|
||||
|
||||
import com.velocitypowered.proxy.network.packet.AbstractPluginMessagePacket;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network.packet.clientbound;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
@@ -16,7 +33,10 @@ public class ClientboundResourcePackRequestPacket implements Packet {
|
||||
final String hash = ProtocolUtils.readString(buf);
|
||||
return new ClientboundResourcePackRequestPacket(url, hash);
|
||||
};
|
||||
public static final PacketWriter<ClientboundResourcePackRequestPacket> ENCODER = PacketWriter.deprecatedEncode();
|
||||
public static final PacketWriter<ClientboundResourcePackRequestPacket> ENCODER = (out, packet, version) -> {
|
||||
ProtocolUtils.writeString(out, packet.url);
|
||||
ProtocolUtils.writeString(out, packet.hash);
|
||||
};
|
||||
|
||||
private final String url;
|
||||
private final String hash;
|
||||
@@ -26,12 +46,6 @@ public class ClientboundResourcePackRequestPacket implements Packet {
|
||||
this.hash = Objects.requireNonNull(hash, "hash");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeString(buf, url);
|
||||
ProtocolUtils.writeString(buf, hash);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(PacketHandler handler) {
|
||||
return handler.handle(this);
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network.packet.clientbound;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network.packet.clientbound;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
@@ -25,7 +42,16 @@ public class ClientboundServerLoginSuccessPacket implements Packet {
|
||||
final String username = ProtocolUtils.readString(buf, 16);
|
||||
return new ClientboundServerLoginSuccessPacket(uuid, username);
|
||||
};
|
||||
public static final PacketWriter<ClientboundServerLoginSuccessPacket> ENCODER = PacketWriter.deprecatedEncode();
|
||||
public static final PacketWriter<ClientboundServerLoginSuccessPacket> ENCODER = (out, packet, version) -> {
|
||||
if (version.gte(ProtocolVersion.MINECRAFT_1_16)) {
|
||||
ProtocolUtils.writeUuidIntArray(out, packet.uuid);
|
||||
} else if (version.gte(ProtocolVersion.MINECRAFT_1_7_6)) {
|
||||
ProtocolUtils.writeString(out, packet.uuid.toString());
|
||||
} else {
|
||||
ProtocolUtils.writeString(out, UuidUtils.toUndashed(packet.uuid));
|
||||
}
|
||||
ProtocolUtils.writeString(out, packet.username);
|
||||
};
|
||||
|
||||
private final UUID uuid;
|
||||
private final String username;
|
||||
@@ -35,18 +61,6 @@ public class ClientboundServerLoginSuccessPacket implements Packet {
|
||||
this.username = Objects.requireNonNull(username, "username");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolVersion version) {
|
||||
if (version.gte(ProtocolVersion.MINECRAFT_1_16)) {
|
||||
ProtocolUtils.writeUuidIntArray(buf, uuid);
|
||||
} else if (version.gte(ProtocolVersion.MINECRAFT_1_7_6)) {
|
||||
ProtocolUtils.writeString(buf, uuid.toString());
|
||||
} else {
|
||||
ProtocolUtils.writeString(buf, UuidUtils.toUndashed(uuid));
|
||||
}
|
||||
ProtocolUtils.writeString(buf, username);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(PacketHandler handler) {
|
||||
return handler.handle(this);
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network.packet.clientbound;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network.packet.clientbound;
|
||||
|
||||
import com.velocitypowered.proxy.network.packet.AbstractStatusPingPacket;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network.packet.clientbound;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
@@ -16,7 +33,7 @@ public class ClientboundStatusResponsePacket implements Packet {
|
||||
return new ClientboundStatusResponsePacket(status);
|
||||
};
|
||||
public static final PacketWriter<ClientboundStatusResponsePacket> ENCODER = (buf, packet, version) ->
|
||||
ProtocolUtils.writeString(buf, packet.status);
|
||||
ProtocolUtils.writeString(buf, packet.status);
|
||||
|
||||
private final @Nullable CharSequence status;
|
||||
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network.packet.clientbound;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network.packet.clientbound;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.network.packet.legacy;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@@ -28,7 +45,7 @@ public class LegacyDisconnectPacket implements LegacyPacket {
|
||||
*/
|
||||
public static LegacyDisconnectPacket fromServerPing(ServerPing response,
|
||||
LegacyMinecraftPingVersion version) {
|
||||
Players players = response.getPlayers().orElse(FAKE_PLAYERS);
|
||||
Players players = response.players().orElse(FAKE_PLAYERS);
|
||||
|
||||
switch (version) {
|
||||
case MINECRAFT_1_3:
|
||||
@@ -37,20 +54,20 @@ public class LegacyDisconnectPacket implements LegacyPacket {
|
||||
// MOTD.
|
||||
return new LegacyDisconnectPacket(String.join(LEGACY_COLOR_CODE,
|
||||
cleanSectionSymbol(getFirstLine(PlainComponentSerializer.plain().serialize(
|
||||
response.getDescription()))),
|
||||
Integer.toString(players.getOnline()),
|
||||
Integer.toString(players.getMax())));
|
||||
response.description()))),
|
||||
Integer.toString(players.online()),
|
||||
Integer.toString(players.maximum())));
|
||||
case MINECRAFT_1_4:
|
||||
case MINECRAFT_1_6:
|
||||
// Minecraft 1.4-1.6 provide support for more fields, and additionally support color codes.
|
||||
return new LegacyDisconnectPacket(String.join("\0",
|
||||
LEGACY_COLOR_CODE + "1",
|
||||
Integer.toString(response.getVersion().getProtocol()),
|
||||
response.getVersion().getName(),
|
||||
Integer.toString(response.version().protocol()),
|
||||
response.version().name(),
|
||||
getFirstLine(LegacyComponentSerializer.legacySection().serialize(response
|
||||
.getDescription())),
|
||||
Integer.toString(players.getOnline()),
|
||||
Integer.toString(players.getMax())
|
||||
.description())),
|
||||
Integer.toString(players.online()),
|
||||
Integer.toString(players.maximum())
|
||||
));
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown version " + version);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user