Use sealed types in command interfaces (#1239)

* Use sealed types in command interfaces

* Some minor code fixes
This commit is contained in:
Adrian 2024-02-09 14:15:53 -05:00 committed by GitHub
parent 6f7f722bfb
commit 7bff6b19eb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 51 additions and 43 deletions

View File

@ -29,5 +29,5 @@ import com.velocitypowered.api.proxy.Player;
*
* </ul>
*/
public interface Command {
public sealed interface Command permits BrigadierCommand, InvocableCommand {
}

View File

@ -21,7 +21,8 @@ import java.util.concurrent.CompletableFuture;
*
* @param <I> the type of the command invocation object
*/
public interface InvocableCommand<I extends CommandInvocation<?>> extends Command {
public sealed interface InvocableCommand<I extends CommandInvocation<?>> extends Command
permits RawCommand, SimpleCommand {
/**
* Executes the command for the specified invocation.

View File

@ -12,7 +12,7 @@ package com.velocitypowered.api.command;
* the command and its arguments directly without further processing.
* This is useful for bolting on external command frameworks to Velocity.
*/
public interface RawCommand extends InvocableCommand<RawCommand.Invocation> {
public non-sealed interface RawCommand extends InvocableCommand<RawCommand.Invocation> {
/**
* Contains the invocation data for a raw command.

View File

@ -16,7 +16,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
* <p>Prefer using {@link BrigadierCommand}, which is also
* backwards-compatible with older clients.
*/
public interface SimpleCommand extends InvocableCommand<SimpleCommand.Invocation> {
public non-sealed interface SimpleCommand extends InvocableCommand<SimpleCommand.Invocation> {
/**
* Contains the invocation data for a simple command.

View File

@ -93,6 +93,7 @@ import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.IntFunction;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.audience.ForwardingAudience;
import net.kyori.adventure.key.Key;
@ -143,7 +144,6 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
private final ConnectionManager cm;
private final ProxyOptions options;
private final HttpClient httpClient;
private @MonotonicNonNull VelocityConfiguration configuration;
private @MonotonicNonNull KeyPair serverKeyPair;
private final ServerMap servers;
@ -159,7 +159,7 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
private final VelocityEventManager eventManager;
private final VelocityScheduler scheduler;
private final VelocityChannelRegistrar channelRegistrar = new VelocityChannelRegistrar();
private ServerListPingHandler serverListPingHandler;
private final ServerListPingHandler serverListPingHandler;
VelocityServer(final ProxyOptions options) {
pluginManager = new VelocityPluginManager(this);
@ -168,7 +168,6 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
scheduler = new VelocityScheduler(pluginManager);
console = new VelocityConsole(this);
cm = new ConnectionManager(this);
httpClient = HttpClient.newHttpClient();
servers = new ServerMap(this);
serverListPingHandler = new ServerListPingHandler(this);
this.options = options;
@ -282,40 +281,39 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
try {
if (!Files.exists(langPath)) {
Files.createDirectory(langPath);
Files.walk(path).forEach(file -> {
if (!Files.isRegularFile(file)) {
return;
}
try {
Path langFile = langPath.resolve(file.getFileName().toString());
if (!Files.exists(langFile)) {
try (InputStream is = Files.newInputStream(file)) {
Files.copy(is, langFile);
try (final Stream<Path> files = Files.walk(path)) {
files.filter(Files::isRegularFile).forEach(file -> {
try {
final Path langFile = langPath.resolve(file.getFileName().toString());
if (!Files.exists(langFile)) {
try (final InputStream is = Files.newInputStream(file)) {
Files.copy(is, langFile);
}
}
} catch (IOException e) {
logger.error("Encountered an I/O error whilst loading translations", e);
}
} catch (IOException e) {
logger.error("Encountered an I/O error whilst loading translations", e);
}
});
}
}
try (final Stream<Path> files = Files.walk(langPath)) {
files.filter(Files::isRegularFile).forEach(file -> {
final String filename = com.google.common.io.Files
.getNameWithoutExtension(file.getFileName().toString());
final String localeName = filename.replace("messages_", "")
.replace("messages", "")
.replace('_', '-');
final Locale locale = localeName.isBlank()
? Locale.US
: Locale.forLanguageTag(localeName);
translationRegistry.registerAll(locale, file, false);
ClosestLocaleMatcher.INSTANCE.registerKnown(locale);
});
}
Files.walk(langPath).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 = localeName.isBlank()
? Locale.US
: Locale.forLanguageTag(localeName);
translationRegistry.registerAll(locale, file, false);
ClosestLocaleMatcher.INSTANCE.registerKnown(locale);
});
} catch (IOException e) {
logger.error("Encountered an I/O error whilst loading translations", e);
}
@ -419,10 +417,9 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
// move back to a fallback server.
Collection<ConnectedPlayer> evacuate = new ArrayList<>();
for (Map.Entry<String, String> entry : newConfiguration.getServers().entrySet()) {
ServerInfo newInfo =
new ServerInfo(entry.getKey(), AddressUtil.parseAddress(entry.getValue()));
ServerInfo newInfo = new ServerInfo(entry.getKey(), AddressUtil.parseAddress(entry.getValue()));
Optional<RegisteredServer> rs = servers.getServer(entry.getKey());
if (!rs.isPresent()) {
if (rs.isEmpty()) {
servers.register(newInfo);
} else if (!rs.get().getServerInfo().equals(newInfo)) {
for (Player player : rs.get().getPlayersConnected()) {

View File

@ -84,14 +84,14 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler {
}
@Override
public boolean handle(HandshakePacket handshake) {
final InitialInboundConnection ic = new InitialInboundConnection(connection,
cleanVhost(handshake.getServerAddress()), handshake);
public boolean handle(final HandshakePacket handshake) {
final StateRegistry nextState = getStateForProtocol(handshake.getNextStatus());
if (nextState == null) {
LOGGER.error("{} provided invalid protocol {}", ic, handshake.getNextStatus());
LOGGER.error("{} provided invalid protocol {}", this, handshake.getNextStatus());
connection.close(true);
} else {
final InitialInboundConnection ic = new InitialInboundConnection(connection,
cleanVhost(handshake.getServerAddress()), handshake);
connection.setProtocolVersion(handshake.getProtocolVersion());
connection.setAssociation(ic);
@ -208,6 +208,16 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler {
connection.close(true);
}
@Override
public String toString() {
final boolean isPlayerAddressLoggingEnabled = connection.server.getConfiguration()
.isPlayerAddressLoggingEnabled();
final String playerIp =
isPlayerAddressLoggingEnabled
? this.connection.getRemoteAddress().toString() : "<ip address withheld>";
return "[initial connection] " + playerIp;
}
private record LegacyInboundConnection(
MinecraftConnection connection,
LegacyPingPacket ping