package ru.dragonestia.kubik.plugin; import com.google.gson.Gson; import com.google.inject.Inject; import com.velocitypowered.api.event.connection.PluginMessageEvent; import com.velocitypowered.api.event.player.PlayerChooseInitialServerEvent; import com.velocitypowered.api.event.proxy.ProxyInitializeEvent; import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.proxy.ProxyShutdownEvent; import com.velocitypowered.api.plugin.Plugin; import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.api.proxy.ServerConnection; import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier; import com.velocitypowered.api.proxy.server.RegisteredServer; import com.velocitypowered.api.proxy.server.ServerInfo; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.slf4j.Logger; import ru.dragonestia.kubik.client.Kubik; import ru.dragonestia.kubik.client.proxy.ProxyControl; import ru.dragonestia.kubik.client.proxy.ProxyServerRegistry; import ru.dragonestia.kubik.client.util.EnvUtil; import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; @Plugin( id = "kubik-velocity-plugin", name = "KubikConnector", version = "1.0.0", description = "Kubik connector plugin", authors = { "ScarletRedMan" } ) public class KubikPlugin implements ProxyServerRegistry { private final static MinecraftChannelIdentifier KUBIK_TRANSFER_CHANNEL_ID = MinecraftChannelIdentifier.from("kubik:transfer"); private final ProxyServer proxyServer; private final Logger logger; private final ProxyControl proxyControl; private final Gson gson = new Gson(); private final Map> pluginChannelHandlers = new ConcurrentHashMap<>(); private final Map registeredServers = new ConcurrentHashMap<>(); private Kubik kubik; private String initialServerGroupId; @Inject public KubikPlugin(ProxyServer proxyServer, Logger logger) { this.proxyServer = proxyServer; this.logger = logger; var kubikHttpUrl = EnvUtil.getString("KUBIK_DISCOVERY_HTTP_URL", "http://localhost:8080"); var kubikWsUrl = EnvUtil.getString("KUBIK_DISCOVERY_WS_URL", "ws://localhost:8080"); logger.info("Using kubik urls: {}, {}", kubikHttpUrl, kubikWsUrl); kubik = new Kubik(kubikHttpUrl, kubikWsUrl); proxyControl = kubik.initProxy(this); initialServerGroupId = EnvUtil.getString("KUBIK_INITIAL_SERVER_GROUP_ID", "lobby"); } @Subscribe public void onProxyInitialization(ProxyInitializeEvent event) { registerPluginChannel(KUBIK_TRANSFER_CHANNEL_ID, e -> { e.setResult(PluginMessageEvent.ForwardResult.handled()); if (!(e.getSource() instanceof ServerConnection backend)) return; var serverId = new String(e.getData(), StandardCharsets.UTF_8); var player = (Player) e.getTarget(); logger.info("Taken transfer request for player {} to {}", player.getUsername(), serverId); var server = registeredServers.get(serverId); if (server == null) { logger.error("Could not find server with id '{}'", serverId); player.disconnect(Component.text("Сервер '%s' недоступен".formatted(serverId), NamedTextColor.RED)); return; } player.createConnectionRequest(server).fireAndForget(); }); } @Subscribe public void onPreShutdown(ProxyShutdownEvent event) { proxyControl.dispose(); } @Subscribe public void onChooseInitialServer(PlayerChooseInitialServerEvent event) { var player = event.getPlayer(); if (initialServerGroupId == null) { logger.error("Initial server group id is null"); player.disconnect(Component.text("Неправильно сконфигурировано лобби сервера")); return; } var serverId = kubik.pickServer(initialServerGroupId); if (serverId == null) { logger.error("Could not find server with groupId '{}'", initialServerGroupId); player.disconnect(Component.text("Нет доступных серверов для лобби")); return; } var server = registeredServers.get(serverId); if (server == null) { logger.error("Server '{}' is not registered for groupId '{}'", serverId, initialServerGroupId); player.disconnect(Component.text("Не зарегистрирован сервер для лобби")); return; } event.setInitialServer(server); } @Subscribe public void onTakenPluginMessage(PluginMessageEvent event) { var handler = pluginChannelHandlers.get(event.getIdentifier().getId()); if (handler != null) handler.accept(event); } private void registerPluginChannel(MinecraftChannelIdentifier channelId, Consumer handler) { pluginChannelHandlers.put(channelId.getId(), handler); proxyServer.getChannelRegistrar().register(KUBIK_TRANSFER_CHANNEL_ID); logger.info("Registered plugin channel '{}'", channelId.getId()); } @Override public void register(String id, String address, int port) { var server = registeredServers.computeIfAbsent(id, _ -> proxyServer.createRawRegisteredServer(new ServerInfo( id, InetSocketAddress.createUnresolved(address, port) ))); logger.info("Registered server '{}'(address={} port={})", id, address, port); } @Override public void unregister(String id) { var server = registeredServers.remove(id); logger.info("Unregistered server '{}'", id); if (server == null) return; //TODO } }