--- a/net/minecraft/world/level/saveddata/maps/WorldMap.java
+++ b/net/minecraft/world/level/saveddata/maps/WorldMap.java
@@ -31,6 +31,16 @@
 import net.minecraft.world.level.saveddata.PersistentBase;
 import org.slf4j.Logger;
 
+// CraftBukkit start
+import java.util.UUID;
+import net.minecraft.nbt.NBTBase;
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.CraftServer;
+import org.bukkit.craftbukkit.CraftWorld;
+import org.bukkit.craftbukkit.map.CraftMapView;
+import org.bukkit.craftbukkit.util.CraftChatMessage;
+// CraftBukkit end
+
 public class WorldMap extends PersistentBase {
 
     private static final Logger LOGGER = LogUtils.getLogger();
@@ -53,6 +63,13 @@
     private final Map<String, WorldMapFrame> frameMarkers = Maps.newHashMap();
     private int trackedDecorationCount;
 
+    // CraftBukkit start
+    public final CraftMapView mapView;
+    private CraftServer server;
+    public UUID uniqueId = null;
+    public String id;
+    // CraftBukkit end
+
     private WorldMap(int i, int j, byte b0, boolean flag, boolean flag1, boolean flag2, ResourceKey<World> resourcekey) {
         this.scale = b0;
         this.centerX = i;
@@ -62,6 +79,10 @@
         this.unlimitedTracking = flag1;
         this.locked = flag2;
         this.setDirty();
+        // CraftBukkit start
+        mapView = new CraftMapView(this);
+        server = (CraftServer) org.bukkit.Bukkit.getServer();
+        // CraftBukkit end
     }
 
     public static WorldMap createFresh(double d0, double d1, byte b0, boolean flag, boolean flag1, ResourceKey<World> resourcekey) {
@@ -79,12 +100,30 @@
     }
 
     public static WorldMap load(NBTTagCompound nbttagcompound) {
-        DataResult dataresult = DimensionManager.parseLegacy(new Dynamic(DynamicOpsNBT.INSTANCE, nbttagcompound.get("dimension")));
+        DataResult<ResourceKey<World>> dataresult = DimensionManager.parseLegacy(new Dynamic(DynamicOpsNBT.INSTANCE, nbttagcompound.get("dimension"))); // CraftBukkit - decompile error
         Logger logger = WorldMap.LOGGER;
 
         Objects.requireNonNull(logger);
-        ResourceKey<World> resourcekey = (ResourceKey) dataresult.resultOrPartial(logger::error).orElseThrow(() -> {
-            return new IllegalArgumentException("Invalid map dimension: " + nbttagcompound.get("dimension"));
+        // CraftBukkit start
+        ResourceKey<World> resourcekey = dataresult.resultOrPartial(logger::error).orElseGet(() -> {
+            long least = nbttagcompound.getLong("UUIDLeast");
+            long most = nbttagcompound.getLong("UUIDMost");
+
+            if (least != 0L && most != 0L) {
+                UUID uniqueId = new UUID(most, least);
+
+                CraftWorld world = (CraftWorld) Bukkit.getWorld(uniqueId);
+                // Check if the stored world details are correct.
+                if (world == null) {
+                    /* All Maps which do not have their valid world loaded are set to a dimension which hopefully won't be reached.
+                       This is to prevent them being corrupted with the wrong map data. */
+                    // PAIL: Use Vanilla exception handling for now
+                } else {
+                    return world.getHandle().dimension();
+                }
+            }
+            throw new IllegalArgumentException("Invalid map dimension: " + nbttagcompound.get("dimension"));
+            // CraftBukkit end
         });
         int i = nbttagcompound.getInt("xCenter");
         int j = nbttagcompound.getInt("zCenter");
@@ -122,13 +161,32 @@
 
     @Override
     public NBTTagCompound save(NBTTagCompound nbttagcompound) {
-        DataResult dataresult = MinecraftKey.CODEC.encodeStart(DynamicOpsNBT.INSTANCE, this.dimension.location());
+        DataResult<NBTBase> dataresult = MinecraftKey.CODEC.encodeStart(DynamicOpsNBT.INSTANCE, this.dimension.location()); // CraftBukkit - decompile error
         Logger logger = WorldMap.LOGGER;
 
         Objects.requireNonNull(logger);
         dataresult.resultOrPartial(logger::error).ifPresent((nbtbase) -> {
             nbttagcompound.put("dimension", nbtbase);
         });
+        // CraftBukkit start
+        if (true) {
+            if (this.uniqueId == null) {
+                for (org.bukkit.World world : server.getWorlds()) {
+                    CraftWorld cWorld = (CraftWorld) world;
+                    if (cWorld.getHandle().dimension() == this.dimension) {
+                        this.uniqueId = cWorld.getUID();
+                        break;
+                    }
+                }
+            }
+            /* Perform a second check to see if a matching world was found, this is a necessary
+               change incase Maps are forcefully unlinked from a World and lack a UID.*/
+            if (this.uniqueId != null) {
+                nbttagcompound.putLong("UUIDLeast", this.uniqueId.getLeastSignificantBits());
+                nbttagcompound.putLong("UUIDMost", this.uniqueId.getMostSignificantBits());
+            }
+        }
+        // CraftBukkit end
         nbttagcompound.putInt("xCenter", this.centerX);
         nbttagcompound.putInt("zCenter", this.centerZ);
         nbttagcompound.putByte("scale", this.scale);
@@ -503,7 +561,7 @@
             this.player = entityhuman;
         }
 
-        private WorldMap.b createPatch() {
+        private WorldMap.b createPatch(byte[] buffer) { // CraftBukkit
             int i = this.minDirtyX;
             int j = this.minDirtyY;
             int k = this.maxDirtyX + 1 - this.minDirtyX;
@@ -512,7 +570,7 @@
 
             for (int i1 = 0; i1 < k; ++i1) {
                 for (int j1 = 0; j1 < l; ++j1) {
-                    abyte[i1 + j1 * k] = WorldMap.this.colors[i + i1 + (j + j1) * 128];
+                    abyte[i1 + j1 * k] = buffer[i + i1 + (j + j1) * 128]; // CraftBukkit
                 }
             }
 
@@ -522,19 +580,29 @@
         @Nullable
         Packet<?> nextUpdatePacket(int i) {
             WorldMap.b worldmap_b;
+            org.bukkit.craftbukkit.map.RenderData render = WorldMap.this.mapView.render((org.bukkit.craftbukkit.entity.CraftPlayer) this.player.getBukkitEntity()); // CraftBukkit
 
             if (this.dirtyData) {
                 this.dirtyData = false;
-                worldmap_b = this.createPatch();
+                worldmap_b = this.createPatch(render.buffer); // CraftBukkit
             } else {
                 worldmap_b = null;
             }
 
             Collection collection;
 
-            if (this.dirtyDecorations && this.tick++ % 5 == 0) {
+            if ((true || this.dirtyDecorations) && this.tick++ % 5 == 0) { // CraftBukkit - custom maps don't update this yet
                 this.dirtyDecorations = false;
-                collection = WorldMap.this.decorations.values();
+                // CraftBukkit start
+                java.util.Collection<MapIcon> icons = new java.util.ArrayList<MapIcon>();
+
+                for (org.bukkit.map.MapCursor cursor : render.cursors) {
+                    if (cursor.isVisible()) {
+                        icons.add(new MapIcon(MapIcon.Type.byIcon(cursor.getRawType()), cursor.getX(), cursor.getY(), cursor.getDirection(), CraftChatMessage.fromStringOrNull(cursor.getCaption())));
+                    }
+                }
+                collection = icons;
+                // CraftBukkit end
             } else {
                 collection = null;
             }
