diff --git a/divinemc-api/build.gradle.kts.patch b/divinemc-api/build.gradle.kts.patch index c02d0ae..44b2f40 100644 --- a/divinemc-api/build.gradle.kts.patch +++ b/divinemc-api/build.gradle.kts.patch @@ -86,7 +86,7 @@ } } } -@@ -162,6 +_,15 @@ +@@ -162,6 +_,16 @@ } } @@ -96,6 +96,7 @@ + compilerArgs.add("-Xlint:-module") + compilerArgs.add("-Xlint:-removal") + compilerArgs.add("-Xlint:-dep-ann") ++ compilerArgs.add("--add-modules=jdk.incubator.vector") +} +// DivineMC end - Hide unnecessary compilation warnings + diff --git a/divinemc-api/paper-patches/files/src/main/java/org/bukkit/map/MapPalette.java.patch b/divinemc-api/paper-patches/files/src/main/java/org/bukkit/map/MapPalette.java.patch new file mode 100644 index 0000000..fe3a0f4 --- /dev/null +++ b/divinemc-api/paper-patches/files/src/main/java/org/bukkit/map/MapPalette.java.patch @@ -0,0 +1,29 @@ +--- a/src/main/java/org/bukkit/map/MapPalette.java ++++ b/src/main/java/org/bukkit/map/MapPalette.java +@@ -35,7 +_,7 @@ + } + + @NotNull +- static final Color[] colors = { ++ public static final Color[] colors = { // DivineMC - Pufferfish SIMD - make public + // Start generate - MapPalette#colors + // @GeneratedFrom 1.21.5 + new Color(0x00000000, true), +@@ -395,9 +_,15 @@ + temp.getRGB(0, 0, temp.getWidth(), temp.getHeight(), pixels, 0, temp.getWidth()); + + byte[] result = new byte[temp.getWidth() * temp.getHeight()]; +- for (int i = 0; i < pixels.length; i++) { +- result[i] = matchColor(new Color(pixels[i], true)); ++ // DivineMC start - Pufferfish SIMD ++ if (gg.pufferfish.pufferfish.simd.SIMDDetection.isEnabled) { ++ gg.pufferfish.pufferfish.simd.VectorMapPalette.matchColorVectorized(pixels, result); ++ } else { ++ for (int i = 0; i < pixels.length; i++) { ++ result[i] = matchColor(new Color(pixels[i], true)); ++ } + } ++ // DivineMC end - Pufferfish SIMD + return result; + } + diff --git a/divinemc-api/src/main/java/gg/pufferfish/pufferfish/simd/SIMDChecker.java b/divinemc-api/src/main/java/gg/pufferfish/pufferfish/simd/SIMDChecker.java new file mode 100644 index 0000000..9c428a7 --- /dev/null +++ b/divinemc-api/src/main/java/gg/pufferfish/pufferfish/simd/SIMDChecker.java @@ -0,0 +1,33 @@ +package gg.pufferfish.pufferfish.simd; + +import org.slf4j.Logger; +import jdk.incubator.vector.FloatVector; +import jdk.incubator.vector.IntVector; +import jdk.incubator.vector.VectorSpecies; + +@Deprecated +public class SIMDChecker { + public static boolean canEnable(Logger logger) { + try { + if (SIMDDetection.getJavaVersion() < 17) { + return false; + } else { + SIMDDetection.testRun = true; + + VectorSpecies ISPEC = IntVector.SPECIES_PREFERRED; + VectorSpecies FSPEC = FloatVector.SPECIES_PREFERRED; + + logger.info("Max SIMD vector size on this system is {} bits (int)", ISPEC.vectorBitSize()); + logger.info("Max SIMD vector size on this system is {} bits (float)", FSPEC.vectorBitSize()); + + if (ISPEC.elementSize() < 2 || FSPEC.elementSize() < 2) { + logger.warn("SIMD is not properly supported on this system!"); + return false; + } + + return true; + } + } catch (NoClassDefFoundError | Exception ignored) {} // Basically, we don't do anything. This lets us detect if it's not functional and disable it. + return false; + } +} diff --git a/divinemc-api/src/main/java/gg/pufferfish/pufferfish/simd/SIMDDetection.java b/divinemc-api/src/main/java/gg/pufferfish/pufferfish/simd/SIMDDetection.java new file mode 100644 index 0000000..026617f --- /dev/null +++ b/divinemc-api/src/main/java/gg/pufferfish/pufferfish/simd/SIMDDetection.java @@ -0,0 +1,33 @@ +package gg.pufferfish.pufferfish.simd; + +import org.slf4j.Logger; + +@Deprecated +public class SIMDDetection { + public static boolean isEnabled = false; + public static boolean versionLimited = false; + public static boolean testRun = false; + + @Deprecated + public static boolean canEnable(Logger logger) { + try { + return SIMDChecker.canEnable(logger); + } catch (NoClassDefFoundError | Exception ignored) { + return false; + } + } + + @Deprecated + public static int getJavaVersion() { + // https://stackoverflow.com/a/2591122 + String version = System.getProperty("java.version"); + if(version.startsWith("1.")) { + version = version.substring(2, 3); + } else { + int dot = version.indexOf("."); + if(dot != -1) { version = version.substring(0, dot); } + } + version = version.split("-")[0]; + return Integer.parseInt(version); + } +} diff --git a/divinemc-api/src/main/java/gg/pufferfish/pufferfish/simd/VectorMapPalette.java b/divinemc-api/src/main/java/gg/pufferfish/pufferfish/simd/VectorMapPalette.java new file mode 100644 index 0000000..297f985 --- /dev/null +++ b/divinemc-api/src/main/java/gg/pufferfish/pufferfish/simd/VectorMapPalette.java @@ -0,0 +1,82 @@ +package gg.pufferfish.pufferfish.simd; + +import java.awt.Color; +import jdk.incubator.vector.FloatVector; +import jdk.incubator.vector.IntVector; +import jdk.incubator.vector.VectorMask; +import jdk.incubator.vector.VectorSpecies; +import org.bukkit.map.MapPalette; + +@Deprecated +public class VectorMapPalette { + private static final VectorSpecies I_SPEC = IntVector.SPECIES_PREFERRED; + private static final VectorSpecies F_SPEC = FloatVector.SPECIES_PREFERRED; + + @Deprecated + public static void matchColorVectorized(int[] in, byte[] out) { + int speciesLength = I_SPEC.length(); + int i; + for (i = 0; i < in.length - speciesLength; i += speciesLength) { + float[] redsArr = new float[speciesLength]; + float[] bluesArr = new float[speciesLength]; + float[] greensArr = new float[speciesLength]; + int[] alphasArr = new int[speciesLength]; + + for (int j = 0; j < speciesLength; j++) { + alphasArr[j] = (in[i + j] >> 24) & 0xFF; + redsArr[j] = (in[i + j] >> 16) & 0xFF; + greensArr[j] = (in[i + j] >> 8) & 0xFF; + bluesArr[j] = (in[i + j] >> 0) & 0xFF; + } + + IntVector alphas = IntVector.fromArray(I_SPEC, alphasArr, 0); + FloatVector reds = FloatVector.fromArray(F_SPEC, redsArr, 0); + FloatVector greens = FloatVector.fromArray(F_SPEC, greensArr, 0); + FloatVector blues = FloatVector.fromArray(F_SPEC, bluesArr, 0); + IntVector resultIndex = IntVector.zero(I_SPEC); + VectorMask modificationMask = VectorMask.fromLong(I_SPEC, 0xffffffff); + + modificationMask = modificationMask.and(alphas.lt(128).not()); + FloatVector bestDistances = FloatVector.broadcast(F_SPEC, Float.MAX_VALUE); + + for (int c = 4; c < MapPalette.colors.length; c++) { + // We're using 32-bit floats here because it's 2x faster and nobody will know the difference. + // For correctness, the original algorithm uses 64-bit floats instead. Completely unnecessary. + FloatVector compReds = FloatVector.broadcast(F_SPEC, MapPalette.colors[c].getRed()); + FloatVector compGreens = FloatVector.broadcast(F_SPEC, MapPalette.colors[c].getGreen()); + FloatVector compBlues = FloatVector.broadcast(F_SPEC, MapPalette.colors[c].getBlue()); + + FloatVector rMean = reds.add(compReds).div(2.0f); + FloatVector rDiff = reds.sub(compReds); + FloatVector gDiff = greens.sub(compGreens); + FloatVector bDiff = blues.sub(compBlues); + + FloatVector weightR = rMean.div(256.0f).add(2); + FloatVector weightG = FloatVector.broadcast(F_SPEC, 4.0f); + FloatVector weightB = FloatVector.broadcast(F_SPEC, 255.0f).sub(rMean).div(256.0f).add(2.0f); + + FloatVector distance = weightR.mul(rDiff).mul(rDiff).add(weightG.mul(gDiff).mul(gDiff)).add(weightB.mul(bDiff).mul(bDiff)); + + // Now we compare to the best distance we've found. + // This mask contains a "1" if better, and a "0" otherwise. + VectorMask bestDistanceMask = distance.lt(bestDistances); + bestDistances = bestDistances.blend(distance, bestDistanceMask); // Update the best distances + + // Update the result array + // We also AND with the modification mask because we don't want to interfere if the alpha value isn't large enough. + resultIndex = resultIndex.blend(c, bestDistanceMask.cast(I_SPEC).and(modificationMask)); // Update the results + } + + for (int j = 0; j < speciesLength; j++) { + int index = resultIndex.lane(j); + out[i + j] = (byte) (index < 128 ? index : -129 + (index - 127)); + } + } + + // For the final ones, fall back to the regular method + for (; i < in.length; i++) { + //noinspection removal + out[i] = MapPalette.matchColor(new Color(in[i], true)); + } + } +} diff --git a/divinemc-server/build.gradle.kts.patch b/divinemc-server/build.gradle.kts.patch index 442e701..8524bef 100644 --- a/divinemc-server/build.gradle.kts.patch +++ b/divinemc-server/build.gradle.kts.patch @@ -136,7 +136,7 @@ implementation("net.neoforged:srgutils:1.0.9") // Mappings handling implementation("net.neoforged:AutoRenamingTool:2.0.3") // Remap plugins -@@ -224,30 +_,41 @@ +@@ -224,30 +_,42 @@ implementation("me.lucko:spark-paper:1.10.133-20250413.112336-1") } @@ -146,6 +146,7 @@ + compilerArgs.add("-Xlint:-module") + compilerArgs.add("-Xlint:-removal") + compilerArgs.add("-Xlint:-dep-ann") ++ compilerArgs.add("--add-modules=jdk.incubator.vector") +} +// DivineMC end - Hide irrelevant compilation warnings + diff --git a/divinemc-server/minecraft-patches/features/0002-Configuration.patch b/divinemc-server/minecraft-patches/features/0002-Configuration.patch index 3c3976c..0194fff 100644 --- a/divinemc-server/minecraft-patches/features/0002-Configuration.patch +++ b/divinemc-server/minecraft-patches/features/0002-Configuration.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Configuration diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java -index 6a296adcd9d5289dd86840fdc58dce3accbe9ce5..90c78b71fc456e9369af7afb62beb7de7303eaf1 100644 +index debea77d5777b90c6b17b225e27e6b3c72370175..1a8c125a58f7363dbff4f11f5e34537ca1fbd605 100644 --- a/net/minecraft/server/dedicated/DedicatedServer.java +++ b/net/minecraft/server/dedicated/DedicatedServer.java @@ -193,6 +193,15 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface @@ -23,7 +23,7 @@ index 6a296adcd9d5289dd86840fdc58dce3accbe9ce5..90c78b71fc456e9369af7afb62beb7de + // DivineMC end - Configuration com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now - this.setPvpAllowed(properties.pvp); + // DivineMC start - Pufferfish SIMD diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java index bbadbdfd643e61a6a3e55df7dd7a646ea1a9744b..38ddadf551c039202c68c44d740f23a08b58d003 100644 --- a/net/minecraft/world/level/Level.java diff --git a/divinemc-server/minecraft-patches/features/0003-Completely-remove-Mojang-profiler.patch b/divinemc-server/minecraft-patches/features/0003-Completely-remove-Mojang-profiler.patch index 426af29..f4fd526 100644 --- a/divinemc-server/minecraft-patches/features/0003-Completely-remove-Mojang-profiler.patch +++ b/divinemc-server/minecraft-patches/features/0003-Completely-remove-Mojang-profiler.patch @@ -1069,10 +1069,10 @@ index a3192400b37274620977e5a40d4283bfec3ab9b3..97fb981d89b1a831e6e94708f44d0983 + // DivineMC end - Completely remove Mojang profiler } diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java -index 90c78b71fc456e9369af7afb62beb7de7303eaf1..0033b1acec1adfaaf8e6d9892fd9a971eb40b76a 100644 +index 1a8c125a58f7363dbff4f11f5e34537ca1fbd605..116970622a4e7cc9c7c8333cdb18da71381abcff 100644 --- a/net/minecraft/server/dedicated/DedicatedServer.java +++ b/net/minecraft/server/dedicated/DedicatedServer.java -@@ -798,12 +798,6 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface +@@ -818,12 +818,6 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface return this.settings.getProperties().serverResourcePackInfo; } diff --git a/divinemc-server/minecraft-patches/features/0025-Implement-NoChatReports.patch b/divinemc-server/minecraft-patches/features/0025-Implement-NoChatReports.patch index 6680e8e..8684ee8 100644 --- a/divinemc-server/minecraft-patches/features/0025-Implement-NoChatReports.patch +++ b/divinemc-server/minecraft-patches/features/0025-Implement-NoChatReports.patch @@ -206,10 +206,10 @@ index 094d1821d298fc228270b2d6cf0445949434f3e2..8f7e3e5f1d3a87ba3528c9dd61e063ec private static final String PREFIX = "data:image/png;base64,"; public static final Codec CODEC = Codec.STRING.comapFlatMap(string -> { diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java -index 0033b1acec1adfaaf8e6d9892fd9a971eb40b76a..25460607359b7f172842657f2693ce3bf6151750 100644 +index 116970622a4e7cc9c7c8333cdb18da71381abcff..3f9b26de801b2d8e85c56d219ca7bd61c41b3f9d 100644 --- a/net/minecraft/server/dedicated/DedicatedServer.java +++ b/net/minecraft/server/dedicated/DedicatedServer.java -@@ -611,6 +611,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface +@@ -631,6 +631,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface @Override public boolean enforceSecureProfile() { diff --git a/divinemc-server/minecraft-patches/features/0043-Parallel-world-ticking.patch b/divinemc-server/minecraft-patches/features/0043-Parallel-world-ticking.patch index d12e573..9a2ae47 100644 --- a/divinemc-server/minecraft-patches/features/0043-Parallel-world-ticking.patch +++ b/divinemc-server/minecraft-patches/features/0043-Parallel-world-ticking.patch @@ -210,12 +210,12 @@ index 172c69d577e53354fd4f37702d395e8f61754336..ef2cf6d9ca57266bb0466ca1aa5d2066 } // CraftBukkit end diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java -index 25460607359b7f172842657f2693ce3bf6151750..5287bf52df85ebe32334f90a0d66e9befa34c36b 100644 +index 3f9b26de801b2d8e85c56d219ca7bd61c41b3f9d..8fa8cd1a06c86c8424d43b588ff13a917865e80e 100644 --- a/net/minecraft/server/dedicated/DedicatedServer.java +++ b/net/minecraft/server/dedicated/DedicatedServer.java -@@ -204,6 +204,13 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface - // DivineMC end - Configuration - com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now +@@ -224,6 +224,13 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface + } + // DivineMC end - Pufferfish SIMD + // DivineMC start - Parallel world ticking + if (org.bxteam.divinemc.DivineConfig.enableParallelWorldTicking) { @@ -404,7 +404,7 @@ index 338df3c49e19b7ff3f54ecf93a980d4573b142d7..0b8301ea5e90565e673e38e51f7ed3c8 serverPlayer.connection = player.connection; serverPlayer.restoreFrom(player, keepInventory); diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index b98010d6d3d369c680ccc8f15da9574e4f6a139c..7326796c98761db2d00cf9a7e92bbc82bc6510fe 100644 +index 255e48ac3c05dec9b861fee0c8ec8f478abfa999..07b8fd62a2a3bbd4195ad6550748802a70f75bcb 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java @@ -3248,14 +3248,34 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch new file mode 100644 index 0000000..93ab0b0 --- /dev/null +++ b/divinemc-server/minecraft-patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch @@ -0,0 +1,29 @@ +--- a/net/minecraft/server/dedicated/DedicatedServer.java ++++ b/net/minecraft/server/dedicated/DedicatedServer.java +@@ -195,6 +_,26 @@ + // Purpur end - Purpur config files + com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now + ++ // DivineMC start - Pufferfish SIMD ++ try { ++ gg.pufferfish.pufferfish.simd.SIMDDetection.isEnabled = gg.pufferfish.pufferfish.simd.SIMDDetection.canEnable(LOGGER); ++ gg.pufferfish.pufferfish.simd.SIMDDetection.versionLimited = gg.pufferfish.pufferfish.simd.SIMDDetection.getJavaVersion() < 17 || gg.pufferfish.pufferfish.simd.SIMDDetection.getJavaVersion() > 21; ++ } catch (NoClassDefFoundError | Exception ignored) { ++ ignored.printStackTrace(); ++ } ++ ++ if (gg.pufferfish.pufferfish.simd.SIMDDetection.isEnabled) { ++ LOGGER.info("SIMD operations detected as functional. Will replace some operations with faster versions."); ++ } else if (gg.pufferfish.pufferfish.simd.SIMDDetection.versionLimited) { ++ LOGGER.warn("Will not enable SIMD! These optimizations are only safely supported on Java 17 and higher."); ++ } else { ++ LOGGER.warn("SIMD operations are available for your server, but are not configured!"); ++ LOGGER.warn("To enable additional optimizations, add \"--add-modules=jdk.incubator.vector\" to your startup flags, BEFORE the \"-jar\"."); ++ LOGGER.warn("If you have already added this flag, then SIMD operations are not supported on your JVM or CPU."); ++ LOGGER.warn("Debug: Java: {}, test run: {}", System.getProperty("java.version"), gg.pufferfish.pufferfish.simd.SIMDDetection.testRun); ++ } ++ // DivineMC end - Pufferfish SIMD ++ + this.setPvpAllowed(properties.pvp); + this.setFlightAllowed(properties.allowFlight); + this.setMotd(properties.motd); diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/DivineConfig.java b/divinemc-server/src/main/java/org/bxteam/divinemc/DivineConfig.java index 2cbe505..c7bd453 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/DivineConfig.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/DivineConfig.java @@ -1,6 +1,7 @@ package org.bxteam.divinemc; import com.google.common.base.Throwables; +import gg.pufferfish.pufferfish.simd.SIMDDetection; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.EntityType;