mojira.dev

chumbanotz

Assigned

No issues.

Reported

MC-226948 Withers are now affected by potion effects Fixed MC-218695 Shulkers do not flash red when hurt or killed Fixed MC-216057 Invisible entities can be targeted on the debug screen Confirmed MC-214344 Snow Golems can place snow when not on the ground Confirmed MC-214113 Endermen and Shulkers can teleport onto the Nether roof Confirmed MC-213349 Certain mobs that can melee can't use the Fire Aspect enchantment Fixed MC-156600 Shields appear to stop blocking when they have taken damage and are still in use Fixed MC-29274 Withers will not pursue players in survival mode unless attacked Fixed MC-10818 Skeleton/Wither Skeleton leg texture experiences Z-fighting Fixed MC-10391 Monster Spawners can suffocate mobs Works As Intended MC-10387 The bottom of a Hopper becomes dark while being broken Fixed MC-10385 Hoppers display a breaking animation on their top Duplicate MC-10250 The Ender Dragon's death animation glitches upon world reload Fixed MC-10203 Incorrect Cave Spider shadow Fixed MC-9803 The Ender Dragon is harmed by Fishing Rods and Eggs Works As Intended MC-9600 Iron Golems are unaffected by Strength and Weakness potions Duplicate MC-9418 Beacon held by player has a flashing texture on the bottom Duplicate MC-9357 Mobs with the old AI have inverted head movement Fixed MC-9250 A Wither's shield glows red from damage instead of the Wither itself Fixed MC-9242 Withers glitch downwards while pressing against blocks Duplicate

Comments

The classes EntityDamageSource and IndirectEntityDamageSource override the method DamageSource#getLocalizedDeathMessage and check for the currently held item in the main hand of the attacker. As explained in this comment, the ItemStack responsible for the action should be stored in the projectile then passed to the DamageSource and used in the death message instead.

 A possible solution is to cache the ItemStack that causes the action in the DamageSource instance that will be used to cause the damage and check for enchantments against this item instead of the player's currently held item. The DamageSource will also need to be cached for projectiles and written to NBT in case the world is closed before the damage is applied.

On second thought, the DamageSource likely doesn't need to be written to NBT for projectiles, saving the ItemStack to the projectile should suffice. The ItemStack can be passed to the DamageSource when needed.

Spiders and Wolves use the class LeapAtTargetGoal which handles the leaping at their target. This class calls Goal::setFlags in its constructor with the values of Goal.Flag.MOVE and Goal.Flag.LOOK. These flags prevent other AI goals with the same flags from executing. The MeleeAttackGoal handles the melee attack and has the same goal flags set. To fix this, remove the call to Goal::setFlags from the LeapAtTargetGoal to allow it to run at the same time as MeleeAttackGoal.

I think this is related to my comment on MC-198068, but to summarize, the AI that controls them looking at their target is the same class that makes them pathfind to and attack their target, which keeps starting and resetting when they cannot find a path to the target, thus causing the mobs to briefly look at and away from the target.

Wolves are programmed to take less damage from a damage source with an associated entity that isn't a player or arrow, essentially taking a mob's damage on easy mode. My guess as to why is to make tamed wolves more useful when fighting mobs. Here's the relevant part of the code:

if (entity != null && !(entity instanceof Player) && !(entity instanceof AbstractArrow)) {
        damage = (damage + 1.0F) / 2.0F;
}

This class is called net.minecraft.util.Mth in Mojang's mappings.

It will still be possible to hit invisible entities, the name of the entity simply won't show on the debug screen.

I believe this may be the same issue as MC-121048.

The blaze is attacking itself. When a blaze gets hurts, it alerts other blazes within its follow range that it has been hurt and sets their attack target to the original blaze's target.

Mobs have an integer field called noActionTime which is increased every tick so long as the mob is alive and has its AI enabled. When a mob is within 32 blocks of the closest non-spectator player, this timer is set to zero. This field is also used to determine when a mob can randomly despawn. When this timer is greater than 100 ticks (10 seconds), most mobs are programmed to not wander around. This seems to be intentional given the name of the field. My guess is this was implemented to not use up the game's resources for mobs trying to pathfind that are far from any players. This value is not saved to NBT which means noActionTime is set to the default value of zero when the world is reloaded.

I can confirm that this is still an issue in 1.17 Release Candidate 1.

The mobs listed above all override the method LivingEntity::travel which controls the movement logic for mobs and players alike. Horses, donkeys, mules, llamas, trader llamas, zombie horses and skeleton horses all extend the same base class called AbstractHorse. Pigs and striders implement the interface ItemSteerable which handles its movement when ridden while its rider is holding the needed item for steering.

