minecraft-src/net/minecraft/world/entity/monster/EnderMan.java
2025-07-04 03:15:13 +03:00

632 lines
22 KiB
Java

package net.minecraft.world.entity.monster;
import java.util.EnumSet;
import java.util.Optional;
import java.util.UUID;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.component.DataComponents;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.core.registries.Registries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.tags.BlockTags;
import net.minecraft.tags.DamageTypeTags;
import net.minecraft.tags.FluidTags;
import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource;
import net.minecraft.util.TimeUtil;
import net.minecraft.util.valueproviders.UniformInt;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.NeutralMob;
import net.minecraft.world.entity.ai.attributes.AttributeInstance;
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.ai.attributes.AttributeModifier.Operation;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier.Builder;
import net.minecraft.world.entity.ai.goal.FloatGoal;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal;
import net.minecraft.world.entity.ai.goal.MeleeAttackGoal;
import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal;
import net.minecraft.world.entity.ai.goal.WaterAvoidingRandomStrollGoal;
import net.minecraft.world.entity.ai.goal.Goal.Flag;
import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal;
import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal;
import net.minecraft.world.entity.ai.goal.target.ResetUniversalAngerTargetGoal;
import net.minecraft.world.entity.ai.targeting.TargetingConditions;
import net.minecraft.world.entity.ai.targeting.TargetingConditions.Selector;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.projectile.ThrownPotion;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.alchemy.PotionContents;
import net.minecraft.world.item.alchemy.Potions;
import net.minecraft.world.item.enchantment.EnchantmentHelper;
import net.minecraft.world.item.enchantment.providers.VanillaEnchantmentProviders;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.ClipContext.Fluid;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.level.gameevent.GameEvent.Context;
import net.minecraft.world.level.pathfinder.PathType;
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
public class EnderMan extends Monster implements NeutralMob {
private static final ResourceLocation SPEED_MODIFIER_ATTACKING_ID = ResourceLocation.withDefaultNamespace("attacking");
private static final AttributeModifier SPEED_MODIFIER_ATTACKING = new AttributeModifier(SPEED_MODIFIER_ATTACKING_ID, 0.15F, Operation.ADD_VALUE);
private static final int DELAY_BETWEEN_CREEPY_STARE_SOUND = 400;
private static final int MIN_DEAGGRESSION_TIME = 600;
private static final EntityDataAccessor<Optional<BlockState>> DATA_CARRY_STATE = SynchedEntityData.defineId(
EnderMan.class, EntityDataSerializers.OPTIONAL_BLOCK_STATE
);
private static final EntityDataAccessor<Boolean> DATA_CREEPY = SynchedEntityData.defineId(EnderMan.class, EntityDataSerializers.BOOLEAN);
private static final EntityDataAccessor<Boolean> DATA_STARED_AT = SynchedEntityData.defineId(EnderMan.class, EntityDataSerializers.BOOLEAN);
private int lastStareSound = Integer.MIN_VALUE;
private int targetChangeTime;
private static final UniformInt PERSISTENT_ANGER_TIME = TimeUtil.rangeOfSeconds(20, 39);
private int remainingPersistentAngerTime;
@Nullable
private UUID persistentAngerTarget;
public EnderMan(EntityType<? extends EnderMan> entityType, Level level) {
super(entityType, level);
this.setPathfindingMalus(PathType.WATER, -1.0F);
}
@Override
protected void registerGoals() {
this.goalSelector.addGoal(0, new FloatGoal(this));
this.goalSelector.addGoal(1, new EnderMan.EndermanFreezeWhenLookedAt(this));
this.goalSelector.addGoal(2, new MeleeAttackGoal(this, 1.0, false));
this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0, 0.0F));
this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 8.0F));
this.goalSelector.addGoal(8, new RandomLookAroundGoal(this));
this.goalSelector.addGoal(10, new EnderMan.EndermanLeaveBlockGoal(this));
this.goalSelector.addGoal(11, new EnderMan.EndermanTakeBlockGoal(this));
this.targetSelector.addGoal(1, new EnderMan.EndermanLookForPlayerGoal(this, this::isAngryAt));
this.targetSelector.addGoal(2, new HurtByTargetGoal(this));
this.targetSelector.addGoal(3, new NearestAttackableTargetGoal(this, Endermite.class, true, false));
this.targetSelector.addGoal(4, new ResetUniversalAngerTargetGoal<>(this, false));
}
public static Builder createAttributes() {
return Monster.createMonsterAttributes()
.add(Attributes.MAX_HEALTH, 40.0)
.add(Attributes.MOVEMENT_SPEED, 0.3F)
.add(Attributes.ATTACK_DAMAGE, 7.0)
.add(Attributes.FOLLOW_RANGE, 64.0)
.add(Attributes.STEP_HEIGHT, 1.0);
}
@Override
public void setTarget(@Nullable LivingEntity livingEntity) {
super.setTarget(livingEntity);
AttributeInstance attributeInstance = this.getAttribute(Attributes.MOVEMENT_SPEED);
if (livingEntity == null) {
this.targetChangeTime = 0;
this.entityData.set(DATA_CREEPY, false);
this.entityData.set(DATA_STARED_AT, false);
attributeInstance.removeModifier(SPEED_MODIFIER_ATTACKING_ID);
} else {
this.targetChangeTime = this.tickCount;
this.entityData.set(DATA_CREEPY, true);
if (!attributeInstance.hasModifier(SPEED_MODIFIER_ATTACKING_ID)) {
attributeInstance.addTransientModifier(SPEED_MODIFIER_ATTACKING);
}
}
}
@Override
protected void defineSynchedData(net.minecraft.network.syncher.SynchedEntityData.Builder builder) {
super.defineSynchedData(builder);
builder.define(DATA_CARRY_STATE, Optional.empty());
builder.define(DATA_CREEPY, false);
builder.define(DATA_STARED_AT, false);
}
@Override
public void startPersistentAngerTimer() {
this.setRemainingPersistentAngerTime(PERSISTENT_ANGER_TIME.sample(this.random));
}
@Override
public void setRemainingPersistentAngerTime(int remainingPersistentAngerTime) {
this.remainingPersistentAngerTime = remainingPersistentAngerTime;
}
@Override
public int getRemainingPersistentAngerTime() {
return this.remainingPersistentAngerTime;
}
@Override
public void setPersistentAngerTarget(@Nullable UUID persistentAngerTarget) {
this.persistentAngerTarget = persistentAngerTarget;
}
@Nullable
@Override
public UUID getPersistentAngerTarget() {
return this.persistentAngerTarget;
}
public void playStareSound() {
if (this.tickCount >= this.lastStareSound + 400) {
this.lastStareSound = this.tickCount;
if (!this.isSilent()) {
this.level().playLocalSound(this.getX(), this.getEyeY(), this.getZ(), SoundEvents.ENDERMAN_STARE, this.getSoundSource(), 2.5F, 1.0F, false);
}
}
}
@Override
public void onSyncedDataUpdated(EntityDataAccessor<?> dataAccessor) {
if (DATA_CREEPY.equals(dataAccessor) && this.hasBeenStaredAt() && this.level().isClientSide) {
this.playStareSound();
}
super.onSyncedDataUpdated(dataAccessor);
}
@Override
public void addAdditionalSaveData(CompoundTag tag) {
super.addAdditionalSaveData(tag);
BlockState blockState = this.getCarriedBlock();
if (blockState != null) {
tag.put("carriedBlockState", NbtUtils.writeBlockState(blockState));
}
this.addPersistentAngerSaveData(tag);
}
@Override
public void readAdditionalSaveData(CompoundTag tag) {
super.readAdditionalSaveData(tag);
BlockState blockState = null;
if (tag.contains("carriedBlockState", 10)) {
blockState = NbtUtils.readBlockState(this.level().holderLookup(Registries.BLOCK), tag.getCompound("carriedBlockState"));
if (blockState.isAir()) {
blockState = null;
}
}
this.setCarriedBlock(blockState);
this.readPersistentAngerSaveData(this.level(), tag);
}
boolean isBeingStaredBy(Player player) {
return !LivingEntity.PLAYER_NOT_WEARING_DISGUISE_ITEM.test(player) ? false : this.isLookingAtMe(player, 0.025, true, false, new double[]{this.getEyeY()});
}
@Override
public void aiStep() {
if (this.level().isClientSide) {
for (int i = 0; i < 2; i++) {
this.level()
.addParticle(
ParticleTypes.PORTAL,
this.getRandomX(0.5),
this.getRandomY() - 0.25,
this.getRandomZ(0.5),
(this.random.nextDouble() - 0.5) * 2.0,
-this.random.nextDouble(),
(this.random.nextDouble() - 0.5) * 2.0
);
}
}
this.jumping = false;
if (!this.level().isClientSide) {
this.updatePersistentAnger((ServerLevel)this.level(), true);
}
super.aiStep();
}
@Override
public boolean isSensitiveToWater() {
return true;
}
@Override
protected void customServerAiStep(ServerLevel level) {
if (level.isDay() && this.tickCount >= this.targetChangeTime + 600) {
float f = this.getLightLevelDependentMagicValue();
if (f > 0.5F && level.canSeeSky(this.blockPosition()) && this.random.nextFloat() * 30.0F < (f - 0.4F) * 2.0F) {
this.setTarget(null);
this.teleport();
}
}
super.customServerAiStep(level);
}
/**
* Teleport the enderman to a random nearby position
*/
protected boolean teleport() {
if (!this.level().isClientSide() && this.isAlive()) {
double d = this.getX() + (this.random.nextDouble() - 0.5) * 64.0;
double e = this.getY() + (this.random.nextInt(64) - 32);
double f = this.getZ() + (this.random.nextDouble() - 0.5) * 64.0;
return this.teleport(d, e, f);
} else {
return false;
}
}
/**
* Teleport the enderman to another entity
*/
boolean teleportTowards(Entity target) {
Vec3 vec3 = new Vec3(this.getX() - target.getX(), this.getY(0.5) - target.getEyeY(), this.getZ() - target.getZ());
vec3 = vec3.normalize();
double d = 16.0;
double e = this.getX() + (this.random.nextDouble() - 0.5) * 8.0 - vec3.x * 16.0;
double f = this.getY() + (this.random.nextInt(16) - 8) - vec3.y * 16.0;
double g = this.getZ() + (this.random.nextDouble() - 0.5) * 8.0 - vec3.z * 16.0;
return this.teleport(e, f, g);
}
/**
* Teleport the enderman
*/
private boolean teleport(double x, double y, double z) {
BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos(x, y, z);
while (mutableBlockPos.getY() > this.level().getMinY() && !this.level().getBlockState(mutableBlockPos).blocksMotion()) {
mutableBlockPos.move(Direction.DOWN);
}
BlockState blockState = this.level().getBlockState(mutableBlockPos);
boolean bl = blockState.blocksMotion();
boolean bl2 = blockState.getFluidState().is(FluidTags.WATER);
if (bl && !bl2) {
Vec3 vec3 = this.position();
boolean bl3 = this.randomTeleport(x, y, z, true);
if (bl3) {
this.level().gameEvent(GameEvent.TELEPORT, vec3, Context.of(this));
if (!this.isSilent()) {
this.level().playSound(null, this.xo, this.yo, this.zo, SoundEvents.ENDERMAN_TELEPORT, this.getSoundSource(), 1.0F, 1.0F);
this.playSound(SoundEvents.ENDERMAN_TELEPORT, 1.0F, 1.0F);
}
}
return bl3;
} else {
return false;
}
}
@Override
protected SoundEvent getAmbientSound() {
return this.isCreepy() ? SoundEvents.ENDERMAN_SCREAM : SoundEvents.ENDERMAN_AMBIENT;
}
@Override
protected SoundEvent getHurtSound(DamageSource damageSource) {
return SoundEvents.ENDERMAN_HURT;
}
@Override
protected SoundEvent getDeathSound() {
return SoundEvents.ENDERMAN_DEATH;
}
@Override
protected void dropCustomDeathLoot(ServerLevel level, DamageSource damageSource, boolean recentlyHit) {
super.dropCustomDeathLoot(level, damageSource, recentlyHit);
BlockState blockState = this.getCarriedBlock();
if (blockState != null) {
ItemStack itemStack = new ItemStack(Items.DIAMOND_AXE);
EnchantmentHelper.enchantItemFromProvider(
itemStack, level.registryAccess(), VanillaEnchantmentProviders.ENDERMAN_LOOT_DROP, level.getCurrentDifficultyAt(this.blockPosition()), this.getRandom()
);
net.minecraft.world.level.storage.loot.LootParams.Builder builder = new net.minecraft.world.level.storage.loot.LootParams.Builder((ServerLevel)this.level())
.withParameter(LootContextParams.ORIGIN, this.position())
.withParameter(LootContextParams.TOOL, itemStack)
.withOptionalParameter(LootContextParams.THIS_ENTITY, this);
for (ItemStack itemStack2 : blockState.getDrops(builder)) {
this.spawnAtLocation(level, itemStack2);
}
}
}
public void setCarriedBlock(@Nullable BlockState state) {
this.entityData.set(DATA_CARRY_STATE, Optional.ofNullable(state));
}
@Nullable
public BlockState getCarriedBlock() {
return (BlockState)this.entityData.get(DATA_CARRY_STATE).orElse(null);
}
@Override
public boolean hurtServer(ServerLevel level, DamageSource damageSource, float amount) {
if (this.isInvulnerableTo(level, damageSource)) {
return false;
} else {
boolean bl = damageSource.getDirectEntity() instanceof ThrownPotion;
if (!damageSource.is(DamageTypeTags.IS_PROJECTILE) && !bl) {
boolean bl2 = super.hurtServer(level, damageSource, amount);
if (!(damageSource.getEntity() instanceof LivingEntity) && this.random.nextInt(10) != 0) {
this.teleport();
}
return bl2;
} else {
boolean bl2 = bl && this.hurtWithCleanWater(level, damageSource, (ThrownPotion)damageSource.getDirectEntity(), amount);
for (int i = 0; i < 64; i++) {
if (this.teleport()) {
return true;
}
}
return bl2;
}
}
}
private boolean hurtWithCleanWater(ServerLevel level, DamageSource damageSource, ThrownPotion potion, float amount) {
ItemStack itemStack = potion.getItem();
PotionContents potionContents = itemStack.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY);
return potionContents.is(Potions.WATER) ? super.hurtServer(level, damageSource, amount) : false;
}
public boolean isCreepy() {
return this.entityData.get(DATA_CREEPY);
}
public boolean hasBeenStaredAt() {
return this.entityData.get(DATA_STARED_AT);
}
public void setBeingStaredAt() {
this.entityData.set(DATA_STARED_AT, true);
}
@Override
public boolean requiresCustomPersistence() {
return super.requiresCustomPersistence() || this.getCarriedBlock() != null;
}
static class EndermanFreezeWhenLookedAt extends Goal {
private final EnderMan enderman;
@Nullable
private LivingEntity target;
public EndermanFreezeWhenLookedAt(EnderMan enderman) {
this.enderman = enderman;
this.setFlags(EnumSet.of(Flag.JUMP, Flag.MOVE));
}
@Override
public boolean canUse() {
this.target = this.enderman.getTarget();
if (!(this.target instanceof Player)) {
return false;
} else {
double d = this.target.distanceToSqr(this.enderman);
return d > 256.0 ? false : this.enderman.isBeingStaredBy((Player)this.target);
}
}
@Override
public void start() {
this.enderman.getNavigation().stop();
}
@Override
public void tick() {
this.enderman.getLookControl().setLookAt(this.target.getX(), this.target.getEyeY(), this.target.getZ());
}
}
static class EndermanLeaveBlockGoal extends Goal {
private final EnderMan enderman;
public EndermanLeaveBlockGoal(EnderMan enderman) {
this.enderman = enderman;
}
@Override
public boolean canUse() {
if (this.enderman.getCarriedBlock() == null) {
return false;
} else {
return !getServerLevel(this.enderman).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)
? false
: this.enderman.getRandom().nextInt(reducedTickDelay(2000)) == 0;
}
}
@Override
public void tick() {
RandomSource randomSource = this.enderman.getRandom();
Level level = this.enderman.level();
int i = Mth.floor(this.enderman.getX() - 1.0 + randomSource.nextDouble() * 2.0);
int j = Mth.floor(this.enderman.getY() + randomSource.nextDouble() * 2.0);
int k = Mth.floor(this.enderman.getZ() - 1.0 + randomSource.nextDouble() * 2.0);
BlockPos blockPos = new BlockPos(i, j, k);
BlockState blockState = level.getBlockState(blockPos);
BlockPos blockPos2 = blockPos.below();
BlockState blockState2 = level.getBlockState(blockPos2);
BlockState blockState3 = this.enderman.getCarriedBlock();
if (blockState3 != null) {
blockState3 = Block.updateFromNeighbourShapes(blockState3, this.enderman.level(), blockPos);
if (this.canPlaceBlock(level, blockPos, blockState3, blockState, blockState2, blockPos2)) {
level.setBlock(blockPos, blockState3, 3);
level.gameEvent(GameEvent.BLOCK_PLACE, blockPos, Context.of(this.enderman, blockState3));
this.enderman.setCarriedBlock(null);
}
}
}
private boolean canPlaceBlock(
Level level, BlockPos destinationPos, BlockState carriedState, BlockState destinationState, BlockState belowDestinationState, BlockPos belowDestinationPos
) {
return destinationState.isAir()
&& !belowDestinationState.isAir()
&& !belowDestinationState.is(Blocks.BEDROCK)
&& belowDestinationState.isCollisionShapeFullBlock(level, belowDestinationPos)
&& carriedState.canSurvive(level, destinationPos)
&& level.getEntities(this.enderman, AABB.unitCubeFromLowerCorner(Vec3.atLowerCornerOf(destinationPos))).isEmpty();
}
}
static class EndermanLookForPlayerGoal extends NearestAttackableTargetGoal<Player> {
private final EnderMan enderman;
/**
* The player
*/
@Nullable
private Player pendingTarget;
private int aggroTime;
private int teleportTime;
private final TargetingConditions startAggroTargetConditions;
private final TargetingConditions continueAggroTargetConditions = TargetingConditions.forCombat().ignoreLineOfSight();
private final Selector isAngerInducing;
public EndermanLookForPlayerGoal(EnderMan enderman, @Nullable Selector selector) {
super(enderman, Player.class, 10, false, false, selector);
this.enderman = enderman;
this.isAngerInducing = (livingEntity, serverLevel) -> (enderman.isBeingStaredBy((Player)livingEntity) || enderman.isAngryAt(livingEntity, serverLevel))
&& !enderman.hasIndirectPassenger(livingEntity);
this.startAggroTargetConditions = TargetingConditions.forCombat().range(this.getFollowDistance()).selector(this.isAngerInducing);
}
@Override
public boolean canUse() {
this.pendingTarget = getServerLevel(this.enderman).getNearestPlayer(this.startAggroTargetConditions.range(this.getFollowDistance()), this.enderman);
return this.pendingTarget != null;
}
@Override
public void start() {
this.aggroTime = this.adjustedTickDelay(5);
this.teleportTime = 0;
this.enderman.setBeingStaredAt();
}
@Override
public void stop() {
this.pendingTarget = null;
super.stop();
}
@Override
public boolean canContinueToUse() {
if (this.pendingTarget != null) {
if (!this.isAngerInducing.test(this.pendingTarget, getServerLevel(this.enderman))) {
return false;
} else {
this.enderman.lookAt(this.pendingTarget, 10.0F, 10.0F);
return true;
}
} else {
if (this.target != null) {
if (this.enderman.hasIndirectPassenger(this.target)) {
return false;
}
if (this.continueAggroTargetConditions.test(getServerLevel(this.enderman), this.enderman, this.target)) {
return true;
}
}
return super.canContinueToUse();
}
}
@Override
public void tick() {
if (this.enderman.getTarget() == null) {
super.setTarget(null);
}
if (this.pendingTarget != null) {
if (--this.aggroTime <= 0) {
this.target = this.pendingTarget;
this.pendingTarget = null;
super.start();
}
} else {
if (this.target != null && !this.enderman.isPassenger()) {
if (this.enderman.isBeingStaredBy((Player)this.target)) {
if (this.target.distanceToSqr(this.enderman) < 16.0) {
this.enderman.teleport();
}
this.teleportTime = 0;
} else if (this.target.distanceToSqr(this.enderman) > 256.0
&& this.teleportTime++ >= this.adjustedTickDelay(30)
&& this.enderman.teleportTowards(this.target)) {
this.teleportTime = 0;
}
}
super.tick();
}
}
}
static class EndermanTakeBlockGoal extends Goal {
private final EnderMan enderman;
public EndermanTakeBlockGoal(EnderMan enderman) {
this.enderman = enderman;
}
@Override
public boolean canUse() {
if (this.enderman.getCarriedBlock() != null) {
return false;
} else {
return !getServerLevel(this.enderman).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)
? false
: this.enderman.getRandom().nextInt(reducedTickDelay(20)) == 0;
}
}
@Override
public void tick() {
RandomSource randomSource = this.enderman.getRandom();
Level level = this.enderman.level();
int i = Mth.floor(this.enderman.getX() - 2.0 + randomSource.nextDouble() * 4.0);
int j = Mth.floor(this.enderman.getY() + randomSource.nextDouble() * 3.0);
int k = Mth.floor(this.enderman.getZ() - 2.0 + randomSource.nextDouble() * 4.0);
BlockPos blockPos = new BlockPos(i, j, k);
BlockState blockState = level.getBlockState(blockPos);
Vec3 vec3 = new Vec3(this.enderman.getBlockX() + 0.5, j + 0.5, this.enderman.getBlockZ() + 0.5);
Vec3 vec32 = new Vec3(i + 0.5, j + 0.5, k + 0.5);
BlockHitResult blockHitResult = level.clip(new ClipContext(vec3, vec32, net.minecraft.world.level.ClipContext.Block.OUTLINE, Fluid.NONE, this.enderman));
boolean bl = blockHitResult.getBlockPos().equals(blockPos);
if (blockState.is(BlockTags.ENDERMAN_HOLDABLE) && bl) {
level.removeBlock(blockPos, false);
level.gameEvent(GameEvent.BLOCK_DESTROY, blockPos, Context.of(this.enderman, blockState));
this.enderman.setCarriedBlock(blockState.getBlock().defaultBlockState());
}
}
}
}