The Bug:
Villagers can trample farmland.
This issue can commonly be seen when farmer villagers wander and jump around their workstations.
Steps to Reproduce:
Build the setup as shown in the attachment below.
Summon a villager and wait for it to claim the composter as its workstation.
Give the villager some carrots so it can begin working.
Observe the behavior of the villager for around a minute and watch closely as it wanders and jumps around its workstation.
Take note as to whether or not villagers can trample farmland.
Observed Behavior:
Villagers can trample farmland.
Expected Behavior:
Villagers would not be able to trample farmland.
Code Analysis:
Code analysis by @unknown can be found below.
The following is based on a decompiled version of Minecraft 1.19.2 using MCP-Reborn.
net.minecraft.world.level.block.FarmBlock.java
public class FarmBlock extends Block {
...
public void fallOn(Level level, BlockState blockState, BlockPos blockPos, Entity entity, float f) {
if (!level.isClientSide
&& level.random.nextFloat() < f - 0.5F
&& entity instanceof LivingEntity
&& (entity instanceof Player || level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))
&& entity.getBbWidth() * entity.getBbWidth() * entity.getBbHeight() > 0.512F) {
turnToDirt(blockState, level, blockPos);
}
super.fallOn(level, blockState, blockPos, entity, f);
}
...
If we look at the above class, we can see that there are only two necessary checks that are carried out before allowing villagers to trample farmland. One of these checks is to quite simply see if the entity falling on the farmland is a living entity and if it is, the other check is then to see if "mobGriefing" gamerule is set to "true". If these two requirements are met along with the other criteria within the "if" statement, the farmland can be trampled. The game doesn't check to see if the living entity is a villager before allowing them to trample farmland, therefore resulting in this problem occurring.
Fix:
Simply altering the existing "if" statement within this piece of code to check if the living entity is a villager before allowing them to trample farmland will resolve this problem.
Current "if" statement:
if (!level.isClientSide
&& level.random.nextFloat() < f - 0.5F
&& entity instanceof LivingEntity
&& (entity instanceof Player || level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))
&& entity.getBbWidth() * entity.getBbWidth() * entity.getBbHeight() > 0.512F)
Fixed "if" statement:
if (!level.isClientSide
&& level.random.nextFloat() < f - 0.5F
&& (entity instanceof LivingEntity && !(entity instanceof Villager))
&& (entity instanceof Player || level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))
&& entity.getBbWidth() * entity.getBbWidth() * entity.getBbHeight() > 0.512F)
Linked issues
is duplicated by 12
Attachments
Comments 21
As a possible fix, why not add a "Soft Step" attribute to villagers that makes them unable to trample farmland no matter how they fall on it?
If it's a tag added to the Entity data shared by mobs, makers of adventure maps could also make the mobs of their choice unable to trample farmland.
At first, I felt this was an issue. However, I no longer feel this way: Even in "real", situations can occur which can and do trample crops. This ranges from combat to trespassers taking a "shortcut" through a farm field.
Instead, what I believe the issue is:
Villagers themselves should attempt to avoid actions that would trample crops in normal circumstances. A villager being chased by a zombie, for example, is not going to stop and consider if his running away will trample crops; He is going to run for his life! This is the same reason am iron golem will not wait for a zombie to move to a clear spot before trying to engage the zombie in combat.
There are two immediate "fixes" I can imagine:
(1): Re-arrange generated farms to place the composter either on a block not direcly adjacent to farmland, or lower the composter by one block so villagers will not "jump down" to get off the composter.
And/or (2): Check at an appropriate place in the villager movement code if the next move might trample crops, and choose an alternate route/movement if it might. This way, the check can be skipped if the villager is "fleeing in terror and does not care about crops". It would also affect them if, for example, a tree had spawned in such a way that the leaves become another possible place to "leap down" upon crops.
Following on from my code analysis, I've double-checked my proposed fix and I can confidently confirm that it's fully functioning and works as expected, so I've attached two screenshots to this report, one of which shows the current code and the other that shows the fixed code. I feel this information may be quite insightful hence my reasoning for providing it. 🙂
[media][media]
They also jump next to waterlogged blocks that are there for hydrating the farmland, which also tramples farmland:
[media]