diff --git a/patches/server/0004-Paper-config-files.patch b/patches/server/0004-Paper-config-files.patch
index 351a727884..e616c9efc8 100644
--- a/patches/server/0004-Paper-config-files.patch
+++ b/patches/server/0004-Paper-config-files.patch
@@ -7,10 +7,10 @@ Loads each yml file for early init too so it can be used for early options
 
 diff --git a/src/main/java/com/destroystokyo/paper/PaperCommand.java b/src/main/java/com/destroystokyo/paper/PaperCommand.java
 new file mode 100644
-index 0000000000000000000000000000000000000000..94cc5b494cdbc163fb70d0f4a6708d6ca2f42288
+index 0000000000000000000000000000000000000000..bee2fa2bfbb61209381f24ed6508d3d1c73a344a
 --- /dev/null
 +++ b/src/main/java/com/destroystokyo/paper/PaperCommand.java
-@@ -0,0 +1,286 @@
+@@ -0,0 +1,285 @@
 +package com.destroystokyo.paper;
 +
 +import com.google.common.base.Functions;
@@ -65,7 +65,7 @@ index 0000000000000000000000000000000000000000..94cc5b494cdbc163fb70d0f4a6708d6c
 +
 +    private static boolean testPermission(CommandSender commandSender, String permission) {
 +        if (commandSender.hasPermission(BASE_PERM + permission) || commandSender.hasPermission("bukkit.command.paper")) return true;
-+        commandSender.sendMessage(Bukkit.getPermissionMessage());
++        commandSender.sendMessage(ChatColor.RED + "I'm sorry, but you do not have permission to perform this command. Please contact the server administrators if you believe that this is in error."); // Sorry, kashike
 +        return false;
 +    }
 +
@@ -151,7 +151,7 @@ index 0000000000000000000000000000000000000000..94cc5b494cdbc163fb70d0f4a6708d6c
 +            case "ver":
 +                if (!testPermission(sender, "version")) break; // "ver" needs a special check because it's an alias. All other commands are checked up before the switch statement (because they are present in the SUBCOMMANDS set)
 +            case "version":
