From d455e0c2a5c619dc2ab16c0e34cea96531f6e109 Mon Sep 17 00:00:00 2001 From: RobotHanzo <36107150+RobotHanzo@users.noreply.github.com> Date: Wed, 21 Jan 2026 01:02:38 +0800 Subject: [PATCH 1/5] feat: Support runtime server addition --- velocity/build.gradle.kts | 27 ++-- .../forcepack/velocity/ForcePackVelocity.java | 131 +++++++++++------- .../listener/ServerRegistrationListener.java | 55 ++++++++ 3 files changed, 152 insertions(+), 61 deletions(-) create mode 100644 velocity/src/main/java/com/convallyria/forcepack/velocity/listener/ServerRegistrationListener.java diff --git a/velocity/build.gradle.kts b/velocity/build.gradle.kts index 4e86c68..986bca0 100644 --- a/velocity/build.gradle.kts +++ b/velocity/build.gradle.kts @@ -22,13 +22,24 @@ dependencies { } } -tasks.shadowJar { - minimize { - exclude(project(":webserver")) +tasks{ + compileJava { + options.release.set(17) + } + + java { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + + shadowJar { + minimize { + exclude(project(":webserver")) + } + mergeServiceFiles() + relocate("io.leangen.geantyref", "forcepack.libs.geantyref") + relocate("org.bstats", "com.convallyria.forcepack.velocity.libs.bstats") + relocate("org.glassfish.jaxb", "com.convallyria.forcepack.libs.jaxb") + relocate("org.objectweb.asm", "com.convallyria.forcepack.libs.asm") } - mergeServiceFiles() - relocate("io.leangen.geantyref", "forcepack.libs.geantyref") - relocate("org.bstats", "com.convallyria.forcepack.velocity.libs.bstats") - relocate("org.glassfish.jaxb", "com.convallyria.forcepack.libs.jaxb") - relocate("org.objectweb.asm", "com.convallyria.forcepack.libs.asm") } diff --git a/velocity/src/main/java/com/convallyria/forcepack/velocity/ForcePackVelocity.java b/velocity/src/main/java/com/convallyria/forcepack/velocity/ForcePackVelocity.java index f7914cf..e85b25e 100644 --- a/velocity/src/main/java/com/convallyria/forcepack/velocity/ForcePackVelocity.java +++ b/velocity/src/main/java/com/convallyria/forcepack/velocity/ForcePackVelocity.java @@ -13,6 +13,7 @@ import com.convallyria.forcepack.velocity.config.VelocityConfig; import com.convallyria.forcepack.velocity.handler.PackHandler; import com.convallyria.forcepack.velocity.listener.ResourcePackListener; +import com.convallyria.forcepack.velocity.listener.ServerRegistrationListener; import com.convallyria.forcepack.velocity.resourcepack.VelocityResourcePack; import com.convallyria.forcepack.velocity.schedule.VelocityScheduler; import com.convallyria.forcepack.webserver.ForcePackWebServer; @@ -53,6 +54,7 @@ import java.util.Set; import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.stream.Collectors; @@ -162,6 +164,7 @@ public void reloadConfig() { private void registerListeners() { final EventManager eventManager = server.getEventManager(); eventManager.register(this, new ResourcePackListener(this)); + eventManager.register(this, new ServerRegistrationListener(this)); if (!getConfig().getBoolean("disable-commands-until-loaded", false)) return; eventManager.register(this, CommandExecuteEvent.class, event -> { @@ -214,17 +217,7 @@ private void addResourcePacks(@Nullable Player player, String rootName) { for (String name : root.getKeys()) { log("Checking %s - %s", typeName, name); final VelocityConfig serverConfig = root.getConfig(name); - final Map configs = new HashMap<>(); - // Add the default fallback - configs.put("default", serverConfig.getConfig("resourcepack")); - final VelocityConfig versionConfig = serverConfig.getConfig("version"); - if (versionConfig != null) { - log("Detected versioned resource packs for %s", name); - for (String versionId : versionConfig.getKeys()) { - configs.put(versionId, versionConfig.getConfig(versionId).getConfig("resourcepack")); - log("Added version config %s for %s", versionId, name); - } - } + final Map configs = getPackConfigs(serverConfig, name); configs.forEach((id, config) -> { if (config == null) { @@ -237,7 +230,68 @@ private void addResourcePacks(@Nullable Player player, String rootName) { } } - private void registerResourcePack(VelocityConfig rootServerConfig, VelocityConfig resourcePack, String id, String name, String typeName, boolean groups, boolean verifyPacks, @Nullable Player player) { + public Map getPackConfigs(VelocityConfig serverConfig, String name) { + final Map configs = new HashMap<>(); + // Add the default fallback + configs.put("default", serverConfig.getConfig("resourcepack")); + final VelocityConfig versionConfig = serverConfig.getConfig("version"); + if (versionConfig != null) { + log("Detected versioned resource packs for %s", name); + for (String versionId : versionConfig.getKeys()) { + configs.put(versionId, versionConfig.getConfig(versionId).getConfig("resourcepack")); + log("Added version config %s for %s", versionId, name); + } + } + return configs; + } + + public void registerResourcePack(VelocityConfig rootServerConfig, VelocityConfig resourcePack, String id, String name, String typeName, boolean groups, boolean verifyPacks, @Nullable Player player) { + processResourcePackConfig(resourcePack, id, name, (url, hash) -> { + this.handleRegister(rootServerConfig, resourcePack, name, id, typeName, url, hash, groups, verifyPacks, player); + }); + } + + private void handleRegister(VelocityConfig rootServerConfig, VelocityConfig resourcePack, String name, String id, String typeName, String url, @Nullable String hash, boolean groups, boolean verifyPacks, @Nullable Player player) { + if (groups) { + final boolean exact = rootServerConfig.getBoolean("exact-match"); + for (String serverName : rootServerConfig.getStringList("servers")) { + for (RegisteredServer registeredServer : server.getAllServers()) { + final String serverInfoName = registeredServer.getServerInfo().getName(); + final boolean matches = exact ? + serverInfoName.equals(serverName) : + serverInfoName.contains(serverName); + if (!matches) continue; + + VelocityResourcePack pack = createResourcePack(resourcePack, name, id, typeName, url, hash, verifyPacks, serverInfoName, name, player); + if (pack != null) { + resourcePacks.add(pack); + log("Added resource pack for server %s (%s)", serverInfoName, pack.getUUID().toString()); + } + } + } + } else { + VelocityResourcePack pack = createResourcePack(resourcePack, name, id, typeName, url, hash, verifyPacks, name, null, player); + if (pack != null) { + resourcePacks.add(pack); + } + } + } + + public void registerResourcePackForServer(VelocityConfig resourcePack, String id, String groupName, String typeName, boolean verifyPacks, String targetServerName, @Nullable Player player) { + processResourcePackConfig(resourcePack, id, groupName, (url, hash) -> { + this.handleRegisterForServer(resourcePack, groupName, id, typeName, url, hash, verifyPacks, targetServerName, player); + }); + } + + private void handleRegisterForServer(VelocityConfig resourcePack, String name, String id, String typeName, String url, @Nullable String hash, boolean verifyPacks, String targetServerName, @Nullable Player player) { + VelocityResourcePack pack = createResourcePack(resourcePack, name, id, typeName, url, hash, verifyPacks, targetServerName, name, player); + if (pack != null) { + resourcePacks.add(pack); + log("Added resource pack for server %s (%s)", targetServerName, pack.getUUID().toString()); + } + } + + private void processResourcePackConfig(VelocityConfig resourcePack, String id, String name, BiConsumer action) { List urls = resourcePack.getStringList("urls"); if (urls.isEmpty()) { urls = List.of(resourcePack.getString("url", "")); @@ -257,11 +311,12 @@ private void registerResourcePack(VelocityConfig rootServerConfig, VelocityConfi for (int i = 0; i < urls.size(); i++) { final String url = urls.get(i); final String hash = i >= hashes.size() ? null : hashes.get(i); - this.handleRegister(rootServerConfig, resourcePack, name, id, typeName, url, hash, groups, verifyPacks, player); + action.accept(url, hash); } } - private void handleRegister(VelocityConfig rootServerConfig, VelocityConfig resourcePack, String name, String id, String typeName, String url, @Nullable String hash, boolean groups, boolean verifyPacks, @Nullable Player player) { + @Nullable + private VelocityResourcePack createResourcePack(VelocityConfig resourcePack, String name, String id, String typeName, String url, @Nullable String hash, boolean verifyPacks, String targetServerName, @Nullable String groupName, @Nullable Player player) { final ConsoleCommandSource consoleSender = this.getServer().getConsoleCommandSource(); if (url.isEmpty()) { logger.error("No URL found for {}. Did you set up the config correctly?", name); @@ -310,7 +365,7 @@ private void handleRegister(VelocityConfig rootServerConfig, VelocityConfig reso this.getLogger().error("Your config hash returned: {}", data.getConfigHash()); this.getLogger().error("Please provide a correct SHA-1 hash!"); this.getLogger().error("-----------------------------------------------"); - return; + return null; } else { Component hashMsg = Component.text("Hash verification complete for " + typeName + " " + name + " (" + id + ").").color(NamedTextColor.GREEN); consoleSender.sendMessage(hashMsg); @@ -326,23 +381,7 @@ private void handleRegister(VelocityConfig rootServerConfig, VelocityConfig reso version = getVersionFromId(id); } catch (IllegalArgumentException ignored) {} - if (groups) { - final boolean exact = rootServerConfig.getBoolean("exact-match"); - for (String serverName : rootServerConfig.getStringList("servers")) { - for (RegisteredServer registeredServer : server.getAllServers()) { - final String serverInfoName = registeredServer.getServerInfo().getName(); - final boolean matches = exact ? - serverInfoName.equals(serverName) : - serverInfoName.contains(serverName); - if (!matches) continue; - final VelocityResourcePack pack = new VelocityResourcePack(this, serverInfoName, url, hash, sizeInMB.get(), name, version); - resourcePacks.add(pack); - log("Added resource pack for server %s (%s)", serverInfoName, pack.getUUID().toString()); - } - } - } else { - resourcePacks.add(new VelocityResourcePack(this, name, url, hash, sizeInMB.get(), null, version)); - } + return new VelocityResourcePack(this, targetServerName, url, hash, sizeInMB.get(), groupName, version); } private void checkUnload() { @@ -395,27 +434,8 @@ private void checkGlobal() { } configs.forEach((id, config) -> { - List urls = config.getStringList("urls"); - if (urls.isEmpty()) { - urls = List.of(config.getString("url", "")); - } - - List hashes = config.getStringList("hashes"); - if (hashes.isEmpty()) { - hashes = List.of(config.getString("hash", "")); - } - - final boolean generateHash = config.getBoolean("generate-hash", false); - if (!generateHash && urls.size() != hashes.size()) { - getLogger().error("[global-pack] There are not the same amount of URLs and hashes! Please provide a hash for every resource pack URL! ({})", id); - getLogger().error("Hint: Enabling generate-hash will auto-generate missing hashes"); - } - - for (int i = 0; i < urls.size(); i++) { - final String url = urls.get(i); - final String hash = i >= hashes.size() ? null : hashes.get(i); - this.registerGlobalResourcePack(config, id, url, hash); - } + processResourcePackConfig(config, id == null ? null : id.toString(), "global-pack", + (url, hash) -> this.registerGlobalResourcePack(config, id, url, hash)); }); } @@ -592,4 +612,9 @@ public MiniMessage getMiniMessage() { public void log(String info, Object... format) { if (this.getConfig().getBoolean("debug")) this.getLogger().info(String.format(info, format)); } + + public void addResourcePack(String serverName, VelocityResourcePack pack) { + resourcePacks.add(pack); + log("Added resource pack for server %s (%s)", serverName, pack.getUUID().toString()); + } } diff --git a/velocity/src/main/java/com/convallyria/forcepack/velocity/listener/ServerRegistrationListener.java b/velocity/src/main/java/com/convallyria/forcepack/velocity/listener/ServerRegistrationListener.java new file mode 100644 index 0000000..3610ec7 --- /dev/null +++ b/velocity/src/main/java/com/convallyria/forcepack/velocity/listener/ServerRegistrationListener.java @@ -0,0 +1,55 @@ +package com.convallyria.forcepack.velocity.listener; + +import com.convallyria.forcepack.velocity.ForcePackVelocity; +import com.convallyria.forcepack.velocity.config.VelocityConfig; +import com.velocitypowered.api.event.Subscribe; +import com.velocitypowered.api.event.proxy.server.ServerRegisteredEvent; +import com.velocitypowered.api.proxy.server.RegisteredServer; + +import java.util.List; +import java.util.Map; + +public class ServerRegistrationListener { + + private final ForcePackVelocity plugin; + + public ServerRegistrationListener(ForcePackVelocity plugin) { + this.plugin = plugin; + } + + @Subscribe + public void onServerRegistered(ServerRegisteredEvent event) { + RegisteredServer registeredServer = event.registeredServer(); + String serverName = registeredServer.getServerInfo().getName(); + VelocityConfig groups = plugin.getConfig().getConfig("groups"); + + if (groups == null) return; + + // Check if we already have packs for this server + boolean hasPack = plugin.getResourcePacks().stream() + .anyMatch(pack -> pack.getServer().equals(serverName)); + + if (hasPack) return; + + for (String groupName : groups.getKeys()) { + VelocityConfig groupConfig = groups.getConfig(groupName); + List servers = groupConfig.getStringList("servers"); + boolean exact = groupConfig.getBoolean("exact-match"); + + boolean matches = exact ? + servers.contains(serverName) : + servers.stream().anyMatch(serverName::contains); + + if (matches) { + plugin.log("New server %s matches group %s, adding resource packs...", serverName, groupName); + + final Map configs = plugin.getPackConfigs(groupConfig, groupName); + + configs.forEach((id, config) -> { + if (config == null) return; + plugin.registerResourcePackForServer(config, id, groupName, "group", plugin.getConfig().getBoolean("verify-resource-packs"), serverName, null); + }); + } + } + } +} From ceecc42ef6a61a0d8ceca0af4c91fdaf809358f7 Mon Sep 17 00:00:00 2001 From: RobotHanzo <36107150+RobotHanzo@users.noreply.github.com> Date: Wed, 21 Jan 2026 02:11:27 +0800 Subject: [PATCH 2/5] Update velocity/build.gradle.kts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- velocity/build.gradle.kts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/velocity/build.gradle.kts b/velocity/build.gradle.kts index 986bca0..3d22964 100644 --- a/velocity/build.gradle.kts +++ b/velocity/build.gradle.kts @@ -27,11 +27,6 @@ tasks{ options.release.set(17) } - java { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 - } - shadowJar { minimize { exclude(project(":webserver")) From cbd1bbdfd0c027e999dae7e2e2f18b4efaf382b4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 31 Jan 2026 20:30:14 +0000 Subject: [PATCH 3/5] Initial plan From 1e94b0eb688cfc21101df6934fd356da30ad31b8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 31 Jan 2026 20:33:42 +0000 Subject: [PATCH 4/5] Add support for servers configuration in ServerRegistrationListener Co-authored-by: RobotHanzo <36107150+RobotHanzo@users.noreply.github.com> --- .../listener/ServerRegistrationListener.java | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/velocity/src/main/java/com/convallyria/forcepack/velocity/listener/ServerRegistrationListener.java b/velocity/src/main/java/com/convallyria/forcepack/velocity/listener/ServerRegistrationListener.java index 3610ec7..2c5d036 100644 --- a/velocity/src/main/java/com/convallyria/forcepack/velocity/listener/ServerRegistrationListener.java +++ b/velocity/src/main/java/com/convallyria/forcepack/velocity/listener/ServerRegistrationListener.java @@ -21,9 +21,6 @@ public ServerRegistrationListener(ForcePackVelocity plugin) { public void onServerRegistered(ServerRegisteredEvent event) { RegisteredServer registeredServer = event.registeredServer(); String serverName = registeredServer.getServerInfo().getName(); - VelocityConfig groups = plugin.getConfig().getConfig("groups"); - - if (groups == null) return; // Check if we already have packs for this server boolean hasPack = plugin.getResourcePacks().stream() @@ -31,6 +28,27 @@ public void onServerRegistered(ServerRegisteredEvent event) { if (hasPack) return; + // Check the "servers" configuration first + VelocityConfig servers = plugin.getConfig().getConfig("servers"); + if (servers != null) { + VelocityConfig serverConfig = servers.getConfig(serverName); + if (serverConfig != null) { + plugin.log("New server %s matches servers configuration, adding resource packs...", serverName); + + final Map configs = plugin.getPackConfigs(serverConfig, serverName); + + configs.forEach((id, config) -> { + if (config == null) return; + plugin.registerResourcePackForServer(config, id, serverName, "server", plugin.getConfig().getBoolean("verify-resource-packs"), serverName, null); + }); + return; + } + } + + // Check the "groups" configuration + VelocityConfig groups = plugin.getConfig().getConfig("groups"); + if (groups == null) return; + for (String groupName : groups.getKeys()) { VelocityConfig groupConfig = groups.getConfig(groupName); List servers = groupConfig.getStringList("servers"); From 0c44b63da5c02c23522d610600e79bbd572b81ee Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 31 Jan 2026 20:35:58 +0000 Subject: [PATCH 5/5] Add clarifying comment for duplicate serverName parameter Co-authored-by: RobotHanzo <36107150+RobotHanzo@users.noreply.github.com> --- .../forcepack/velocity/listener/ServerRegistrationListener.java | 1 + 1 file changed, 1 insertion(+) diff --git a/velocity/src/main/java/com/convallyria/forcepack/velocity/listener/ServerRegistrationListener.java b/velocity/src/main/java/com/convallyria/forcepack/velocity/listener/ServerRegistrationListener.java index 2c5d036..c55e573 100644 --- a/velocity/src/main/java/com/convallyria/forcepack/velocity/listener/ServerRegistrationListener.java +++ b/velocity/src/main/java/com/convallyria/forcepack/velocity/listener/ServerRegistrationListener.java @@ -39,6 +39,7 @@ public void onServerRegistered(ServerRegisteredEvent event) { configs.forEach((id, config) -> { if (config == null) return; + // serverName is used both as the config name and target server name plugin.registerResourcePackForServer(config, id, serverName, "server", plugin.getConfig().getBoolean("verify-resource-packs"), serverName, null); }); return;