diff --git a/patches/api/Adventure.patch b/patches/api/Adventure.patch
index a40462a961..5cd70049f5 100644
--- a/patches/api/Adventure.patch
+++ b/patches/api/Adventure.patch
@@ -1140,8 +1140,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
  /**
   * Represents a world, which may contain entities, chunks and blocks
   */
--public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient, Metadatable {
-+public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient, Metadatable, net.kyori.adventure.audience.ForwardingAudience { // Paper
+-public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient, Metadatable, PersistentDataHolder {
++public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient, Metadatable, PersistentDataHolder, net.kyori.adventure.audience.ForwardingAudience { // Paper
  
      /**
       * Gets the {@link Block} at the given coordinates
diff --git a/patches/api/Implement-Keyed-on-World.patch b/patches/api/Implement-Keyed-on-World.patch
index a97caf34d9..ff132eb26a 100644
--- a/patches/api/Implement-Keyed-on-World.patch
+++ b/patches/api/Implement-Keyed-on-World.patch
@@ -57,8 +57,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
  /**
   * Represents a world, which may contain entities, chunks and blocks
   */
--public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient, Metadatable, net.kyori.adventure.audience.ForwardingAudience { // Paper
-+public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient, Metadatable, net.kyori.adventure.audience.ForwardingAudience, Keyed { // Paper
+-public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient, Metadatable, PersistentDataHolder, net.kyori.adventure.audience.ForwardingAudience { // Paper
++public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient, Metadatable, PersistentDataHolder, net.kyori.adventure.audience.ForwardingAudience, Keyed { // Paper
  
      // Paper start
      /**
diff --git a/patches/api/Implement-furnace-cook-speed-multiplier-API.patch b/patches/api/Implement-furnace-cook-speed-multiplier-API.patch
index b790dfe123..7504ded4b0 100644
--- a/patches/api/Implement-furnace-cook-speed-multiplier-API.patch
+++ b/patches/api/Implement-furnace-cook-speed-multiplier-API.patch
@@ -10,8 +10,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 --- a/src/main/java/org/bukkit/block/Furnace.java
 +++ b/src/main/java/org/bukkit/block/Furnace.java
 @@ -0,0 +0,0 @@ public interface Furnace extends Container {
-      */
-     public void setCookTimeTotal(int cookTimeTotal);
+     @NotNull
+     public Map<CookingRecipe<?>, Integer> getRecipesUsed();
  
 +    // Paper start
 +    /**
diff --git a/patches/api/Provide-E-TE-Chunk-count-stat-methods.patch b/patches/api/Provide-E-TE-Chunk-count-stat-methods.patch
index 011613dd1b..f76242a590 100644
--- a/patches/api/Provide-E-TE-Chunk-count-stat-methods.patch
+++ b/patches/api/Provide-E-TE-Chunk-count-stat-methods.patch
@@ -12,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +++ b/src/main/java/org/bukkit/World.java
 @@ -0,0 +0,0 @@ import org.jetbrains.annotations.Nullable;
   */
- public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient, Metadatable, net.kyori.adventure.audience.ForwardingAudience { // Paper
+ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient, Metadatable, PersistentDataHolder, net.kyori.adventure.audience.ForwardingAudience { // Paper
  
 +    // Paper start
 +    /**
diff --git a/patches/server/Add-setPlayerProfile-API-for-Skulls.patch b/patches/server/Add-setPlayerProfile-API-for-Skulls.patch
index 194c91b198..99ea9f931e 100644
--- a/patches/server/Add-setPlayerProfile-API-for-Skulls.patch
+++ b/patches/server/Add-setPlayerProfile-API-for-Skulls.patch
@@ -51,40 +51,17 @@ diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java
 +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java
-@@ -0,0 +0,0 @@ import com.google.common.collect.ImmutableMap.Builder;
- import com.mojang.authlib.GameProfile;
- import java.util.Map;
- import java.util.UUID;
--import net.minecraft.nbt.CompoundTag;
--import net.minecraft.nbt.NbtUtils;
--import net.minecraft.nbt.Tag;
--import net.minecraft.world.level.block.entity.SkullBlockEntity;
- import org.bukkit.Bukkit;
- import org.bukkit.Material;
- import org.bukkit.OfflinePlayer;
-@@ -0,0 +0,0 @@ import org.bukkit.craftbukkit.util.CraftMagicNumbers;
- import org.bukkit.inventory.meta.SkullMeta;
- import org.bukkit.profile.PlayerProfile;
- 
-+import javax.annotation.Nullable;
-+import net.minecraft.nbt.CompoundTag;
-+import net.minecraft.nbt.NbtUtils;
-+import net.minecraft.nbt.Tag;
-+import net.minecraft.world.level.block.entity.SkullBlockEntity;
- @DelegateDeserialization(SerializableMeta.class)
- class CraftMetaSkull extends CraftMetaItem implements SkullMeta {
- 
 @@ -0,0 +0,0 @@ class CraftMetaSkull extends CraftMetaItem implements SkullMeta {
          return this.hasOwner() ? this.profile.getName() : null;
      }
  
 +    // Paper start
 +    @Override
-+    public void setPlayerProfile(@Nullable com.destroystokyo.paper.profile.PlayerProfile profile) {
++    public void setPlayerProfile(@org.jetbrains.annotations.Nullable com.destroystokyo.paper.profile.PlayerProfile profile) {
 +        setProfile((profile == null) ? null : com.destroystokyo.paper.profile.CraftPlayerProfile.asAuthlibCopy(profile));
 +    }
 +
-+    @Nullable
++    @org.jetbrains.annotations.Nullable
 +    @Override
 +    public com.destroystokyo.paper.profile.PlayerProfile getPlayerProfile() {
 +        return profile != null ? com.destroystokyo.paper.profile.CraftPlayerProfile.asBukkitCopy(profile) : null;
@@ -119,7 +96,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 @@ -0,0 +0,0 @@ class CraftMetaSkull extends CraftMetaItem implements SkullMeta {
      Builder<String, Object> serialize(Builder<String, Object> builder) {
          super.serialize(builder);
-         if (this.hasOwner()) {
+         if (this.profile != null) {
 -            return builder.put(SKULL_OWNER.BUKKIT, new CraftPlayerProfile(this.profile));
 +            return builder.put(SKULL_OWNER.BUKKIT, new com.destroystokyo.paper.profile.CraftPlayerProfile(this.profile)); // Paper
          }
diff --git a/patches/server/Adventure.patch b/patches/server/Adventure.patch
index 1b518310a7..705ec69115 100644
--- a/patches/server/Adventure.patch
+++ b/patches/server/Adventure.patch
@@ -1844,9 +1844,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
 +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
 @@ -0,0 +0,0 @@ public class CraftWorld extends CraftRegionAccessor implements World {
-     private final List<BlockPopulator> populators = new ArrayList<BlockPopulator>();
      private final BlockMetadataStore blockMetadata = new BlockMetadataStore(this);
      private final Object2IntOpenHashMap<SpawnCategory> spawnCategoryLimit = new Object2IntOpenHashMap<>();
+     private final CraftPersistentDataContainer persistentDataContainer = new CraftPersistentDataContainer(CraftWorld.DATA_TYPE_REGISTRY);
 +    private net.kyori.adventure.pointer.Pointers adventure$pointers; // Paper - implement pointers
  
      private static final Random rand = new Random();
diff --git a/patches/server/Asynchronous-chunk-IO-and-loading.patch b/patches/server/Asynchronous-chunk-IO-and-loading.patch
index 10bcf4e2a8..010481d4b2 100644
--- a/patches/server/Asynchronous-chunk-IO-and-loading.patch
+++ b/patches/server/Asynchronous-chunk-IO-and-loading.patch
@@ -3607,8 +3607,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    }
 +    // Paper end
  
-     // Spigot start
      @Override
+     public PersistentDataContainer getPersistentDataContainer() {
 diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
diff --git a/patches/server/Implement-Keyed-on-World.patch b/patches/server/Implement-Keyed-on-World.patch
index aa530bacc5..19fe1cf191 100644
--- a/patches/server/Implement-Keyed-on-World.patch
+++ b/patches/server/Implement-Keyed-on-World.patch
@@ -48,4 +48,4 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    }
      // Paper end
  
-     // Spigot start
+     @Override
diff --git a/patches/server/Implement-furnace-cook-speed-multiplier-API.patch b/patches/server/Implement-furnace-cook-speed-multiplier-API.patch
index 6aba9ebd1b..151542217c 100644
--- a/patches/server/Implement-furnace-cook-speed-multiplier-API.patch
+++ b/patches/server/Implement-furnace-cook-speed-multiplier-API.patch
@@ -93,8 +93,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 --- a/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java
 +++ b/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java
 @@ -0,0 +0,0 @@ public abstract class CraftFurnace<T extends AbstractFurnaceBlockEntity> extends
-     public void setCookTimeTotal(int cookTimeTotal) {
-         this.getSnapshot().cookingTotalTime = cookTimeTotal;
+ 
+         return recipesUsed.build();
      }
 +
 +    // Paper start - cook speed multiplier API
diff --git a/patches/server/Implement-regenerateChunk.patch b/patches/server/Implement-regenerateChunk.patch
index 0706ea5033..dafd833637 100644
--- a/patches/server/Implement-regenerateChunk.patch
+++ b/patches/server/Implement-regenerateChunk.patch
@@ -10,9 +10,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
 +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
 @@ -0,0 +0,0 @@ import org.bukkit.util.Vector;
- 
  public class CraftWorld extends CraftRegionAccessor implements World {
      public static final int CUSTOM_DIMENSION_OFFSET = 10;
+     private static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry();
 +    private static final ChunkStatus[] REGEN_CHUNK_STATUSES = {ChunkStatus.BIOMES, ChunkStatus.NOISE, ChunkStatus.SURFACE, ChunkStatus.CARVERS, ChunkStatus.LIQUID_CARVERS, ChunkStatus.FEATURES}; // Paper - implement regenerate chunk method
  
      private final ServerLevel world;
@@ -25,6 +25,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 -        /*
 -        if (!unloadChunk0(x, z, false)) {
 -            return false;
+-        }
+-
+-        final long chunkKey = ChunkCoordIntPair.pair(x, z);
+-        world.getChunkProvider().unloadQueue.remove(chunkKey);
 +        // Paper start - implement regenerateChunk method
 +        final ServerLevel serverLevel = this.world;
 +        final net.minecraft.server.level.ServerChunkCache serverChunkCache = serverLevel.getChunkSource();
@@ -33,10 +37,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        for (final BlockPos blockPos : BlockPos.betweenClosed(chunkPos.getMinBlockX(), serverLevel.getMinBuildHeight(), chunkPos.getMinBlockZ(), chunkPos.getMaxBlockX(), serverLevel.getMaxBuildHeight() - 1, chunkPos.getMaxBlockZ())) {
 +            levelChunk.removeBlockEntity(blockPos);
 +            serverLevel.setBlock(blockPos, net.minecraft.world.level.block.Blocks.AIR.defaultBlockState(), 16);
-         }
- 
--        final long chunkKey = ChunkCoordIntPair.pair(x, z);
--        world.getChunkProvider().unloadQueue.remove(chunkKey);
++        }
++
 +        for (final ChunkStatus chunkStatus : REGEN_CHUNK_STATUSES) {
 +            final List<ChunkAccess> list = new ArrayList<>();
 +            final int range = Math.max(1, chunkStatus.getRange());
diff --git a/patches/server/Provide-E-TE-Chunk-count-stat-methods.patch b/patches/server/Provide-E-TE-Chunk-count-stat-methods.patch
index 4e1181e35f..69c0c595a8 100644
--- a/patches/server/Provide-E-TE-Chunk-count-stat-methods.patch
+++ b/patches/server/Provide-E-TE-Chunk-count-stat-methods.patch
@@ -24,7 +24,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
 +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
 @@ -0,0 +0,0 @@ public class CraftWorld extends CraftRegionAccessor implements World {
-     private final Object2IntOpenHashMap<SpawnCategory> spawnCategoryLimit = new Object2IntOpenHashMap<>();
+     private final CraftPersistentDataContainer persistentDataContainer = new CraftPersistentDataContainer(CraftWorld.DATA_TYPE_REGISTRY);
      private net.kyori.adventure.pointer.Pointers adventure$pointers; // Paper - implement pointers
  
 +    // Paper start - Provide fast information methods
diff --git a/work/Bukkit b/work/Bukkit
index 8085edde6d..8d8180320a 160000
--- a/work/Bukkit
+++ b/work/Bukkit
@@ -1 +1 @@
-Subproject commit 8085edde6dfb5c9a95741c0c499ac9317e406ea1
+Subproject commit 8d8180320a17a60f563127fea77549ba420462c2
diff --git a/work/CraftBukkit b/work/CraftBukkit
index de95135562..c0326c2840 160000
--- a/work/CraftBukkit
+++ b/work/CraftBukkit
@@ -1 +1 @@
-Subproject commit de9513556263817fab3394a69f580b8564932083
+Subproject commit c0326c2840e9f91d6109c1f364c69b4053a787dc
diff --git a/work/Spigot b/work/Spigot
index 6edb62f30a..699290cdcc 160000
--- a/work/Spigot
+++ b/work/Spigot
@@ -1 +1 @@
-Subproject commit 6edb62f30a5d2783a1b7087322029a92b02f17b5
+Subproject commit 699290cdcc3d7721a3031b395d8693a9a11d8f6d