--- a/net/minecraft/world/inventory/CartographyTableMenu.java
+++ b/net/minecraft/world/inventory/CartographyTableMenu.java
@@ -6,15 +6,36 @@
 import net.minecraft.world.Container;
 import net.minecraft.world.SimpleContainer;
 import net.minecraft.world.entity.player.Inventory;
-import net.minecraft.world.entity.player.Player;
 import net.minecraft.world.item.ItemStack;
 import net.minecraft.world.item.Items;
 import net.minecraft.world.item.MapItem;
 import net.minecraft.world.item.component.MapPostProcessing;
 import net.minecraft.world.level.block.Blocks;
 import net.minecraft.world.level.saveddata.maps.MapItemSavedData;
+// CraftBukkit start
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.inventory.CraftInventoryCartography;
+import org.bukkit.craftbukkit.inventory.CraftInventoryView;
+import org.bukkit.entity.Player;
+// CraftBukkit end
 
 public class CartographyTableMenu extends AbstractContainerMenu {
+
+    // CraftBukkit start
+    private CraftInventoryView bukkitEntity = null;
+    private Player player;
+
+    @Override
+    public CraftInventoryView getBukkitView() {
+        if (this.bukkitEntity != null) {
+            return this.bukkitEntity;
+        }
+
+        CraftInventoryCartography inventory = new CraftInventoryCartography(this.container, this.resultContainer);
+        this.bukkitEntity = new CraftInventoryView(this.player, inventory, this);
+        return this.bukkitEntity;
+    }
+    // CraftBukkit end
     public static final int MAP_SLOT = 0;
     public static final int ADDITIONAL_SLOT = 1;
     public static final int RESULT_SLOT = 2;
@@ -24,35 +45,51 @@
     private static final int USE_ROW_SLOT_END = 39;
     private final ContainerLevelAccess access;
     long lastSoundTime;
-    public final Container container = new SimpleContainer(2) {
-        @Override
-        public void setChanged() {
-            CartographyTableMenu.this.slotsChanged(this);
-            super.setChanged();
-        }
-    };
-    private final ResultContainer resultContainer = new ResultContainer() {
-        @Override
-        public void setChanged() {
-            CartographyTableMenu.this.slotsChanged(this);
-            super.setChanged();
-        }
-    };
+    public final Container container;
+    private final ResultContainer resultContainer;
 
     public CartographyTableMenu(int syncId, Inventory inventory) {
         this(syncId, inventory, ContainerLevelAccess.NULL);
     }
 
-    public CartographyTableMenu(int syncId, Inventory inventory, ContainerLevelAccess context) {
+    public CartographyTableMenu(int syncId, Inventory inventory, final ContainerLevelAccess context) {
         super(MenuType.CARTOGRAPHY_TABLE, syncId);
+        this.container = new SimpleContainer(this.createBlockHolder(context), 2) { // Paper - Add missing InventoryHolders
+            @Override
+            public void setChanged() {
+                CartographyTableMenu.this.slotsChanged(this);
+                super.setChanged();
+            }
+
+            // CraftBukkit start
+            @Override
+            public Location getLocation() {
+                return context.getLocation();
+            }
+            // CraftBukkit end
+        };
+        this.resultContainer = new ResultContainer(this.createBlockHolder(context)) { // Paper - Add missing InventoryHolders
+            @Override
+            public void setChanged() {
+                // CartographyTableMenu.this.slotsChanged(this); // Paper - Add CatographyItemEvent - do not recompute results if the result slot changes - allows to set the result slot via api
+                super.setChanged();
+            }
+
+            // CraftBukkit start
+            @Override
+            public Location getLocation() {
+                return context.getLocation();
+            }
+            // CraftBukkit end
+        };
         this.access = context;
-        this.addSlot(new Slot(this.container, 0, 15, 15) {
+        this.addSlot(new Slot(this.container, 0, 15, 15) { // CraftBukkit - decompile error
             @Override
             public boolean mayPlace(ItemStack stack) {
                 return stack.is(Items.FILLED_MAP);
             }
         });
-        this.addSlot(new Slot(this.container, 1, 15, 52) {
+        this.addSlot(new Slot(this.container, 1, 15, 52) { // CraftBukkit - decompile error
             @Override
             public boolean mayPlace(ItemStack stack) {
                 return stack.is(Items.PAPER) || stack.is(Items.MAP) || stack.is(Items.GLASS_PANE);
@@ -65,63 +102,73 @@
             }
 
             @Override
-            public void onTake(Player player, ItemStack stack) {
-                CartographyTableMenu.this.slots.get(0).remove(1);
-                CartographyTableMenu.this.slots.get(1).remove(1);
+            public void onTake(net.minecraft.world.entity.player.Player player, ItemStack stack) {
+                ((Slot) CartographyTableMenu.this.slots.get(0)).remove(1);
+                ((Slot) CartographyTableMenu.this.slots.get(1)).remove(1);
                 stack.getItem().onCraftedBy(stack, player.level(), player);
-                context.execute((world, pos) -> {
-                    long l = world.getGameTime();
-                    if (CartographyTableMenu.this.lastSoundTime != l) {
-                        world.playSound(null, pos, SoundEvents.UI_CARTOGRAPHY_TABLE_TAKE_RESULT, SoundSource.BLOCKS, 1.0F, 1.0F);
-                        CartographyTableMenu.this.lastSoundTime = l;
+                context.execute((world, blockposition) -> {
+                    long j = world.getGameTime();
+
+                    if (CartographyTableMenu.this.lastSoundTime != j) {
+                        world.playSound((net.minecraft.world.entity.player.Player) null, blockposition, SoundEvents.UI_CARTOGRAPHY_TABLE_TAKE_RESULT, SoundSource.BLOCKS, 1.0F, 1.0F);
+                        CartographyTableMenu.this.lastSoundTime = j;
                     }
+
                 });
                 super.onTake(player, stack);
             }
         });
 
-        for (int i = 0; i < 3; i++) {
-            for (int j = 0; j < 9; j++) {
-                this.addSlot(new Slot(inventory, j + i * 9 + 9, 8 + j * 18, 84 + i * 18));
+        int j;
+
+        for (j = 0; j < 3; ++j) {
+            for (int k = 0; k < 9; ++k) {
+                this.addSlot(new Slot(inventory, k + j * 9 + 9, 8 + k * 18, 84 + j * 18));
             }
         }
 
-        for (int k = 0; k < 9; k++) {
-            this.addSlot(new Slot(inventory, k, 8 + k * 18, 142));
+        for (j = 0; j < 9; ++j) {
+            this.addSlot(new Slot(inventory, j, 8 + j * 18, 142));
         }
+
+        this.player = (Player) inventory.player.getBukkitEntity(); // CraftBukkit
     }
 
     @Override
-    public boolean stillValid(Player player) {
+    public boolean stillValid(net.minecraft.world.entity.player.Player player) {
+        if (!this.checkReachable) return true; // CraftBukkit
         return stillValid(this.access, player, Blocks.CARTOGRAPHY_TABLE);
     }
 
     @Override
     public void slotsChanged(Container inventory) {
-        ItemStack itemStack = this.container.getItem(0);
-        ItemStack itemStack2 = this.container.getItem(1);
-        ItemStack itemStack3 = this.resultContainer.getItem(2);
-        if (itemStack3.isEmpty() || !itemStack.isEmpty() && !itemStack2.isEmpty()) {
-            if (!itemStack.isEmpty() && !itemStack2.isEmpty()) {
-                this.setupResultSlot(itemStack, itemStack2, itemStack3);
-            }
-        } else {
+        ItemStack itemstack = this.container.getItem(0);
+        ItemStack itemstack1 = this.container.getItem(1);
+        ItemStack itemstack2 = this.resultContainer.getItem(2);
+
+        if (!itemstack2.isEmpty() && (itemstack.isEmpty() || itemstack1.isEmpty())) {
             this.resultContainer.removeItemNoUpdate(2);
+        } else if (!itemstack.isEmpty() && !itemstack1.isEmpty()) {
+            this.setupResultSlot(itemstack, itemstack1, itemstack2);
         }
+
+        org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper - Add PrepareResultEvent
     }
 
     private void setupResultSlot(ItemStack map, ItemStack item, ItemStack oldResult) {
-        this.access.execute((world, pos) -> {
-            MapItemSavedData mapItemSavedData = MapItem.getSavedData(map, world);
-            if (mapItemSavedData != null) {
-                ItemStack itemStack4;
-                if (item.is(Items.PAPER) && !mapItemSavedData.locked && mapItemSavedData.scale < 4) {
-                    itemStack4 = map.copyWithCount(1);
-                    itemStack4.set(DataComponents.MAP_POST_PROCESSING, MapPostProcessing.SCALE);
+        this.access.execute((world, blockposition) -> {
+            MapItemSavedData worldmap = MapItem.getSavedData(map, world);
+
+            if (worldmap != null) {
+                ItemStack itemstack3;
+
+                if (item.is(Items.PAPER) && !worldmap.locked && worldmap.scale < 4) {
+                    itemstack3 = map.copyWithCount(1);
+                    itemstack3.set(DataComponents.MAP_POST_PROCESSING, MapPostProcessing.SCALE);
                     this.broadcastChanges();
-                } else if (item.is(Items.GLASS_PANE) && !mapItemSavedData.locked) {
-                    itemStack4 = map.copyWithCount(1);
-                    itemStack4.set(DataComponents.MAP_POST_PROCESSING, MapPostProcessing.LOCK);
+                } else if (item.is(Items.GLASS_PANE) && !worldmap.locked) {
+                    itemstack3 = map.copyWithCount(1);
+                    itemstack3.set(DataComponents.MAP_POST_PROCESSING, MapPostProcessing.LOCK);
                     this.broadcastChanges();
                 } else {
                     if (!item.is(Items.MAP)) {
@@ -130,14 +177,15 @@
                         return;
                     }
 
-                    itemStack4 = map.copyWithCount(2);
+                    itemstack3 = map.copyWithCount(2);
                     this.broadcastChanges();
                 }
 
-                if (!ItemStack.matches(itemStack4, oldResult)) {
-                    this.resultContainer.setItem(2, itemStack4);
+                if (!ItemStack.matches(itemstack3, oldResult)) {
+                    this.resultContainer.setItem(2, itemstack3);
                     this.broadcastChanges();
                 }
+
             }
         });
     }
@@ -148,59 +196,63 @@
     }
 
     @Override
-    public ItemStack quickMoveStack(Player player, int slot) {
-        ItemStack itemStack = ItemStack.EMPTY;
-        Slot slot2 = this.slots.get(slot);
-        if (slot2 != null && slot2.hasItem()) {
-            ItemStack itemStack2 = slot2.getItem();
-            itemStack = itemStack2.copy();
+    public ItemStack quickMoveStack(net.minecraft.world.entity.player.Player player, int slot) {
+        ItemStack itemstack = ItemStack.EMPTY;
+        Slot slot1 = (Slot) this.slots.get(slot);
+
+        if (slot1 != null && slot1.hasItem()) {
+            ItemStack itemstack1 = slot1.getItem();
+
+            itemstack = itemstack1.copy();
             if (slot == 2) {
-                itemStack2.getItem().onCraftedBy(itemStack2, player.level(), player);
-                if (!this.moveItemStackTo(itemStack2, 3, 39, true)) {
+                itemstack1.getItem().onCraftedBy(itemstack1, player.level(), player);
+                if (!this.moveItemStackTo(itemstack1, 3, 39, true)) {
                     return ItemStack.EMPTY;
                 }
 
-                slot2.onQuickCraft(itemStack2, itemStack);
+                slot1.onQuickCraft(itemstack1, itemstack);
             } else if (slot != 1 && slot != 0) {
-                if (itemStack2.is(Items.FILLED_MAP)) {
-                    if (!this.moveItemStackTo(itemStack2, 0, 1, false)) {
+                if (itemstack1.is(Items.FILLED_MAP)) {
+                    if (!this.moveItemStackTo(itemstack1, 0, 1, false)) {
                         return ItemStack.EMPTY;
                     }
-                } else if (!itemStack2.is(Items.PAPER) && !itemStack2.is(Items.MAP) && !itemStack2.is(Items.GLASS_PANE)) {
+                } else if (!itemstack1.is(Items.PAPER) && !itemstack1.is(Items.MAP) && !itemstack1.is(Items.GLASS_PANE)) {
                     if (slot >= 3 && slot < 30) {
-                        if (!this.moveItemStackTo(itemStack2, 30, 39, false)) {
+                        if (!this.moveItemStackTo(itemstack1, 30, 39, false)) {
                             return ItemStack.EMPTY;
                         }
-                    } else if (slot >= 30 && slot < 39 && !this.moveItemStackTo(itemStack2, 3, 30, false)) {
+                    } else if (slot >= 30 && slot < 39 && !this.moveItemStackTo(itemstack1, 3, 30, false)) {
                         return ItemStack.EMPTY;
                     }
-                } else if (!this.moveItemStackTo(itemStack2, 1, 2, false)) {
+                } else if (!this.moveItemStackTo(itemstack1, 1, 2, false)) {
                     return ItemStack.EMPTY;
                 }
-            } else if (!this.moveItemStackTo(itemStack2, 3, 39, false)) {
+            } else if (!this.moveItemStackTo(itemstack1, 3, 39, false)) {
                 return ItemStack.EMPTY;
             }
 
-            if (itemStack2.isEmpty()) {
-                slot2.setByPlayer(ItemStack.EMPTY);
+            if (itemstack1.isEmpty()) {
+                slot1.setByPlayer(ItemStack.EMPTY);
             }
 
-            slot2.setChanged();
-            if (itemStack2.getCount() == itemStack.getCount()) {
+            slot1.setChanged();
+            if (itemstack1.getCount() == itemstack.getCount()) {
                 return ItemStack.EMPTY;
             }
 
-            slot2.onTake(player, itemStack2);
+            slot1.onTake(player, itemstack1);
             this.broadcastChanges();
         }
 
-        return itemStack;
+        return itemstack;
     }
 
     @Override
-    public void removed(Player player) {
+    public void removed(net.minecraft.world.entity.player.Player player) {
         super.removed(player);
         this.resultContainer.removeItemNoUpdate(2);
-        this.access.execute((world, pos) -> this.clearContainer(player, this.container));
+        this.access.execute((world, blockposition) -> {
+            this.clearContainer(player, this.container);
+        });
     }
 }
