/* * Decompiled with CFR 0.152. * * Could not load the following classes: * com.google.common.collect.ImmutableList * com.google.common.collect.ImmutableSet * com.mojang.datafixers.util.Pair * com.mojang.serialization.Dynamic * org.jspecify.annotations.Nullable */ package net.minecraft.world.entity.monster; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.mojang.datafixers.util.Pair; import com.mojang.serialization.Dynamic; import java.util.List; import java.util.Optional; import java.util.Set; import net.minecraft.core.BlockPos; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; import net.minecraft.util.profiling.Profiler; import net.minecraft.util.profiling.ProfilerFiller; import net.minecraft.util.valueproviders.UniformInt; import net.minecraft.world.DifficultyInstance; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.SpawnGroupData; import net.minecraft.world.entity.ai.Brain; import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.ai.behavior.BehaviorControl; import net.minecraft.world.entity.ai.behavior.BehaviorUtils; import net.minecraft.world.entity.ai.behavior.DoNothing; 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.SetEntityLookTargetSometimes; 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.StopAttackingIfTargetInvalid; import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder; import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities; import net.minecraft.world.entity.ai.sensing.Sensor; import net.minecraft.world.entity.ai.sensing.SensorType; import net.minecraft.world.entity.monster.Monster; import net.minecraft.world.entity.monster.hoglin.HoglinBase; import net.minecraft.world.entity.schedule.Activity; import net.minecraft.world.level.Level; import net.minecraft.world.level.ServerLevelAccessor; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.storage.ValueInput; import net.minecraft.world.level.storage.ValueOutput; import org.jspecify.annotations.Nullable; public class Zoglin extends Monster implements HoglinBase { private static final EntityDataAccessor DATA_BABY_ID = SynchedEntityData.defineId(Zoglin.class, EntityDataSerializers.BOOLEAN); private static final int MAX_HEALTH = 40; private static final int ATTACK_KNOCKBACK = 1; private static final float KNOCKBACK_RESISTANCE = 0.6f; private static final int ATTACK_DAMAGE = 6; private static final float BABY_ATTACK_DAMAGE = 0.5f; private static final int ATTACK_INTERVAL = 40; private static final int BABY_ATTACK_INTERVAL = 15; private static final int ATTACK_DURATION = 200; private static final float MOVEMENT_SPEED_WHEN_FIGHTING = 0.3f; private static final float SPEED_MULTIPLIER_WHEN_IDLING = 0.4f; private static final boolean DEFAULT_BABY = false; private int attackAnimationRemainingTicks; protected static final ImmutableList>> SENSOR_TYPES = ImmutableList.of(SensorType.NEAREST_LIVING_ENTITIES, SensorType.NEAREST_PLAYERS); protected static final ImmutableList> MEMORY_TYPES = ImmutableList.of(MemoryModuleType.NEAREST_LIVING_ENTITIES, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryModuleType.NEAREST_VISIBLE_PLAYER, MemoryModuleType.NEAREST_VISIBLE_ATTACKABLE_PLAYER, MemoryModuleType.LOOK_TARGET, MemoryModuleType.WALK_TARGET, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryModuleType.PATH, MemoryModuleType.ATTACK_TARGET, MemoryModuleType.ATTACK_COOLING_DOWN); public Zoglin(EntityType type, Level level) { super((EntityType)type, level); this.xpReward = 5; } protected Brain.Provider brainProvider() { return Brain.provider(MEMORY_TYPES, SENSOR_TYPES); } @Override protected Brain makeBrain(Dynamic input) { Brain brain = this.brainProvider().makeBrain(input); Zoglin.initCoreActivity(brain); Zoglin.initIdleActivity(brain); Zoglin.initFightActivity(brain); brain.setCoreActivities((Set)ImmutableSet.of((Object)Activity.CORE)); brain.setDefaultActivity(Activity.IDLE); brain.useDefaultActivity(); return brain; } private static void initCoreActivity(Brain brain) { brain.addActivity(Activity.CORE, 0, (ImmutableList>)ImmutableList.of((Object)new LookAtTargetSink(45, 90), (Object)new MoveToTargetSink())); } private static void initIdleActivity(Brain brain) { brain.addActivity(Activity.IDLE, 10, (ImmutableList>)ImmutableList.of(StartAttacking.create((level, zoglin) -> zoglin.findNearestValidAttackTarget(level)), SetEntityLookTargetSometimes.create(8.0f, UniformInt.of(30, 60)), new RunOne(ImmutableList.of((Object)Pair.of(RandomStroll.stroll(0.4f), (Object)2), (Object)Pair.of(SetWalkTargetFromLookTarget.create(0.4f, 3), (Object)2), (Object)Pair.of((Object)new DoNothing(30, 60), (Object)1))))); } private static void initFightActivity(Brain brain) { brain.addActivityAndRemoveMemoryWhenStopped(Activity.FIGHT, 10, (ImmutableList>)ImmutableList.of(SetWalkTargetFromAttackTargetIfTargetOutOfReach.create(1.0f), BehaviorBuilder.triggerIf(Zoglin::isAdult, MeleeAttack.create(40)), BehaviorBuilder.triggerIf(Zoglin::isBaby, MeleeAttack.create(15)), StopAttackingIfTargetInvalid.create()), MemoryModuleType.ATTACK_TARGET); } private Optional findNearestValidAttackTarget(ServerLevel level) { return this.getBrain().getMemory(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES).orElse(NearestVisibleLivingEntities.empty()).findClosest(target -> this.isTargetable(level, (LivingEntity)target)); } private boolean isTargetable(ServerLevel level, LivingEntity livingEntity) { EntityType type = livingEntity.getType(); return type != EntityType.ZOGLIN && type != EntityType.CREEPER && Sensor.isEntityAttackable(level, this, livingEntity); } @Override protected void defineSynchedData(SynchedEntityData.Builder entityData) { super.defineSynchedData(entityData); entityData.define(DATA_BABY_ID, false); } @Override public void onSyncedDataUpdated(EntityDataAccessor accessor) { super.onSyncedDataUpdated(accessor); if (DATA_BABY_ID.equals(accessor)) { this.refreshDimensions(); } } @Override public @Nullable SpawnGroupData finalizeSpawn(ServerLevelAccessor level, DifficultyInstance difficulty, EntitySpawnReason spawnReason, @Nullable SpawnGroupData groupData) { if (level.getRandom().nextFloat() < 0.2f) { this.setBaby(true); } return super.finalizeSpawn(level, difficulty, spawnReason, groupData); } public static AttributeSupplier.Builder createAttributes() { return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 40.0).add(Attributes.MOVEMENT_SPEED, 0.3f).add(Attributes.KNOCKBACK_RESISTANCE, 0.6f).add(Attributes.ATTACK_KNOCKBACK, 1.0).add(Attributes.ATTACK_DAMAGE, 6.0); } public boolean isAdult() { return !this.isBaby(); } @Override public boolean doHurtTarget(ServerLevel level, Entity target) { if (!(target instanceof LivingEntity)) { return false; } LivingEntity entity = (LivingEntity)target; this.attackAnimationRemainingTicks = 10; level.broadcastEntityEvent(this, (byte)4); this.makeSound(SoundEvents.ZOGLIN_ATTACK); return HoglinBase.hurtAndThrowTarget(level, this, entity); } @Override public boolean canBeLeashed() { return true; } @Override protected void blockedByItem(LivingEntity defender) { if (!this.isBaby()) { HoglinBase.throwTarget(this, defender); } } @Override public boolean hurtServer(ServerLevel level, DamageSource source, float damage) { Entity entity; boolean wasHurt = super.hurtServer(level, source, damage); if (!wasHurt || !((entity = source.getEntity()) instanceof LivingEntity)) { return wasHurt; } LivingEntity attacker = (LivingEntity)entity; if (this.canAttack(attacker) && !BehaviorUtils.isOtherTargetMuchFurtherAwayThanCurrentAttackTarget(this, attacker, 4.0)) { this.setAttackTarget(attacker); } return true; } private void setAttackTarget(LivingEntity target) { this.brain.eraseMemory(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); this.brain.setMemoryWithExpiry(MemoryModuleType.ATTACK_TARGET, target, 200L); } public Brain getBrain() { return super.getBrain(); } protected void updateActivity() { Activity oldActivity = this.brain.getActiveNonCoreActivity().orElse(null); this.brain.setActiveActivityToFirstValid((List)ImmutableList.of((Object)Activity.FIGHT, (Object)Activity.IDLE)); Activity newActivity = this.brain.getActiveNonCoreActivity().orElse(null); if (newActivity == Activity.FIGHT && oldActivity != Activity.FIGHT) { this.playAngrySound(); } this.setAggressive(this.brain.hasMemoryValue(MemoryModuleType.ATTACK_TARGET)); } @Override protected void customServerAiStep(ServerLevel level) { ProfilerFiller profiler = Profiler.get(); profiler.push("zoglinBrain"); this.getBrain().tick(level, this); profiler.pop(); this.updateActivity(); } @Override public void setBaby(boolean baby) { this.getEntityData().set(DATA_BABY_ID, baby); if (!this.level().isClientSide() && baby) { this.getAttribute(Attributes.ATTACK_DAMAGE).setBaseValue(0.5); } } @Override public boolean isBaby() { return this.getEntityData().get(DATA_BABY_ID); } @Override public void aiStep() { if (this.attackAnimationRemainingTicks > 0) { --this.attackAnimationRemainingTicks; } super.aiStep(); } @Override public void handleEntityEvent(byte id) { if (id == 4) { this.attackAnimationRemainingTicks = 10; this.makeSound(SoundEvents.ZOGLIN_ATTACK); } else { super.handleEntityEvent(id); } } @Override public int getAttackAnimationRemainingTicks() { return this.attackAnimationRemainingTicks; } @Override protected SoundEvent getAmbientSound() { if (this.level().isClientSide()) { return null; } if (this.brain.hasMemoryValue(MemoryModuleType.ATTACK_TARGET)) { return SoundEvents.ZOGLIN_ANGRY; } return SoundEvents.ZOGLIN_AMBIENT; } @Override protected SoundEvent getHurtSound(DamageSource source) { return SoundEvents.ZOGLIN_HURT; } @Override protected SoundEvent getDeathSound() { return SoundEvents.ZOGLIN_DEATH; } @Override protected void playStepSound(BlockPos pos, BlockState blockState) { this.playSound(SoundEvents.ZOGLIN_STEP, 0.15f, 1.0f); } protected void playAngrySound() { this.makeSound(SoundEvents.ZOGLIN_ANGRY); } @Override public @Nullable LivingEntity getTarget() { return this.getTargetFromBrain(); } @Override protected void addAdditionalSaveData(ValueOutput output) { super.addAdditionalSaveData(output); output.putBoolean("IsBaby", this.isBaby()); } @Override protected void readAdditionalSaveData(ValueInput input) { super.readAdditionalSaveData(input); this.setBaby(input.getBooleanOr("IsBaby", false)); } }