--- a/net/minecraft/world/level/chunk/storage/EntityStorage.java
+++ b/net/minecraft/world/level/chunk/storage/EntityStorage.java
@@ -27,43 +27,30 @@
     private static final String ENTITIES_TAG = "Entities";
     private static final String POSITION_TAG = "Position";
     public final ServerLevel level;
-    private final SimpleRegionStorage simpleRegionStorage;
+    // Paper - rewrite chunk system
     private final LongSet emptyChunks = new LongOpenHashSet();
-    public final ProcessorMailbox<Runnable> entityDeserializerQueue;
+    // Paper - rewrite chunk system
 
     public EntityStorage(SimpleRegionStorage storage, ServerLevel world, Executor executor) {
-        this.simpleRegionStorage = storage;
+        // Paper - rewrite chunk system
         this.level = world;
-        this.entityDeserializerQueue = ProcessorMailbox.create(executor, "entity-deserializer");
+        // Paper - rewrite chunk system
     }
 
     @Override
     public CompletableFuture<ChunkEntities<Entity>> loadEntities(ChunkPos pos) {
-        return this.emptyChunks.contains(pos.toLong())
-            ? CompletableFuture.completedFuture(emptyChunk(pos))
-            : this.simpleRegionStorage.read(pos).thenApplyAsync(nbt -> {
-                if (nbt.isEmpty()) {
-                    this.emptyChunks.add(pos.toLong());
-                    return emptyChunk(pos);
-                } else {
-                    try {
-                        ChunkPos chunkPos2 = readChunkPos(nbt.get());
-                        if (!Objects.equals(pos, chunkPos2)) {
-                            LOGGER.error("Chunk file at {} is in the wrong location. (Expected {}, got {})", pos, pos, chunkPos2);
-                        }
-                    } catch (Exception var6) {
-                        LOGGER.warn("Failed to parse chunk {} position info", pos, var6);
-                    }
+        throw new UnsupportedOperationException(); // Paper - rewrite chunk system - copy out read logic into readEntities
+    }
 
-                    CompoundTag compoundTag = this.simpleRegionStorage.upgradeChunkTag(nbt.get(), -1);
-                    ListTag listTag = compoundTag.getList("Entities", 10);
-                    List<Entity> list = EntityType.loadEntitiesRecursive(listTag, this.level).collect(ImmutableList.toImmutableList());
-                    return new ChunkEntities<>(pos, list);
-                }
-            }, this.entityDeserializerQueue::tell);
+    // Paper start - rewrite chunk system
+    public static List<Entity> readEntities(ServerLevel level, CompoundTag compoundTag) {
+        ListTag listTag = compoundTag.getList("Entities", 10);
+        List<Entity> list = EntityType.loadEntitiesRecursive(listTag, level).collect(ImmutableList.toImmutableList());
+        return list;
     }
+    // Paper end - rewrite chunk system
 
