--- a/net/minecraft/world/entity/monster/EnderMan.java
+++ b/net/minecraft/world/entity/monster/EnderMan.java
@@ -1,12 +1,15 @@
 package net.minecraft.world.entity.monster;
 
 import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.List;
 import java.util.Optional;
 import java.util.UUID;
 import java.util.function.Predicate;
 import javax.annotation.Nullable;
 import net.minecraft.core.BlockPos;
 import net.minecraft.core.Direction;
+import net.minecraft.core.Holder;
 import net.minecraft.core.component.DataComponents;
 import net.minecraft.core.particles.ParticleTypes;
 import net.minecraft.core.registries.Registries;
@@ -64,17 +67,18 @@
 import net.minecraft.world.phys.AABB;
 import net.minecraft.world.phys.BlockHitResult;
 import net.minecraft.world.phys.Vec3;
+// CraftBukkit start;
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.event.entity.EntityTargetEvent;
+// CraftBukkit end
 
 public class EnderMan extends Monster implements NeutralMob {
+
     private static final UUID SPEED_MODIFIER_ATTACKING_UUID = UUID.fromString("020E0DFB-87AE-4653-9556-831010E291A0");
-    private static final AttributeModifier SPEED_MODIFIER_ATTACKING = new AttributeModifier(
-        SPEED_MODIFIER_ATTACKING_UUID, "Attacking speed boost", 0.15F, AttributeModifier.Operation.ADD_VALUE
-    );
+    private static final AttributeModifier SPEED_MODIFIER_ATTACKING = new AttributeModifier(EnderMan.SPEED_MODIFIER_ATTACKING_UUID, "Attacking speed boost", 0.15000000596046448D, AttributeModifier.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<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;
@@ -93,56 +97,70 @@
     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(2, new MeleeAttackGoal(this, 1.0D, false));
+        this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0D, 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(2, new HurtByTargetGoal(this, new Class[0]));
         this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Endermite.class, true, false));
         this.targetSelector.addGoal(4, new ResetUniversalAngerTargetGoal<>(this, false));
     }
 
     public static AttributeSupplier.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);
+        return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 40.0D).add(Attributes.MOVEMENT_SPEED, 0.30000001192092896D).add(Attributes.ATTACK_DAMAGE, 7.0D).add(Attributes.FOLLOW_RANGE, 64.0D).add(Attributes.STEP_HEIGHT, 1.0D);
     }
 
     @Override
     public void setTarget(@Nullable LivingEntity target) {
-        super.setTarget(target);
-        AttributeInstance attributeInstance = this.getAttribute(Attributes.MOVEMENT_SPEED);
-        if (target == null) {
+        // CraftBukkit start - fire event
+        this.setTarget(target, EntityTargetEvent.TargetReason.UNKNOWN, true);
+    }
+
+    // Paper start - EndermanEscapeEvent
+    private boolean tryEscape(com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason reason) {
+        return new com.destroystokyo.paper.event.entity.EndermanEscapeEvent((org.bukkit.craftbukkit.entity.CraftEnderman) this.getBukkitEntity(), reason).callEvent();
+    }
+    // Paper end - EndermanEscapeEvent
+
+    @Override
+    public boolean setTarget(LivingEntity entityliving, EntityTargetEvent.TargetReason reason, boolean fireEvent) {
+        if (!super.setTarget(entityliving, reason, fireEvent)) {
+            return false;
+        }
+        entityliving = this.getTarget();
+        // CraftBukkit end
+        AttributeInstance attributemodifiable = this.getAttribute(Attributes.MOVEMENT_SPEED);
+
+        if (entityliving == null) {
             this.targetChangeTime = 0;
-            this.entityData.set(DATA_CREEPY, false);
-            this.entityData.set(DATA_STARED_AT, false);
-            attributeInstance.removeModifier(SPEED_MODIFIER_ATTACKING.id());
+            this.entityData.set(EnderMan.DATA_CREEPY, false);
+            this.entityData.set(EnderMan.DATA_STARED_AT, false);
+            attributemodifiable.removeModifier(EnderMan.SPEED_MODIFIER_ATTACKING.id());
         } else {
             this.targetChangeTime = this.tickCount;
-            this.entityData.set(DATA_CREEPY, true);
-            if (!attributeInstance.hasModifier(SPEED_MODIFIER_ATTACKING)) {
-                attributeInstance.addTransientModifier(SPEED_MODIFIER_ATTACKING);
+            this.entityData.set(EnderMan.DATA_CREEPY, true);
+            if (!attributemodifiable.hasModifier(EnderMan.SPEED_MODIFIER_ATTACKING)) {
+                attributemodifiable.addTransientModifier(EnderMan.SPEED_MODIFIER_ATTACKING);
             }
         }
+        return true;
+
     }
 
     @Override
     protected void defineSynchedData(SynchedEntityData.Builder builder) {
         super.defineSynchedData(builder);
-        builder.define(DATA_CARRY_STATE, Optional.empty());
-        builder.define(DATA_CREEPY, false);
-        builder.define(DATA_STARED_AT, false);
+        builder.define(EnderMan.DATA_CARRY_STATE, Optional.empty());
+        builder.define(EnderMan.DATA_CREEPY, false);
+        builder.define(EnderMan.DATA_STARED_AT, false);
     }
 
     @Override
     public void startPersistentAngerTimer() {
-        this.setRemainingPersistentAngerTime(PERSISTENT_ANGER_TIME.sample(this.random));
+        this.setRemainingPersistentAngerTime(EnderMan.PERSISTENT_ANGER_TIME.sample(this.random));
     }
 
     @Override
@@ -173,11 +191,12 @@
                 this.level().playLocalSound(this.getX(), this.getEyeY(), this.getZ(), SoundEvents.ENDERMAN_STARE, this.getSoundSource(), 2.5F, 1.0F, false);
             }
         }