-+                Command ver = org.bukkit.Bukkit.getServer().getCommandMap().getCommand("version");
++                Command ver = MinecraftServer.getServer().server.getCommandMap().getCommand("version");
 +                if (ver != null) {
 +                    ver.execute(sender, commandLabel, new String[0]);
 +                    break;
@@ -219,12 +219,11 @@ index 0000000000000000000000000000000000000000..94cc5b494cdbc163fb70d0f4a6708d6c
 +                Map<ResourceLocation, Integer> nonEntityTicking = Maps.newHashMap();
 +                ServerChunkCache chunkProviderServer = world.getChunkSource();
 +
-+                Collection<Entity> entities = world.entitiesById.values();
-+                entities.forEach(e -> {
++                world.getAllEntities().forEach(e -> {
 +                    ResourceLocation key = new ResourceLocation(""); // TODO: update in next patch
 +
 +                    MutablePair<Integer, Map<ChunkPos, Integer>> info = list.computeIfAbsent(key, k -> MutablePair.of(0, Maps.newHashMap()));
-+                    ChunkPos chunk = new ChunkPos(e.xChunk, e.zChunk);
++                    ChunkPos chunk = e.chunkPosition();
 +                    info.left++;
 +                    info.right.put(chunk, info.right.getOrDefault(chunk, 0) + 1);
 +                    if (!chunkProviderServer.isPositionTicking(e)) {
diff --git a/patches/server/0007-Paper-Metrics.patch b/patches/server/0007-Paper-Metrics.patch
index 38a4e27283..c94eb31fa6 100644
--- a/patches/server/0007-Paper-Metrics.patch
+++ b/patches/server/0007-Paper-Metrics.patch
@@ -15,7 +15,7 @@ decisions on behalf of the project.
 
 diff --git a/src/main/java/com/destroystokyo/paper/Metrics.java b/src/main/java/com/destroystokyo/paper/Metrics.java
 new file mode 100644
-index 0000000000000000000000000000000000000000..0b9e689d57705965721b5c55bc45d36657f360e4
+index 0000000000000000000000000000000000000000..e3b74dbdf8e14219a56fab939f3174e0c2f66de6
 --- /dev/null
 +++ b/src/main/java/com/destroystokyo/paper/Metrics.java
 @@ -0,0 +1,670 @@
@@ -618,7 +618,7 @@ index 0000000000000000000000000000000000000000..0b9e689d57705965721b5c55bc45d366
 +                }));
 +
 +                metrics.addCustomChart(new Metrics.SingleLineChart("players", () -> Bukkit.getOnlinePlayers().size()));
-+                metrics.addCustomChart(new Metrics.SimplePie("online_mode", () -> Bukkit.getOnlineMode() || PaperConfig.isProxyOnlineMode() ? "online" : "offline"));
++                metrics.addCustomChart(new Metrics.SimplePie("online_mode", () -> Bukkit.getOnlineMode() ? "online" : "offline"));
 +                metrics.addCustomChart(new Metrics.SimplePie("paper_version", () -> (Metrics.class.getPackage().getImplementationVersion() != null) ? Metrics.class.getPackage().getImplementationVersion() : "unknown"));
 +
 +                metrics.addCustomChart(new Metrics.DrilldownPie("java_version", () -> {
diff --git a/patches/server/0008-Add-MinecraftKey-Information-to-Objects.patch b/patches/server/0008-Add-MinecraftKey-Information-to-Objects.patch
index 5d6c20956d..b96b5157a6 100644
--- a/patches/server/0008-Add-MinecraftKey-Information-to-Objects.patch
+++ b/patches/server/0008-Add-MinecraftKey-Information-to-Objects.patch
@@ -6,18 +6,18 @@ Subject: [PATCH] Add MinecraftKey Information to Objects
 Stores the reference to the objects respective MinecraftKey
 
 diff --git a/src/main/java/com/destroystokyo/paper/PaperCommand.java b/src/main/java/com/destroystokyo/paper/PaperCommand.java
-index 94cc5b494cdbc163fb70d0f4a6708d6ca2f42288..3ef396c0a543b5724769e0b83314f332739bdff0 100644
+index bee2fa2bfbb61209381f24ed6508d3d1c73a344a..1fa190e098079522e0fe3593fa261c1b7ad4e24b 100644
 --- a/src/main/java/com/destroystokyo/paper/PaperCommand.java
 +++ b/src/main/java/com/destroystokyo/paper/PaperCommand.java
-@@ -208,7 +208,7 @@ public class PaperCommand extends Command {
+@@ -207,7 +207,7 @@ public class PaperCommand extends Command {
+                 ServerChunkCache chunkProviderServer = world.getChunkSource();
  
-                 Collection<Entity> entities = world.entitiesById.values();
-                 entities.forEach(e -> {
+                 world.getAllEntities().forEach(e -> {
 -                    ResourceLocation key = new ResourceLocation(""); // TODO: update in next patch
 +                    ResourceLocation key = e.getMinecraftKey();
  
                      MutablePair<Integer, Map<ChunkPos, Integer>> info = list.computeIfAbsent(key, k -> MutablePair.of(0, Maps.newHashMap()));
-                     ChunkPos chunk = new ChunkPos(e.xChunk, e.zChunk);
+                     ChunkPos chunk = e.chunkPosition();
 diff --git a/src/main/java/net/minecraft/server/KeyedObject.java b/src/main/java/net/minecraft/server/KeyedObject.java
 new file mode 100644
 index 0000000000000000000000000000000000000000..d02bd109399d6b32cbbb5e6f9ec7e650e8299a26
diff --git a/patches/server/0009-Timings-v2.patch b/patches/server/0009-Timings-v2.patch
index c9ed1235fa..77a87bfdee 100644
--- a/patches/server/0009-Timings-v2.patch
+++ b/patches/server/0009-Timings-v2.patch
@@ -1642,10 +1642,18 @@ index 3b2b57f5049d26a14e45eb4ec88a5b498005d372..ebe33c891e25c729c4373190da86c7a8
          if (!this.level.isClientSide && this.isSensitiveToWater() && this.isInWaterRainOrBubble()) {
              this.hurt(DamageSource.DROWN, 1.0F);
 diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
-index c9c8ce20e3adff1fe49489a6ac2d2e6be2795949..931a22bfce05716d6a6c0030c790f2338f7edd9f 100644
+index c9c8ce20e3adff1fe49489a6ac2d2e6be2795949..59730455fcdf22bada7288833cf7e8b6c9b4096a 100644
 --- a/src/main/java/net/minecraft/world/level/Level.java
 +++ b/src/main/java/net/minecraft/world/level/Level.java
-@@ -149,7 +149,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
+@@ -82,7 +82,6 @@ import org.bukkit.Bukkit;
+ import org.bukkit.Location;
+ import org.bukkit.craftbukkit.CraftServer;
+ import org.bukkit.craftbukkit.CraftWorld;
+-import org.bukkit.craftbukkit.SpigotTimings; // Spigot
+ import org.bukkit.craftbukkit.block.CapturedBlockState;
+ import org.bukkit.craftbukkit.block.CraftBlockState;
+ import org.bukkit.craftbukkit.block.data.CraftBlockData;
+@@ -149,7 +148,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
  
      public final com.destroystokyo.paper.PaperWorldConfig paperConfig; // Paper
  
@@ -1654,7 +1662,7 @@ index c9c8ce20e3adff1fe49489a6ac2d2e6be2795949..931a22bfce05716d6a6c0030c790f233
      public static BlockPos lastPhysicsProblem; // Spigot
      private org.spigotmc.TickLimiter entityLimiter;
      private org.spigotmc.TickLimiter tileLimiter;
-@@ -236,7 +236,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
+@@ -236,7 +235,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
              }
          });
          // CraftBukkit end
@@ -1663,7 +1671,7 @@ index c9c8ce20e3adff1fe49489a6ac2d2e6be2795949..931a22bfce05716d6a6c0030c790f233
          this.entityLimiter = new org.spigotmc.TickLimiter(spigotConfig.entityMaxTickTime);
          this.tileLimiter = new org.spigotmc.TickLimiter(spigotConfig.tileMaxTickTime);
      }
-@@ -721,15 +721,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
+@@ -721,15 +720,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
  
          timings.tileEntityTick.stopTiming(); // Spigot
          this.tickingBlockEntities = false;
@@ -1772,14 +1780,14 @@ index e4601134598e509a158ceacec6099a78bbabe89d..0e70d9df226e0843a943b3a57d1319ce
      private static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry();
      public CraftPersistentDataContainer persistentDataContainer;
 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 57f32618d6c95734fa4b45274afaf2319c7608ae..0aa56efbfe42cad7840dae2f1f8ab3dc365128fd 100644
+index 57f32618d6c95734fa4b45274afaf2319c7608ae..485cb87e83dd4b4b052905fb7f5f83d3c26f542f 100644
 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
 +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
 @@ -725,6 +725,7 @@ public class LevelChunk implements ChunkAccess {
              server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkLoadEvent(this.bukkitChunk, this.needsDecoration));
  
              if (this.needsDecoration) {
-+                try (co.aikar.timings.Timing ignored = this.world.timings.chunkLoadPopulate.startTiming()) { // Paper
++                try (co.aikar.timings.Timing ignored = this.level.timings.chunkLoadPopulate.startTiming()) { // Paper
                  this.needsDecoration = false;
                  java.util.Random random = new java.util.Random();
                  random.setSeed(this.level.getSeed());
@@ -1865,6 +1873,175 @@ index 743c9f11dbbb66db97bcb3b8fecd97290a7c9f61..c85f69cc6ef8a61ca1b07beb5f2b2159
          @Override
          public void restart() {
              org.spigotmc.RestartCommand.restart();
+diff --git a/src/main/java/org/bukkit/craftbukkit/SpigotTimings.java b/src/main/java/org/bukkit/craftbukkit/SpigotTimings.java
+deleted file mode 100644
+index b0ffa23faf62629043dfd613315eaf9c5fcc2cfe..0000000000000000000000000000000000000000
+--- a/src/main/java/org/bukkit/craftbukkit/SpigotTimings.java
++++ /dev/null
+@@ -1,163 +0,0 @@
+-package org.bukkit.craftbukkit;
+-
+-import java.util.HashMap;
+-import net.minecraft.world.entity.Entity;
+-import net.minecraft.world.level.Level;
+-import net.minecraft.world.level.block.entity.BlockEntity;
+-import net.minecraft.world.level.storage.PrimaryLevelData;
+-import org.bukkit.craftbukkit.scheduler.CraftTask;
+-import org.bukkit.plugin.java.JavaPluginLoader;
+-import org.bukkit.scheduler.BukkitTask;
+-import org.spigotmc.CustomTimingsHandler;
+-
+-public class SpigotTimings {
+-
+-    public static final CustomTimingsHandler serverTickTimer = new CustomTimingsHandler("** Full Server Tick");
+-    public static final CustomTimingsHandler playerListTimer = new CustomTimingsHandler("Player List");
+-    public static final CustomTimingsHandler commandFunctionsTimer = new CustomTimingsHandler("Command Functions");
+-    public static final CustomTimingsHandler connectionTimer = new CustomTimingsHandler("Connection Handler");
+-    public static final CustomTimingsHandler playerConnectionTimer = new CustomTimingsHandler("** PlayerConnection");
+-    public static final CustomTimingsHandler tickablesTimer = new CustomTimingsHandler("Tickables");
+-    public static final CustomTimingsHandler schedulerTimer = new CustomTimingsHandler("Scheduler");
+-    public static final CustomTimingsHandler timeUpdateTimer = new CustomTimingsHandler("Time Update");
+-    public static final CustomTimingsHandler serverCommandTimer = new CustomTimingsHandler("Server Command");
+-    public static final CustomTimingsHandler worldSaveTimer = new CustomTimingsHandler("World Save");
+-
+-    public static final CustomTimingsHandler entityMoveTimer = new CustomTimingsHandler("** entityMove");
+-    public static final CustomTimingsHandler tickEntityTimer = new CustomTimingsHandler("** tickEntity");
+-    public static final CustomTimingsHandler activatedEntityTimer = new CustomTimingsHandler("** activatedTickEntity");
+-    public static final CustomTimingsHandler tickTileEntityTimer = new CustomTimingsHandler("** tickTileEntity");
+-
+-    public static final CustomTimingsHandler timerEntityBaseTick = new CustomTimingsHandler("** livingEntityBaseTick");
+-    public static final CustomTimingsHandler timerEntityAI = new CustomTimingsHandler("** livingEntityAI");
+-    public static final CustomTimingsHandler timerEntityAICollision = new CustomTimingsHandler("** livingEntityAICollision");
+-    public static final CustomTimingsHandler timerEntityAIMove = new CustomTimingsHandler("** livingEntityAIMove");
+-    public static final CustomTimingsHandler timerEntityTickRest = new CustomTimingsHandler("** livingEntityTickRest");
+-
+-    public static final CustomTimingsHandler processQueueTimer = new CustomTimingsHandler("processQueue");
+-    public static final CustomTimingsHandler schedulerSyncTimer = new CustomTimingsHandler("** Scheduler - Sync Tasks", JavaPluginLoader.pluginParentTimer);
+-
+-    public static final CustomTimingsHandler playerCommandTimer = new CustomTimingsHandler("** playerCommand");
+-
+-    public static final CustomTimingsHandler entityActivationCheckTimer = new CustomTimingsHandler("entityActivationCheck");
+-    public static final CustomTimingsHandler checkIfActiveTimer = new CustomTimingsHandler("** checkIfActive");
+-
+-    public static final HashMap<String, CustomTimingsHandler> entityTypeTimingMap = new HashMap<String, CustomTimingsHandler>();
+-    public static final HashMap<String, CustomTimingsHandler> tileEntityTypeTimingMap = new HashMap<String, CustomTimingsHandler>();
+-    public static final HashMap<String, CustomTimingsHandler> pluginTaskTimingMap = new HashMap<String, CustomTimingsHandler>();
+-
+-    /**
+-     * Gets a timer associated with a plugins tasks.
+-     * @param task
+-     * @param period
+-     * @return
+-     */
+-    public static CustomTimingsHandler getPluginTaskTimings(BukkitTask task, long period) {
+-        if (!task.isSync()) {
+-            return null;
+-        }
+-        String plugin;
+-        final CraftTask ctask = (CraftTask) task;
+-
+-        if (task.getOwner() != null) {
+-            plugin = task.getOwner().getDescription().getFullName();
+-        } else {
+-            plugin = "Unknown";
+-        }
+-        String taskname = ctask.getTaskName();
+-
+-        String name = "Task: " + plugin + " Runnable: " + taskname;
+-        if (period > 0) {
+-            name += "(interval:" + period + ")";
+-        } else {
+-            name += "(Single)";
+-        }
+-        CustomTimingsHandler result = SpigotTimings.pluginTaskTimingMap.get(name);
+-        if (result == null) {
+-            result = new CustomTimingsHandler(name, SpigotTimings.schedulerSyncTimer);
+-            SpigotTimings.pluginTaskTimingMap.put(name, result);
+-        }
+-        return result;
+-    }
+-
+-    /**
+-     * Get a named timer for the specified entity type to track type specific timings.
+-     * @param entity
+-     * @return
+-     */
+-    public static CustomTimingsHandler getEntityTimings(Entity entity) {
+-        String entityType = entity.getClass().getName();
+-        CustomTimingsHandler result = SpigotTimings.entityTypeTimingMap.get(entityType);
+-        if (result == null) {
+-            result = new CustomTimingsHandler("** tickEntity - " + entity.getClass().getSimpleName(), SpigotTimings.activatedEntityTimer);
+-            SpigotTimings.entityTypeTimingMap.put(entityType, result);
+-        }
+-        return result;
+-    }
+-
+-    /**
+-     * Get a named timer for the specified tile entity type to track type specific timings.
+-     * @param entity
+-     * @return
+-     */
+-    public static CustomTimingsHandler getTileEntityTimings(BlockEntity entity) {
+-        String entityType = entity.getClass().getName();
+-        CustomTimingsHandler result = SpigotTimings.tileEntityTypeTimingMap.get(entityType);
+-        if (result == null) {
+-            result = new CustomTimingsHandler("** tickTileEntity - " + entity.getClass().getSimpleName(), SpigotTimings.tickTileEntityTimer);
+-            SpigotTimings.tileEntityTypeTimingMap.put(entityType, result);
+-        }
+-        return result;
+-    }
+-
+-    /**
+-     * Set of timers per world, to track world specific timings.
+-     */
+-    public static class WorldTimingsHandler {
+-        public final CustomTimingsHandler mobSpawn;
+-        public final CustomTimingsHandler doChunkUnload;
+-        public final CustomTimingsHandler doTickPending;
+-        public final CustomTimingsHandler doTickTiles;
+-        public final CustomTimingsHandler doChunkMap;
+-        public final CustomTimingsHandler doSounds;
+-        public final CustomTimingsHandler entityTick;
+-        public final CustomTimingsHandler tileEntityTick;
+-        public final CustomTimingsHandler tileEntityPending;
+-        public final CustomTimingsHandler tracker;
+-        public final CustomTimingsHandler doTick;
+-        public final CustomTimingsHandler tickEntities;
+-
+-        public final CustomTimingsHandler syncChunkLoadTimer;
+-        public final CustomTimingsHandler syncChunkLoadStructuresTimer;
+-        public final CustomTimingsHandler syncChunkLoadEntitiesTimer;
+-        public final CustomTimingsHandler syncChunkLoadTileEntitiesTimer;
+-        public final CustomTimingsHandler syncChunkLoadTileTicksTimer;
+-        public final CustomTimingsHandler syncChunkLoadPostTimer;
+-
+-        public WorldTimingsHandler(Level server) {
+-            String name = ((PrimaryLevelData) server.levelData).getLevelName() + " - ";
+-
+-            this.mobSpawn = new CustomTimingsHandler("** " + name + "mobSpawn");
+-            this.doChunkUnload = new CustomTimingsHandler("** " + name + "doChunkUnload");
+-            this.doTickPending = new CustomTimingsHandler("** " + name + "doTickPending");
+-            this.doTickTiles = new CustomTimingsHandler("** " + name + "doTickTiles");
+-            this.doChunkMap = new CustomTimingsHandler("** " + name + "doChunkMap");
+-            this.doSounds = new CustomTimingsHandler("** " + name + "doSounds");
+-            this.entityTick = new CustomTimingsHandler("** " + name + "entityTick");
+-            this.tileEntityTick = new CustomTimingsHandler("** " + name + "tileEntityTick");
+-            this.tileEntityPending = new CustomTimingsHandler("** " + name + "tileEntityPending");
+-
+-            this.syncChunkLoadTimer = new CustomTimingsHandler("** " + name + "syncChunkLoad");
+-            this.syncChunkLoadStructuresTimer = new CustomTimingsHandler("** " + name + "chunkLoad - Structures");
+-            this.syncChunkLoadEntitiesTimer = new CustomTimingsHandler("** " + name + "chunkLoad - Entities");
+-            this.syncChunkLoadTileEntitiesTimer = new CustomTimingsHandler("** " + name + "chunkLoad - TileEntities");
+-            this.syncChunkLoadTileTicksTimer = new CustomTimingsHandler("** " + name + "chunkLoad - TileTicks");
+-            this.syncChunkLoadPostTimer = new CustomTimingsHandler("** " + name + "chunkLoad - Post");
+-
+-
+-            this.tracker = new CustomTimingsHandler(name + "tracker");
+-            this.doTick = new CustomTimingsHandler(name + "doTick");
+-            this.tickEntities = new CustomTimingsHandler(name + "tickEntities");
+-        }
+-    }
+-}
 diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
 index 06d071d43337f2b919144a8db28684f4a3c826cf..457506210f041291be6bcdef7286d0860cb85946 100644
 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java