--- a/net/minecraft/world/level/levelgen/structure/templatesystem/DefinedStructure.java
+++ b/net/minecraft/world/level/levelgen/structure/templatesystem/DefinedStructure.java
@@ -56,6 +56,12 @@
 import net.minecraft.world.phys.shapes.VoxelShapeBitSet;
 import net.minecraft.world.phys.shapes.VoxelShapeDiscrete;
 
+// CraftBukkit start
+import net.minecraft.nbt.NBTBase;
+import org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer;
+import org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry;
+// CraftBukkit end
+
 public class DefinedStructure {
 
     public static final String PALETTE_TAG = "palette";
@@ -74,6 +80,11 @@
     private BaseBlockPosition size;
     private String author;
 
+    // CraftBukkit start - data containers
+    private static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry();
+    public CraftPersistentDataContainer persistentDataContainer = new CraftPersistentDataContainer(DATA_TYPE_REGISTRY);
+    // CraftBukkit end
+
     public DefinedStructure() {
         this.size = BaseBlockPosition.ZERO;
         this.author = "?";
@@ -147,7 +158,7 @@
     }
 
     private static List<DefinedStructure.BlockInfo> buildInfoList(List<DefinedStructure.BlockInfo> list, List<DefinedStructure.BlockInfo> list1, List<DefinedStructure.BlockInfo> list2) {
-        Comparator<DefinedStructure.BlockInfo> comparator = Comparator.comparingInt((definedstructure_blockinfo) -> {
+        Comparator<DefinedStructure.BlockInfo> comparator = Comparator.<DefinedStructure.BlockInfo>comparingInt((definedstructure_blockinfo) -> { // CraftBukkit - decompile error
             return definedstructure_blockinfo.pos.getY();
         }).thenComparingInt((definedstructure_blockinfo) -> {
             return definedstructure_blockinfo.pos.getX();
@@ -253,6 +264,19 @@
         if (this.palettes.isEmpty()) {
             return false;
         } else {
+            // CraftBukkit start
+            // We only want the TransformerGeneratorAccess at certain locations because in here are many "block update" calls that shouldn't be transformed
+            WorldAccess wrappedAccess = worldaccess;
+            org.bukkit.craftbukkit.util.CraftStructureTransformer structureTransformer = null;
+            if (wrappedAccess instanceof org.bukkit.craftbukkit.util.TransformerGeneratorAccess transformerAccess) {
+                worldaccess = transformerAccess.getHandle();
+                structureTransformer = transformerAccess.getStructureTransformer();
+                // The structureTransformer is not needed if we can not transform blocks therefore we can save a little bit of performance doing this
+                if (structureTransformer != null && !structureTransformer.canTransformBlocks()) {
+                    structureTransformer = null;
+                }
+            }
+            // CraftBukkit end
             List<DefinedStructure.BlockInfo> list = definedstructureinfo.getRandomPalette(this.palettes, blockposition).blocks();
 
             if ((!list.isEmpty() || !definedstructureinfo.isIgnoreEntities() && !this.entityInfoList.isEmpty()) && this.size.getX() >= 1 && this.size.getY() >= 1 && this.size.getZ() >= 1) {
@@ -284,6 +308,20 @@
                             Clearable.tryClear(tileentity);
                             worldaccess.setBlock(blockposition2, Blocks.BARRIER.defaultBlockState(), 20);
                         }
+                        // CraftBukkit start
+                        if (structureTransformer != null) {
+                            org.bukkit.craftbukkit.block.CraftBlockState craftBlockState = (org.bukkit.craftbukkit.block.CraftBlockState) org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(worldaccess, blockposition2, iblockdata, null);
+                            if (definedstructure_blockinfo.nbt != null && craftBlockState instanceof org.bukkit.craftbukkit.block.CraftBlockEntityState<?> entityState) {
+                                entityState.loadData(definedstructure_blockinfo.nbt);
+                                if (craftBlockState instanceof org.bukkit.craftbukkit.block.CraftLootable<?> craftLootable) {
+                                    craftLootable.setSeed(randomsource.nextLong());
+                                }
+                            }
+                            craftBlockState = structureTransformer.transformCraftState(craftBlockState);
+                            iblockdata = craftBlockState.getHandle();
+                            definedstructure_blockinfo = new DefinedStructure.BlockInfo(blockposition2, iblockdata, (craftBlockState instanceof org.bukkit.craftbukkit.block.CraftBlockEntityState<?> craftBlockEntityState ? craftBlockEntityState.getSnapshotNBT() : null));
+                        }
+                        // CraftBukkit end
 
                         if (worldaccess.setBlock(blockposition2, iblockdata, i)) {
                             j = Math.min(j, blockposition2.getX());
@@ -296,7 +334,7 @@
                             if (definedstructure_blockinfo.nbt != null) {
                                 tileentity = worldaccess.getBlockEntity(blockposition2);
                                 if (tileentity != null) {
-                                    if (tileentity instanceof RandomizableContainer) {
+                                    if (structureTransformer == null && tileentity instanceof RandomizableContainer) { // CraftBukkit - only process if don't have a transformer access (Was already set above) - SPIGOT-7520: Use structureTransformer as check, so that it is the same as above
                                         definedstructure_blockinfo.nbt.putLong("LootTableSeed", randomsource.nextLong());
                                     }
 
@@ -401,7 +439,7 @@
                 }
 
                 if (!definedstructureinfo.isIgnoreEntities()) {
-                    this.placeEntities(worldaccess, blockposition, definedstructureinfo.getMirror(), definedstructureinfo.getRotation(), definedstructureinfo.getRotationPivot(), structureboundingbox, definedstructureinfo.shouldFinalizeEntities());
+                    this.placeEntities(wrappedAccess, blockposition, definedstructureinfo.getMirror(), definedstructureinfo.getRotation(), definedstructureinfo.getRotationPivot(), structureboundingbox, definedstructureinfo.shouldFinalizeEntities()); // CraftBukkit
                 }
 
                 return true;
@@ -503,11 +541,13 @@
     }
 
     private static Optional<Entity> createEntityIgnoreException(WorldAccess worldaccess, NBTTagCompound nbttagcompound) {
-        try {
+        // CraftBukkit start
+        // try {
             return EntityTypes.create(nbttagcompound, worldaccess.getLevel(), EntitySpawnReason.STRUCTURE);
-        } catch (Exception exception) {
-            return Optional.empty();
-        }
+        // } catch (Exception exception) {
+            // return Optional.empty();
+        // }
+        // CraftBukkit end
     }
 
     public BaseBlockPosition getSize(EnumBlockRotation enumblockrotation) {
@@ -721,6 +761,11 @@
 
         nbttagcompound.put("entities", nbttaglist3);
         nbttagcompound.put("size", this.newIntegerList(this.size.getX(), this.size.getY(), this.size.getZ()));
+        // CraftBukkit start - PDC
+        if (!this.persistentDataContainer.isEmpty()) {
+            nbttagcompound.put("BukkitValues", this.persistentDataContainer.toTagCompound());
+        }
+        // CraftBukkit end
         return GameProfileSerializer.addCurrentDataVersion(nbttagcompound);
     }
 
@@ -760,6 +805,12 @@
             }
         }
 
+        // CraftBukkit start - PDC
+        NBTBase base = nbttagcompound.get("BukkitValues");
+        if (base instanceof NBTTagCompound) {
+            this.persistentDataContainer.putAll((NBTTagCompound) base);
+        }
+        // CraftBukkit end
     }
 
     private void loadPalette(HolderGetter<Block> holdergetter, NBTTagList nbttaglist, NBTTagList nbttaglist1) {
@@ -924,7 +975,7 @@
         public IBlockData stateFor(int i) {
             IBlockData iblockdata = (IBlockData) this.ids.byId(i);
 
-            return iblockdata == null ? DefinedStructure.c.DEFAULT_BLOCK_STATE : iblockdata;
+            return iblockdata == null ? DEFAULT_BLOCK_STATE : iblockdata; // CraftBukkit - decompile error
         }
 
         public Iterator<IBlockData> iterator() {
