diff --git a/paper-server/patches/features/0003-Improve-Maps-in-item-frames-performance-and-bug-fixe.patch b/paper-server/patches/features/0003-Improve-Maps-in-item-frames-performance-and-bug-fixe.patch index 77da1105f4..a547df5f1b 100644 --- a/paper-server/patches/features/0003-Improve-Maps-in-item-frames-performance-and-bug-fixe.patch +++ b/paper-server/patches/features/0003-Improve-Maps-in-item-frames-performance-and-bug-fixe.patch @@ -13,7 +13,7 @@ custom renderers are in use, defaulting to the much simpler Vanilla system. Additionally, numerous issues to player position tracking on maps has been fixed. diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index 678b3027e8c53e6021ea49afa69cdbe5f60dcf25..cce78d73e8adafd66d0f3ffb3fabb5e6c025c7df 100644 +index 1f66adcd70aae7eac3d9f9539163905695581631..34a53bf34d10c56e6f53ce9aab2fc2780509f2f1 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java @@ -2282,7 +2282,9 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @@ -28,10 +28,10 @@ index 678b3027e8c53e6021ea49afa69cdbe5f60dcf25..cce78d73e8adafd66d0f3ffb3fabb5e6 } } diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java -index 68e3282a0aa23bd41ab7c77be287d2b49461e33c..def43c515030412b147afd6049b100a3153733d2 100644 +index 36e0d3f225a71b75ece7bf3fceeba47af948a6df..ff5889f8fed0707a6654d9d21862e32e2ebc866d 100644 --- a/net/minecraft/server/level/ServerPlayer.java +++ b/net/minecraft/server/level/ServerPlayer.java -@@ -2607,6 +2607,14 @@ public class ServerPlayer extends Player { +@@ -2594,6 +2594,14 @@ public class ServerPlayer extends Player { this.awardStat(Stats.DROP); } diff --git a/paper-server/patches/features/0007-Anti-Xray.patch b/paper-server/patches/features/0007-Anti-Xray.patch index bb7e6f43a4..46c23e31dd 100644 --- a/paper-server/patches/features/0007-Anti-Xray.patch +++ b/paper-server/patches/features/0007-Anti-Xray.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Anti-Xray diff --git a/io/papermc/paper/FeatureHooks.java b/io/papermc/paper/FeatureHooks.java -index 1e5d94cdcdffb4d2940f17bacdf0e6a488e84318..d3aebc7f833764351c8e5fe1fad1aa2f8718ca37 100644 +index b97e0a8d4c429776b86def10739faee089e2bc9b..184e6c6fe2ba522d0ea0774604839320c4152371 100644 --- a/io/papermc/paper/FeatureHooks.java +++ b/io/papermc/paper/FeatureHooks.java @@ -7,6 +7,7 @@ import it.unimi.dsi.fastutil.longs.LongSets; @@ -153,7 +153,7 @@ index 3a384175f8e7f204234bbaf3081bdc20c47a0d4b..5699bc15eba92e22433a20cb8326b59f private ClientboundLevelChunkWithLightPacket(RegistryFriendlyByteBuf buffer) { diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index 7702004b68b7735043914f93b54b4413cd21ba41..4d20bda4cba578c47216d450c99389b744a59008 100644 +index a43b8febcf616aa1662ea126ce60f7973799ea46..cdda7f6272cfc48638df4e0e51b496e91ed77ba5 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java @@ -348,7 +348,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @@ -166,7 +166,7 @@ index 7702004b68b7735043914f93b54b4413cd21ba41..4d20bda4cba578c47216d450c99389b7 this.levelStorageAccess = levelStorageAccess; this.uuid = org.bukkit.craftbukkit.util.WorldUUID.getUUID(levelStorageAccess.levelDirectory.path().toFile()); diff --git a/net/minecraft/server/level/ServerPlayerGameMode.java b/net/minecraft/server/level/ServerPlayerGameMode.java -index 23d241e98f37979701f80fb6f7b76954bd699ad6..fd7ad2b1bffe3880def0f0c9a7ed8de5088ecd71 100644 +index 1178af2ba50ad71556e0a5cbde3e5dc290396148..bf2a4c03afb73367a6d2530c78ff9f7c06f7f6a6 100644 --- a/net/minecraft/server/level/ServerPlayerGameMode.java +++ b/net/minecraft/server/level/ServerPlayerGameMode.java @@ -298,6 +298,7 @@ public class ServerPlayerGameMode { @@ -196,10 +196,10 @@ index 342bc843c384761e883de861044f4f8930ae8763..14878690a88fd4de3e2c127086607e6c if (io.papermc.paper.event.packet.PlayerChunkLoadEvent.getHandlerList().getRegisteredListeners().length > 0) { new io.papermc.paper.event.packet.PlayerChunkLoadEvent(new org.bukkit.craftbukkit.CraftChunk(chunk), packetListener.getPlayer().getBukkitEntity()).callEvent(); diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java -index 8a93d1034eb0dab4b4010d52ddbb0caa5697416d..bafeeab3edbc73f6f86474e18ab4a3d96ce17157 100644 +index 0837c732e60d82c36793a5a030f56d9004a5a83f..b0df94fb5f933491af8b024cc8ecf8b98e448f16 100644 --- a/net/minecraft/server/players/PlayerList.java +++ b/net/minecraft/server/players/PlayerList.java -@@ -404,7 +404,7 @@ public abstract class PlayerList { +@@ -403,7 +403,7 @@ public abstract class PlayerList { .getOrThrow(net.minecraft.world.level.biome.Biomes.PLAINS); player.connection.send(new net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket( new net.minecraft.world.level.chunk.EmptyLevelChunk(serverLevel, player.chunkPosition(), plains), diff --git a/paper-server/patches/features/0021-Moonrise-optimisation-patches.patch b/paper-server/patches/features/0021-Moonrise-optimisation-patches.patch index 8bdfa4ff3f..4e71dab65e 100644 --- a/paper-server/patches/features/0021-Moonrise-optimisation-patches.patch +++ b/paper-server/patches/features/0021-Moonrise-optimisation-patches.patch @@ -23551,7 +23551,7 @@ index 47c62090b421ebea1253ee3f1c896ed84119cea6..e738405e5112584e02e01df2d5ede267 thread1 -> { DedicatedServer dedicatedServer1 = new DedicatedServer( diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index 5649482a8b85056bc009b868e19ca11f21d59fbf..c3318c2fa121d75363c6bc9eadf408dc8040c2bb 100644 +index 768d287be8040797130499b021b2cfd3970f44e5..9c5305b4542483efeeeab19a79eb8eae6d15ef2c 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java @@ -173,7 +173,7 @@ import net.minecraft.world.phys.Vec2; @@ -23641,7 +23641,7 @@ index 5649482a8b85056bc009b868e19ca11f21d59fbf..c3318c2fa121d75363c6bc9eadf408dc public MinecraftServer( // CraftBukkit start joptsimple.OptionSet options, -@@ -628,7 +699,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop false : this::haveTime); @@ -23728,7 +23728,7 @@ index 5649482a8b85056bc009b868e19ca11f21d59fbf..c3318c2fa121d75363c6bc9eadf408dc this.tickFrame.end(); profilerFiller.popPush("nextTickWait"); this.mayHaveDelayedTasks = true; -@@ -1302,6 +1383,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop S spin(Function threadFunction) { ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system -@@ -1643,6 +1644,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0; // Paper - BlockPhysicsEvent serverLevel.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - Add EntityMoveEvent @@ -28,7 +28,7 @@ index 0c35921acebd88f3a9a37676e47e7482dfea6d9c..1ff57c17f7fe3af3fb7fc5fbc5148ca3 /* Drop global time updates if (this.tickCount % 20 == 0) { diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index ffb5bfdd76a92bac61c7c352fdded4200d13b3ae..651a65aaa37f2cf26d54f75529cbda71e6fc2bc4 100644 +index bbb4bb0940765a12c45a99c8234ca82ef1934903..7dbf6113d79ab826ba5bb9b648b557f625e2b438 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java @@ -2678,4 +2678,16 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe diff --git a/paper-server/patches/features/0028-Improved-Watchdog-Support.patch b/paper-server/patches/features/0028-Improved-Watchdog-Support.patch index 601c2bb5ea..4a0d417552 100644 --- a/paper-server/patches/features/0028-Improved-Watchdog-Support.patch +++ b/paper-server/patches/features/0028-Improved-Watchdog-Support.patch @@ -100,7 +100,7 @@ index e738405e5112584e02e01df2d5ede2676fa1bffb..560d80cb1177297210646b44ce25fd2f /* CraftBukkit start - Replace everything OptionParser optionParser = new OptionParser(); diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index 43306cac3549a03612077df3aacf501051d05a01..d077debf5936050484856e0b84f764967b5d3f5c 100644 +index ddd23354d68f5cbdc9f72c11246ab26a6c0bbe16..3f880bdfd95f7556d1d76e4602a6d24dda78438c 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java @@ -298,6 +298,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0; // Paper - BlockPhysicsEvent serverLevel.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - Add EntityMoveEvent serverLevel.updateLagCompensationTick(); // Paper - lag compensation diff --git a/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch b/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch index ca5ee37782..55497abf8a 100644 --- a/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch @@ -153,7 +153,7 @@ protected abstract boolean initServer() throws IOException; - protected void loadLevel() { -+ protected void loadLevel(String s) { // CraftBukkit ++ protected void loadLevel(String levelId) { // CraftBukkit if (!JvmProfiler.INSTANCE.isRunning()) { } @@ -165,11 +165,11 @@ - this.createLevels(chunkProgressListener); - this.forceDifficulty(); - this.prepareLevels(chunkProgressListener); -+ this.loadWorld0(s); // CraftBukkit ++ this.loadWorld0(levelId); // CraftBukkit if (profiledDuration != null) { profiledDuration.finish(true); } -@@ -364,25 +_,245 @@ +@@ -364,25 +_,265 @@ protected void forceDifficulty() { } @@ -193,37 +193,39 @@ - this.commandStorage = new CommandStorage(dataStorage); - WorldBorder worldBorder = serverLevel.getWorldBorder(); + // CraftBukkit start -+ private void loadWorld0(String s) { -+ LevelStorageSource.LevelStorageAccess worldSession = this.storageSource; -+ RegistryAccess.Frozen iregistrycustom_dimension = this.registries.compositeAccess(); -+ Registry dimensions = iregistrycustom_dimension.lookupOrThrow(Registries.LEVEL_STEM); -+ for (LevelStem worldDimension : dimensions) { -+ ResourceKey dimensionKey = dimensions.getResourceKey(worldDimension).get(); -+ ServerLevel world; ++ private void loadWorld0(String levelId) { ++ // Mostly modelled off of net.minecraft.server.Main ++ LevelStorageSource.LevelStorageAccess levelStorageAccess = this.storageSource; ++ RegistryAccess.Frozen registryAccess = this.registries.compositeAccess(); ++ Registry levelStemRegistry = registryAccess.lookupOrThrow(Registries.LEVEL_STEM); ++ for (LevelStem levelStem : levelStemRegistry) { ++ ResourceKey levelStemKey = levelStemRegistry.getResourceKey(levelStem).get(); ++ ServerLevel serverLevel; + int dimension = 0; + -+ if (dimensionKey == LevelStem.NETHER) { ++ if (levelStemKey == LevelStem.NETHER) { + if (this.server.getAllowNether()) { + dimension = -1; + } else { + continue; + } -+ } else if (dimensionKey == LevelStem.END) { ++ } else if (levelStemKey == LevelStem.END) { + if (this.server.getAllowEnd()) { + dimension = 1; + } else { + continue; + } -+ } else if (dimensionKey != LevelStem.OVERWORLD) { ++ } else if (levelStemKey != LevelStem.OVERWORLD) { + dimension = -999; + } + -+ String worldType = (dimension == -999) ? dimensionKey.location().getNamespace() + "_" + dimensionKey.location().getPath() : org.bukkit.World.Environment.getEnvironment(dimension).toString().toLowerCase(Locale.ROOT); -+ String name = (dimensionKey == LevelStem.OVERWORLD) ? s : s + "_" + worldType; ++ // Migration of old CB world folders... ++ String worldType = (dimension == -999) ? levelStemKey.location().getNamespace() + "_" + levelStemKey.location().getPath() : org.bukkit.World.Environment.getEnvironment(dimension).toString().toLowerCase(Locale.ROOT); ++ String name = (levelStemKey == LevelStem.OVERWORLD) ? levelId : levelId + "_" + worldType; + if (dimension != 0) { -+ java.io.File newWorld = LevelStorageSource.getStorageFolder(new java.io.File(name).toPath(), dimensionKey).toFile(); -+ java.io.File oldWorld = LevelStorageSource.getStorageFolder(new java.io.File(s).toPath(), dimensionKey).toFile(); -+ java.io.File oldLevelDat = new java.io.File(new java.io.File(s), "level.dat"); // The data folders exist on first run as they are created in the PersistentCollection constructor above, but the level.dat won't ++ java.io.File newWorld = LevelStorageSource.getStorageFolder(new java.io.File(name).toPath(), levelStemKey).toFile(); ++ java.io.File oldWorld = LevelStorageSource.getStorageFolder(new java.io.File(levelId).toPath(), levelStemKey).toFile(); ++ java.io.File oldLevelDat = new java.io.File(new java.io.File(levelId), "level.dat"); // The data folders exist on first run as they are created in the PersistentCollection constructor above, but the level.dat won't + + if (!newWorld.isDirectory() && oldWorld.isDirectory() && oldLevelDat.isFile()) { + MinecraftServer.LOGGER.info("---- Migration of old " + worldType + " folder required ----"); @@ -240,7 +242,7 @@ + // Migrate world data too. + try { + com.google.common.io.Files.copy(oldLevelDat, new java.io.File(new java.io.File(name), "level.dat")); -+ org.apache.commons.io.FileUtils.copyDirectory(new java.io.File(new java.io.File(s), "data"), new java.io.File(new java.io.File(name), "data")); ++ org.apache.commons.io.FileUtils.copyDirectory(new java.io.File(new java.io.File(levelId), "data"), new java.io.File(new java.io.File(name), "data")); + } catch (IOException exception) { + MinecraftServer.LOGGER.warn("Unable to migrate world data."); + } @@ -256,137 +258,155 @@ + } + + try { -+ worldSession = LevelStorageSource.createDefault(this.server.getWorldContainer().toPath()).validateAndCreateAccess(name, dimensionKey); ++ levelStorageAccess = LevelStorageSource.createDefault(this.server.getWorldContainer().toPath()).validateAndCreateAccess(name, levelStemKey); + } catch (IOException | net.minecraft.world.level.validation.ContentValidationException ex) { + throw new RuntimeException(ex); + } + } + -+ com.mojang.serialization.Dynamic dynamic; -+ if (worldSession.hasWorldData()) { -+ net.minecraft.world.level.storage.LevelSummary worldinfo; -+ ++ com.mojang.serialization.Dynamic dataTag; ++ if (levelStorageAccess.hasWorldData()) { ++ net.minecraft.world.level.storage.LevelSummary summary; + try { -+ dynamic = worldSession.getDataTag(); -+ worldinfo = worldSession.getSummary(dynamic); -+ } catch (net.minecraft.nbt.NbtException | net.minecraft.nbt.ReportedNbtException | IOException ioexception) { -+ LevelStorageSource.LevelDirectory convertable_b = worldSession.getLevelDirectory(); -+ -+ MinecraftServer.LOGGER.warn("Failed to load world data from {}", convertable_b.dataFile(), ioexception); ++ dataTag = levelStorageAccess.getDataTag(); ++ summary = levelStorageAccess.getSummary(dataTag); ++ } catch (net.minecraft.nbt.NbtException | net.minecraft.nbt.ReportedNbtException | IOException e) { ++ LevelStorageSource.LevelDirectory levelDirectory = levelStorageAccess.getLevelDirectory(); ++ MinecraftServer.LOGGER.warn("Failed to load world data from {}", levelDirectory.dataFile(), e); + MinecraftServer.LOGGER.info("Attempting to use fallback"); + + try { -+ dynamic = worldSession.getDataTagFallback(); -+ worldinfo = worldSession.getSummary(dynamic); -+ } catch (net.minecraft.nbt.NbtException | net.minecraft.nbt.ReportedNbtException | IOException ioexception1) { -+ MinecraftServer.LOGGER.error("Failed to load world data from {}", convertable_b.oldDataFile(), ioexception1); -+ MinecraftServer.LOGGER.error("Failed to load world data from {} and {}. World files may be corrupted. Shutting down.", convertable_b.dataFile(), convertable_b.oldDataFile()); ++ dataTag = levelStorageAccess.getDataTagFallback(); ++ summary = levelStorageAccess.getSummary(dataTag); ++ } catch (net.minecraft.nbt.NbtException | net.minecraft.nbt.ReportedNbtException | IOException e1) { ++ MinecraftServer.LOGGER.error("Failed to load world data from {}", levelDirectory.oldDataFile(), e1); ++ MinecraftServer.LOGGER.error( ++ "Failed to load world data from {} and {}. World files may be corrupted. Shutting down.", ++ levelDirectory.dataFile(), ++ levelDirectory.oldDataFile() ++ ); + return; + } + -+ worldSession.restoreLevelDataFromOld(); ++ levelStorageAccess.restoreLevelDataFromOld(); + } + -+ if (worldinfo.requiresManualConversion()) { ++ if (summary.requiresManualConversion()) { + MinecraftServer.LOGGER.info("This world must be opened in an older version (like 1.6.4) to be safely converted"); + return; + } + -+ if (!worldinfo.isCompatible()) { ++ if (!summary.isCompatible()) { + MinecraftServer.LOGGER.info("This world was created by an incompatible version."); + return; + } + } else { -+ dynamic = null; ++ dataTag = null; + } + -+ org.bukkit.generator.ChunkGenerator gen = this.server.getGenerator(name); ++ org.bukkit.generator.ChunkGenerator chunkGenerator = this.server.getGenerator(name); + org.bukkit.generator.BiomeProvider biomeProvider = this.server.getBiomeProvider(name); + -+ net.minecraft.world.level.storage.PrimaryLevelData worlddata; -+ WorldLoader.DataLoadContext worldloader_a = this.worldLoader; -+ Registry iregistry = worldloader_a.datapackDimensions().lookupOrThrow(Registries.LEVEL_STEM); -+ if (dynamic != null) { -+ net.minecraft.world.level.storage.LevelDataAndDimensions leveldataanddimensions = LevelStorageSource.getLevelDataAndDimensions(dynamic, worldloader_a.dataConfiguration(), iregistry, worldloader_a.datapackWorldgen()); -+ -+ worlddata = (net.minecraft.world.level.storage.PrimaryLevelData) leveldataanddimensions.worldData(); ++ net.minecraft.world.level.storage.PrimaryLevelData primaryLevelData; ++ WorldLoader.DataLoadContext context = this.worldLoader; ++ Registry contextLevelStemRegistry = context.datapackDimensions().lookupOrThrow(Registries.LEVEL_STEM); ++ if (dataTag != null) { ++ net.minecraft.world.level.storage.LevelDataAndDimensions levelDataAndDimensions = LevelStorageSource.getLevelDataAndDimensions( ++ dataTag, context.dataConfiguration(), contextLevelStemRegistry, context.datapackWorldgen() ++ ); ++ primaryLevelData = (net.minecraft.world.level.storage.PrimaryLevelData) levelDataAndDimensions.worldData(); + } else { -+ LevelSettings worldsettings; -+ WorldOptions worldoptions; -+ net.minecraft.world.level.levelgen.WorldDimensions worlddimensions; -+ ++ LevelSettings levelSettings; ++ WorldOptions worldOptions; ++ net.minecraft.world.level.levelgen.WorldDimensions worldDimensions; + if (this.isDemo()) { -+ worldsettings = MinecraftServer.DEMO_SETTINGS; -+ worldoptions = WorldOptions.DEMO_OPTIONS; -+ worlddimensions = net.minecraft.world.level.levelgen.presets.WorldPresets.createNormalWorldDimensions(worldloader_a.datapackWorldgen()); ++ levelSettings = MinecraftServer.DEMO_SETTINGS; ++ worldOptions = WorldOptions.DEMO_OPTIONS; ++ worldDimensions = net.minecraft.world.level.levelgen.presets.WorldPresets.createNormalWorldDimensions(context.datapackWorldgen()); + } else { -+ net.minecraft.server.dedicated.DedicatedServerProperties dedicatedserverproperties = ((net.minecraft.server.dedicated.DedicatedServer) this).getProperties(); -+ -+ worldsettings = new LevelSettings(dedicatedserverproperties.levelName, dedicatedserverproperties.gamemode, dedicatedserverproperties.hardcore, dedicatedserverproperties.difficulty, false, new GameRules(worldloader_a.dataConfiguration().enabledFeatures()), worldloader_a.dataConfiguration()); -+ worldoptions = this.options.has("bonusChest") ? dedicatedserverproperties.worldOptions.withBonusChest(true) : dedicatedserverproperties.worldOptions; -+ worlddimensions = dedicatedserverproperties.createDimensions(worldloader_a.datapackWorldgen()); ++ net.minecraft.server.dedicated.DedicatedServerProperties properties = ((net.minecraft.server.dedicated.DedicatedServer) this).getProperties(); ++ levelSettings = new LevelSettings( ++ properties.levelName, ++ properties.gamemode, ++ properties.hardcore, ++ properties.difficulty, ++ false, ++ new GameRules(context.dataConfiguration().enabledFeatures()), ++ context.dataConfiguration() ++ ); ++ worldOptions = this.options.has("bonusChest") ? properties.worldOptions.withBonusChest(true) : properties.worldOptions; // CraftBukkit ++ worldDimensions = properties.createDimensions(context.datapackWorldgen()); + } + -+ net.minecraft.world.level.levelgen.WorldDimensions.Complete worlddimensions_b = worlddimensions.bake(iregistry); -+ com.mojang.serialization.Lifecycle lifecycle = worlddimensions_b.lifecycle().add(worldloader_a.datapackWorldgen().allRegistriesLifecycle()); ++ net.minecraft.world.level.levelgen.WorldDimensions.Complete complete = worldDimensions.bake(contextLevelStemRegistry); ++ com.mojang.serialization.Lifecycle lifecycle = complete.lifecycle().add(context.datapackWorldgen().allRegistriesLifecycle()); + -+ worlddata = new net.minecraft.world.level.storage.PrimaryLevelData(worldsettings, worldoptions, worlddimensions_b.specialWorldProperty(), lifecycle); ++ primaryLevelData = new net.minecraft.world.level.storage.PrimaryLevelData(levelSettings, worldOptions, complete.specialWorldProperty(), lifecycle); + } -+ worlddata.checkName(name); // CraftBukkit - Migration did not rewrite the level.dat; This forces 1.8 to take the last loaded world as respawn (in this case the end) ++ ++ primaryLevelData.checkName(name); // CraftBukkit - Migration did not rewrite the level.dat; This forces 1.8 to take the last loaded world as respawn (in this case the end) + if (this.options.has("forceUpgrade")) { -+ net.minecraft.server.Main.forceUpgrade(worldSession, net.minecraft.util.datafix.DataFixers.getDataFixer(), this.options.has("eraseCache"), () -> { -+ return true; -+ }, iregistrycustom_dimension, this.options.has("recreateRegionFiles")); ++ net.minecraft.server.Main.forceUpgrade(levelStorageAccess, net.minecraft.util.datafix.DataFixers.getDataFixer(), this.options.has("eraseCache"), () -> true, registryAccess, this.options.has("recreateRegionFiles")); + } + -+ net.minecraft.world.level.storage.PrimaryLevelData iworlddataserver = worlddata; -+ boolean flag = worlddata.isDebugWorld(); -+ WorldOptions worldoptions = worlddata.worldGenOptions(); -+ long i = worldoptions.seed(); -+ long j = BiomeManager.obfuscateSeed(i); -+ List list = ImmutableList.of(new PhantomSpawner(), new PatrolSpawner(), new CatSpawner(), new VillageSiege(), new WanderingTraderSpawner(iworlddataserver)); -+ LevelStem worlddimension = (LevelStem) dimensions.getValue(dimensionKey); ++ // Now modelled off the createLevels method ++ net.minecraft.world.level.storage.PrimaryLevelData serverLevelData = primaryLevelData; ++ boolean isDebugWorld = primaryLevelData.isDebugWorld(); ++ WorldOptions worldOptions = primaryLevelData.worldGenOptions(); ++ long seed = worldOptions.seed(); ++ long l = BiomeManager.obfuscateSeed(seed); ++ List list = ImmutableList.of( ++ new PhantomSpawner(), new PatrolSpawner(), new CatSpawner(), new VillageSiege(), new WanderingTraderSpawner(serverLevelData) ++ ); ++ LevelStem customStem = levelStemRegistry.getValue(levelStemKey); + -+ org.bukkit.generator.WorldInfo worldInfo = new org.bukkit.craftbukkit.generator.CraftWorldInfo(iworlddataserver, worldSession, org.bukkit.World.Environment.getEnvironment(dimension), worlddimension.type().value(), worlddimension.generator(), this.registryAccess()); // Paper - Expose vanilla BiomeProvider from WorldInfo -+ if (biomeProvider == null && gen != null) { -+ biomeProvider = gen.getDefaultBiomeProvider(worldInfo); ++ org.bukkit.generator.WorldInfo worldInfo = new org.bukkit.craftbukkit.generator.CraftWorldInfo(serverLevelData, levelStorageAccess, org.bukkit.World.Environment.getEnvironment(dimension), customStem.type().value(), customStem.generator(), this.registryAccess()); // Paper - Expose vanilla BiomeProvider from WorldInfo ++ if (biomeProvider == null && chunkGenerator != null) { ++ biomeProvider = chunkGenerator.getDefaultBiomeProvider(worldInfo); + } + -+ ResourceKey worldKey = ResourceKey.create(Registries.DIMENSION, dimensionKey.location()); ++ ResourceKey dimensionKey = ResourceKey.create(Registries.DIMENSION, levelStemKey.location()); + -+ if (dimensionKey == LevelStem.OVERWORLD) { -+ this.worldData = worlddata; ++ if (levelStemKey == LevelStem.OVERWORLD) { ++ this.worldData = primaryLevelData; + this.worldData.setGameType(((net.minecraft.server.dedicated.DedicatedServer) this).getProperties().gamemode); // From DedicatedServer.init + -+ ChunkProgressListener worldloadlistener = this.progressListenerFactory.create(this.worldData.getGameRules().getInt(GameRules.RULE_SPAWN_CHUNK_RADIUS)); ++ ChunkProgressListener listener = this.progressListenerFactory.create(this.worldData.getGameRules().getInt(GameRules.RULE_SPAWN_CHUNK_RADIUS)); + -+ world = new ServerLevel(this, this.executor, worldSession, iworlddataserver, worldKey, worlddimension, worldloadlistener, flag, j, list, true, (RandomSequences) null, org.bukkit.World.Environment.getEnvironment(dimension), gen, biomeProvider); -+ DimensionDataStorage worldpersistentdata = world.getDataStorage(); -+ this.readScoreboard(worldpersistentdata); -+ this.server.scoreboardManager = new org.bukkit.craftbukkit.scoreboard.CraftScoreboardManager(this, world.getScoreboard()); -+ this.commandStorage = new CommandStorage(worldpersistentdata); ++ serverLevel = new ServerLevel( ++ this, this.executor, levelStorageAccess, serverLevelData, dimensionKey, customStem, listener, isDebugWorld, l, list, true, null, ++ org.bukkit.World.Environment.getEnvironment(dimension), chunkGenerator, biomeProvider ++ ); ++ DimensionDataStorage dataStorage = serverLevel.getDataStorage(); ++ this.readScoreboard(dataStorage); ++ this.commandStorage = new CommandStorage(dataStorage); ++ this.server.scoreboardManager = new org.bukkit.craftbukkit.scoreboard.CraftScoreboardManager(this, serverLevel.getScoreboard()); + } else { -+ ChunkProgressListener worldloadlistener = this.progressListenerFactory.create(this.worldData.getGameRules().getInt(GameRules.RULE_SPAWN_CHUNK_RADIUS)); ++ ChunkProgressListener listener = this.progressListenerFactory.create(this.worldData.getGameRules().getInt(GameRules.RULE_SPAWN_CHUNK_RADIUS)); + // Paper start - option to use the dimension_type to check if spawners should be added. I imagine mojang will add some datapack-y way of managing this in the future. + final List spawners; -+ if (io.papermc.paper.configuration.GlobalConfiguration.get().misc.useDimensionTypeForCustomSpawners && this.registryAccess().lookupOrThrow(Registries.DIMENSION_TYPE).getResourceKey(worlddimension.type().value()).orElseThrow() == net.minecraft.world.level.dimension.BuiltinDimensionTypes.OVERWORLD) { ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().misc.useDimensionTypeForCustomSpawners && this.registryAccess().lookupOrThrow(Registries.DIMENSION_TYPE).getResourceKey(customStem.type().value()).orElseThrow() == net.minecraft.world.level.dimension.BuiltinDimensionTypes.OVERWORLD) { + spawners = list; + } else { + spawners = Collections.emptyList(); + } -+ world = new ServerLevel(this, this.executor, worldSession, iworlddataserver, worldKey, worlddimension, worldloadlistener, flag, j, spawners, true, this.overworld().getRandomSequences(), org.bukkit.World.Environment.getEnvironment(dimension), gen, biomeProvider); ++ serverLevel = new ServerLevel( ++ this, this.executor, levelStorageAccess, serverLevelData, dimensionKey, customStem, listener, isDebugWorld, l, spawners, true, this.overworld().getRandomSequences(), ++ org.bukkit.World.Environment.getEnvironment(dimension), chunkGenerator, biomeProvider ++ ); + // Paper end - option to use the dimension_type to check if spawners should be added + } + -+ worlddata.setModdedInfo(this.getServerModName(), this.getModdedStatus().shouldReportAsModified()); -+ this.addLevel(world); // Paper - Put world into worldlist before initing the world; move up -+ this.initWorld(world, worlddata, this.worldData, worldoptions); ++ // Back to the createLevels method without crazy modifications ++ primaryLevelData.setModdedInfo(this.getServerModName(), this.getModdedStatus().shouldReportAsModified()); ++ this.addLevel(serverLevel); // Paper - Put world into worldlist before initing the world; move up ++ this.initWorld(serverLevel, primaryLevelData, this.worldData, worldOptions); + + // Paper - Put world into worldlist before initing the world; move up -+ this.getPlayerList().addWorldborderListener(world); ++ this.getPlayerList().addWorldborderListener(serverLevel); + -+ if (worlddata.getCustomBossEvents() != null) { -+ this.getCustomBossEvents().load(worlddata.getCustomBossEvents(), this.registryAccess()); ++ if (primaryLevelData.getCustomBossEvents() != null) { ++ this.getCustomBossEvents().load(primaryLevelData.getCustomBossEvents(), this.registryAccess()); + } + } + this.forceDifficulty(); @@ -1209,15 +1229,6 @@ private ProfilerFiller createProfiler() { if (this.willStartRecordingMetrics) { this.metricsRecorder = ActiveMetricsRecorder.createStarted( -@@ -1941,7 +_,7 @@ - } - - public ServerPlayerGameMode createGameModeForPlayer(ServerPlayer player) { -- return (ServerPlayerGameMode)(this.isDemo() ? new DemoMode(player) : new ServerPlayerGameMode(player)); -+ return (this.isDemo() ? new DemoMode(player) : new ServerPlayerGameMode(player)); - } - - @Nullable @@ -1980,16 +_,22 @@ } diff --git a/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch b/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch index ce890ce4a0..7c69b49dd9 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch @@ -206,30 +206,17 @@ if (thrownEnderpearl.isRemoved()) { LOGGER.warn("Trying to save removed ender pearl, skipping"); } else { -@@ -593,6 +_,29 @@ +@@ -593,6 +_,16 @@ } } -+ // CraftBukkit start - World fallback code, either respawn location or global spawn -+ public void spawnIn(Level world) { -+ this.setLevel(world); -+ if (world == null) { -+ this.unsetRemoved(); -+ Vec3 position = null; -+ if (this.respawnDimension != null) { -+ world = this.server.getLevel(this.respawnDimension); -+ if (world != null && this.getRespawnPosition() != null) { -+ position = ServerPlayer.findRespawnAndUseSpawnBlock((ServerLevel) world, this.getRespawnPosition(), this.getRespawnAngle(), false, false).map(ServerPlayer.RespawnPosAngle::position).orElse(null); -+ } -+ } -+ if (world == null || position == null) { -+ world = ((org.bukkit.craftbukkit.CraftWorld) org.bukkit.Bukkit.getServer().getWorlds().get(0)).getHandle(); -+ position = Vec3.atCenterOf(world.getSharedSpawnPos()); -+ } -+ this.setLevel(world); -+ this.setPosRaw(position.x(), position.y(), position.z()); // Paper - don't register to chunks yet ++ // CraftBukkit start ++ public void spawnIn(final ServerLevel level) { ++ if (level == null) { ++ throw new IllegalArgumentException("level can't be null"); + } -+ this.gameMode.setLevel((ServerLevel) world); ++ this.setLevel(level); ++ this.gameMode.setLevel(level); + } + // CraftBukkit end + @@ -840,7 +827,7 @@ + + { + { -+ Either either = super.startSleepInBed(at, force).ifRight((unit) -> { ++ Either either = super.startSleepInBed(at, force).ifRight(unit -> { + // CraftBukkit end this.awardStat(Stats.SLEEP_IN_BED); CriteriaTriggers.SLEPT_IN_BED.trigger(this); diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch index c53210937f..5c3d9c3714 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch @@ -808,7 +808,7 @@ d3 = d - this.player.getX(); d4 = d1 - this.player.getY(); if (d4 > -0.5 || d4 < 0.5) { -@@ -970,20 +_,104 @@ +@@ -970,20 +_,101 @@ d5 = d2 - this.player.getZ(); d7 = d3 * d3 + d4 * d4 + d5 * d5; @@ -847,11 +847,8 @@ + teleportBack = false; + } + } -+ if (teleportBack) { ++ if (!teleportBack) { + // Paper end - Add fail move event -+ this.internalTeleport(x, y, z, f, f1); // CraftBukkit - SPIGOT-1807: Don't call teleport event, when the client thinks the player is falling, because the chunks are not loaded on the client yet. -+ this.player.doCheckFallDamage(this.player.getX() - x, this.player.getY() - y, this.player.getZ() - z, packet.isOnGround()); -+ } else { + // CraftBukkit start - fire PlayerMoveEvent + // Reset to old location first + this.player.absMoveTo(prevX, prevY, prevZ, prevYaw, prevPitch); @@ -922,16 +919,15 @@ this.player.absMoveTo(d, d1, d2, f, f1); boolean isAutoSpinAttack = this.player.isAutoSpinAttack(); this.clientIsFloating = d4 >= -0.03125 -@@ -1018,9 +_,6 @@ - this.lastGoodX = this.player.getX(); +@@ -1019,7 +_,7 @@ this.lastGoodY = this.player.getY(); this.lastGoodZ = this.player.getZ(); -- } else { + } else { - this.teleport(x, y, z, f, f1); -- this.player.doCheckFallDamage(this.player.getX() - x, this.player.getY() - y, this.player.getZ() - z, packet.isOnGround()); ++ this.internalTeleport(x, y, z, f, f1); // CraftBukkit - SPIGOT-1807: Don't call teleport event, when the client thinks the player is falling, because the chunks are not loaded on the client yet. + this.player.doCheckFallDamage(this.player.getX() - x, this.player.getY() - y, this.player.getZ() - z, packet.isOnGround()); } } - } @@ -1053,6 +_,7 @@ this.player.getXRot() ); diff --git a/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch b/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch index 8239aa71e1..2ddcf75909 100644 --- a/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch @@ -47,7 +47,7 @@ GameProfile gameProfile = player.getGameProfile(); GameProfileCache profileCache = this.server.getProfileCache(); String string; -@@ -150,30 +_,94 @@ +@@ -150,30 +_,93 @@ } Optional optional = this.load(player); @@ -136,7 +136,6 @@ + serverLevel = ((org.bukkit.craftbukkit.CraftWorld) loc.getWorld()).getHandle(); + + player.spawnIn(serverLevel); -+ player.gameMode.setLevel((ServerLevel) player.level()); + // Paper start - set raw so we aren't fully joined to the world (not added to chunk or world) + player.setPosRaw(loc.getX(), loc.getY(), loc.getZ()); + player.setRot(loc.getYaw(), loc.getPitch()); @@ -334,7 +333,7 @@ } @Override -@@ -309,67 +_,175 @@ +@@ -309,56 +_,162 @@ } protected void save(ServerPlayer player) { @@ -469,8 +468,6 @@ - public Component canPlayerLogin(SocketAddress socketAddress, GameProfile gameProfile) { - if (this.bans.isBanned(gameProfile)) { - UserBanListEntry userBanListEntry = this.bans.get(gameProfile); -- MutableComponent mutableComponent = Component.translatable("multiplayer.disconnect.banned.reason", userBanListEntry.getReason()); -- if (userBanListEntry.getExpires() != null) { + // CraftBukkit start - Whole method, SocketAddress to LoginListener, added hostname to signature, return EntityPlayer + public ServerPlayer canPlayerLogin(net.minecraft.server.network.ServerLoginPacketListenerImpl loginlistener, GameProfile gameProfile) { + // if (this.bans.isBanned(gameProfile)) { @@ -507,14 +504,13 @@ + org.bukkit.event.player.PlayerLoginEvent event = new org.bukkit.event.player.PlayerLoginEvent(player, loginlistener.connection.hostname, ((java.net.InetSocketAddress) socketAddress).getAddress(), ((java.net.InetSocketAddress) loginlistener.connection.channel.remoteAddress()).getAddress()); + + // Paper start - Fix MC-158900 -+ UserBanListEntry gameprofilebanentry; -+ if (this.bans.isBanned(gameProfile) && (gameprofilebanentry = this.bans.get(gameProfile)) != null) { ++ UserBanListEntry userBanListEntry; ++ if (this.bans.isBanned(gameProfile) && (userBanListEntry = this.bans.get(gameProfile)) != null) { + // Paper end - Fix MC-158900 -+ MutableComponent mutableComponent = Component.translatable("multiplayer.disconnect.banned.reason", gameprofilebanentry.getReason()); -+ if (gameprofilebanentry.getExpires() != null) { + MutableComponent mutableComponent = Component.translatable("multiplayer.disconnect.banned.reason", userBanListEntry.getReason()); + if (userBanListEntry.getExpires() != null) { mutableComponent.append( -- Component.translatable("multiplayer.disconnect.banned.expiration", BAN_DATE_FORMAT.format(userBanListEntry.getExpires())) -+ Component.translatable("multiplayer.disconnect.banned.expiration", BAN_DATE_FORMAT.format(gameprofilebanentry.getExpires())) +@@ -366,10 +_,12 @@ ); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch index 6bbcc9ce75..3576351376 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch @@ -306,11 +306,10 @@ } public void onClientRemoval() { -@@ -367,7 +_,18 @@ +@@ -367,6 +_,17 @@ } public void setPose(Pose pose) { -- this.entityData.set(DATA_POSE, pose); + if (this.fixedPose) return; // Paper - Expand Pose API + // CraftBukkit start + if (pose == this.getPose()) { @@ -322,10 +321,9 @@ + } + // Paper end - Don't fire sync event during generation + // CraftBukkit end -+ this.entityData.set(Entity.DATA_POSE, pose); + this.entityData.set(DATA_POSE, pose); } - public Pose getPose() { @@ -390,6 +_,32 @@ } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java index 104caaf260..f59b4a6998 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -1288,7 +1288,7 @@ public final class CraftServer implements Server { Preconditions.checkArgument(creator != null, "WorldCreator cannot be null"); String name = creator.name(); - ChunkGenerator generator = creator.generator(); + ChunkGenerator chunkGenerator = creator.generator(); BiomeProvider biomeProvider = creator.biomeProvider(); File folder = new File(this.getWorldContainer(), name); World world = this.getWorld(name); @@ -1307,151 +1307,170 @@ public final class CraftServer implements Server { Preconditions.checkArgument(folder.isDirectory(), "File (%s) exists and isn't a folder", name); } - if (generator == null) { - generator = this.getGenerator(name); + if (chunkGenerator == null) { + chunkGenerator = this.getGenerator(name); } if (biomeProvider == null) { biomeProvider = this.getBiomeProvider(name); } - ResourceKey actualDimension; - switch (creator.environment()) { - case NORMAL: - actualDimension = LevelStem.OVERWORLD; - break; - case NETHER: - actualDimension = LevelStem.NETHER; - break; - case THE_END: - actualDimension = LevelStem.END; - break; - default: - throw new IllegalArgumentException("Illegal dimension (" + creator.environment() + ")"); - } + ResourceKey actualDimension = switch (creator.environment()) { + case NORMAL -> LevelStem.OVERWORLD; + case NETHER -> LevelStem.NETHER; + case THE_END -> LevelStem.END; + default -> throw new IllegalArgumentException("Illegal dimension (" + creator.environment() + ")"); + }; - LevelStorageSource.LevelStorageAccess worldSession; + LevelStorageSource.LevelStorageAccess levelStorageAccess; try { - worldSession = LevelStorageSource.createDefault(this.getWorldContainer().toPath()).validateAndCreateAccess(name, actualDimension); + levelStorageAccess = LevelStorageSource.createDefault(this.getWorldContainer().toPath()).validateAndCreateAccess(name, actualDimension); } catch (IOException | ContentValidationException ex) { throw new RuntimeException(ex); } - Dynamic dynamic; - if (worldSession.hasWorldData()) { - net.minecraft.world.level.storage.LevelSummary worldinfo; - + Dynamic dataTag; + if (levelStorageAccess.hasWorldData()) { + net.minecraft.world.level.storage.LevelSummary summary; try { - dynamic = worldSession.getDataTag(); - worldinfo = worldSession.getSummary(dynamic); - } catch (NbtException | ReportedNbtException | IOException ioexception) { - LevelStorageSource.LevelDirectory convertable_b = worldSession.getLevelDirectory(); - - MinecraftServer.LOGGER.warn("Failed to load world data from {}", convertable_b.dataFile(), ioexception); + dataTag = levelStorageAccess.getDataTag(); + summary = levelStorageAccess.getSummary(dataTag); + } catch (NbtException | ReportedNbtException | IOException e) { + LevelStorageSource.LevelDirectory levelDirectory = levelStorageAccess.getLevelDirectory(); + MinecraftServer.LOGGER.warn("Failed to load world data from {}", levelDirectory.dataFile(), e); MinecraftServer.LOGGER.info("Attempting to use fallback"); try { - dynamic = worldSession.getDataTagFallback(); - worldinfo = worldSession.getSummary(dynamic); - } catch (NbtException | ReportedNbtException | IOException ioexception1) { - MinecraftServer.LOGGER.error("Failed to load world data from {}", convertable_b.oldDataFile(), ioexception1); - MinecraftServer.LOGGER.error("Failed to load world data from {} and {}. World files may be corrupted. Shutting down.", convertable_b.dataFile(), convertable_b.oldDataFile()); + dataTag = levelStorageAccess.getDataTagFallback(); + summary = levelStorageAccess.getSummary(dataTag); + } catch (NbtException | ReportedNbtException | IOException e1) { + MinecraftServer.LOGGER.error("Failed to load world data from {}", levelDirectory.oldDataFile(), e1); + MinecraftServer.LOGGER.error( + "Failed to load world data from {} and {}. World files may be corrupted. Shutting down.", + levelDirectory.dataFile(), + levelDirectory.oldDataFile() + ); return null; } - worldSession.restoreLevelDataFromOld(); + levelStorageAccess.restoreLevelDataFromOld(); } - if (worldinfo.requiresManualConversion()) { + if (summary.requiresManualConversion()) { MinecraftServer.LOGGER.info("This world must be opened in an older version (like 1.6.4) to be safely converted"); return null; } - if (!worldinfo.isCompatible()) { + if (!summary.isCompatible()) { MinecraftServer.LOGGER.info("This world was created by an incompatible version."); return null; } } else { - dynamic = null; + dataTag = null; } boolean hardcore = creator.hardcore(); - PrimaryLevelData worlddata; - WorldLoader.DataLoadContext worldloader_a = this.console.worldLoader; - RegistryAccess.Frozen iregistrycustom_dimension = worldloader_a.datapackDimensions(); - net.minecraft.core.Registry iregistry = iregistrycustom_dimension.lookupOrThrow(Registries.LEVEL_STEM); - if (dynamic != null) { - LevelDataAndDimensions leveldataanddimensions = LevelStorageSource.getLevelDataAndDimensions(dynamic, worldloader_a.dataConfiguration(), iregistry, worldloader_a.datapackWorldgen()); - - worlddata = (PrimaryLevelData) leveldataanddimensions.worldData(); - iregistrycustom_dimension = leveldataanddimensions.dimensions().dimensionsRegistryAccess(); + PrimaryLevelData primaryLevelData; + WorldLoader.DataLoadContext context = this.console.worldLoader; + RegistryAccess.Frozen registryAccess = context.datapackDimensions(); + net.minecraft.core.Registry contextLevelStemRegistry = registryAccess.lookupOrThrow(Registries.LEVEL_STEM); + if (dataTag != null) { + LevelDataAndDimensions levelDataAndDimensions = LevelStorageSource.getLevelDataAndDimensions( + dataTag, context.dataConfiguration(), contextLevelStemRegistry, context.datapackWorldgen() + ); + primaryLevelData = (PrimaryLevelData) levelDataAndDimensions.worldData(); + registryAccess = levelDataAndDimensions.dimensions().dimensionsRegistryAccess(); } else { - LevelSettings worldsettings; - WorldOptions worldoptions = new WorldOptions(creator.seed(), creator.generateStructures(), false); - WorldDimensions worlddimensions; + LevelSettings levelSettings; + WorldOptions worldOptions = new WorldOptions(creator.seed(), creator.generateStructures(), false); + WorldDimensions worldDimensions; DedicatedServerProperties.WorldDimensionData properties = new DedicatedServerProperties.WorldDimensionData(GsonHelper.parse((creator.generatorSettings().isEmpty()) ? "{}" : creator.generatorSettings()), creator.type().name().toLowerCase(Locale.ROOT)); + levelSettings = new LevelSettings( + name, + GameType.byId(this.getDefaultGameMode().getValue()), + hardcore, Difficulty.EASY, + false, + new GameRules(context.dataConfiguration().enabledFeatures()), + context.dataConfiguration()) + ; + worldDimensions = properties.create(context.datapackWorldgen()); - worldsettings = new LevelSettings(name, GameType.byId(this.getDefaultGameMode().getValue()), hardcore, Difficulty.EASY, false, new GameRules(worldloader_a.dataConfiguration().enabledFeatures()), worldloader_a.dataConfiguration()); - worlddimensions = properties.create(worldloader_a.datapackWorldgen()); + WorldDimensions.Complete complete = worldDimensions.bake(contextLevelStemRegistry); + Lifecycle lifecycle = complete.lifecycle().add(context.datapackWorldgen().allRegistriesLifecycle()); - WorldDimensions.Complete worlddimensions_b = worlddimensions.bake(iregistry); - Lifecycle lifecycle = worlddimensions_b.lifecycle().add(worldloader_a.datapackWorldgen().allRegistriesLifecycle()); - - worlddata = new PrimaryLevelData(worldsettings, worldoptions, worlddimensions_b.specialWorldProperty(), lifecycle); - iregistrycustom_dimension = worlddimensions_b.dimensionsRegistryAccess(); + primaryLevelData = new PrimaryLevelData(levelSettings, worldOptions, complete.specialWorldProperty(), lifecycle); + registryAccess = complete.dimensionsRegistryAccess(); } - iregistry = iregistrycustom_dimension.lookupOrThrow(Registries.LEVEL_STEM); - worlddata.customDimensions = iregistry; - worlddata.checkName(name); - worlddata.setModdedInfo(this.console.getServerModName(), this.console.getModdedStatus().shouldReportAsModified()); + + contextLevelStemRegistry = registryAccess.lookupOrThrow(Registries.LEVEL_STEM); + primaryLevelData.customDimensions = contextLevelStemRegistry; + primaryLevelData.checkName(name); + primaryLevelData.setModdedInfo(this.console.getServerModName(), this.console.getModdedStatus().shouldReportAsModified()); if (this.console.options.has("forceUpgrade")) { - net.minecraft.server.Main.forceUpgrade(worldSession, DataFixers.getDataFixer(), this.console.options.has("eraseCache"), () -> true, iregistrycustom_dimension, this.console.options.has("recreateRegionFiles")); + net.minecraft.server.Main.forceUpgrade(levelStorageAccess, DataFixers.getDataFixer(), this.console.options.has("eraseCache"), () -> true, registryAccess, this.console.options.has("recreateRegionFiles")); } - long j = BiomeManager.obfuscateSeed(worlddata.worldGenOptions().seed()); // Paper - use world seed - List list = ImmutableList.of(new PhantomSpawner(), new PatrolSpawner(), new CatSpawner(), new VillageSiege(), new WanderingTraderSpawner(worlddata)); - LevelStem worlddimension = iregistry.getValue(actualDimension); + long i = BiomeManager.obfuscateSeed(primaryLevelData.worldGenOptions().seed()); + List list = ImmutableList.of( + new PhantomSpawner(), new PatrolSpawner(), new CatSpawner(), new VillageSiege(), new WanderingTraderSpawner(primaryLevelData) + ); + LevelStem customStem = contextLevelStemRegistry.getValue(actualDimension); - WorldInfo worldInfo = new CraftWorldInfo(worlddata, worldSession, creator.environment(), worlddimension.type().value(), worlddimension.generator(), this.getHandle().getServer().registryAccess()); // Paper - Expose vanilla BiomeProvider from WorldInfo - if (biomeProvider == null && generator != null) { - biomeProvider = generator.getDefaultBiomeProvider(worldInfo); + WorldInfo worldInfo = new CraftWorldInfo(primaryLevelData, levelStorageAccess, creator.environment(), customStem.type().value(), customStem.generator(), this.getHandle().getServer().registryAccess()); // Paper - Expose vanilla BiomeProvider from WorldInfo + if (biomeProvider == null && chunkGenerator != null) { + biomeProvider = chunkGenerator.getDefaultBiomeProvider(worldInfo); } - ResourceKey worldKey; + ResourceKey dimensionKey; String levelName = this.getServer().getProperties().levelName; if (name.equals(levelName + "_nether")) { - worldKey = net.minecraft.world.level.Level.NETHER; + dimensionKey = net.minecraft.world.level.Level.NETHER; } else if (name.equals(levelName + "_the_end")) { - worldKey = net.minecraft.world.level.Level.END; + dimensionKey = net.minecraft.world.level.Level.END; } else { - worldKey = ResourceKey.create(Registries.DIMENSION, ResourceLocation.fromNamespaceAndPath(creator.key().namespace(), creator.key().value())); + dimensionKey = ResourceKey.create(Registries.DIMENSION, ResourceLocation.fromNamespaceAndPath(creator.key().namespace(), creator.key().value())); } // If set to not keep spawn in memory (changed from default) then adjust rule accordingly if (creator.keepSpawnLoaded() == net.kyori.adventure.util.TriState.FALSE) { // Paper - worlddata.getGameRules().getRule(GameRules.RULE_SPAWN_CHUNK_RADIUS).set(0, null); + primaryLevelData.getGameRules().getRule(GameRules.RULE_SPAWN_CHUNK_RADIUS).set(0, null); } - ServerLevel internal = (ServerLevel) new ServerLevel(this.console, this.console.executor, worldSession, worlddata, worldKey, worlddimension, this.getServer().progressListenerFactory.create(worlddata.getGameRules().getInt(GameRules.RULE_SPAWN_CHUNK_RADIUS)), - worlddata.isDebugWorld(), j, creator.environment() == Environment.NORMAL ? list : ImmutableList.of(), true, this.console.overworld().getRandomSequences(), creator.environment(), generator, biomeProvider); + + ServerLevel serverLevel = new ServerLevel( + this.console, + this.console.executor, + levelStorageAccess, + primaryLevelData, + dimensionKey, + customStem, + this.getServer().progressListenerFactory.create(primaryLevelData.getGameRules().getInt(GameRules.RULE_SPAWN_CHUNK_RADIUS)), + primaryLevelData.isDebugWorld(), + i, + creator.environment() == Environment.NORMAL ? list : ImmutableList.of(), + true, + this.console.overworld().getRandomSequences(), + creator.environment(), + chunkGenerator, biomeProvider + ); if (!(this.worlds.containsKey(name.toLowerCase(Locale.ROOT)))) { return null; } - this.console.addLevel(internal); // Paper - Put world into worldlist before initing the world; move up - this.console.initWorld(internal, worlddata, worlddata, worlddata.worldGenOptions()); + this.console.addLevel(serverLevel); // Paper - Put world into worldlist before initing the world; move up + this.console.initWorld(serverLevel, primaryLevelData, primaryLevelData, primaryLevelData.worldGenOptions()); - internal.setSpawnSettings(true); + serverLevel.setSpawnSettings(true); // Paper - Put world into worldlist before initing the world; move up - this.getServer().prepareLevels(internal.getChunkSource().chunkMap.progressListener, internal); - io.papermc.paper.FeatureHooks.tickEntityManager(internal); // SPIGOT-6526: Load pending entities so they are available to the API // Paper - chunk system + this.getServer().prepareLevels(serverLevel.getChunkSource().chunkMap.progressListener, serverLevel); + io.papermc.paper.FeatureHooks.tickEntityManager(serverLevel); // SPIGOT-6526: Load pending entities so they are available to the API // Paper - chunk system - this.pluginManager.callEvent(new WorldLoadEvent(internal.getWorld())); - return internal.getWorld(); + this.pluginManager.callEvent(new WorldLoadEvent(serverLevel.getWorld())); + return serverLevel.getWorld(); } @Override