--- a/net/minecraft/world/level/block/ShulkerBoxBlock.java
+++ b/net/minecraft/world/level/block/ShulkerBoxBlock.java
@@ -78,8 +_,8 @@
     protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) {
         if (level instanceof ServerLevel serverLevel
             && level.getBlockEntity(pos) instanceof ShulkerBoxBlockEntity shulkerBoxBlockEntity
-            && canOpen(state, level, pos, shulkerBoxBlockEntity)) {
-            player.openMenu(shulkerBoxBlockEntity);
+            && canOpen(state, level, pos, shulkerBoxBlockEntity) // Paper - Fix InventoryOpenEvent cancellation - expand if for belows check
+            && player.openMenu(shulkerBoxBlockEntity).isPresent()) { // Paper - Fix InventoryOpenEvent cancellation
             player.awardStat(Stats.OPEN_SHULKER_BOX);
             PiglinAi.angerNearbyPiglins(serverLevel, player, true);
         }
@@ -117,7 +_,7 @@
                 itemEntity.setDefaultPickUpDelay();
                 level.addFreshEntity(itemEntity);
             } else {
-                shulkerBoxBlockEntity.unpackLootTable(player);
+                shulkerBoxBlockEntity.unpackLootTable(player, true); // Paper - force clear loot table so replenish data isn't persisted in the stack
             }
         }
 
@@ -127,7 +_,15 @@
     @Override
     protected List<ItemStack> getDrops(BlockState state, LootParams.Builder params) {
         BlockEntity blockEntity = params.getOptionalParameter(LootContextParams.BLOCK_ENTITY);
+        Runnable reAdd = null; // Paper
         if (blockEntity instanceof ShulkerBoxBlockEntity shulkerBoxBlockEntity) {
+            // Paper start - clear loot table if it was already used
+            if (shulkerBoxBlockEntity.lootableData().getLastFill() != -1 || !params.getLevel().paperConfig().lootables.retainUnlootedShulkerBoxLootTableOnNonPlayerBreak) {
+                net.minecraft.resources.ResourceKey<net.minecraft.world.level.storage.loot.LootTable> lootTableResourceKey = shulkerBoxBlockEntity.getLootTable();
+                reAdd = () -> shulkerBoxBlockEntity.setLootTable(lootTableResourceKey);
+                shulkerBoxBlockEntity.setLootTable(null);
+            }
+            // Paper end
             params = params.withDynamicDrop(CONTENTS, output -> {
                 for (int i = 0; i < shulkerBoxBlockEntity.getContainerSize(); i++) {
                     output.accept(shulkerBoxBlockEntity.getItem(i));
@@ -135,7 +_,13 @@
             });
         }
 
+        // Paper start - re-set loot table if it was cleared
+        try {
         return super.getDrops(state, params);
+        } finally {
+            if (reAdd != null) reAdd.run();
+        }
+        // Paper end - re-set loot table if it was cleared
     }
 
     @Override
