This commit is contained in:
kento2 2026-08-29 03:06:29 +02:00
parent ce56c6e105
commit 35a0784e40
46 changed files with 597 additions and 673 deletions

View file

@ -9,12 +9,14 @@ java_library(
visibility = ["//visibility:public"],
deps = [
"//core/common",
artifact("site.lab0x13.scrow:commands-common"),
artifact("com.velocitypowered:velocity-api"),
artifact("de.kentoj.scrow:kencommandapi-velocity"),
artifact("site.lab0x13.scrow:commands-velocity"),
],
exports = [
"//core/common",
artifact("de.kentoj.scrow:kencommandapi-velocity"),
artifact("site.lab0x13.scrow:commands-common"),
artifact("site.lab0x13.scrow:commands-velocity"),
artifact("org.mongodb:bson"),
],
neverlink = True,
@ -25,11 +27,13 @@ java_binary(
srcs = glob(["plugin/main/java/**/*.java", "api/main/java/**/*.java"]),
create_executable = False,
deps = [
":api",
"//core/common",
artifact("site.lab0x13.scrow:commands-common"),
artifact("com.velocitypowered:velocity-api"),
artifact("com.google.inject:guice"),
artifact("io.nats:jnats"),
artifact("de.kentoj.scrow:kencommandapi-velocity"),
artifact("site.lab0x13.scrow:commands-velocity"),
artifact("org.mongodb:bson"),
artifact("org.postgresql:postgresql"),
artifact("com.google.code.gson:gson"),

View file

@ -1,22 +1,21 @@
package de.kentoj.scrow.velocity;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.proxy.Player;
import de.kentoj.kencommandapi.CommandAPI;
import de.kentoj.scrow.velocity.commands.ScrowVelocityCC;
import de.kentoj.scrowlib.instancemanager.InstanceManager;
import de.kentoj.scrowlib.messaging.MessageBroker;
import de.kentoj.scrowlib.player.NetworkPlayer;
import de.kentoj.scrowlib.player.NetworkPlayerFactory;
import org.jdbi.v3.core.Jdbi;
import org.jetbrains.annotations.ApiStatus;
import site.lab0x13.scrow.commands.velocity.ScrowCommands;
import java.util.UUID;
public class ScrowAPI {
private static Jdbi jdbi;
private static CommandAPI<CommandSource> commands;
private static CommandAPI<Player> playerCommands;
private static ScrowCommands<ScrowVelocityCC> commands;
private static MessageBroker messageBroker;
private static InstanceManager instanceManager;
private static NetworkPlayerFactory playerFactory;
@ -30,32 +29,27 @@ public class ScrowAPI {
}
@ApiStatus.Internal
public static void initMessageBroker(MessageBroker messageBroker) {
public static void setMessageBroker(MessageBroker messageBroker) {
ScrowAPI.messageBroker = messageBroker;
}
@ApiStatus.Internal
public static void initInstanceManager(InstanceManager instanceManager) {
public static void setInstanceManager(InstanceManager instanceManager) {
ScrowAPI.instanceManager = instanceManager;
}
@ApiStatus.Internal
public static void initJdbi(Jdbi jdbi) {
public static void setJdbi(Jdbi jdbi) {
ScrowAPI.jdbi = jdbi;
}
@ApiStatus.Internal
public static void initPlayerFactory(NetworkPlayerFactory playerFactory) {
public static void setPlayerFactory(NetworkPlayerFactory playerFactory) {
ScrowAPI.playerFactory = playerFactory;
}
@ApiStatus.Internal
public static void initPlayerCommands(CommandAPI<Player> playerCommands) {
ScrowAPI.playerCommands = playerCommands;
}
@ApiStatus.Internal
public static void initCommands(CommandAPI<CommandSource> commands) {
public static void setCommands(ScrowCommands<ScrowVelocityCC> commands) {
ScrowAPI.commands = commands;
}
@ -63,14 +57,10 @@ public class ScrowAPI {
return jdbi;
}
public static CommandAPI<CommandSource> commands() {
public static ScrowCommands<ScrowVelocityCC> commands() {
return commands;
}
public static CommandAPI<Player> playerCommands() {
return playerCommands;
}
public static MessageBroker messageBroker() {
return messageBroker;
}

View file

@ -0,0 +1,19 @@
package de.kentoj.scrow.velocity.commands;
import com.velocitypowered.api.command.CommandSource;
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
import site.lab0x13.scrow.commands.velocity.VelocityCommandContext;
public class ScrowVelocityCC extends VelocityCommandContext<ScrowVelocityCC> {
private final ScrowMessageStyle style;
public ScrowVelocityCC(CommandSource sender, ScrowMessageStyle style) {
super(sender);
this.style = style;
}
public ScrowMessageStyle style() {
return style;
}
}

View file

@ -3,6 +3,7 @@ package de.kentoj.scrow.corevelocity;
import com.google.inject.Inject;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
import com.velocitypowered.api.plugin.Plugin;
import com.velocitypowered.api.proxy.ProxyServer;
import de.kentoj.scrow.corevelocity.misc.OnlineCommand;
@ -12,14 +13,12 @@ import de.kentoj.scrow.corevelocity.privmsg.MsgCommand;
import de.kentoj.scrow.corevelocity.privmsg.PrivMsgHandler;
import de.kentoj.scrow.corevelocity.privmsg.ReplyCommand;
import de.kentoj.scrow.corevelocity.serverregistration.ConsulV1ServerInstanceScanner;
import de.kentoj.scrow.corevelocity.serverregistration.RegistrationTask;
import de.kentoj.scrow.corevelocity.serverregistration.ServerInstanceScanner;
import de.kentoj.scrow.corevelocity.serverregistration.PlayerTryJoinLobbyListener;
import de.kentoj.scrow.velocity.ScrowAPI;
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
import de.kentoj.scrowlib.utils.EnvUtils;
import net.kyori.adventure.text.format.NamedTextColor;
import java.time.Duration;
import site.lab0x13.scrow.commands.model.literal.MessageStyle;
@Plugin(
id = "corevelocity",
@ -31,6 +30,7 @@ public final class CoreVelocityPlugin {
@Inject
private ProxyServer server;
private ConsulV1ServerInstanceScanner instanceScanner;
@Subscribe
private void onInit(ProxyInitializeEvent __) {
@ -39,15 +39,21 @@ public final class CoreVelocityPlugin {
var lastTargetCache = new LastTargetCache();
var style = new ScrowMessageStyle("MSG", NamedTextColor.LIGHT_PURPLE);
var privmsgHelper = new PrivMsgHandler(style);
ScrowAPI.playerCommands().register(new ReplyCommand(server, lastTargetCache, privmsgHelper, style).rootLiteral());
ScrowAPI.playerCommands().register(new MsgCommand(server, lastTargetCache, privmsgHelper, style).rootLiteral());
ScrowAPI.commands().register(new ReplyCommand(server, lastTargetCache, privmsgHelper, style).rootLiteral());
ScrowAPI.commands().register(new MsgCommand(server, lastTargetCache, privmsgHelper, style).rootLiteral());
ScrowAPI.commands().register(new OnlineCommand(server).rootLiteral());
var sendPlayerWatchdog = new SendPlayerWatchdog(server);
sendPlayerWatchdog.listen();
ServerInstanceScanner instanceScanner = new ConsulV1ServerInstanceScanner(EnvUtils.envOrThrow("HOST_CONSUL"));
server.getScheduler().buildTask(this, new RegistrationTask(server, instanceScanner))
.repeat(Duration.ofSeconds(3))
instanceScanner = new ConsulV1ServerInstanceScanner(server, EnvUtils.envOrThrow("HOST_CONSUL"));
server.getEventManager().register(this, new PlayerTryJoinLobbyListener(server));
server.getScheduler()
.buildTask(this, () -> instanceScanner.start())
.schedule();
}
@Subscribe
private void onShutdown(ProxyShutdownEvent __) {
instanceScanner.close();
}
}

View file

@ -1,10 +1,9 @@
package de.kentoj.scrow.corevelocity;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ProxyServer;
import de.kentoj.kencommandapi.CommandAPI;
import de.kentoj.scrow.velocity.ScrowAPI;
import de.kentoj.scrow.velocity.commands.ScrowVelocityCC;
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
import de.kentoj.scrowlib.instancemanager.InstanceManagerImpl;
import de.kentoj.scrowlib.messaging.InMemoyMessageBroker;
import de.kentoj.scrowlib.messaging.NatsMessageBroker;
@ -14,6 +13,7 @@ import io.nats.client.Options;
import org.jdbi.v3.core.Jdbi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import site.lab0x13.scrow.commands.velocity.ScrowCommands;
import java.io.IOException;
import java.util.Properties;
@ -30,13 +30,13 @@ public class ScrowAPISurface {
.server(natsHost)
.pedantic()
.build();
ScrowAPI.initMessageBroker(new NatsMessageBroker(Nats.connect(options)));
ScrowAPI.setMessageBroker(new NatsMessageBroker(Nats.connect(options)));
} catch (IOException | InterruptedException e) {
throw new RuntimeException(e);
}
} else {
log.error("HOST_NATS not set -> Using in-memory dummy message broker");
ScrowAPI.initMessageBroker(new InMemoyMessageBroker());
ScrowAPI.setMessageBroker(new InMemoyMessageBroker());
}
var hostPostgres = System.getenv().get("HOST_POSTGRES");
@ -45,7 +45,7 @@ public class ScrowAPISurface {
Class.forName("org.postgresql.Driver", true, ScrowAPISurface.class.getClassLoader());
var props = new Properties();
props.setProperty("user", "postgres");
ScrowAPI.initJdbi(Jdbi.create(hostPostgres, props));
ScrowAPI.setJdbi(Jdbi.create(hostPostgres, props));
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
@ -53,10 +53,9 @@ public class ScrowAPISurface {
log.error("HOST_POSTGRES not set -> Using in-memory database");
}
ScrowAPI.initInstanceManager(new InstanceManagerImpl(ScrowAPI.messageBroker()));
ScrowAPI.initCommands(new CommandAPI<>(server, CommandSource.class));
ScrowAPI.initPlayerCommands(new CommandAPI<>(server, Player.class));
ScrowAPI.initPlayerFactory(playerId -> new NetworkPlayerImpl(ScrowAPI.messageBroker(), playerId));
ScrowAPI.setInstanceManager(new InstanceManagerImpl(ScrowAPI.messageBroker()));
ScrowAPI.setCommands(new ScrowCommands<>(server, (literal, sender) -> new ScrowVelocityCC(sender, (ScrowMessageStyle) literal.style())));
ScrowAPI.setPlayerFactory(playerId -> new NetworkPlayerImpl(ScrowAPI.messageBroker(), playerId));
}
public static void destroyScrowAPI() {

View file

@ -1,38 +1,33 @@
package de.kentoj.scrow.corevelocity.misc;
import com.leakyabstractions.result.api.Result;
import com.leakyabstractions.result.core.Results;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.proxy.ProxyServer;
import de.kentoj.kencommandapi.api.invocation.CommandContext;
import de.kentoj.kencommandapi.api.invocation.SyncCommandExecutor;
import de.kentoj.kencommandapi.api.literal.Literal;
import de.kentoj.kencommandapi.api.literal.RootLiteral;
import de.kentoj.scrow.velocity.commands.ScrowVelocityCC;
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
import site.lab0x13.scrow.commands.model.literal.Literal;
import site.lab0x13.scrow.commands.model.literal.RootLiteral;
public final class OnlineCommand {
private final RootLiteral<CommandSource> rootLiteral;
private final RootLiteral<ScrowVelocityCC> rootLiteral;
private final ScrowMessageStyle style = ScrowMessageStyle.GENERIC;
private final ProxyServer server;
public OnlineCommand(ProxyServer server) {
this.server = server;
rootLiteral = Literal.<CommandSource>builder("online")
rootLiteral = Literal.<ScrowVelocityCC>builder("online")
.withSyncExecutor(this::executeSync)
.asRootLiteral(ScrowMessageStyle.GENERIC);
}
private Result<Object, String> executeSync(CommandContext<CommandSource> ctx) {
private void executeSync(ScrowVelocityCC ctx) {
int cnt = server.getPlayerCount();
var msg = cnt != 1
? "There are currently " + cnt + " players online."
: "There is currently 1 player online.";
ctx.sender().sendMessage(style.ok(msg));
return Results.success(new Object());
}
public RootLiteral<CommandSource> rootLiteral() {
public RootLiteral<ScrowVelocityCC> rootLiteral() {
return rootLiteral;
}
}

View file

@ -1,54 +1,53 @@
package de.kentoj.scrow.corevelocity.privmsg;
import com.leakyabstractions.result.api.Result;
import com.leakyabstractions.result.core.Results;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ProxyServer;
import de.kentoj.kencommandapi.api.argument.CommandArgumentSpec;
import de.kentoj.kencommandapi.api.argument.types.StringArgumentType;
import de.kentoj.kencommandapi.api.invocation.CommandContext;
import de.kentoj.kencommandapi.api.literal.Literal;
import de.kentoj.kencommandapi.api.literal.RootLiteral;
import de.kentoj.kencommandapi.api.platform.MessageStyle;
import de.kentoj.kencommandapi.type.PlayerArgumentType;
import de.kentoj.scrow.velocity.commands.ScrowVelocityCC;
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
import site.lab0x13.scrow.commands.model.argument.Argument;
import site.lab0x13.scrow.commands.model.argument.types.StringArgumentType;
import site.lab0x13.scrow.commands.model.literal.Literal;
import site.lab0x13.scrow.commands.model.literal.RootLiteral;
import site.lab0x13.scrow.commands.velocity.type.PlayerArgumentType;
public class MsgCommand {
private final RootLiteral<Player> rootLiteral;
private final CommandArgumentSpec<Player, Player> targetArg;
private final CommandArgumentSpec<Player, String> msgArg;
private final RootLiteral<ScrowVelocityCC> rootLiteral;
private final Argument<ScrowVelocityCC, Player> targetArg;
private final Argument<ScrowVelocityCC, String> msgArg;
private final LastTargetCache cache;
private final PrivMsgHandler privMsgHandler;
public MsgCommand(ProxyServer server, LastTargetCache cache, PrivMsgHandler helper, MessageStyle style) {
public MsgCommand(ProxyServer server, LastTargetCache cache, PrivMsgHandler helper, ScrowMessageStyle style) {
this.cache = cache;
this.privMsgHandler = helper;
targetArg = CommandArgumentSpec.builder("target", new PlayerArgumentType<Player>(server)).build();
msgArg = CommandArgumentSpec.builder("msg", new StringArgumentType<Player>(true)).build();
targetArg = Argument.builder("target", new PlayerArgumentType<ScrowVelocityCC>(server)).build();
msgArg = Argument.builder("msg", new StringArgumentType<ScrowVelocityCC>(true)).build();
rootLiteral = Literal.<Player>builder("msg", "w", "privmsg")
rootLiteral = Literal.<ScrowVelocityCC>builder("msg", "w", "privmsg")
.withArgument(targetArg)
.withArgument(msgArg)
.withSyncExecutor(this::executeSync)
.asRootLiteral(style);
}
private Result<Object, String> executeSync(CommandContext<Player> ctx) {
var target = ctx.getArg(targetArg);
private void executeSync(ScrowVelocityCC ctx) {
var target = ctx.getarg(targetArg);
var msg = ctx.getArg(msgArg);
var isMessagingSelf = target.getUniqueId().equals(ctx.sender().getUniqueId());
if (isMessagingSelf) return Results.failure("You can't message yourself.");
var isMessagingSelf = target.getUniqueId().equals(ctx.player().getUniqueId());
if (isMessagingSelf) {
ctx.player().sendMessage(ctx.style().err("You can't message yourself."));
return;
}
cache.setLastTarget(ctx.sender().getUniqueId(), target.getUniqueId());
privMsgHandler.handle(ctx.sender(), target, msg);
return Results.success(new Object());
cache.setLastTarget(ctx.player().getUniqueId(), target.getUniqueId());
privMsgHandler.handle(ctx.player(), target, msg);
}
public RootLiteral<Player> rootLiteral() {
public RootLiteral<ScrowVelocityCC> rootLiteral() {
return rootLiteral;
}
}

View file

@ -1,53 +1,51 @@
package de.kentoj.scrow.corevelocity.privmsg;
import com.leakyabstractions.result.api.Result;
import com.leakyabstractions.result.core.Results;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ProxyServer;
import de.kentoj.kencommandapi.api.argument.CommandArgumentSpec;
import de.kentoj.kencommandapi.api.argument.types.StringArgumentType;
import de.kentoj.kencommandapi.api.invocation.CommandContext;
import de.kentoj.kencommandapi.api.literal.Literal;
import de.kentoj.kencommandapi.api.literal.RootLiteral;
import de.kentoj.kencommandapi.api.platform.MessageStyle;
import de.kentoj.kencommandapi.type.PlayerArgumentType;
import de.kentoj.scrow.velocity.commands.ScrowVelocityCC;
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
import site.lab0x13.scrow.commands.model.argument.Argument;
import site.lab0x13.scrow.commands.model.argument.types.StringArgumentType;
import site.lab0x13.scrow.commands.model.literal.Literal;
import site.lab0x13.scrow.commands.model.literal.RootLiteral;
public class ReplyCommand {
private final RootLiteral<Player> rootLiteral;
private final CommandArgumentSpec<Player, String> msgArg;
private final RootLiteral<ScrowVelocityCC> rootLiteral;
private final Argument<ScrowVelocityCC, String> msgArg;
private final LastTargetCache cache;
private final ProxyServer server;
private final PrivMsgHandler privMsgHandler;
public ReplyCommand(ProxyServer server, LastTargetCache cache, PrivMsgHandler privMsgHandler, MessageStyle style) {
public ReplyCommand(ProxyServer server, LastTargetCache cache, PrivMsgHandler privMsgHandler, ScrowMessageStyle style) {
this.cache = cache;
this.server = server;
this.privMsgHandler = privMsgHandler;
msgArg = CommandArgumentSpec.builder("msg", new StringArgumentType<Player>(true)).build();
rootLiteral = Literal.<Player>builder("reply", "r")
msgArg = Argument.builder("msg", new StringArgumentType<ScrowVelocityCC>(true)).build();
rootLiteral = Literal.<ScrowVelocityCC>builder("reply", "r")
.withArgument(msgArg)
.withSyncExecutor(this::executeSync)
.asRootLiteral(style);
}
private Result<Object, String> executeSync(CommandContext<Player> ctx) {
var targetId = cache.getLastTarget(ctx.sender().getUniqueId());
if (targetId == null)
return Results.failure("You didn't messaged anyone recently. Use /msg first");
private void executeSync(ScrowVelocityCC ctx) {
var targetId = cache.getLastTarget(ctx.player().getUniqueId());
if (targetId == null) {
ctx.player().sendMessage(ctx.style().err("You didn't messaged anyone recently. Use /msg first"));
return;
}
var target = server.getPlayer(targetId).orElse(null);
var msg = ctx.getArg(msgArg);
if (target == null)
return Results.failure("The player you last messaged is no longer online.");
if (target == null) {
ctx.player().sendMessage(ctx.style().err("The player you last messaged is no longer online."));
return;
}
privMsgHandler.handle(ctx.sender(), target, msg);
return Results.success(new Object());
}
public RootLiteral<Player> rootLiteral() {
public RootLiteral<ScrowVelocityCC> rootLiteral() {
return rootLiteral;
}
}

View file

@ -1,50 +1,105 @@
package de.kentoj.scrow.corevelocity.serverregistration;
import com.google.common.hash.Hashing;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.velocitypowered.api.proxy.ProxyServer;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.proxy.server.ServerInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Closeable;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.stream.Stream;
import java.util.List;
import java.util.stream.StreamSupport;
public class ConsulV1ServerInstanceScanner implements ServerInstanceScanner, Closeable {
public class ConsulV1ServerInstanceScanner implements Closeable {
private static final Logger log = LoggerFactory.getLogger("server registration");
private final ProxyServer server;
private final String consulUrl;
private final HttpClient client;
public ConsulV1ServerInstanceScanner(String consulUrl) {
// see https://developer.hashicorp.com/consul/api-docs/features/blocking
private long lastIndex = -1;
public ConsulV1ServerInstanceScanner(ProxyServer server, String consulUrl) {
this.server = server;
this.consulUrl = consulUrl;
this.client = HttpClient.newHttpClient();
}
@Override
// FIXME query cluster-wide
public Stream<ServerInfo> queryMinecraftServers() throws IOException, InterruptedException {
var url = consulUrl + "/v1/agent/services/?filter=" + URLEncoder.encode("\"minecraft\" in Tags", StandardCharsets.UTF_8);
public void start() {
while (!Thread.currentThread().isInterrupted()) {
try {
log.info("Querying servers...");
var knownServers = server.getAllServers().stream()
.map(RegisteredServer::getServerInfo)
.toList();
var currentServers = queryMinecraftServers();
registerNewServers(knownServers, currentServers);
unregisterDeadServers(knownServers, currentServers);
} catch (IOException e) {
throw new RuntimeException("failed querying Minecraft servers", e);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
private void unregisterDeadServers(List<ServerInfo> knownServers, List<ServerInfo> currentServers) {
var currentServerIds = currentServers.stream().map(ServerInfo::getName).toList();
knownServers.stream()
.filter(s -> !currentServerIds.contains(s.getName()))
.forEach(s -> {
server.unregisterServer(s);
log.info("Unregistered server {}", s.getName());
});
}
private void registerNewServers(List<ServerInfo> knownServers, List<ServerInfo> currentServers) {
var knownServerIds = knownServers.stream()
.map(ServerInfo::getName)
.toList();
currentServers.forEach(s -> {
if (knownServerIds.contains(s.getName()))
return;
server.registerServer(s);
log.info("registered server {}", s.getName());
});
}
private List<ServerInfo> queryMinecraftServers() throws IOException, InterruptedException {
var url = consulUrl + "/v1/health/service/minecraft?passing=true";
if (lastIndex >= 0)
url += "&index=" + lastIndex;
var request = HttpRequest.newBuilder(URI.create(url))
.GET()
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
var jsonResponse = JsonParser.parseString(response.body()).getAsJsonObject();
return jsonResponse.entrySet().stream()
.map(Map.Entry::getValue)
.map(JsonElement::getAsJsonObject)
var jsonResponse = JsonParser.parseString(response.body()).getAsJsonArray();
lastIndex = response.headers().firstValueAsLong("X-Consul-Index").orElseThrow();
return StreamSupport.stream(jsonResponse.spliterator(), false)
.map(j -> j.getAsJsonObject().get("Service").getAsJsonObject())
.map(service -> {
var name = toServerName(service.get("Service").getAsString(), service.get("ID").getAsString());
var host = InetSocketAddress.createUnresolved(service.get("Address").getAsString(),
service.get("Port").getAsInt());
return new ServerInfo(name, host);
});
var gamemodeName = service.get("Meta").getAsJsonObject().get("mode").getAsString();
var address = InetSocketAddress.createUnresolved(
service.get("Address").getAsString(), service.get("Port").getAsInt());
var id = toServerName(gamemodeName, service.get("ID").getAsString());
return new ServerInfo(id, address);
})
.toList();
}
private String toServerName(String serviceName, String id) {
@ -54,7 +109,7 @@ public class ConsulV1ServerInstanceScanner implements ServerInstanceScanner, Clo
}
@Override
public void close() throws IOException {
public void close() {
client.close();
}
}

View file

@ -0,0 +1,22 @@
package de.kentoj.scrow.corevelocity.serverregistration;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.player.PlayerChooseInitialServerEvent;
import com.velocitypowered.api.proxy.ProxyServer;
public class PlayerTryJoinLobbyListener {
private final ProxyServer server;
public PlayerTryJoinLobbyListener(ProxyServer server) {
this.server = server;
}
@Subscribe
private void onChooseInitialServer(PlayerChooseInitialServerEvent ev) {
var lobby = server.getAllServers().stream()
.filter(n -> n.getServerInfo().getName().startsWith("lobby-"))
.findAny();
lobby.ifPresent(ev::setInitialServer);
}
}

View file

@ -1,29 +0,0 @@
package de.kentoj.scrow.corevelocity.serverregistration;
import com.velocitypowered.api.proxy.ProxyServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
public class RegistrationTask implements Runnable {
private static final Logger log = LoggerFactory.getLogger(RegistrationTask.class);
private final ProxyServer server;
private final ServerInstanceScanner watcher;
public RegistrationTask(ProxyServer server, ServerInstanceScanner watcher) {
this.server = server;
this.watcher = watcher;
}
@Override
public void run() {
try {
watcher.queryMinecraftServers().forEach(server::registerServer);
} catch (IOException | InterruptedException e) {
throw new RuntimeException("Failed querying available servers", e);
}
}
}

View file

@ -1,11 +0,0 @@
package de.kentoj.scrow.corevelocity.serverregistration;
import com.velocitypowered.api.proxy.server.ServerInfo;
import java.io.IOException;
import java.util.stream.Stream;
public interface ServerInstanceScanner {
Stream<ServerInfo> queryMinecraftServers() throws IOException, InterruptedException;
}