diff --git a/build-data/paper.at b/build-data/paper.at index 3bd1667cc3..f18d4fd87a 100644 --- a/build-data/paper.at +++ b/build-data/paper.at @@ -143,7 +143,6 @@ public net.minecraft.world.entity.Entity isInBubbleColumn()Z # Allow delegation to vanilla chunk gen public org.bukkit.craftbukkit.generator.CustomChunkGenerator delegate -private-f org.bukkit.craftbukkit.generator.CraftChunkData sections # Optimize redstone algorithm public net.minecraft.world.level.block.RedStoneWireBlock shouldSignal diff --git a/patches/api/Allow-delegation-to-vanilla-chunk-gen.patch b/patches/api/Allow-delegation-to-vanilla-chunk-gen.patch new file mode 100644 index 0000000000..8a34f1c3b8 --- /dev/null +++ b/patches/api/Allow-delegation-to-vanilla-chunk-gen.patch @@ -0,0 +1,89 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MiniDigger | Martin +Date: Wed, 29 Apr 2020 02:09:17 +0200 +Subject: [PATCH] Allow delegation to vanilla chunk gen + + +diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -0,0 +0,0 @@ public final class Bukkit { + return server.createChunkData(world); + } + ++ // Paper start ++ /** ++ * Create a ChunkData for use in a generator, that is populated by the vanilla generator for that world ++ * ++ * @param world the world to create the ChunkData for ++ * @param x the x coordinate of the chunk ++ * @param z the z coordinate of the chunk ++ * @return a new ChunkData for the world ++ * @deprecated The new multi-stage worldgen API allows a similar effect by overriding all of the "shouldGenerate..." methods to ++ * return true, and then modifying the chunkdata in a later stage such as surface or bedrock generation. ++ */ ++ @NotNull ++ @Deprecated(forRemoval = true) ++ public static ChunkGenerator.ChunkData createVanillaChunkData(@NotNull World world, int x, int z) { ++ return server.createVanillaChunkData(world, x, z); ++ } ++ // Paper stop ++ + /** + * Creates a boss bar instance to display to players. The progress + * defaults to 1.0 +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -0,0 +0,0 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + @NotNull + public ChunkGenerator.ChunkData createChunkData(@NotNull World world); + ++ // Paper start ++ /** ++ * Create a ChunkData for use in a generator, that is populated by the vanilla generator for that world. ++ * ++ * @param world the world to create the ChunkData for ++ * @param x the x coordinate of the chunk ++ * @param z the z coordinate of the chunk ++ * @return a new ChunkData for the world ++ * @deprecated The new multi-stage worldgen API allows a similar effect by overriding all of the "shouldGenerate..." methods to ++ * return true, and then modifying the chunkdata in a later stage such as surface or bedrock generation. ++ */ ++ @NotNull ++ @Deprecated(forRemoval = true) ++ ChunkGenerator.ChunkData createVanillaChunkData(@NotNull World world, int x, int z); ++ // Paper end ++ + /** + * Creates a boss bar instance to display to players. The progress + * defaults to 1.0 +diff --git a/src/main/java/org/bukkit/generator/ChunkGenerator.java b/src/main/java/org/bukkit/generator/ChunkGenerator.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/org/bukkit/generator/ChunkGenerator.java ++++ b/src/main/java/org/bukkit/generator/ChunkGenerator.java +@@ -0,0 +0,0 @@ public abstract class ChunkGenerator { + return false; + } + ++ // Paper start ++ /** ++ * Create a ChunkData for use in a generator, that is populated by the vanilla generator for that world ++ * ++ * @param world the world to create the ChunkData for ++ * @param x the x coordinate of the chunk ++ * @param z the z coordinate of the chunk ++ * @return a new ChunkData for the world ++ * ++ */ ++ @NotNull ++ public ChunkData createVanillaChunkData(@NotNull World world, int x, int z) { ++ return Bukkit.getServer().createVanillaChunkData(world, x, z); ++ } ++ // Paper end ++ + /** + * Data for a Chunk. + */ diff --git a/patches/server/Allow-delegation-to-vanilla-chunk-gen.patch b/patches/server/Allow-delegation-to-vanilla-chunk-gen.patch new file mode 100644 index 0000000000..30e6e58de9 --- /dev/null +++ b/patches/server/Allow-delegation-to-vanilla-chunk-gen.patch @@ -0,0 +1,146 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MiniDigger | Martin +Date: Wed, 29 Apr 2020 02:10:32 +0200 +Subject: [PATCH] Allow delegation to vanilla chunk gen + + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -0,0 +0,0 @@ public final class CraftServer implements Server { + return new OldCraftChunkData(world.getMinHeight(), world.getMaxHeight(), handle.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), world); // Paper - Anti-Xray - Add parameters + } + ++ // Paper start ++ private static final List VANILLA_GEN_STATUSES = List.of( ++ net.minecraft.world.level.chunk.ChunkStatus.EMPTY, ++ net.minecraft.world.level.chunk.ChunkStatus.STRUCTURE_STARTS, ++ net.minecraft.world.level.chunk.ChunkStatus.STRUCTURE_REFERENCES, ++ net.minecraft.world.level.chunk.ChunkStatus.BIOMES, ++ net.minecraft.world.level.chunk.ChunkStatus.NOISE, ++ net.minecraft.world.level.chunk.ChunkStatus.SURFACE, ++ net.minecraft.world.level.chunk.ChunkStatus.CARVERS, ++ net.minecraft.world.level.chunk.ChunkStatus.LIQUID_CARVERS, ++ net.minecraft.world.level.chunk.ChunkStatus.FEATURES, ++ net.minecraft.world.level.chunk.ChunkStatus.LIGHT ++ ); ++ ++ @net.minecraft.MethodsReturnNonnullByDefault ++ private static final class PaperEmptyLevelChunk extends net.minecraft.world.level.chunk.EmptyLevelChunk { ++ private final net.minecraft.world.level.biome.Biome biome; ++ ++ public PaperEmptyLevelChunk(net.minecraft.world.level.Level world, net.minecraft.world.level.ChunkPos pos) { ++ super(world, pos); ++ this.biome = this.level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY).getOrThrow(net.minecraft.world.level.biome.Biomes.PLAINS); ++ } ++ ++ @Override ++ public net.minecraft.world.level.biome.Biome getNoiseBiome(int biomeX, int biomeY, int biomeZ) { ++ return this.biome; ++ } ++ ++ @Override ++ public void markPosForPostprocessing(BlockPos pos) {} ++ } ++ ++ @Override ++ @Deprecated(forRemoval = true) ++ public ChunkGenerator.ChunkData createVanillaChunkData(World world, int x, int z) { ++ // do bunch of vanilla shit ++ final net.minecraft.server.level.ServerLevel serverLevel = ((CraftWorld) world).getHandle(); ++ final Registry biomeRegistry = serverLevel.getServer().registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); ++ final net.minecraft.world.level.chunk.ProtoChunk protoChunk = new net.minecraft.world.level.chunk.ProtoChunk( ++ new net.minecraft.world.level.ChunkPos(x, z), ++ net.minecraft.world.level.chunk.UpgradeData.EMPTY, ++ serverLevel, ++ biomeRegistry, ++ null ++ ); ++ ++ final net.minecraft.world.level.chunk.ChunkGenerator chunkGenerator; ++ if (serverLevel.chunkSource.getGenerator() instanceof org.bukkit.craftbukkit.generator.CustomChunkGenerator bukkit) { ++ chunkGenerator = bukkit.delegate; ++ } else { ++ chunkGenerator = serverLevel.chunkSource.getGenerator(); ++ } ++ ++ final net.minecraft.world.level.ChunkPos chunkPos = new net.minecraft.world.level.ChunkPos(x, z); ++ final net.minecraft.util.thread.ProcessorMailbox mailbox = net.minecraft.util.thread.ProcessorMailbox.create( ++ net.minecraft.Util.backgroundExecutor(), ++ "CraftServer#createVanillaChunkData(worldName='" + world.getName() + "', x='" + x + "', z='" + z + "')" ++ ); ++ for (final net.minecraft.world.level.chunk.ChunkStatus chunkStatus : VANILLA_GEN_STATUSES) { ++ final List chunks = Lists.newArrayList(); ++ final int statusRange = Math.max(1, chunkStatus.getRange()); ++ ++ for (int zz = chunkPos.z - statusRange; zz <= chunkPos.z + statusRange; ++zz) { ++ for (int xx = chunkPos.x - statusRange; xx <= chunkPos.x + statusRange; ++xx) { ++ if (xx == chunkPos.x && zz == chunkPos.z) { ++ chunks.add(protoChunk); ++ } else { ++ final net.minecraft.world.level.chunk.ChunkAccess chunk = new PaperEmptyLevelChunk(serverLevel, new net.minecraft.world.level.ChunkPos(xx, zz)); ++ chunks.add(chunk); ++ } ++ } ++ } ++ ++ chunkStatus.generate( ++ mailbox::tell, ++ serverLevel, ++ chunkGenerator, ++ serverLevel.getStructureManager(), ++ serverLevel.chunkSource.getLightEngine(), ++ chunk -> { ++ throw new UnsupportedOperationException("Not creating full chunks here"); ++ }, ++ chunks, ++ true ++ ).thenAccept(either -> { ++ if (chunkStatus == net.minecraft.world.level.chunk.ChunkStatus.NOISE) { ++ either.left().ifPresent(chunk -> net.minecraft.world.level.levelgen.Heightmap.primeHeightmaps(chunk, net.minecraft.world.level.chunk.ChunkStatus.POST_FEATURES)); ++ } ++ }).join(); ++ } ++ ++ // get empty object ++ OldCraftChunkData data = (OldCraftChunkData) this.createChunkData(world); ++ // copy over generated sections ++ data.getLights().addAll(protoChunk.getLights().toList()); ++ data.setRawChunkData(protoChunk.getSections()); ++ // hooray! ++ return data; ++ } ++ // Paper end ++ + @Override + public BossBar createBossBar(String title, BarColor color, BarStyle style, BarFlag... flags) { + return new CraftBossBar(title, color, style, flags); +diff --git a/src/main/java/org/bukkit/craftbukkit/generator/OldCraftChunkData.java b/src/main/java/org/bukkit/craftbukkit/generator/OldCraftChunkData.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/org/bukkit/craftbukkit/generator/OldCraftChunkData.java ++++ b/src/main/java/org/bukkit/craftbukkit/generator/OldCraftChunkData.java +@@ -0,0 +0,0 @@ import org.bukkit.material.MaterialData; + public final class OldCraftChunkData implements ChunkGenerator.ChunkData { + private final int minHeight; + private final int maxHeight; +- private final LevelChunkSection[] sections; ++ private LevelChunkSection[] sections; // Paper + private final Registry biomes; + private Set tiles; + private final Set lights = new HashSet<>(); +@@ -0,0 +0,0 @@ public final class OldCraftChunkData implements ChunkGenerator.ChunkData { + return this.tiles; + } + +- Set getLights() { ++ public Set getLights() { // Paper + return this.lights; + } ++ ++ // Paper start ++ public void setRawChunkData(LevelChunkSection[] sections) { ++ this.sections = sections; ++ } ++ // Paper end + }