mojira.dev
MC-253908

Goat AI breaks when on non-full blocks and will not ram entities

The Bug

Goats, when on an area consisting of not full blocks (soul sand, mud, honey, path blocks, farmland, etc.)  Will not attack entities.  Additionally, if the entity is not placed on a full block (such as placing an armor stand on a path block), the goats will not ram it.

Reproduce

  • Make a room filled with a non full block like Soul Sand

  • Summon a goat

  • Go into survival

  • Do

    /execute as @e[type=minecraft:goat,limit=1,sort=nearest] run data modify entity @s Brain.memories."minecraft:ram_cooldown_ticks".value set value 1

Observed Result

The Goat never rammed

Expected Result

The Goat would ram

Linked issues

Attachments

Comments 2

Code analysis (Mojang mappings, 1.19.4-rc2): The ramming start is controlled by the PrepareRamNearestTarget behavior, which chooses a ram target position by picking the block position of the nearest targetable living entity, and then calculating the ram start position. PrepareRamNearestTarget#calculateRammingStartPosition will not return a block position if the block underneath the targeted ram position is not a walkable block. Not only that, it checks if every single block the goat will have to pathfind through is a walkable block:

...
    private Optional<BlockPos> calculateRammingStartPosition(PathfinderMob $$0, LivingEntity $$12) {
        BlockPos $$2 = $$12.blockPosition();
        if (!this.isWalkableBlock($$0, $$2)) {
            return Optional.empty();
        }
        ArrayList<BlockPos> $$3 = Lists.newArrayList();
        BlockPos.MutableBlockPos $$4 = $$2.mutable();
        for (Direction $$5 : Direction.Plane.HORIZONTAL) {
            $$4.set($$2);
            for (int $$6 = 0; $$6 < this.maxRamDistance; ++$$6) {
                if (this.isWalkableBlock($$0, (BlockPos)$$4.move($$5))) continue;
                $$4.move($$5.getOpposite());
                break;
            }
            if ($$4.distManhattan($$2) < this.minRamDistance) continue;
            $$3.add($$4.immutable());
        }
        ...
    }

    private boolean isWalkableBlock(PathfinderMob $$0, BlockPos $$1) {
        return $$0.getNavigation().isStableDestination($$1) && $$0.getPathfindingMalus(WalkNodeEvaluator.getBlockPathTypeStatic((BlockGetter)$$0.level, $$1.mutable())) == 0.0f;
    }
...

A walkable block has to be a stable destination, which in PathNavigation#isStableDestination(BlockPos), checks if there is a solid, full block underneath:

public boolean isStableDestination(BlockPos $$0) {
        BlockPos $$1 = $$0.below();
        return this.level.getBlockState($$1).isSolidRender(this.level, $$1);
    }

I believe that at least using isFaceSturdy(this.level, $$1, Direction.UP) instead of isSolidRender(this.level, $$1) would allow goats to ram on top of top slabs, glass blocks and slime blocks, which they currently don't do, while not breaking anything. However, they still wouldn't be ram on, for example, bottom slabs, enchanting tables or walls. Ideally, the behavior should use isPathfindable(...) instead, but that could break something.

Can confirm in 1.20.4

Patrick Reyman

(Unassigned)

Confirmed

Gameplay

Low

Mob behaviour

goat, pathfinding

1.19, 1.19.1 Pre-release 4, 1.19.3, 1.19.4 Release Candidate 2, 1.19.4, 1.20.4

Retrieved