diff --git a/patches/unapplied/api/Timings-v2.patch b/patches/api/Timings-v2.patch
similarity index 100%
rename from patches/unapplied/api/Timings-v2.patch
rename to patches/api/Timings-v2.patch
diff --git a/patches/unapplied/server/Add-MinecraftKey-Information-to-Objects.patch b/patches/server/Add-MinecraftKey-Information-to-Objects.patch
similarity index 91%
rename from patches/unapplied/server/Add-MinecraftKey-Information-to-Objects.patch
rename to patches/server/Add-MinecraftKey-Information-to-Objects.patch
index 0b799c10de..572c2719b0 100644
--- a/patches/unapplied/server/Add-MinecraftKey-Information-to-Objects.patch
+++ b/patches/server/Add-MinecraftKey-Information-to-Objects.patch
@@ -18,17 +18,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
  
                      MutablePair<Integer, Map<ChunkPos, Integer>> info = list.computeIfAbsent(key, k -> MutablePair.of(0, Maps.newHashMap()));
                      ChunkPos chunk = e.chunkPosition();
-diff --git a/src/main/java/net/minecraft/server/KeyedObject.java b/src/main/java/net/minecraft/server/KeyedObject.java
+diff --git a/src/main/java/io/papermc/paper/util/KeyedObject.java b/src/main/java/io/papermc/paper/util/KeyedObject.java
 new file mode 100644
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
 --- /dev/null
-+++ b/src/main/java/net/minecraft/server/KeyedObject.java
++++ b/src/main/java/io/papermc/paper/util/KeyedObject.java
 @@ -0,0 +0,0 @@
-+package net.minecraft.server;
++package io.papermc.paper.util;
 +
 +import net.minecraft.resources.ResourceLocation;
 +
