From 4ac56284a834e25ec2f89db1db1bb28a05ef5b90 Mon Sep 17 00:00:00 2001 From: Pierre Maurice Schwang Date: Sun, 24 May 2026 10:45:51 +0200 Subject: [PATCH] fix: support new minecraft version format --- .gitignore | 3 +- .../plotsquared/bukkit/BukkitPlatform.java | 14 +- .../bukkit/generator/BukkitPlotGenerator.java | 10 +- .../bukkit/listener/ChunkListener.java | 122 +++------------- .../bukkit/listener/PlayerEventListener.java | 4 +- .../bukkit/listener/SingleWorldListener.java | 3 +- .../bukkit/player/BukkitPlayer.java | 3 +- .../plotsquared/bukkit/util/BukkitUtil.java | 12 +- .../com/plotsquared/core/PlotPlatform.java | 10 ++ .../com/plotsquared/core/plot/PlotArea.java | 5 +- .../core/util/MinecraftVersion.java | 132 ++++++++++++++++++ build.gradle.kts | 2 +- 12 files changed, 195 insertions(+), 125 deletions(-) create mode 100644 Core/src/main/java/com/plotsquared/core/util/MinecraftVersion.java diff --git a/.gitignore b/.gitignore index b2bc4a8dd0..d8ff1527e0 100644 --- a/.gitignore +++ b/.gitignore @@ -138,5 +138,4 @@ build/ .DS_Store # Ignore run folders -run-[0-9].[0-9][0-9]/ -run-[0-9].[0-9][0-9].[0-9]/ +run-*/ diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java index d60bbe3879..804d0376e2 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java @@ -100,6 +100,7 @@ import com.plotsquared.core.setup.SettingsNodesWrapper; import com.plotsquared.core.util.EventDispatcher; import com.plotsquared.core.util.FileUtils; +import com.plotsquared.core.util.MinecraftVersion; import com.plotsquared.core.util.PlatformWorldManager; import com.plotsquared.core.util.PlayerManager; import com.plotsquared.core.util.PremiumVerification; @@ -237,14 +238,19 @@ public final class BukkitPlatform extends JavaPlugin implements Listener, PlotPl return this.version; } + @Override + public MinecraftVersion minecraftVersion() { + return MinecraftVersion.current(); + } + @Override public int versionMinHeight() { - return serverVersion()[1] >= 18 ? -64 : 0; + return minecraftVersion().isNewerOrEqualThan(MinecraftVersion.CAVES_AND_CLIFFS_2) ? -64 : 0; } @Override public int versionMaxHeight() { - return serverVersion()[1] >= 18 ? 319 : 255; + return minecraftVersion().isNewerOrEqualThan(MinecraftVersion.CAVES_AND_CLIFFS_2) ? 319 : 255; } @Override @@ -364,14 +370,14 @@ public void onEnable() { if (Settings.Enabled_Components.EVENTS) { getServer().getPluginManager().registerEvents(injector().getInstance(PlayerEventListener.class), this); - if ((serverVersion()[1] == 20 && serverVersion()[2] >= 1) || serverVersion()[1] > 20) { + if (minecraftVersion().isNewerOrEqualThan(20, 1)) { getServer().getPluginManager().registerEvents(injector().getInstance(PlayerEventListener1201.class), this); } getServer().getPluginManager().registerEvents(injector().getInstance(BlockEventListener.class), this); if (Settings.HIGH_FREQUENCY_LISTENER) { getServer().getPluginManager().registerEvents(injector().getInstance(HighFreqBlockEventListener.class), this); } - if (serverVersion()[1] >= 17) { + if (minecraftVersion().isNewerOrEqualThan(MinecraftVersion.CAVES_AND_CLIFFS)) { getServer().getPluginManager().registerEvents(injector().getInstance(BlockEventListener117.class), this); } getServer().getPluginManager().registerEvents(injector().getInstance(EntityEventListener.class), this); diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/generator/BukkitPlotGenerator.java b/Bukkit/src/main/java/com/plotsquared/bukkit/generator/BukkitPlotGenerator.java index f713ed3506..2a763c4c67 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/generator/BukkitPlotGenerator.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/generator/BukkitPlotGenerator.java @@ -32,6 +32,7 @@ import com.plotsquared.core.plot.world.PlotAreaManager; import com.plotsquared.core.queue.ZeroedDelegateScopedQueueCoordinator; import com.plotsquared.core.util.ChunkManager; +import com.plotsquared.core.util.MinecraftVersion; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; @@ -90,14 +91,13 @@ public BukkitPlotGenerator( this.plotGenerator = generator; this.platformGenerator = this; this.populators = new ArrayList<>(); - int minecraftMinorVersion = PlotSquared.platform().serverVersion()[1]; - if (minecraftMinorVersion >= 17) { + if (MinecraftVersion.current().isNewerOrEqualThan(MinecraftVersion.CAVES_AND_CLIFFS)) { this.populators.add(new BlockStatePopulator(this.plotGenerator)); } else { this.populators.add(new LegacyBlockStatePopulator(this.plotGenerator)); } this.full = true; - this.useNewGenerationMethods = PlotSquared.platform().serverVersion()[1] >= 19; + this.useNewGenerationMethods = MinecraftVersion.current().isNewerOrEqualThan(MinecraftVersion.THE_WILD_UPDATE); this.biomeProvider = new BukkitPlotBiomeProvider(); } @@ -112,7 +112,7 @@ public BukkitPlotGenerator(final String world, final ChunkGenerator cg, final @N this.full = false; this.platformGenerator = cg; this.plotGenerator = new DelegatePlotGenerator(cg, world); - this.useNewGenerationMethods = PlotSquared.platform().serverVersion()[1] >= 19; + this.useNewGenerationMethods = MinecraftVersion.current().isNewerOrEqualThan(MinecraftVersion.THE_WILD_UPDATE); this.biomeProvider = null; } @@ -446,7 +446,7 @@ private final class BukkitPlotBiomeProvider extends BiomeProvider { static { Set disabledBiomes = new HashSet<>(List.of(Biome.CUSTOM)); - if (PlotSquared.platform().serverVersion()[1] <= 19) { + if (MinecraftVersion.current().isOlderOrEqualThan(MinecraftVersion.THE_WILD_UPDATE)) { final Biome cherryGrove = Registry.BIOME.get(NamespacedKey.minecraft("cherry_grove")); if (cherryGrove != null) { disabledBiomes.add(cherryGrove); diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/ChunkListener.java b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/ChunkListener.java index 763263e991..f2f981035f 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/ChunkListener.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/ChunkListener.java @@ -19,13 +19,13 @@ package com.plotsquared.bukkit.listener; import com.google.inject.Inject; -import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.location.Location; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.world.PlotAreaManager; import com.plotsquared.core.plot.world.SinglePlotArea; +import com.plotsquared.core.util.MinecraftVersion; import com.plotsquared.core.util.ReflectionUtils; import com.plotsquared.core.util.ReflectionUtils.RefClass; import com.plotsquared.core.util.ReflectionUtils.RefField; @@ -34,27 +34,26 @@ import com.plotsquared.core.util.task.TaskManager; import com.plotsquared.core.util.task.TaskTime; import io.papermc.lib.PaperLib; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.BlockState; import org.bukkit.entity.Entity; -import org.bukkit.entity.Item; -import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockPhysicsEvent; import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.event.entity.EntitySpawnEvent; import org.bukkit.event.entity.ItemSpawnEvent; import org.bukkit.event.world.ChunkLoadEvent; import org.bukkit.event.world.ChunkUnloadEvent; import org.checkerframework.checker.nullness.qual.NonNull; -import java.lang.reflect.Method; -import java.util.HashSet; import java.util.Objects; import static com.plotsquared.core.util.ReflectionUtils.getRefClass; @@ -62,31 +61,21 @@ @SuppressWarnings("unused") public class ChunkListener implements Listener { + private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + ChunkListener.class.getSimpleName()); + private final PlotAreaManager plotAreaManager; - private final int version; private RefMethod methodSetUnsaved; private RefMethod methodGetHandleChunk; private RefMethod methodGetHandleWorld; private RefField mustNotSave; private Object objChunkStatusFull = null; - /* - private RefMethod methodGetFullChunk; - private RefMethod methodGetBukkitChunk; - private RefMethod methodGetChunkProvider; - private RefMethod methodGetVisibleMap; - private RefField worldServer; - private RefField playerChunkMap; - private RefField updatingChunks; - private RefField visibleChunks; - */ private Chunk lastChunk; private boolean ignoreUnload = false; @Inject public ChunkListener(final @NonNull PlotAreaManager plotAreaManager) { this.plotAreaManager = plotAreaManager; - version = PlotSquared.platform().serverVersion()[1]; if (!Settings.Chunk_Processor.AUTO_TRIM) { return; } @@ -98,76 +87,24 @@ public ChunkListener(final @NonNull PlotAreaManager plotAreaManager) { try { this.methodGetHandleChunk = classCraftChunk.getMethod("getHandle"); } catch (NoSuchMethodException ignored) { - try { - RefClass classChunkStatus = getRefClass("net.minecraft.world.level.chunk.ChunkStatus"); - this.objChunkStatusFull = classChunkStatus.getRealClass().getField("n").get(null); - this.methodGetHandleChunk = classCraftChunk.getMethod("getHandle", classChunkStatus.getRealClass()); - } catch (NoSuchMethodException ex) { - throw new RuntimeException(ex); - } + RefClass classChunkStatus = getRefClass("net.minecraft.world.level.chunk.ChunkStatus"); + this.objChunkStatusFull = classChunkStatus.getRealClass().getField("n").get(null); + this.methodGetHandleChunk = classCraftChunk.getMethod("getHandle", classChunkStatus.getRealClass()); } - try { - if (version < 17) { - RefClass classChunk = getRefClass("{nms}.Chunk"); - this.mustNotSave = classChunk.getField("mustNotSave"); - } else { - RefClass classChunk = getRefClass("net.minecraft.world.level.chunk.Chunk"); - this.mustNotSave = classChunk.getField("mustNotSave"); - } - } catch (NoSuchFieldException e) { - e.printStackTrace(); + if (MinecraftVersion.current().isNewerOrEqualThan(MinecraftVersion.CAVES_AND_CLIFFS)) { + RefClass classChunk = getRefClass("net.minecraft.world.level.chunk.Chunk"); + this.mustNotSave = classChunk.getField("mustNotSave"); + } else { + RefClass classChunk = getRefClass("{nms}.Chunk"); + this.mustNotSave = classChunk.getField("mustNotSave"); } - } catch (Throwable ignored) { + } catch (Throwable t) { Settings.Chunk_Processor.AUTO_TRIM = false; + LOGGER.error("Failed to initialize NMS access for auto-trimming capabilities. Disabling auto trim", t); } for (World world : Bukkit.getWorlds()) { world.setAutoSave(false); } - if (version > 13) { - return; - } - TaskManager.runTaskRepeat(() -> { - try { - HashSet toUnload = new HashSet<>(); - for (World world : Bukkit.getWorlds()) { - String worldName = world.getName(); - if (!this.plotAreaManager.hasPlotArea(worldName)) { - continue; - } - Object craftWorld = methodGetHandleWorld.of(world).call(); - if (version == 13) { - Object chunkMap = craftWorld.getClass().getDeclaredMethod("getPlayerChunkMap").invoke(craftWorld); - Method methodIsChunkInUse = - chunkMap.getClass().getDeclaredMethod("isChunkInUse", int.class, int.class); - Chunk[] chunks = world.getLoadedChunks(); - for (Chunk chunk : chunks) { - if ((boolean) methodIsChunkInUse.invoke(chunkMap, chunk.getX(), chunk.getZ())) { - continue; - } - int x = chunk.getX(); - int z = chunk.getZ(); - if (!shouldSave(worldName, x, z)) { - unloadChunk(worldName, chunk, false); - continue; - } - toUnload.add(chunk); - } - } - } - if (toUnload.isEmpty()) { - return; - } - long start = System.currentTimeMillis(); - for (Chunk chunk : toUnload) { - if (System.currentTimeMillis() - start > 5) { - return; - } - chunk.unload(true); - } - } catch (Throwable e) { - e.printStackTrace(); - } - }, TaskTime.ticks(1L)); } public boolean unloadChunk(String world, Chunk chunk, boolean safe) { @@ -263,25 +200,7 @@ public void onChunkLoad(ChunkLoadEvent event) { @EventHandler(priority = EventPriority.LOWEST) public void onItemSpawn(ItemSpawnEvent event) { - Item entity = event.getEntity(); - PaperLib.getChunkAtAsync(event.getLocation()).thenAccept(chunk -> { - if (chunk == this.lastChunk) { - event.getEntity().remove(); - event.setCancelled(true); - return; - } - if (!this.plotAreaManager.hasPlotArea(chunk.getWorld().getName())) { - return; - } - Entity[] entities = chunk.getEntities(); - if (entities.length > Settings.Chunk_Processor.MAX_ENTITIES) { - event.getEntity().remove(); - event.setCancelled(true); - this.lastChunk = chunk; - } else { - this.lastChunk = null; - } - }); + this.onInternalEntitySpawn(event); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @@ -293,7 +212,10 @@ public void onBlockPhysics(BlockPhysicsEvent event) { @EventHandler(priority = EventPriority.LOWEST) public void onEntitySpawn(CreatureSpawnEvent event) { - LivingEntity entity = event.getEntity(); + this.onInternalEntitySpawn(event); + } + + private void onInternalEntitySpawn(EntitySpawnEvent event) { PaperLib.getChunkAtAsync(event.getLocation()).thenAccept(chunk -> { if (chunk == this.lastChunk) { event.getEntity().remove(); diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/PlayerEventListener.java b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/PlayerEventListener.java index f7a2623caa..3ee8ec811a 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/PlayerEventListener.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/PlayerEventListener.java @@ -72,6 +72,7 @@ import com.plotsquared.core.plot.world.PlotAreaManager; import com.plotsquared.core.util.EventDispatcher; import com.plotsquared.core.util.MathMan; +import com.plotsquared.core.util.MinecraftVersion; import com.plotsquared.core.util.PlotFlagUtil; import com.plotsquared.core.util.PremiumVerification; import com.plotsquared.core.util.entity.EntityCategories; @@ -216,8 +217,7 @@ public class PlayerEventListener implements Listener { "PINK_DYE", "GLOW_INK_SAC" )); - int[] version = PlotSquared.platform().serverVersion(); - if (version[1] >= 20) { + if (MinecraftVersion.current().isNewerOrEqualThan(MinecraftVersion.TRAILS_AND_TALES)) { mutableDyes.add("HONEYCOMB"); } DYES = Set.copyOf(mutableDyes); diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/SingleWorldListener.java b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/SingleWorldListener.java index 8036b94e25..9c506b03c0 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/SingleWorldListener.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/SingleWorldListener.java @@ -22,6 +22,7 @@ import com.plotsquared.core.plot.world.PlotAreaManager; import com.plotsquared.core.plot.world.SinglePlotArea; import com.plotsquared.core.plot.world.SinglePlotAreaManager; +import com.plotsquared.core.util.MinecraftVersion; import com.plotsquared.core.util.ReflectionUtils; import org.bukkit.Chunk; import org.bukkit.World; @@ -49,7 +50,7 @@ public SingleWorldListener() throws Exception { this.methodGetHandleChunk = classCraftChunk.getMethod("getHandle").getRealMethod(); } catch (NoSuchMethodException ignored) { try { - String chunkStatus = PlotSquared.platform().serverVersion()[1] < 21 + String chunkStatus = MinecraftVersion.current().isOlderThan(MinecraftVersion.TRICKY_TRIALS) ? "net.minecraft.world.level.chunk" + ".ChunkStatus" : "net.minecraft.world.level.chunk.status.ChunkStatus"; ReflectionUtils.RefClass classChunkStatus = getRefClass(chunkStatus); diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitPlayer.java b/Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitPlayer.java index bd9c992874..5317f3cd26 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitPlayer.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitPlayer.java @@ -32,6 +32,7 @@ import com.plotsquared.core.plot.world.PlotAreaManager; import com.plotsquared.core.util.EventDispatcher; import com.plotsquared.core.util.MathMan; +import com.plotsquared.core.util.MinecraftVersion; import com.plotsquared.core.util.WorldUtil; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.extension.platform.Actor; @@ -313,7 +314,7 @@ public void setFlight(boolean fly) { @Override public void playMusic(final @NonNull Location location, final @NonNull ItemType id) { if (id == ItemTypes.AIR) { - if (PlotSquared.platform().serverVersion()[1] >= 19) { + if (MinecraftVersion.current().isOlderOrEqualThan(MinecraftVersion.THE_WILD_UPDATE)) { player.stopSound(SoundCategory.MUSIC); return; } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitUtil.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitUtil.java index fd1ce055ef..261ecbc760 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitUtil.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitUtil.java @@ -30,6 +30,7 @@ import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.util.BlockUtil; import com.plotsquared.core.util.MathMan; +import com.plotsquared.core.util.MinecraftVersion; import com.plotsquared.core.util.PlayerManager; import com.plotsquared.core.util.StringComparison; import com.plotsquared.core.util.WorldUtil; @@ -56,7 +57,6 @@ import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.Sign; -import org.bukkit.block.data.Directional; import org.bukkit.block.data.type.WallSign; import org.bukkit.entity.Allay; import org.bukkit.entity.Ambient; @@ -357,15 +357,14 @@ public void setSign( facing = BlockFace.SOUTH; } } - if (PlotSquared.platform().serverVersion()[1] == 13) { + if (MinecraftVersion.current().isOlderOrEqualThan(13)) { block.setType(Material.valueOf(area.legacySignMaterial()), false); } else { block.setType(Material.valueOf(area.signMaterial()), false); } - if (!(block.getBlockData() instanceof WallSign)) { + if (!(block.getBlockData() instanceof WallSign sign)) { throw new RuntimeException("Something went wrong generating a sign"); } - final Directional sign = (Directional) block.getBlockData(); sign.setFacing(facing); block.setBlockData(sign, false); } @@ -438,7 +437,6 @@ public void setFoodLevel(final @NonNull PlotPlayer player, @NonNegative final @Override public @NonNull Set getTypesInCategory(final @NonNull String category) { final Collection> allowedInterfaces = new HashSet<>(); - final int[] version = PlotSquared.platform().serverVersion(); switch (category) { case "animal" -> { allowedInterfaces.add(IronGolem.class); @@ -446,7 +444,7 @@ public void setFoodLevel(final @NonNull PlotPlayer player, @NonNegative final allowedInterfaces.add(Animals.class); allowedInterfaces.add(WaterMob.class); allowedInterfaces.add(Ambient.class); - if (version[1] >= 19) { + if (MinecraftVersion.current().isOlderOrEqualThan(MinecraftVersion.THE_WILD_UPDATE)) { allowedInterfaces.add(Allay.class); } } @@ -478,7 +476,7 @@ public void setFoodLevel(final @NonNull PlotPlayer player, @NonNegative final } case "player" -> allowedInterfaces.add(Player.class); case "interaction" -> { - if ((version[1] > 19) || (version[1] == 19 && version[2] >= 4)) { + if (MinecraftVersion.current().isNewerOrEqualThan(19, 4)) { allowedInterfaces.add(Interaction.class); } } diff --git a/Core/src/main/java/com/plotsquared/core/PlotPlatform.java b/Core/src/main/java/com/plotsquared/core/PlotPlatform.java index 844d553b63..ab1d825cbc 100644 --- a/Core/src/main/java/com/plotsquared/core/PlotPlatform.java +++ b/Core/src/main/java/com/plotsquared/core/PlotPlatform.java @@ -37,6 +37,7 @@ import com.plotsquared.core.queue.GlobalBlockQueue; import com.plotsquared.core.util.ChunkManager; import com.plotsquared.core.util.EconHandler; +import com.plotsquared.core.util.MinecraftVersion; import com.plotsquared.core.util.PlatformWorldManager; import com.plotsquared.core.util.PlayerManager; import com.plotsquared.core.util.RegionManager; @@ -94,9 +95,18 @@ public interface PlotPlatform

