package net.minecraft.world.entity.monster.piglin; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.mojang.datafixers.util.Pair; import java.util.Collections; import java.util.List; import java.util.Optional; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; import net.minecraft.tags.ItemTags; import net.minecraft.util.RandomSource; import net.minecraft.util.TimeUtil; import net.minecraft.util.valueproviders.UniformInt; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.EquipmentSlotGroup; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.PathfinderMob; import net.minecraft.world.entity.ai.Brain; import net.minecraft.world.entity.ai.behavior.BackUpIfTooClose; import net.minecraft.world.entity.ai.behavior.BehaviorControl; import net.minecraft.world.entity.ai.behavior.BehaviorUtils; import net.minecraft.world.entity.ai.behavior.CopyMemoryWithExpiry; import net.minecraft.world.entity.ai.behavior.CrossbowAttack; import net.minecraft.world.entity.ai.behavior.DismountOrSkipMounting; import net.minecraft.world.entity.ai.behavior.DoNothing; import net.minecraft.world.entity.ai.behavior.EraseMemoryIf; import net.minecraft.world.entity.ai.behavior.GoToTargetLocation; import net.minecraft.world.entity.ai.behavior.GoToWantedItem; import net.minecraft.world.entity.ai.behavior.InteractWith; import net.minecraft.world.entity.ai.behavior.InteractWithDoor; import net.minecraft.world.entity.ai.behavior.LookAtTargetSink; import net.minecraft.world.entity.ai.behavior.MeleeAttack; import net.minecraft.world.entity.ai.behavior.Mount; import net.minecraft.world.entity.ai.behavior.MoveToTargetSink; import net.minecraft.world.entity.ai.behavior.OneShot; import net.minecraft.world.entity.ai.behavior.RandomStroll; import net.minecraft.world.entity.ai.behavior.RunOne; import net.minecraft.world.entity.ai.behavior.SetEntityLookTarget; import net.minecraft.world.entity.ai.behavior.SetEntityLookTargetSometimes; import net.minecraft.world.entity.ai.behavior.SetLookAndInteract; import net.minecraft.world.entity.ai.behavior.SetWalkTargetAwayFrom; import net.minecraft.world.entity.ai.behavior.SetWalkTargetFromAttackTargetIfTargetOutOfReach; import net.minecraft.world.entity.ai.behavior.SetWalkTargetFromLookTarget; import net.minecraft.world.entity.ai.behavior.StartAttacking; import net.minecraft.world.entity.ai.behavior.StartCelebratingIfTargetDead; import net.minecraft.world.entity.ai.behavior.StopAttackingIfTargetInvalid; import net.minecraft.world.entity.ai.behavior.StopBeingAngryIfTargetDead; import net.minecraft.world.entity.ai.behavior.TriggerGate; import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder; import net.minecraft.world.entity.ai.behavior.declarative.Trigger; import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.sensing.Sensor; import net.minecraft.world.entity.ai.util.LandRandomPos; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.monster.hoglin.Hoglin; import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.schedule.Activity; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.level.GameRules; import net.minecraft.world.level.storage.loot.BuiltInLootTables; import net.minecraft.world.level.storage.loot.LootParams; import net.minecraft.world.level.storage.loot.LootTable; import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets; import net.minecraft.world.level.storage.loot.parameters.LootContextParams; import net.minecraft.world.phys.Vec3; public class PiglinAi { public static final int REPELLENT_DETECTION_RANGE_HORIZONTAL = 8; public static final int REPELLENT_DETECTION_RANGE_VERTICAL = 4; public static final Item BARTERING_ITEM = Items.GOLD_INGOT; private static final int PLAYER_ANGER_RANGE = 16; private static final int ANGER_DURATION = 600; private static final int ADMIRE_DURATION = 119; private static final int MAX_DISTANCE_TO_WALK_TO_ITEM = 9; private static final int MAX_TIME_TO_WALK_TO_ITEM = 200; private static final int HOW_LONG_TIME_TO_DISABLE_ADMIRE_WALKING_IF_CANT_REACH_ITEM = 200; private static final int CELEBRATION_TIME = 300; protected static final UniformInt TIME_BETWEEN_HUNTS = TimeUtil.rangeOfSeconds(30, 120); private static final int BABY_FLEE_DURATION_AFTER_GETTING_HIT = 100; private static final int HIT_BY_PLAYER_MEMORY_TIMEOUT = 400; private static final int MAX_WALK_DISTANCE_TO_START_RIDING = 8; private static final UniformInt RIDE_START_INTERVAL = TimeUtil.rangeOfSeconds(10, 40); private static final UniformInt RIDE_DURATION = TimeUtil.rangeOfSeconds(10, 30); private static final UniformInt RETREAT_DURATION = TimeUtil.rangeOfSeconds(5, 20); private static final int MELEE_ATTACK_COOLDOWN = 20; private static final int EAT_COOLDOWN = 200; private static final int DESIRED_DISTANCE_FROM_ENTITY_WHEN_AVOIDING = 12; private static final int MAX_LOOK_DIST = 8; private static final int MAX_LOOK_DIST_FOR_PLAYER_HOLDING_LOVED_ITEM = 14; private static final int INTERACTION_RANGE = 8; private static final int MIN_DESIRED_DIST_FROM_TARGET_WHEN_HOLDING_CROSSBOW = 5; private static final float SPEED_WHEN_STRAFING_BACK_FROM_TARGET = 0.75F; private static final int DESIRED_DISTANCE_FROM_ZOMBIFIED = 6; private static final UniformInt AVOID_ZOMBIFIED_DURATION = TimeUtil.rangeOfSeconds(5, 7); private static final UniformInt BABY_AVOID_NEMESIS_DURATION = TimeUtil.rangeOfSeconds(5, 7); private static final float PROBABILITY_OF_CELEBRATION_DANCE = 0.1F; private static final float SPEED_MULTIPLIER_WHEN_AVOIDING = 1.0F; private static final float SPEED_MULTIPLIER_WHEN_RETREATING = 1.0F; private static final float SPEED_MULTIPLIER_WHEN_MOUNTING = 0.8F; private static final float SPEED_MULTIPLIER_WHEN_GOING_TO_WANTED_ITEM = 1.0F; private static final float SPEED_MULTIPLIER_WHEN_GOING_TO_CELEBRATE_LOCATION = 1.0F; private static final float SPEED_MULTIPLIER_WHEN_DANCING = 0.6F; private static final float SPEED_MULTIPLIER_WHEN_IDLING = 0.6F; protected static Brain makeBrain(Piglin p_34841_, Brain p_34842_) { initCoreActivity(p_34842_); initIdleActivity(p_34842_); initAdmireItemActivity(p_34842_); initFightActivity(p_34841_, p_34842_); initCelebrateActivity(p_34842_); initRetreatActivity(p_34842_); initRideHoglinActivity(p_34842_); p_34842_.setCoreActivities(ImmutableSet.of(Activity.CORE)); p_34842_.setDefaultActivity(Activity.IDLE); p_34842_.useDefaultActivity(); return p_34842_; } protected static void initMemories(Piglin p_219206_, RandomSource p_219207_) { int i = TIME_BETWEEN_HUNTS.sample(p_219207_); p_219206_.getBrain().setMemoryWithExpiry(MemoryModuleType.HUNTED_RECENTLY, true, i); } private static void initCoreActivity(Brain p_34821_) { p_34821_.addActivity( Activity.CORE, 0, ImmutableList.of( new LookAtTargetSink(45, 90), new MoveToTargetSink(), InteractWithDoor.create(), babyAvoidNemesis(), avoidZombified(), StopHoldingItemIfNoLongerAdmiring.create(), StartAdmiringItemIfSeen.create(119), StartCelebratingIfTargetDead.create(300, PiglinAi::wantsToDance), StopBeingAngryIfTargetDead.create() ) ); } private static void initIdleActivity(Brain p_34892_) { p_34892_.addActivity( Activity.IDLE, 10, ImmutableList.of( SetEntityLookTarget.create(PiglinAi::isPlayerHoldingLovedItem, 14.0F), StartAttacking.create((p_390707_, p_390708_) -> p_390708_.isAdult(), PiglinAi::findNearestValidAttackTarget), BehaviorBuilder.triggerIf(Piglin::canHunt, StartHuntingHoglin.create()), avoidRepellent(), babySometimesRideBabyHoglin(), createIdleLookBehaviors(), createIdleMovementBehaviors(), SetLookAndInteract.create(EntityType.PLAYER, 4) ) ); } private static void initFightActivity(Piglin p_34904_, Brain p_34905_) { p_34905_.addActivityAndRemoveMemoryWhenStopped( Activity.FIGHT, 10, ImmutableList.of( StopAttackingIfTargetInvalid.create((p_359284_, p_359285_) -> !isNearestValidAttackTarget(p_359284_, p_34904_, p_359285_)), BehaviorBuilder.triggerIf(PiglinAi::hasCrossbow, BackUpIfTooClose.create(5, 0.75F)), SetWalkTargetFromAttackTargetIfTargetOutOfReach.create(1.0F), MeleeAttack.create(20), new CrossbowAttack<>(), RememberIfHoglinWasKilled.create(), EraseMemoryIf.create(PiglinAi::isNearZombified, MemoryModuleType.ATTACK_TARGET) ), MemoryModuleType.ATTACK_TARGET ); } private static void initCelebrateActivity(Brain p_34921_) { p_34921_.addActivityAndRemoveMemoryWhenStopped( Activity.CELEBRATE, 10, ImmutableList.of( avoidRepellent(), SetEntityLookTarget.create(PiglinAi::isPlayerHoldingLovedItem, 14.0F), StartAttacking.create((p_390705_, p_390706_) -> p_390706_.isAdult(), PiglinAi::findNearestValidAttackTarget), BehaviorBuilder.triggerIf(p_34804_ -> !p_34804_.isDancing(), GoToTargetLocation.create(MemoryModuleType.CELEBRATE_LOCATION, 2, 1.0F)), BehaviorBuilder.triggerIf(Piglin::isDancing, GoToTargetLocation.create(MemoryModuleType.CELEBRATE_LOCATION, 4, 0.6F)), new RunOne( ImmutableList.of( Pair.of(SetEntityLookTarget.create(EntityType.PIGLIN, 8.0F), 1), Pair.of((BehaviorControl)(BehaviorControl)RandomStroll.stroll(0.6F, 2, 1), 1), Pair.of(new DoNothing(10, 20), 1) ) ) ), MemoryModuleType.CELEBRATE_LOCATION ); } private static void initAdmireItemActivity(Brain p_34941_) { p_34941_.addActivityAndRemoveMemoryWhenStopped( Activity.ADMIRE_ITEM, 10, ImmutableList.of( GoToWantedItem.create(PiglinAi::isNotHoldingLovedItemInOffHand, 1.0F, true, 9), StopAdmiringIfItemTooFarAway.create(9), StopAdmiringIfTiredOfTryingToReachItem.create(200, 200) ), MemoryModuleType.ADMIRING_ITEM ); } private static void initRetreatActivity(Brain p_34959_) { p_34959_.addActivityAndRemoveMemoryWhenStopped( Activity.AVOID, 10, ImmutableList.of( SetWalkTargetAwayFrom.entity(MemoryModuleType.AVOID_TARGET, 1.0F, 12, true), createIdleLookBehaviors(), createIdleMovementBehaviors(), EraseMemoryIf.create(PiglinAi::wantsToStopFleeing, MemoryModuleType.AVOID_TARGET) ), MemoryModuleType.AVOID_TARGET ); } private static void initRideHoglinActivity(Brain p_34974_) { p_34974_.addActivityAndRemoveMemoryWhenStopped( Activity.RIDE, 10, ImmutableList.of( Mount.create(0.8F), SetEntityLookTarget.create(PiglinAi::isPlayerHoldingLovedItem, 8.0F), BehaviorBuilder.sequence( BehaviorBuilder.triggerIf(Entity::isPassenger), TriggerGate.triggerOneShuffled( ImmutableList., Integer>>builder() .addAll(createLookBehaviors()) .add(Pair.of(BehaviorBuilder.triggerIf(p_258950_ -> true), 1)) .build() ) ), DismountOrSkipMounting.create(8, PiglinAi::wantsToStopRiding) ), MemoryModuleType.RIDE_TARGET ); } private static ImmutableList, Integer>> createLookBehaviors() { return ImmutableList.of( Pair.of(SetEntityLookTarget.create(EntityType.PLAYER, 8.0F), 1), Pair.of(SetEntityLookTarget.create(EntityType.PIGLIN, 8.0F), 1), Pair.of(SetEntityLookTarget.create(8.0F), 1) ); } private static RunOne createIdleLookBehaviors() { return new RunOne<>( ImmutableList., Integer>>builder() .addAll(createLookBehaviors()) .add(Pair.of(new DoNothing(30, 60), 1)) .build() ); } private static RunOne createIdleMovementBehaviors() { return new RunOne<>( ImmutableList.of( Pair.of(RandomStroll.stroll(0.6F), 2), Pair.of(InteractWith.of(EntityType.PIGLIN, 8, MemoryModuleType.INTERACTION_TARGET, 0.6F, 2), 2), Pair.of(BehaviorBuilder.triggerIf(PiglinAi::doesntSeeAnyPlayerHoldingLovedItem, SetWalkTargetFromLookTarget.create(0.6F, 3)), 2), Pair.of(new DoNothing(30, 60), 1) ) ); } private static BehaviorControl avoidRepellent() { return SetWalkTargetAwayFrom.pos(MemoryModuleType.NEAREST_REPELLENT, 1.0F, 8, false); } private static BehaviorControl babyAvoidNemesis() { return CopyMemoryWithExpiry.create(Piglin::isBaby, MemoryModuleType.NEAREST_VISIBLE_NEMESIS, MemoryModuleType.AVOID_TARGET, BABY_AVOID_NEMESIS_DURATION); } private static BehaviorControl avoidZombified() { return CopyMemoryWithExpiry.create(PiglinAi::isNearZombified, MemoryModuleType.NEAREST_VISIBLE_ZOMBIFIED, MemoryModuleType.AVOID_TARGET, AVOID_ZOMBIFIED_DURATION); } protected static void updateActivity(Piglin p_34899_) { Brain brain = p_34899_.getBrain(); Activity activity = brain.getActiveNonCoreActivity().orElse(null); brain.setActiveActivityToFirstValid(ImmutableList.of(Activity.ADMIRE_ITEM, Activity.FIGHT, Activity.AVOID, Activity.CELEBRATE, Activity.RIDE, Activity.IDLE)); Activity activity1 = brain.getActiveNonCoreActivity().orElse(null); if (activity != activity1) { getSoundForCurrentActivity(p_34899_).ifPresent(p_34899_::makeSound); } p_34899_.setAggressive(brain.hasMemoryValue(MemoryModuleType.ATTACK_TARGET)); if (!brain.hasMemoryValue(MemoryModuleType.RIDE_TARGET) && isBabyRidingBaby(p_34899_)) { p_34899_.stopRiding(); } if (!brain.hasMemoryValue(MemoryModuleType.CELEBRATE_LOCATION)) { brain.eraseMemory(MemoryModuleType.DANCING); } p_34899_.setDancing(brain.hasMemoryValue(MemoryModuleType.DANCING)); } private static boolean isBabyRidingBaby(Piglin p_34993_) { if (!p_34993_.isBaby()) { return false; } else { Entity entity = p_34993_.getVehicle(); return entity instanceof Piglin && ((Piglin)entity).isBaby() || entity instanceof Hoglin && ((Hoglin)entity).isBaby(); } } protected static void pickUpItem(ServerLevel p_363619_, Piglin p_34844_, ItemEntity p_34845_) { stopWalking(p_34844_); ItemStack itemstack; if (p_34845_.getItem().is(Items.GOLD_NUGGET)) { p_34844_.take(p_34845_, p_34845_.getItem().getCount()); itemstack = p_34845_.getItem(); p_34845_.discard(); } else { p_34844_.take(p_34845_, 1); itemstack = removeOneItemFromItemEntity(p_34845_); } if (isLovedItem(itemstack)) { p_34844_.getBrain().eraseMemory(MemoryModuleType.TIME_TRYING_TO_REACH_ADMIRE_ITEM); holdInOffhand(p_363619_, p_34844_, itemstack); admireGoldItem(p_34844_); } else if (isFood(itemstack) && !hasEatenRecently(p_34844_)) { eat(p_34844_); } else { boolean flag = !p_34844_.equipItemIfPossible(p_363619_, itemstack).equals(ItemStack.EMPTY); if (!flag) { putInInventory(p_34844_, itemstack); } } } private static void holdInOffhand(ServerLevel p_363193_, Piglin p_34933_, ItemStack p_34934_) { if (isHoldingItemInOffHand(p_34933_)) { p_34933_.spawnAtLocation(p_363193_, p_34933_.getItemInHand(InteractionHand.OFF_HAND)); } p_34933_.holdInOffHand(p_34934_); } private static ItemStack removeOneItemFromItemEntity(ItemEntity p_34823_) { ItemStack itemstack = p_34823_.getItem(); ItemStack itemstack1 = itemstack.split(1); if (itemstack.isEmpty()) { p_34823_.discard(); } else { p_34823_.setItem(itemstack); } return itemstack1; } protected static void stopHoldingOffHandItem(ServerLevel p_367801_, Piglin p_34868_, boolean p_34869_) { ItemStack itemstack = p_34868_.getItemInHand(InteractionHand.OFF_HAND); p_34868_.setItemInHand(InteractionHand.OFF_HAND, ItemStack.EMPTY); if (p_34868_.isAdult()) { boolean flag = isBarterCurrency(itemstack); if (p_34869_ && flag) { throwItems(p_34868_, getBarterResponseItems(p_34868_)); } else if (!flag) { boolean flag1 = !p_34868_.equipItemIfPossible(p_367801_, itemstack).isEmpty(); if (!flag1) { putInInventory(p_34868_, itemstack); } } } else { boolean flag2 = !p_34868_.equipItemIfPossible(p_367801_, itemstack).isEmpty(); if (!flag2) { ItemStack itemstack1 = p_34868_.getMainHandItem(); if (isLovedItem(itemstack1)) { putInInventory(p_34868_, itemstack1); } else { throwItems(p_34868_, Collections.singletonList(itemstack1)); } p_34868_.holdInMainHand(itemstack); } } } protected static void cancelAdmiring(ServerLevel p_368810_, Piglin p_34928_) { if (isAdmiringItem(p_34928_) && !p_34928_.getOffhandItem().isEmpty()) { p_34928_.spawnAtLocation(p_368810_, p_34928_.getOffhandItem()); p_34928_.setItemInHand(InteractionHand.OFF_HAND, ItemStack.EMPTY); } } private static void putInInventory(Piglin p_34953_, ItemStack p_34954_) { ItemStack itemstack = p_34953_.addToInventory(p_34954_); throwItemsTowardRandomPos(p_34953_, Collections.singletonList(itemstack)); } private static void throwItems(Piglin p_34861_, List p_34862_) { Optional optional = p_34861_.getBrain().getMemory(MemoryModuleType.NEAREST_VISIBLE_PLAYER); if (optional.isPresent()) { throwItemsTowardPlayer(p_34861_, optional.get(), p_34862_); } else { throwItemsTowardRandomPos(p_34861_, p_34862_); } } private static void throwItemsTowardRandomPos(Piglin p_34913_, List p_34914_) { throwItemsTowardPos(p_34913_, p_34914_, getRandomNearbyPos(p_34913_)); } private static void throwItemsTowardPlayer(Piglin p_34851_, Player p_34852_, List p_34853_) { throwItemsTowardPos(p_34851_, p_34853_, p_34852_.position()); } private static void throwItemsTowardPos(Piglin p_34864_, List p_34865_, Vec3 p_34866_) { if (!p_34865_.isEmpty()) { p_34864_.swing(InteractionHand.OFF_HAND); for (ItemStack itemstack : p_34865_) { BehaviorUtils.throwItem(p_34864_, itemstack, p_34866_.add(0.0, 1.0, 0.0)); } } } private static List getBarterResponseItems(Piglin p_34997_) { LootTable loottable = p_34997_.level().getServer().reloadableRegistries().getLootTable(BuiltInLootTables.PIGLIN_BARTERING); List list = loottable.getRandomItems( new LootParams.Builder((ServerLevel)p_34997_.level()).withParameter(LootContextParams.THIS_ENTITY, p_34997_).create(LootContextParamSets.PIGLIN_BARTER) ); return list; } private static boolean wantsToDance(LivingEntity p_34811_, LivingEntity p_34812_) { return p_34812_.getType() != EntityType.HOGLIN ? false : RandomSource.create(p_34811_.level().getGameTime()).nextFloat() < 0.1F; } protected static boolean wantsToPickup(Piglin p_34858_, ItemStack p_34859_) { if (p_34858_.isBaby() && p_34859_.is(ItemTags.IGNORED_BY_PIGLIN_BABIES)) { return false; } else if (p_34859_.is(ItemTags.PIGLIN_REPELLENTS)) { return false; } else if (isAdmiringDisabled(p_34858_) && p_34858_.getBrain().hasMemoryValue(MemoryModuleType.ATTACK_TARGET)) { return false; } else if (isBarterCurrency(p_34859_)) { return isNotHoldingLovedItemInOffHand(p_34858_); } else { boolean flag = p_34858_.canAddToInventory(p_34859_); if (p_34859_.is(Items.GOLD_NUGGET)) { return flag; } else if (isFood(p_34859_)) { return !hasEatenRecently(p_34858_) && flag; } else { return !isLovedItem(p_34859_) ? p_34858_.canReplaceCurrentItem(p_34859_) : isNotHoldingLovedItemInOffHand(p_34858_) && flag; } } } protected static boolean isLovedItem(ItemStack p_149966_) { return p_149966_.is(ItemTags.PIGLIN_LOVED); } private static boolean wantsToStopRiding(Piglin p_34835_, Entity p_34836_) { return !(p_34836_ instanceof Mob mob) ? false : !mob.isBaby() || !mob.isAlive() || wasHurtRecently(p_34835_) || wasHurtRecently(mob) || mob instanceof Piglin && mob.getVehicle() == null; } private static boolean isNearestValidAttackTarget(ServerLevel p_362158_, Piglin p_34901_, LivingEntity p_34902_) { return findNearestValidAttackTarget(p_362158_, p_34901_).filter(p_34887_ -> p_34887_ == p_34902_).isPresent(); } private static boolean isNearZombified(Piglin p_34999_) { Brain brain = p_34999_.getBrain(); if (brain.hasMemoryValue(MemoryModuleType.NEAREST_VISIBLE_ZOMBIFIED)) { LivingEntity livingentity = brain.getMemory(MemoryModuleType.NEAREST_VISIBLE_ZOMBIFIED).get(); return p_34999_.closerThan(livingentity, 6.0); } else { return false; } } private static Optional findNearestValidAttackTarget(ServerLevel p_368686_, Piglin p_35001_) { Brain brain = p_35001_.getBrain(); if (isNearZombified(p_35001_)) { return Optional.empty(); } else { Optional optional = BehaviorUtils.getLivingEntityFromUUIDMemory(p_35001_, MemoryModuleType.ANGRY_AT); if (optional.isPresent() && Sensor.isEntityAttackableIgnoringLineOfSight(p_368686_, p_35001_, optional.get())) { return optional; } else { if (brain.hasMemoryValue(MemoryModuleType.UNIVERSAL_ANGER)) { Optional optional1 = brain.getMemory(MemoryModuleType.NEAREST_VISIBLE_ATTACKABLE_PLAYER); if (optional1.isPresent()) { return optional1; } } Optional optional3 = brain.getMemory(MemoryModuleType.NEAREST_VISIBLE_NEMESIS); if (optional3.isPresent()) { return optional3; } else { Optional optional2 = brain.getMemory(MemoryModuleType.NEAREST_TARGETABLE_PLAYER_NOT_WEARING_GOLD); return optional2.isPresent() && Sensor.isEntityAttackable(p_368686_, p_35001_, optional2.get()) ? optional2 : Optional.empty(); } } } } public static void angerNearbyPiglins(ServerLevel p_362859_, Player p_34874_, boolean p_34875_) { List list = p_34874_.level().getEntitiesOfClass(Piglin.class, p_34874_.getBoundingBox().inflate(16.0)); list.stream().filter(PiglinAi::isIdle).filter(p_34881_ -> !p_34875_ || BehaviorUtils.canSee(p_34881_, p_34874_)).forEach(p_359282_ -> { if (p_362859_.getGameRules().getBoolean(GameRules.RULE_UNIVERSAL_ANGER)) { setAngerTargetToNearestTargetablePlayerIfFound(p_362859_, p_359282_, p_34874_); } else { setAngerTarget(p_362859_, p_359282_, p_34874_); } }); } public static InteractionResult mobInteract(ServerLevel p_362693_, Piglin p_34847_, Player p_34848_, InteractionHand p_34849_) { ItemStack itemstack = p_34848_.getItemInHand(p_34849_); if (canAdmire(p_34847_, itemstack)) { ItemStack itemstack1 = itemstack.consumeAndReturn(1, p_34848_); holdInOffhand(p_362693_, p_34847_, itemstack1); admireGoldItem(p_34847_); stopWalking(p_34847_); return InteractionResult.SUCCESS; } else { return InteractionResult.PASS; } } protected static boolean canAdmire(Piglin p_34910_, ItemStack p_34911_) { return !isAdmiringDisabled(p_34910_) && !isAdmiringItem(p_34910_) && p_34910_.isAdult() && isBarterCurrency(p_34911_); } protected static void wasHurtBy(ServerLevel p_361749_, Piglin p_34838_, LivingEntity p_34839_) { if (!(p_34839_ instanceof Piglin)) { if (isHoldingItemInOffHand(p_34838_)) { stopHoldingOffHandItem(p_361749_, p_34838_, false); } Brain brain = p_34838_.getBrain(); brain.eraseMemory(MemoryModuleType.CELEBRATE_LOCATION); brain.eraseMemory(MemoryModuleType.DANCING); brain.eraseMemory(MemoryModuleType.ADMIRING_ITEM); if (p_34839_ instanceof Player) { brain.setMemoryWithExpiry(MemoryModuleType.ADMIRING_DISABLED, true, 400L); } getAvoidTarget(p_34838_).ifPresent(p_390701_ -> { if (p_390701_.getType() != p_34839_.getType()) { brain.eraseMemory(MemoryModuleType.AVOID_TARGET); } }); if (p_34838_.isBaby()) { brain.setMemoryWithExpiry(MemoryModuleType.AVOID_TARGET, p_34839_, 100L); if (Sensor.isEntityAttackableIgnoringLineOfSight(p_361749_, p_34838_, p_34839_)) { broadcastAngerTarget(p_361749_, p_34838_, p_34839_); } } else if (p_34839_.getType() == EntityType.HOGLIN && hoglinsOutnumberPiglins(p_34838_)) { setAvoidTargetAndDontHuntForAWhile(p_34838_, p_34839_); broadcastRetreat(p_34838_, p_34839_); } else { maybeRetaliate(p_361749_, p_34838_, p_34839_); } } } protected static void maybeRetaliate(ServerLevel p_362623_, AbstractPiglin p_34827_, LivingEntity p_34828_) { if (!p_34827_.getBrain().isActive(Activity.AVOID)) { if (Sensor.isEntityAttackableIgnoringLineOfSight(p_362623_, p_34827_, p_34828_)) { if (!BehaviorUtils.isOtherTargetMuchFurtherAwayThanCurrentAttackTarget(p_34827_, p_34828_, 4.0)) { if (p_34828_.getType() == EntityType.PLAYER && p_362623_.getGameRules().getBoolean(GameRules.RULE_UNIVERSAL_ANGER)) { setAngerTargetToNearestTargetablePlayerIfFound(p_362623_, p_34827_, p_34828_); broadcastUniversalAnger(p_362623_, p_34827_); } else { setAngerTarget(p_362623_, p_34827_, p_34828_); broadcastAngerTarget(p_362623_, p_34827_, p_34828_); } } } } } public static Optional getSoundForCurrentActivity(Piglin p_34948_) { return p_34948_.getBrain().getActiveNonCoreActivity().map(p_34908_ -> getSoundForActivity(p_34948_, p_34908_)); } private static SoundEvent getSoundForActivity(Piglin p_34855_, Activity p_34856_) { if (p_34856_ == Activity.FIGHT) { return SoundEvents.PIGLIN_ANGRY; } else if (p_34855_.isConverting()) { return SoundEvents.PIGLIN_RETREAT; } else if (p_34856_ == Activity.AVOID && isNearAvoidTarget(p_34855_)) { return SoundEvents.PIGLIN_RETREAT; } else if (p_34856_ == Activity.ADMIRE_ITEM) { return SoundEvents.PIGLIN_ADMIRING_ITEM; } else if (p_34856_ == Activity.CELEBRATE) { return SoundEvents.PIGLIN_CELEBRATE; } else if (seesPlayerHoldingLovedItem(p_34855_)) { return SoundEvents.PIGLIN_JEALOUS; } else { return isNearRepellent(p_34855_) ? SoundEvents.PIGLIN_RETREAT : SoundEvents.PIGLIN_AMBIENT; } } private static boolean isNearAvoidTarget(Piglin p_35003_) { Brain brain = p_35003_.getBrain(); return !brain.hasMemoryValue(MemoryModuleType.AVOID_TARGET) ? false : brain.getMemory(MemoryModuleType.AVOID_TARGET).get().closerThan(p_35003_, 12.0); } protected static List getVisibleAdultPiglins(Piglin p_35005_) { return p_35005_.getBrain().getMemory(MemoryModuleType.NEAREST_VISIBLE_ADULT_PIGLINS).orElse(ImmutableList.of()); } private static List getAdultPiglins(AbstractPiglin p_34961_) { return p_34961_.getBrain().getMemory(MemoryModuleType.NEARBY_ADULT_PIGLINS).orElse(ImmutableList.of()); } public static boolean isWearingSafeArmor(LivingEntity p_365495_) { for (EquipmentSlot equipmentslot : EquipmentSlotGroup.ARMOR) { if (p_365495_.getItemBySlot(equipmentslot).is(ItemTags.PIGLIN_SAFE_ARMOR)) { return true; } } return false; } private static void stopWalking(Piglin p_35007_) { p_35007_.getBrain().eraseMemory(MemoryModuleType.WALK_TARGET); p_35007_.getNavigation().stop(); } private static BehaviorControl babySometimesRideBabyHoglin() { SetEntityLookTargetSometimes.Ticker setentitylooktargetsometimes$ticker = new SetEntityLookTargetSometimes.Ticker(RIDE_START_INTERVAL); return CopyMemoryWithExpiry.create( p_375153_ -> p_375153_.isBaby() && setentitylooktargetsometimes$ticker.tickDownAndCheck(p_375153_.level().random), MemoryModuleType.NEAREST_VISIBLE_BABY_HOGLIN, MemoryModuleType.RIDE_TARGET, RIDE_DURATION ); } protected static void broadcastAngerTarget(ServerLevel p_368320_, AbstractPiglin p_366359_, LivingEntity p_364430_) { getAdultPiglins(p_366359_).forEach(p_390704_ -> { if (p_364430_.getType() != EntityType.HOGLIN || p_390704_.canHunt() && ((Hoglin)p_364430_).canBeHunted()) { setAngerTargetIfCloserThanCurrent(p_368320_, p_390704_, p_364430_); } }); } protected static void broadcastUniversalAnger(ServerLevel p_369015_, AbstractPiglin p_34896_) { getAdultPiglins(p_34896_).forEach(p_359293_ -> getNearestVisibleTargetablePlayer(p_359293_).ifPresent(p_359276_ -> setAngerTarget(p_369015_, p_359293_, p_359276_))); } protected static void setAngerTarget(ServerLevel p_364284_, AbstractPiglin p_34925_, LivingEntity p_34926_) { if (Sensor.isEntityAttackableIgnoringLineOfSight(p_364284_, p_34925_, p_34926_)) { p_34925_.getBrain().eraseMemory(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); p_34925_.getBrain().setMemoryWithExpiry(MemoryModuleType.ANGRY_AT, p_34926_.getUUID(), 600L); if (p_34926_.getType() == EntityType.HOGLIN && p_34925_.canHunt()) { dontKillAnyMoreHoglinsForAWhile(p_34925_); } if (p_34926_.getType() == EntityType.PLAYER && p_364284_.getGameRules().getBoolean(GameRules.RULE_UNIVERSAL_ANGER)) { p_34925_.getBrain().setMemoryWithExpiry(MemoryModuleType.UNIVERSAL_ANGER, true, 600L); } } } private static void setAngerTargetToNearestTargetablePlayerIfFound(ServerLevel p_368737_, AbstractPiglin p_34945_, LivingEntity p_34946_) { Optional optional = getNearestVisibleTargetablePlayer(p_34945_); if (optional.isPresent()) { setAngerTarget(p_368737_, p_34945_, optional.get()); } else { setAngerTarget(p_368737_, p_34945_, p_34946_); } } private static void setAngerTargetIfCloserThanCurrent(ServerLevel p_365346_, AbstractPiglin p_34963_, LivingEntity p_34964_) { Optional optional = getAngerTarget(p_34963_); LivingEntity livingentity = BehaviorUtils.getNearestTarget(p_34963_, optional, p_34964_); if (!optional.isPresent() || optional.get() != livingentity) { setAngerTarget(p_365346_, p_34963_, livingentity); } } private static Optional getAngerTarget(AbstractPiglin p_34976_) { return BehaviorUtils.getLivingEntityFromUUIDMemory(p_34976_, MemoryModuleType.ANGRY_AT); } public static Optional getAvoidTarget(Piglin p_34987_) { return p_34987_.getBrain().hasMemoryValue(MemoryModuleType.AVOID_TARGET) ? p_34987_.getBrain().getMemory(MemoryModuleType.AVOID_TARGET) : Optional.empty(); } public static Optional getNearestVisibleTargetablePlayer(AbstractPiglin p_34894_) { return p_34894_.getBrain().hasMemoryValue(MemoryModuleType.NEAREST_VISIBLE_ATTACKABLE_PLAYER) ? p_34894_.getBrain().getMemory(MemoryModuleType.NEAREST_VISIBLE_ATTACKABLE_PLAYER) : Optional.empty(); } private static void broadcastRetreat(Piglin p_34930_, LivingEntity p_34931_) { getVisibleAdultPiglins(p_34930_).stream().filter(p_34985_ -> p_34985_ instanceof Piglin).forEach(p_34819_ -> retreatFromNearestTarget((Piglin)p_34819_, p_34931_)); } private static void retreatFromNearestTarget(Piglin p_34950_, LivingEntity p_34951_) { Brain brain = p_34950_.getBrain(); LivingEntity $$3 = BehaviorUtils.getNearestTarget(p_34950_, brain.getMemory(MemoryModuleType.AVOID_TARGET), p_34951_); $$3 = BehaviorUtils.getNearestTarget(p_34950_, brain.getMemory(MemoryModuleType.ATTACK_TARGET), $$3); setAvoidTargetAndDontHuntForAWhile(p_34950_, $$3); } private static boolean wantsToStopFleeing(Piglin p_35009_) { Brain brain = p_35009_.getBrain(); if (!brain.hasMemoryValue(MemoryModuleType.AVOID_TARGET)) { return true; } else { LivingEntity livingentity = brain.getMemory(MemoryModuleType.AVOID_TARGET).get(); EntityType entitytype = livingentity.getType(); if (entitytype == EntityType.HOGLIN) { return piglinsEqualOrOutnumberHoglins(p_35009_); } else { return isZombified(entitytype) ? !brain.isMemoryValue(MemoryModuleType.NEAREST_VISIBLE_ZOMBIFIED, livingentity) : false; } } } private static boolean piglinsEqualOrOutnumberHoglins(Piglin p_35011_) { return !hoglinsOutnumberPiglins(p_35011_); } private static boolean hoglinsOutnumberPiglins(Piglin p_35013_) { int i = p_35013_.getBrain().getMemory(MemoryModuleType.VISIBLE_ADULT_PIGLIN_COUNT).orElse(0) + 1; int j = p_35013_.getBrain().getMemory(MemoryModuleType.VISIBLE_ADULT_HOGLIN_COUNT).orElse(0); return j > i; } private static void setAvoidTargetAndDontHuntForAWhile(Piglin p_34968_, LivingEntity p_34969_) { p_34968_.getBrain().eraseMemory(MemoryModuleType.ANGRY_AT); p_34968_.getBrain().eraseMemory(MemoryModuleType.ATTACK_TARGET); p_34968_.getBrain().eraseMemory(MemoryModuleType.WALK_TARGET); p_34968_.getBrain().setMemoryWithExpiry(MemoryModuleType.AVOID_TARGET, p_34969_, RETREAT_DURATION.sample(p_34968_.level().random)); dontKillAnyMoreHoglinsForAWhile(p_34968_); } protected static void dontKillAnyMoreHoglinsForAWhile(AbstractPiglin p_34923_) { p_34923_.getBrain().setMemoryWithExpiry(MemoryModuleType.HUNTED_RECENTLY, true, TIME_BETWEEN_HUNTS.sample(p_34923_.level().random)); } private static void eat(Piglin p_35015_) { p_35015_.getBrain().setMemoryWithExpiry(MemoryModuleType.ATE_RECENTLY, true, 200L); } private static Vec3 getRandomNearbyPos(Piglin p_35017_) { Vec3 vec3 = LandRandomPos.getPos(p_35017_, 4, 2); return vec3 == null ? p_35017_.position() : vec3; } private static boolean hasEatenRecently(Piglin p_35019_) { return p_35019_.getBrain().hasMemoryValue(MemoryModuleType.ATE_RECENTLY); } protected static boolean isIdle(AbstractPiglin p_34943_) { return p_34943_.getBrain().isActive(Activity.IDLE); } private static boolean hasCrossbow(LivingEntity p_34919_) { return p_34919_.isHolding(Items.CROSSBOW); } private static void admireGoldItem(LivingEntity p_34939_) { p_34939_.getBrain().setMemoryWithExpiry(MemoryModuleType.ADMIRING_ITEM, true, 119L); } private static boolean isAdmiringItem(Piglin p_35021_) { return p_35021_.getBrain().hasMemoryValue(MemoryModuleType.ADMIRING_ITEM); } private static boolean isBarterCurrency(ItemStack p_149968_) { return p_149968_.is(BARTERING_ITEM); } private static boolean isFood(ItemStack p_149970_) { return p_149970_.is(ItemTags.PIGLIN_FOOD); } private static boolean isNearRepellent(Piglin p_35023_) { return p_35023_.getBrain().hasMemoryValue(MemoryModuleType.NEAREST_REPELLENT); } private static boolean seesPlayerHoldingLovedItem(LivingEntity p_34972_) { return p_34972_.getBrain().hasMemoryValue(MemoryModuleType.NEAREST_PLAYER_HOLDING_WANTED_ITEM); } private static boolean doesntSeeAnyPlayerHoldingLovedItem(LivingEntity p_34983_) { return !seesPlayerHoldingLovedItem(p_34983_); } public static boolean isPlayerHoldingLovedItem(LivingEntity p_34884_) { return p_34884_.getType() == EntityType.PLAYER && p_34884_.isHolding(PiglinAi::isLovedItem); } private static boolean isAdmiringDisabled(Piglin p_35025_) { return p_35025_.getBrain().hasMemoryValue(MemoryModuleType.ADMIRING_DISABLED); } private static boolean wasHurtRecently(LivingEntity p_34989_) { return p_34989_.getBrain().hasMemoryValue(MemoryModuleType.HURT_BY); } private static boolean isHoldingItemInOffHand(Piglin p_35027_) { return !p_35027_.getOffhandItem().isEmpty(); } private static boolean isNotHoldingLovedItemInOffHand(Piglin p_35029_) { return p_35029_.getOffhandItem().isEmpty() || !isLovedItem(p_35029_.getOffhandItem()); } public static boolean isZombified(EntityType p_34807_) { return p_34807_ == EntityType.ZOMBIFIED_PIGLIN || p_34807_ == EntityType.ZOGLIN; } }