package net.minecraft.world.entity.monster.warden; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.mojang.datafixers.util.Pair; import com.mojang.serialization.Dynamic; import java.util.List; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.util.Mth; import net.minecraft.util.Unit; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.ai.Brain; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.ai.behavior.BehaviorControl; import net.minecraft.world.entity.ai.behavior.BlockPosTracker; import net.minecraft.world.entity.ai.behavior.DoNothing; import net.minecraft.world.entity.ai.behavior.GoToTargetLocation; import net.minecraft.world.entity.ai.behavior.LookAtTargetSink; import net.minecraft.world.entity.ai.behavior.MeleeAttack; import net.minecraft.world.entity.ai.behavior.MoveToTargetSink; 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.SetWalkTargetFromAttackTargetIfTargetOutOfReach; import net.minecraft.world.entity.ai.behavior.StopAttackingIfTargetInvalid; import net.minecraft.world.entity.ai.behavior.Swim; import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder; import net.minecraft.world.entity.ai.behavior.declarative.MemoryAccessor; import net.minecraft.world.entity.ai.behavior.warden.Digging; import net.minecraft.world.entity.ai.behavior.warden.Emerging; import net.minecraft.world.entity.ai.behavior.warden.ForceUnmount; import net.minecraft.world.entity.ai.behavior.warden.Roar; import net.minecraft.world.entity.ai.behavior.warden.SetRoarTarget; import net.minecraft.world.entity.ai.behavior.warden.SetWardenLookTarget; import net.minecraft.world.entity.ai.behavior.warden.Sniffing; import net.minecraft.world.entity.ai.behavior.warden.SonicBoom; import net.minecraft.world.entity.ai.behavior.warden.TryToSniff; import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryStatus; import net.minecraft.world.entity.ai.sensing.Sensor; import net.minecraft.world.entity.ai.sensing.SensorType; import net.minecraft.world.entity.schedule.Activity; public class WardenAi { private static final float SPEED_MULTIPLIER_WHEN_IDLING = 0.5F; private static final float SPEED_MULTIPLIER_WHEN_INVESTIGATING = 0.7F; private static final float SPEED_MULTIPLIER_WHEN_FIGHTING = 1.2F; private static final int MELEE_ATTACK_COOLDOWN = 18; private static final int DIGGING_DURATION = Mth.ceil(100.0F); public static final int EMERGE_DURATION = Mth.ceil(133.59999F); public static final int ROAR_DURATION = Mth.ceil(84.0F); private static final int SNIFFING_DURATION = Mth.ceil(83.2F); public static final int DIGGING_COOLDOWN = 1200; private static final int DISTURBANCE_LOCATION_EXPIRY_TIME = 100; private static final List>> SENSOR_TYPES = List.of(SensorType.NEAREST_PLAYERS, SensorType.WARDEN_ENTITY_SENSOR); private static final List> MEMORY_TYPES = List.of( MemoryModuleType.NEAREST_LIVING_ENTITIES, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryModuleType.NEAREST_VISIBLE_PLAYER, MemoryModuleType.NEAREST_VISIBLE_ATTACKABLE_PLAYER, MemoryModuleType.NEAREST_VISIBLE_NEMESIS, MemoryModuleType.LOOK_TARGET, MemoryModuleType.WALK_TARGET, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryModuleType.PATH, MemoryModuleType.ATTACK_TARGET, MemoryModuleType.ATTACK_COOLING_DOWN, MemoryModuleType.NEAREST_ATTACKABLE, MemoryModuleType.ROAR_TARGET, MemoryModuleType.DISTURBANCE_LOCATION, MemoryModuleType.RECENT_PROJECTILE, MemoryModuleType.IS_SNIFFING, MemoryModuleType.IS_EMERGING, MemoryModuleType.ROAR_SOUND_DELAY, MemoryModuleType.DIG_COOLDOWN, MemoryModuleType.ROAR_SOUND_COOLDOWN, MemoryModuleType.SNIFF_COOLDOWN, MemoryModuleType.TOUCH_COOLDOWN, MemoryModuleType.VIBRATION_COOLDOWN, MemoryModuleType.SONIC_BOOM_COOLDOWN, MemoryModuleType.SONIC_BOOM_SOUND_COOLDOWN, MemoryModuleType.SONIC_BOOM_SOUND_DELAY ); private static final BehaviorControl DIG_COOLDOWN_SETTER = BehaviorBuilder.create( p_258953_ -> p_258953_.group(p_258953_.registered(MemoryModuleType.DIG_COOLDOWN)).apply(p_258953_, p_258960_ -> (p_258956_, p_258957_, p_258958_) -> { if (p_258953_.tryGet(p_258960_).isPresent()) { p_258960_.setWithExpiry(Unit.INSTANCE, 1200L); } return true; }) ); public static void updateActivity(Warden p_219513_) { p_219513_.getBrain() .setActiveActivityToFirstValid( ImmutableList.of( Activity.EMERGE, Activity.DIG, Activity.ROAR, Activity.FIGHT, Activity.INVESTIGATE, Activity.SNIFF, Activity.IDLE ) ); } protected static Brain makeBrain(Warden p_219521_, Dynamic p_219522_) { Brain.Provider provider = Brain.provider(MEMORY_TYPES, SENSOR_TYPES); Brain brain = provider.makeBrain(p_219522_); initCoreActivity(brain); initEmergeActivity(brain); initDiggingActivity(brain); initIdleActivity(brain); initRoarActivity(brain); initFightActivity(p_219521_, brain); initInvestigateActivity(brain); initSniffingActivity(brain); brain.setCoreActivities(ImmutableSet.of(Activity.CORE)); brain.setDefaultActivity(Activity.IDLE); brain.useDefaultActivity(); return brain; } private static void initCoreActivity(Brain p_219511_) { p_219511_.addActivity( Activity.CORE, 0, ImmutableList.of(new Swim<>(0.8F), SetWardenLookTarget.create(), new LookAtTargetSink(45, 90), new MoveToTargetSink()) ); } private static void initEmergeActivity(Brain p_219527_) { p_219527_.addActivityAndRemoveMemoryWhenStopped(Activity.EMERGE, 5, ImmutableList.of(new Emerging<>(EMERGE_DURATION)), MemoryModuleType.IS_EMERGING); } private static void initDiggingActivity(Brain p_219532_) { p_219532_.addActivityWithConditions( Activity.DIG, ImmutableList.of(Pair.of(0, new ForceUnmount()), Pair.of(1, new Digging<>(DIGGING_DURATION))), ImmutableSet.of(Pair.of(MemoryModuleType.ROAR_TARGET, MemoryStatus.VALUE_ABSENT), Pair.of(MemoryModuleType.DIG_COOLDOWN, MemoryStatus.VALUE_ABSENT)) ); } private static void initIdleActivity(Brain p_219537_) { p_219537_.addActivity( Activity.IDLE, 10, ImmutableList.of( SetRoarTarget.create(Warden::getEntityAngryAt), TryToSniff.create(), new RunOne<>( ImmutableMap.of(MemoryModuleType.IS_SNIFFING, MemoryStatus.VALUE_ABSENT), ImmutableList.of(Pair.of(RandomStroll.stroll(0.5F), 2), Pair.of(new DoNothing(30, 60), 1)) ) ) ); } private static void initInvestigateActivity(Brain p_219542_) { p_219542_.addActivityAndRemoveMemoryWhenStopped( Activity.INVESTIGATE, 5, ImmutableList.of(SetRoarTarget.create(Warden::getEntityAngryAt), GoToTargetLocation.create(MemoryModuleType.DISTURBANCE_LOCATION, 2, 0.7F)), MemoryModuleType.DISTURBANCE_LOCATION ); } private static void initSniffingActivity(Brain p_219544_) { p_219544_.addActivityAndRemoveMemoryWhenStopped( Activity.SNIFF, 5, ImmutableList.of(SetRoarTarget.create(Warden::getEntityAngryAt), new Sniffing<>(SNIFFING_DURATION)), MemoryModuleType.IS_SNIFFING ); } private static void initRoarActivity(Brain p_219546_) { p_219546_.addActivityAndRemoveMemoryWhenStopped(Activity.ROAR, 10, ImmutableList.of(new Roar()), MemoryModuleType.ROAR_TARGET); } private static void initFightActivity(Warden p_219518_, Brain p_219519_) { p_219519_.addActivityAndRemoveMemoryWhenStopped( Activity.FIGHT, 10, ImmutableList.of( DIG_COOLDOWN_SETTER, StopAttackingIfTargetInvalid.create( (p_363002_, p_219540_) -> !p_219518_.getAngerLevel().isAngry() || !p_219518_.canTargetEntity(p_219540_), WardenAi::onTargetInvalid, false ), SetEntityLookTarget.create(p_219535_ -> isTarget(p_219518_, p_219535_), (float)p_219518_.getAttributeValue(Attributes.FOLLOW_RANGE)), SetWalkTargetFromAttackTargetIfTargetOutOfReach.create(1.2F), new SonicBoom(), MeleeAttack.create(18) ), MemoryModuleType.ATTACK_TARGET ); } private static boolean isTarget(Warden p_219515_, LivingEntity p_219516_) { return p_219515_.getBrain().getMemory(MemoryModuleType.ATTACK_TARGET).filter(p_219509_ -> p_219509_ == p_219516_).isPresent(); } private static void onTargetInvalid(ServerLevel p_363022_, Warden p_219529_, LivingEntity p_219530_) { if (!p_219529_.canTargetEntity(p_219530_)) { p_219529_.clearAnger(p_219530_); } setDigCooldown(p_219529_); } public static void setDigCooldown(LivingEntity p_219506_) { if (p_219506_.getBrain().hasMemoryValue(MemoryModuleType.DIG_COOLDOWN)) { p_219506_.getBrain().setMemoryWithExpiry(MemoryModuleType.DIG_COOLDOWN, Unit.INSTANCE, 1200L); } } public static void setDisturbanceLocation(Warden p_219524_, BlockPos p_219525_) { if (p_219524_.level().getWorldBorder().isWithinBounds(p_219525_) && !p_219524_.getEntityAngryAt().isPresent() && !p_219524_.getBrain().getMemory(MemoryModuleType.ATTACK_TARGET).isPresent()) { setDigCooldown(p_219524_); p_219524_.getBrain().setMemoryWithExpiry(MemoryModuleType.SNIFF_COOLDOWN, Unit.INSTANCE, 100L); p_219524_.getBrain().setMemoryWithExpiry(MemoryModuleType.LOOK_TARGET, new BlockPosTracker(p_219525_), 100L); p_219524_.getBrain().setMemoryWithExpiry(MemoryModuleType.DISTURBANCE_LOCATION, p_219525_, 100L); p_219524_.getBrain().eraseMemory(MemoryModuleType.WALK_TARGET); } } }