mojira.dev
MC-9935

EntityAIAvoidEntity Interference

Creeper doesn't react at the Cat if there is another Cat (not visible for Creeper) within 3 blocks below it.

Most likely Creeper checks Cat presence starting from below coordinates and getting locked at first found Cat.

At the first screenshot, 2nd and 3rd floor Creepers doesn't react at their Cat unless you kill Cat below.

At the second screenshot all Creepers act properly.

Attachments

Comments 3

The EntityAIAvoidEntity only looks for +/-3 blocks up and down from the entity (creeper). That is why it works if the cat below is more than 3 blocks below.

The reason why it ignores the upper cat when there is one below and within those 3 blocks is because the routine that seeks for entities works from bottom up, and adds the results into a list in the order found. The AI routine itself is more than a bit naive, and picks the first result as the one entity it is going to avoid, if needed (i.e. if it can see it).

One fix might be to loop through the result list, and skip an entity if it can not be seen (or is otherwise ignorable). This will cause a tiny bit of extra processing, and will still leave e.g. such weird behaviour that if there is one cat further away but one block lower, and another cat right near the creeper at the same height and in the opposite direction as the first cat, the creeper would run right into the nearby cat.

Better solution would be to loop through the list, skip ignorable cases (i.e. can not see) and for valid cases add a vector from horror to creeper with length 1/distance to a sum. The sum vector would tell which way might be best to flee in panic. However, this adds more processing, though should still be nothing to worry about.

An inelegant but working fix

EntityAIAvoidEntity.shouldExecute()

...
    List entities = this.theEntity.worldObj.getEntitiesWithinAABB(this.targetEntityClass, this.theEntity.boundingBox.expand((double) this.distanceFromEntity, 3.0D, (double) this.distanceFromEntity));

    if (entities.isEmpty()) {
        return false;
    }

    //this.closestLivingEntity = (Entity) entities.get(0); // OLD CODE
    // FIX:
    Entity nearest = null;
    double nearestDistanceSquared = 10000000000d;
    for (Object entity : entities) {
        Entity ent = (Entity) entity;
        if (!this.theEntity.getEntitySenses().canSee(ent))
            continue;
        double d = ent.getDistanceSqToEntity(this.theEntity);
        if (d < nearestDistanceSquared) {
            nearestDistanceSquared = d;
            nearest = ent;
        }
    }
    if (nearest == null)
        return false;
    this.closestLivingEntity = nearest;
    ...

Tested on 1.4.7, with similar setup as in the screenshots. Now each creeper was fleeing the cat at the same height as it was. And all creepers did flee, sooner or later.

Edit: Additional improvement for efficiency would be good; the way it seeks for the location to flee to is so simplistic that it causes lots of unnecessary extra rounds through the shouldExecute() method. It should try harder to find a way to flee, in order to avoid doing the calculations to find the nearest cat (or whatever other solution is found for that) over and over again in rapid succession.

From your explanation all Entities that use this class have the same bug, so I updated the title and added example with Villagers and Zombies.

MTandi

Nathan Adams

Unconfirmed

Snapshot 13w07a

Snapshot 13w09a

Retrieved