Paper/patches/server/0712-Add-Feature-Generation-API.patch
Shane Freeder f521a18a17
Updated Upstream (Bukkit/CraftBukkit)
Upstream has released updates that appear to apply and compile correctly.
This update has not been tested by PaperMC and as with ANY update, please do your own testing

Bukkit Changes:
75a0ee4f SPIGOT-6691: Material.LAVA_CAULDRON is not Levelled

CraftBukkit Changes:
e1c96e50 SPIGOT-6682: Blocking with shield not reset after die
97f629b6 SPIGOT-6220: Structures in the world with custom generator not work
85379258 Increase outdated build delay
f7f8dce4 SPIGOT-6552: Some inventory types reset cursor on switch
2021-08-04 16:26:56 +01:00

399 lines
19 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: dfsek <dfsek@protonmail.com>
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/generation/CraftProtoWorld.java b/src/main/java/io/papermc/paper/world/generation/CraftProtoWorld.java
new file mode 100644
index 0000000000000000000000000000000000000000..69b17fe56f28f8978abc3f363a9e805d7c7b007a
--- /dev/null
+++ b/src/main/java/io/papermc/paper/world/generation/CraftProtoWorld.java
@@ -0,0 +1,115 @@
+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;
+
+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 <T extends Entity> @NotNull T spawn(@NotNull Vector location, @NotNull Class<T> clazz, @Nullable Consumer<T> 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 fc342d2f74077f8f102c731e12f27fc6f2c1bcd4..d333812188b24f228d7d3329da24cba2c9e00e6c 100644
--- a/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java
+++ b/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java
@@ -204,6 +204,12 @@ public class CustomChunkGenerator extends InternalChunkGenerator {
if (this.generator.shouldGenerateDecorations()) {
this.delegate.applyBiomeDecoration(region, accessor);
}
+
+ // 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 bfdeb4f2971e65c38334f2f90c66ef62564e83e6..5ec7a3903838ce2f60926782965107e84b44643c 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java
@@ -271,13 +271,18 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta
return this.blockEntityTag != null;
}
+ // Paper start - Delegate to utility method
@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) {
+ 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) {
case SHIELD:
- this.blockEntityTag.putString("id", "banner");
+ blockEntityTag.putString("id", "banner");
break;
case SHULKER_BOX:
case WHITE_SHULKER_BOX:
@@ -296,19 +301,19 @@ 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");
break;
case BEE_NEST:
case BEEHIVE:
- this.blockEntityTag.putString("id", "beehive");
+ blockEntityTag.putString("id", "beehive");
break;
}
}
BlockPos blockposition = BlockPos.ZERO;
net.minecraft.world.level.block.state.BlockState iblockdata = CraftMagicNumbers.getBlock(stateMaterial).defaultBlockState();
- BlockEntity te = (this.blockEntityTag == null) ? null : BlockEntity.loadStatic(blockposition, iblockdata, blockEntityTag);
+ BlockEntity te = (blockEntityTag == null) ? null : BlockEntity.loadStatic(blockposition, iblockdata, blockEntityTag);
- switch (this.material) {
+ switch (material) {
case ACACIA_SIGN:
case ACACIA_WALL_SIGN:
case BIRCH_SIGN:
@@ -328,53 +333,53 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta
if (te == null) {
te = new SignBlockEntity(blockposition, iblockdata);
}
- return new CraftSign(this.material, (SignBlockEntity) te);
+ return new CraftSign(material, (SignBlockEntity) te);
case CHEST:
case TRAPPED_CHEST:
if (te == null) {
te = new ChestBlockEntity(blockposition, iblockdata);
}
- return new CraftChest(this.material, (ChestBlockEntity) te);
+ return new CraftChest(material, (ChestBlockEntity) te);
case FURNACE:
if (te == null) {
te = new FurnaceBlockEntity(blockposition, iblockdata);
}
- return new CraftFurnaceFurnace(this.material, (FurnaceBlockEntity) te);
+ return new CraftFurnaceFurnace(material, (FurnaceBlockEntity) te);
case DISPENSER:
if (te == null) {
te = new DispenserBlockEntity(blockposition, iblockdata);
}
- return new CraftDispenser(this.material, (DispenserBlockEntity) te);
+ return new CraftDispenser(material, (DispenserBlockEntity) te);
case DROPPER:
if (te == null) {
te = new DropperBlockEntity(blockposition, iblockdata);
}
- return new CraftDropper(this.material, (DropperBlockEntity) te);
+ return new CraftDropper(material, (DropperBlockEntity) te);
case END_GATEWAY:
if (te == null) {
te = new TheEndGatewayBlockEntity(blockposition, iblockdata);
}
- return new CraftEndGateway(this.material, (TheEndGatewayBlockEntity) te);
+ return new CraftEndGateway(material, (TheEndGatewayBlockEntity) te);
case HOPPER:
if (te == null) {
te = new HopperBlockEntity(blockposition, iblockdata);
}
- return new CraftHopper(this.material, (HopperBlockEntity) te);
+ return new CraftHopper(material, (HopperBlockEntity) te);
case SPAWNER:
if (te == null) {
te = new SpawnerBlockEntity(blockposition, iblockdata);
}
- return new CraftCreatureSpawner(this.material, (SpawnerBlockEntity) te);
+ return new CraftCreatureSpawner(material, (SpawnerBlockEntity) te);
case JUKEBOX:
if (te == null) {
te = new JukeboxBlockEntity(blockposition, iblockdata);
}
- return new CraftJukebox(this.material, (JukeboxBlockEntity) te);
+ return new CraftJukebox(material, (JukeboxBlockEntity) te);
case BREWING_STAND:
if (te == null) {
te = new BrewingStandBlockEntity(blockposition, iblockdata);
}
- return new CraftBrewingStand(this.material, (BrewingStandBlockEntity) te);
+ return new CraftBrewingStand(material, (BrewingStandBlockEntity) te);
case CREEPER_HEAD:
case CREEPER_WALL_HEAD:
case DRAGON_HEAD:
@@ -390,24 +395,24 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta
if (te == null) {
te = new SkullBlockEntity(blockposition, iblockdata);
}
- return new CraftSkull(this.material, (SkullBlockEntity) te);
+ return new CraftSkull(material, (SkullBlockEntity) te);
case COMMAND_BLOCK:
case REPEATING_COMMAND_BLOCK:
case CHAIN_COMMAND_BLOCK:
if (te == null) {
te = new CommandBlockEntity(blockposition, iblockdata);
}
- return new CraftCommandBlock(this.material, (CommandBlockEntity) te);
+ return new CraftCommandBlock(material, (CommandBlockEntity) te);
case BEACON:
if (te == null) {
te = new BeaconBlockEntity(blockposition, iblockdata);
}
- return new CraftBeacon(this.material, (BeaconBlockEntity) te);
+ return new CraftBeacon(material, (BeaconBlockEntity) te);
case SHIELD:
if (te == null) {
te = new BannerBlockEntity(blockposition, iblockdata);
}
- ((BannerBlockEntity) te).baseColor = (this.blockEntityTag == null) ? DyeColor.WHITE : DyeColor.byId(this.blockEntityTag.getInt(CraftMetaBanner.BASE.NBT));
+ ((BannerBlockEntity) te).baseColor = (blockEntityTag == null) ? DyeColor.WHITE : DyeColor.byId(blockEntityTag.getInt(CraftMetaBanner.BASE.NBT));
case BLACK_BANNER:
case BLACK_WALL_BANNER:
case BLUE_BANNER:
@@ -443,12 +448,12 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta
if (te == null) {
te = new BannerBlockEntity(blockposition, iblockdata);
}
- return new CraftBanner(this.material == Material.SHIELD ? CraftMetaBlockState.shieldToBannerHack(this.blockEntityTag) : this.material, (BannerBlockEntity) te);
+ return new CraftBanner(material == Material.SHIELD ? CraftMetaBlockState.shieldToBannerHack(blockEntityTag) : material, (BannerBlockEntity) te);
case STRUCTURE_BLOCK:
if (te == null) {
te = new StructureBlockEntity(blockposition, iblockdata);
}
- return new CraftStructureBlock(this.material, (StructureBlockEntity) te);
+ return new CraftStructureBlock(material, (StructureBlockEntity) te);
case SHULKER_BOX:
case WHITE_SHULKER_BOX:
case ORANGE_SHULKER_BOX:
@@ -469,78 +474,79 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta
if (te == null) {
te = new ShulkerBoxBlockEntity(blockposition, iblockdata);
}
- return new CraftShulkerBox(this.material, (ShulkerBoxBlockEntity) te);
+ return new CraftShulkerBox(material, (ShulkerBoxBlockEntity) te);
case ENCHANTING_TABLE:
if (te == null) {
te = new EnchantmentTableBlockEntity(blockposition, iblockdata);
}
- return new CraftEnchantingTable(this.material, (EnchantmentTableBlockEntity) te);
+ return new CraftEnchantingTable(material, (EnchantmentTableBlockEntity) te);
case ENDER_CHEST:
if (te == null) {
te = new EnderChestBlockEntity(blockposition, iblockdata);
}
- return new CraftEnderChest(this.material, (EnderChestBlockEntity) te);
+ return new CraftEnderChest(material, (EnderChestBlockEntity) te);
case DAYLIGHT_DETECTOR:
if (te == null) {
te = new DaylightDetectorBlockEntity(blockposition, iblockdata);
}
- return new CraftDaylightDetector(this.material, (DaylightDetectorBlockEntity) te);
+ return new CraftDaylightDetector(material, (DaylightDetectorBlockEntity) te);
case COMPARATOR:
if (te == null) {
te = new ComparatorBlockEntity(blockposition, iblockdata);
}
- return new CraftComparator(this.material, (ComparatorBlockEntity) te);
+ return new CraftComparator(material, (ComparatorBlockEntity) te);
case BARREL:
if (te == null) {
te = new BarrelBlockEntity(blockposition, iblockdata);
}
- return new CraftBarrel(this.material, (BarrelBlockEntity) te);
+ return new CraftBarrel(material, (BarrelBlockEntity) te);
case BELL:
if (te == null) {
te = new BellBlockEntity(blockposition, iblockdata);
}
- return new CraftBell(this.material, (BellBlockEntity) te);
+ return new CraftBell(material, (BellBlockEntity) te);
case BLAST_FURNACE:
if (te == null) {
te = new BlastFurnaceBlockEntity(blockposition, iblockdata);
}
- return new CraftBlastFurnace(this.material, (BlastFurnaceBlockEntity) te);
+ return new CraftBlastFurnace(material, (BlastFurnaceBlockEntity) te);
case CAMPFIRE:
case SOUL_CAMPFIRE:
if (te == null) {
te = new CampfireBlockEntity(blockposition, iblockdata);
}
- return new CraftCampfire(this.material, (CampfireBlockEntity) te);
+ return new CraftCampfire(material, (CampfireBlockEntity) te);
case JIGSAW:
if (te == null) {
te = new JigsawBlockEntity(blockposition, iblockdata);
}
- return new CraftJigsaw(this.material, (JigsawBlockEntity) te);
+ return new CraftJigsaw(material, (JigsawBlockEntity) te);
case LECTERN:
if (te == null) {
te = new LecternBlockEntity(blockposition, iblockdata);
}
- return new CraftLectern(this.material, (LecternBlockEntity) te);
+ return new CraftLectern(material, (LecternBlockEntity) te);
case SMOKER:
if (te == null) {
te = new SmokerBlockEntity(blockposition, iblockdata);
}
- return new CraftSmoker(this.material, (SmokerBlockEntity) te);
+ return new CraftSmoker(material, (SmokerBlockEntity) te);
case BEE_NEST:
case BEEHIVE:
if (te == null) {
te = new BeehiveBlockEntity(blockposition, iblockdata);
}
- return new CraftBeehive(this.material, (BeehiveBlockEntity) te);
+ return new CraftBeehive(material, (BeehiveBlockEntity) te);
case SCULK_SENSOR:
if (te == null) {
te = new SculkSensorBlockEntity(blockposition, iblockdata);
}
- return new CraftSculkSensor(this.material, (SculkSensorBlockEntity) te);
+ return new CraftSculkSensor(material, (SculkSensorBlockEntity) te);
default:
- throw new IllegalStateException("Missing blockState for " + this.material);
+ throw new IllegalStateException("Missing blockState for " + material);
}
}
+ // Paper end
@Override
public void setBlockState(BlockState blockState) {