+
     }
 
     @Override
     public void onSyncedDataUpdated(EntityDataAccessor<?> data) {
-        if (DATA_CREEPY.equals(data) && this.hasBeenStaredAt() && this.level().isClientSide) {
+        if (EnderMan.DATA_CREEPY.equals(data) && this.hasBeenStaredAt() && this.level().isClientSide) {
             this.playStareSound();
         }
 
@@ -187,9 +206,10 @@
     @Override
     public void addAdditionalSaveData(CompoundTag nbt) {
         super.addAdditionalSaveData(nbt);
-        BlockState blockState = this.getCarriedBlock();
-        if (blockState != null) {
-            nbt.put("carriedBlockState", NbtUtils.writeBlockState(blockState));
+        BlockState iblockdata = this.getCarriedBlock();
+
+        if (iblockdata != null) {
+            nbt.put("carriedBlockState", NbtUtils.writeBlockState(iblockdata));
         }
 
         this.addPersistentAngerSaveData(nbt);
@@ -198,52 +218,55 @@
     @Override
     public void readAdditionalSaveData(CompoundTag nbt) {
         super.readAdditionalSaveData(nbt);
-        BlockState blockState = null;
+        BlockState iblockdata = null;
+
         if (nbt.contains("carriedBlockState", 10)) {
-            blockState = NbtUtils.readBlockState(this.level().holderLookup(Registries.BLOCK), nbt.getCompound("carriedBlockState"));
-            if (blockState.isAir()) {
-                blockState = null;
+            iblockdata = NbtUtils.readBlockState(this.level().holderLookup(Registries.BLOCK), nbt.getCompound("carriedBlockState"));
+            if (iblockdata.isAir()) {
+                iblockdata = null;
             }
         }
 
-        this.setCarriedBlock(blockState);
+        this.setCarriedBlock(iblockdata);
         this.readPersistentAngerSaveData(this.level(), nbt);
     }
 
-    boolean isLookingAtMe(Player player) {
-        ItemStack itemStack = player.getInventory().armor.get(3);
-        if (itemStack.is(Blocks.CARVED_PUMPKIN.asItem())) {
+    // Paper start - EndermanAttackPlayerEvent
+    private boolean isLookingAtMe(Player player) {
+        boolean shouldAttack = isLookingAtMe_check(player);
+        com.destroystokyo.paper.event.entity.EndermanAttackPlayerEvent event = new com.destroystokyo.paper.event.entity.EndermanAttackPlayerEvent((org.bukkit.entity.Enderman) getBukkitEntity(), (org.bukkit.entity.Player) player.getBukkitEntity());
+        event.setCancelled(!shouldAttack);
+        return event.callEvent();
+    }
+    private boolean isLookingAtMe_check(Player player) {
+        // Paper end - EndermanAttackPlayerEvent
+        ItemStack itemstack = (ItemStack) player.getInventory().armor.get(3);
+
+        if (itemstack.is(Blocks.CARVED_PUMPKIN.asItem())) {
             return false;
         } else {
-            Vec3 vec3 = player.getViewVector(1.0F).normalize();
-            Vec3 vec32 = new Vec3(this.getX() - player.getX(), this.getEyeY() - player.getEyeY(), this.getZ() - player.getZ());
-            double d = vec32.length();
-            vec32 = vec32.normalize();
-            double e = vec3.dot(vec32);
-            return e > 1.0 - 0.025 / d && player.hasLineOfSight(this);
+            Vec3 vec3d = player.getViewVector(1.0F).normalize();
+            Vec3 vec3d1 = new Vec3(this.getX() - player.getX(), this.getEyeY() - player.getEyeY(), this.getZ() - player.getZ());
+            double d0 = vec3d1.length();
+
+            vec3d1 = vec3d1.normalize();
+            double d1 = vec3d.dot(vec3d1);
+
+            return d1 > 1.0D - 0.025D / d0 ? player.hasLineOfSight(this) : false;
         }
     }
 
     @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
-                    );
+            for (int i = 0; i < 2; ++i) {
+                this.level().addParticle(ParticleTypes.PORTAL, this.getRandomX(0.5D), this.getRandomY() - 0.25D, this.getRandomZ(0.5D), (this.random.nextDouble() - 0.5D) * 2.0D, -this.random.nextDouble(), (this.random.nextDouble() - 0.5D) * 2.0D);
             }
         }
 
         this.jumping = false;
         if (!this.level().isClientSide) {
-            this.updatePersistentAnger((ServerLevel)this.level(), true);
+            this.updatePersistentAnger((ServerLevel) this.level(), true);
         }
 
         super.aiStep();
@@ -258,8 +281,9 @@
     protected void customServerAiStep() {
         if (this.level().isDay() && this.tickCount >= this.targetChangeTime + 600) {
             float f = this.getLightLevelDependentMagicValue();
-            if (f > 0.5F && this.level().canSeeSky(this.blockPosition()) && this.random.nextFloat() * 30.0F < (f - 0.4F) * 2.0F) {
-                this.setTarget(null);
+
+            if (f > 0.5F && this.level().canSeeSky(this.blockPosition()) && this.random.nextFloat() * 30.0F < (f - 0.4F) * 2.0F && this.tryEscape(com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.RUNAWAY)) { // Paper - EndermanEscapeEvent
+                this.setTarget((LivingEntity) null);
                 this.teleport();
             }
         }
@@ -269,47 +293,52 @@
 
     public boolean teleport() {
         if (!this.level().isClientSide() && this.isAlive()) {
-            double d = this.getX() + (this.random.nextDouble() - 0.5) * 64.0;
-            double e = this.getY() + (double)(this.random.nextInt(64) - 32);
-            double f = this.getZ() + (this.random.nextDouble() - 0.5) * 64.0;
-            return this.teleport(d, e, f);
+            double d0 = this.getX() + (this.random.nextDouble() - 0.5D) * 64.0D;
+            double d1 = this.getY() + (double) (this.random.nextInt(64) - 32);
+            double d2 = this.getZ() + (this.random.nextDouble() - 0.5D) * 64.0D;
+
+            return this.teleport(d0, d1, d2);
         } else {
             return false;
         }
     }
 
     public boolean teleportTowards(Entity entity) {
-        Vec3 vec3 = new Vec3(this.getX() - entity.getX(), this.getY(0.5) - entity.getEyeY(), this.getZ() - entity.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() + (double)(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);
+        Vec3 vec3d = new Vec3(this.getX() - entity.getX(), this.getY(0.5D) - entity.getEyeY(), this.getZ() - entity.getZ());
+
+        vec3d = vec3d.normalize();
+        double d0 = 16.0D;
+        double d1 = this.getX() + (this.random.nextDouble() - 0.5D) * 8.0D - vec3d.x * 16.0D;
+        double d2 = this.getY() + (double) (this.random.nextInt(16) - 8) - vec3d.y * 16.0D;
+        double d3 = this.getZ() + (this.random.nextDouble() - 0.5D) * 8.0D - vec3d.z * 16.0D;
+
+        return this.teleport(d1, d2, d3);
     }
 
     private boolean teleport(double x, double y, double z) {
-        BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos(x, y, z);
+        BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos(x, y, z);
 
-        while (mutableBlockPos.getY() > this.level().getMinBuildHeight() && !this.level().getBlockState(mutableBlockPos).blocksMotion()) {
-            mutableBlockPos.move(Direction.DOWN);
+        while (blockposition_mutableblockposition.getY() > this.level().getMinBuildHeight() && !this.level().getBlockState(blockposition_mutableblockposition).blocksMotion()) {
+            blockposition_mutableblockposition.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, GameEvent.Context.of(this));
+        BlockState iblockdata = this.level().getBlockState(blockposition_mutableblockposition);
+        boolean flag = iblockdata.blocksMotion();
+        boolean flag1 = iblockdata.getFluidState().is(FluidTags.WATER);
+
+        if (flag && !flag1) {
+            Vec3 vec3d = this.position();
+            boolean flag2 = this.randomTeleport(x, y, z, true);
+
+            if (flag2) {
+                this.level().gameEvent((Holder) GameEvent.TELEPORT, vec3d, GameEvent.Context.of((Entity) this));
                 if (!this.isSilent()) {
-                    this.level().playSound(null, this.xo, this.yo, this.zo, SoundEvents.ENDERMAN_TELEPORT, this.getSoundSource(), 1.0F, 1.0F);
+                    this.level().playSound((Player) 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;
+            return flag2;
         } else {
             return false;
         }
@@ -333,28 +362,32 @@
     @Override
     protected void dropCustomDeathLoot(DamageSource source, int lootingMultiplier, boolean allowDrops) {
         super.dropCustomDeathLoot(source, lootingMultiplier, allowDrops);
-        BlockState blockState = this.getCarriedBlock();
-        if (blockState != null) {
-            ItemStack itemStack = new ItemStack(Items.DIAMOND_AXE);
-            itemStack.enchant(Enchantments.SILK_TOUCH, 1);
-            LootParams.Builder builder = new LootParams.Builder((ServerLevel)this.level())
-                .withParameter(LootContextParams.ORIGIN, this.position())
-                .withParameter(LootContextParams.TOOL, itemStack)
-                .withOptionalParameter(LootContextParams.THIS_ENTITY, this);
+        BlockState iblockdata = this.getCarriedBlock();
 
-            for (ItemStack itemStack2 : blockState.getDrops(builder)) {
-                this.spawnAtLocation(itemStack2);
+        if (iblockdata != null) {
+            ItemStack itemstack = new ItemStack(Items.DIAMOND_AXE);
+
+            itemstack.enchant(Enchantments.SILK_TOUCH, 1);
+            LootParams.Builder lootparams_a = (new LootParams.Builder((ServerLevel) this.level())).withParameter(LootContextParams.ORIGIN, this.position()).withParameter(LootContextParams.TOOL, itemstack).withOptionalParameter(LootContextParams.THIS_ENTITY, this);
+            List<ItemStack> list = iblockdata.getDrops(lootparams_a);
+            Iterator iterator = list.iterator();
+
+            while (iterator.hasNext()) {
+                ItemStack itemstack1 = (ItemStack) iterator.next();
+
+                this.spawnAtLocation(itemstack1);
             }
         }
+
     }
 
     public void setCarriedBlock(@Nullable BlockState state) {
-        this.entityData.set(DATA_CARRY_STATE, Optional.ofNullable(state));
+        this.entityData.set(EnderMan.DATA_CARRY_STATE, Optional.ofNullable(state));
     }
 
     @Nullable
     public BlockState getCarriedBlock() {
-        return this.entityData.get(DATA_CARRY_STATE).orElse(null);
+        return (BlockState) ((Optional) this.entityData.get(EnderMan.DATA_CARRY_STATE)).orElse((Object) null);
     }
 
     @Override
@@ -362,52 +395,68 @@
         if (this.isInvulnerableTo(source)) {
             return false;
         } else {
-            boolean bl = source.getDirectEntity() instanceof ThrownPotion;
-            if (!source.is(DamageTypeTags.IS_PROJECTILE) && !bl) {
-                boolean bl3 = super.hurt(source, amount);
+            boolean flag = source.getDirectEntity() instanceof ThrownPotion;
+            boolean flag1;
+
+            if (!source.is(DamageTypeTags.IS_PROJECTILE) && !flag) {
+                flag1 = super.hurt(source, amount);
                 if (!this.level().isClientSide() && !(source.getEntity() instanceof LivingEntity) && this.random.nextInt(10) != 0) {
                     this.teleport();
                 }
 
-                return bl3;
+                return flag1;
             } else {
-                boolean bl2 = bl && this.hurtWithCleanWater(source, (ThrownPotion)source.getDirectEntity(), amount);
+                flag1 = flag && this.hurtWithCleanWater(source, (ThrownPotion) source.getDirectEntity(), amount);
 
-                for (int i = 0; i < 64; i++) {
+                if (this.tryEscape(com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.INDIRECT)) { // Paper - EndermanEscapeEvent
+                for (int i = 0; i < 64; ++i) {
                     if (this.teleport()) {
                         return true;
                     }
                 }
+                } // Paper - EndermanEscapeEvent
 
-                return bl2;
+                return flag1;
             }
         }
     }
 
     private boolean hurtWithCleanWater(DamageSource source, ThrownPotion potion, float amount) {
-        ItemStack itemStack = potion.getItem();
-        PotionContents potionContents = itemStack.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY);
-        return potionContents.is(Potions.WATER) && super.hurt(source, amount);
+        ItemStack itemstack = potion.getItem();
+        PotionContents potioncontents = (PotionContents) itemstack.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY);
+
+        return potioncontents.is(Potions.WATER) ? super.hurt(source, amount) : false;
     }
 
     public boolean isCreepy() {
-        return this.entityData.get(DATA_CREEPY);
+        return (Boolean) this.entityData.get(EnderMan.DATA_CREEPY);
     }
 
     public boolean hasBeenStaredAt() {
-        return this.entityData.get(DATA_STARED_AT);
+        return (Boolean) this.entityData.get(EnderMan.DATA_STARED_AT);
     }
 
     public void setBeingStaredAt() {
-        this.entityData.set(DATA_STARED_AT, true);
+        this.entityData.set(EnderMan.DATA_STARED_AT, true);
+    }
+
+    // Paper start
+    public void setCreepy(boolean creepy) {
+        this.entityData.set(EnderMan.DATA_CREEPY, creepy);
     }
 
+    public void setHasBeenStaredAt(boolean hasBeenStaredAt) {
+        this.entityData.set(EnderMan.DATA_STARED_AT, hasBeenStaredAt);
+    }
+    // Paper end
+
     @Override
     public boolean requiresCustomPersistence() {
         return super.requiresCustomPersistence() || this.getCarriedBlock() != null;
     }
 
-    static class EndermanFreezeWhenLookedAt extends Goal {
+    private static class EndermanFreezeWhenLookedAt extends Goal {
+
         private final EnderMan enderman;
         @Nullable
         private LivingEntity target;
@@ -423,8 +472,9 @@
             if (!(this.target instanceof Player)) {
                 return false;
             } else {
-                double d = this.target.distanceToSqr(this.enderman);
-                return !(d > 256.0) && this.enderman.isLookingAtMe((Player)this.target);
+                double d0 = this.target.distanceToSqr((Entity) this.enderman);
+
+                return d0 > 256.0D ? false : this.enderman.isLookingAtMe((Player) this.target);
             }
         }
 
@@ -439,7 +489,8 @@
         }
     }
 
-    static class EndermanLeaveBlockGoal extends Goal {
+    private static class EndermanLeaveBlockGoal extends Goal {
+
         private final EnderMan enderman;
 
         public EndermanLeaveBlockGoal(EnderMan enderman) {
@@ -448,44 +499,82 @@
 
         @Override
         public boolean canUse() {
-            return this.enderman.getCarriedBlock() != null
-                && this.enderman.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)
-                && this.enderman.getRandom().nextInt(reducedTickDelay(2000)) == 0;
+            return this.enderman.getCarriedBlock() == null ? false : (!this.enderman.level().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, GameEvent.Context.of(this.enderman, blockState3));
-                    this.enderman.setCarriedBlock(null);
+            RandomSource randomsource = this.enderman.getRandom();
+            Level world = this.enderman.level();
+            int i = Mth.floor(this.enderman.getX() - 1.0D + randomsource.nextDouble() * 2.0D);
+            int j = Mth.floor(this.enderman.getY() + randomsource.nextDouble() * 2.0D);
+            int k = Mth.floor(this.enderman.getZ() - 1.0D + randomsource.nextDouble() * 2.0D);
+            BlockPos blockposition = new BlockPos(i, j, k);
+            BlockState iblockdata = world.getBlockStateIfLoaded(blockposition); // Paper - Prevent endermen from loading chunks
+            if (iblockdata == null) return; // Paper - Prevent endermen from loading chunks
+            BlockPos blockposition1 = blockposition.below();
+            BlockState iblockdata1 = world.getBlockState(blockposition1);
+            BlockState iblockdata2 = this.enderman.getCarriedBlock();
+
+            if (iblockdata2 != null) {
+                iblockdata2 = Block.updateFromNeighbourShapes(iblockdata2, this.enderman.level(), blockposition);
+                if (this.canPlaceBlock(world, blockposition, iblockdata2, iblockdata, iblockdata1, blockposition1)) {
+                    if (CraftEventFactory.callEntityChangeBlockEvent(this.enderman, blockposition, iblockdata2)) { // CraftBukkit - Place event
+                    world.setBlock(blockposition, iblockdata2, 3);
+                    world.gameEvent((Holder) GameEvent.BLOCK_PLACE, blockposition, GameEvent.Context.of(this.enderman, iblockdata2));
+                    this.enderman.setCarriedBlock((BlockState) null);
+                    } // CraftBukkit
                 }
+
             }
         }
 
         private boolean canPlaceBlock(Level world, BlockPos posAbove, BlockState carriedState, BlockState stateAbove, BlockState state, BlockPos pos) {
-            return stateAbove.isAir()
-                && !state.isAir()
-                && !state.is(Blocks.BEDROCK)
-                && state.isCollisionShapeFullBlock(world, pos)
-                && carriedState.canSurvive(world, posAbove)
-                && world.getEntities(this.enderman, AABB.unitCubeFromLowerCorner(Vec3.atLowerCornerOf(posAbove))).isEmpty();
+            return stateAbove.isAir() && !state.isAir() && !state.is(Blocks.BEDROCK) && state.isCollisionShapeFullBlock(world, pos) && carriedState.canSurvive(world, posAbove) && world.getEntities(this.enderman, AABB.unitCubeFromLowerCorner(Vec3.atLowerCornerOf(posAbove))).isEmpty();
         }
     }
 
-    static class EndermanLookForPlayerGoal extends NearestAttackableTargetGoal<Player> {
+    private static class EndermanTakeBlockGoal extends Goal {
+
+        private final EnderMan enderman;
+
+        public EndermanTakeBlockGoal(EnderMan enderman) {
+            this.enderman = enderman;
+        }
+
+        @Override
+        public boolean canUse() {
+            return this.enderman.getCarriedBlock() != null ? false : (!this.enderman.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) ? false : this.enderman.getRandom().nextInt(reducedTickDelay(20)) == 0);
+        }
+
+        @Override
+        public void tick() {
+            RandomSource randomsource = this.enderman.getRandom();
+            Level world = this.enderman.level();
+            int i = Mth.floor(this.enderman.getX() - 2.0D + randomsource.nextDouble() * 4.0D);
+            int j = Mth.floor(this.enderman.getY() + randomsource.nextDouble() * 3.0D);
+            int k = Mth.floor(this.enderman.getZ() - 2.0D + randomsource.nextDouble() * 4.0D);
+            BlockPos blockposition = new BlockPos(i, j, k);
+            BlockState iblockdata = world.getBlockStateIfLoaded(blockposition); // Paper - Prevent endermen from loading chunks
+            if (iblockdata == null) return; // Paper - Prevent endermen from loading chunks
+            Vec3 vec3d = new Vec3((double) this.enderman.getBlockX() + 0.5D, (double) j + 0.5D, (double) this.enderman.getBlockZ() + 0.5D);
+            Vec3 vec3d1 = new Vec3((double) i + 0.5D, (double) j + 0.5D, (double) k + 0.5D);
+            BlockHitResult movingobjectpositionblock = world.clip(new ClipContext(vec3d, vec3d1, ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, this.enderman));
+            boolean flag = movingobjectpositionblock.getBlockPos().equals(blockposition);
+
+            if (iblockdata.is(BlockTags.ENDERMAN_HOLDABLE) && flag) {
+                if (CraftEventFactory.callEntityChangeBlockEvent(this.enderman, blockposition, iblockdata.getFluidState().createLegacyBlock())) { // CraftBukkit - Place event // Paper - fix wrong block state
+                world.removeBlock(blockposition, false);
+                world.gameEvent((Holder) GameEvent.BLOCK_DESTROY, blockposition, GameEvent.Context.of(this.enderman, iblockdata));
+                this.enderman.setCarriedBlock(iblockdata.getBlock().defaultBlockState());
+                } // CraftBukkit
+            }
+
+        }
+    }
+
+    private static class EndermanLookForPlayerGoal extends NearestAttackableTargetGoal<Player> {
+
         private final EnderMan enderman;
         @Nullable
         private Player pendingTarget;
@@ -498,8 +587,9 @@
         public EndermanLookForPlayerGoal(EnderMan enderman, @Nullable Predicate<LivingEntity> targetPredicate) {
             super(enderman, Player.class, 10, false, false, targetPredicate);
             this.enderman = enderman;
-            this.isAngerInducing = playerEntity -> (enderman.isLookingAtMe((Player)playerEntity) || enderman.isAngryAt(playerEntity))
-                    && !enderman.hasIndirectPassenger(playerEntity);
+            this.isAngerInducing = (entityliving) -> {
+                return (enderman.isLookingAtMe((Player) entityliving) || enderman.isAngryAt(entityliving)) && !enderman.hasIndirectPassenger(entityliving);
+            };
             this.startAggroTargetConditions = TargetingConditions.forCombat().range(this.getFollowDistance()).selector(this.isAngerInducing);
         }
 
@@ -549,7 +639,7 @@
         @Override
         public void tick() {
             if (this.enderman.getTarget() == null) {
-                super.setTarget(null);
+                super.setTarget((LivingEntity) null);
             }
 
             if (this.pendingTarget != null) {
@@ -560,56 +650,20 @@
                 }
             } else {
                 if (this.target != null && !this.enderman.isPassenger()) {
-                    if (this.enderman.isLookingAtMe((Player)this.target)) {
-                        if (this.target.distanceToSqr(this.enderman) < 16.0) {
+                    if (this.enderman.isLookingAtMe((Player) this.target)) {
+                        if (this.target.distanceToSqr((Entity) this.enderman) < 16.0D && this.enderman.tryEscape(com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.STARE)) { // Paper - EndermanEscapeEvent
                             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)) {
+                    } else if (this.target.distanceToSqr((Entity) this.enderman) > 256.0D && 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() {
-            return this.enderman.getCarriedBlock() == null
-                && this.enderman.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)
-                && 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((double)this.enderman.getBlockX() + 0.5, (double)j + 0.5, (double)this.enderman.getBlockZ() + 0.5);
-            Vec3 vec32 = new Vec3((double)i + 0.5, (double)j + 0.5, (double)k + 0.5);
-            BlockHitResult blockHitResult = level.clip(new ClipContext(vec3, vec32, ClipContext.Block.OUTLINE, ClipContext.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, GameEvent.Context.of(this.enderman, blockState));
-                this.enderman.setCarriedBlock(blockState.getBlock().defaultBlockState());
-            }
         }
     }
 }
