From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: dfsek Date: Sat, 19 Jun 2021 20:15:59 -0700 Subject: [PATCH] Add more LimitedRegion API diff --git a/src/main/java/io/papermc/paper/world/generation/CraftProtoWorld.java b/src/main/java/io/papermc/paper/world/generation/CraftProtoWorld.java new file mode 100644 index 0000000000000000000000000000000000000000..1c6668c2b5e1816db7e0ebabc99af3586849e606 --- /dev/null +++ b/src/main/java/io/papermc/paper/world/generation/CraftProtoWorld.java @@ -0,0 +1,116 @@ +package io.papermc.paper.world.generation; + +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +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 net.minecraft.world.level.block.entity.BlockEntity; +import org.bukkit.World; +import org.bukkit.block.BlockState; +import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.block.CraftBlockEntityState; +import org.bukkit.craftbukkit.block.CraftBlockState; +import org.bukkit.craftbukkit.block.data.CraftBlockData; +import org.bukkit.craftbukkit.inventory.CraftMetaBlockState; +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; + +@Deprecated +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 setBlockState(int x, int y, int z, @NotNull BlockState state) { + BlockPos pos = new BlockPos(x, y, z); + if(!state.getBlockData().matches(getDelegate().getBlockState(pos).createCraftBlockData())) { + throw new IllegalArgumentException("BlockData does not match! Expected " + state.getBlockData().getAsString(false) + ", got " + getDelegate().getBlockState(pos).createCraftBlockData().getAsString(false)); + } + getDelegate().getBlockEntity(pos).load(((CraftBlockEntityState) state).getSnapshotNBT()); + } + + @Override + public @NotNull BlockState getBlockState(int x, int y, int z) { + BlockEntity entity = getDelegate().getBlockEntity(new BlockPos(x, y, z)); + return CraftMetaBlockState.createBlockState(entity.getBlockState().getBukkitMaterial(), entity.save(new CompoundTag())); + } + + @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) { + mob.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/CraftLimitedRegion.java b/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java index d91c88d7bdfd954fa81fbf1c9ad92161d70993a6..f5ef7e026061351590f1ce77694e2d8fb8521048 100644 --- a/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java +++ b/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java @@ -151,7 +151,10 @@ public class CraftLimitedRegion extends CraftRegionAccessor implements LimitedRe @Override public BlockState getBlockState(int x, int y, int z) { Preconditions.checkArgument(this.isInRegion(x, y, z), "Coordinates %s, %s, %s are not in the region", x, y, z); - return super.getBlockState(x, y, z); + // Paper start + net.minecraft.world.level.block.entity.BlockEntity entity = getHandle().getBlockEntity(new BlockPos(x, y, z)); + return org.bukkit.craftbukkit.inventory.CraftMetaBlockState.createBlockState(entity.getBlockState().getBukkitMaterial(), entity.save(new CompoundTag())); + // Paper end } @Override @@ -169,7 +172,7 @@ public class CraftLimitedRegion extends CraftRegionAccessor implements LimitedRe @Override public void setBlockData(int x, int y, int z, BlockData blockData) { Preconditions.checkArgument(this.isInRegion(x, y, z), "Coordinates %s, %s, %s are not in the region", x, y, z); - super.setBlockData(x, y, z, blockData); + getHandle().setBlock(new BlockPos(x, y, z), ((org.bukkit.craftbukkit.block.data.CraftBlockData) blockData).getState(), 3); // Paper } @Override @@ -199,4 +202,45 @@ public class CraftLimitedRegion extends CraftRegionAccessor implements LimitedRe public void addEntityToWorld(net.minecraft.world.entity.Entity entity, CreatureSpawnEvent.SpawnReason reason) { this.entities.add(entity); } + + // Paper start + @Override + public void setBlockState(int x, int y, int z, BlockState state) { + BlockPos pos = new BlockPos(x, y, z); + if (!state.getBlockData().matches(getHandle().getBlockState(pos).createCraftBlockData())) { + throw new IllegalArgumentException("BlockData does not match! Expected " + state.getBlockData().getAsString(false) + ", got " + getHandle().getBlockState(pos).createCraftBlockData().getAsString(false)); + } + getHandle().getBlockEntity(pos).load(((org.bukkit.craftbukkit.block.CraftBlockEntityState) state).getSnapshotNBT()); + } + + @Override + public void scheduleBlockUpdate(int x, int y, int z) { + BlockPos position = new BlockPos(x, y, z); + getHandle().getBlockTicks().scheduleTick(position, getHandle().getBlockIfLoaded(position), 0); + } + + @Override + public void scheduleFluidUpdate(int x, int y, int z) { + BlockPos position = new BlockPos(x, y, z); + getHandle().getLiquidTicks().scheduleTick(position, getHandle().getFluidState(position).getType(), 0); + } + + @Override + public 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 getHandle().getMinecraftWorld().getWorld(); + } + + @Override + public int getCenterChunkX() { + return centerChunkX; + } + + @Override + public int getCenterChunkZ() { + return centerChunkZ; + } + // Paper end } diff --git a/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java b/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java index eb82aaf9dcbc912d780a90842601da85497fa443..1b05bb78eaee548806df8ebfff1a1401e30d52e0 100644 --- a/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java +++ b/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java @@ -196,6 +196,12 @@ public class CustomChunkGenerator extends InternalChunkGenerator { for (BlockPos lightPosition : craftData.getLights()) { ((ProtoChunk) chunk).addLight(new BlockPos((x << 4) + lightPosition.getX(), lightPosition.getY(), (z << 4) + lightPosition.getZ())); // PAIL rename addLightBlock } + + // Paper start + io.papermc.paper.world.generation.CraftProtoWorld protoWorld = new io.papermc.paper.world.generation.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 diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java index 55dd618d8421271063843c6e65dbcaceba9a33de..56f65b49e0ce55ee5aa9d929a98ea055ce27a8a1 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java @@ -214,11 +214,16 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta @Override public BlockState getBlockState() { - Material stateMaterial = (this.material != Material.SHIELD) ? this.material : CraftMetaBlockState.shieldToBannerHack(this.blockEntityTag); // Only actually used for jigsaws - if (this.blockEntityTag != null) { - switch (this.material) { + // Paper start + return createBlockState(this.material, this.blockEntityTag); + } + public static BlockState createBlockState(Material material, CompoundTag blockEntityTag) { + Material stateMaterial = (material != Material.SHIELD) ? material : CraftMetaBlockState.shieldToBannerHack(blockEntityTag); // Only actually used for jigsaws + if (blockEntityTag != null) { + switch (material) { + // Paper end case SHIELD: - this.blockEntityTag.putString("id", "banner"); + blockEntityTag.putString("id", "banner"); // Paper break; case SHULKER_BOX: case WHITE_SHULKER_BOX: @@ -237,11 +242,11 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta case GREEN_SHULKER_BOX: case RED_SHULKER_BOX: case BLACK_SHULKER_BOX: - this.blockEntityTag.putString("id", "shulker_box"); + blockEntityTag.putString("id", "shulker_box"); // Paper break; case BEE_NEST: case BEEHIVE: - this.blockEntityTag.putString("id", "beehive"); + blockEntityTag.putString("id", "beehive"); // Paper break; } }