diff --git a/build-data/paper.at b/build-data/paper.at
index 2790d40943..777d1ed2a2 100644
--- a/build-data/paper.at
+++ b/build-data/paper.at
@@ -50,7 +50,7 @@ public net.minecraft.world.entity.player.Player removeEntitiesOnShoulder()V
 # LivingEntity setkiller
 public net.minecraft.world.entity.LivingEntity lastHurtByPlayerTime
 
-# SkeletonHorse Addittions
+# SkeletonHorse Additions
 public net.minecraft.world.entity.animal.horse.SkeletonHorse trapTime
 
 # Fix client rendering skulls
@@ -66,6 +66,7 @@ public-f net.minecraft.world.level.chunk.storage.RegionFileStorage
 public net.minecraft.world.level.chunk.storage.RegionFileStorage getFile(Lnet/minecraft/world/level/ChunkPos;Z)Lnet/minecraft/world/level/chunk/storage/RegionFile;
 public net.minecraft.world.level.chunk.storage.SectionStorage dirty
 public net.minecraft.util.thread.BlockableEventLoop runAllTasks()V
+public net.minecraft.server.level.ChunkMap getPoiManager()Lnet/minecraft/world/entity/ai/village/poi/PoiManager;
 
 # Improve death events
 public net.minecraft.world.entity.LivingEntity getDeathSound()Lnet/minecraft/sounds/SoundEvent;
diff --git a/patches/unapplied/api/Add-source-block-constructor-and-getChangedBlockData.patch b/patches/api/Add-source-block-constructor-and-getChangedBlockData.patch
similarity index 100%
rename from patches/unapplied/api/Add-source-block-constructor-and-getChangedBlockData.patch
rename to patches/api/Add-source-block-constructor-and-getChangedBlockData.patch
diff --git a/patches/unapplied/api/Async-Chunks-API.patch b/patches/api/Async-Chunks-API.patch
similarity index 100%
rename from patches/unapplied/api/Async-Chunks-API.patch
rename to patches/api/Async-Chunks-API.patch
diff --git a/patches/unapplied/api/isChunkGenerated-API.patch b/patches/api/isChunkGenerated-API.patch
similarity index 100%
rename from patches/unapplied/api/isChunkGenerated-API.patch
rename to patches/api/isChunkGenerated-API.patch
diff --git a/patches/server/Asynchronous-chunk-IO-and-loading.patch b/patches/server/Asynchronous-chunk-IO-and-loading.patch
index f2e23de52b..cd34d35ab9 100644
--- a/patches/server/Asynchronous-chunk-IO-and-loading.patch
+++ b/patches/server/Asynchronous-chunk-IO-and-loading.patch
@@ -3,8 +3,7 @@ From: Spottedleaf <Spottedleaf@users.noreply.github.com>
 Date: Sat, 13 Jul 2019 09:23:10 -0700
 Subject: [PATCH] Asynchronous chunk IO and loading
 
-# UPDATE NOTES: RegionFileStorage and SectionStorage need resolving (will conflict on apply)
-# ChunkSerializer needs the new tick lists to be saved (see added todos)
+ChunkSerializer needs the new tick lists to be saved (see added todos)
 
 This patch re-adds a file IO thread as well as shoving de-serializing
 chunk NBT data onto worker threads. This patch also will shove
