--- a/net/minecraft/world/level/levelgen/structure/StructureStart.java
+++ b/net/minecraft/world/level/levelgen/structure/StructureStart.java
@@ -30,6 +_,12 @@
     @Nullable
     private volatile BoundingBox cachedBoundingBox;
 
+    // CraftBukkit start
+    private static final org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry();
+    public org.bukkit.craftbukkit.persistence.DirtyCraftPersistentDataContainer persistentDataContainer = new org.bukkit.craftbukkit.persistence.DirtyCraftPersistentDataContainer(StructureStart.DATA_TYPE_REGISTRY);
+    public org.bukkit.event.world.AsyncStructureGenerateEvent.Cause generationEventCause = org.bukkit.event.world.AsyncStructureGenerateEvent.Cause.WORLD_GENERATION;
+    // CraftBukkit end
+
     public StructureStart(Structure structure, ChunkPos chunkPos, int references, PiecesContainer pieceContainer) {
         this.structure = structure;
         this.chunkPos = chunkPos;
@@ -87,11 +_,23 @@
             BlockPos center = boundingBox.getCenter();
             BlockPos blockPos = new BlockPos(center.getX(), boundingBox.minY(), center.getZ());
 
-            for (StructurePiece structurePiece : list) {
-                if (structurePiece.getBoundingBox().intersects(box)) {
-                    structurePiece.postProcess(level, structureManager, generator, random, box, chunkPos, blockPos);
+            // CraftBukkit start
+            // for (StructurePiece structurePiece : list) {
+            //     if (structurePiece.getBoundingBox().intersects(box)) {
+            //         structurePiece.postProcess(level, structureManager, generator, random, box, chunkPos, blockPos);
+            //     }
+            // }
+            List<StructurePiece> pieces = list.stream().filter(piece -> piece.getBoundingBox().intersects(box)).toList();
+            if (!pieces.isEmpty()) {
+                org.bukkit.craftbukkit.util.TransformerGeneratorAccess transformerAccess = new org.bukkit.craftbukkit.util.TransformerGeneratorAccess();
+                transformerAccess.setDelegate(level);
+                transformerAccess.setStructureTransformer(new org.bukkit.craftbukkit.util.CraftStructureTransformer(this.generationEventCause, level, structureManager, this.structure, box, chunkPos));
+                for (StructurePiece piece : pieces) {
+                    piece.postProcess(transformerAccess, structureManager, generator, random, box, chunkPos, blockPos);
                 }
+                transformerAccess.getStructureTransformer().discard();
             }
+            // CraftBukkit end
 
             this.structure.afterPlace(level, structureManager, generator, random, box, chunkPos, this.pieceContainer);
         }
@@ -99,6 +_,11 @@
 
     public CompoundTag createTag(StructurePieceSerializationContext context, ChunkPos chunkPos) {
         CompoundTag compoundTag = new CompoundTag();
+        // CraftBukkit start - store persistent data in nbt
+        if (!this.persistentDataContainer.isEmpty()) {
+            compoundTag.put("StructureBukkitValues", this.persistentDataContainer.toTagCompound());
+        }
+        // CraftBukkit end
         if (this.isValid()) {
             compoundTag.putString("id", context.registryAccess().lookupOrThrow(Registries.STRUCTURE).getKey(this.structure).toString());
             compoundTag.putInt("ChunkX", chunkPos.x);
