--- a/net/minecraft/world/level/levelgen/structure/StructurePiece.java
+++ b/net/minecraft/world/level/levelgen/structure/StructurePiece.java
@@ -50,7 +50,7 @@
     private EnumBlockRotation rotation;
     protected int genDepth;
     private final WorldGenFeatureStructurePieceType type;
-    private static final Set<Block> SHAPE_CHECK_BLOCKS = ImmutableSet.builder().add(Blocks.NETHER_BRICK_FENCE).add(Blocks.TORCH).add(Blocks.WALL_TORCH).add(Blocks.OAK_FENCE).add(Blocks.SPRUCE_FENCE).add(Blocks.DARK_OAK_FENCE).add(Blocks.ACACIA_FENCE).add(Blocks.BIRCH_FENCE).add(Blocks.JUNGLE_FENCE).add(Blocks.LADDER).add(Blocks.IRON_BARS).build();
+    public static final Set<Block> SHAPE_CHECK_BLOCKS = ImmutableSet.<Block>builder().add(Blocks.NETHER_BRICK_FENCE).add(Blocks.TORCH).add(Blocks.WALL_TORCH).add(Blocks.OAK_FENCE).add(Blocks.SPRUCE_FENCE).add(Blocks.DARK_OAK_FENCE).add(Blocks.ACACIA_FENCE).add(Blocks.BIRCH_FENCE).add(Blocks.JUNGLE_FENCE).add(Blocks.LADDER).add(Blocks.IRON_BARS).build();  // CraftBukkit - decompile error / PAIL private -> public
 
     protected StructurePiece(WorldGenFeatureStructurePieceType worldgenfeaturestructurepiecetype, int i, StructureBoundingBox structureboundingbox) {
         this.type = worldgenfeaturestructurepiecetype;
@@ -59,14 +59,11 @@
     }
 
     public StructurePiece(WorldGenFeatureStructurePieceType worldgenfeaturestructurepiecetype, NBTTagCompound nbttagcompound) {
-        int i = nbttagcompound.getInt("GD");
-        DataResult dataresult = StructureBoundingBox.CODEC.parse(DynamicOpsNBT.INSTANCE, nbttagcompound.get("BB"));
-        Logger logger = StructurePiece.LOGGER;
-
-        Objects.requireNonNull(logger);
-        this(worldgenfeaturestructurepiecetype, i, (StructureBoundingBox) dataresult.resultOrPartial(logger::error).orElseThrow(() -> {
+        // CraftBukkit start - decompile error
+        this(worldgenfeaturestructurepiecetype, nbttagcompound.getInt("GD"), (StructureBoundingBox) StructureBoundingBox.CODEC.parse(DynamicOpsNBT.INSTANCE, nbttagcompound.get("BB")).resultOrPartial(Objects.requireNonNull(StructurePiece.LOGGER)::error).orElseThrow(() -> {
             return new IllegalArgumentException("Invalid boundingbox");
         }));
+        // CraftBukkit end
         int j = nbttagcompound.getInt("O");
 
         this.setOrientation(j == -1 ? null : EnumDirection.from2DDataValue(j));
@@ -84,13 +81,11 @@
         NBTTagCompound nbttagcompound = new NBTTagCompound();
 
         nbttagcompound.putString("id", BuiltInRegistries.STRUCTURE_PIECE.getKey(this.getType()).toString());
-        DataResult dataresult = StructureBoundingBox.CODEC.encodeStart(DynamicOpsNBT.INSTANCE, this.boundingBox);
-        Logger logger = StructurePiece.LOGGER;
-
-        Objects.requireNonNull(logger);
-        dataresult.resultOrPartial(logger::error).ifPresent((nbtbase) -> {
-            nbttagcompound.put("BB", nbtbase);
+        // CraftBukkit start - decompile error
+        StructureBoundingBox.CODEC.encodeStart(DynamicOpsNBT.INSTANCE, this.boundingBox).resultOrPartial(Objects.requireNonNull(StructurePiece.LOGGER)::error).ifPresent((nbtbase) -> {
+             nbttagcompound.put("BB", nbtbase);
         });
+        // CraftBukkit end
         EnumDirection enumdirection = this.getOrientation();
 
         nbttagcompound.putInt("O", enumdirection == null ? -1 : enumdirection.get2DDataValue());
@@ -190,6 +185,11 @@
                 }
 
                 generatoraccessseed.setBlock(blockposition_mutableblockposition, iblockdata, 2);
+                // CraftBukkit start - fluid handling is already done if we have a transformer generator access
+                if (generatoraccessseed instanceof org.bukkit.craftbukkit.util.TransformerGeneratorAccess) {
+                    return;
+                }
+                // CraftBukkit end
                 Fluid fluid = generatoraccessseed.getFluidState(blockposition_mutableblockposition);
 
                 if (!fluid.isEmpty()) {
@@ -204,6 +204,38 @@
         }
     }
 
+    // CraftBukkit start
+    protected boolean placeCraftBlockEntity(WorldAccess worldAccess, BlockPosition position, org.bukkit.craftbukkit.block.CraftBlockEntityState<?> craftBlockEntityState, int i) {
+        if (worldAccess instanceof org.bukkit.craftbukkit.util.TransformerGeneratorAccess transformerAccess) {
+            return transformerAccess.setCraftBlock(position, craftBlockEntityState, i);
+        }
+        boolean result = worldAccess.setBlock(position, craftBlockEntityState.getHandle(), i);
+        TileEntity tileEntity = worldAccess.getBlockEntity(position);
+        if (tileEntity != null) {
+            tileEntity.load(craftBlockEntityState.getSnapshotNBT());
+        }
+        return result;
+    }
+
+    protected void placeCraftSpawner(WorldAccess worldAccess, BlockPosition position, org.bukkit.entity.EntityType entityType, int i) {
+        // This method is used in structures that are generated by code and place spawners as they set the entity after the block was placed making it impossible for plugins to access that information
+        org.bukkit.craftbukkit.block.CraftCreatureSpawner spawner = (org.bukkit.craftbukkit.block.CraftCreatureSpawner) org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(position, Blocks.SPAWNER.defaultBlockState(), null);
+        spawner.setSpawnedType(entityType);
+        placeCraftBlockEntity(worldAccess, position, spawner, i);
+    }
+
+    protected void setCraftLootTable(WorldAccess worldAccess, BlockPosition position, RandomSource randomSource, net.minecraft.resources.MinecraftKey loottableKey) {
+        // This method is used in structures that use data markers to a loot table to loot containers as otherwise plugins won't have access to that information.
+        net.minecraft.world.level.block.entity.TileEntity tileEntity = worldAccess.getBlockEntity(position);
+        if (tileEntity instanceof net.minecraft.world.level.block.entity.TileEntityLootable tileEntityLootable) {
+            tileEntityLootable.setLootTable(loottableKey, randomSource.nextLong());
+            if (worldAccess instanceof org.bukkit.craftbukkit.util.TransformerGeneratorAccess transformerAccess) {
+                transformerAccess.setCraftBlock(position, (org.bukkit.craftbukkit.block.CraftBlockState) org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(position, tileEntity.getBlockState(), tileEntityLootable.saveWithFullMetadata()), 3);
+            }
+        }
+    }
+    // CraftBukkit end
+
     protected boolean canBeReplaced(IWorldReader iworldreader, int i, int j, int k, StructureBoundingBox structureboundingbox) {
         return true;
     }
@@ -397,12 +429,20 @@
                 iblockdata = reorient(worldaccess, blockposition, Blocks.CHEST.defaultBlockState());
             }
 
+            // CraftBukkit start
+            /*
             worldaccess.setBlock(blockposition, iblockdata, 2);
             TileEntity tileentity = worldaccess.getBlockEntity(blockposition);
 
             if (tileentity instanceof TileEntityChest) {
                 ((TileEntityChest) tileentity).setLootTable(minecraftkey, randomsource.nextLong());
             }
+            */
+            org.bukkit.craftbukkit.block.CraftChest chestState = (org.bukkit.craftbukkit.block.CraftChest) org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(blockposition, iblockdata, null);
+            chestState.setLootTable(org.bukkit.Bukkit.getLootTable(org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(minecraftkey)));
+            chestState.setSeed(randomsource.nextLong());
+            placeCraftBlockEntity(worldaccess, blockposition, chestState, 2);
+            // CraftBukkit end
 
             return true;
         } else {
@@ -414,12 +454,31 @@
         BlockPosition.MutableBlockPosition blockposition_mutableblockposition = this.getWorldPos(i, j, k);
 
         if (structureboundingbox.isInside(blockposition_mutableblockposition) && !generatoraccessseed.getBlockState(blockposition_mutableblockposition).is(Blocks.DISPENSER)) {
+            // CraftBukkit start
+            /*
             this.placeBlock(generatoraccessseed, (IBlockData) Blocks.DISPENSER.defaultBlockState().setValue(BlockDispenser.FACING, enumdirection), i, j, k, structureboundingbox);
             TileEntity tileentity = generatoraccessseed.getBlockEntity(blockposition_mutableblockposition);
 
             if (tileentity instanceof TileEntityDispenser) {
                 ((TileEntityDispenser) tileentity).setLootTable(minecraftkey, randomsource.nextLong());
             }
+            */
+            if (!this.canBeReplaced(generatoraccessseed, i, j, k, structureboundingbox)) {
+                return true;
+            }
+            IBlockData iblockdata = Blocks.DISPENSER.defaultBlockState().setValue(BlockDispenser.FACING, enumdirection);
+            if (this.mirror != EnumBlockMirror.NONE) {
+                iblockdata = iblockdata.mirror(this.mirror);
+            }
+            if (this.rotation != EnumBlockRotation.NONE) {
+                iblockdata = iblockdata.rotate(this.rotation);
+            }
+
+            org.bukkit.craftbukkit.block.CraftDispenser dispenserState = (org.bukkit.craftbukkit.block.CraftDispenser) org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(blockposition_mutableblockposition, iblockdata, null);
+            dispenserState.setLootTable(org.bukkit.Bukkit.getLootTable(org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(minecraftkey)));
+            dispenserState.setSeed(randomsource.nextLong());
+            placeCraftBlockEntity(generatoraccessseed, blockposition_mutableblockposition, dispenserState, 2);
+            // CraftBukkit end
 
             return true;
         } else {
@@ -432,7 +491,7 @@
     }
 
     public static StructureBoundingBox createBoundingBox(Stream<StructurePiece> stream) {
-        Stream stream1 = stream.map(StructurePiece::getBoundingBox);
+        Stream<StructureBoundingBox> stream1 = stream.map(StructurePiece::getBoundingBox); // CraftBukkit - decompile error
 
         Objects.requireNonNull(stream1);
         return (StructureBoundingBox) StructureBoundingBox.encapsulatingBoxes(stream1::iterator).orElseThrow(() -> {
