From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: dfsek Date: Sat, 19 Jun 2021 20:15:59 -0700 Subject: [PATCH] Add Feature Generation API diff --git a/src/main/java/io/papermc/paper/world/gen/CraftProtoWorld.java b/src/main/java/io/papermc/paper/world/gen/CraftProtoWorld.java new file mode 100644 index 0000000000000000000000000000000000000000..33de2d14a90b405c6c0057e1f01d38a5c9e0d3f2 --- /dev/null +++ b/src/main/java/io/papermc/paper/world/gen/CraftProtoWorld.java @@ -0,0 +1,94 @@ +package io.papermc.paper.world.gen; + +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.world.entity.Mob; +import net.minecraft.world.entity.MobSpawnType; +import net.minecraft.world.entity.SpawnGroupData; +import org.bukkit.World; +import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.block.data.CraftBlockData; +import org.bukkit.entity.Entity; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.util.Vector; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; +import java.util.function.Consumer; + +public class CraftProtoWorld implements ProtoWorld { + private WorldGenRegion region; + + public CraftProtoWorld(WorldGenRegion region) { + this.region = region; + } + + public void clearReference() { + region = null; + } + + @Override + public void setBlockData(int x, int y, int z, @NotNull BlockData data) { + BlockPos position = new BlockPos(x, y, z); + getDelegate().setBlock(position, ((CraftBlockData) data).getState(), 3); + } + + @Override + public void scheduleBlockUpdate(int x, int y, int z) { + BlockPos position = new BlockPos(x, y, z); + getDelegate().getBlockTicks().scheduleTick(position, getDelegate().getBlockIfLoaded(position), 0); + } + + @Override + public void scheduleFluidUpdate(int x, int y, int z) { + BlockPos position = new BlockPos(x, y, z); + getDelegate().getLiquidTicks().scheduleTick(position, getDelegate().getFluidState(position).getType(), 0); + } + + @Override + public @NotNull World getWorld() { + // reading/writing the returned Minecraft world causes a deadlock. + // By implementing this, and covering it in warnings, we're assuming people won't be stupid, and + // if they are stupid, they'll figure it out pretty fast. + return getDelegate().getMinecraftWorld().getWorld(); + } + + @Override + public @NotNull BlockData getBlockData(int x, int y, int z) { + return CraftBlockData.fromData(getDelegate().getBlockState(new BlockPos(x, y, z))); + } + + @Override + public int getCenterChunkX() { + return getDelegate().getCenter().x; + } + + @Override + public int getCenterChunkZ() { + return getDelegate().getCenter().z; + } + + @SuppressWarnings({"unchecked", "deprecation"}) + @Override + public @NotNull T spawn(@NotNull Vector location, @NotNull Class clazz, @Nullable Consumer function, CreatureSpawnEvent.@NotNull SpawnReason reason) throws IllegalArgumentException { + net.minecraft.world.entity.Entity entity = getDelegate().getMinecraftWorld().getWorld().createEntity(location.toLocation(getWorld()), clazz); + Objects.requireNonNull(entity, "Cannot spawn null entity"); + if (entity instanceof Mob) { + ((Mob) entity).finalizeSpawn(getDelegate(), getDelegate().getCurrentDifficultyAt(entity.blockPosition()), MobSpawnType.COMMAND, (SpawnGroupData) null, null); + } + + if (function != null) { + function.accept((T) entity.getBukkitEntity()); + } + + getDelegate().addEntity(entity, reason); + return (T) entity.getBukkitEntity(); + } + + @NotNull + private WorldGenRegion getDelegate() { + return Objects.requireNonNull(region, "Cannot access ProtoWorld after generation!"); + } +} + diff --git a/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java b/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java index 46ce973ca68420825316352ad4df907edf52bfec..bd1794ac7c7d736457203b4773f89af23d21a63d 100644 --- a/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java +++ b/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java @@ -191,6 +191,12 @@ public class CustomChunkGenerator extends InternalChunkGenerator { if (this.generator.shouldGenerateDecorations()) { this.delegate.applyBiomeDecoration(region, accessor); } + + // Paper start + io.papermc.paper.world.gen.CraftProtoWorld protoWorld = new io.papermc.paper.world.gen.CraftProtoWorld(region); + generator.generateDecorations(protoWorld); + protoWorld.clearReference(); // make sure people dont try to use the ProtoWorld after we're done with it. + // Paper end } @Override