In the beginning of this method, these mobs checks if it is alive, which means all motion is skipped when it is dead. This check was likely put to stop these mobs moving when dying while being ridden. This check should be removed from the travel method and instead the method LivingEntity::isImmobile should be overridden which if true stop all AI logic for mobs. By default this method returns LivingEntity::isDeadOrDying. It seems this was attempted in the AbstractHorse class, however there is a simple mistake. Instead of this:

protected boolean isImmobile() {
    return super.isImmobile() && this.isVehicle() && this.isSaddled() || this.isEating() || this.isStanding();
 }

The logical AND should be replaced with logical OR after super.isImmobile(), like this:

protected boolean isImmobile() {
    return super.isImmobile() || this.isVehicle() && this.isSaddled() || this.isEating() || this.isStanding();
 }

The above code should be applied to pigs and striders as well without the specific horse methods.

Players and mobs use a timer to count down the next time they can take damage as described here called invulnerableTime. Which means that non-mob entities don't take more damage, but take damage every tick instead of every 10 ticks. Interestingly, the field invulnerableTime is available in the Entity class, so all that needs to be done is to take the logic from players/mobs and apply it to the other entities.

When any mob is attached with a lead, a field called restrictCenter is set to the leash holder's position and another field called restrictRadius stores the restriction distance which is set to 5 blocks when a mob is leashed. This field is tested for in various mob AI classes to check if a mob is allowed to navigate outside of the restrictRadius from the restrictCenter position and whether a mob should try to or continue to attack another mob if the target or the attacker is outside of this restriction. The issue is that when a mob has its lead removed, restrictRadius is not reset to the sentinel value of -1 (which means the mob has no restriction) until the game is reloaded.
This is also the cause for MC-221754.

The reasons for this is most likely related to MC-198068. See the comment here for an explanation.

The cause of this issue is likely located in the BodyRotationControl class. The yRot field is not updated when the mob is not moving. Here's an example of a fix in the method BodyRotationControl::clientTick. The only change is the addition of the last line.

if (this.isMoving()) {
         this.mob.yBodyRot = this.mob.getYRot(); // Take the logic from here
         this.rotateHeadIfNecessary();
         this.lastStableYHeadRot = this.mob.yHeadRot;
         this.headStableTime = 0;
      } else {
         if (this.notCarryingMobPassengers()) {
            if (Math.abs(this.mob.yHeadRot - this.lastStableYHeadRot) > 15.0F) {
               this.headStableTime = 0;
               this.lastStableYHeadRot = this.mob.yHeadRot;
               this.rotateBodyIfNecessary();
            } else {
               ++this.headStableTime;
               if (this.headStableTime > 10) {
                  this.rotateHeadTowardsFront();
               }
            }
            this.mob.setYRot(this.mob.yBodyRot). //And apply the opposite here
         }
      }

The mobs that have this issue all use the MeleeAttackGoal class or their own class that extends it. There is a field called lastCanUseCheck, which is the first check if the goal can be used. This field is used to ensure if at least one second has passed since the last time this goal executed before any other checks are done.

For the goal to execute, the mob then must have a target that is alive and the mob must either have a path to the target, or be within melee range. While the goal is running, a field called followingTargetEvenIfNotSeen is checked to allow the mob to pathfind toward the target even if it cannot be seen. Some mobs have this set to false, and others set to true.

The method MeleeAttackGoal::canContinueToUse is called each tick while the goal is running to check if the goal should continue. The field followingTargetEvenIfNotSeen is checked again in this method and if it's not true, the goal will stop if the mob does not have a path. Which means that when mobs occasionally can't find a path to the target and have followingTargetEvenIfNotSeen set to false, the goal stops and begins the checks to start again as described in the first and second paragraph.

The field lastCanUseCheck should be removed entirely, and the check for followingTargetEvenIfNotSeen in the method MeleeAttackGoal::canContinueToUse should also be removed.

This issue is directly responsible for MC-191642. The field that controls the attack timer is called ticksUntilNextAttack. When the goal starts, this field is set to zero, which, as a result of the above description, causes the timer to reset and allow the mob to attack twice in a row. The method MeleeAttackGoal::start should remove where the field ticksUntilNextAttack is set to zero.

Based on Mojang's mappings, the class FollowParentGoal controls the AI for baby animals to follow the nearest adult of the same type. This class needs to call Goal::setFlags with the value Goal.Flag.MOVE to prevent other goals that set this flag from executing.

Applies to slimes and magma cubes as well.