-+// TODO(Mariell Hoversholm): Move stupid ass class
 +public interface KeyedObject {
 +    ResourceLocation getMinecraftKey();
 +    default String getMinecraftKeyString() {
@@ -45,7 +44,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
  // CraftBukkit end
  
 -public abstract class Entity implements Nameable, EntityAccess, CommandSource {
-+public abstract class Entity implements Nameable, EntityAccess, CommandSource, net.minecraft.server.KeyedObject { // Paper
++public abstract class Entity implements Nameable, EntityAccess, CommandSource, io.papermc.paper.util.KeyedObject { // Paper
  
      // CraftBukkit start
      private static final int CURRENT_LEVEL = 2;
@@ -71,6 +70,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        getMinecraftKey(); // Try to load if it doesn't exists. see: https://github.com/PaperMC/Paper/issues/1280
 +        return entityKeyString;
 +    }
++
      @Nullable
      public final String getEncodeId() {
          EntityType<?> entitytypes = this.getType();
@@ -91,12 +91,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
  import org.spigotmc.CustomTimingsHandler; // Spigot
  
 -public abstract class BlockEntity {
-+public abstract class BlockEntity implements net.minecraft.server.KeyedObject { // Paper
++public abstract class BlockEntity implements io.papermc.paper.util.KeyedObject { // Paper
  
      public CustomTimingsHandler tickTimer = org.bukkit.craftbukkit.SpigotTimings.getTileEntityTimings(this); // Spigot
      // CraftBukkit start - data containers
 @@ -0,0 +0,0 @@ public abstract class BlockEntity {
-         this.blockState = state;
+         return new BlockPos(nbt.getInt("x"), nbt.getInt("y"), nbt.getInt("z"));
      }
  
 +    // Paper start
diff --git a/patches/server/MC-Dev-fixes.patch b/patches/server/MC-Dev-fixes.patch
index 3a8d1d8fda..85cb4c6414 100644
--- a/patches/server/MC-Dev-fixes.patch
+++ b/patches/server/MC-Dev-fixes.patch
@@ -225,19 +225,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
          }));
          RecipeManager.LOGGER.info("Loaded {} recipes", map1.size());
      }
-diff --git a/src/main/java/net/minecraft/world/level/TickNextTickData.java b/src/main/java/net/minecraft/world/level/TickNextTickData.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/net/minecraft/world/level/TickNextTickData.java
-+++ b/src/main/java/net/minecraft/world/level/TickNextTickData.java
-@@ -0,0 +0,0 @@ public class TickNextTickData<T> {
-     }
- 
-     public static <T> Comparator<TickNextTickData<T>> createTimeComparator() {
--        return Comparator.comparingLong((tickNextTickData) -> {
-+        return Comparator.<TickNextTickData<T>>comparingLong((tickNextTickData) -> { // Paper - decompile fix
-             return tickNextTickData.triggerTick;
-         }).thenComparing((tickNextTickData) -> {
-             return tickNextTickData.priority;
 diff --git a/src/main/java/net/minecraft/world/level/biome/Biome.java b/src/main/java/net/minecraft/world/level/biome/Biome.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/net/minecraft/world/level/biome/Biome.java
diff --git a/patches/unapplied/server/MC-Utils.patch b/patches/server/MC-Utils.patch
similarity index 97%
rename from patches/unapplied/server/MC-Utils.patch
rename to patches/server/MC-Utils.patch
index a101a1f015..01045e3849 100644
--- a/patches/unapplied/server/MC-Utils.patch
+++ b/patches/server/MC-Utils.patch
@@ -4471,13 +4471,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 --- a/src/main/java/net/minecraft/network/PacketEncoder.java
 +++ b/src/main/java/net/minecraft/network/PacketEncoder.java
 @@ -0,0 +0,0 @@ public class PacketEncoder extends MessageToByteEncoder<Packet<?>> {
-                         throw new IllegalArgumentException("Packet too big (is " + j + ", should be less than 8388608): " + packet);
+                         JvmProfiler.INSTANCE.onPacketSent(k, integer, channelHandlerContext.channel().remoteAddress(), j);
                      }
-                 } catch (Throwable var9) {
--                    LOGGER.error(var9);
-+                    LOGGER.error("Packet encoding of packet ID {} threw (skippable? {})", integer, packet.isSkippable(), var9); // Paper - WHAT WAS IT? WHO DID THIS TO YOU? WHAT DID YOU SEE?
+                 } catch (Throwable var10) {
+-                    LOGGER.error(var10);
++                    LOGGER.error("Packet encoding of packet ID {} threw (skippable? {})", integer, packet.isSkippable(), var10); // Paper - Give proper error message
                      if (packet.isSkippable()) {
-                         throw new SkipPacketException(var9);
+                         throw new SkipPacketException(var10);
                      } else {
 diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java
 new file mode 100644
@@ -5017,13 +5017,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
                      {
                          double currentTps = 1E3 / ( curTime - tickSection ) * MinecraftServer.SAMPLE_INTERVAL;
 @@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
-             this.snooper.prepare();
+             MinecraftServer.LOGGER.debug("Autosave finished");
+             SpigotTimings.worldSaveTimer.stopTiming(); // Spigot
          }
- 
+-
 +        io.papermc.paper.util.CachedLists.reset(); // Paper
-         this.profiler.pop();
          this.profiler.push("tallying");
          long l = this.tickTimes[this.tickCount % 100] = Util.getNanos() - i;
+ 
 @@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
              try {
                  worldserver.timings.doTick.startTiming(); // Spigot
@@ -5144,13 +5145,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
          }
  
          if (flag2 && !flag3) {
-             completablefuture = this.fullChunkFuture;
+             this.fullChunkFuture.complete(ChunkHolder.UNLOADED_LEVEL_CHUNK);
              this.fullChunkFuture = ChunkHolder.UNLOADED_LEVEL_CHUNK_FUTURE;
 +            ++this.fullChunkCreateCount; // Paper - cache ticking ready status
 +            this.isFullChunkReady = false; // Paper - cache ticking ready status
-             this.updateChunkToSave(((CompletableFuture<Either<LevelChunk, ChunkHolder.ChunkLoadingFailure>>) completablefuture).thenApply((either1) -> { // CraftBukkit - decompile error
-                 Objects.requireNonNull(chunkStorage);
-                 return either1.ifLeft(chunkStorage::packTicks);
+         }
+ 
+         boolean flag4 = playerchunk_state.isOrAfter(ChunkHolder.FullChunkStatus.TICKING);
 @@ -0,0 +0,0 @@ public class ChunkHolder {
          if (!flag4 && flag5) {
              this.tickingChunkFuture = chunkStorage.prepareTickingChunk(this);
@@ -5279,11 +5280,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    // Paper end
 +
      public ChunkMap(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureManager structureManager, Executor executor, BlockableEventLoop<Runnable> mainThreadExecutor, LightChunkGetter chunkProvider, ChunkGenerator chunkGenerator, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier<DimensionDataStorage> persistentStateManagerFactory, int viewDistance, boolean dsync) {
-         super(new File(session.getDimensionPath(world.dimension()), "region"), dataFixer, dsync);
+         super(session.getDimensionPath(world.dimension()).resolve("region"), dataFixer, dsync);
          this.visibleChunkMap = this.updatingChunkMap.clone();
 @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
          this.overworldDataStorage = persistentStateManagerFactory;
-         this.poiManager = new PoiManager(new File(file, "poi"), dataFixer, dsync, world);
+         this.poiManager = new PoiManager(path.resolve("poi"), dataFixer, dsync, world);
          this.setViewDistance(viewDistance);
 +        // Paper start
 +        this.dataRegionManager = new io.papermc.paper.chunk.SingleThreadChunkRegionManager(this.level, 2, (1.0 / 3.0), 1, 6, "Data", DataRegionData::new, DataRegionSectionData::new);
@@ -5291,7 +5292,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        // Paper end
      }
  
-     private static double euclideanDistanceSquared(ChunkPos pos, Entity entity) {
+     protected ChunkGenerator generator() {
 @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
          }
      }
@@ -5702,7 +5703,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    final io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<LevelChunk> entityTickingChunks = new io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<>(4096, 0.75f, 4096, 0.15, true);
 +    // Paper end
  
-     public ServerChunkCache(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureManager structureManager, Executor workerExecutor, ChunkGenerator chunkGenerator, int viewDistance, boolean flag, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkstatusupdatelistener, Supplier<DimensionDataStorage> supplier) {
+     public ServerChunkCache(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureManager structureManager, Executor workerExecutor, ChunkGenerator chunkGenerator, int viewDistance, int simulationDistance, boolean dsync, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier<DimensionDataStorage> persistentStateManagerFactory) {
          this.level = world;
 @@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
          this.lastChunk[0] = chunk;
@@ -5755,14 +5756,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
      @Override
      public ChunkAccess getChunk(int x, int z, ChunkStatus leastStatus, boolean create) {
 @@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
-             }
+             gameprofilerfiller.popPush("spawnAndTick");
+             boolean flag2 = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit
  
-             this.level.getProfiler().popPush("broadcast");
--            list.forEach((playerchunk) -> {
-+            this.chunkMap.getChunks().forEach((playerchunk) -> { // Paper - no... just no...
-                 Optional<LevelChunk> optional = ((Either) playerchunk.getTickingChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).left(); // CraftBukkit - decompile error
+-            Collections.shuffle(list);
++            //Collections.shuffle(list); // Paper - no... just no...
+             Iterator iterator1 = list.iterator();
  
-                 Objects.requireNonNull(playerchunk);
+             while (iterator1.hasNext()) {
 diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -5784,7 +5785,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
  public class ServerLevel extends Level implements WorldGenLevel {
  
 @@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel {
-         return this.chunkSource.getChunk(x, z, false);
+         return convertable.dimensionType;
      }
  
 +    // Paper start
@@ -5960,7 +5961,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    private boolean keepAlivePending; @Deprecated private void setPendingPing(boolean isPending) { this.keepAlivePending = isPending;}; @Deprecated private boolean isPendingPing() { return this.keepAlivePending;}; // Paper - OBFHELPER
 +    private long keepAliveChallenge; @Deprecated private void setKeepAliveID(long keepAliveID) { this.keepAliveChallenge = keepAliveID;}; @Deprecated private long getKeepAliveID() {return this.keepAliveChallenge; };  // Paper - OBFHELPER
      // CraftBukkit start - multithreaded fields
-     private AtomicInteger chatSpamTickCount = new AtomicInteger();
+     private final AtomicInteger chatSpamTickCount = new AtomicInteger();
      // CraftBukkit end
 diff --git a/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java b/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
@@ -6019,19 +6020,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    public org.bukkit.craftbukkit.entity.CraftMob getBukkitMob() { return (org.bukkit.craftbukkit.entity.CraftMob) super.getBukkitEntity(); } // Paper
      public void setTarget(@Nullable LivingEntity target) {
          // CraftBukkit start - fire event
-         this.setGoalTarget(target, EntityTargetEvent.TargetReason.UNKNOWN, true);
+         this.setTarget(target, EntityTargetEvent.TargetReason.UNKNOWN, true);
 diff --git a/src/main/java/net/minecraft/world/entity/PathfinderMob.java b/src/main/java/net/minecraft/world/entity/PathfinderMob.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/net/minecraft/world/entity/PathfinderMob.java
 +++ b/src/main/java/net/minecraft/world/entity/PathfinderMob.java
-@@ -0,0 +0,0 @@ import org.bukkit.event.entity.EntityUnleashEvent;
- 
- public abstract class PathfinderMob extends Mob {
+@@ -0,0 +0,0 @@ public abstract class PathfinderMob extends Mob {
+         super(type, world);
+     }
  
 +    public org.bukkit.craftbukkit.entity.CraftCreature getBukkitCreature() { return (org.bukkit.craftbukkit.entity.CraftCreature) super.getBukkitEntity(); } // Paper
 +
-     protected PathfinderMob(EntityType<? extends PathfinderMob> type, Level world) {
-         super(type, world);
+     public float getWalkTargetValue(BlockPos pos) {
+         return this.getWalkTargetValue(pos, this.level);
      }
 diff --git a/src/main/java/net/minecraft/world/entity/monster/Monster.java b/src/main/java/net/minecraft/world/entity/monster/Monster.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
@@ -6071,8 +6072,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        return bukkitStack;
 +    }
 +    // Paper end
-     public void setTag(@Nullable CompoundTag tag) {
-         this.tag = tag;
++
+     public void setTag(@Nullable CompoundTag nbt) {
+         this.tag = nbt;
          if (this.getItem().canBeDepleted()) {
 @@ -0,0 +0,0 @@ public final class ItemStack {
      // CraftBukkit start
@@ -6195,20 +6197,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
  import org.bukkit.craftbukkit.block.data.CraftBlockData;
  import org.bukkit.craftbukkit.util.CraftNamespacedKey;
  import org.bukkit.event.block.BlockPhysicsEvent;
-@@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
-                 Level.this.getCraftServer().getHandle().sendAll(new ClientboundSetBorderWarningDistancePacket(border), border.world);
-             }
- 
--            public void onBorderSetDamagePerBlock(WorldBorder border, double damagePerBlock) {}
-+            public void onBorderSetDamagePerBlock(WorldBorder border, double damagePerBlock) {
-+            }
- 
--            public void onBorderSetDamageSafeZOne(WorldBorder border, double safeZoneRadius) {}
-+            public void onBorderSetDamageSafeZOne(WorldBorder border, double safeZoneRadius) {
-+            }
-         });
-         // CraftBukkit end
-         this.timings = new SpigotTimings.WorldTimingsHandler(this); // Spigot - code below can generate new world and access timings
 @@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
          return y < -20000000 || y >= 20000000;
      }
@@ -6307,7 +6295,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
  import net.minecraft.world.level.block.Blocks;
  import net.minecraft.world.level.block.entity.BlockEntity;
 @@ -0,0 +0,0 @@ public class PathNavigationRegion implements BlockGetter, CollisionGetter {
-         return this.getChunk(chunkX, chunkZ);
+         return List.of();
      }
  
 +    // Paper start - if loaded util
@@ -6388,38 +6376,42 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
          }
  
          public boolean useShapeForLightOcclusion() {
+diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java b/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
+--- a/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java
++++ b/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java
+@@ -0,0 +0,0 @@ public abstract class ChunkAccess implements BlockGetter, BiomeManager.NoiseBiom
+     protected final ShortList[] postProcessing;
+     protected volatile boolean unsaved;
+     private volatile boolean isLightCorrect;
+-    protected final ChunkPos chunkPos;
++    protected final ChunkPos chunkPos; public final long coordinateKey; public final int locX; public final int locZ; // Paper - cache coordinate key
+     private long inhabitedTime;
+     @Nullable
+     @Deprecated
+@@ -0,0 +0,0 @@ public abstract class ChunkAccess implements BlockGetter, BiomeManager.NoiseBiom
+     protected final LevelChunkSection[] sections;
+ 
+     public ChunkAccess(ChunkPos pos, UpgradeData upgradeData, LevelHeightAccessor heightLimitView, Registry<Biome> biome, long inhabitedTime, @Nullable LevelChunkSection[] sectionArrayInitializer, @Nullable BlendingData blendingData) {
+-        this.chunkPos = pos;
++        this.locX = pos.x; this.locZ = pos.z; // Paper - reduce need for field lookups
++        this.chunkPos = pos; this.coordinateKey = ChunkPos.asLong(locX, locZ); // Paper - cache long key
+         this.upgradeData = upgradeData;
+         this.levelHeightAccessor = heightLimitView;
+         this.sections = new LevelChunkSection[heightLimitView.getSectionsCount()];
 diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
 +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
-@@ -0,0 +0,0 @@ import net.minecraft.core.SectionPos;
- import net.minecraft.nbt.CompoundTag;
+@@ -0,0 +0,0 @@ import net.minecraft.nbt.CompoundTag;
  import net.minecraft.network.FriendlyByteBuf;
+ import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData;
  import net.minecraft.server.level.ChunkHolder;
 +import net.minecraft.server.level.ServerChunkCache;
  import net.minecraft.server.level.ServerLevel;
  import net.minecraft.util.profiling.ProfilerFiller;
  import net.minecraft.world.entity.Entity;
-@@ -0,0 +0,0 @@ public class LevelChunk implements ChunkAccess {
-     private Supplier<ChunkHolder.FullChunkStatus> fullStatus;
-     @Nullable
-     private Consumer<LevelChunk> postLoad;
--    private final ChunkPos chunkPos;
-+    private final ChunkPos chunkPos; public final long coordinateKey; public final int locX; public final int locZ; // Paper - cache coordinate key
-     private volatile boolean isLightCorrect;
-     private final Int2ObjectMap<GameEventDispatcher> gameEventDispatcherSections;
- 
-@@ -0,0 +0,0 @@ public class LevelChunk implements ChunkAccess {
-         this.structureStarts = Maps.newHashMap();
-         this.structuresRefences = Maps.newHashMap();
-         this.level = (ServerLevel) world; // CraftBukkit - type
--        this.chunkPos = pos;
-+        this.locX = pos.x; this.locZ = pos.z; // Paper - reduce need for field look ups
-+        this.chunkPos = pos; this.coordinateKey = ChunkPos.asLong(locX, locZ); // Paper - cache long key
-         this.upgradeData = upgradeData;
-         this.gameEventDispatcherSections = new Int2ObjectOpenHashMap();
-         Heightmap.Types[] aheightmap_type = Heightmap.Types.values();
-@@ -0,0 +0,0 @@ public class LevelChunk implements ChunkAccess {
+@@ -0,0 +0,0 @@ public class LevelChunk extends ChunkAccess {
      public final org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer persistentDataContainer = new org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer(LevelChunk.DATA_TYPE_REGISTRY);
      // CraftBukkit end
  
@@ -6527,10 +6519,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    }
 +    // Paper end
 +
-     public LevelChunk(ServerLevel worldserver, ProtoChunk protoChunk, @Nullable Consumer<LevelChunk> consumer) {
-         this(worldserver, protoChunk.getPos(), protoChunk.getBiomes(), protoChunk.getUpgradeData(), protoChunk.getBlockTicks(), protoChunk.getLiquidTicks(), protoChunk.getInhabitedTime(), protoChunk.getSections(), consumer);
+     public LevelChunk(ServerLevel world, ProtoChunk protoChunk, @Nullable LevelChunk.PostLoadProcessor chunk_c) {
+         this(world, protoChunk.getPos(), protoChunk.getUpgradeData(), protoChunk.unpackBlockTicks(), protoChunk.unpackFluidTicks(), protoChunk.getInhabitedTime(), protoChunk.getSections(), chunk_c, protoChunk.getBlendingData());
          Iterator iterator = protoChunk.getBlockEntities().values().iterator();
-@@ -0,0 +0,0 @@ public class LevelChunk implements ChunkAccess {
+@@ -0,0 +0,0 @@ public class LevelChunk extends ChunkAccess {
          }
      }
  
@@ -6549,7 +6541,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
      @Override
      public FluidState getFluidState(BlockPos pos) {
          return this.getFluidState(pos.getX(), pos.getY(), pos.getZ());
-@@ -0,0 +0,0 @@ public class LevelChunk implements ChunkAccess {
+@@ -0,0 +0,0 @@ public class LevelChunk extends ChunkAccess {
          return this.getBlockEntity(pos, LevelChunk.EntityCreationType.CHECK);
      }
  
@@ -6557,7 +6549,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
      @Nullable
      public BlockEntity getBlockEntity(BlockPos pos, LevelChunk.EntityCreationType creationType) {
          // CraftBukkit start
-@@ -0,0 +0,0 @@ public class LevelChunk implements ChunkAccess {
+@@ -0,0 +0,0 @@ public class LevelChunk extends ChunkAccess {
  
      // CraftBukkit start
      public void loadCallback() {
@@ -6583,7 +6575,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
          if (server != null) {
              /*
               * If it's a new world, the first few chunks are generated inside
-@@ -0,0 +0,0 @@ public class LevelChunk implements ChunkAccess {
+@@ -0,0 +0,0 @@ public class LevelChunk extends ChunkAccess {
          server.getPluginManager().callEvent(unloadEvent);
          // note: saving can be prevented, but not forced if no saving is actually required
          this.mustNotSave = !unloadEvent.isSaveChunk();
@@ -6604,36 +6596,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        this.resetNeighbours();
 +        // Paper end
      }
-     // CraftBukkit end
- 
-@@ -0,0 +0,0 @@ public class LevelChunk implements ChunkAccess {
-     }
- 
-     public void packTicks(ServerLevel world) {
--        DefaultedRegistry registryblocks;
--
-         if (this.blockTicks == EmptyTickList.<Block>empty()) { // CraftBukkit - decompile error
--            registryblocks = Registry.BLOCK;
--            Objects.requireNonNull(registryblocks);
--            this.blockTicks = new ChunkTickList<>(registryblocks::getKey, world.getBlockTicks().fetchTicksInChunk(this.chunkPos, true, false), world.getGameTime());
-+            this.blockTicks = new ChunkTickList<>(Registry.BLOCK::getKey, world.getBlockTicks().fetchTicksInChunk(this.chunkPos, true, false), world.getGameTime()); // Paper - decompile fix: inline Registry.BLOCK
-             this.setUnsaved(true);
-         }
- 
-         if (this.liquidTicks == EmptyTickList.<Fluid>empty()) { // CraftBukkit - decompile error
--            registryblocks = Registry.FLUID;
--            Objects.requireNonNull(registryblocks);
--            this.liquidTicks = new ChunkTickList<>(registryblocks::getKey, world.getLiquidTicks().fetchTicksInChunk(this.chunkPos, true, false), world.getGameTime());
-+            this.liquidTicks = new ChunkTickList<>(Registry.FLUID::getKey, world.getLiquidTicks().fetchTicksInChunk(this.chunkPos, true, false), world.getGameTime()); // Paper - decompile fix: inline Registry.FLUID
-             this.setUnsaved(true);
-         }
  
+     @Override
 diff --git a/src/main/java/net/minecraft/world/level/chunk/ProtoChunk.java b/src/main/java/net/minecraft/world/level/chunk/ProtoChunk.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/net/minecraft/world/level/chunk/ProtoChunk.java
 +++ b/src/main/java/net/minecraft/world/level/chunk/ProtoChunk.java
-@@ -0,0 +0,0 @@ public class ProtoChunk implements ChunkAccess {
-         this.postProcessing = new ShortList[world.getSectionsCount()];
+@@ -0,0 +0,0 @@ public class ProtoChunk extends ChunkAccess {
+         return new ChunkAccess.TicksToSave(this.blockTicks, this.fluidTicks);
      }
  
 +    // Paper start - If loaded util
diff --git a/patches/unapplied/server/Not-implemeneted.patch b/patches/server/Not-implemeneted.patch
similarity index 100%
rename from patches/unapplied/server/Not-implemeneted.patch
rename to patches/server/Not-implemeneted.patch
diff --git a/patches/unapplied/server/Paper-Metrics.patch b/patches/server/Paper-Metrics.patch
similarity index 100%
rename from patches/unapplied/server/Paper-Metrics.patch
rename to patches/server/Paper-Metrics.patch
diff --git a/patches/unapplied/server/Timings-v2.patch b/patches/server/Timings-v2.patch
similarity index 92%
rename from patches/unapplied/server/Timings-v2.patch
rename to patches/server/Timings-v2.patch
index e9e9c18ba2..0ea5d870fa 100644
--- a/patches/unapplied/server/Timings-v2.patch
+++ b/patches/server/Timings-v2.patch
@@ -783,7 +783,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import co.aikar.timings.MinecraftTimings; // Paper
  import org.spigotmc.SlackActivityAccountant; // Spigot
  
- public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTask> implements SnooperPopulator, CommandSource, AutoCloseable {
+ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTask> implements CommandSource, AutoCloseable {
 @@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
          }
          // CraftBukkit end
@@ -853,25 +853,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 -            SpigotTimings.worldSaveTimer.startTiming(); // Spigot
              MinecraftServer.LOGGER.debug("Autosave started");
              this.profiler.push("save");
-             this.playerList.saveAll();
-             this.saveAllChunks(true, false, false);
+             this.saveEverything(true, false, false);
              this.profiler.pop();
              MinecraftServer.LOGGER.debug("Autosave finished");
 -            SpigotTimings.worldSaveTimer.stopTiming(); // Spigot
          }
- 
-         this.profiler.push("snooper");
-@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
- 
          io.papermc.paper.util.CachedLists.reset(); // Paper
-         this.profiler.pop();
-+
 +        // Paper start - move executeAll() into full server tick timing
 +        try (co.aikar.timings.Timing ignored = MinecraftTimings.processTasksTimer.startTiming()) {
 +            this.runAllTasks();
 +        }
 +        // Paper end
-+
          this.profiler.push("tallying");
          long l = this.tickTimes[this.tickCount % 100] = Util.getNanos() - i;
  
@@ -1057,6 +1049,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
  
 +import co.aikar.timings.Timing; // Paper
  import com.google.common.collect.ImmutableList;
+ import com.google.common.collect.ImmutableList.Builder;
  import com.google.common.collect.Iterables;
 +import com.google.common.collect.ComparisonChain; // Paper
  import com.google.common.collect.Lists;
@@ -1077,7 +1070,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
  
 -                if (nbttagcompound != null) {
 +                if (nbttagcompound != null) {try (Timing ignored2 = this.level.timings.chunkLoadLevelTimer.startTimingIfSync()) { // Paper start - timings
-                     boolean flag = nbttagcompound.contains("Level", 10) && nbttagcompound.getCompound("Level").contains("Status", 8);
+                     boolean flag = nbttagcompound.contains("Status", 8);
  
                      if (flag) {
 @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -1090,11 +1083,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
                  Throwable throwable = reportedexception.getCause();
  
 @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
-             ChunkStatus chunkstatus = ChunkHolder.getStatus(playerchunk.getTicketLevel());
+             ChunkStatus chunkstatus = ChunkHolder.getStatus(chunkHolder.getTicketLevel());
  
              return !chunkstatus.isOrAfter(ChunkStatus.FULL) ? ChunkHolder.UNLOADED_CHUNK : either.mapLeft((ichunkaccess) -> {
-+            try (Timing ignored = level.timings.chunkPostLoad.startTimingIfSync()) { // Paper
-                 ChunkPos chunkcoordintpair = playerchunk.getPos();
++                try (Timing ignored = level.timings.chunkPostLoad.startTimingIfSync()) { // Paper
+                 ChunkPos chunkcoordintpair = chunkHolder.getPos();
                  ProtoChunk protochunk = (ProtoChunk) ichunkaccess;
                  LevelChunk chunk;
 @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -1106,15 +1099,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
          }, (runnable) -> {
              ProcessorHandle mailbox = this.mainThreadMailbox;
 @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
- 
-         ChunkMap.TrackedEntity playerchunkmap_entitytracker;
-         ObjectIterator objectiterator;
+         List<ServerPlayer> list = Lists.newArrayList();
+         List<ServerPlayer> list1 = this.level.players();
+         ObjectIterator objectiterator = this.entityMap.values().iterator();
 +        level.timings.tracker1.startTiming(); // Paper
  
-         for (objectiterator = this.entityMap.values().iterator(); objectiterator.hasNext(); playerchunkmap_entitytracker.serverEntity.sendChanges()) {
-             playerchunkmap_entitytracker = (ChunkMap.TrackedEntity) objectiterator.next();
+         ChunkMap.TrackedEntity playerchunkmap_entitytracker;
+ 
 @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
-                 playerchunkmap_entitytracker.lastSectionPos = sectionposition1;
+                 playerchunkmap_entitytracker.serverEntity.sendChanges();
              }
          }
 +        level.timings.tracker1.stopTiming(); // Paper
@@ -1141,12 +1134,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
              gameprofilerfiller.incrementCounter("getChunkCacheMiss");
 -            level.timings.syncChunkLoadTimer.startTiming(); // Spigot
              CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> completablefuture = this.getChunkFutureMainThread(x, z, leastStatus, create);
-             ServerChunkCache.MainThreadExecutor chunkproviderserver_a = this.mainThreadProcessor;
+             ServerChunkCache.MainThreadExecutor chunkproviderserver_b = this.mainThreadProcessor;
  
              Objects.requireNonNull(completablefuture);
 +            if (!completablefuture.isDone()) { // Paper
 +                this.level.timings.syncChunkLoad.startTiming(); // Paper
-             chunkproviderserver_a.managedBlock(completablefuture::isDone);
+             chunkproviderserver_b.managedBlock(completablefuture::isDone);
 -            level.timings.syncChunkLoadTimer.stopTiming(); // Spigot
 +                this.level.timings.syncChunkLoad.stopTiming(); // Paper
 +            } // Paper
@@ -1174,68 +1167,55 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
          this.level.getProfiler().popPush("unload");
          this.chunkMap.tick(booleansupplier);
 @@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
-             boolean flag2 = level.ticksPerAnimalSpawns != 0L && worlddata.getGameTime() % level.ticksPerAnimalSpawns == 0L; // CraftBukkit
+             boolean flag1 = level.ticksPerAnimalSpawns != 0L && worlddata.getGameTime() % level.ticksPerAnimalSpawns == 0L; // CraftBukkit
  
-             this.level.getProfiler().push("naturalSpawnCount");
+             gameprofilerfiller.push("naturalSpawnCount");
 +            this.level.timings.countNaturalMobs.startTiming(); // Paper - timings
              int l = this.distanceManager.getNaturalSpawnChunkCount();
-             NaturalSpawner.SpawnState spawnercreature_d = NaturalSpawner.createState(l, this.level.getAllEntities(), this::getFullChunk);
+             NaturalSpawner.SpawnState spawnercreature_d = NaturalSpawner.createState(l, this.level.getAllEntities(), this::getFullChunk, new LocalMobCapCalculator(this.chunkMap));
 +            this.level.timings.countNaturalMobs.stopTiming(); // Paper - timings
  
              this.lastSpawnState = spawnercreature_d;
-             this.level.getProfiler().pop();
-             List<ChunkHolder> list = Lists.newArrayList(this.chunkMap.getChunks());
- 
-             Collections.shuffle(list);
+             gameprofilerfiller.popPush("filteringLoadedChunks");
+             List<ServerChunkCache.ChunkAndHolder> list = Lists.newArrayListWithCapacity(l);
+             Iterator iterator = this.chunkMap.getChunks().iterator();
 +            this.level.timings.chunkTicks.startTiming(); // Paper
-             list.forEach((playerchunk) -> {
-                 Optional<LevelChunk> optional = ((Either) playerchunk.getTickingChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).left();
  
+             while (iterator.hasNext()) {
+                 ChunkHolder playerchunk = (ChunkHolder) iterator.next();
 @@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
-                             NaturalSpawner.spawnForChunk(this.level, chunk, spawnercreature_d, this.spawnFriendlies, this.spawnEnemies, flag2);
-                         }
+                     }
  
+                     if (this.level.shouldTickBlocksAt(chunkcoordintpair.toLong())) {
 -                        this.level.timings.doTickTiles.startTiming(); // Spigot
-+                        // this.level.timings.doTickTiles.startTiming(); // Spigot // Paper
-                         this.level.tickChunk(chunk, k);
+                         this.level.tickChunk(chunk1, k);
 -                        this.level.timings.doTickTiles.stopTiming(); // Spigot
-+                        // this.level.timings.doTickTiles.stopTiming(); // Spigot // Paper
                      }
                  }
-             });
+             }
+-
 +            this.level.timings.chunkTicks.stopTiming(); // Paper
-             this.level.getProfiler().push("customSpawners");
-             if (flag1) {
+             gameprofilerfiller.popPush("customSpawners");
+             if (flag2) {
 +                try (co.aikar.timings.Timing ignored = this.level.timings.miscMobSpawning.startTiming()) { // Paper - timings
                  this.level.tickCustomSpawners(this.spawnEnemies, this.spawnFriendlies);
 +                } // Paper - timings
              }
  
-             this.level.getProfiler().popPush("broadcast");
-@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
-                 Optional<LevelChunk> optional = ((Either) playerchunk.getTickingChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).left(); // CraftBukkit - decompile error
- 
-                 Objects.requireNonNull(playerchunk);
--                optional.ifPresent(playerchunk::broadcastChanges);
-+
-+                // Paper start - timings
-+                optional.ifPresent(chunk -> {
-+                    this.level.timings.broadcastChunkUpdates.startTiming(); // Paper - timings
-+                    playerchunk.broadcastChanges(chunk);
-+                    this.level.timings.broadcastChunkUpdates.stopTiming(); // Paper - timings
-+                });
-+                // Paper end
+             gameprofilerfiller.popPush("broadcast");
+             list.forEach((chunkproviderserver_a1) -> {
++                this.level.timings.broadcastChunkUpdates.startTiming(); // Paper - timing
+                 chunkproviderserver_a1.holder.broadcastChanges(chunkproviderserver_a1.chunk);
++                this.level.timings.broadcastChunkUpdates.stopTiming(); // Paper - timing
              });
-             this.level.getProfiler().pop();
-             this.level.getProfiler().pop();
+             gameprofilerfiller.pop();
+             gameprofilerfiller.pop();
+-            this.level.timings.tracker.startTiming(); // Spigot
+             this.chunkMap.tick();
+-            this.level.timings.tracker.stopTiming(); // Spigot
          }
- 
--        this.level.timings.tracker.startTiming(); // Spigot
-         this.chunkMap.tick();
--        this.level.timings.tracker.stopTiming(); // Spigot
      }
  
-     private void getFullChunk(long pos, Consumer<LevelChunk> chunkConsumer) {
 diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -1257,22 +1237,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
  import org.bukkit.craftbukkit.event.CraftEventFactory;
  import org.bukkit.craftbukkit.util.WorldUUID;
  import org.bukkit.event.entity.CreatureSpawnEvent;
-@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel {
-         DefaultedRegistry registryblocks = Registry.BLOCK;
- 
-         Objects.requireNonNull(registryblocks);
--        this.blockTicks = new ServerTickList<>(this, predicate, Registry.BLOCK::getKey, this::tickBlock); // CraftBukkit - decompile error
-+        this.blockTicks = new ServerTickList<>(this, predicate, Registry.BLOCK::getKey, this::tickBlock, "Blocks"); // CraftBukkit - decompile error // Paper - Timings
-         Predicate<Fluid> predicate2 = (fluidtype) -> { // CraftBukkit - decompile error
-             return fluidtype == null || fluidtype == Fluids.EMPTY;
-         };
-         registryblocks = Registry.FLUID;
-         Objects.requireNonNull(registryblocks);
--        this.liquidTicks = new ServerTickList<>(this, predicate2, Registry.FLUID::getKey, this::tickLiquid); // CraftBukkit - decompile error
-+        this.liquidTicks = new ServerTickList<>(this, predicate2, Registry.FLUID::getKey, this::tickLiquid, "Fluids"); // CraftBukkit - decompile error // Paper - Timings
-         this.navigatingMobs = new ObjectOpenHashSet();
-         this.blockEvents = new ObjectLinkedOpenHashSet();
-         this.dragonParts = new Int2ObjectOpenHashMap();
 @@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel {
          this.updateSkyBrightness();
          this.tickTime();
@@ -1280,8 +1244,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 -        timings.doTickPending.startTiming(); // Spigot
 +        timings.scheduledBlocks.startTiming(); // Paper
          if (!this.isDebug()) {
-             this.blockTicks.tick();
-             this.liquidTicks.tick();
+             j = this.getGameTime();
+             gameprofilerfiller.push("blockTicks");
+@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel {
+             this.fluidTicks.tick(j, 65536, this::tickFluid);
+             gameprofilerfiller.pop();
          }
 -        timings.doTickPending.stopTiming(); // Spigot
 +        timings.scheduledBlocks.stopTiming(); // Paper
@@ -1418,7 +1385,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 -            org.bukkit.craftbukkit.SpigotTimings.playerCommandTimer.stopTiming(); // Spigot
 +            MinecraftTimings.playerCommandTimer.stopTiming(); // Paper
          }
-         // this.minecraftServer.getCommandDispatcher().a(this.player.getCommandListener(), s);
+         // this.server.getCommands().performCommand(this.player.createCommandSourceStack(), s);
          // CraftBukkit end
 diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
@@ -1456,7 +1423,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
  import org.bukkit.event.entity.EntityCombustByEntityEvent;
  import org.bukkit.event.hanging.HangingBreakByEntityEvent;
  import org.bukkit.event.vehicle.VehicleBlockCollisionEvent;
-@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i
      public org.bukkit.projectiles.ProjectileSource projectileSource; // For projectiles only
      public boolean forceExplosionKnockback; // SPIGOT-949
      public boolean persistentInvisibility = false;
@@ -1464,7 +1431,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
      // Spigot start
      public final org.spigotmc.ActivationRange.ActivationType activationType = org.spigotmc.ActivationRange.initializeEntityActivationType(this);
      public final boolean defaultActivationState;
-@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i
      }
  
      public void move(MoverType movementType, Vec3 movement) {
@@ -1472,14 +1439,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
          if (this.noPhysics) {
              this.setPos(this.getX() + movement.x, this.getY() + movement.y, this.getZ() + movement.z);
          } else {
-@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i
                  this.level.getProfiler().pop();
              }
          }
 -        org.bukkit.craftbukkit.SpigotTimings.entityMoveTimer.stopTiming(); // Spigot
      }
  
-     protected void tryCheckInsideBlocks() {
+     protected boolean isHorizontalCollisionMinor(Vec3 adjustedMovement) {
 diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/net/minecraft/world/entity/EntityType.java
@@ -1603,7 +1570,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        // SpigotTimings.timerEntityAIMove.stopTiming(); // Spigot // Paper
          this.level.getProfiler().pop();
          this.level.getProfiler().push("freezing");
-         boolean flag1 = this.getType().is((Tag) EntityTypeTags.FREEZE_HURTS_EXTRA_TYPES);
+         boolean flag1 = this.getType().is(EntityTypeTags.FREEZE_HURTS_EXTRA_TYPES);
 @@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity {
              this.checkAutoSpinAttack(axisalignedbb, this.getBoundingBox());
          }
@@ -1636,7 +1603,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
      private org.spigotmc.TickLimiter entityLimiter;
      private org.spigotmc.TickLimiter tileLimiter;
 @@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
-             }
+             public void onBorderSetDamageSafeZOne(WorldBorder border, double safeZoneRadius) {}
          });
          // CraftBukkit end
 -        this.timings = new SpigotTimings.WorldTimingsHandler(this); // Spigot - code below can generate new world and access timings
@@ -1661,52 +1628,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
          } catch (Throwable throwable) {
              CrashReport crashreport = CrashReport.forThrowable(throwable, "Ticking entity");
              CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Entity being ticked");
-diff --git a/src/main/java/net/minecraft/world/level/ServerTickList.java b/src/main/java/net/minecraft/world/level/ServerTickList.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/net/minecraft/world/level/ServerTickList.java
-+++ b/src/main/java/net/minecraft/world/level/ServerTickList.java
-@@ -0,0 +0,0 @@ public class ServerTickList<T> implements TickList<T> {
-     private final List<TickNextTickData<T>> alreadyTicked = Lists.newArrayList();
-     private final Consumer<TickNextTickData<T>> ticker;
- 
--    public ServerTickList(ServerLevel world, Predicate<T> invalidObjPredicate, Function<T, ResourceLocation> idToName, Consumer<TickNextTickData<T>> tickConsumer) {
-+    // Paper start - timings
-+    private final co.aikar.timings.Timing timingCleanup; // Paper
-+    private final co.aikar.timings.Timing timingTicking; // Paper
-+
-+    public ServerTickList(ServerLevel world, Predicate<T> invalidObjPredicate, Function<T, ResourceLocation> idToName, Consumer<TickNextTickData<T>> tickConsumer, String timingsType) {
-+        this.timingCleanup = co.aikar.timings.WorldTimingsHandler.getTickList(world, timingsType + " - Cleanup");
-+        this.timingTicking = co.aikar.timings.WorldTimingsHandler.getTickList(world, timingsType + " - Ticking");
-+        // Paper end
-         this.ignore = invalidObjPredicate;
-         this.toId = idToName;
-         this.level = world;
-@@ -0,0 +0,0 @@ public class ServerTickList<T> implements TickList<T> {
- 
-             this.level.getProfiler().push("cleaning");
- 
-+            this.timingCleanup.startTiming(); // Paper
-             TickNextTickData nextticklistentry;
- 
-             while (i > 0 && iterator.hasNext()) {
-@@ -0,0 +0,0 @@ public class ServerTickList<T> implements TickList<T> {
-                     --i;
-                 }
-             }
-+            this.timingCleanup.stopTiming(); // Paper
- 
-+            this.timingTicking.startTiming(); // Paper
-             this.level.getProfiler().popPush("ticking");
- 
-             while ((nextticklistentry = (TickNextTickData) this.currentlyTicking.poll()) != null) {
-@@ -0,0 +0,0 @@ public class ServerTickList<T> implements TickList<T> {
-                 }
-             }
- 
-+            this.timingTicking.stopTiming(); // Paper
-             this.level.getProfiler().pop();
-             this.alreadyTicked.clear();
-             this.currentlyTicking.clear();
 diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/net/minecraft/world/level/block/Block.java
@@ -1738,7 +1659,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import co.aikar.timings.MinecraftTimings; // Paper
 +import co.aikar.timings.Timing; // Paper
  
- public abstract class BlockEntity implements net.minecraft.server.KeyedObject { // Paper
+ public abstract class BlockEntity implements io.papermc.paper.util.KeyedObject { // Paper
  
 -    public CustomTimingsHandler tickTimer = org.bukkit.craftbukkit.SpigotTimings.getTileEntityTimings(this); // Spigot
 +    public Timing tickTimer = MinecraftTimings.getTileEntityTimings(this); // Paper
@@ -1749,7 +1670,7 @@ diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
 +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
-@@ -0,0 +0,0 @@ public class LevelChunk implements ChunkAccess {
+@@ -0,0 +0,0 @@ public class LevelChunk extends ChunkAccess {
              server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkLoadEvent(this.bukkitChunk, this.needsDecoration));
  
              if (this.needsDecoration) {
@@ -1757,7 +1678,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
                  this.needsDecoration = false;
                  java.util.Random random = new java.util.Random();
                  random.setSeed(this.level.getSeed());
-@@ -0,0 +0,0 @@ public class LevelChunk implements ChunkAccess {
+@@ -0,0 +0,0 @@ public class LevelChunk extends ChunkAccess {
                      }
                  }
                  server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkPopulateEvent(this.bukkitChunk));
@@ -1770,30 +1691,27 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 --- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
 +++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
 @@ -0,0 +0,0 @@ public class ChunkSerializer {
-     private static void postLoadChunk(ServerLevel world, CompoundTag nbt, LevelChunk chunk) {
-         ListTag nbttaglist;
+         ListTag nbttaglist1 = ChunkSerializer.getListOfCompoundsOrNull(nbt, "block_entities");
  
--        world.timings.syncChunkLoadEntitiesTimer.startTiming(); // Spigot
-         if (nbt.contains("Entities", 9)) {
-             nbttaglist = nbt.getList("Entities", 10);
-             if (!nbttaglist.isEmpty()) {
-@@ -0,0 +0,0 @@ public class ChunkSerializer {
+         return nbttaglist == null && nbttaglist1 == null ? null : (chunk) -> {
+-            world.timings.syncChunkLoadEntitiesTimer.startTiming(); // Spigot
+             if (nbttaglist != null) {
+                 world.addLegacyChunkEntities(EntityType.loadEntitiesRecursive(nbttaglist, world));
              }
-         }
+-            world.timings.syncChunkLoadEntitiesTimer.stopTiming(); // Spigot
  
--        world.timings.syncChunkLoadEntitiesTimer.stopTiming(); // Spigot
--        world.timings.syncChunkLoadTileEntitiesTimer.startTiming(); // Spigot
-         nbttaglist = nbt.getList("TileEntities", 10);
- 
-         for (int i = 0; i < nbttaglist.size(); ++i) {
+-            world.timings.syncChunkLoadTileEntitiesTimer.startTiming(); // Spigot
+             if (nbttaglist1 != null) {
+                 for (int i = 0; i < nbttaglist1.size(); ++i) {
+                     CompoundTag nbttagcompound1 = nbttaglist1.getCompound(i);
 @@ -0,0 +0,0 @@ public class ChunkSerializer {
+                     }
                  }
              }
-         }
--        world.timings.syncChunkLoadTileEntitiesTimer.stopTiming(); // Spigot
- 
-     }
+-            world.timings.syncChunkLoadTileEntitiesTimer.stopTiming(); // Spigot
  
+             // CraftBukkit start - load chunk persistent data from nbt
+             net.minecraft.nbt.Tag persistentBase = nbt.get("ChunkBukkitValues");
 diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
diff --git a/todo.txt b/todo.txt
new file mode 100644
index 0000000000..098ea2d921
--- /dev/null
+++ b/todo.txt
@@ -0,0 +1 @@
+Add Timings to LevelTicks and EntityTickList