diff --git a/WindSpigot-Server/pom.xml b/WindSpigot-Server/pom.xml
index 68bcfcf7..38626b83 100644
--- a/WindSpigot-Server/pom.xml
+++ b/WindSpigot-Server/pom.xml
@@ -155,13 +155,17 @@
3.21.0
-
-
-
- net.kyori
- adventure-key
- 4.10.1
-
+
+ net.kyori
+ adventure-key
+ 4.10.1
+
+
+
+ org.javassist
+ javassist
+ 3.29.2-GA
+
diff --git a/WindSpigot-Server/src/main/java/com/windpvp/windspigot/commons/PluginUtils.java b/WindSpigot-Server/src/main/java/com/windpvp/windspigot/commons/PluginUtils.java
index 30859f84..d33a04fa 100644
--- a/WindSpigot-Server/src/main/java/com/windpvp/windspigot/commons/PluginUtils.java
+++ b/WindSpigot-Server/src/main/java/com/windpvp/windspigot/commons/PluginUtils.java
@@ -1,13 +1,28 @@
package com.windpvp.windspigot.commons;
+
import org.bukkit.plugin.Plugin;
-/**
- * @author Elierrr
- */
public class PluginUtils {
+
public static int getCitizensBuild(Plugin plugin) {
+ if (plugin == null || plugin.getDescription() == null) {
+ return 2396;
+ }
+ return parseCitizensBuild(plugin.getDescription().getVersion());
+ }
+
+ public static int parseCitizensBuild(String version) {
try {
- return Integer.parseInt(plugin.getDescription().getVersion().split("\\(build ")[1].replace(")", ""));
+ if (version == null) {
+ return 2396;
+ }
+ if (version.contains("(build ")) {
+ return Integer.parseInt(version.split("\\(build ")[1].replace(")", "").trim());
+ }
+ if (version.startsWith("2.0.25") || version.startsWith("2.0.26") || version.startsWith("2.0.27")) {
+ return 1000;
+ }
+ return 2396;
} catch (Throwable ignored) {
return 2396;
}
diff --git a/WindSpigot-Server/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/WindSpigot-Server/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index d96c817f..ba2eb89e 100644
--- a/WindSpigot-Server/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/WindSpigot-Server/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -169,6 +169,10 @@
import net.minecraft.server.WorldSettings;
import net.minecraft.server.WorldType;
import xyz.sculas.nacho.malware.AntiMalware;
+import javassist.ClassPool;
+import javassist.CtClass;
+import javassist.CtMethod;
+import javassist.LoaderClassPath;
public final class CraftServer implements Server {
private static final Player[] EMPTY_PLAYER_ARRAY = new Player[0];
@@ -371,19 +375,30 @@ public void loadPlugins() {
}
// Nacho end
- // Nacho start - Add notice for older Citizens versions
+ // WindSpigot start - GamingOP69 - Auto-patch older Citizens EmptyChannel for Netty 4.1 compatibility
else if (plugin.getDescription().getFullName().contains("Citizens")) {
if (PluginUtils.getCitizensBuild(plugin) < 2396) {
- logger.warning("Please update to Citizens 2.0.28 #7 or higher!\n"
- + "Previously, there was a fix for older versions, but that has been removed.\n"
- + "So, if you want Citizens to work, please update!\n"
- + "You can download the latest version with this link: "
- + "https://ci.citizensnpcs.co/job/Citizens2/\n"
- + "Sleeping for 10s so this message can be read.");
- Thread.sleep(10000);
+ try {
+ ClassPool pool = ClassPool.getDefault();
+ pool.insertClassPath(new LoaderClassPath(plugin.getClass().getClassLoader()));
+ pool.importPackage("io.netty.channel.ChannelMetadata");
+
+ CtClass emptyChannel = pool.get("net.citizensnpcs.nms.v1_8_R3.network.EmptyChannel");
+ if (emptyChannel.isFrozen()) {
+ emptyChannel.defrost();
+ }
+
+ CtMethod metaData = emptyChannel.getDeclaredMethods("metadata")[0];
+ metaData.setBody("{ return new ChannelMetadata(true); }");
+
+ emptyChannel.toClass(plugin.getClass().getClassLoader(), plugin.getClass().getProtectionDomain());
+ logger.info("Successfully patched Citizens EmptyChannel for Netty 4.1 compatibility!");
+ } catch (Throwable t) {
+ logger.warning("Could not automatically patch Citizens: " + t.getMessage());
+ }
}
}
- // Nacho end
+ // WindSpigot end - GamingOP69
plugin.getLogger().info(String.format("Loading %s", plugin.getDescription().getFullName()));
plugin.onLoad();
diff --git a/WindSpigot-Server/src/test/java/com/windpvp/windspigot/citizens/CitizensVersionDetectionTest.java b/WindSpigot-Server/src/test/java/com/windpvp/windspigot/citizens/CitizensVersionDetectionTest.java
new file mode 100644
index 00000000..31bfe815
--- /dev/null
+++ b/WindSpigot-Server/src/test/java/com/windpvp/windspigot/citizens/CitizensVersionDetectionTest.java
@@ -0,0 +1,38 @@
+package com.windpvp.windspigot.citizens;
+
+import com.windpvp.windspigot.commons.PluginUtils;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class CitizensVersionDetectionTest {
+
+ @Test
+ public void testOlderBuildDetected() {
+ int build = PluginUtils.parseCitizensBuild("2.0.25-SNAPSHOT (build 1770)");
+ Assert.assertEquals(1770, build);
+ Assert.assertTrue("Older build 1770 must be less than 2396", build < 2396);
+ }
+
+ @Test
+ public void testLegacyVersionWithoutBuildDetected() {
+ int build25 = PluginUtils.parseCitizensBuild("2.0.25");
+ Assert.assertTrue("2.0.25 must trigger older build detection", build25 < 2396);
+
+ int build26 = PluginUtils.parseCitizensBuild("2.0.26-SNAPSHOT");
+ Assert.assertTrue("2.0.26 must trigger older build detection", build26 < 2396);
+ }
+
+ @Test
+ public void testNewerBuildDetected() {
+ int build = PluginUtils.parseCitizensBuild("2.0.28-SNAPSHOT (build 2400)");
+ Assert.assertEquals(2400, build);
+ Assert.assertTrue("Newer build 2400 must be >= 2396", build >= 2396);
+ }
+
+ @Test
+ public void testFallbackOnNullOrUnknownVersion() {
+ Assert.assertEquals(2396, PluginUtils.parseCitizensBuild(null));
+ Assert.assertEquals(2396, PluginUtils.parseCitizensBuild("unknown-version"));
+ Assert.assertEquals(2396, PluginUtils.getCitizensBuild(null));
+ }
+}