@@ -1540,8 +1539,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +            // apply fixes
 +
 +            try {
-+                chunkData.chunkData = chunkManager.getChunkData(this.world.getTypeKey(),
-+                    chunkManager.overworldDataStorage, chunkData.chunkData, chunkPos, this.world); // clone data for safety, file IO thread does not clone
++                chunkData.chunkData = chunkManager.upgradeChunkTag(this.world.getTypeKey(),
++                    chunkManager.overworldDataStorage, chunkData.chunkData, chunkManager.generator.getTypeNameForDataFixer(), chunkPos, this.world); // clone data for safety, file IO thread does not clone
 +            } catch (final Throwable ex) {
 +                PaperFileIOThread.LOGGER.error("Could not apply datafixers for chunk task: " + this.toString(), ex);
 +                this.complete(ChunkLoadTask.createEmptyHolder());
@@ -1552,8 +1551,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +            }
 +
 +            try {
-+                chunkHolder = ChunkSerializer.loadChunk(this.world,
-+                    chunkManager.structureManager, chunkManager.getVillagePlace(), chunkPos,
++                chunkHolder = ChunkSerializer.loadChunk(this.world, chunkManager.getPoiManager(), chunkPos,
 +                    chunkData.chunkData, true);
 +            } catch (final Throwable ex) {
 +                PaperFileIOThread.LOGGER.error("Could not de-serialize chunk data for task: " + this.toString(), ex);
@@ -2280,19 +2278,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
      }
  
      @Override
-diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/net/minecraft/server/MCUtil.java
-+++ b/src/main/java/net/minecraft/server/MCUtil.java
-@@ -0,0 +0,0 @@ public final class MCUtil {
-     public static int getTicketLevelFor(net.minecraft.world.level.chunk.ChunkStatus status) {
-         return net.minecraft.server.level.ChunkMap.MAX_VIEW_DISTANCE + net.minecraft.world.level.chunk.ChunkStatus.getDistance(status);
-     }
-+
-+    public static int getTicketLevelFor(net.minecraft.world.level.chunk.ChunkStatus status) {
-+        return net.minecraft.server.level.ChunkMap.MAX_VIEW_DISTANCE + net.minecraft.world.level.chunk.ChunkStatus.getDistance(status);
-+    }
- }
 diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/net/minecraft/server/Main.java
@@ -2322,25 +2307,6 @@ diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/mai
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/net/minecraft/server/level/ChunkHolder.java
 +++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java
-@@ -0,0 +0,0 @@ public class ChunkHolder {
-                 return chunkstatus;
-             }
-         }
-+        return null;
-+    }
-+
-+    public ChunkStatus getChunkHolderStatus() {
-+        for (ChunkStatus curr = ChunkStatus.FULL, next = curr.getParent(); curr != next; curr = next, next = next.getParent()) {
-+            CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> future = this.getFutureIfPresentUnchecked(curr);
-+            Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure> either = future.getNow(null);
-+            if (either == null || !either.left().isPresent()) {
-+                continue;
-+            }
-+            return curr;
-+        }
- 
-         return null;
-     }
 @@ -0,0 +0,0 @@ public class ChunkHolder {
          ChunkStatus chunkstatus = ChunkHolder.getStatus(this.oldTicketLevel);
          ChunkStatus chunkstatus1 = ChunkHolder.getStatus(this.ticketLevel);
@@ -2471,7 +2437,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +                        LOGGER.fatal("Failed to prepare async save, attempting synchronous save", ex);
 +                        this.save(ichunkaccess);
 +                    }
-+                    // Paper end - async chunk savin
++                    // Paper end - async chunk saving
                      if (this.entitiesInLevel.remove(pos) && ichunkaccess instanceof LevelChunk) {
                          LevelChunk chunk = (LevelChunk) ichunkaccess;
  
@@ -2504,6 +2470,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
  
 +                if (chunkHolder.protoChunk != null) {try (Timing ignored2 = this.level.timings.chunkLoadLevelTimer.startTimingIfSync()) { // Paper start - timings // Paper - chunk is created async
 +                    if (true) {
++                        ProtoChunk protochunk = chunkHolder.protoChunk;
                          this.markPosition(pos, protochunk.getStatus().getChunkType());
                          return Either.left(protochunk);
                      }
@@ -2629,15 +2596,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
      }
      // Paper end
 +    // Paper start - async chunk io
-+    public ChunkAccess getChunkAtImmediately(int x, int z) {
-+        ChunkHolder holder = this.chunkMap.getVisibleChunkIfPresent(ChunkPos.asLong(x, z));
-+        if (holder == null) {
-+            return null;
-+        }
-+
-+        return holder.getLastAvailable();
-+    }
-+
 +    private long asyncLoadSeqCounter;
 +
 +    public CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> getChunkAtAsynchronously(int x, int z, boolean gen, boolean isUrgent) {
@@ -2736,14 +2694,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +            return CompletableFuture.completedFuture(either);
 +        }, this.mainThreadProcessor);
 +    }