extends LocaleHolder { * Gets the version of Minecraft that is running * * @return server version as array of numbers + * @deprecated non-standardized format, use {@link #minecraftVersion()} */ + @Deprecated(since = "TODO") int[] serverVersion(); + /** + * Gets the version of Minecraft that this server is running + * + * @return minecraft version + */ + MinecraftVersion minecraftVersion(); + /** * Gets the default minimum world height for the version of Minecraft that the server is running. * diff --git a/Core/src/main/java/com/plotsquared/core/plot/PlotArea.java b/Core/src/main/java/com/plotsquared/core/plot/PlotArea.java index d121aee8c6..aa8b1f2673 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/PlotArea.java +++ b/Core/src/main/java/com/plotsquared/core/plot/PlotArea.java @@ -48,6 +48,7 @@ import com.plotsquared.core.queue.GlobalBlockQueue; import com.plotsquared.core.queue.QueueCoordinator; import com.plotsquared.core.util.MathMan; +import com.plotsquared.core.util.MinecraftVersion; import com.plotsquared.core.util.PlotExpression; import com.plotsquared.core.util.RegionUtil; import com.plotsquared.core.util.StringMan; @@ -325,7 +326,7 @@ public void loadDefaultConfiguration(ConfigurationSection config) { this.mobSpawnerSpawning = config.getBoolean("mob_spawner_spawning"); this.autoMerge = config.getBoolean("plot.auto_merge"); this.allowSigns = config.getBoolean("plot.create_signs"); - if (PlotSquared.platform().serverVersion()[1] == 13) { + if (MinecraftVersion.current().isOlderOrEqualThan(13)) { this.legacySignMaterial = config.getString("plot.legacy_sign_material"); } else { this.signMaterial = config.getString("plot.sign_material"); @@ -470,7 +471,7 @@ public void saveConfiguration(ConfigurationSection config) { options.put("mob_spawner_spawning", this.isMobSpawnerSpawning()); options.put("plot.auto_merge", this.isAutoMerge()); options.put("plot.create_signs", this.allowSigns()); - if (PlotSquared.platform().serverVersion()[1] == 13) { + if (MinecraftVersion.current().isOlderOrEqualThan(13)) { options.put("plot.legacy_sign_material", this.legacySignMaterial); } else { options.put("plot.sign_material", this.signMaterial()); diff --git a/Core/src/main/java/com/plotsquared/core/util/MinecraftVersion.java b/Core/src/main/java/com/plotsquared/core/util/MinecraftVersion.java new file mode 100644 index 0000000000..46cecdf65f --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/util/MinecraftVersion.java @@ -0,0 +1,132 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.util; + +import com.plotsquared.core.PlotSquared; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.Comparator; + +/** + * Represents a minecraft version. For simplicity, and compatibility with modern versions, the `1.` prefix of older versions is + * ignored and the minor version part becomes the major version part. + *

+ *

    + *
  • `1.17.0` -> `(17, 0)`
  • + *
  • `26.2` -> `(26, 2)`
  • + *
+ * + * @param major the major part of the version string. For versions pre 26.1 this is the minor version part + * @param minor the minor part of the version string. For versions pre 26.1 this is the patch version part + */ +public record MinecraftVersion(int major, int minor, int patch) implements Comparable { + + /** + * Minecraft 1.17 release version + */ + public static final MinecraftVersion CAVES_AND_CLIFFS = new MinecraftVersion(17, 0, 0); + /** + * Minecraft 1.18 release version + */ + public static final MinecraftVersion CAVES_AND_CLIFFS_2 = new MinecraftVersion(18, 0, 0); + /** + * Minecraft 1.19 release version + */ + public static final MinecraftVersion THE_WILD_UPDATE = new MinecraftVersion(19, 0, 0); + /** + * Minecraft 1.20 release version + */ + public static final MinecraftVersion TRAILS_AND_TALES = new MinecraftVersion(20, 0, 0); + /** + * Minecraft 1.21 release version + */ + public static final MinecraftVersion TRICKY_TRIALS = new MinecraftVersion(21, 0, 0); + /** + * Minecraft 26.1 release version + */ + public static final MinecraftVersion TINY_TAKEOVER = new MinecraftVersion(26, 1, 0); + + private static final Comparator COMPARATOR = Comparator + .comparingInt(MinecraftVersion::major) + .thenComparingInt(MinecraftVersion::minor); + private static MinecraftVersion current; + + public static MinecraftVersion current() { + if (current == null) { + //noinspection deprecation + int[] parts = PlotSquared.platform().serverVersion(); + if (parts.length < 2) { + throw new IllegalStateException("Version string provided by platform is malformed: " + Arrays.toString(parts)); + } + // if real major version part is `1`, we are running on legacy versions + if (parts[0] == 1) { + // legacy versions don't have real patch versions (as their major part is basically a dummy) + current = new MinecraftVersion(parts[1], parts.length > 2 ? parts[2] : 0, 0); + } else { + // modern versions do have a optional patch version (e.g. 26.1.2) + current = new MinecraftVersion(parts[0], parts[1], parts.length > 2 ? parts[2] : 0); + } + } + return current; + } + + @Override + public int compareTo(@NotNull final MinecraftVersion o) { + return COMPARATOR.compare(this, o); + } + + public boolean isNewerOrEqualThan(MinecraftVersion other) { + if (this.major() > other.major()) { + return true; + } + return this.major() == other.major() && this.minor() >= other.minor(); + } + + public boolean isOlderOrEqualThan(MinecraftVersion other) { + if (this.major() < other.major()) { + return true; + } + return this.major() == other.major() && this.minor() <= other.minor(); + } + + public boolean isOlderThan(MinecraftVersion other) { + if (this.major() < other.major()) { + return true; + } + return this.major() == other.major() && this.minor() < other.minor(); + } + + public boolean isNewerOrEqualThan(int otherMajor) { + return this.major() >= otherMajor; + } + + public boolean isNewerOrEqualThan(int otherMajor, int otherMinor) { + return this.major() > otherMajor || (this.major() == otherMajor && this.minor() >= otherMinor); + } + + public boolean isOlderOrEqualThan(int otherMajor) { + return this.major() <= otherMajor; + } + + public boolean isOlderOrEqualThan(int otherMajor, int otherMinor) { + return this.major() < otherMajor || (this.major() == otherMajor && this.minor() <= otherMinor); + } + +} diff --git a/build.gradle.kts b/build.gradle.kts index be5b94a510..e227012c14 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -216,7 +216,7 @@ tasks.getByName("jar") { enabled = false } -val supportedVersions = listOf("1.19.4", "1.20.6", "1.21.1", "1.21.3", "1.21.4", "1.21.5", "1.21.6", "1.21.7", "1.21.8") +val supportedVersions = listOf("1.19.4", "1.20.6", "1.21.11", "26.1.2") tasks { register("cacheLatestFaweArtifact") { val lastSuccessfulBuildUrl = uri("https://ci.athion.net/job/FastAsyncWorldEdit/lastSuccessfulBuild/api/json").toURL()