-    private static ChunkPos readChunkPos(CompoundTag chunkNbt) {
+    public static ChunkPos readChunkPos(CompoundTag chunkNbt) { // Paper - public
         int[] is = chunkNbt.getIntArray("Position");
         return new ChunkPos(is[0], is[1]);
     }
@@ -78,38 +65,85 @@
 
     @Override
     public void storeEntities(ChunkEntities<Entity> dataList) {
+        // Paper start - rewrite chunk system
+        if (true) {
+            throw new UnsupportedOperationException();
+        }
+        // Paper end - rewrite chunk system
         ChunkPos chunkPos = dataList.getPos();
         if (dataList.isEmpty()) {
             if (this.emptyChunks.add(chunkPos.toLong())) {
-                this.simpleRegionStorage.write(chunkPos, null);
+                // Paper - rewrite chunk system - fix compile for unused field in dead code
             }
         } else {
-            ListTag listTag = new ListTag();
-            dataList.getEntities().forEach(entity -> {
-                CompoundTag compoundTagx = new CompoundTag();
-                if (entity.save(compoundTagx)) {
-                    listTag.add(compoundTagx);
-                }
-            });
-            CompoundTag compoundTag = NbtUtils.addCurrentDataVersion(new CompoundTag());
-            compoundTag.put("Entities", listTag);
-            writeChunkPos(compoundTag, chunkPos);
-            this.simpleRegionStorage.write(chunkPos, compoundTag).exceptionally(ex -> {
-                LOGGER.error("Failed to store chunk {}", chunkPos, ex);
-                return null;
-            });
+            // Paper - move into saveEntityChunk0
             this.emptyChunks.remove(chunkPos.toLong());
         }
     }
 
+    // Paper start - rewrite chunk system
+    public static void copyEntities(final CompoundTag from, final CompoundTag into) {
+        if (from == null) {
+            return;
+        }
+        final ListTag entitiesFrom = from.getList("Entities", net.minecraft.nbt.Tag.TAG_COMPOUND);
+        if (entitiesFrom == null || entitiesFrom.isEmpty()) {
+            return;
+        }
+
+        final ListTag entitiesInto = into.getList("Entities", net.minecraft.nbt.Tag.TAG_COMPOUND);
+        into.put("Entities", entitiesInto); // this is in case into doesn't have any entities
+        entitiesInto.addAll(0, entitiesFrom.copy()); // need to copy, this is coming from the save thread
+    }
+
+    public static CompoundTag saveEntityChunk(List<Entity> entities, ChunkPos chunkPos, ServerLevel level) {
+        return saveEntityChunk0(entities, chunkPos, level, false);
+    }
+    private static CompoundTag saveEntityChunk0(List<Entity> entities, ChunkPos chunkPos, ServerLevel level, boolean force) {
+        if (!force && entities.isEmpty()) {
+            return null;
+        }
+
+        ListTag listTag = new ListTag();
+        final java.util.Map<net.minecraft.world.entity.EntityType<?>, Integer> savedEntityCounts = new java.util.HashMap<>(); // Paper - Entity load/save limit per chunk
+        entities.forEach((entity) -> { // diff here: use entities parameter
+            // Paper start - Entity load/save limit per chunk
+            final EntityType<?> entityType = entity.getType();
+            final int saveLimit = level.paperConfig().chunks.entityPerChunkSaveLimit.getOrDefault(entityType, -1);
+            if (saveLimit > -1) {
+                if (savedEntityCounts.getOrDefault(entityType, 0) >= saveLimit) {
+                    return;
+                }
+                savedEntityCounts.merge(entityType, 1, Integer::sum);
+            }
+            // Paper end - Entity load/save limit per chunk
+            CompoundTag compoundTag = new CompoundTag();
+            if (entity.save(compoundTag)) {
+                listTag.add(compoundTag);
+            }
+
+        });
+        CompoundTag compoundTag = NbtUtils.addCurrentDataVersion(new CompoundTag());
+        compoundTag.put("Entities", listTag);
+        writeChunkPos(compoundTag, chunkPos);
+        // Paper - remove worker usage
+
+        return !force && listTag.isEmpty() ? null : compoundTag;
+    }
+
+    public static CompoundTag upgradeChunkTag(CompoundTag chunkNbt) {
+        int i = NbtUtils.getDataVersion(chunkNbt, -1);
+        return ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag(ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.ENTITY_CHUNK, chunkNbt, i, net.minecraft.SharedConstants.getCurrentVersion().getDataVersion().getVersion());
+    }
+    // Paper end - rewrite chunk system
+
     @Override
     public void flush(boolean sync) {
-        this.simpleRegionStorage.synchronize(sync).join();
-        this.entityDeserializerQueue.runAll();
+        throw new UnsupportedOperationException(); // Paper - rewrite chunk system
     }
 
     @Override
     public void close() throws IOException {
-        this.simpleRegionStorage.close();
+        throw new UnsupportedOperationException(); // Paper - rewrite chunk system
     }
 }