-+
-+    public <T> void addTicketAtLevel(TicketType<T> ticketType, ChunkPos chunkPos, int ticketLevel, T identifier) {
-+        this.distanceManager.addTicketAtLevel(ticketType, chunkPos, ticketLevel, identifier);
-+    }
-+
-+    public <T> void removeTicketAtLevel(TicketType<T> ticketType, ChunkPos chunkPos, int ticketLevel, T identifier) {
-+        this.distanceManager.removeTicketAtLevel(ticketType, chunkPos, ticketLevel, identifier);
-+    }
 +    // Paper end - async chunk io
  
      @Nullable
@@ -2812,21 +2762,21 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    public final com.destroystokyo.paper.io.PaperFileIOThread.ChunkDataController poiDataController = new com.destroystokyo.paper.io.PaperFileIOThread.ChunkDataController() {
 +        @Override
 +        public void writeData(int x, int z, net.minecraft.nbt.CompoundTag compound) throws java.io.IOException {
-+            ServerLevel.this.getChunkSource().chunkMap.getVillagePlace().write(new ChunkPos(x, z), compound);
++            ServerLevel.this.getChunkSource().chunkMap.getPoiManager().write(new ChunkPos(x, z), compound);
 +        }
 +
 +        @Override
 +        public net.minecraft.nbt.CompoundTag readData(int x, int z) throws java.io.IOException {
-+            return ServerLevel.this.getChunkSource().chunkMap.getVillagePlace().read(new ChunkPos(x, z));
++            return ServerLevel.this.getChunkSource().chunkMap.getPoiManager().read(new ChunkPos(x, z));
 +        }
 +
 +        @Override
 +        public <T> T computeForRegionFile(int chunkX, int chunkZ, java.util.function.Function<net.minecraft.world.level.chunk.storage.RegionFile, T> function) {
-+            synchronized (ServerLevel.this.getChunkSource().chunkMap.getVillagePlace()) {
++            synchronized (ServerLevel.this.getChunkSource().chunkMap.getPoiManager()) {
 +                net.minecraft.world.level.chunk.storage.RegionFile file;
 +
 +                try {
-+                    file = ServerLevel.this.getChunkSource().chunkMap.getVillagePlace().getFile(new ChunkPos(chunkX, chunkZ), false);
++                    file = ServerLevel.this.getChunkSource().chunkMap.getPoiManager().getRegionFile(new ChunkPos(chunkX, chunkZ), false);
 +                } catch (java.io.IOException ex) {
 +                    throw new RuntimeException(ex);
 +                }
@@ -2837,8 +2787,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +
 +        @Override
 +        public <T> T computeForRegionFileIfLoaded(int chunkX, int chunkZ, java.util.function.Function<net.minecraft.world.level.chunk.storage.RegionFile, T> function) {
-+            synchronized (ServerLevel.this.getChunkSource().chunkMap.getVillagePlace()) {
-+                net.minecraft.world.level.chunk.storage.RegionFile file = ServerLevel.this.getChunkSource().chunkMap.getVillagePlace().getRegionFileIfLoaded(new ChunkPos(chunkX, chunkZ));
++            synchronized (ServerLevel.this.getChunkSource().chunkMap.getPoiManager()) {
++                net.minecraft.world.level.chunk.storage.RegionFile file = ServerLevel.this.getChunkSource().chunkMap.getPoiManager().getRegionFileIfLoaded(new ChunkPos(chunkX, chunkZ));
 +                return function.apply(file);
 +            }
 +        }
@@ -2861,7 +2811,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +                net.minecraft.world.level.chunk.storage.RegionFile file;
 +
 +                try {
-+                    file = ServerLevel.this.getChunkSource().chunkMap.regionFileCache.getFile(new ChunkPos(chunkX, chunkZ), false);
++                    file = ServerLevel.this.getChunkSource().chunkMap.regionFileCache.getRegionFile(new ChunkPos(chunkX, chunkZ), false);
 +                } catch (java.io.IOException ex) {
 +                    throw new RuntimeException(ex);
 +                }
@@ -3085,9 +3035,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
  
 -            return protochunk1;
 +            return new InProgressChunkHolder(protochunk1, tasksToExecuteOnMain); // Paper - Async chunk loading
-         }
-     }
- 
++        }
++    }
++
 +    // Paper start - async chunk save for unload
 +    public static final class AsyncSaveData {
 +        public final DataLayer[] blockLight;
@@ -3107,9 +3057,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +            this.fluidTickList = fluidTickList;
 +            this.blockEntities = blockEntities;
 +            this.worldTime = worldTime;
-+        }
-+    }
-+
+         }
+     }
+ 
 +    // must be called sync
 +    public static AsyncSaveData getAsyncSaveData(ServerLevel world, ChunkAccess chunk) {
 +        org.spigotmc.AsyncCatcher.catchOp("preparation of chunk data for async save");
@@ -3139,22 +3089,22 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        net.minecraft.world.ticks.TickContainerAccess<Block> blockTickList = chunk.getBlockTicks();
 +
 +        //TODO check ChunkSerializer "block_ticks"
-+        ListTag blockTickListSerialized;
-+        if (blockTickList instanceof ProtoTickList || blockTickList instanceof ChunkTickList) {
-+            blockTickListSerialized = null;
-+        } else {
-+            blockTickListSerialized = world.getBlockTicks().save(chunkPos);
-+        }
++        ListTag blockTickListSerialized = null; // Paper - remove null
++        // if (blockTickList instanceof ProtoTickList || blockTickList instanceof ChunkTickList) {
++        //     blockTickListSerialized = null;
++        // } else {
++        //     blockTickListSerialized = world.getBlockTicks().save(chunkPos);
++        // }
 +
 +        net.minecraft.world.ticks.TickContainerAccess<Fluid> fluidTickList = chunk.getFluidTicks();
 +
 +        //TODO
-+        ListTag fluidTickListSerialized;
-+        if (fluidTickList instanceof ProtoTickList || fluidTickList instanceof ChunkTickList) {
-+            fluidTickListSerialized = null;
-+        } else {
-+            fluidTickListSerialized = world.getFluidTicks().save(chunkPos);
-+        }
++        ListTag fluidTickListSerialized = null; // Paper - remove null
++        // if (fluidTickList instanceof ProtoTickList || fluidTickList instanceof ChunkTickList) {
++        //     fluidTickListSerialized = null;
++        // } else {
++        //     fluidTickListSerialized = world.getFluidTicks().save(chunkPos);
++        // }
 +
 +        ListTag blockEntitiesSerialized = new ListTag();
 +        for (final BlockPos blockPos : chunk.getBlockEntitiesPos()) {
@@ -3182,9 +3132,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
          CompoundTag nbttagcompound = new CompoundTag();
  
 @@ -0,0 +0,0 @@ public class ChunkSerializer {
+         nbttagcompound.putInt("xPos", chunkcoordintpair.x);
          nbttagcompound.putInt("yPos", chunk.getMinSection());
          nbttagcompound.putInt("zPos", chunkcoordintpair.z);
-         nbttagcompound.putLong("LastUpdate", world.getGameTime());
+-        nbttagcompound.putLong("LastUpdate", world.getGameTime());
 +        nbttagcompound.putLong("LastUpdate", asyncsavedata != null ? asyncsavedata.worldTime : world.getGameTime()); // Paper - async chunk unloading
          nbttagcompound.putLong("InhabitedTime", chunk.getInhabitedTime());
          nbttagcompound.putString("Status", chunk.getStatus().getName());
@@ -3333,6 +3284,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
      }
  
      public ChunkScanAccess chunkScanner() {
+-        return this.worker;
++        // Paper start - nuke IO worker
++        return ((chunkPos, streamTagVisitor) -> {
++            try {
++                this.regionFileCache.scanChunk(chunkPos, streamTagVisitor);
++                return java.util.concurrent.CompletableFuture.completedFuture(null);
++            } catch (IOException e) {
++                throw new RuntimeException(e);
++            }
++        });
++        // Paper end
+     }
+ }
 diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
@@ -3384,27 +3348,27 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 @@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable {
          this.sync = dsync;
      }
-
--    public RegionFile getFile(ChunkPos chunkcoordintpair, boolean existingOnly) throws IOException { // CraftBukkit
+ 
+-    private RegionFile getRegionFile(ChunkPos chunkcoordintpair, boolean existingOnly) throws IOException { // CraftBukkit
 +    // Paper start
 +    public synchronized RegionFile getRegionFileIfLoaded(ChunkPos chunkcoordintpair) {
 +        return this.regionCache.getAndMoveToFirst(ChunkPos.asLong(chunkcoordintpair.getRegionX(), chunkcoordintpair.getRegionZ()));
 +    }
 +
 +    public synchronized boolean chunkExists(ChunkPos pos) throws IOException {
-+        RegionFile regionfile = getFile(pos, true);
++        RegionFile regionfile = getRegionFile(pos, true);
 +
 +        return regionfile != null ? regionfile.hasChunk(pos) : false;
 +    }
 +
-+    public synchronized RegionFile getFile(ChunkPos chunkcoordintpair, boolean existingOnly) throws IOException { // CraftBukkit
-+        return this.getFile(chunkcoordintpair, existingOnly, false);
++    public synchronized RegionFile getRegionFile(ChunkPos chunkcoordintpair, boolean existingOnly) throws IOException { // CraftBukkit
++        return this.getRegionFile(chunkcoordintpair, existingOnly, false);
 +    }
-+    public synchronized RegionFile getFile(ChunkPos chunkcoordintpair, boolean existingOnly, boolean lock) throws IOException {
++    public synchronized RegionFile getRegionFile(ChunkPos chunkcoordintpair, boolean existingOnly, boolean lock) throws IOException {
 +        // Paper end
          long i = ChunkPos.asLong(chunkcoordintpair.getRegionX(), chunkcoordintpair.getRegionZ());
          RegionFile regionfile = (RegionFile) this.regionCache.getAndMoveToFirst(i);
-
+ 
          if (regionfile != null) {
 +            // Paper start
 +            if (lock) {
@@ -3416,8 +3380,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
          } else {
              if (this.regionCache.size() >= com.destroystokyo.paper.PaperConfig.regionFileCacheSize) { // Paper - configurable
 @@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable {
-             RegionFile regionfile1 = new RegionFile(file1, this.folder, this.sync);
-
+             RegionFile regionfile1 = new RegionFile(path1, this.folder, this.sync);
+ 
              this.regionCache.putAndMoveToFirst(i, regionfile1);
 +            // Paper start
 +            if (lock) {
@@ -3432,54 +3396,58 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
      @Nullable
      public CompoundTag read(ChunkPos pos) throws IOException {
          // CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing
--        RegionFile regionfile = this.getFile(pos, true);
-+        RegionFile regionfile = this.getFile(pos, true, true); // Paper
+-        RegionFile regionfile = this.getRegionFile(pos, true);
++        RegionFile regionfile = this.getRegionFile(pos, true, true); // Paper
          if (regionfile == null) {
              return null;
          }
          // CraftBukkit end
 +        try { // Paper
          DataInputStream datainputstream = regionfile.getChunkDataInputStream(pos);
-
+ 
          CompoundTag nbttagcompound;
 @@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable {
          }
-
+ 
          return nbttagcompound;
 +        } finally { // Paper start
 +            regionfile.fileLock.unlock();
 +        } // Paper end
      }
-
+ 
+     public void scanChunk(ChunkPos chunkcoordintpair, StreamTagVisitor streamtagvisitor) throws IOException {
+@@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable {
+     }
+ 
      protected void write(ChunkPos pos, @Nullable CompoundTag nbt) throws IOException {
--        RegionFile regionfile = this.getFile(pos, false); // CraftBukkit
-+        RegionFile regionfile = this.getFile(pos, false, true); // CraftBukkit // Paper
+-        RegionFile regionfile = this.getRegionFile(pos, false); // CraftBukkit
++        RegionFile regionfile = this.getRegionFile(pos, false, true); // CraftBukkit // Paper
 +        try { // Paper
          int attempts = 0; Exception laste = null; while (attempts++ < 5) { try { // Paper
-
+ 
          if (nbt == null) {
 @@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable {
-             MinecraftServer.LOGGER.error("Failed to save chunk", laste);
+             net.minecraft.server.MinecraftServer.LOGGER.error("Failed to save chunk", laste);
          }
          // Paper end
 +        } finally { // Paper start
 +            regionfile.fileLock.unlock();
 +        } // Paper end
      }
-
+ 
 -    public void close() throws IOException {
 +    public synchronized void close() throws IOException { // Paper -> synchronized
          ExceptionCollector<IOException> exceptionsuppressor = new ExceptionCollector<>();
          ObjectIterator objectiterator = this.regionCache.values().iterator();
-
+ 
 @@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable {
          exceptionsuppressor.throwIfPresent();
      }
-
+ 
 -    public void flush() throws IOException {
 +    public synchronized void flush() throws IOException { // Paper - synchronize
          ObjectIterator objectiterator = this.regionCache.values().iterator();
-
+ 
          while (objectiterator.hasNext()) {
 diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
@@ -3488,7 +3456,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 @@ -0,0 +0,0 @@ import net.minecraft.world.level.LevelHeightAccessor;
  import org.apache.logging.log4j.LogManager;
  import org.apache.logging.log4j.Logger;
-
+ 
 -public class SectionStorage<R> implements AutoCloseable {
 +public class SectionStorage<R> extends RegionFileStorage implements AutoCloseable { // Paper - nuke IOWorker
      private static final Logger LOGGER = LogManager.getLogger();
@@ -3500,22 +3468,22 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
      private final Function<Runnable, Codec<R>> codec;
 @@ -0,0 +0,0 @@ public class SectionStorage<R> implements AutoCloseable {
      protected final LevelHeightAccessor levelHeightAccessor;
-
-     public SectionStorage(File directory, Function<Runnable, Codec<R>> codecFactory, Function<Runnable, R> factory, DataFixer dataFixer, DataFixTypes dataFixTypes, boolean dsync, LevelHeightAccessor world) {
-+        super(directory, dsync); // Paper - nuke IOWorker
+ 
+     public SectionStorage(Path path, Function<Runnable, Codec<R>> codecFactory, Function<Runnable, R> factory, DataFixer dataFixer, DataFixTypes dataFixTypes, boolean dsync, LevelHeightAccessor world) {
++        super(path, dsync);
          this.codec = codecFactory;
          this.factory = factory;
          this.fixerUpper = dataFixer;
          this.type = dataFixTypes;
          this.levelHeightAccessor = world;
--        this.worker = new IOWorker(directory, dsync, directory.getName());
+-        this.worker = new IOWorker(path, dsync, path.getFileName().toString());
 +        // Paper - remove mojang I/O thread
      }
-
+ 
      protected void tick(BooleanSupplier shouldKeepTicking) {
 @@ -0,0 +0,0 @@ public class SectionStorage<R> implements AutoCloseable {
      }
-
+ 
      private void readColumn(ChunkPos chunkPos) {
 -        this.readColumn(chunkPos, NbtOps.INSTANCE, this.tryRead(chunkPos));
 +        // Paper start - expose function to load in data
@@ -3525,7 +3493,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        this.readColumn(chunkPos, NbtOps.INSTANCE, compound);
 +        // Paper end - expose function to load in data
      }
-
+ 
      @Nullable
      private CompoundTag tryRead(ChunkPos pos) {
          try {
@@ -3543,9 +3511,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
          } else {
              LOGGER.error("Expected compound tag, got {}", (Object)tag);
          }
-
+ 
      }
-
+ 
 +    // Paper start - internal get data function, copied from above
 +    private CompoundTag getDataInternal(ChunkPos chunkcoordintpair) {
 +        Dynamic<Tag> dynamic = this.writeColumn(chunkcoordintpair, NbtOps.INSTANCE);
@@ -3561,7 +3529,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    // Paper end
      private <T> Dynamic<T> writeColumn(ChunkPos chunkPos, DynamicOps<T> dynamicOps) {
          Map<T, T> map = Maps.newHashMap();
-
+ 
 @@ -0,0 +0,0 @@ public class SectionStorage<R> implements AutoCloseable {
  
      @Override
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 1514614884..9afad2ea0c 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -10,7 +10,7 @@ rootProject.name = "Paper"
 include(
     "Paper-API",
     "Paper-Server",
-    // "Paper-MojangAPI", // todo
+     "Paper-MojangAPI",
 )
 
 val testPlugin = file("test-plugin.settings.gradle.kts")