The bug
Since farmland is now 15/16 of a block, jumping on it will change it back to dirt, which is a full block. The player is now stuck inside the block.
Caused by fixing MC-85162.
Code analysis / Fix
See this comment by @unknown.
Linked issues
is cloned by 1
relates to 4
testing discovered 1
Attachments
Comments 24
I didn't see this issue before submitting mine, but that's because I was looking for the keyword villager in the subject and should have searched for farmland or similar. Anyways, on mine, I attached a video showing a villager falling through the block. See MC-104906. Hope it helps get it resolved soon.
Confirmed for 1.10.2 as well. The obvious fix would be that when the farmland converts to dirt, it finds all entities within its new bounding box (or within its old bounding box + 1/16 on the y axis) and teleports them up by 0.0625 (1/16) blocks. From what I remember of modding, that should be just a few lines of code to fix this (of course, I'm not sure how different the Forge API is to the original source code, so maybe it's harder than it seems).
Can anyone still reproduce this with a single farmland block only or only with at least two (see this comment)? If not the description needs to be updated.
I could directly reproduce it with the setup described in the post you linked (sign on 2nd farmland etc.), couldn't reproduce with single farmland yet, but maybe my setup for one farmland is wrong atm.
Also can't reproduce it so far with the single-farmland-instructions from the same comment (positioning at .9).
Alright, figured this out. (MCP 940, with 1.12.1 SRG mappings)
Why it only works some of the time
@unknown' fix in 16w35a (which was suggested by @unknown) is correct, but the implementation has a slight flaw: it only sets the position on the server; the client isn't informed that it should move up. However, there is another mechanism that later causes the client to be informed: the serverside check that prevents players from moving into blocks. When the block is changed, the client starts falling into it. However, the server detects this and rejects that movement (after all, the server thinks the player is on top of the block). The server then teleports the player on top of the block, and everything is fine.
However, if the player does not fall (i.e. they're partially standing on another block), then the server doesn't move them up (even though they are still positioned inside a block). Why doesn't the server think they're in a block and thus move them out in this case? Well, for some reason, hitboxes are shrunk slightly before checking if the player is in a block. Specifically, they're shrunk by 0.0625D
... or precisely 1/16th of a block. So the server is completely fine with the player being partially inside the farmland. And thus, the player can still move around, and overwrite the moved up position that the farmland chose. Then, when the player moves too far forward and has no other block holding them up, they start falling into the farmland. This time, there's no server position outside of the block to help them, and they get stuck.
Fix
To fix this, the client needs to be informed of the change in position using NetHandlerPlayClient.setPlayerLocation
(this same special casing is used in plenty of other places, including the teleport commands):
private void turnToDirt(World worldIn, BlockPos pos) {
IBlockState iblockstate = Blocks.DIRT.getDefaultState();
worldIn.setBlockState(pos, iblockstate);
AxisAlignedBB axisalignedbb = iblockstate.getCollisionBoundingBox(worldIn, pos).offset(pos);
for (Entity entity : worldIn.getEntitiesWithinAABBExcludingEntity((Entity)null, axisalignedbb)) {
if (entity instanceof EntityPlayerMP) {
double delta = axisalignedbb.maxY - entity.posY;
((EntityPlayerMP) entity).connection.setPlayerLocation(0, delta, 0, 0, 0, EnumSet.allOf(SPacketPlayerPosLook.EnumFlags.class));
} else {
entity.setPosition(entity.posX, axisalignedbb.maxY, entity.posZ);
}
}
}
(I use a relative teleport instead of an absolute one because a relative teleport will be smoother)
This same logic should be added to BlockGrassPath
. While grass paths can't be trampled, they do change when blocks are placed above them (for instance, signs). They do not make any attempt to move players out of the ground, which means that players will get stuck in them when the block is placed (again, the 1/16th of a block contraction). Fixing this simply requires adding the same code to BlockGrassPath
's dirt conversion logic (which MCP calls updateBlockState
).
Caused by the fix of MC-85162 ?