@@ -1,31 +1,39 @@
package net.momirealms.craftengine.bukkit.util ;
import io.papermc.paper.entity.Shearable ;
import net.momirealms.craftengine.bukkit.item.BukkitItemManager ;
import net.momirealms.craftengine.bukkit.item.behavior.BlockItemBehavior ;
import net.momirealms.craftengine.bukkit.item.recipe.BukkitRecipeManager ;
import net.momirealms.craftengine.core.block.BlockKeys ;
import net.momirealms.craftengine.core.entity.EntityTypeKeys ;
import net.momirealms.craftengine.core.item.Item ;
import net.momirealms.craftengine.core.item.ItemKeys ;
import net.momirealms.craftengine.core.item.behavior.ItemBehavior ;
import net.momirealms.craftengine.core.item.recipe.RecipeTypes ;
import net.momirealms.craftengine.core.item.recipe.UniqueIdItem ;
import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput ;
import net.momirealms.craftengine.core.plugin.CraftEngine ;
import net.momirealms.craftengine.core.plugin.config.Config ;
import net.momirealms.craftengine.core.util.Direction ;
import net.momirealms.craftengine.core.util.Key ;
import net.momirealms.craftengine.core.util.QuadFunction ;
import net.momirealms.craftengine.core.util.* ;
import net.momirealms.craftengine.core.world.BlockHitResult ;
import net.momirealms.craftengine.core.world.BlockPos ;
import org.bukkit.GameMode ;
import org.bukkit.block.data.BlockData ;
import org.bukkit.block.data.Levelled ;
import org.bukkit.block.data.type.Bell ;
import org.bukkit.entity.Player ;
import org.bukkit.block.data.type.ChiseledBookshelf ;
import org.bukkit.block.data.type.RespawnAnchor ;
import org.bukkit.entity.* ;
import org.bukkit.inventory.EquipmentSlot ;
import org.bukkit.inventory.ItemStack ;
import org.jetbrains.annotations.Nullable ;
import java.util.HashMap ;
import java.util.Map ;
import java.util.* ;
public class InteractUtils {
private static final Map < Key , QuadFunction < Player , Item < ItemStack > , BlockData , BlockHitResult , Boolean > > INTERACTIONS = new HashMap < > ( ) ;
private static final Map < Key , QuadFunction < Player , Item < ItemStack > , BlockData , BlockHitResult , Boolean > > WILL_CONSUME = new HashMap < > ( ) ;
private static final Map < Key , TriFunction < Player , Entity , @Nullable Item < ItemStack > , Boolean > > ENTITY_INTERACTIONS = new HashMap < > ( ) ;
private static final Key NOTE_BLOCK_TOP_INSTRUMENTS = Key . of ( " minecraft:noteblock_top_instruments " ) ;
private InteractUtils ( ) { }
@@ -50,6 +58,43 @@ public class InteractUtils {
registerInteraction ( BlockKeys . GREEN_CANDLE_CAKE , ( player , item , blockState , result ) - > ! canEat ( player , false ) ) ;
registerInteraction ( BlockKeys . RED_CANDLE_CAKE , ( player , item , blockState , result ) - > ! canEat ( player , false ) ) ;
registerInteraction ( BlockKeys . BLACK_CANDLE_CAKE , ( player , item , blockState , result ) - > ! canEat ( player , false ) ) ;
registerInteraction ( BlockKeys . COMMAND_BLOCK , ( player , item , blockState , result ) - > player . isOp ( ) & & player . getGameMode ( ) = = GameMode . CREATIVE ) ;
registerInteraction ( BlockKeys . CHAIN_COMMAND_BLOCK , ( player , item , blockState , result ) - > player . isOp ( ) & & player . getGameMode ( ) = = GameMode . CREATIVE ) ;
registerInteraction ( BlockKeys . REPEATING_COMMAND_BLOCK , ( player , item , blockState , result ) - > player . isOp ( ) & & player . getGameMode ( ) = = GameMode . CREATIVE ) ;
registerInteraction ( BlockKeys . JIGSAW , ( player , item , blockState , result ) - > player . isOp ( ) & & player . getGameMode ( ) = = GameMode . CREATIVE ) ;
registerInteraction ( BlockKeys . STRUCTURE_BLOCK , ( player , item , blockState , result ) - > player . isOp ( ) & & player . getGameMode ( ) = = GameMode . CREATIVE ) ;
registerInteraction ( BlockKeys . TEST_INSTANCE_BLOCK , ( player , item , blockState , result ) - > player . isOp ( ) & & player . getGameMode ( ) = = GameMode . CREATIVE ) ;
registerInteraction ( BlockKeys . TEST_BLOCK , ( player , item , blockState , result ) - > player . isOp ( ) & & player . getGameMode ( ) = = GameMode . CREATIVE ) ;
registerInteraction ( BlockKeys . LIGHT , ( player , item , blockState , result ) - > item . vanillaId ( ) . equals ( ItemKeys . LIGHT ) ) ;
registerInteraction ( BlockKeys . LODESTONE , ( player , item , blockState , result ) - > item . vanillaId ( ) . equals ( ItemKeys . COMPASS ) ) ;
registerInteraction ( BlockKeys . BEE_NEST , ( player , item , blockState , result ) - > Set . of ( ItemKeys . SHEARS , ItemKeys . GLASS_BOTTLE ) . contains ( item . vanillaId ( ) ) ) ;
registerInteraction ( BlockKeys . BEEHIVE , ( player , item , blockState , result ) - > Set . of ( ItemKeys . SHEARS , ItemKeys . GLASS_BOTTLE ) . contains ( item . vanillaId ( ) ) ) ;
registerInteraction ( BlockKeys . POWDER_SNOW , ( player , item , blockState , result ) - > item . vanillaId ( ) . equals ( ItemKeys . BUCKET ) ) ;
registerWillConsume ( BlockKeys . CAULDRON , ( player , item , blockState , result ) - > Set . of ( ItemKeys . WATER_BUCKET , ItemKeys . LAVA_BUCKET ) . contains ( item . vanillaId ( ) ) ) ;
registerWillConsume ( BlockKeys . LAVA_CAULDRON , ( player , item , blockState , result ) - > Set . of ( ItemKeys . BUCKET , ItemKeys . WATER_BUCKET , ItemKeys . LAVA_BUCKET ) . contains ( item . vanillaId ( ) ) ) ;
registerInteraction ( BlockKeys . REDSTONE_ORE , ( player , item , blockState , result ) - > {
Optional < List < ItemBehavior > > behaviors = item . getItemBehavior ( ) ;
if ( behaviors . isPresent ( ) ) {
for ( ItemBehavior behavior : behaviors . get ( ) ) {
if ( behavior instanceof BlockItemBehavior ) return false ;
}
}
return true ;
} ) ;
registerInteraction ( BlockKeys . DEEPSLATE_REDSTONE_ORE , ( player , item , blockState , result ) - > {
Optional < List < ItemBehavior > > behaviors = item . getItemBehavior ( ) ;
if ( behaviors . isPresent ( ) ) {
for ( ItemBehavior behavior : behaviors . get ( ) ) {
if ( behavior instanceof BlockItemBehavior ) return false ;
}
}
return true ;
} ) ;
registerWillConsume ( BlockKeys . WATER_CAULDRON , ( player , item , blockState , result ) - > {
if ( blockState instanceof Levelled levelled & & levelled . getLevel ( ) = = levelled . getMaximumLevel ( ) )
return item . vanillaId ( ) . equals ( ItemKeys . BUCKET ) ;
return Set . of ( ItemKeys . GLASS_BOTTLE , ItemKeys . WATER_BUCKET , ItemKeys . LAVA_BUCKET ) . contains ( item . vanillaId ( ) ) ;
} ) ;
registerInteraction ( BlockKeys . BELL , ( player , item , blockState , result ) - > {
Direction direction = result . getDirection ( ) ;
BlockPos pos = result . getBlockPos ( ) ;
@@ -88,7 +133,20 @@ public class InteractUtils {
item . recipeIngredientId ( ) , item
) ) ) ! = null ;
} ) ;
registerInteraction ( BlockKeys . CHISELED_BOOKSHELF , ( player , item , blockState , result ) - > {
if ( ! ( blockState instanceof ChiseledBookshelf chiseledBookshelf ) ) return false ;
return DirectionUtils . toDirection ( chiseledBookshelf . getFacing ( ) ) = = result . getDirection ( ) ;
} ) ;
registerInteraction ( BlockKeys . COMPOSTER , ( player , item , blockState , result ) - > {
if ( item . getItem ( ) . getType ( ) . isCompostable ( ) ) return true ;
return blockState instanceof Levelled levelled & & levelled . getLevel ( ) = = levelled . getMaximumLevel ( ) ;
} ) ;
registerInteraction ( BlockKeys . RESPAWN_ANCHOR , ( player , item , blockState , result ) - > {
if ( item . vanillaId ( ) . equals ( ItemKeys . GLOWSTONE ) ) return true ;
return blockState instanceof RespawnAnchor respawnAnchor & & respawnAnchor . getCharges ( ) ! = 0 ;
} ) ;
registerInteraction ( BlockKeys . DECORATED_POT , ( player , item , blockState , result ) - > true ) ;
registerInteraction ( BlockKeys . FLOWER_POT , ( player , item , blockState , result ) - > true ) ;
registerInteraction ( BlockKeys . HOPPER , ( player , item , blockState , result ) - > true ) ;
registerInteraction ( BlockKeys . DISPENSER , ( player , item , blockState , result ) - > true ) ;
registerInteraction ( BlockKeys . DROPPER , ( player , item , blockState , result ) - > true ) ;
@@ -264,9 +322,6 @@ public class InteractUtils {
registerInteraction ( BlockKeys . RED_BED , ( player , item , blockState , result ) - > true ) ;
registerInteraction ( BlockKeys . BLACK_BED , ( player , item , blockState , result ) - > true ) ;
registerInteraction ( BlockKeys . DRAGON_EGG , ( player , item , blockState , result ) - > true ) ;
registerInteraction ( BlockKeys . REPEATING_COMMAND_BLOCK , ( player , item , blockState , result ) - > true ) ;
registerInteraction ( BlockKeys . CHAIN_COMMAND_BLOCK , ( player , item , blockState , result ) - > true ) ;
registerInteraction ( BlockKeys . COMMAND_BLOCK , ( player , item , blockState , result ) - > true ) ;
}
static {
@@ -274,6 +329,112 @@ public class InteractUtils {
result . getDirection ( ) = = Direction . UP & & item . id ( ) . equals ( ItemKeys . CACTUS ) ) ;
}
static {
registerEntityInteraction ( EntityTypeKeys . BEE , ( player , entity , item ) - > canFeed ( entity , item ) ) ;
registerEntityInteraction ( EntityTypeKeys . FOX , ( player , entity , item ) - > canFeed ( entity , item ) ) ;
registerEntityInteraction ( EntityTypeKeys . FROG , ( player , entity , item ) - > canFeed ( entity , item ) ) ;
registerEntityInteraction ( EntityTypeKeys . PANDA , ( player , entity , item ) - > canFeed ( entity , item ) ) ;
registerEntityInteraction ( EntityTypeKeys . HOGLIN , ( player , entity , item ) - > canFeed ( entity , item ) ) ;
registerEntityInteraction ( EntityTypeKeys . OCELOT , ( player , entity , item ) - > canFeed ( entity , item ) ) ;
registerEntityInteraction ( EntityTypeKeys . RABBIT , ( player , entity , item ) - > canFeed ( entity , item ) ) ;
registerEntityInteraction ( EntityTypeKeys . TURTLE , ( player , entity , item ) - > canFeed ( entity , item ) ) ;
registerEntityInteraction ( EntityTypeKeys . CHICKEN , ( player , entity , item ) - > canFeed ( entity , item ) ) ;
registerEntityInteraction ( EntityTypeKeys . SNIFFER , ( player , entity , item ) - > canFeed ( entity , item ) ) ;
registerEntityInteraction ( EntityTypeKeys . AXOLOTL , ( player , entity , item ) - >
canFeed ( entity , item ) | | ( item ! = null & & item . vanillaId ( ) . equals ( ItemKeys . WATER_BUCKET ) ) ) ;
registerEntityInteraction ( EntityTypeKeys . COD , ( player , entity , item ) - >
item ! = null & & item . vanillaId ( ) . equals ( ItemKeys . WATER_BUCKET ) ) ;
registerEntityInteraction ( EntityTypeKeys . SALMON , ( player , entity , item ) - >
item ! = null & & item . vanillaId ( ) . equals ( ItemKeys . WATER_BUCKET ) ) ;
registerEntityInteraction ( EntityTypeKeys . TROPICAL_FISH , ( player , entity , item ) - >
item ! = null & & item . vanillaId ( ) . equals ( ItemKeys . WATER_BUCKET ) ) ;
registerEntityInteraction ( EntityTypeKeys . PUFFERFISH , ( player , entity , item ) - >
item ! = null & & item . vanillaId ( ) . equals ( ItemKeys . WATER_BUCKET ) ) ;
registerEntityInteraction ( EntityTypeKeys . TADPOLE , ( player , entity , item ) - >
item ! = null & & item . vanillaId ( ) . equals ( ItemKeys . WATER_BUCKET ) ) ;
registerEntityInteraction ( EntityTypeKeys . SNOW_GOLEM , ( player , entity , item ) - >
shearable ( entity , item ) ) ;
registerEntityInteraction ( EntityTypeKeys . SHEEP , ( player , entity , item ) - >
canFeed ( entity , item ) | | shearable ( entity , item ) ) ;
registerEntityInteraction ( EntityTypeKeys . BOGGED , ( player , entity , item ) - >
canFeed ( entity , item ) | | shearable ( entity , item ) ) ;
registerEntityInteraction ( EntityTypeKeys . MOOSHROOM , ( player , entity , item ) - >
canFeed ( entity , item ) | | shearable ( entity , item ) | | ( item ! = null & & ( item . vanillaId ( ) . equals ( ItemKeys . BUCKET ) | | item . vanillaId ( ) . equals ( ItemKeys . BOWL ) ) ) ) ;
registerEntityInteraction ( EntityTypeKeys . COW , ( player , entity , item ) - >
canFeed ( entity , item ) | | ( item ! = null & & item . vanillaId ( ) . equals ( ItemKeys . BUCKET ) ) ) ;
registerEntityInteraction ( EntityTypeKeys . GOAT , ( player , entity , item ) - >
canFeed ( entity , item ) | | ( item ! = null & & item . vanillaId ( ) . equals ( ItemKeys . BUCKET ) ) ) ;
registerEntityInteraction ( EntityTypeKeys . CREEPER , ( player , entity , item ) - >
item ! = null & & item . vanillaId ( ) . equals ( ItemKeys . FLINT_AND_STEEL ) ) ;
registerEntityInteraction ( EntityTypeKeys . PIGLIN , ( player , entity , item ) - >
item ! = null & & item . vanillaId ( ) . equals ( ItemKeys . GOLD_INGOT ) ) ;
registerEntityInteraction ( EntityTypeKeys . ARMADILLO , ( player , entity , item ) - >
canFeed ( entity , item ) | | ( item ! = null & & item . vanillaId ( ) . equals ( ItemKeys . BRUSH ) ) ) ;
registerEntityInteraction ( EntityTypeKeys . ZOMBIE_HORSE , ( player , entity , item ) - >
entity instanceof Tameable tameable & & tameable . isTamed ( ) ) ;
registerEntityInteraction ( EntityTypeKeys . SKELETON_HORSE , ( player , entity , item ) - >
entity instanceof Tameable tameable & & tameable . isTamed ( ) ) ;
registerEntityInteraction ( EntityTypeKeys . PIG , ( player , entity , item ) - >
canFeed ( entity , item ) | | ( hasSaddle ( player , entity ) & & ! player . isSneaking ( ) ) ) ;
registerEntityInteraction ( EntityTypeKeys . STRIDER , ( player , entity , item ) - >
canFeed ( entity , item ) | | ( hasSaddle ( player , entity ) & & ! player . isSneaking ( ) ) ) ;
registerEntityInteraction ( EntityTypeKeys . WOLF , ( player , entity , item ) - > canFeed ( entity , item ) | | isPetOwner ( player , entity ) ) ;
registerEntityInteraction ( EntityTypeKeys . CAT , ( player , entity , item ) - > canFeed ( entity , item ) | | isPetOwner ( player , entity ) ) ;
registerEntityInteraction ( EntityTypeKeys . ACACIA_BOAT , ( player , entity , item ) - > ! player . isSneaking ( ) ) ;
registerEntityInteraction ( EntityTypeKeys . BAMBOO_BOAT , ( player , entity , item ) - > ! player . isSneaking ( ) ) ;
registerEntityInteraction ( EntityTypeKeys . BIRCH_BOAT , ( player , entity , item ) - > ! player . isSneaking ( ) ) ;
registerEntityInteraction ( EntityTypeKeys . CHERRY_BOAT , ( player , entity , item ) - > ! player . isSneaking ( ) ) ;
registerEntityInteraction ( EntityTypeKeys . DARK_OAK_BOAT , ( player , entity , item ) - > ! player . isSneaking ( ) ) ;
registerEntityInteraction ( EntityTypeKeys . JUNGLE_BOAT , ( player , entity , item ) - > ! player . isSneaking ( ) ) ;
registerEntityInteraction ( EntityTypeKeys . MANGROVE_BOAT , ( player , entity , item ) - > ! player . isSneaking ( ) ) ;
registerEntityInteraction ( EntityTypeKeys . OAK_BOAT , ( player , entity , item ) - > ! player . isSneaking ( ) ) ;
registerEntityInteraction ( EntityTypeKeys . SPRUCE_BOAT , ( player , entity , item ) - > ! player . isSneaking ( ) ) ;
registerEntityInteraction ( EntityTypeKeys . MINECART , ( player , entity , item ) - > ! player . isSneaking ( ) ) ;
registerEntityInteraction ( EntityTypeKeys . PARROT , ( player , entity , item ) - > {
if ( item ! = null & & item . is ( Key . of ( " parrot_poisonous_food " ) ) ) return true ;
return canFeed ( entity , item ) | | isPetOwner ( player , entity ) ;
} ) ;
registerEntityInteraction ( EntityTypeKeys . HAPPY_GHAST , ( player , entity , item ) - > {
if ( ! VersionHelper . isOrAbove1_21_6 ( ) ) return false ;
if ( entity instanceof HappyGhast happyGhast & & ! player . isSneaking ( ) ) {
ItemStack bodyItem = happyGhast . getEquipment ( ) . getItem ( EquipmentSlot . BODY ) ;
Item < ItemStack > wrap = BukkitItemManager . instance ( ) . wrap ( bodyItem ) ;
return wrap . is ( Key . of ( " harnesses " ) ) ;
}
return canFeed ( entity , item ) ;
} ) ;
registerEntityInteraction ( EntityTypeKeys . ALLAY , ( player , entity , item ) - > true ) ;
registerEntityInteraction ( EntityTypeKeys . HORSE , ( player , entity , item ) - > true ) ;
registerEntityInteraction ( EntityTypeKeys . DONKEY , ( player , entity , item ) - > true ) ;
registerEntityInteraction ( EntityTypeKeys . MULE , ( player , entity , item ) - > true ) ;
registerEntityInteraction ( EntityTypeKeys . VILLAGER , ( player , entity , item ) - > true ) ;
registerEntityInteraction ( EntityTypeKeys . WANDERING_TRADER , ( player , entity , item ) - > true ) ;
registerEntityInteraction ( EntityTypeKeys . LLAMA , ( player , entity , item ) - > true ) ;
registerEntityInteraction ( EntityTypeKeys . TRADER_LLAMA , ( player , entity , item ) - > true ) ;
registerEntityInteraction ( EntityTypeKeys . CAMEL , ( player , entity , item ) - > true ) ;
registerEntityInteraction ( EntityTypeKeys . ITEM_FRAME , ( player , entity , item ) - > true ) ;
registerEntityInteraction ( EntityTypeKeys . GLOW_ITEM_FRAME , ( player , entity , item ) - > true ) ;
registerEntityInteraction ( EntityTypeKeys . INTERACTION , ( player , entity , item ) - > true ) ;
registerEntityInteraction ( EntityTypeKeys . ACACIA_CHEST_BOAT , ( player , entity , item ) - > true ) ;
registerEntityInteraction ( EntityTypeKeys . BAMBOO_CHEST_BOAT , ( player , entity , item ) - > true ) ;
registerEntityInteraction ( EntityTypeKeys . BIRCH_CHEST_BOAT , ( player , entity , item ) - > true ) ;
registerEntityInteraction ( EntityTypeKeys . CHERRY_CHEST_BOAT , ( player , entity , item ) - > true ) ;
registerEntityInteraction ( EntityTypeKeys . DARK_OAK_CHEST_BOAT , ( player , entity , item ) - > true ) ;
registerEntityInteraction ( EntityTypeKeys . JUNGLE_CHEST_BOAT , ( player , entity , item ) - > true ) ;
registerEntityInteraction ( EntityTypeKeys . MANGROVE_CHEST_BOAT , ( player , entity , item ) - > true ) ;
registerEntityInteraction ( EntityTypeKeys . OAK_CHEST_BOAT , ( player , entity , item ) - > true ) ;
registerEntityInteraction ( EntityTypeKeys . SPRUCE_CHEST_BOAT , ( player , entity , item ) - > true ) ;
registerEntityInteraction ( EntityTypeKeys . CHEST_MINECART , ( player , entity , item ) - > true ) ;
registerEntityInteraction ( EntityTypeKeys . FURNACE_MINECART , ( player , entity , item ) - > true ) ;
registerEntityInteraction ( EntityTypeKeys . HOPPER_MINECART , ( player , entity , item ) - > true ) ;
registerEntityInteraction ( EntityTypeKeys . COMMAND_BLOCK_MINECART , ( player , entity , item ) - > true ) ;
//< 1.20.5
registerEntityInteraction ( EntityTypeKeys . MINECART_CHEST , ( player , entity , item ) - > true ) ;
registerEntityInteraction ( EntityTypeKeys . MINECART_HOPPER , ( player , entity , item ) - > true ) ;
registerEntityInteraction ( EntityTypeKeys . MINECART_FURNACE , ( player , entity , item ) - > true ) ;
registerEntityInteraction ( EntityTypeKeys . MINECART_COMMAND , ( player , entity , item ) - > true ) ;
}
private static void registerInteraction ( Key key , QuadFunction < org . bukkit . entity . Player , Item < ItemStack > , BlockData , BlockHitResult , Boolean > function ) {
var previous = INTERACTIONS . put ( key , function ) ;
if ( previous ! = null ) {
@@ -288,6 +449,13 @@ public class InteractUtils {
}
}
private static void registerEntityInteraction ( Key key , TriFunction < Player , Entity , @Nullable Item < ItemStack > , Boolean > function ) {
var previous = ENTITY_INTERACTIONS . put ( key , function ) ;
if ( previous ! = null ) {
CraftEngine . instance ( ) . logger ( ) . warn ( " Duplicated entity interaction check: " + key ) ;
}
}
public static boolean isInteractable ( Player player , BlockData state , BlockHitResult hit , @Nullable Item < ItemStack > item ) {
Key blockType = BlockStateUtils . getBlockOwnerIdFromData ( state ) ;
if ( INTERACTIONS . containsKey ( blockType ) ) {
@@ -297,6 +465,12 @@ public class InteractUtils {
}
}
public static boolean isEntityInteractable ( Player player , Entity entity , @Nullable Item < ItemStack > item ) {
Key key = Key . of ( String . valueOf ( entity . getType ( ) ) ) ;
TriFunction < Player , Entity , Item < ItemStack > , Boolean > func = ENTITY_INTERACTIONS . get ( key ) ;
return func ! = null & & func . apply ( player , entity , item ) ;
}
public static boolean willConsume ( Player player , BlockData state , BlockHitResult hit , @Nullable Item < ItemStack > item ) {
if ( item = = null ) return false ;
Key blockType = BlockStateUtils . getBlockOwnerIdFromData ( state ) ;
@@ -306,8 +480,24 @@ public class InteractUtils {
return false ;
}
}
private static boolean canEat ( Player player , boolean ignoreHunger ) {
return ignoreHunger | | player . isInvulnerable ( ) | | player . getFoodLevel ( ) < 20 ;
}
private static boolean canFeed ( Entity entity , Item < ItemStack > item ) {
return entity instanceof Animals animals & & item . is ( Key . of ( animals . getType ( ) . toString ( ) . toLowerCase ( ) + " _food " ) ) ;
}
private static boolean hasSaddle ( Player player , Entity entity ) {
return entity instanceof Steerable steerable & & steerable . hasSaddle ( ) & & ! player . isSneaking ( ) ;
}
private static boolean shearable ( Entity entity , Item < ItemStack > item ) {
return entity instanceof Shearable shearable & & item . vanillaId ( ) . equals ( ItemKeys . SHEARS ) & & shearable . readyToBeSheared ( ) ;
}
private static boolean isPetOwner ( Player player , Entity entity ) {
return entity instanceof Tameable tameable & & tameable . isTamed ( ) & & player . getUniqueId ( ) . equals ( tameable . getOwnerUniqueId ( ) ) ;
}
}