From 1aed8f3c263a8fd93c85ddbd120d4189bedaf511 Mon Sep 17 00:00:00 2001 From: David Date: Tue, 24 Mar 2026 17:53:34 +0100 Subject: [PATCH 1/9] feat: 26.1.1 --- aspaper-api/build.gradle.kts.patch | 2 +- aspaper-server/build.gradle.kts.patch | 25 +++--- .../features/0001-Disable-dragon-battle.patch | 30 ++++--- .../0002-Avoid-IO-call-for-UUID.patch | 19 ---- ...Prevent-config-disk-io-on-world-load.patch | 32 +++++++ ...Prevent-config-disk-io-on-world-load.patch | 32 ------- .../0004-Read-only-dimension-data-store.patch | 25 ------ .../server/level/ServerLevel.java.patch | 87 ++++++++++--------- ...-temp-folder-after-world-is-unloaded.patch | 6 +- .../features/0006-World-overrides.patch | 47 +++++----- .../bukkit/craftbukkit/CraftServer.java.patch | 2 +- .../infernalsuite/asp/SlimeNMSBridgeImpl.java | 17 ++-- .../level/ReadOnlyDimensionDataStorage.java | 4 +- .../asp/level/SlimeLevelInstance.java | 74 ++++++++++++---- .../asp/level/chunk/NMSSlimeChunk.java | 4 +- .../asp/level/chunk/SlimeChunkConverter.java | 8 +- .../com/infernalsuite/asp/util/NmsUtil.java | 2 +- buildSrc/build.gradle.kts | 1 + buildSrc/src/main/kotlin/constants.kt | 2 +- gradle.properties | 8 +- gradle/libs.versions.toml | 10 +-- gradle/wrapper/gradle-wrapper.properties | 2 +- settings.gradle.kts | 4 +- 23 files changed, 223 insertions(+), 220 deletions(-) delete mode 100644 aspaper-server/minecraft-patches/features/0002-Avoid-IO-call-for-UUID.patch create mode 100644 aspaper-server/minecraft-patches/features/0002-Prevent-config-disk-io-on-world-load.patch delete mode 100644 aspaper-server/minecraft-patches/features/0003-Prevent-config-disk-io-on-world-load.patch delete mode 100644 aspaper-server/minecraft-patches/features/0004-Read-only-dimension-data-store.patch diff --git a/aspaper-api/build.gradle.kts.patch b/aspaper-api/build.gradle.kts.patch index 238e02fc8..67dd5744d 100644 --- a/aspaper-api/build.gradle.kts.patch +++ b/aspaper-api/build.gradle.kts.patch @@ -9,7 +9,7 @@ api("com.google.guava:guava:33.3.1-jre") api("com.google.code.gson:gson:2.11.0") @@ -91,7 +_,7 @@ - testRuntimeOnly("org.junit.platform:junit-platform-launcher") + testRuntimeOnly("org.junit.platform:junit-platform-launcher:6.0.3") } -val generatedDir: java.nio.file.Path = layout.projectDirectory.dir("src/generated/java").asFile.toPath() diff --git a/aspaper-server/build.gradle.kts.patch b/aspaper-server/build.gradle.kts.patch index 0f7bbb593..fffadae8b 100644 --- a/aspaper-server/build.gradle.kts.patch +++ b/aspaper-server/build.gradle.kts.patch @@ -1,9 +1,11 @@ --- a/paper-server/build.gradle.kts +++ b/paper-server/build.gradle.kts -@@ -22,6 +_,17 @@ +@@ -22,9 +_,20 @@ minecraftVersion = providers.gradleProperty("mcVersion") gitFilePatches = false +- updatingMinecraft { +- // oldPaperCommit = "7e80cef5198561d0db53406127e5b8bc7af51577" + val aspaper = forks.register("aspaper") { + upstream.patchDir("paperServer") { + upstreamPath = "paper-server" @@ -11,14 +13,17 @@ + patchesDir = rootDirectory.dir("aspaper-server/paper-patches") + outputDir = rootDirectory.dir("paper-server") + } -+ } + } + + activeFork = aspaper + - spigot { - enabled = true - buildDataRef = "17f77cee7117ab9d6175f088ae8962bfd04e61a9" -@@ -104,7 +_,19 @@ ++// updatingMinecraft { ++// oldPaperCommit = "7e80cef5198561d0db53406127e5b8bc7af51577" ++// } + } + + tasks.generateDevelopmentBundle { +@@ -86,7 +_,19 @@ } } @@ -39,17 +44,17 @@ configurations.named(log4jPlugins.compileClasspathConfigurationName) { extendsFrom(configurations.compileClasspath.get()) } -@@ -127,7 +_,8 @@ +@@ -109,7 +_,8 @@ } dependencies { - implementation(project(":paper-api")) + implementation(project(":aspaper-api")) //ASP + implementation(project(":core")) //ASP - implementation("ca.spottedleaf:concurrentutil:0.0.8") + implementation("ca.spottedleaf:concurrentutil:0.0.10") implementation("org.jline:jline-terminal-ffm:3.27.1") // use ffm on java 22+ implementation("org.jline:jline-terminal-jni:3.27.1") // fall back to jni on java 21 -@@ -198,14 +_,14 @@ +@@ -171,14 +_,14 @@ val gitBranch = git.exec(providers, "rev-parse", "--abbrev-ref", "HEAD").get().trim() attributes( "Main-Class" to "org.bukkit.craftbukkit.Main", @@ -69,7 +74,7 @@ "Build-Number" to (build ?: ""), "Build-Time" to buildTime.toString(), "Git-Branch" to gitBranch, -@@ -264,7 +_,7 @@ +@@ -237,7 +_,7 @@ jvmArgumentProviders.add(provider) } diff --git a/aspaper-server/minecraft-patches/features/0001-Disable-dragon-battle.patch b/aspaper-server/minecraft-patches/features/0001-Disable-dragon-battle.patch index 43da52134..e3c9da36b 100644 --- a/aspaper-server/minecraft-patches/features/0001-Disable-dragon-battle.patch +++ b/aspaper-server/minecraft-patches/features/0001-Disable-dragon-battle.patch @@ -5,21 +5,27 @@ Subject: [PATCH] Disable dragon battle diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index 24d3b1161cf45a915b37f510645500c5a45350eb..cd7aca9f76aef0824d94c73373a8f4536d05c4e8 100644 +index c5415bcc157219d452e15e80d569df5df3043ba5..785e7784c8f6e2c29c7f363dd700e2bbd0fe15f4 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java -@@ -715,7 +715,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -2,6 +2,7 @@ package net.minecraft.server.level; + + import com.google.common.annotations.VisibleForTesting; + import com.google.common.collect.Lists; ++import com.infernalsuite.asp.api.world.properties.SlimeProperty; + import com.mojang.datafixers.DataFixer; + import com.mojang.datafixers.util.Pair; + import com.mojang.logging.LogUtils; +@@ -741,7 +742,11 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet ); - this.structureManager = new StructureManager(this, this.serverLevelData.worldGenOptions(), this.structureCheck); // CraftBukkit - if (this.dimension() == Level.END && this.dimensionTypeRegistration().is(BuiltinDimensionTypes.END) || env == org.bukkit.World.Environment.THE_END) { // CraftBukkit - Allow to create EnderDragonBattle in default and custom END -- this.dragonFight = new EndDragonFight(this, this.serverLevelData.worldGenOptions().seed(), this.serverLevelData.endDragonFightData()); // CraftBukkit -+ // ASP START -+ if (bootstrap == null || bootstrap.initial().getPropertyMap().getValue(com.infernalsuite.asp.api.world.properties.SlimeProperties.DRAGON_BATTLE)) { -+ this.dragonFight = new EndDragonFight(this, this.serverLevelData.worldGenOptions().seed(), this.serverLevelData.endDragonFightData()); // CraftBukkit + this.structureManager = new StructureManager(this, options, this.structureCheck); + if (this.dimensionType().hasEnderDragonFight()) { +- this.dragonFight = this.getDataStorage().computeIfAbsent(EnderDragonFight.TYPE); ++ if(bootstrap == null || bootstrap.initial().getPropertyMap().getValue(com.infernalsuite.asp.api.world.properties.SlimeProperties.DRAGON_BATTLE)) { // ASP - only create dragon fight if property is enabled) ++ this.dragonFight = this.getDataStorage().computeIfAbsent(EnderDragonFight.TYPE); + } else { -+ this.dragonFight = new EndDragonFight(this, this.serverLevelData.worldGenOptions().seed(), new EndDragonFight.Data(false, true, true, false,Optional.empty(),Optional.empty(),Optional.empty())); // ASP - disable dragon ++ this.dragonFight = new EnderDragonFight(false, true, true, Optional.empty(), 0,Optional.empty(),Optional.empty(), List.of(), List.of()); + } -+ // ASP END - } else { - this.dragonFight = null; + this.dragonFight.init(this, seed, BlockPos.ZERO); } + diff --git a/aspaper-server/minecraft-patches/features/0002-Avoid-IO-call-for-UUID.patch b/aspaper-server/minecraft-patches/features/0002-Avoid-IO-call-for-UUID.patch deleted file mode 100644 index 53c38eb97..000000000 --- a/aspaper-server/minecraft-patches/features/0002-Avoid-IO-call-for-UUID.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: David Mayr -Date: Mon, 10 Mar 2025 11:41:14 +0100 -Subject: [PATCH] Avoid IO call for UUID - - -diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index cd7aca9f76aef0824d94c73373a8f4536d05c4e8..7893b71f81ae055512ec88415ebe388b7152cc5a 100644 ---- a/net/minecraft/server/level/ServerLevel.java -+++ b/net/minecraft/server/level/ServerLevel.java -@@ -642,7 +642,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - // CraftBukkit start - super(serverLevelData, dimension, server.registryAccess(), levelStem.type(), false, isDebug, biomeZoomSeed, server.getMaxChainedNeighborUpdates(), gen, biomeProvider, env, spigotConfig -> server.paperConfigurations.createWorldConfig(io.papermc.paper.configuration.PaperConfigurations.createWorldContextMap(levelStorageAccess.levelDirectory.path(), serverLevelData.getLevelName(), dimension.identifier(), spigotConfig, server.registryAccess(), serverLevelData.getGameRules())), dispatcher); // Paper - create paper world configs & Async-Anti-Xray: Pass executor - this.levelStorageAccess = levelStorageAccess; -- this.uuid = org.bukkit.craftbukkit.util.WorldUUID.getOrCreate(levelStorageAccess.levelDirectory.path().toFile()); -+ this.uuid = bootstrap == null ? org.bukkit.craftbukkit.util.WorldUUID.getOrCreate(levelStorageAccess.levelDirectory.path().toFile()) : java.util.UUID.randomUUID(); //ASP - avoid IO calls - this.levelLoadListener = new net.minecraft.server.level.progress.LoggingLevelLoadListener(false, this); - // CraftBukkit end - this.tickTime = tickTime; diff --git a/aspaper-server/minecraft-patches/features/0002-Prevent-config-disk-io-on-world-load.patch b/aspaper-server/minecraft-patches/features/0002-Prevent-config-disk-io-on-world-load.patch new file mode 100644 index 000000000..c4fbeb228 --- /dev/null +++ b/aspaper-server/minecraft-patches/features/0002-Prevent-config-disk-io-on-world-load.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: David Mayr +Date: Wed, 12 Mar 2025 21:14:56 +0100 +Subject: [PATCH] Prevent config disk io on world load + + +diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java +index 785e7784c8f6e2c29c7f363dd700e2bbd0fe15f4..328366d6c7f655dbc97b86608574eb421ce998a8 100644 +--- a/net/minecraft/server/level/ServerLevel.java ++++ b/net/minecraft/server/level/ServerLevel.java +@@ -659,7 +659,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet + savedDataStorage.set(io.papermc.paper.world.saveddata.PaperWorldPDC.TYPE, loadedWorldData.pdc() == null ? io.papermc.paper.world.saveddata.PaperWorldPDC.TYPE.constructor().get() : loadedWorldData.pdc()); + final GameRules gameRules = new GameRules(server.getWorldData().enabledFeatures(), savedDataStorage.computeIfAbsent(net.minecraft.world.level.gamerules.GameRuleMap.TYPE)); + this.gameRules = gameRules; +- super(levelData, dimension, server.registryAccess(), levelStem.type(), false, isDebug, biomeZoomSeed, server.getMaxChainedNeighborUpdates(), loadedWorldData.bukkitName(), gen, biomeProvider, env, spigotConfig -> server.paperConfigurations.createWorldConfig(io.papermc.paper.configuration.PaperConfigurations.createWorldContextMap(server.storageSource.getDimensionPath(dimension), loadedWorldData.bukkitName(), dimension.identifier(), spigotConfig, server.registryAccess(), gameRules))); // Paper - create paper world configs ++ super(levelData, dimension, server.registryAccess(), levelStem.type(), false, isDebug, biomeZoomSeed, server.getMaxChainedNeighborUpdates(), loadedWorldData.bukkitName(), gen, biomeProvider, env, spigotConfig -> bootstrap != null ? com.infernalsuite.asp.config.SlimePaperWorldConfig.initializeOrGet() : server.paperConfigurations.createWorldConfig(io.papermc.paper.configuration.PaperConfigurations.createWorldContextMap(server.storageSource.getDimensionPath(dimension), loadedWorldData.bukkitName(), dimension.identifier(), spigotConfig, server.registryAccess(), gameRules))); // Paper - create paper world configs //ASP - Optimize world config + this.weatherData = savedDataStorage.computeIfAbsent(WeatherData.TYPE); + this.weatherData.setLevel(this); + this.typeKey = typeKey; +diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java +index 4ac838fa756c65f36a343224cabbee2b5d5ea110..fe49d1cb9f4062061e3f55384218842cbb923e12 100644 +--- a/net/minecraft/world/level/Level.java ++++ b/net/minecraft/world/level/Level.java +@@ -846,7 +846,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl + this.maxSectionY = this.maxY >> 4; + this.sectionsCount = this.maxSectionY - this.minSectionY + 1; + // Paper end - getblock optimisations - cache world height/sections +- this.spigotConfig = new org.spigotmc.SpigotWorldConfig(bukkitName); // Spigot ++ this.spigotConfig = new org.spigotmc.SpigotWorldConfig(bukkitName, !(this instanceof com.infernalsuite.asp.level.SlimeLevelInstance)); // Spigot //ASP - Improve Slime IO + this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper - create paper world config + this.generator = generator; + this.world = new CraftWorld((ServerLevel) this, generator, biomeProvider, environment); diff --git a/aspaper-server/minecraft-patches/features/0003-Prevent-config-disk-io-on-world-load.patch b/aspaper-server/minecraft-patches/features/0003-Prevent-config-disk-io-on-world-load.patch deleted file mode 100644 index 43196636b..000000000 --- a/aspaper-server/minecraft-patches/features/0003-Prevent-config-disk-io-on-world-load.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: David Mayr -Date: Wed, 12 Mar 2025 21:14:56 +0100 -Subject: [PATCH] Prevent config disk io on world load - - -diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index ab0c9f02e446476053d586567ea1a61ae2675e0c..3241c3ae29b25c3a44a30677ae86d03ec3eca88d 100644 ---- a/net/minecraft/server/level/ServerLevel.java -+++ b/net/minecraft/server/level/ServerLevel.java -@@ -640,7 +640,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - ) { - //ASP end - // CraftBukkit start -- super(serverLevelData, dimension, server.registryAccess(), levelStem.type(), false, isDebug, biomeZoomSeed, server.getMaxChainedNeighborUpdates(), gen, biomeProvider, env, spigotConfig -> server.paperConfigurations.createWorldConfig(io.papermc.paper.configuration.PaperConfigurations.createWorldContextMap(levelStorageAccess.levelDirectory.path(), serverLevelData.getLevelName(), dimension.identifier(), spigotConfig, server.registryAccess(), serverLevelData.getGameRules())), dispatcher); // Paper - create paper world configs & Async-Anti-Xray: Pass executor -+ super(serverLevelData, dimension, server.registryAccess(), levelStem.type(), false, isDebug, biomeZoomSeed, server.getMaxChainedNeighborUpdates(), gen, biomeProvider, env, spigotConfig -> bootstrap != null ? com.infernalsuite.asp.config.SlimePaperWorldConfig.initializeOrGet() : server.paperConfigurations.createWorldConfig(io.papermc.paper.configuration.PaperConfigurations.createWorldContextMap(levelStorageAccess.levelDirectory.path(), serverLevelData.getLevelName(), dimension.identifier(), spigotConfig, server.registryAccess(), serverLevelData.getGameRules())), dispatcher); // Paper - create paper world configs & Async-Anti-Xray: Pass executor //ASP - Optimize world config - this.levelStorageAccess = levelStorageAccess; - this.uuid = bootstrap == null ? org.bukkit.craftbukkit.util.WorldUUID.getOrCreate(levelStorageAccess.levelDirectory.path().toFile()) : java.util.UUID.randomUUID(); //ASP - avoid IO calls - this.levelLoadListener = new net.minecraft.server.level.progress.LoggingLevelLoadListener(false, this); -diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java -index 579bbba4e823d4d0318e58759ca732b7c8e4d865..f7b2cd6a02a371de162159ef9d8999f737be7435 100644 ---- a/net/minecraft/world/level/Level.java -+++ b/net/minecraft/world/level/Level.java -@@ -843,7 +843,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl - this.maxSectionY = this.maxY >> 4; - this.sectionsCount = this.maxSectionY - this.minSectionY + 1; - // Paper end - getblock optimisations - cache world height/sections -- this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) levelData).getLevelName()); // Spigot -+ this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) levelData).getLevelName(), !(this instanceof com.infernalsuite.asp.level.SlimeLevelInstance)); // Spigot //ASP - Improve Slime IO - this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper - create paper world config - this.generator = generator; - this.world = new CraftWorld((ServerLevel) this, generator, biomeProvider, environment); diff --git a/aspaper-server/minecraft-patches/features/0004-Read-only-dimension-data-store.patch b/aspaper-server/minecraft-patches/features/0004-Read-only-dimension-data-store.patch deleted file mode 100644 index d3d2261b9..000000000 --- a/aspaper-server/minecraft-patches/features/0004-Read-only-dimension-data-store.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: David Mayr -Date: Thu, 13 Mar 2025 00:09:20 +0100 -Subject: [PATCH] Read only dimension data store - - -diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java -index af67b07722bb0125acd081dab767d7e7b360623b..fc4f631f7d55ce67f348e3b6090095e6ef8445e8 100644 ---- a/net/minecraft/server/level/ServerChunkCache.java -+++ b/net/minecraft/server/level/ServerChunkCache.java -@@ -208,7 +208,13 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon - LOGGER.error("Failed to create dimension data storage directory", (Throwable)var14); - } - -- this.dataStorage = new DimensionDataStorage(path, fixerUpper, level.registryAccess()); -+ //ASP start - No dimension data storage -+ if(level instanceof com.infernalsuite.asp.level.SlimeLevelInstance) { -+ this.dataStorage = new com.infernalsuite.asp.level.ReadOnlyDimensionDataStorage(path, fixerUpper, level.registryAccess()); -+ } else { -+ this.dataStorage = new DimensionDataStorage(path, fixerUpper, level.registryAccess()); -+ } -+ //ASP end - No dimension data storage - this.ticketStorage = this.dataStorage.computeIfAbsent(TicketStorage.TYPE); - this.chunkMap = new ChunkMap( - level, diff --git a/aspaper-server/minecraft-patches/sources/net/minecraft/server/level/ServerLevel.java.patch b/aspaper-server/minecraft-patches/sources/net/minecraft/server/level/ServerLevel.java.patch index c8af94f8e..c91aea952 100644 --- a/aspaper-server/minecraft-patches/sources/net/minecraft/server/level/ServerLevel.java.patch +++ b/aspaper-server/minecraft-patches/sources/net/minecraft/server/level/ServerLevel.java.patch @@ -1,70 +1,75 @@ --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java -@@ -598,7 +_,31 @@ +@@ -602,8 +_,35 @@ + this.playerTickingChunks.remove((LevelChunk)chunkHolder.getCurrentChunk()); } // Paper end - chunk tick iteration - +- - public ServerLevel( + public com.infernalsuite.asp.level.SlimeInMemoryWorld slimeInstance; // ASP + + public ServerLevel( -+ MinecraftServer server, -+ Executor dispatcher, -+ LevelStorageSource.LevelStorageAccess levelStorageAccess, -+ net.minecraft.world.level.storage.PrimaryLevelData serverLevelData, // CraftBukkit -+ ResourceKey dimension, -+ LevelStem levelStem, -+ boolean isDebug, -+ long biomeZoomSeed, -+ List customSpawners, -+ boolean tickTime, -+ @Nullable RandomSequences randomSequences, -+ org.bukkit.World.Environment env, // CraftBukkit -+ org.bukkit.generator.ChunkGenerator gen, // CraftBukkit -+ org.bukkit.generator.BiomeProvider biomeProvider // CraftBukkit ++ final MinecraftServer server, ++ final Executor executor, ++ final LevelStorageSource.LevelStorageAccess levelStorage, ++ final WorldGenSettings worldGenSettings, // CraftBukkit ++ final ResourceKey dimension, ++ final LevelStem levelStem, ++ final boolean isDebug, ++ final long biomeZoomSeed, ++ final List customSpawners, ++ final boolean tickTime ++ // Paper start - add parameters ++ , ResourceKey typeKey, ++ org.bukkit.World.Environment env, ++ org.bukkit.generator.ChunkGenerator gen, ++ org.bukkit.generator.BiomeProvider biomeProvider, ++ SavedDataStorage savedDataStorage, ++ io.papermc.paper.world.PaperWorldLoader.LoadedWorldData loadedWorldData ++ // Paper end - add parameters + ) { + //ASP start -+ this(null, server, dispatcher, levelStorageAccess, serverLevelData, dimension, levelStem, -+ isDebug, biomeZoomSeed, customSpawners, tickTime, randomSequences, env, gen, biomeProvider); ++ this(null, server, executor, levelStorage, worldGenSettings, dimension, levelStem, ++ isDebug, biomeZoomSeed, customSpawners, tickTime, typeKey, env, gen, biomeProvider, savedDataStorage, loadedWorldData); + } + + public ServerLevel( + com.infernalsuite.asp.level.@Nullable SlimeBootstrap bootstrap, - MinecraftServer server, - Executor dispatcher, - LevelStorageSource.LevelStorageAccess levelStorageAccess, -@@ -614,6 +_,7 @@ - org.bukkit.generator.ChunkGenerator gen, // CraftBukkit - org.bukkit.generator.BiomeProvider biomeProvider // CraftBukkit + final MinecraftServer server, + final Executor executor, + final LevelStorageSource.LevelStorageAccess levelStorage, +@@ -623,6 +_,7 @@ + io.papermc.paper.world.PaperWorldLoader.LoadedWorldData loadedWorldData + // Paper end - add parameters ) { + //ASP end // CraftBukkit start - super(serverLevelData, dimension, server.registryAccess(), levelStem.type(), false, isDebug, biomeZoomSeed, server.getMaxChainedNeighborUpdates(), gen, biomeProvider, env, spigotConfig -> server.paperConfigurations.createWorldConfig(io.papermc.paper.configuration.PaperConfigurations.createWorldContextMap(levelStorageAccess.levelDirectory.path(), serverLevelData.getLevelName(), dimension.identifier(), spigotConfig, server.registryAccess(), serverLevelData.getGameRules())), dispatcher); // Paper - create paper world configs & Async-Anti-Xray: Pass executor - this.levelStorageAccess = levelStorageAccess; -@@ -641,6 +_,13 @@ - chunkGenerator = new org.bukkit.craftbukkit.generator.CustomChunkGenerator(this, chunkGenerator, gen); - } - // CraftBukkit end + final io.papermc.paper.world.saveddata.PaperLevelOverrides levelData = loadedWorldData.levelOverrides(); + savedDataStorage.set(io.papermc.paper.world.saveddata.PaperLevelOverrides.TYPE, levelData); +@@ -644,7 +_,13 @@ + this.server = server; + this.customSpawners = customSpawners; + this.serverLevelData = levelData; + // ASP START + ChunkGenerator generator = levelStem.generator(); + ChunkGenerator result = this.getGenerator(bootstrap); + if (result != null) { -+ chunkGenerator = result; ++ generator = result; + } + // ASP END -+ - boolean flag = server.forceSynchronousWrites(); - DataFixer fixerUpper = server.getFixerUpper(); - // Paper - rewrite chunk system -@@ -723,6 +_,12 @@ - public void setDragonFight(@Nullable EndDragonFight dragonFight) { - this.dragonFight = dragonFight; + // CraftBukkit start + if (loadedWorldData.pdc() != null) { + this.getWorld().readBukkitValues(loadedWorldData.pdc().persistentData().toTagCompound()); +@@ -732,6 +_,12 @@ + // Paper end - rewrite chunk system + this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit } + + // ASP START -+ public ChunkGenerator getGenerator(com.infernalsuite.asp.level.SlimeBootstrap bootstrap) { ++ public @Nullable ChunkGenerator getGenerator(com.infernalsuite.asp.level.@Nullable SlimeBootstrap bootstrap) { + return null; + } + // ASP END - public void setWeatherParameters(int clearTime, int weatherTime, boolean isRaining, boolean isThundering) { - this.serverLevelData.setClearWeatherTime(clearTime); + // Paper start + @Override diff --git a/aspaper-server/paper-patches/features/0004-Delete-temp-folder-after-world-is-unloaded.patch b/aspaper-server/paper-patches/features/0004-Delete-temp-folder-after-world-is-unloaded.patch index 3f53a5191..53f2092e1 100644 --- a/aspaper-server/paper-patches/features/0004-Delete-temp-folder-after-world-is-unloaded.patch +++ b/aspaper-server/paper-patches/features/0004-Delete-temp-folder-after-world-is-unloaded.patch @@ -5,13 +5,13 @@ Subject: [PATCH] Delete temp folder after world is unloaded diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 7a8399c5f5ea404e31b2a907c7324cab5f9b4699..c56d700bd879bcaf785cacad07c7562f391f9e18 100644 +index 10864a9cf4714ca57f999c1d9f28a298001fd911..460b72bfaf327f63c875c483f2a2aa98d176b294 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -1357,6 +1357,12 @@ public final class CraftServer implements Server { +@@ -1352,6 +1352,12 @@ public final class CraftServer implements Server { + handle.getChunkSource().close(save); io.papermc.paper.FeatureHooks.closeEntityManager(handle, save); // SPIGOT-6722: close entityManager // Paper - chunk system - handle.levelStorageAccess.close(); + + //ASP start - avoid temp storage leak during runtime + if(handle instanceof com.infernalsuite.asp.level.SlimeLevelInstance asp) { diff --git a/aspaper-server/paper-patches/features/0006-World-overrides.patch b/aspaper-server/paper-patches/features/0006-World-overrides.patch index 8e3cb747c..c6078298e 100644 --- a/aspaper-server/paper-patches/features/0006-World-overrides.patch +++ b/aspaper-server/paper-patches/features/0006-World-overrides.patch @@ -1,41 +1,36 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: David -Date: Thu, 18 Sep 2025 20:28:39 +0200 +Date: Sat, 4 Apr 2026 11:55:18 +0200 Subject: [PATCH] World overrides diff --git a/src/main/java/io/papermc/paper/world/PaperWorldLoader.java b/src/main/java/io/papermc/paper/world/PaperWorldLoader.java -index f5e9dd5880681cf4c9b442fbd2e0e9aad1cfb804..6de0f58a8c1a08393276ecaba5b8e7e9640bdbf6 100644 +index cd3e7cc8cf083915de46e03d9b2aaea3003f48fb..7d4623ecf63c0b307a0101ae1dbbb2c85125853e 100644 --- a/src/main/java/io/papermc/paper/world/PaperWorldLoader.java +++ b/src/main/java/io/papermc/paper/world/PaperWorldLoader.java -@@ -3,6 +3,7 @@ package io.papermc.paper.world; - import com.google.common.io.Files; - import com.mojang.logging.LogUtils; - import com.mojang.serialization.Dynamic; -+import net.minecraft.core.Registry; - import net.minecraft.core.registries.Registries; - import net.minecraft.nbt.NbtException; - import net.minecraft.nbt.ReportedNbtException; -@@ -108,7 +109,21 @@ public record PaperWorldLoader(MinecraftServer server, String levelId) { - - // Loosely modeled on code in net.minecraft.server.Main - public void loadInitialWorlds() { -- for (final LevelStem stem : this.server.registryAccess().lookupOrThrow(Registries.LEVEL_STEM)) { +@@ -131,11 +131,24 @@ public record PaperWorldLoader(MinecraftServer server, String levelId) { + final var levelStemRegistry = this.server.registryAccess().lookupOrThrow(Registries.LEVEL_STEM); + final boolean hasWorldData = this.server.storageSource.hasWorldData(); + final LevelStem overworldStem = requireNonNull(levelStemRegistry.getValue(LevelStem.OVERWORLD), "Overworld stem missing"); +- this.loadInitialWorld(overworldStem, hasWorldData); ++ + //ASP start - overwrite vanilla worlds if needed -+ Registry registry = this.server.registryAccess().lookupOrThrow(Registries.LEVEL_STEM); -+ for (final LevelStem stem : registry) { -+ ResourceKey levelStemKey = registry.getResourceKey(stem).get(); -+ if(levelStemKey == LevelStem.NETHER && com.infernalsuite.asp.SlimeNMSBridgeImpl.instance().loadNetherOverride()) { -+ continue; -+ } ++ if(!com.infernalsuite.asp.SlimeNMSBridgeImpl.instance().loadOverworldOverride()) { ++ this.loadInitialWorld(overworldStem, hasWorldData); ++ } ++ + for (final LevelStem stem : levelStemRegistry) { + if (stem == overworldStem) { + continue; + } ++ ++ ResourceKey levelStemKey = levelStemRegistry.getResourceKey(stem).get(); + if(levelStemKey == LevelStem.END && com.infernalsuite.asp.SlimeNMSBridgeImpl.instance().loadEndOverride()) { + continue; + } + if(levelStemKey == LevelStem.OVERWORLD && com.infernalsuite.asp.SlimeNMSBridgeImpl.instance().loadOverworldOverride()) { + continue; + } -+ //ASP end - overwrite vanilla worlds if needed -+ - final WorldLoadingInfo info = this.getWorldInfo(this.levelId, stem); - this.migrateWorldFolder(info); - if (!info.enabled()) { + this.loadInitialWorld(stem, hasWorldData); + } + diff --git a/aspaper-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/CraftServer.java.patch b/aspaper-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/CraftServer.java.patch index 7e591c25d..46411ebe0 100644 --- a/aspaper-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/CraftServer.java.patch +++ b/aspaper-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/CraftServer.java.patch @@ -1,6 +1,6 @@ --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -1347,6 +_,8 @@ +@@ -1343,6 +_,8 @@ return false; } diff --git a/aspaper-server/src/main/java/com/infernalsuite/asp/SlimeNMSBridgeImpl.java b/aspaper-server/src/main/java/com/infernalsuite/asp/SlimeNMSBridgeImpl.java index c0433c4b2..67a3d4384 100644 --- a/aspaper-server/src/main/java/com/infernalsuite/asp/SlimeNMSBridgeImpl.java +++ b/aspaper-server/src/main/java/com/infernalsuite/asp/SlimeNMSBridgeImpl.java @@ -20,6 +20,7 @@ import net.minecraft.server.WorldLoader; import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.server.dedicated.DedicatedServerProperties; +import net.minecraft.world.Difficulty; import net.minecraft.world.level.gamerules.GameRules; import net.minecraft.world.level.gamerules.GameRuleMap; import net.minecraft.world.level.Level; @@ -27,8 +28,8 @@ import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.WorldOptions; import net.minecraft.world.level.storage.CommandStorage; -import net.minecraft.world.level.storage.DimensionDataStorage; import net.minecraft.world.level.storage.PrimaryLevelData; +import net.minecraft.world.level.storage.SavedDataStorage; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.bukkit.Bukkit; @@ -79,7 +80,7 @@ public boolean loadOverworldOverride() { // See MinecraftServer loading logic // Some stuff is needed when loading overworld world SlimeLevelInstance instance = ((SlimeInMemoryWorld) this.loadInstance(defaultWorld, Level.OVERWORLD)).getInstance(); - DimensionDataStorage worldpersistentdata = instance.getDataStorage(); + SavedDataStorage worldpersistentdata = instance.getDataStorage(); instance.getCraftServer().scoreboardManager = new org.bukkit.craftbukkit.scoreboard.CraftScoreboardManager(instance.getServer(), instance.getScoreboard()); instance.getServer().commandStorage = new CommandStorage(worldpersistentdata); @@ -170,7 +171,7 @@ public int getCurrentVersion() { public void registerWorld(SlimeLevelInstance server) { MinecraftServer mcServer = MinecraftServer.getServer(); - mcServer.initWorld(server, server.serverLevelData, server.serverLevelData.worldGenOptions()); + mcServer.initWorld(server); mcServer.addLevel(server); } @@ -210,14 +211,12 @@ private PrimaryLevelData createWorldData(SlimeWorld world) { MinecraftServer mcServer = MinecraftServer.getServer(); DedicatedServerProperties serverProps = ((DedicatedServer) mcServer).getProperties(); String worldName = world.getName(); - WorldLoader.DataLoadContext context = mcServer.worldLoaderContext; - LevelSettings worldsettings = new LevelSettings(worldName, serverProps.gameMode.get(), false, serverProps.difficulty.get(), - true, new GameRules(context.dataConfiguration().enabledFeatures(), GameRuleMap.of()), mcServer.worldLoaderContext.dataConfiguration()); + LevelSettings worldsettings = new LevelSettings(worldName, serverProps.gameMode.get(), new LevelSettings.DifficultySettings( + serverProps.difficulty.get(), serverProps.hardcore, false + ), true, mcServer.worldLoaderContext.dataConfiguration()); - WorldOptions worldoptions = new WorldOptions(0, false, false); - - PrimaryLevelData data = new PrimaryLevelData(worldsettings, worldoptions, PrimaryLevelData.SpecialWorldProperty.FLAT, Lifecycle.stable()); + PrimaryLevelData data = new PrimaryLevelData(worldsettings, PrimaryLevelData.SpecialWorldProperty.FLAT, Lifecycle.stable()); data.checkName(worldName); data.setModdedInfo(mcServer.getServerModName(), mcServer.getModdedStatus().shouldReportAsModified()); data.setInitialized(true); diff --git a/aspaper-server/src/main/java/com/infernalsuite/asp/level/ReadOnlyDimensionDataStorage.java b/aspaper-server/src/main/java/com/infernalsuite/asp/level/ReadOnlyDimensionDataStorage.java index 4397426de..f17727f8e 100644 --- a/aspaper-server/src/main/java/com/infernalsuite/asp/level/ReadOnlyDimensionDataStorage.java +++ b/aspaper-server/src/main/java/com/infernalsuite/asp/level/ReadOnlyDimensionDataStorage.java @@ -4,7 +4,7 @@ import net.minecraft.core.HolderLookup; import net.minecraft.world.level.saveddata.SavedData; import net.minecraft.world.level.saveddata.SavedDataType; -import net.minecraft.world.level.storage.DimensionDataStorage; +import net.minecraft.world.level.storage.SavedDataStorage; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -15,7 +15,7 @@ /* * This dimension data storage does not serialize and/or load from disk. */ -public class ReadOnlyDimensionDataStorage extends DimensionDataStorage { +public class ReadOnlyDimensionDataStorage extends SavedDataStorage { public ReadOnlyDimensionDataStorage(Path dataFolder, DataFixer fixerUpper, HolderLookup.Provider registries) { super(dataFolder, fixerUpper, registries); diff --git a/aspaper-server/src/main/java/com/infernalsuite/asp/level/SlimeLevelInstance.java b/aspaper-server/src/main/java/com/infernalsuite/asp/level/SlimeLevelInstance.java index 51a1c1b81..33377dd47 100644 --- a/aspaper-server/src/main/java/com/infernalsuite/asp/level/SlimeLevelInstance.java +++ b/aspaper-server/src/main/java/com/infernalsuite/asp/level/SlimeLevelInstance.java @@ -17,6 +17,9 @@ import com.infernalsuite.asp.api.world.properties.SlimeProperties; import com.infernalsuite.asp.api.world.properties.SlimePropertyMap; import com.mojang.logging.LogUtils; +import io.papermc.paper.world.PaperWorldLoader; +import io.papermc.paper.world.saveddata.PaperLevelOverrides; +import io.papermc.paper.world.saveddata.PaperWorldPDC; import net.kyori.adventure.nbt.BinaryTag; import net.kyori.adventure.nbt.CompoundBinaryTag; import net.kyori.adventure.util.TriState; @@ -25,6 +28,7 @@ import net.minecraft.core.Holder; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtOps; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.Identifier; import net.minecraft.server.MinecraftServer; @@ -40,7 +44,10 @@ import net.minecraft.world.level.chunk.storage.RegionStorageInfo; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.gamerules.GameRules; +import net.minecraft.world.level.levelgen.WorldGenSettings; +import net.minecraft.world.level.levelgen.WorldOptions; import net.minecraft.world.level.storage.LevelData; +import net.minecraft.world.level.storage.LevelResource; import net.minecraft.world.level.storage.LevelStorageSource; import net.minecraft.world.level.storage.PrimaryLevelData; import net.minecraft.world.level.validation.DirectoryValidator; @@ -69,14 +76,15 @@ public class SlimeLevelInstance extends ServerLevel { - public static LevelStorageSource CUSTOM_LEVEL_STORAGE; + public static LevelStorageSource.LevelStorageAccess CUSTOM_LEVEL_STORAGE_ACCESS; private static final Logger LOGGER = LogUtils.getClassLogger(); static { try { Path path = Files.createTempDirectory("swm-" + UUID.randomUUID().toString().substring(0, 5)).toAbsolutePath(); DirectoryValidator directoryvalidator = LevelStorageSource.parseValidator(path.resolve("allowed_symlinks.txt")); - CUSTOM_LEVEL_STORAGE = new LevelStorageSource(path, path, directoryvalidator, DataFixers.getDataFixer()); + CUSTOM_LEVEL_STORAGE_ACCESS = new LevelStorageSource(path, path, directoryvalidator, DataFixers.getDataFixer()) + .createAccess("slime"); FileUtils.forceDeleteOnExit(path.toFile()); @@ -91,14 +99,49 @@ public class SlimeLevelInstance extends ServerLevel { private final Object saveLock = new Object(); public SlimeLevelInstance(SlimeBootstrap slimeBootstrap, PrimaryLevelData primaryLevelData, - ResourceKey worldKey, - ResourceKey dimensionKey, LevelStem worldDimension, + ResourceKey dimensionKey, + ResourceKey levelStemKey, LevelStem levelStem, org.bukkit.World.Environment environment) throws IOException { + WorldGenSettings settings = WorldGenSettings.of( + new WorldOptions(WorldOptions.randomSeed(), false, false), + MinecraftServer.getServer().registryAccess() + ); + ConcurrentMap initialExtraData = slimeBootstrap.initial().getExtraData(); + PaperWorldPDC pdc = null; + if(initialExtraData.containsKey("BukkitValues")) { + pdc = PaperWorldPDC.CODEC.parse(NbtOps.INSTANCE, Converter.convertTag(initialExtraData.get("BukkitValues"))) + .getOrThrow(); + } - super(slimeBootstrap, MinecraftServer.getServer(), MinecraftServer.getServer().executor, - CUSTOM_LEVEL_STORAGE.createAccess(slimeBootstrap.initial().getName() + UUID.randomUUID(), dimensionKey), - primaryLevelData, worldKey, worldDimension, false, 0, - Collections.emptyList(), true, null, environment, null, null); + final PaperWorldLoader.LoadedWorldData data = new PaperWorldLoader.LoadedWorldData( + slimeBootstrap.initial().getName(), + UUID.randomUUID(), + pdc, + PaperLevelOverrides.createFromLiveLevelData(primaryLevelData) + ); + data.levelOverrides().attach(primaryLevelData, dimensionKey); + + super( + slimeBootstrap, + MinecraftServer.getServer(), + MinecraftServer.getServer().executor, + CUSTOM_LEVEL_STORAGE_ACCESS, + settings, + dimensionKey, + levelStem, + + false, + 0L, + Collections.emptyList(), + true, + levelStemKey, + + environment, + null, + null, + new ReadOnlyDimensionDataStorage(CUSTOM_LEVEL_STORAGE_ACCESS.getDimensionPath(dimensionKey), MinecraftServer.getServer().getFixerUpper(), MinecraftServer.getServer().registryAccess()), + data + ); this.slimeInstance = new SlimeInMemoryWorld(slimeBootstrap, this); @@ -122,19 +165,14 @@ public SlimeLevelInstance(SlimeBootstrap slimeBootstrap, PrimaryLevelData primar super.chunkSource.setSpawnSettings(propertyMap.getValue(SlimeProperties.ALLOW_MONSTERS), propertyMap.getValue(SlimeProperties.ALLOW_ANIMALS)); - ConcurrentMap extraData = this.slimeInstance.getExtraData(); - //Attempt to read PDC - if (extraData.containsKey("BukkitValues")) { - getWorld().readBukkitValues(Converter.convertTag(extraData.get("BukkitValues"))); - } propertyMap.getOptionalValue(SlimeProperties.PVP) .ifPresent(val -> getGameRules().set(GameRules.PVP, val, this)); this.entityDataController = new SlimeEntityDataLoader( new ca.spottedleaf.moonrise.patches.chunk_system.io.datacontroller.EntityDataController.EntityRegionFileStorage( - new RegionStorageInfo(levelStorageAccess.getLevelId(), worldKey, "entities"), - levelStorageAccess.getDimensionPath(worldKey).resolve("entities"), + new RegionStorageInfo(CUSTOM_LEVEL_STORAGE_ACCESS.getLevelId(), dimensionKey, "entities"), + CUSTOM_LEVEL_STORAGE_ACCESS.getDimensionPath(dimensionKey).resolve("entities"), MinecraftServer.getServer().forceSynchronousWrites() ), this.chunkTaskScheduler, @@ -175,8 +213,6 @@ public Future save() { Bukkit.getPluginManager().callEvent(new WorldSaveEvent(getWorld())); //this.getChunkSource().save(forceSave); - this.serverLevelData.setCustomBossEvents(MinecraftServer.getServer().getCustomBossEvents().save(MinecraftServer.getServer().registryAccess())); - if (MinecraftServer.getServer().isStopped()) { // Make sure the world gets saved before stopping the server by running it from the main thread saveInternal().get(); // Async wait for it to finish } else { @@ -221,7 +257,7 @@ public ChunkDataLoadTask getLoadTask(ChunkLoadTask task, ChunkTaskScheduler sche public void deleteTempFiles() { WORLD_SAVER_SERVICE.execute(() -> { - Path path = this.levelStorageAccess.levelDirectory.path(); + Path path = CUSTOM_LEVEL_STORAGE_ACCESS.getDimensionPath(this.dimension()); try { // We do this manually and not use the deleteLevel function as it would cause a level deleted message // to appear in the log which might be confusing for our users @@ -240,7 +276,7 @@ public void deleteTempFiles() { if (exception != null) { throw exception; } else { - if (dir.equals(levelStorageAccess.levelDirectory.path())) { + if (dir.equals(CUSTOM_LEVEL_STORAGE_ACCESS.getDimensionPath(dimension()))) { Files.deleteIfExists(path); } diff --git a/aspaper-server/src/main/java/com/infernalsuite/asp/level/chunk/NMSSlimeChunk.java b/aspaper-server/src/main/java/com/infernalsuite/asp/level/chunk/NMSSlimeChunk.java index 8165f80aa..1dd875495 100644 --- a/aspaper-server/src/main/java/com/infernalsuite/asp/level/chunk/NMSSlimeChunk.java +++ b/aspaper-server/src/main/java/com/infernalsuite/asp/level/chunk/NMSSlimeChunk.java @@ -52,12 +52,12 @@ public void updatePersistentDataContainer() { @Override public int getX() { - return chunk.getPos().x; + return chunk.getPos().x(); } @Override public int getZ() { - return chunk.getPos().z; + return chunk.getPos().z(); } @Override diff --git a/aspaper-server/src/main/java/com/infernalsuite/asp/level/chunk/SlimeChunkConverter.java b/aspaper-server/src/main/java/com/infernalsuite/asp/level/chunk/SlimeChunkConverter.java index 50a733388..bb992df3a 100644 --- a/aspaper-server/src/main/java/com/infernalsuite/asp/level/chunk/SlimeChunkConverter.java +++ b/aspaper-server/src/main/java/com/infernalsuite/asp/level/chunk/SlimeChunkConverter.java @@ -51,14 +51,14 @@ public class SlimeChunkConverter { static { PalettedContainerFactory factory = PalettedContainerFactory.create(net.minecraft.server.MinecraftServer.getServer().registryAccess()); { - PalettedContainer empty = new PalettedContainer<>(Blocks.AIR.defaultBlockState(),factory.blockStatesStrategy(), null); + PalettedContainer empty = new PalettedContainer<>(Blocks.AIR.defaultBlockState(),factory.blockStatesStrategy()); Tag tag = factory.blockStatesContainerCodec().encodeStart(NbtOps.INSTANCE, empty).getOrThrow(); EMPTY_BLOCK_STATE_PALETTE = Converter.convertTag(tag); } { Registry biomes = net.minecraft.server.MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); - PalettedContainer> empty = new PalettedContainer<>(biomes.get(Biomes.PLAINS).orElseThrow(), factory.biomeStrategy(), null); + PalettedContainer> empty = new PalettedContainer<>(biomes.get(Biomes.PLAINS).orElseThrow(), factory.biomeStrategy()); Tag tag = factory.biomeContainerRWCodec().encodeStart(NbtOps.INSTANCE, empty).getOrThrow(); EMPTY_BIOME_PALETTE = Converter.convertTag(tag); @@ -106,7 +106,7 @@ public static SlimeChunkLevel deserializeSlimeChunk(SlimeLevelInstance instance, }); blockPalette = dataresult.getOrThrow(); // todo proper logging } else { - blockPalette = new PalettedContainer<>(Blocks.AIR.defaultBlockState(), instance.palettedContainerFactory().blockStatesStrategy(), null); + blockPalette = new PalettedContainer<>(Blocks.AIR.defaultBlockState(), instance.palettedContainerFactory().blockStatesStrategy()); } PalettedContainer> biomePalette; @@ -117,7 +117,7 @@ public static SlimeChunkLevel deserializeSlimeChunk(SlimeLevelInstance instance, }); biomePalette = dataresult.getOrThrow(); // todo proper logging } else { - biomePalette = new PalettedContainer<>(biomeRegistry.get(Biomes.PLAINS).orElseThrow(), instance.palettedContainerFactory().biomeStrategy(), null); + biomePalette = new PalettedContainer<>(biomeRegistry.get(Biomes.PLAINS).orElseThrow(), instance.palettedContainerFactory().biomeStrategy()); } if (sectionId < sections.length) { diff --git a/aspaper-server/src/main/java/com/infernalsuite/asp/util/NmsUtil.java b/aspaper-server/src/main/java/com/infernalsuite/asp/util/NmsUtil.java index c62d4c1d1..7485f9f85 100644 --- a/aspaper-server/src/main/java/com/infernalsuite/asp/util/NmsUtil.java +++ b/aspaper-server/src/main/java/com/infernalsuite/asp/util/NmsUtil.java @@ -47,6 +47,6 @@ public static void runSyncAndWait(Runnable runnable) { } public static NewChunkHolder getChunkHolder(LevelChunk chunk) { - return chunk.level.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(chunk.getPos().x, chunk.getPos().z); + return chunk.level.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(chunk.getPos().x(), chunk.getPos().z()); } } diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 622214173..363e9de87 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -5,6 +5,7 @@ plugins { group = "com.infernalsuite" repositories { + maven("https://repo.papermc.io/repository/maven-public/") mavenLocal() mavenCentral() gradlePluginPortal() diff --git a/buildSrc/src/main/kotlin/constants.kt b/buildSrc/src/main/kotlin/constants.kt index 6f6fe73c9..2abb70b36 100644 --- a/buildSrc/src/main/kotlin/constants.kt +++ b/buildSrc/src/main/kotlin/constants.kt @@ -1,2 +1,2 @@ -const val JAVA_VERSION = 21 +const val JAVA_VERSION = 25 const val PAPER_MAVEN_PUBLIC_URL = "https://repo.papermc.io/repository/maven-public/" \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 148c39a05..8095350a4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,10 +1,10 @@ group=com.infernalsuite.asp aspApiVersion=4.2.0-SNAPSHOT -apiVersion=1.21.11 -version=1.21.11-R0.1-SNAPSHOT -mcVersion=1.21.11 +apiVersion=26.1.1 +version=26.1.1.build.8-alpha +mcVersion=26.1.1 -paperRef=6d5b910ff0b3c9a9d164f3d90d60a4f2467b510f +paperRef=f6d27019a96211cbb2b9b006fb1c0a7625ecdab8 org.gradle.caching=true org.gradle.parallel=true diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6ed94a33e..45a2ce363 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,11 +1,11 @@ [versions] -adventure = "4.24.0" -annotations = "26.0.1" +adventure = "4.26.1" +annotations = "1.0.0" autoservice = "1.1.1" blossom = "2.1.0" bstats = "3.1.0" cloud-core = "2.0.0" -cloud-minecraft = "2.0.0-beta.14" +cloud-minecraft = "2.0.0-SNAPSHOT" configurate = "4.1.2" indra-git = "3.1.3" gradle-profiles = "0.54.0" @@ -15,7 +15,7 @@ lettuce = "6.5.1.RELEASE" lombok = "1.18.36" lombok-plugin = "8.11" mongo = "5.2.1" -paperweight = "2.0.0-beta.19" +paperweight = "2.0.0-SNAPSHOT" plugin-yml-paper = "0.6.0" shadow = "9.2.2" slf4j = "2.0.16" @@ -33,7 +33,7 @@ shadow = { id = "com.gradleup.shadow", version.ref = "shadow" } [libraries] adventure-nbt = { module = "net.kyori:adventure-nbt", version.ref = "adventure" } -annotations = { module = "org.jetbrains:annotations", version.ref = "annotations" } +annotations = { module = "org.jspecify:jspecify", version.ref = "annotations" } auto-service = { module = "com.google.auto.service:auto-service", version.ref = "autoservice" } auto-service-annotations = { module = "com.google.auto.service:auto-service-annotations", version.ref = "autoservice" } bstats = { module = "org.bstats:bstats-bukkit", version.ref = "bstats" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index bad7c2462..c61a118f7 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/settings.gradle.kts b/settings.gradle.kts index d38dbeaf4..bd4bfc38e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,14 +1,14 @@ pluginManagement { repositories { + maven("https://repo.papermc.io/repository/maven-public/") mavenLocal() mavenCentral() gradlePluginPortal() - maven("https://repo.papermc.io/repository/maven-public/") } } plugins { - id("org.gradle.toolchains.foojay-resolver-convention") version "0.9.0" + id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" } rootProject.name = "ASPaper" From 9a5ae12e603c54a1401a50468b52706abe87b38e Mon Sep 17 00:00:00 2001 From: David Date: Wed, 22 Apr 2026 00:55:58 +0200 Subject: [PATCH 2/9] feat: 26.1.2 --- aspaper-api/build.gradle.kts.patch | 4 +-- ...Prevent-config-disk-io-on-world-load.patch | 14 ++++---- ...-temp-folder-after-world-is-unloaded.patch | 2 +- ...Prevent-config-disk-io-on-world-load.patch | 34 +++++++++++-------- .../features/0006-World-overrides.patch | 14 ++++---- .../asp/config/SlimePaperWorldConfig.java | 4 +-- gradle.properties | 8 ++--- 7 files changed, 42 insertions(+), 38 deletions(-) diff --git a/aspaper-api/build.gradle.kts.patch b/aspaper-api/build.gradle.kts.patch index 67dd5744d..81953aa43 100644 --- a/aspaper-api/build.gradle.kts.patch +++ b/aspaper-api/build.gradle.kts.patch @@ -6,8 +6,8 @@ dependencies { + api(project(":api")) //ASP // api dependencies are listed transitively to API consumers - api("com.google.guava:guava:33.3.1-jre") - api("com.google.code.gson:gson:2.11.0") + api("com.google.guava:guava:33.5.0-jre") + api("com.google.code.gson:gson:2.13.2") @@ -91,7 +_,7 @@ testRuntimeOnly("org.junit.platform:junit-platform-launcher:6.0.3") } diff --git a/aspaper-server/minecraft-patches/features/0002-Prevent-config-disk-io-on-world-load.patch b/aspaper-server/minecraft-patches/features/0002-Prevent-config-disk-io-on-world-load.patch index c4fbeb228..2f1764f22 100644 --- a/aspaper-server/minecraft-patches/features/0002-Prevent-config-disk-io-on-world-load.patch +++ b/aspaper-server/minecraft-patches/features/0002-Prevent-config-disk-io-on-world-load.patch @@ -5,28 +5,28 @@ Subject: [PATCH] Prevent config disk io on world load diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index 785e7784c8f6e2c29c7f363dd700e2bbd0fe15f4..328366d6c7f655dbc97b86608574eb421ce998a8 100644 +index 58ed69b501daa445747050ae3c2532292bf2c386..c0873f9cec8b5877157b7f8803b617465cb0876b 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java @@ -659,7 +659,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet savedDataStorage.set(io.papermc.paper.world.saveddata.PaperWorldPDC.TYPE, loadedWorldData.pdc() == null ? io.papermc.paper.world.saveddata.PaperWorldPDC.TYPE.constructor().get() : loadedWorldData.pdc()); final GameRules gameRules = new GameRules(server.getWorldData().enabledFeatures(), savedDataStorage.computeIfAbsent(net.minecraft.world.level.gamerules.GameRuleMap.TYPE)); this.gameRules = gameRules; -- super(levelData, dimension, server.registryAccess(), levelStem.type(), false, isDebug, biomeZoomSeed, server.getMaxChainedNeighborUpdates(), loadedWorldData.bukkitName(), gen, biomeProvider, env, spigotConfig -> server.paperConfigurations.createWorldConfig(io.papermc.paper.configuration.PaperConfigurations.createWorldContextMap(server.storageSource.getDimensionPath(dimension), loadedWorldData.bukkitName(), dimension.identifier(), spigotConfig, server.registryAccess(), gameRules))); // Paper - create paper world configs -+ super(levelData, dimension, server.registryAccess(), levelStem.type(), false, isDebug, biomeZoomSeed, server.getMaxChainedNeighborUpdates(), loadedWorldData.bukkitName(), gen, biomeProvider, env, spigotConfig -> bootstrap != null ? com.infernalsuite.asp.config.SlimePaperWorldConfig.initializeOrGet() : server.paperConfigurations.createWorldConfig(io.papermc.paper.configuration.PaperConfigurations.createWorldContextMap(server.storageSource.getDimensionPath(dimension), loadedWorldData.bukkitName(), dimension.identifier(), spigotConfig, server.registryAccess(), gameRules))); // Paper - create paper world configs //ASP - Optimize world config +- super(levelData, dimension, server.registryAccess(), levelStem.type(), false, isDebug, biomeZoomSeed, server.getMaxChainedNeighborUpdates(), loadedWorldData.bukkitName(), gen, biomeProvider, env, spigotConfig -> server.paperConfigurations.createWorldConfig(io.papermc.paper.configuration.PaperConfigurations.createWorldContextMap(server.storageSource.getDimensionPath(dimension), dimension.identifier(), spigotConfig, server.registryAccess(), gameRules)), executor); // Paper - create paper world configs // Paper - Anti-Xray - Pass executor ++ super(levelData, dimension, server.registryAccess(), levelStem.type(), false, isDebug, biomeZoomSeed, server.getMaxChainedNeighborUpdates(), loadedWorldData.bukkitName(), gen, biomeProvider, env, spigotConfig -> bootstrap != null ? com.infernalsuite.asp.config.SlimePaperWorldConfig.initializeOrGet() : server.paperConfigurations.createWorldConfig(io.papermc.paper.configuration.PaperConfigurations.createWorldContextMap(server.storageSource.getDimensionPath(dimension), dimension.identifier(), spigotConfig, server.registryAccess(), gameRules)), executor); // Paper - create paper world configs // Paper - Anti-Xray - Pass executor //ASP - Optimize world config this.weatherData = savedDataStorage.computeIfAbsent(WeatherData.TYPE); this.weatherData.setLevel(this); this.typeKey = typeKey; diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java -index 4ac838fa756c65f36a343224cabbee2b5d5ea110..fe49d1cb9f4062061e3f55384218842cbb923e12 100644 +index e34e901dce06c6bc6060418593010dcfb38e9396..e1fd30fc9b17d241c421c66114c9611b2979053e 100644 --- a/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java -@@ -846,7 +846,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl +@@ -849,7 +849,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl this.maxSectionY = this.maxY >> 4; this.sectionsCount = this.maxSectionY - this.minSectionY + 1; // Paper end - getblock optimisations - cache world height/sections -- this.spigotConfig = new org.spigotmc.SpigotWorldConfig(bukkitName); // Spigot -+ this.spigotConfig = new org.spigotmc.SpigotWorldConfig(bukkitName, !(this instanceof com.infernalsuite.asp.level.SlimeLevelInstance)); // Spigot //ASP - Improve Slime IO +- this.spigotConfig = new org.spigotmc.SpigotWorldConfig(bukkitName, CraftNamespacedKey.fromMinecraft(dimension.identifier())); // Spigot ++ this.spigotConfig = new org.spigotmc.SpigotWorldConfig(bukkitName, CraftNamespacedKey.fromMinecraft(dimension.identifier()), !(this instanceof com.infernalsuite.asp.level.SlimeLevelInstance)); // Spigot //ASP - Improve Slime IO this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper - create paper world config this.generator = generator; this.world = new CraftWorld((ServerLevel) this, generator, biomeProvider, environment); diff --git a/aspaper-server/paper-patches/features/0004-Delete-temp-folder-after-world-is-unloaded.patch b/aspaper-server/paper-patches/features/0004-Delete-temp-folder-after-world-is-unloaded.patch index 53f2092e1..71f3da933 100644 --- a/aspaper-server/paper-patches/features/0004-Delete-temp-folder-after-world-is-unloaded.patch +++ b/aspaper-server/paper-patches/features/0004-Delete-temp-folder-after-world-is-unloaded.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Delete temp folder after world is unloaded diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 10864a9cf4714ca57f999c1d9f28a298001fd911..460b72bfaf327f63c875c483f2a2aa98d176b294 100644 +index 324352276da542632858e68eac3c39a4542e09db..f4da118fbb65474fca70e7a1211e69fa2ff6d35b 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -1352,6 +1352,12 @@ public final class CraftServer implements Server { diff --git a/aspaper-server/paper-patches/features/0005-Prevent-config-disk-io-on-world-load.patch b/aspaper-server/paper-patches/features/0005-Prevent-config-disk-io-on-world-load.patch index 43df3051a..5d159caf8 100644 --- a/aspaper-server/paper-patches/features/0005-Prevent-config-disk-io-on-world-load.patch +++ b/aspaper-server/paper-patches/features/0005-Prevent-config-disk-io-on-world-load.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Prevent config disk io on world load diff --git a/src/main/java/org/spigotmc/SpigotConfig.java b/src/main/java/org/spigotmc/SpigotConfig.java -index c935d75b83338ce41507e9be11153dd1c4052cb6..3feaba566c22b1e93b2b4edc7786723a2f9e28c6 100644 +index 025ec3f3e84a3367b4d709c8c3ecd98f6dfecab4..182de15ca133fc42bf703ee9d116302bf5207c0d 100644 --- a/src/main/java/org/spigotmc/SpigotConfig.java +++ b/src/main/java/org/spigotmc/SpigotConfig.java @@ -79,7 +79,12 @@ public class SpigotConfig { @@ -35,37 +35,41 @@ index c935d75b83338ce41507e9be11153dd1c4052cb6..3feaba566c22b1e93b2b4edc7786723a Bukkit.getLogger().log(Level.SEVERE, "Could not save " + SpigotConfig.CONFIG_FILE, ex); } diff --git a/src/main/java/org/spigotmc/SpigotWorldConfig.java b/src/main/java/org/spigotmc/SpigotWorldConfig.java -index 43c6240ec2855c0f668ce04de29d22a223d2612f..c6f398977149c8b35454fb79f099322c36d557d5 100644 +index 339832e312578ee385bbf3c9d5c131435abe7d7a..3924ba62c2df8372b67f6666f0c02d007ea3021c 100644 --- a/src/main/java/org/spigotmc/SpigotWorldConfig.java +++ b/src/main/java/org/spigotmc/SpigotWorldConfig.java -@@ -10,17 +10,28 @@ public class SpigotWorldConfig { - private final YamlConfiguration config; +@@ -15,13 +15,23 @@ public class SpigotWorldConfig { private boolean verbose; -+ // ASP start - Improve Slime IO - public SpigotWorldConfig(String worldName) { -+ this(worldName, true); + public SpigotWorldConfig(String legacyWorldName, Key worldKey) { ++ // ASP start - Improve Slime IO ++ this(legacyWorldName, worldKey, true); + } -+ // ASP end - Improve Slime IO + -+ public SpigotWorldConfig(String worldName, boolean saveOnLoad) { // ASP - Improve Slime IO - this.worldName = worldName; ++ public SpigotWorldConfig(String legacyWorldName, Key worldKey, boolean saveOnLoad) { ++ // ASP end - Improve Slime IO + this.legacyWorldName = legacyWorldName; + this.worldName = worldKey.asString(); this.config = SpigotConfig.config; - this.init(); -+ this.init(saveOnLoad); // ASP - Improve Slime IO ++ this.init(saveOnLoad); // ASP - Improve Slime IO } - -+ // ASP start - Improve Slime IO +- public void init() { ++ // ASP start - Improve Slime IO + init(true); + } + public void init(boolean saveOnLoad) { -+ // ASP end - Improve Slime IO ++ // ASP end - Improve Slime IO this.verbose = this.getBoolean("verbose", false); // Paper + if (SpigotConfig.version <= 12) { + ConfigurationSection section = this.config.getConfigurationSection("world-settings." + this.legacyWorldName); +@@ -33,7 +43,7 @@ public class SpigotWorldConfig { + } this.log("-------- World Settings For [" + this.worldName + "] --------"); - SpigotConfig.readConfig(SpigotWorldConfig.class, this); -+ SpigotConfig.readConfig(SpigotWorldConfig.class, this, saveOnLoad); // ASP - Improve Slime IO ++ SpigotConfig.readConfig(SpigotWorldConfig.class, this, saveOnLoad); } private void log(String s) { diff --git a/aspaper-server/paper-patches/features/0006-World-overrides.patch b/aspaper-server/paper-patches/features/0006-World-overrides.patch index c6078298e..9bcc53e1c 100644 --- a/aspaper-server/paper-patches/features/0006-World-overrides.patch +++ b/aspaper-server/paper-patches/features/0006-World-overrides.patch @@ -1,11 +1,11 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: David -Date: Sat, 4 Apr 2026 11:55:18 +0200 +Date: Thu, 18 Sep 2025 20:28:39 +0200 Subject: [PATCH] World overrides diff --git a/src/main/java/io/papermc/paper/world/PaperWorldLoader.java b/src/main/java/io/papermc/paper/world/PaperWorldLoader.java -index cd3e7cc8cf083915de46e03d9b2aaea3003f48fb..7d4623ecf63c0b307a0101ae1dbbb2c85125853e 100644 +index cd3e7cc8cf083915de46e03d9b2aaea3003f48fb..64fcc1333b9e72ff02176daaf85290935cb21082 100644 --- a/src/main/java/io/papermc/paper/world/PaperWorldLoader.java +++ b/src/main/java/io/papermc/paper/world/PaperWorldLoader.java @@ -131,11 +131,24 @@ public record PaperWorldLoader(MinecraftServer server, String levelId) { @@ -13,24 +13,24 @@ index cd3e7cc8cf083915de46e03d9b2aaea3003f48fb..7d4623ecf63c0b307a0101ae1dbbb2c8 final boolean hasWorldData = this.server.storageSource.hasWorldData(); final LevelStem overworldStem = requireNonNull(levelStemRegistry.getValue(LevelStem.OVERWORLD), "Overworld stem missing"); - this.loadInitialWorld(overworldStem, hasWorldData); -+ + //ASP start - overwrite vanilla worlds if needed + if(!com.infernalsuite.asp.SlimeNMSBridgeImpl.instance().loadOverworldOverride()) { + this.loadInitialWorld(overworldStem, hasWorldData); + } -+ ++ //ASP end - overwrite vanilla worlds if needed for (final LevelStem stem : levelStemRegistry) { if (stem == overworldStem) { continue; } -+ ++ //ASP start - overwrite vanilla worlds if needed + ResourceKey levelStemKey = levelStemRegistry.getResourceKey(stem).get(); -+ if(levelStemKey == LevelStem.END && com.infernalsuite.asp.SlimeNMSBridgeImpl.instance().loadEndOverride()) { ++ if(levelStemKey == LevelStem.NETHER && com.infernalsuite.asp.SlimeNMSBridgeImpl.instance().loadNetherOverride()) { + continue; + } -+ if(levelStemKey == LevelStem.OVERWORLD && com.infernalsuite.asp.SlimeNMSBridgeImpl.instance().loadOverworldOverride()) { ++ if(levelStemKey == LevelStem.END && com.infernalsuite.asp.SlimeNMSBridgeImpl.instance().loadEndOverride()) { + continue; + } ++ //ASP end - overwrite vanilla worlds if needed this.loadInitialWorld(stem, hasWorldData); } diff --git a/aspaper-server/src/main/java/com/infernalsuite/asp/config/SlimePaperWorldConfig.java b/aspaper-server/src/main/java/com/infernalsuite/asp/config/SlimePaperWorldConfig.java index f2f3fcac8..771162adb 100644 --- a/aspaper-server/src/main/java/com/infernalsuite/asp/config/SlimePaperWorldConfig.java +++ b/aspaper-server/src/main/java/com/infernalsuite/asp/config/SlimePaperWorldConfig.java @@ -3,6 +3,7 @@ import io.papermc.paper.configuration.Configurations; import io.papermc.paper.configuration.PaperConfigurations; import io.papermc.paper.configuration.WorldConfiguration; +import net.kyori.adventure.key.Key; import net.minecraft.resources.Identifier; import net.minecraft.server.MinecraftServer; import net.minecraft.world.level.gamerules.GameRules; @@ -30,7 +31,7 @@ private static void initialize( PaperConfigurations paperConfigurations, MinecraftServer server ) { - SpigotWorldConfig spigotWorldConfig = new SpigotWorldConfig("asp-slimeworld"); + SpigotWorldConfig spigotWorldConfig = new SpigotWorldConfig("asp-slimeworld", Key.key(FAKE_WORLD_KEY.getNamespace(), FAKE_WORLD_KEY.getPath()), false); GameRules gameRules = new GameRules(server.worldLoaderContext.dataConfiguration().enabledFeatures()); @@ -43,7 +44,6 @@ private static void initialize( */ Path.of("config", "advancedslimepaper"), - "asp-slimeworld", FAKE_WORLD_KEY, spigotWorldConfig, server.registryAccess(), diff --git a/gradle.properties b/gradle.properties index 8095350a4..d54b27786 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,10 +1,10 @@ group=com.infernalsuite.asp aspApiVersion=4.2.0-SNAPSHOT -apiVersion=26.1.1 -version=26.1.1.build.8-alpha -mcVersion=26.1.1 +apiVersion=26.1.2 +version=26.1.2.build.19-alpha +mcVersion=26.1.2 -paperRef=f6d27019a96211cbb2b9b006fb1c0a7625ecdab8 +paperRef=1d14197790a353a58aced4333cd4fe4041184a21 org.gradle.caching=true org.gradle.parallel=true From 7e01bbaad4d34ffb3810a949bcd8cab5cfbb5bc6 Mon Sep 17 00:00:00 2001 From: David Date: Wed, 22 Apr 2026 01:38:25 +0200 Subject: [PATCH 3/9] feat: papermc antixray support --- .../asp/level/chunk/SlimeChunkConverter.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/aspaper-server/src/main/java/com/infernalsuite/asp/level/chunk/SlimeChunkConverter.java b/aspaper-server/src/main/java/com/infernalsuite/asp/level/chunk/SlimeChunkConverter.java index bb992df3a..4242b7413 100644 --- a/aspaper-server/src/main/java/com/infernalsuite/asp/level/chunk/SlimeChunkConverter.java +++ b/aspaper-server/src/main/java/com/infernalsuite/asp/level/chunk/SlimeChunkConverter.java @@ -101,12 +101,20 @@ public static SlimeChunkLevel deserializeSlimeChunk(SlimeLevelInstance instance, PalettedContainer blockPalette; if (slimeSection.getBlockStatesTag() != null) { - DataResult> dataresult = instance.palettedContainerFactory().blockStatesContainerCodec().parse(NbtOps.INSTANCE, Converter.convertTag(slimeSection.getBlockStatesTag())).promotePartial((s) -> { + + //If Paper AntiXray is not ready during upgrading, comment these three lines and uncomment the one below. + final BlockState[] presetBlockStates = instance.chunkPacketBlockController.getPresetBlockStates(instance, pos, sectionId); // Paper - Anti-Xray - Add preset block states + final Codec> antiXrayBlockStateCodec = presetBlockStates == null ? instance.palettedContainerFactory().blockStatesContainerCodec() + : PalettedContainer.codecRW(BlockState.CODEC, instance.palettedContainerFactory().blockStatesStrategy(), net.minecraft.world.level.block.Blocks.AIR.defaultBlockState(), presetBlockStates); // Paper - Anti-Xray + //For upgrading purposes only + //final Codec> antiXrayBlockStateCodec = instance.palettedContainerFactory().blockStatesContainerCodec(); + + DataResult> dataresult = antiXrayBlockStateCodec.parse(NbtOps.INSTANCE, Converter.convertTag(slimeSection.getBlockStatesTag())).promotePartial((s) -> { System.out.println("Recoverable error when parsing section " + x + "," + z + ": " + s); // todo proper logging }); blockPalette = dataresult.getOrThrow(); // todo proper logging } else { - blockPalette = new PalettedContainer<>(Blocks.AIR.defaultBlockState(), instance.palettedContainerFactory().blockStatesStrategy()); + blockPalette = instance.palettedContainerFactory().createForBlockStates(instance, pos, instance.getSectionYFromSectionIndex(sectionId)); } PalettedContainer> biomePalette; @@ -117,7 +125,7 @@ public static SlimeChunkLevel deserializeSlimeChunk(SlimeLevelInstance instance, }); biomePalette = dataresult.getOrThrow(); // todo proper logging } else { - biomePalette = new PalettedContainer<>(biomeRegistry.get(Biomes.PLAINS).orElseThrow(), instance.palettedContainerFactory().biomeStrategy()); + biomePalette = instance.palettedContainerFactory().createForBiomes(); } if (sectionId < sections.length) { From bf25555a39e2e6d46064f049b4a733ed2587320b Mon Sep 17 00:00:00 2001 From: David Date: Wed, 22 Apr 2026 01:39:18 +0200 Subject: [PATCH 4/9] fix: illegal chunk container methods --- .../infernalsuite/asp/level/chunk/SlimeChunkConverter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aspaper-server/src/main/java/com/infernalsuite/asp/level/chunk/SlimeChunkConverter.java b/aspaper-server/src/main/java/com/infernalsuite/asp/level/chunk/SlimeChunkConverter.java index 4242b7413..7e586183c 100644 --- a/aspaper-server/src/main/java/com/infernalsuite/asp/level/chunk/SlimeChunkConverter.java +++ b/aspaper-server/src/main/java/com/infernalsuite/asp/level/chunk/SlimeChunkConverter.java @@ -51,14 +51,14 @@ public class SlimeChunkConverter { static { PalettedContainerFactory factory = PalettedContainerFactory.create(net.minecraft.server.MinecraftServer.getServer().registryAccess()); { - PalettedContainer empty = new PalettedContainer<>(Blocks.AIR.defaultBlockState(),factory.blockStatesStrategy()); + PalettedContainer empty = new PalettedContainer<>(Blocks.AIR.defaultBlockState(),factory.blockStatesStrategy(), null); Tag tag = factory.blockStatesContainerCodec().encodeStart(NbtOps.INSTANCE, empty).getOrThrow(); EMPTY_BLOCK_STATE_PALETTE = Converter.convertTag(tag); } { Registry biomes = net.minecraft.server.MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); - PalettedContainer> empty = new PalettedContainer<>(biomes.get(Biomes.PLAINS).orElseThrow(), factory.biomeStrategy()); + PalettedContainer> empty = new PalettedContainer<>(biomes.get(Biomes.PLAINS).orElseThrow(), factory.biomeStrategy(), null); Tag tag = factory.biomeContainerRWCodec().encodeStart(NbtOps.INSTANCE, empty).getOrThrow(); EMPTY_BIOME_PALETTE = Converter.convertTag(tag); From ca0fc36c3838797dd8b7d05b8036e5fa5eca985b Mon Sep 17 00:00:00 2001 From: David Date: Wed, 22 Apr 2026 02:42:24 +0200 Subject: [PATCH 5/9] feat: allow importing 26.1.2 worlds, implement anvil world upgrades --- .../asp/api/SlimeDataConverter.java | 3 + .../infernalsuite/asp/AdvancedSlimePaper.java | 3 +- .../asp/SimpleDataFixerConverter.java | 14 ++- .../serialization/anvil/AnvilWorldReader.java | 118 ++++++++++++------ .../asp/serialization/slime/ChunkPruner.java | 4 + .../asp/importer/SWMImporter.java | 2 +- .../plugin/commands/sub/ImportWorldCmd.java | 35 ++++-- 7 files changed, 132 insertions(+), 47 deletions(-) diff --git a/api/src/main/java/com/infernalsuite/asp/api/SlimeDataConverter.java b/api/src/main/java/com/infernalsuite/asp/api/SlimeDataConverter.java index 5820073d9..2a62e9c5c 100644 --- a/api/src/main/java/com/infernalsuite/asp/api/SlimeDataConverter.java +++ b/api/src/main/java/com/infernalsuite/asp/api/SlimeDataConverter.java @@ -15,8 +15,11 @@ public interface SlimeDataConverter { CompoundBinaryTag convertChunkTo1_13(CompoundBinaryTag globalTag); + CompoundBinaryTag convertChunk(CompoundBinaryTag globalTag, int to); + List convertEntities(List input, int from, int to); List convertTileEntities(List input, int from, int to); ListBinaryTag convertBlockPalette(ListBinaryTag input, int from, int to); + int getServerVersion(); } diff --git a/aspaper-server/src/main/java/com/infernalsuite/asp/AdvancedSlimePaper.java b/aspaper-server/src/main/java/com/infernalsuite/asp/AdvancedSlimePaper.java index 188e13b78..2966b59d7 100644 --- a/aspaper-server/src/main/java/com/infernalsuite/asp/AdvancedSlimePaper.java +++ b/aspaper-server/src/main/java/com/infernalsuite/asp/AdvancedSlimePaper.java @@ -48,6 +48,7 @@ public class AdvancedSlimePaper implements AdvancedSlimePaperAPI { } private final SlimeSerializationAdapter serializationAdapter = new SlimeSerializationAdapterImpl(); + private final AnvilWorldReader reader = new AnvilWorldReader(BRIDGE_INSTANCE.getSlimeDataConverter()); public static AdvancedSlimePaper instance() { return (AdvancedSlimePaper) AdvancedSlimePaperAPI.instance(); @@ -206,7 +207,7 @@ public SlimeWorld readVanillaWorld(File worldDir, String worldName, SlimeLoader SlimeWorld world; try { - world = AnvilWorldReader.INSTANCE.readFromData(AnvilImportData.legacy(worldDir, worldName, loader)); + world = this.reader.readFromData(AnvilImportData.legacy(worldDir, worldName, loader)); } catch (RuntimeException e) { if (e.getCause() == null) { throw e; diff --git a/aspaper-server/src/main/java/com/infernalsuite/asp/SimpleDataFixerConverter.java b/aspaper-server/src/main/java/com/infernalsuite/asp/SimpleDataFixerConverter.java index c900ef914..c7eb01d74 100644 --- a/aspaper-server/src/main/java/com/infernalsuite/asp/SimpleDataFixerConverter.java +++ b/aspaper-server/src/main/java/com/infernalsuite/asp/SimpleDataFixerConverter.java @@ -130,11 +130,16 @@ private static CompoundBinaryTag convertAndBack(CompoundBinaryTag value, Consume @Override public CompoundBinaryTag convertChunkTo1_13(CompoundBinaryTag tag) { - CompoundTag nmsTag = (CompoundTag) Converter.convertTag(tag); + return convertChunk(tag, 1631); + } + + @Override + public CompoundBinaryTag convertChunk(CompoundBinaryTag globalTag, int to) { + CompoundTag nmsTag = (CompoundTag) Converter.convertTag(globalTag); int version = nmsTag.getInt("DataVersion").orElseThrow(); - long encodedNewVersion = DataConverter.encodeVersions(1631, Integer.MAX_VALUE); + long encodedNewVersion = DataConverter.encodeVersions(to, Integer.MAX_VALUE); long encodedCurrentVersion = DataConverter.encodeVersions(version, Integer.MAX_VALUE); MCTypeRegistry.CHUNK.convert(new NBTMapType(nmsTag), encodedCurrentVersion, encodedNewVersion); @@ -190,4 +195,9 @@ public ListBinaryTag convertBlockPalette(ListBinaryTag input, int from, int to) return Converter.convertTag(listType.getTag()); } + + @Override + public int getServerVersion() { + return 0; + } } diff --git a/core/src/main/java/com/infernalsuite/asp/serialization/anvil/AnvilWorldReader.java b/core/src/main/java/com/infernalsuite/asp/serialization/anvil/AnvilWorldReader.java index 91dafa14b..d62cd66ba 100644 --- a/core/src/main/java/com/infernalsuite/asp/serialization/anvil/AnvilWorldReader.java +++ b/core/src/main/java/com/infernalsuite/asp/serialization/anvil/AnvilWorldReader.java @@ -1,6 +1,7 @@ package com.infernalsuite.asp.serialization.anvil; import com.infernalsuite.asp.util.Util; +import com.infernalsuite.asp.api.SlimeDataConverter; import com.infernalsuite.asp.api.exceptions.InvalidWorldException; import com.infernalsuite.asp.api.utils.NibbleArray; import com.infernalsuite.asp.api.world.SlimeChunk; @@ -8,6 +9,7 @@ import com.infernalsuite.asp.api.world.SlimeWorld; import com.infernalsuite.asp.api.world.properties.SlimeProperties; import com.infernalsuite.asp.api.world.properties.SlimePropertyMap; +import com.infernalsuite.asp.serialization.slime.ChunkPruner; import com.infernalsuite.asp.skeleton.SlimeChunkSectionSkeleton; import com.infernalsuite.asp.skeleton.SlimeChunkSkeleton; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; @@ -39,21 +41,39 @@ public class AnvilWorldReader implements com.infernalsuite.asp.serialization.Sli private static final Logger LOGGER = LoggerFactory.getLogger(AnvilWorldReader.class); - public static final AnvilWorldReader INSTANCE = new AnvilWorldReader(); + public static final AnvilWorldReader INSTANCE_NO_CONVERSION = new AnvilWorldReader(null); + + private final SlimeDataConverter slimeDataConverter; + + public AnvilWorldReader(SlimeDataConverter slimeDataConverter) { + this.slimeDataConverter = slimeDataConverter; + } @Override public SlimeWorld readFromData(AnvilImportData importData) { Path worldDir = importData.worldDir(); try { - Path levelFile = worldDir.resolve("level.dat"); - if (!Files.exists(levelFile) || !Files.isRegularFile(levelFile)) { - throw new RuntimeException(new InvalidWorldException(worldDir)); - } - LevelData data = readLevelData(levelFile); + int worldVersion = 0; + int spawnX = 0; + int spawnY = 0; + int spawnZ = 0; - int worldVersion = data.version; + Path levelFile = worldDir.resolve("level.dat"); + if (Files.exists(levelFile) && Files.isRegularFile(levelFile)) { + LevelData levelData = readLevelData(levelFile); + worldVersion = levelData.version; + spawnX = levelData.x; + spawnY = levelData.y; + spawnZ = levelData.z; + } else { + if(!Files.exists(worldDir.resolve("region"))) + throw new RuntimeException(new InvalidWorldException(worldDir)); + + worldVersion = -1; //Figure that out later + //TODO: Spawn pos + } SlimePropertyMap propertyMap = new SlimePropertyMap(); @@ -67,6 +87,7 @@ public SlimeWorld readFromData(AnvilImportData importData) { * * Vanilla users would need to delete the main region folder in order to import other dimensions. */ + //TODO: Figure this out on 26.1.2. I think we cant so we need to make users provide this info Path environmentDir = worldDir; propertyMap.setValue(SlimeProperties.ENVIRONMENT, "normal"); if (!doesWorldContainRegion(worldDir)) { @@ -88,11 +109,45 @@ public SlimeWorld readFromData(AnvilImportData importData) { Long2ObjectMap chunks = new Long2ObjectOpenHashMap<>(); + int worldHeight; + int minY; + switch (propertyMap.getValue(SlimeProperties.ENVIRONMENT)) { + case "normal" -> { + worldHeight = 384; + minY = -64; + } + case "nether", "the_end" -> { + worldHeight = 256; + minY = 0; + } + case null, default -> throw new IllegalStateException("Unsupported environment, cant obtain world height data"); + } + + int minSectionY = minY >> 4; + int maxSectionY = (minY + worldHeight - 1) >> 4; + try (var stream = Files.newDirectoryStream(regionDir, path -> path.toString().endsWith(".mca"))) { for (final Path path : stream) { LOGGER.info("Loading region file {}...", path.getFileName()); - chunks.putAll(loadChunks(path, worldVersion, propertyMap).stream() - .collect(Collectors.toMap(chunk -> Util.chunkPosition(chunk.getX(), chunk.getZ()), Function.identity()))); + + List chunkNBT = loadChunks(path, propertyMap); + if(worldVersion == -1) { + for (CompoundBinaryTag entries : chunkNBT) { + int dataVersion = entries.getInt("DataVersion", -1); + if (dataVersion != -1) { + worldVersion = dataVersion; + break; + } + } + } + + for (CompoundBinaryTag entries : chunkNBT) { + SlimeChunk slimeChunk = convertChunk(entries, worldVersion, minSectionY, maxSectionY); + if(slimeChunk == null) continue; + if(ChunkPruner.canBePruned(slimeChunk)) continue; + + chunks.put(Util.chunkPosition(slimeChunk.getX(), slimeChunk.getZ()), slimeChunk); + } } } @@ -114,9 +169,9 @@ public SlimeWorld readFromData(AnvilImportData importData) { throw new InvalidWorldException(environmentDir); } - propertyMap.setValue(SlimeProperties.SPAWN_X, data.x); - propertyMap.setValue(SlimeProperties.SPAWN_Y, data.y); - propertyMap.setValue(SlimeProperties.SPAWN_Z, data.z); + propertyMap.setValue(SlimeProperties.SPAWN_X, spawnX); + propertyMap.setValue(SlimeProperties.SPAWN_Y, spawnY); + propertyMap.setValue(SlimeProperties.SPAWN_Z, spawnZ); return new com.infernalsuite.asp.skeleton.SkeletonSlimeWorld(importData.newName(), importData.loader(), importData.loader() == null, chunks, new ConcurrentHashMap<>(), propertyMap, worldVersion); @@ -148,7 +203,7 @@ private static LevelData readLevelData(Path file) throws IOException, InvalidWor throw new InvalidWorldException(file.getParent()); } - private static void loadEntities(Path path, int version, Long2ObjectMap chunkMap) throws IOException { + private void loadEntities(Path path, int version, Long2ObjectMap chunkMap) throws IOException { byte[] regionByteArray = Files.readAllBytes(path); //Is that in mca spec? Well, at least one world had empty MCA files, so lets just keep that here. if(regionByteArray.length == 0) return; @@ -187,7 +242,7 @@ private static void loadEntities(Path path, int version, Long2ObjectMap loadChunks(Path path, int worldVersion, SlimePropertyMap propertyMap) throws IOException { + private List loadChunks(Path path, SlimePropertyMap propertyMap) throws IOException { byte[] regionByteArray = Files.readAllBytes(path); DataInputStream inputStream = new DataInputStream(new ByteArrayInputStream(regionByteArray)); @@ -204,23 +259,6 @@ private static List loadChunks(Path path, int worldVersion, SlimePro } } - int worldHeight; - int minY; - switch (propertyMap.getValue(SlimeProperties.ENVIRONMENT)) { - case "normal" -> { - worldHeight = 384; - minY = -64; - } - case "nether", "the_end" -> { - worldHeight = 256; - minY = 0; - } - case null, default -> throw new IllegalStateException("Unsupported environment, cant obtain world height data"); - } - - int minSectionY = minY >> 4; - int maxSectionY = (minY + worldHeight - 1) >> 4; - return chunks.stream().map((entry) -> { try { @@ -232,7 +270,12 @@ private static List loadChunks(Path path, int worldVersion, SlimePro DataInputStream chunkStream = new DataInputStream(new ByteArrayInputStream(regionByteArray, entry.offset() + 5, chunkSize)); InputStream decompressorStream = compressionScheme == 1 ? new GZIPInputStream(chunkStream) : new InflaterInputStream(chunkStream); CompoundBinaryTag tag = BinaryTagIO.unlimitedReader().read(decompressorStream); - return readChunk(tag, worldVersion, minSectionY, maxSectionY); + + if(slimeDataConverter != null) { + tag = slimeDataConverter.convertChunk(tag, slimeDataConverter.getServerVersion()); + } + + return tag; } catch (IOException ex) { throw new RuntimeException(ex); } @@ -240,14 +283,14 @@ private static List loadChunks(Path path, int worldVersion, SlimePro }).filter(Objects::nonNull).collect(Collectors.toList()); } - private static void readEntityChunk(CompoundBinaryTag compound, int worldVersion, Long2ObjectMap slimeChunkMap) { + private void readEntityChunk(CompoundBinaryTag compound, int worldVersion, Long2ObjectMap slimeChunkMap) { int[] position = compound.getIntArray("Position"); if (position.length == 0) throw new IllegalStateException("Entity chunk is missing position data"); int chunkX = position[0]; int chunkZ = position[1]; int dataVersion = compound.getInt("DataVersion", -1); - if (dataVersion != worldVersion) { + if (dataVersion != worldVersion && (worldVersion != -1 || slimeDataConverter == null)) { LOGGER.error("Cannot load entity chunk at {},{}: data version {} does not match world version {}", chunkX, chunkZ, dataVersion, worldVersion); return; } @@ -260,6 +303,9 @@ private static void readEntityChunk(CompoundBinaryTag compound, int worldVersion for (BinaryTag binaryTag : compound.getList("Entities", BinaryTagTypes.COMPOUND)) { entities.add((CompoundBinaryTag) binaryTag); } + if(slimeDataConverter != null) { + entities = slimeDataConverter.convertEntities(entities, dataVersion, slimeDataConverter.getServerVersion()); + } slimeChunkMap.put(Util.chunkPosition(chunkX, chunkZ), new SlimeChunkSkeleton( chunk.getX(), @@ -277,12 +323,12 @@ private static void readEntityChunk(CompoundBinaryTag compound, int worldVersion } } - private static SlimeChunk readChunk(CompoundBinaryTag compound, int worldVersion, int minSectionY, int maxSectionY) { + private SlimeChunk convertChunk(CompoundBinaryTag compound, int worldVersion, int minSectionY, int maxSectionY) { int chunkX = compound.getInt("xPos"); int chunkZ = compound.getInt("zPos"); int dataVersion = compound.getInt("DataVersion", -1); - if (dataVersion != worldVersion) { + if (dataVersion != worldVersion && (worldVersion != -1 || slimeDataConverter == null)) { LOGGER.error("Cannot load chunk at {},{}: data version {} does not match world version {}", chunkX, chunkZ, dataVersion, worldVersion); return null; } diff --git a/core/src/main/java/com/infernalsuite/asp/serialization/slime/ChunkPruner.java b/core/src/main/java/com/infernalsuite/asp/serialization/slime/ChunkPruner.java index 892a327bd..58d21e813 100644 --- a/core/src/main/java/com/infernalsuite/asp/serialization/slime/ChunkPruner.java +++ b/core/src/main/java/com/infernalsuite/asp/serialization/slime/ChunkPruner.java @@ -42,6 +42,10 @@ public static boolean canBePruned(SlimeWorld world, SlimeChunk chunk) { return false; } + public static boolean canBePruned(SlimeChunk chunk) { + return chunk.getTileEntities().isEmpty() && chunk.getEntities().isEmpty() && areSectionsEmpty(chunk.getSections()); + } + // TAG_List("palette"): 1 entries of type TAG_Compound //[13:15:06 INFO]: { //[13:15:06 INFO]: TAG_Compound: 1 entries diff --git a/importer/src/main/java/com/infernalsuite/asp/importer/SWMImporter.java b/importer/src/main/java/com/infernalsuite/asp/importer/SWMImporter.java index 561e57876..1e82384e0 100644 --- a/importer/src/main/java/com/infernalsuite/asp/importer/SWMImporter.java +++ b/importer/src/main/java/com/infernalsuite/asp/importer/SWMImporter.java @@ -49,7 +49,7 @@ public static void main(String[] args) { public static void importWorld(File worldDir, File outputFile, boolean shouldPrintDebug) { try { outputFile.createNewFile(); - Files.write(outputFile.toPath(), SlimeSerializer.serialize(AnvilWorldReader.INSTANCE.readFromData(AnvilImportData.legacy(worldDir, outputFile.getName(), null)))); + Files.write(outputFile.toPath(), SlimeSerializer.serialize(AnvilWorldReader.INSTANCE_NO_CONVERSION.readFromData(AnvilImportData.legacy(worldDir, outputFile.getName(), null)))); } catch (IndexOutOfBoundsException ex) { System.err.println("Oops, it looks like the world provided is too big to be imported. " + "Please trim it by using the MCEdit tool and try again."); diff --git a/plugin/src/main/java/com/infernalsuite/asp/plugin/commands/sub/ImportWorldCmd.java b/plugin/src/main/java/com/infernalsuite/asp/plugin/commands/sub/ImportWorldCmd.java index 41b88b2b8..2869deb6c 100644 --- a/plugin/src/main/java/com/infernalsuite/asp/plugin/commands/sub/ImportWorldCmd.java +++ b/plugin/src/main/java/com/infernalsuite/asp/plugin/commands/sub/ImportWorldCmd.java @@ -8,8 +8,10 @@ import com.infernalsuite.asp.api.exceptions.WorldTooBigException; import com.infernalsuite.asp.api.world.SlimeWorld; import com.infernalsuite.asp.api.world.properties.SlimeProperties; +import net.kyori.adventure.key.Key; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.incendo.cloud.annotations.Argument; import org.incendo.cloud.annotations.Command; @@ -17,6 +19,7 @@ import org.incendo.cloud.annotations.Permission; import org.incendo.cloud.annotations.injection.RawArgs; import org.incendo.cloud.paper.util.sender.Source; +import org.jspecify.annotations.NonNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -45,13 +48,7 @@ public CompletableFuture importWorld(Source source, String[] args, @Argument(value = "data-source") com.infernalsuite.asp.plugin.commands.parser.NamedSlimeLoader loader, @Argument(value = "new-world-name") String newWorldName) { CommandSender sender = source.source(); - File worldDir = new File(pathToWorld); - - if (!worldDir.exists() || !worldDir.isDirectory()) { - throw new com.infernalsuite.asp.plugin.commands.exception.MessageCommandException(COMMAND_PREFIX.append( - Component.text("Path " + worldDir.getPath() + " does not point out to a valid world directory.")).color(NamedTextColor.RED) - ); - } + File worldDir = getWorldFolder(pathToWorld); String[] oldArgs = importCache.getIfPresent(sender.getName()); @@ -160,5 +157,29 @@ public CompletableFuture importWorld(Source source, String[] args, } } + private static @NonNull File getWorldFolder(String pathToWorld) { + File worldDir = Bukkit.getServer().getLevelDirectory().resolve("dimensions") + .resolve("minecraft") + .resolve(pathToWorld).toFile(); + + if(!worldDir.exists() || !worldDir.isDirectory() && Key.parseable(pathToWorld)) { + Key key = Key.key(pathToWorld); + worldDir = Bukkit.getServer().getLevelDirectory().resolve("dimensions") + .resolve(key.namespace()) + .resolve(key.value()).toFile(); + } + + if(!worldDir.exists() || !worldDir.isDirectory()) { + worldDir = new File(pathToWorld); + } + + if (!worldDir.exists() || !worldDir.isDirectory()) { + throw new com.infernalsuite.asp.plugin.commands.exception.MessageCommandException(COMMAND_PREFIX.append( + Component.text("Path " + worldDir.getPath() + " does not point out to a valid world directory.")).color(NamedTextColor.RED) + ); + } + return worldDir; + } + } From 52d1f6c644ec5ab3d5d070e23eedbc05619d3cac Mon Sep 17 00:00:00 2001 From: David Date: Sun, 10 May 2026 03:43:57 +0200 Subject: [PATCH 6/9] feat: update to newest paper --- ...Prevent-config-disk-io-on-world-load.patch | 3 ++- .../server/level/ServerLevel.java.patch | 12 +++++----- ...-temp-folder-after-world-is-unloaded.patch | 5 ++-- ...rides.patch => 0005-World-overrides.patch} | 0 ...revent-config-disk-io-on-world-load.patch} | 23 ++++++++++--------- gradle.properties | 4 ++-- 6 files changed, 25 insertions(+), 22 deletions(-) rename aspaper-server/paper-patches/features/{0006-World-overrides.patch => 0005-World-overrides.patch} (100%) rename aspaper-server/paper-patches/features/{0005-Prevent-config-disk-io-on-world-load.patch => 0006-Prevent-config-disk-io-on-world-load.patch} (83%) diff --git a/aspaper-server/minecraft-patches/features/0002-Prevent-config-disk-io-on-world-load.patch b/aspaper-server/minecraft-patches/features/0002-Prevent-config-disk-io-on-world-load.patch index 2f1764f22..aee51a5ce 100644 --- a/aspaper-server/minecraft-patches/features/0002-Prevent-config-disk-io-on-world-load.patch +++ b/aspaper-server/minecraft-patches/features/0002-Prevent-config-disk-io-on-world-load.patch @@ -25,7 +25,8 @@ index e34e901dce06c6bc6060418593010dcfb38e9396..e1fd30fc9b17d241c421c66114c9611b this.maxSectionY = this.maxY >> 4; this.sectionsCount = this.maxSectionY - this.minSectionY + 1; // Paper end - getblock optimisations - cache world height/sections -- this.spigotConfig = new org.spigotmc.SpigotWorldConfig(bukkitName, CraftNamespacedKey.fromMinecraft(dimension.identifier())); // Spigot + final org.bukkit.NamespacedKey worldKey = CraftNamespacedKey.fromMinecraft(dimension.identifier()); // Paper +- this.spigotConfig = new org.spigotmc.SpigotWorldConfig(bukkitName, worldKey); // Spigot + this.spigotConfig = new org.spigotmc.SpigotWorldConfig(bukkitName, CraftNamespacedKey.fromMinecraft(dimension.identifier()), !(this instanceof com.infernalsuite.asp.level.SlimeLevelInstance)); // Spigot //ASP - Improve Slime IO this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper - create paper world config this.generator = generator; diff --git a/aspaper-server/minecraft-patches/sources/net/minecraft/server/level/ServerLevel.java.patch b/aspaper-server/minecraft-patches/sources/net/minecraft/server/level/ServerLevel.java.patch index c91aea952..ee6f952a7 100644 --- a/aspaper-server/minecraft-patches/sources/net/minecraft/server/level/ServerLevel.java.patch +++ b/aspaper-server/minecraft-patches/sources/net/minecraft/server/level/ServerLevel.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java -@@ -602,8 +_,35 @@ +@@ -603,8 +_,35 @@ this.playerTickingChunks.remove((LevelChunk)chunkHolder.getCurrentChunk()); } // Paper end - chunk tick iteration @@ -38,7 +38,7 @@ final MinecraftServer server, final Executor executor, final LevelStorageSource.LevelStorageAccess levelStorage, -@@ -623,6 +_,7 @@ +@@ -624,6 +_,7 @@ io.papermc.paper.world.PaperWorldLoader.LoadedWorldData loadedWorldData // Paper end - add parameters ) { @@ -46,7 +46,7 @@ // CraftBukkit start final io.papermc.paper.world.saveddata.PaperLevelOverrides levelData = loadedWorldData.levelOverrides(); savedDataStorage.set(io.papermc.paper.world.saveddata.PaperLevelOverrides.TYPE, levelData); -@@ -644,7 +_,13 @@ +@@ -645,7 +_,13 @@ this.server = server; this.customSpawners = customSpawners; this.serverLevelData = levelData; @@ -58,9 +58,9 @@ + } + // ASP END // CraftBukkit start - if (loadedWorldData.pdc() != null) { - this.getWorld().readBukkitValues(loadedWorldData.pdc().persistentData().toTagCompound()); -@@ -732,6 +_,12 @@ + // Paper start - per-world time + if (!io.papermc.paper.configuration.GlobalConfiguration.get().time.affectsAllWorlds) { +@@ -739,6 +_,12 @@ // Paper end - rewrite chunk system this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit } diff --git a/aspaper-server/paper-patches/features/0004-Delete-temp-folder-after-world-is-unloaded.patch b/aspaper-server/paper-patches/features/0004-Delete-temp-folder-after-world-is-unloaded.patch index 71f3da933..ae740b981 100644 --- a/aspaper-server/paper-patches/features/0004-Delete-temp-folder-after-world-is-unloaded.patch +++ b/aspaper-server/paper-patches/features/0004-Delete-temp-folder-after-world-is-unloaded.patch @@ -5,13 +5,14 @@ Subject: [PATCH] Delete temp folder after world is unloaded diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 324352276da542632858e68eac3c39a4542e09db..f4da118fbb65474fca70e7a1211e69fa2ff6d35b 100644 +index d6418084621338579615d1b486cc2fd0d8c00fb5..d357c33e58c680eb07b9601d8258e9058be64bfc 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -1352,6 +1352,12 @@ public final class CraftServer implements Server { +@@ -1352,6 +1352,13 @@ public final class CraftServer implements Server { handle.getChunkSource().close(save); io.papermc.paper.FeatureHooks.closeEntityManager(handle, save); // SPIGOT-6722: close entityManager // Paper - chunk system ++ handle.levelStorageAccess.close(); + + //ASP start - avoid temp storage leak during runtime + if(handle instanceof com.infernalsuite.asp.level.SlimeLevelInstance asp) { diff --git a/aspaper-server/paper-patches/features/0006-World-overrides.patch b/aspaper-server/paper-patches/features/0005-World-overrides.patch similarity index 100% rename from aspaper-server/paper-patches/features/0006-World-overrides.patch rename to aspaper-server/paper-patches/features/0005-World-overrides.patch diff --git a/aspaper-server/paper-patches/features/0005-Prevent-config-disk-io-on-world-load.patch b/aspaper-server/paper-patches/features/0006-Prevent-config-disk-io-on-world-load.patch similarity index 83% rename from aspaper-server/paper-patches/features/0005-Prevent-config-disk-io-on-world-load.patch rename to aspaper-server/paper-patches/features/0006-Prevent-config-disk-io-on-world-load.patch index 5d159caf8..169953933 100644 --- a/aspaper-server/paper-patches/features/0005-Prevent-config-disk-io-on-world-load.patch +++ b/aspaper-server/paper-patches/features/0006-Prevent-config-disk-io-on-world-load.patch @@ -35,41 +35,42 @@ index 025ec3f3e84a3367b4d709c8c3ecd98f6dfecab4..182de15ca133fc42bf703ee9d116302b Bukkit.getLogger().log(Level.SEVERE, "Could not save " + SpigotConfig.CONFIG_FILE, ex); } diff --git a/src/main/java/org/spigotmc/SpigotWorldConfig.java b/src/main/java/org/spigotmc/SpigotWorldConfig.java -index 339832e312578ee385bbf3c9d5c131435abe7d7a..3924ba62c2df8372b67f6666f0c02d007ea3021c 100644 +index 339832e312578ee385bbf3c9d5c131435abe7d7a..f723674434dc2b33870a2205f3ba1a3715e26aca 100644 --- a/src/main/java/org/spigotmc/SpigotWorldConfig.java +++ b/src/main/java/org/spigotmc/SpigotWorldConfig.java -@@ -15,13 +15,23 @@ public class SpigotWorldConfig { +@@ -14,14 +14,25 @@ public class SpigotWorldConfig { + private final YamlConfiguration config; private boolean verbose; ++ // ASP start - Improve Slime IO public SpigotWorldConfig(String legacyWorldName, Key worldKey) { -+ // ASP start - Improve Slime IO + this(legacyWorldName, worldKey, true); + } ++ // ASP end - Improve Slime IO + -+ public SpigotWorldConfig(String legacyWorldName, Key worldKey, boolean saveOnLoad) { -+ // ASP end - Improve Slime IO ++ public SpigotWorldConfig(String legacyWorldName, Key worldKey, boolean saveOnLoad) { // ASP - Improve Slime IO this.legacyWorldName = legacyWorldName; this.worldName = worldKey.asString(); this.config = SpigotConfig.config; - this.init(); -+ this.init(saveOnLoad); // ASP - Improve Slime IO ++ this.init(saveOnLoad); // ASP - Improve Slime IO } -- + ++ // ASP start - Improve Slime IO public void init() { -+ // ASP start - Improve Slime IO + init(true); + } + public void init(boolean saveOnLoad) { -+ // ASP end - Improve Slime IO ++ // ASP end - Improve Slime IO this.verbose = this.getBoolean("verbose", false); // Paper if (SpigotConfig.version <= 12) { ConfigurationSection section = this.config.getConfigurationSection("world-settings." + this.legacyWorldName); -@@ -33,7 +43,7 @@ public class SpigotWorldConfig { +@@ -33,7 +44,7 @@ public class SpigotWorldConfig { } this.log("-------- World Settings For [" + this.worldName + "] --------"); - SpigotConfig.readConfig(SpigotWorldConfig.class, this); -+ SpigotConfig.readConfig(SpigotWorldConfig.class, this, saveOnLoad); ++ SpigotConfig.readConfig(SpigotWorldConfig.class, this, saveOnLoad); // ASP - Improve Slime IO } private void log(String s) { diff --git a/gradle.properties b/gradle.properties index d54b27786..bf25f3c59 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,10 +1,10 @@ group=com.infernalsuite.asp aspApiVersion=4.2.0-SNAPSHOT apiVersion=26.1.2 -version=26.1.2.build.19-alpha +version=26.1.2.build.61 mcVersion=26.1.2 -paperRef=1d14197790a353a58aced4333cd4fe4041184a21 +paperRef=8dea6f1761c97da76fa2e42c6f74fb1242c23feb org.gradle.caching=true org.gradle.parallel=true From 98828402315c81d39275eaa807078fdf9e8a6a80 Mon Sep 17 00:00:00 2001 From: David Date: Sun, 10 May 2026 16:49:22 +0200 Subject: [PATCH 7/9] build: add fallback for createMojmapPaperclipJar and fix version --- build.gradle.kts | 6 ++++++ gradle.properties | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 6249f1aa3..6865b4ad2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,6 @@ import org.gradle.api.tasks.testing.logging.TestExceptionFormat import org.gradle.api.tasks.testing.logging.TestLogEvent +import org.gradle.kotlin.dsl.register plugins { java @@ -69,3 +70,8 @@ subprojects { } } } + +tasks.register("createMojmapPaperclipJar") { + description = "Fallback to the old mojmap naming for our CI... Yes this was the easiest fix I could come up with." + dependsOn(":aspaper-server:createPaperclipJar") +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index bf25f3c59..d82f8dcf5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ group=com.infernalsuite.asp aspApiVersion=4.2.0-SNAPSHOT apiVersion=26.1.2 -version=26.1.2.build.61 +version=26.1.2.build.61-stable mcVersion=26.1.2 paperRef=8dea6f1761c97da76fa2e42c6f74fb1242c23feb From 8ea21e3a3612d3df6b21d6b37814bb0e0e4f37e8 Mon Sep 17 00:00:00 2001 From: David Date: Sun, 10 May 2026 16:56:14 +0200 Subject: [PATCH 8/9] fix: init world requiring world creator --- .../src/main/java/com/infernalsuite/asp/SlimeNMSBridgeImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aspaper-server/src/main/java/com/infernalsuite/asp/SlimeNMSBridgeImpl.java b/aspaper-server/src/main/java/com/infernalsuite/asp/SlimeNMSBridgeImpl.java index 67a3d4384..f55838f31 100644 --- a/aspaper-server/src/main/java/com/infernalsuite/asp/SlimeNMSBridgeImpl.java +++ b/aspaper-server/src/main/java/com/infernalsuite/asp/SlimeNMSBridgeImpl.java @@ -171,7 +171,7 @@ public int getCurrentVersion() { public void registerWorld(SlimeLevelInstance server) { MinecraftServer mcServer = MinecraftServer.getServer(); - mcServer.initWorld(server); + mcServer.initWorld(server, null); mcServer.addLevel(server); } From 2e69d9f6e20da479e8a3edea0a57ce1a16888fe7 Mon Sep 17 00:00:00 2001 From: David Date: Sun, 10 May 2026 17:03:13 +0200 Subject: [PATCH 9/9] fix: build issues. How did that end up here? --- .../0004-Delete-temp-folder-after-world-is-unloaded.patch | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/aspaper-server/paper-patches/features/0004-Delete-temp-folder-after-world-is-unloaded.patch b/aspaper-server/paper-patches/features/0004-Delete-temp-folder-after-world-is-unloaded.patch index ae740b981..002ffb48d 100644 --- a/aspaper-server/paper-patches/features/0004-Delete-temp-folder-after-world-is-unloaded.patch +++ b/aspaper-server/paper-patches/features/0004-Delete-temp-folder-after-world-is-unloaded.patch @@ -5,14 +5,13 @@ Subject: [PATCH] Delete temp folder after world is unloaded diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index d6418084621338579615d1b486cc2fd0d8c00fb5..d357c33e58c680eb07b9601d8258e9058be64bfc 100644 +index d6418084621338579615d1b486cc2fd0d8c00fb5..56a126bb70f53a13047e72cf2e70cbd45f9ae8bd 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -1352,6 +1352,13 @@ public final class CraftServer implements Server { +@@ -1352,6 +1352,12 @@ public final class CraftServer implements Server { handle.getChunkSource().close(save); io.papermc.paper.FeatureHooks.closeEntityManager(handle, save); // SPIGOT-6722: close entityManager // Paper - chunk system -+ handle.levelStorageAccess.close(); + + //ASP start - avoid temp storage leak during runtime + if(handle instanceof com.infernalsuite.asp.level.SlimeLevelInstance asp) {