--- a/net/minecraft/world/entity/vehicle/ChestBoat.java
+++ b/net/minecraft/world/entity/vehicle/ChestBoat.java
@@ -1,9 +1,11 @@
 package net.minecraft.world.entity.vehicle;
 
 import javax.annotation.Nullable;
+import net.minecraft.core.Holder;
 import net.minecraft.core.NonNullList;
 import net.minecraft.nbt.CompoundTag;
 import net.minecraft.resources.ResourceKey;
+import net.minecraft.world.Container;
 import net.minecraft.world.Containers;
 import net.minecraft.world.InteractionHand;
 import net.minecraft.world.InteractionResult;
@@ -24,23 +26,35 @@
 import net.minecraft.world.level.gameevent.GameEvent;
 import net.minecraft.world.level.storage.loot.LootTable;
 
+// CraftBukkit start
+import java.util.List;
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.entity.CraftHumanEntity;
+import org.bukkit.entity.HumanEntity;
+import org.bukkit.event.entity.EntityRemoveEvent;
+import org.bukkit.inventory.InventoryHolder;
+// CraftBukkit end
+
 public class ChestBoat extends Boat implements HasCustomInventoryScreen, ContainerEntity {
+
     private static final int CONTAINER_SIZE = 27;
-    private NonNullList<ItemStack> itemStacks = NonNullList.withSize(27, ItemStack.EMPTY);
+    private NonNullList<ItemStack> itemStacks;
     @Nullable
     private ResourceKey<LootTable> lootTable;
     private long lootTableSeed;
 
     public ChestBoat(EntityType<? extends Boat> type, Level world) {
         super(type, world);
+        this.itemStacks = NonNullList.withSize(27, ItemStack.EMPTY);
     }
 
-    public ChestBoat(Level world, double d, double e, double f) {
+    public ChestBoat(Level world, double d0, double d1, double d2) {
         super(EntityType.CHEST_BOAT, world);
-        this.setPos(d, e, f);
-        this.xo = d;
-        this.yo = e;
-        this.zo = f;
+        this.itemStacks = NonNullList.withSize(27, ItemStack.EMPTY);
+        this.setPos(d0, d1, d2);
+        this.xo = d0;
+        this.yo = d1;
+        this.zo = d2;
     }
 
     @Override
@@ -73,57 +87,87 @@
 
     @Override
     public void remove(Entity.RemovalReason reason) {
-        if (!this.level().isClientSide && reason.shouldDestroy()) {
-            Containers.dropContents(this.level(), this, this);
+        // CraftBukkit start - add Bukkit remove cause
+        this.remove(reason, null);
+    }
+
+    @Override
+    public void remove(Entity.RemovalReason entity_removalreason, EntityRemoveEvent.Cause cause) {
+        // CraftBukkit end
+        if (!this.level().isClientSide && entity_removalreason.shouldDestroy()) {
+            Containers.dropContents(this.level(), (Entity) this, (Container) this);
         }
 
-        super.remove(reason);
+        super.remove(entity_removalreason, cause); // CraftBukkit - add Bukkit remove cause
     }
 
     @Override
     public InteractionResult interact(Player player, InteractionHand hand) {
+        InteractionResult enuminteractionresult;
+
         if (!player.isSecondaryUseActive()) {
-            InteractionResult interactionResult = super.interact(player, hand);
-            if (interactionResult != InteractionResult.PASS) {
-                return interactionResult;
+            enuminteractionresult = super.interact(player, hand);
+            if (enuminteractionresult != InteractionResult.PASS) {
+                return enuminteractionresult;
             }
         }
 
         if (this.canAddPassenger(player) && !player.isSecondaryUseActive()) {
             return InteractionResult.PASS;
         } else {
-            InteractionResult interactionResult2 = this.interactWithContainerVehicle(player);
-            if (interactionResult2.consumesAction()) {
+            enuminteractionresult = this.interactWithContainerVehicle(player);
+            if (enuminteractionresult.consumesAction()) {
                 this.gameEvent(GameEvent.CONTAINER_OPEN, player);
                 PiglinAi.angerNearbyPiglins(player, true);
             }
 
-            return interactionResult2;
+            return enuminteractionresult;
         }
     }
 
     @Override
     public void openCustomInventoryScreen(Player player) {
-        player.openMenu(this);
-        if (!player.level().isClientSide) {
+        if (!player.level().isClientSide && player.openMenu(this).isPresent()) { // Paper - Fix InventoryOpenEvent cancellation
             this.gameEvent(GameEvent.CONTAINER_OPEN, player);
             PiglinAi.angerNearbyPiglins(player, true);
         }
+
     }
 
     @Override
     public Item getDropItem() {
-        return switch (this.getVariant()) {
-            case SPRUCE -> Items.SPRUCE_CHEST_BOAT;
-            case BIRCH -> Items.BIRCH_CHEST_BOAT;
-            case JUNGLE -> Items.JUNGLE_CHEST_BOAT;
-            case ACACIA -> Items.ACACIA_CHEST_BOAT;
-            case CHERRY -> Items.CHERRY_CHEST_BOAT;
-            case DARK_OAK -> Items.DARK_OAK_CHEST_BOAT;
-            case MANGROVE -> Items.MANGROVE_CHEST_BOAT;
-            case BAMBOO -> Items.BAMBOO_CHEST_RAFT;
-            default -> Items.OAK_CHEST_BOAT;
-        };
+        Item item;
+
+        switch (this.getVariant()) {
+            case SPRUCE:
+                item = Items.SPRUCE_CHEST_BOAT;
+                break;
+            case BIRCH:
+                item = Items.BIRCH_CHEST_BOAT;
+                break;
+            case JUNGLE:
+                item = Items.JUNGLE_CHEST_BOAT;
+                break;
+            case ACACIA:
+                item = Items.ACACIA_CHEST_BOAT;
+                break;
+            case CHERRY:
+                item = Items.CHERRY_CHEST_BOAT;
+                break;
+            case DARK_OAK:
+                item = Items.DARK_OAK_CHEST_BOAT;
+                break;
+            case MANGROVE:
+                item = Items.MANGROVE_CHEST_BOAT;
+                break;
+            case BAMBOO:
+                item = Items.BAMBOO_CHEST_RAFT;
+                break;
+            default:
+                item = Items.OAK_CHEST_BOAT;
+        }
+
+        return item;
     }
 
     @Override
@@ -162,8 +206,7 @@
     }
 
     @Override
-    public void setChanged() {
-    }
+    public void setChanged() {}
 
     @Override
     public boolean stillValid(Player player) {
@@ -173,7 +216,7 @@
     @Nullable
     @Override
     public AbstractContainerMenu createMenu(int syncId, Inventory playerInventory, Player player) {
-        if (this.lootTable != null && player.isSpectator()) {
+        if (this.lootTable != null && player.isSpectator()) { // Paper - LootTable API (TODO spectators can open chests that aren't ready to be re-generated but this doesn't support that)
             return null;
         } else {
             this.unpackLootTable(playerInventory.player);
@@ -218,6 +261,61 @@
 
     @Override
     public void stopOpen(Player player) {
-        this.level().gameEvent(GameEvent.CONTAINER_CLOSE, this.position(), GameEvent.Context.of(player));
+        this.level().gameEvent((Holder) GameEvent.CONTAINER_CLOSE, this.position(), GameEvent.Context.of((Entity) player));
+    }
+
+    // Paper start - LootTable API
+    final com.destroystokyo.paper.loottable.PaperLootableInventoryData lootableData = new com.destroystokyo.paper.loottable.PaperLootableInventoryData();
+
+    @Override
+    public com.destroystokyo.paper.loottable.PaperLootableInventoryData lootableData() {
+        return this.lootableData;
     }
+    // Paper end - LootTable API
+    // CraftBukkit start
+    public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>();
+    private int maxStack = MAX_STACK;
+
+    @Override
+    public List<ItemStack> getContents() {
+        return this.itemStacks;
+    }
+
+    @Override
+    public void onOpen(CraftHumanEntity who) {
+        this.transaction.add(who);
+    }
+
+    @Override
+    public void onClose(CraftHumanEntity who) {
+        this.transaction.remove(who);
+    }
+
+    @Override
+    public List<HumanEntity> getViewers() {
+        return this.transaction;
+    }
+
+    @Override
+    public InventoryHolder getOwner() {
+        org.bukkit.entity.Entity entity = this.getBukkitEntity();
+        if (entity instanceof InventoryHolder) return (InventoryHolder) entity;
+        return null;
+    }
+
+    @Override
+    public int getMaxStackSize() {
+        return this.maxStack;
+    }
+
+    @Override
+    public void setMaxStackSize(int size) {
+        this.maxStack = size;
+    }
+
+    @Override
+    public Location getLocation() {
+        return this.getBukkitEntity().getLocation();
+    }
+    // CraftBukkit end
 }
