--- a/net/minecraft/world/entity/animal/Cat.java
+++ b/net/minecraft/world/entity/animal/Cat.java
@@ -115,7 +_,7 @@
         return this.entityData.get(DATA_VARIANT_ID);
     }
 
-    private void setVariant(Holder<CatVariant> variant) {
+    public void setVariant(Holder<CatVariant> variant) {
         this.entityData.set(DATA_VARIANT_ID, variant);
     }
 
@@ -157,11 +_,11 @@
         return this.entityData.get(IS_LYING);
     }
 
-    void setRelaxStateOne(boolean relaxStateOne) {
+    public void setRelaxStateOne(boolean relaxStateOne) {
         this.entityData.set(RELAX_STATE_ONE, relaxStateOne);
     }
 
-    boolean isRelaxStateOne() {
+    public boolean isRelaxStateOne() {
         return this.entityData.get(RELAX_STATE_ONE);
     }
 
@@ -169,7 +_,7 @@
         return DyeColor.byId(this.entityData.get(DATA_COLLAR_COLOR));
     }
 
-    private void setCollarColor(DyeColor color) {
+    public void setCollarColor(DyeColor color) {
         this.entityData.set(DATA_COLLAR_COLOR, color.getId());
     }
 
@@ -218,7 +_,7 @@
 
     @Nullable
     @Override
-    protected SoundEvent getAmbientSound() {
+    public SoundEvent getAmbientSound() {
         if (this.isTame()) {
             if (this.isInLove()) {
                 return SoundEvents.CAT_PURR;
@@ -240,12 +_,12 @@
     }
 
     @Override
-    protected SoundEvent getHurtSound(DamageSource damageSource) {
+    public SoundEvent getHurtSound(DamageSource damageSource) {
         return SoundEvents.CAT_HURT;
     }
 
     @Override
-    protected SoundEvent getDeathSound() {
+    public SoundEvent getDeathSound() {
         return SoundEvents.CAT_DEATH;
     }
 
@@ -372,6 +_,11 @@
                 if (item instanceof DyeItem dyeItem) {
                     DyeColor dyeColor = dyeItem.getDyeColor();
                     if (dyeColor != this.getCollarColor()) {
+                        // Paper start - Add EntityDyeEvent and CollarColorable interface
+                        final io.papermc.paper.event.entity.EntityDyeEvent event = new io.papermc.paper.event.entity.EntityDyeEvent(this.getBukkitEntity(), org.bukkit.DyeColor.getByWoolData((byte) dyeColor.getId()), ((net.minecraft.server.level.ServerPlayer) player).getBukkitEntity());
+                        if (!event.callEvent()) return InteractionResult.FAIL;
+                        dyeColor = DyeColor.byId(event.getColor().getWoolData());
+                        // Paper end - Add EntityDyeEvent and CollarColorable interface
                         if (!this.level().isClientSide()) {
                             this.setCollarColor(dyeColor);
                             itemInHand.consume(1, player);
@@ -384,7 +_,7 @@
                     if (!this.level().isClientSide()) {
                         this.usePlayerItem(player, hand, itemInHand);
                         FoodProperties foodProperties = itemInHand.get(DataComponents.FOOD);
-                        this.heal(foodProperties != null ? foodProperties.nutrition() : 1.0F);
+                        this.heal(foodProperties != null ? foodProperties.nutrition() : 1.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.EATING); // Paper - Add missing regain reason
                         this.playEatingSound();
                     }
 
@@ -446,7 +_,7 @@
     }
 
     private void tryToTame(Player player) {
-        if (this.random.nextInt(3) == 0) {
+        if (this.random.nextInt(3) == 0 && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, player).isCancelled()) { // CraftBukkit
             this.tame(player);
             this.setOrderedToSit(true);
             this.level().broadcastEntityEvent(this, (byte)7);
@@ -580,15 +_,20 @@
                 .dropFromGiftLootTable(
                     getServerLevel(this.cat),
                     BuiltInLootTables.CAT_MORNING_GIFT,
-                    (level, stack) -> level.addFreshEntity(
-                        new ItemEntity(
+                    // CraftBukkit start
+                    (level, stack) -> {
+                        final ItemEntity item = new ItemEntity(
                             level,
                             (double)mutableBlockPos.getX() - Mth.sin(this.cat.yBodyRot * (float) (Math.PI / 180.0)),
                             mutableBlockPos.getY(),
                             (double)mutableBlockPos.getZ() + Mth.cos(this.cat.yBodyRot * (float) (Math.PI / 180.0)),
                             stack
-                        )
-                    )
+                        );
+                        org.bukkit.event.entity.EntityDropItemEvent event = new org.bukkit.event.entity.EntityDropItemEvent(this.cat.getBukkitEntity(), (org.bukkit.entity.Item) item.getBukkitEntity());
+                        if (!event.callEvent()) return;
+                        level.addFreshEntity(item);
+                    }
+                    // CraftBukkit end
                 );
         }
 
@@ -615,7 +_,7 @@
 
     static class CatTemptGoal extends TemptGoal {
         @Nullable
-        private Player selectedPlayer;
+        private LivingEntity selectedPlayer; // CraftBukkit
         private final Cat cat;
 
         public CatTemptGoal(Cat cat, double speedModifier, Predicate<ItemStack> items, boolean canScare) {
