--- a/net/minecraft/world/inventory/StonecutterMenu.java
+++ b/net/minecraft/world/inventory/StonecutterMenu.java
@@ -7,7 +7,6 @@
 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.Item;
 import net.minecraft.world.item.ItemStack;
 import net.minecraft.world.item.crafting.RecipeHolder;
@@ -17,7 +16,15 @@
 import net.minecraft.world.level.Level;
 import net.minecraft.world.level.block.Blocks;
 
+// CraftBukkit start
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.inventory.CraftInventoryStonecutter;
+import org.bukkit.craftbukkit.inventory.CraftInventoryView;
+import org.bukkit.entity.Player;
+// CraftBukkit end
+
 public class StonecutterMenu extends AbstractContainerMenu {
+
     public static final int INPUT_SLOT = 0;
     public static final int RESULT_SLOT = 1;
     private static final int INV_SLOT_START = 2;
@@ -25,31 +32,59 @@
     private static final int USE_ROW_SLOT_START = 29;
     private static final int USE_ROW_SLOT_END = 38;
     private final ContainerLevelAccess access;
-    private final DataSlot selectedRecipeIndex = DataSlot.standalone();
+    private final DataSlot selectedRecipeIndex;
     private final Level level;
-    private List<RecipeHolder<StonecutterRecipe>> recipes = Lists.newArrayList();
-    private ItemStack input = ItemStack.EMPTY;
+    private List<RecipeHolder<StonecutterRecipe>> recipes;
+    private ItemStack input;
     long lastSoundTime;
     final Slot inputSlot;
     final Slot resultSlot;
-    Runnable slotUpdateListener = () -> {
-    };
-    public final Container container = new SimpleContainer(1) {
-        @Override
-        public void setChanged() {
-            super.setChanged();
-            StonecutterMenu.this.slotsChanged(this);
-            StonecutterMenu.this.slotUpdateListener.run();
+    Runnable slotUpdateListener;
+    public final Container container;
+    final ResultContainer resultContainer;
+    // CraftBukkit start
+    private CraftInventoryView bukkitEntity = null;
+    private Player player;
+
+    @Override
+    public CraftInventoryView getBukkitView() {
+        if (this.bukkitEntity != null) {
+            return this.bukkitEntity;
         }
-    };
-    final ResultContainer resultContainer = new ResultContainer();
+
+        CraftInventoryStonecutter inventory = new CraftInventoryStonecutter(this.container, this.resultContainer);
+        this.bukkitEntity = new CraftInventoryView(this.player, inventory, this);
+        return this.bukkitEntity;
+    }
+    // CraftBukkit end
 
     public StonecutterMenu(int syncId, Inventory playerInventory) {
         this(syncId, playerInventory, ContainerLevelAccess.NULL);
     }
 
-    public StonecutterMenu(int syncId, Inventory playerInventory, ContainerLevelAccess context) {
+    public StonecutterMenu(int syncId, Inventory playerInventory, final ContainerLevelAccess context) {
         super(MenuType.STONECUTTER, syncId);
+        this.selectedRecipeIndex = DataSlot.shared(new int[1], 0); // Paper - Add PlayerStonecutterRecipeSelectEvent
+        this.recipes = Lists.newArrayList();
+        this.input = ItemStack.EMPTY;
+        this.slotUpdateListener = () -> {
+        };
+        this.container = new SimpleContainer(this.createBlockHolder(context), 1) { // Paper - Add missing InventoryHolders
+            @Override
+            public void setChanged() {
+                super.setChanged();
+                StonecutterMenu.this.slotsChanged(this);
+                StonecutterMenu.this.slotUpdateListener.run();
+            }
+
+            // CraftBukkit start
+            @Override
+            public Location getLocation() {
+                return context.getLocation();
+            }
+            // CraftBukkit end
+        };
+        this.resultContainer = new ResultContainer(this.createBlockHolder(context)); // Paper - Add missing InventoryHolders
         this.access = context;
         this.level = playerInventory.player.level();
         this.inputSlot = this.addSlot(new Slot(this.container, 0, 20, 33));
@@ -60,20 +95,23 @@
             }
 
             @Override
-            public void onTake(Player player, ItemStack stack) {
+            public void onTake(net.minecraft.world.entity.player.Player player, ItemStack stack) {
                 stack.onCraftedBy(player.level(), player, stack.getCount());
                 StonecutterMenu.this.resultContainer.awardUsedRecipes(player, this.getRelevantItems());
-                ItemStack itemStack = StonecutterMenu.this.inputSlot.remove(1);
-                if (!itemStack.isEmpty()) {
+                ItemStack itemstack1 = StonecutterMenu.this.inputSlot.remove(1);
+
+                if (!itemstack1.isEmpty()) {
                     StonecutterMenu.this.setupResultSlot();
                 }
 
-                context.execute((world, pos) -> {
-                    long l = world.getGameTime();
-                    if (StonecutterMenu.this.lastSoundTime != l) {
-                        world.playSound(null, pos, SoundEvents.UI_STONECUTTER_TAKE_RESULT, SoundSource.BLOCKS, 1.0F, 1.0F);
-                        StonecutterMenu.this.lastSoundTime = l;
+                context.execute((world, blockposition) -> {
+                    long j = world.getGameTime();
+
+                    if (StonecutterMenu.this.lastSoundTime != j) {
+                        world.playSound((net.minecraft.world.entity.player.Player) null, blockposition, SoundEvents.UI_STONECUTTER_TAKE_RESULT, SoundSource.BLOCKS, 1.0F, 1.0F);
+                        StonecutterMenu.this.lastSoundTime = j;
                     }
+
                 });
                 super.onTake(player, stack);
             }
@@ -83,17 +121,20 @@
             }
         });
 
-        for (int i = 0; i < 3; i++) {
-            for (int j = 0; j < 9; j++) {
-                this.addSlot(new Slot(playerInventory, 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(playerInventory, k + j * 9 + 9, 8 + k * 18, 84 + j * 18));
             }
         }
 
-        for (int k = 0; k < 9; k++) {
-            this.addSlot(new Slot(playerInventory, k, 8 + k * 18, 142));
+        for (j = 0; j < 9; ++j) {
+            this.addSlot(new Slot(playerInventory, j, 8 + j * 18, 142));
         }
 
         this.addDataSlot(this.selectedRecipeIndex);
+        this.player = (Player) playerInventory.player.getBukkitEntity(); // CraftBukkit
     }
 
     public int getSelectedRecipeIndex() {
@@ -113,14 +154,38 @@
     }
 
     @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.STONECUTTER);
     }
 
     @Override
-    public boolean clickMenuButton(Player player, int id) {
+    public boolean clickMenuButton(net.minecraft.world.entity.player.Player player, int id) {
         if (this.isValidRecipeIndex(id)) {
-            this.selectedRecipeIndex.set(id);
+            // Paper start - Add PlayerStonecutterRecipeSelectEvent
+            int recipeIndex = id;
+            this.selectedRecipeIndex.set(recipeIndex);
+            this.selectedRecipeIndex.checkAndClearUpdateFlag(); // mark as changed
+            if (this.isValidRecipeIndex(id)) {
+                io.papermc.paper.event.player.PlayerStonecutterRecipeSelectEvent event = new io.papermc.paper.event.player.PlayerStonecutterRecipeSelectEvent((Player) player.getBukkitEntity(), (org.bukkit.inventory.StonecutterInventory) getBukkitView().getTopInventory(), (org.bukkit.inventory.StonecuttingRecipe) this.getRecipes().get(id).toBukkitRecipe());
+                if (!event.callEvent()) {
+                    player.containerMenu.sendAllDataToRemote();
+                    return false;
+                }
+
+                net.minecraft.resources.ResourceLocation key = org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(event.getStonecuttingRecipe().getKey());
+                if (!this.getRecipes().get(recipeIndex).id().equals(key)) { // If the recipe did NOT stay the same
+                    for (int newRecipeIndex = 0; newRecipeIndex < this.getRecipes().size(); newRecipeIndex++) {
+                        if (this.getRecipes().get(newRecipeIndex).id().equals(key)) {
+                            recipeIndex = newRecipeIndex;
+                            break;
+                        }
+                    }
+                }
+            }
+            player.containerMenu.sendAllDataToRemote();
+            this.selectedRecipeIndex.set(recipeIndex); // set new index, so that listeners can read it
+            // Paper end - Add PlayerStonecutterRecipeSelectEvent
             this.setupResultSlot();
         }
 
@@ -133,11 +198,14 @@
 
     @Override
     public void slotsChanged(Container inventory) {
-        ItemStack itemStack = this.inputSlot.getItem();
-        if (!itemStack.is(this.input.getItem())) {
-            this.input = itemStack.copy();
-            this.setupRecipeList(inventory, itemStack);
+        ItemStack itemstack = this.inputSlot.getItem();
+
+        if (!itemstack.is(this.input.getItem())) {
+            this.input = itemstack.copy();
+            this.setupRecipeList(inventory, itemstack);
         }
+
+        org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper - Add PrepareResultEvent
     }
 
     private static SingleRecipeInput createRecipeInput(Container inventory) {
@@ -149,17 +217,19 @@
         this.selectedRecipeIndex.set(-1);
         this.resultSlot.set(ItemStack.EMPTY);
         if (!stack.isEmpty()) {
-            this.recipes = this.level.getRecipeManager().getRecipesFor(RecipeType.STONECUTTING, createRecipeInput(input), this.level);
+            this.recipes = this.level.getRecipeManager().getRecipesFor(RecipeType.STONECUTTING, StonecutterMenu.createRecipeInput(input), this.level);
         }
+
     }
 
     void setupResultSlot() {
         if (!this.recipes.isEmpty() && this.isValidRecipeIndex(this.selectedRecipeIndex.get())) {
-            RecipeHolder<StonecutterRecipe> recipeHolder = this.recipes.get(this.selectedRecipeIndex.get());
-            ItemStack itemStack = recipeHolder.value().assemble(createRecipeInput(this.container), this.level.registryAccess());
-            if (itemStack.isItemEnabled(this.level.enabledFeatures())) {
-                this.resultContainer.setRecipeUsed(recipeHolder);
-                this.resultSlot.set(itemStack);
+            RecipeHolder<StonecutterRecipe> recipeholder = (RecipeHolder) this.recipes.get(this.selectedRecipeIndex.get());
+            ItemStack itemstack = ((StonecutterRecipe) recipeholder.value()).assemble(StonecutterMenu.createRecipeInput(this.container), this.level.registryAccess());
+
+            if (itemstack.isItemEnabled(this.level.enabledFeatures())) {
+                this.resultContainer.setRecipeUsed(recipeholder);
+                this.resultSlot.set(itemstack);
             } else {
                 this.resultSlot.set(ItemStack.EMPTY);
             }
@@ -185,56 +255,60 @@
     }
 
     @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();
-            Item item = itemStack2.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();
+            Item item = itemstack1.getItem();
+
+            itemstack = itemstack1.copy();
             if (slot == 1) {
-                item.onCraftedBy(itemStack2, player.level(), player);
-                if (!this.moveItemStackTo(itemStack2, 2, 38, true)) {
+                item.onCraftedBy(itemstack1, player.level(), player);
+                if (!this.moveItemStackTo(itemstack1, 2, 38, true)) {
                     return ItemStack.EMPTY;
                 }
 
-                slot2.onQuickCraft(itemStack2, itemStack);
+                slot1.onQuickCraft(itemstack1, itemstack);
             } else if (slot == 0) {
-                if (!this.moveItemStackTo(itemStack2, 2, 38, false)) {
+                if (!this.moveItemStackTo(itemstack1, 2, 38, false)) {
                     return ItemStack.EMPTY;
                 }
-            } else if (this.level.getRecipeManager().getRecipeFor(RecipeType.STONECUTTING, new SingleRecipeInput(itemStack2), this.level).isPresent()) {
-                if (!this.moveItemStackTo(itemStack2, 0, 1, false)) {
+            } else if (this.level.getRecipeManager().getRecipeFor(RecipeType.STONECUTTING, new SingleRecipeInput(itemstack1), this.level).isPresent()) {
+                if (!this.moveItemStackTo(itemstack1, 0, 1, false)) {
                     return ItemStack.EMPTY;
                 }
             } else if (slot >= 2 && slot < 29) {
-                if (!this.moveItemStackTo(itemStack2, 29, 38, false)) {
+                if (!this.moveItemStackTo(itemstack1, 29, 38, false)) {
                     return ItemStack.EMPTY;
                 }
-            } else if (slot >= 29 && slot < 38 && !this.moveItemStackTo(itemStack2, 2, 29, false)) {
+            } else if (slot >= 29 && slot < 38 && !this.moveItemStackTo(itemstack1, 2, 29, 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(1);
-        this.access.execute((world, pos) -> this.clearContainer(player, this.container));
+        this.access.execute((world, blockposition) -> {
+            this.clearContainer(player, this.container);
+        });
     }
 }
