--- a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
+++ b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
@@ -3,6 +3,7 @@
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.mojang.logging.LogUtils;
+import com.mojang.serialization.DataResult;
 import com.mojang.serialization.Dynamic;
 import io.netty.buffer.ByteBuf;
 import java.util.Collection;
@@ -20,6 +21,8 @@
 import net.minecraft.nbt.CompoundTag;
 import net.minecraft.nbt.ListTag;
 import net.minecraft.nbt.NbtOps;
+import net.minecraft.nbt.NumericTag;
+import net.minecraft.nbt.StringTag;
 import net.minecraft.nbt.Tag;
 import net.minecraft.network.FriendlyByteBuf;
 import net.minecraft.network.chat.Component;
@@ -43,7 +46,19 @@
 import net.minecraft.world.level.saveddata.SavedData;
 import org.slf4j.Logger;
 
+// CraftBukkit start
+import io.papermc.paper.adventure.PaperAdventure; // Paper
+import java.util.UUID;
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.CraftServer;
+import org.bukkit.craftbukkit.CraftWorld;
+import org.bukkit.craftbukkit.map.CraftMapCursor;
+import org.bukkit.craftbukkit.map.CraftMapView;
+import org.bukkit.craftbukkit.util.CraftChatMessage;
+// CraftBukkit end
+
 public class MapItemSavedData extends SavedData {
+
     private static final Logger LOGGER = LogUtils.getLogger();
     private static final int MAP_SIZE = 128;
     private static final int HALF_MAP_SIZE = 64;
@@ -64,6 +79,14 @@
     public final Map<String, MapDecoration> decorations = Maps.newLinkedHashMap();
     private final Map<String, MapFrame> frameMarkers = Maps.newHashMap();
     private int trackedDecorationCount;
+    private org.bukkit.craftbukkit.map.RenderData vanillaRender = new org.bukkit.craftbukkit.map.RenderData(); // Paper
+
+    // CraftBukkit start
+    public final CraftMapView mapView;
+    private CraftServer server;
+    public UUID uniqueId = null;
+    public MapId id;
+    // CraftBukkit end
 
     public static SavedData.Factory<MapItemSavedData> factory() {
         return new SavedData.Factory<>(() -> {
@@ -71,9 +94,7 @@
         }, MapItemSavedData::load, DataFixTypes.SAVED_DATA_MAP_DATA);
     }
 
-    private MapItemSavedData(
-        int centerX, int centerZ, byte scale, boolean showDecorations, boolean unlimitedTracking, boolean locked, ResourceKey<Level> dimension
-    ) {
+    private MapItemSavedData(int centerX, int centerZ, byte scale, boolean showDecorations, boolean unlimitedTracking, boolean locked, ResourceKey<Level> dimension) {
         this.scale = scale;
         this.centerX = centerX;
         this.centerZ = centerZ;
@@ -82,17 +103,21 @@
         this.unlimitedTracking = unlimitedTracking;
         this.locked = locked;
         this.setDirty();
+        // CraftBukkit start
+        this.mapView = new CraftMapView(this);
+        this.server = (CraftServer) org.bukkit.Bukkit.getServer();
+        this.vanillaRender.buffer = colors; // Paper
+        // CraftBukkit end
     }
 
-    public static MapItemSavedData createFresh(
-        double centerX, double centerZ, byte scale, boolean showDecorations, boolean unlimitedTracking, ResourceKey<Level> dimension
-    ) {
+    public static MapItemSavedData createFresh(double centerX, double centerZ, byte scale, boolean showDecorations, boolean unlimitedTracking, ResourceKey<Level> dimension) {
         int i = 128 * (1 << scale);
-        int j = Mth.floor((centerX + 64.0) / (double)i);
-        int k = Mth.floor((centerZ + 64.0) / (double)i);
+        int j = Mth.floor((centerX + 64.0D) / (double) i);
+        int k = Mth.floor((centerZ + 64.0D) / (double) i);
         int l = j * i + i / 2 - 64;
-        int m = k * i + i / 2 - 64;
-        return new MapItemSavedData(l, m, scale, showDecorations, unlimitedTracking, false, dimension);
+        int i1 = k * i + i / 2 - 64;
+
+        return new MapItemSavedData(l, i1, scale, showDecorations, unlimitedTracking, false, dimension);
     }
 
     public static MapItemSavedData createForClient(byte scale, boolean locked, ResourceKey<Level> dimension) {
@@ -100,66 +125,120 @@
     }
 
     public static MapItemSavedData load(CompoundTag nbt, HolderLookup.Provider registryLookup) {
-        ResourceKey<Level> resourceKey = DimensionType.parseLegacy(new Dynamic<>(NbtOps.INSTANCE, nbt.get("dimension")))
-            .resultOrPartial(LOGGER::error)
-            .orElseThrow(() -> new IllegalArgumentException("Invalid map dimension: " + nbt.get("dimension")));
+        // Paper start - fix "Not a string" spam
+        Tag dimension = nbt.get("dimension");
+        if (dimension instanceof NumericTag && ((NumericTag) dimension).getAsInt() >= CraftWorld.CUSTOM_DIMENSION_OFFSET) {
+            long least = nbt.getLong("UUIDLeast");
+            long most = nbt.getLong("UUIDMost");
+
+            if (least != 0L && most != 0L) {
+                UUID uuid = new UUID(most, least);
+                CraftWorld world = (CraftWorld) Bukkit.getWorld(uuid);
+                if (world != null) {
+                    dimension = StringTag.valueOf("minecraft:" + world.getName().toLowerCase(java.util.Locale.ENGLISH));
+                } else {
+                    dimension = StringTag.valueOf("bukkit:_invalidworld_");
+                }
+            } else {
+                dimension = StringTag.valueOf("bukkit:_invalidworld_");
+            }
+        }
+        DataResult<ResourceKey<Level>> dataresult = DimensionType.parseLegacy(new Dynamic(NbtOps.INSTANCE, dimension)); // CraftBukkit - decompile error
+        // Paper end - fix "Not a string" spam
+        Logger logger = MapItemSavedData.LOGGER;
+
+        Objects.requireNonNull(logger);
+        // CraftBukkit start
+        ResourceKey<Level> resourcekey = (ResourceKey) dataresult.resultOrPartial(logger::error).orElseGet(() -> {
+            long least = nbt.getLong("UUIDLeast");
+            long most = nbt.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: " + String.valueOf(nbt.get("dimension")));
+            // CraftBukkit end
+        });
         int i = nbt.getInt("xCenter");
         int j = nbt.getInt("zCenter");
-        byte b = (byte)Mth.clamp(nbt.getByte("scale"), 0, 4);
-        boolean bl = !nbt.contains("trackingPosition", 1) || nbt.getBoolean("trackingPosition");
-        boolean bl2 = nbt.getBoolean("unlimitedTracking");
-        boolean bl3 = nbt.getBoolean("locked");
-        MapItemSavedData mapItemSavedData = new MapItemSavedData(i, j, b, bl, bl2, bl3, resourceKey);
-        byte[] bs = nbt.getByteArray("colors");
-        if (bs.length == 16384) {
-            mapItemSavedData.colors = bs;
+        byte b0 = (byte) Mth.clamp(nbt.getByte("scale"), 0, 4);
+        boolean flag = !nbt.contains("trackingPosition", 1) || nbt.getBoolean("trackingPosition");
+        boolean flag1 = nbt.getBoolean("unlimitedTracking");
+        boolean flag2 = nbt.getBoolean("locked");
+        MapItemSavedData worldmap = new MapItemSavedData(i, j, b0, flag, flag1, flag2, resourcekey);
+        byte[] abyte = nbt.getByteArray("colors");
+
+        if (abyte.length == 16384) {
+            worldmap.colors = abyte;
         }
+        worldmap.vanillaRender.buffer = abyte; // Paper
 
-        RegistryOps<Tag> registryOps = registryLookup.createSerializationContext(NbtOps.INSTANCE);
+        RegistryOps<Tag> registryops = registryLookup.createSerializationContext(NbtOps.INSTANCE);
+        List<MapBanner> list = (List) MapBanner.LIST_CODEC.parse(registryops, nbt.get("banners")).resultOrPartial((s) -> {
+            MapItemSavedData.LOGGER.warn("Failed to parse map banner: '{}'", s);
+        }).orElse(List.of());
+        Iterator iterator = list.iterator();
 
-        for (MapBanner mapBanner : MapBanner.LIST_CODEC
-            .parse(registryOps, nbt.get("banners"))
-            .resultOrPartial(banner -> LOGGER.warn("Failed to parse map banner: '{}'", banner))
-            .orElse(List.of())) {
-            mapItemSavedData.bannerMarkers.put(mapBanner.getId(), mapBanner);
-            mapItemSavedData.addDecoration(
-                mapBanner.getDecoration(),
-                null,
-                mapBanner.getId(),
-                (double)mapBanner.pos().getX(),
-                (double)mapBanner.pos().getZ(),
-                180.0,
-                mapBanner.name().orElse(null)
-            );
+        while (iterator.hasNext()) {
+            MapBanner mapiconbanner = (MapBanner) iterator.next();
+
+            worldmap.bannerMarkers.put(mapiconbanner.getId(), mapiconbanner);
+            // CraftBukkit - decompile error
+            worldmap.addDecoration(mapiconbanner.getDecoration(), (LevelAccessor) null, mapiconbanner.getId(), (double) mapiconbanner.pos().getX(), (double) mapiconbanner.pos().getZ(), 180.0D, (Component) mapiconbanner.name().orElse(null));
         }
 
-        ListTag listTag = nbt.getList("frames", 10);
+        ListTag nbttaglist = nbt.getList("frames", 10);
 
-        for (int k = 0; k < listTag.size(); k++) {
-            MapFrame mapFrame = MapFrame.load(listTag.getCompound(k));
-            if (mapFrame != null) {
-                mapItemSavedData.frameMarkers.put(mapFrame.getId(), mapFrame);
-                mapItemSavedData.addDecoration(
-                    MapDecorationTypes.FRAME,
-                    null,
-                    getFrameKey(mapFrame.getEntityId()),
-                    (double)mapFrame.getPos().getX(),
-                    (double)mapFrame.getPos().getZ(),
-                    (double)mapFrame.getRotation(),
-                    null
-                );
+        for (int k = 0; k < nbttaglist.size(); ++k) {
+            MapFrame worldmapframe = MapFrame.load(nbttaglist.getCompound(k));
+
+            if (worldmapframe != null) {
+                worldmap.frameMarkers.put(worldmapframe.getId(), worldmapframe);
+                worldmap.addDecoration(MapDecorationTypes.FRAME, (LevelAccessor) null, MapItemSavedData.getFrameKey(worldmapframe.getEntityId()), (double) worldmapframe.getPos().getX(), (double) worldmapframe.getPos().getZ(), (double) worldmapframe.getRotation(), (Component) null);
             }
         }
 
-        return mapItemSavedData;
+        return worldmap;
     }
 
     @Override
     public CompoundTag save(CompoundTag nbt, HolderLookup.Provider registryLookup) {
-        ResourceLocation.CODEC
-            .encodeStart(NbtOps.INSTANCE, this.dimension.location())
-            .resultOrPartial(LOGGER::error)
-            .ifPresent(tag -> nbt.put("dimension", tag));
+        DataResult<Tag> dataresult = ResourceLocation.CODEC.encodeStart(NbtOps.INSTANCE, this.dimension.location()); // CraftBukkit - decompile error
+        Logger logger = MapItemSavedData.LOGGER;
+
+        Objects.requireNonNull(logger);
+        dataresult.resultOrPartial(logger::error).ifPresent((nbtbase) -> {
+            nbt.put("dimension", nbtbase);
+        });
+        // CraftBukkit start
+        if (true) {
+            if (this.uniqueId == null) {
+                for (org.bukkit.World world : this.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) {
+                nbt.putLong("UUIDLeast", this.uniqueId.getLeastSignificantBits());
+                nbt.putLong("UUIDMost", this.uniqueId.getMostSignificantBits());
+            }
+        }
+        // CraftBukkit end
         nbt.putInt("xCenter", this.centerX);
         nbt.putInt("zCenter", this.centerZ);
         nbt.putByte("scale", this.scale);
@@ -167,139 +246,142 @@
         nbt.putBoolean("trackingPosition", this.trackingPosition);
         nbt.putBoolean("unlimitedTracking", this.unlimitedTracking);
         nbt.putBoolean("locked", this.locked);
-        RegistryOps<Tag> registryOps = registryLookup.createSerializationContext(NbtOps.INSTANCE);
-        nbt.put("banners", MapBanner.LIST_CODEC.encodeStart(registryOps, List.copyOf(this.bannerMarkers.values())).getOrThrow());
-        ListTag listTag = new ListTag();
+        RegistryOps<Tag> registryops = registryLookup.createSerializationContext(NbtOps.INSTANCE);
 
-        for (MapFrame mapFrame : this.frameMarkers.values()) {
-            listTag.add(mapFrame.save());
+        nbt.put("banners", (Tag) MapBanner.LIST_CODEC.encodeStart(registryops, List.copyOf(this.bannerMarkers.values())).getOrThrow());
+        ListTag nbttaglist = new ListTag();
+        Iterator iterator = this.frameMarkers.values().iterator();
+
+        while (iterator.hasNext()) {
+            MapFrame worldmapframe = (MapFrame) iterator.next();
+
+            nbttaglist.add(worldmapframe.save());
         }
 
-        nbt.put("frames", listTag);
+        nbt.put("frames", nbttaglist);
         return nbt;
     }
 
     public MapItemSavedData locked() {
-        MapItemSavedData mapItemSavedData = new MapItemSavedData(
-            this.centerX, this.centerZ, this.scale, this.trackingPosition, this.unlimitedTracking, true, this.dimension
-        );
-        mapItemSavedData.bannerMarkers.putAll(this.bannerMarkers);
-        mapItemSavedData.decorations.putAll(this.decorations);
-        mapItemSavedData.trackedDecorationCount = this.trackedDecorationCount;
-        System.arraycopy(this.colors, 0, mapItemSavedData.colors, 0, this.colors.length);
-        mapItemSavedData.setDirty();
-        return mapItemSavedData;
+        MapItemSavedData worldmap = new MapItemSavedData(this.centerX, this.centerZ, this.scale, this.trackingPosition, this.unlimitedTracking, true, this.dimension);
+
+        worldmap.bannerMarkers.putAll(this.bannerMarkers);
+        worldmap.decorations.putAll(this.decorations);
+        worldmap.trackedDecorationCount = this.trackedDecorationCount;
+        System.arraycopy(this.colors, 0, worldmap.colors, 0, this.colors.length);
+        worldmap.setDirty();
+        return worldmap;
     }
 
     public MapItemSavedData scaled() {
-        return createFresh(
-            (double)this.centerX, (double)this.centerZ, (byte)Mth.clamp(this.scale + 1, 0, 4), this.trackingPosition, this.unlimitedTracking, this.dimension
-        );
+        return MapItemSavedData.createFresh((double) this.centerX, (double) this.centerZ, (byte) Mth.clamp(this.scale + 1, 0, 4), this.trackingPosition, this.unlimitedTracking, this.dimension);
     }
 
     private static Predicate<ItemStack> mapMatcher(ItemStack stack) {
-        MapId mapId = stack.get(DataComponents.MAP_ID);
-        return other -> other == stack || other.is(stack.getItem()) && Objects.equals(mapId, other.get(DataComponents.MAP_ID));
+        MapId mapid = (MapId) stack.get(DataComponents.MAP_ID);
+
+        return (itemstack1) -> {
+            return itemstack1 == stack ? true : itemstack1.is(stack.getItem()) && Objects.equals(mapid, itemstack1.get(DataComponents.MAP_ID));
+        };
     }
 
     public void tickCarriedBy(Player player, ItemStack stack) {
         if (!this.carriedByPlayers.containsKey(player)) {
-            MapItemSavedData.HoldingPlayer holdingPlayer = new MapItemSavedData.HoldingPlayer(player);
-            this.carriedByPlayers.put(player, holdingPlayer);
-            this.carriedBy.add(holdingPlayer);
+            MapItemSavedData.HoldingPlayer worldmap_worldmaphumantracker = new MapItemSavedData.HoldingPlayer(player);
+
+            this.carriedByPlayers.put(player, worldmap_worldmaphumantracker);
+            this.carriedBy.add(worldmap_worldmaphumantracker);
         }
 
-        Predicate<ItemStack> predicate = mapMatcher(stack);
+        Predicate<ItemStack> predicate = MapItemSavedData.mapMatcher(stack);
+
         if (!player.getInventory().contains(predicate)) {
             this.removeDecoration(player.getName().getString());
         }
 
-        for (int i = 0; i < this.carriedBy.size(); i++) {
-            MapItemSavedData.HoldingPlayer holdingPlayer2 = this.carriedBy.get(i);
-            String string = holdingPlayer2.player.getName().getString();
-            if (!holdingPlayer2.player.isRemoved() && (holdingPlayer2.player.getInventory().contains(predicate) || stack.isFramed())) {
-                if (!stack.isFramed() && holdingPlayer2.player.level().dimension() == this.dimension && this.trackingPosition) {
-                    this.addDecoration(
-                        MapDecorationTypes.PLAYER,
-                        holdingPlayer2.player.level(),
-                        string,
-                        holdingPlayer2.player.getX(),
-                        holdingPlayer2.player.getZ(),
-                        (double)holdingPlayer2.player.getYRot(),
-                        null
-                    );
+        for (int i = 0; i < this.carriedBy.size(); ++i) {
+            MapItemSavedData.HoldingPlayer worldmap_worldmaphumantracker1 = (MapItemSavedData.HoldingPlayer) this.carriedBy.get(i);
+            String s = worldmap_worldmaphumantracker1.player.getName().getString();
+
+            if (!worldmap_worldmaphumantracker1.player.isRemoved() && (worldmap_worldmaphumantracker1.player.getInventory().contains(predicate) || stack.isFramed())) {
+                if (!stack.isFramed() && worldmap_worldmaphumantracker1.player.level().dimension() == this.dimension && this.trackingPosition) {
+                    this.addDecoration(MapDecorationTypes.PLAYER, worldmap_worldmaphumantracker1.player.level(), s, worldmap_worldmaphumantracker1.player.getX(), worldmap_worldmaphumantracker1.player.getZ(), (double) worldmap_worldmaphumantracker1.player.getYRot(), (Component) null);
                 }
             } else {
-                this.carriedByPlayers.remove(holdingPlayer2.player);
-                this.carriedBy.remove(holdingPlayer2);
-                this.removeDecoration(string);
+                this.carriedByPlayers.remove(worldmap_worldmaphumantracker1.player);
+                this.carriedBy.remove(worldmap_worldmaphumantracker1);
+                this.removeDecoration(s);
             }
         }
 
         if (stack.isFramed() && this.trackingPosition) {
-            ItemFrame itemFrame = stack.getFrame();
-            BlockPos blockPos = itemFrame.getPos();
-            MapFrame mapFrame = this.frameMarkers.get(MapFrame.frameId(blockPos));
-            if (mapFrame != null && itemFrame.getId() != mapFrame.getEntityId() && this.frameMarkers.containsKey(mapFrame.getId())) {
-                this.removeDecoration(getFrameKey(mapFrame.getEntityId()));
+            ItemFrame entityitemframe = stack.getFrame();
+            BlockPos blockposition = entityitemframe.getPos();
+            MapFrame worldmapframe = (MapFrame) this.frameMarkers.get(MapFrame.frameId(blockposition));
+
+            if (worldmapframe != null && entityitemframe.getId() != worldmapframe.getEntityId() && this.frameMarkers.containsKey(worldmapframe.getId())) {
+                this.removeDecoration(MapItemSavedData.getFrameKey(worldmapframe.getEntityId()));
             }
 
-            MapFrame mapFrame2 = new MapFrame(blockPos, itemFrame.getDirection().get2DDataValue() * 90, itemFrame.getId());
-            this.addDecoration(
-                MapDecorationTypes.FRAME,
-                player.level(),
-                getFrameKey(itemFrame.getId()),
-                (double)blockPos.getX(),
-                (double)blockPos.getZ(),
-                (double)(itemFrame.getDirection().get2DDataValue() * 90),
-                null
-            );
-            this.frameMarkers.put(mapFrame2.getId(), mapFrame2);
+            MapFrame worldmapframe1 = new MapFrame(blockposition, entityitemframe.getDirection().get2DDataValue() * 90, entityitemframe.getId());
+
+            if (this.decorations.size() < player.level().paperConfig().maps.itemFrameCursorLimit) { // Paper - Limit item frame cursors on maps
+            this.addDecoration(MapDecorationTypes.FRAME, player.level(), MapItemSavedData.getFrameKey(entityitemframe.getId()), (double) blockposition.getX(), (double) blockposition.getZ(), (double) (entityitemframe.getDirection().get2DDataValue() * 90), (Component) null);
+            this.frameMarkers.put(worldmapframe1.getId(), worldmapframe1);
+            } // Paper - Limit item frame cursors on maps
         }
 
-        MapDecorations mapDecorations = stack.getOrDefault(DataComponents.MAP_DECORATIONS, MapDecorations.EMPTY);
-        if (!this.decorations.keySet().containsAll(mapDecorations.decorations().keySet())) {
-            mapDecorations.decorations().forEach((id, decoration) -> {
-                if (!this.decorations.containsKey(id)) {
-                    this.addDecoration(decoration.type(), player.level(), id, decoration.x(), decoration.z(), (double)decoration.rotation(), null);
+        MapDecorations mapdecorations = (MapDecorations) stack.getOrDefault(DataComponents.MAP_DECORATIONS, MapDecorations.EMPTY);
+
+        if (!this.decorations.keySet().containsAll(mapdecorations.decorations().keySet())) {
+            mapdecorations.decorations().forEach((s1, mapdecorations_a) -> {
+                if (!this.decorations.containsKey(s1)) {
+                    this.addDecoration(mapdecorations_a.type(), player.level(), s1, mapdecorations_a.x(), mapdecorations_a.z(), (double) mapdecorations_a.rotation(), (Component) null);
                 }
+
             });
         }
+
     }
 
     private void removeDecoration(String id) {
-        MapDecoration mapDecoration = this.decorations.remove(id);
-        if (mapDecoration != null && mapDecoration.type().value().trackCount()) {
-            this.trackedDecorationCount--;
+        MapDecoration mapicon = (MapDecoration) this.decorations.remove(id);
+
+        if (mapicon != null && ((MapDecorationType) mapicon.type().value()).trackCount()) {
+            --this.trackedDecorationCount;
         }
 
         this.setDecorationsDirty();
     }
 
     public static void addTargetDecoration(ItemStack stack, BlockPos pos, String id, Holder<MapDecorationType> decorationType) {
-        MapDecorations.Entry entry = new MapDecorations.Entry(decorationType, (double)pos.getX(), (double)pos.getZ(), 180.0F);
-        stack.update(DataComponents.MAP_DECORATIONS, MapDecorations.EMPTY, decorations -> decorations.withDecoration(id, entry));
-        if (decorationType.value().hasMapColor()) {
-            stack.set(DataComponents.MAP_COLOR, new MapItemColor(decorationType.value().mapColor()));
+        MapDecorations.Entry mapdecorations_a = new MapDecorations.Entry(decorationType, (double) pos.getX(), (double) pos.getZ(), 180.0F);
+
+        stack.update(DataComponents.MAP_DECORATIONS, MapDecorations.EMPTY, (mapdecorations) -> {
+            return mapdecorations.withDecoration(id, mapdecorations_a);
+        });
+        if (((MapDecorationType) decorationType.value()).hasMapColor()) {
+            stack.set(DataComponents.MAP_COLOR, new MapItemColor(((MapDecorationType) decorationType.value()).mapColor()));
         }
+
     }
 
-    private void addDecoration(
-        Holder<MapDecorationType> type, @Nullable LevelAccessor world, String key, double x, double z, double rotation, @Nullable Component text
-    ) {
+    private void addDecoration(Holder<MapDecorationType> type, @Nullable LevelAccessor world, String key, double x, double z, double rotation, @Nullable Component text) {
         int i = 1 << this.scale;
-        float f = (float)(x - (double)this.centerX) / (float)i;
-        float g = (float)(z - (double)this.centerZ) / (float)i;
-        byte b = (byte)((int)((double)(f * 2.0F) + 0.5));
-        byte c = (byte)((int)((double)(g * 2.0F) + 0.5));
-        int j = 63;
-        byte d;
-        if (f >= -63.0F && g >= -63.0F && f <= 63.0F && g <= 63.0F) {
-            rotation += rotation < 0.0 ? -8.0 : 8.0;
-            d = (byte)((int)(rotation * 16.0 / 360.0));
+        float f = (float) (x - (double) this.centerX) / (float) i;
+        float f1 = (float) (z - (double) this.centerZ) / (float) i;
+        byte b0 = (byte) ((int) ((double) (f * 2.0F) + 0.5D));
+        byte b1 = (byte) ((int) ((double) (f1 * 2.0F) + 0.5D));
+        boolean flag = true;
+        byte b2;
+
+        if (f >= -63.0F && f1 >= -63.0F && f <= 63.0F && f1 <= 63.0F) {
+            rotation += rotation < 0.0D ? -8.0D : 8.0D;
+            b2 = (byte) ((int) (rotation * 16.0D / 360.0D));
             if (this.dimension == Level.NETHER && world != null) {
-                int k = (int)(world.getLevelData().getDayTime() / 10L);
-                d = (byte)(k * k * 34187121 + k * 121 >> 15 & 15);
+                int j = (int) (world.getLevelData().getDayTime() / 10L);
+
+                b2 = (byte) (j * j * 34187121 + j * 121 >> 15 & 15);
             }
         } else {
             if (!type.is(MapDecorationTypes.PLAYER)) {
@@ -307,8 +389,9 @@
                 return;
             }
 
-            int l = 320;
-            if (Math.abs(f) < 320.0F && Math.abs(g) < 320.0F) {
+            boolean flag1 = true;
+
+            if (Math.abs(f) < 320.0F && Math.abs(f1) < 320.0F) {
                 type = MapDecorationTypes.PLAYER_OFF_MAP;
             } else {
                 if (!this.unlimitedTracking) {
@@ -319,51 +402,58 @@
                 type = MapDecorationTypes.PLAYER_OFF_LIMITS;
             }
 
-            d = 0;
+            b2 = 0;
             if (f <= -63.0F) {
-                b = -128;
+                b0 = Byte.MIN_VALUE;
             }
 
-            if (g <= -63.0F) {
-                c = -128;
+            if (f1 <= -63.0F) {
+                b1 = Byte.MIN_VALUE;
             }
 
             if (f >= 63.0F) {
-                b = 127;
+                b0 = 127;
             }
 
-            if (g >= 63.0F) {
-                c = 127;
+            if (f1 >= 63.0F) {
+                b1 = 127;
             }
         }
 
-        MapDecoration mapDecoration = new MapDecoration(type, b, c, d, Optional.ofNullable(text));
-        MapDecoration mapDecoration2 = this.decorations.put(key, mapDecoration);
-        if (!mapDecoration.equals(mapDecoration2)) {
-            if (mapDecoration2 != null && mapDecoration2.type().value().trackCount()) {
-                this.trackedDecorationCount--;
+        MapDecoration mapicon = new MapDecoration(type, b0, b1, b2, Optional.ofNullable(text));
+        MapDecoration mapicon1 = (MapDecoration) this.decorations.put(key, mapicon);
+
+        if (!mapicon.equals(mapicon1)) {
+            if (mapicon1 != null && ((MapDecorationType) mapicon1.type().value()).trackCount()) {
+                --this.trackedDecorationCount;
             }
 
-            if (type.value().trackCount()) {
-                this.trackedDecorationCount++;
+            if (((MapDecorationType) type.value()).trackCount()) {
+                ++this.trackedDecorationCount;
             }
 
             this.setDecorationsDirty();
         }
+
     }
 
     @Nullable
     public Packet<?> getUpdatePacket(MapId mapId, Player player) {
-        MapItemSavedData.HoldingPlayer holdingPlayer = this.carriedByPlayers.get(player);
-        return holdingPlayer == null ? null : holdingPlayer.nextUpdatePacket(mapId);
+        MapItemSavedData.HoldingPlayer worldmap_worldmaphumantracker = (MapItemSavedData.HoldingPlayer) this.carriedByPlayers.get(player);
+
+        return worldmap_worldmaphumantracker == null ? null : worldmap_worldmaphumantracker.nextUpdatePacket(mapId);
     }
 
     public void setColorsDirty(int x, int z) {
         this.setDirty();
+        Iterator iterator = this.carriedBy.iterator();
 
-        for (MapItemSavedData.HoldingPlayer holdingPlayer : this.carriedBy) {
-            holdingPlayer.markColorsDirty(x, z);
+        while (iterator.hasNext()) {
+            MapItemSavedData.HoldingPlayer worldmap_worldmaphumantracker = (MapItemSavedData.HoldingPlayer) iterator.next();
+
+            worldmap_worldmaphumantracker.markColorsDirty(x, z);
         }
+
     }
 
     public void setDecorationsDirty() {
@@ -372,37 +462,40 @@
     }
 
     public MapItemSavedData.HoldingPlayer getHoldingPlayer(Player player) {
-        MapItemSavedData.HoldingPlayer holdingPlayer = this.carriedByPlayers.get(player);
-        if (holdingPlayer == null) {
-            holdingPlayer = new MapItemSavedData.HoldingPlayer(player);
-            this.carriedByPlayers.put(player, holdingPlayer);
-            this.carriedBy.add(holdingPlayer);
+        MapItemSavedData.HoldingPlayer worldmap_worldmaphumantracker = (MapItemSavedData.HoldingPlayer) this.carriedByPlayers.get(player);
+
+        if (worldmap_worldmaphumantracker == null) {
+            worldmap_worldmaphumantracker = new MapItemSavedData.HoldingPlayer(player);
+            this.carriedByPlayers.put(player, worldmap_worldmaphumantracker);
+            this.carriedBy.add(worldmap_worldmaphumantracker);
         }
 
-        return holdingPlayer;
+        return worldmap_worldmaphumantracker;
     }
 
     public boolean toggleBanner(LevelAccessor world, BlockPos pos) {
-        double d = (double)pos.getX() + 0.5;
-        double e = (double)pos.getZ() + 0.5;
+        double d0 = (double) pos.getX() + 0.5D;
+        double d1 = (double) pos.getZ() + 0.5D;
         int i = 1 << this.scale;
-        double f = (d - (double)this.centerX) / (double)i;
-        double g = (e - (double)this.centerZ) / (double)i;
-        int j = 63;
-        if (f >= -63.0 && g >= -63.0 && f <= 63.0 && g <= 63.0) {
-            MapBanner mapBanner = MapBanner.fromWorld(world, pos);
-            if (mapBanner == null) {
+        double d2 = (d0 - (double) this.centerX) / (double) i;
+        double d3 = (d1 - (double) this.centerZ) / (double) i;
+        boolean flag = true;
+
+        if (d2 >= -63.0D && d3 >= -63.0D && d2 <= 63.0D && d3 <= 63.0D) {
+            MapBanner mapiconbanner = MapBanner.fromWorld(world, pos);
+
+            if (mapiconbanner == null) {
                 return false;
             }
 
-            if (this.bannerMarkers.remove(mapBanner.getId(), mapBanner)) {
-                this.removeDecoration(mapBanner.getId());
+            if (this.bannerMarkers.remove(mapiconbanner.getId(), mapiconbanner)) {
+                this.removeDecoration(mapiconbanner.getId());
                 return true;
             }
 
-            if (!this.isTrackedCountOverLimit(256)) {
-                this.bannerMarkers.put(mapBanner.getId(), mapBanner);
-                this.addDecoration(mapBanner.getDecoration(), world, mapBanner.getId(), d, e, 180.0, mapBanner.name().orElse(null));
+            if (!this.isTrackedCountOverLimit(((Level) world).paperConfig().maps.itemFrameCursorLimit)) { // Paper - Limit item frame cursors on maps
+                this.bannerMarkers.put(mapiconbanner.getId(), mapiconbanner);
+                this.addDecoration(mapiconbanner.getDecoration(), world, mapiconbanner.getId(), d0, d1, 180.0D, (Component) mapiconbanner.name().orElse(null)); // CraftBukkit - decompile error
                 return true;
             }
         }
@@ -414,15 +507,18 @@
         Iterator<MapBanner> iterator = this.bannerMarkers.values().iterator();
 
         while (iterator.hasNext()) {
-            MapBanner mapBanner = iterator.next();
-            if (mapBanner.pos().getX() == x && mapBanner.pos().getZ() == z) {
-                MapBanner mapBanner2 = MapBanner.fromWorld(world, mapBanner.pos());
-                if (!mapBanner.equals(mapBanner2)) {
+            MapBanner mapiconbanner = (MapBanner) iterator.next();
+
+            if (mapiconbanner.pos().getX() == x && mapiconbanner.pos().getZ() == z) {
+                MapBanner mapiconbanner1 = MapBanner.fromWorld(world, mapiconbanner.pos());
+
+                if (!mapiconbanner.equals(mapiconbanner1)) {
                     iterator.remove();
-                    this.removeDecoration(mapBanner.getId());
+                    this.removeDecoration(mapiconbanner.getId());
                 }
             }
         }
+
     }
 
     public Collection<MapBanner> getBanners() {
@@ -430,13 +526,14 @@
     }
 
     public void removedFromFrame(BlockPos pos, int id) {
-        this.removeDecoration(getFrameKey(id));
+        this.removeDecoration(MapItemSavedData.getFrameKey(id));
         this.frameMarkers.remove(MapFrame.frameId(pos));
     }
 
     public boolean updateColor(int x, int z, byte color) {
-        byte b = this.colors[x + z * 128];
-        if (b != color) {
+        byte b1 = this.colors[x + z * 128];
+
+        if (b1 != color) {
             this.setColor(x, z, color);
             return true;
         } else {
@@ -450,26 +547,34 @@
     }
 
     public boolean isExplorationMap() {
-        for (MapDecoration mapDecoration : this.decorations.values()) {
-            if (mapDecoration.type().value().explorationMapElement()) {
-                return true;
+        Iterator iterator = this.decorations.values().iterator();
+
+        MapDecoration mapicon;
+
+        do {
+            if (!iterator.hasNext()) {
+                return false;
             }
-        }
 
-        return false;
+            mapicon = (MapDecoration) iterator.next();
+        } while (!((MapDecorationType) mapicon.type().value()).explorationMapElement());
+
+        return true;
     }
 
     public void addClientSideDecorations(List<MapDecoration> decorations) {
         this.decorations.clear();
         this.trackedDecorationCount = 0;
 
-        for (int i = 0; i < decorations.size(); i++) {
-            MapDecoration mapDecoration = decorations.get(i);
-            this.decorations.put("icon-" + i, mapDecoration);
-            if (mapDecoration.type().value().trackCount()) {
-                this.trackedDecorationCount++;
+        for (int i = 0; i < decorations.size(); ++i) {
+            MapDecoration mapicon = (MapDecoration) decorations.get(i);
+
+            this.decorations.put("icon-" + i, mapicon);
+            if (((MapDecorationType) mapicon.type().value()).trackCount()) {
+                ++this.trackedDecorationCount;
             }
         }
+
     }
 
     public Iterable<MapDecoration> getDecorations() {
@@ -485,6 +590,22 @@
     }
 
     public class HoldingPlayer {
+
+        // Paper start
+        private void addSeenPlayers(java.util.Collection<MapDecoration> icons) {
+            org.bukkit.entity.Player player = (org.bukkit.entity.Player) this.player.getBukkitEntity();
+            MapItemSavedData.this.decorations.forEach((name, mapIcon) -> {
+                // If this cursor is for a player check visibility with vanish system
+                org.bukkit.entity.Player other = org.bukkit.Bukkit.getPlayerExact(name); // Spigot
+                if (other == null || player.canSee(other)) {
+                    icons.add(mapIcon);
+                }
+            });
+        }
+        private boolean shouldUseVanillaMap() {
+            return mapView.getRenderers().size() == 1 && mapView.getRenderers().get(0).getClass() == org.bukkit.craftbukkit.map.CraftMapRenderer.class;
+        }
+        // Paper end
         public final Player player;
         private boolean dirtyData = true;
         private int minDirtyX;
@@ -495,47 +616,61 @@
         private int tick;
         public int step;
 
-        HoldingPlayer(final Player player) {
-            this.player = player;
+        HoldingPlayer(final Player entityhuman) {
+            this.player = entityhuman;
         }
 
-        private MapItemSavedData.MapPatch createPatch() {
+        private MapItemSavedData.MapPatch createPatch(byte[] buffer) { // CraftBukkit
             int i = this.minDirtyX;
             int j = this.minDirtyY;
             int k = this.maxDirtyX + 1 - this.minDirtyX;
             int l = this.maxDirtyY + 1 - this.minDirtyY;
-            byte[] bs = new byte[k * l];
+            byte[] abyte = new byte[k * l];
 
-            for (int m = 0; m < k; m++) {
-                for (int n = 0; n < l; n++) {
-                    bs[m + n * k] = MapItemSavedData.this.colors[i + m + (j + n) * 128];
+            for (int i1 = 0; i1 < k; ++i1) {
+                for (int j1 = 0; j1 < l; ++j1) {
+                    abyte[i1 + j1 * k] = buffer[i + i1 + (j + j1) * 128]; // CraftBukkit
                 }
             }
 
-            return new MapItemSavedData.MapPatch(i, j, k, l, bs);
+            return new MapItemSavedData.MapPatch(i, j, k, l, abyte);
         }
 
         @Nullable
         Packet<?> nextUpdatePacket(MapId mapId) {
-            MapItemSavedData.MapPatch mapPatch;
+            MapItemSavedData.MapPatch worldmap_b;
+            if (!this.dirtyData && this.tick % 5 != 0) { this.tick++; return null; } // Paper - this won't end up sending, so don't render it!
+            boolean vanillaMaps = shouldUseVanillaMap(); // Paper
+            org.bukkit.craftbukkit.map.RenderData render = !vanillaMaps ? MapItemSavedData.this.mapView.render((org.bukkit.craftbukkit.entity.CraftPlayer) this.player.getBukkitEntity()) : MapItemSavedData.this.vanillaRender; // CraftBukkit // Paper
+
             if (this.dirtyData) {
                 this.dirtyData = false;
-                mapPatch = this.createPatch();
+                worldmap_b = this.createPatch(render.buffer); // CraftBukkit
             } else {
-                mapPatch = null;
+                worldmap_b = null;
             }
 
-            Collection<MapDecoration> collection;
-            if (this.dirtyDecorations && this.tick++ % 5 == 0) {
+            Collection collection;
+
+            if ((true || this.dirtyDecorations) && this.tick++ % 5 == 0) { // CraftBukkit - custom maps don't update this yet
                 this.dirtyDecorations = false;
-                collection = MapItemSavedData.this.decorations.values();
+                // CraftBukkit start
+                java.util.Collection<MapDecoration> icons = new java.util.ArrayList<MapDecoration>();
+
+                if (vanillaMaps) addSeenPlayers(icons); // Paper
+
+                for (org.bukkit.map.MapCursor cursor : render.cursors) {
+                    if (cursor.isVisible()) {
+                        icons.add(new MapDecoration(CraftMapCursor.CraftType.bukkitToMinecraftHolder(cursor.getType()), cursor.getX(), cursor.getY(), cursor.getDirection(), Optional.ofNullable(PaperAdventure.asVanilla(cursor.caption()))));
+                    }
+                }
+                collection = icons;
+                // CraftBukkit end
             } else {
                 collection = null;
             }
 
-            return collection == null && mapPatch == null
-                ? null
-                : new ClientboundMapItemDataPacket(mapId, MapItemSavedData.this.scale, MapItemSavedData.this.locked, collection, mapPatch);
+            return collection == null && worldmap_b == null ? null : new ClientboundMapItemDataPacket(mapId, MapItemSavedData.this.scale, MapItemSavedData.this.locked, collection, worldmap_b);
         }
 
         void markColorsDirty(int startX, int startZ) {
@@ -551,6 +686,7 @@
                 this.maxDirtyX = startX;
                 this.maxDirtyY = startZ;
             }
+
         }
 
         private void markDecorationsDirty() {
@@ -559,42 +695,46 @@
     }
 
     public static record MapPatch(int startX, int startY, int width, int height, byte[] mapColors) {
-        public static final StreamCodec<ByteBuf, Optional<MapItemSavedData.MapPatch>> STREAM_CODEC = StreamCodec.of(
-            MapItemSavedData.MapPatch::write, MapItemSavedData.MapPatch::read
-        );
+
+        public static final StreamCodec<ByteBuf, Optional<MapItemSavedData.MapPatch>> STREAM_CODEC = StreamCodec.of(MapItemSavedData.MapPatch::write, MapItemSavedData.MapPatch::read);
 
         private static void write(ByteBuf buf, Optional<MapItemSavedData.MapPatch> updateData) {
             if (updateData.isPresent()) {
-                MapItemSavedData.MapPatch mapPatch = updateData.get();
-                buf.writeByte(mapPatch.width);
-                buf.writeByte(mapPatch.height);
-                buf.writeByte(mapPatch.startX);
-                buf.writeByte(mapPatch.startY);
-                FriendlyByteBuf.writeByteArray(buf, mapPatch.mapColors);
+                MapItemSavedData.MapPatch worldmap_b = (MapItemSavedData.MapPatch) updateData.get();
+
+                buf.writeByte(worldmap_b.width);
+                buf.writeByte(worldmap_b.height);
+                buf.writeByte(worldmap_b.startX);
+                buf.writeByte(worldmap_b.startY);
+                FriendlyByteBuf.writeByteArray(buf, worldmap_b.mapColors);
             } else {
                 buf.writeByte(0);
             }
+
         }
 
         private static Optional<MapItemSavedData.MapPatch> read(ByteBuf buf) {
-            int i = buf.readUnsignedByte();
-            if (i > 0) {
-                int j = buf.readUnsignedByte();
-                int k = buf.readUnsignedByte();
-                int l = buf.readUnsignedByte();
-                byte[] bs = FriendlyByteBuf.readByteArray(buf);
-                return Optional.of(new MapItemSavedData.MapPatch(k, l, i, j, bs));
+            short short0 = buf.readUnsignedByte();
+
+            if (short0 > 0) {
+                short short1 = buf.readUnsignedByte();
+                short short2 = buf.readUnsignedByte();
+                short short3 = buf.readUnsignedByte();
+                byte[] abyte = FriendlyByteBuf.readByteArray(buf);
+
+                return Optional.of(new MapItemSavedData.MapPatch(short2, short3, short0, short1, abyte));
             } else {
                 return Optional.empty();
             }
         }
 
         public void applyToMap(MapItemSavedData mapState) {
-            for (int i = 0; i < this.width; i++) {
-                for (int j = 0; j < this.height; j++) {
+            for (int i = 0; i < this.width; ++i) {
+                for (int j = 0; j < this.height; ++j) {
                     mapState.setColor(this.startX + i, this.startY + j, this.mapColors[i + j * this.width]);
                 }
             }
+
         }
     }
 }
