Many of the packets concerning the communication about entities between server and client store integers with a conversion factor instead of the exact real numbers.
This causes a variety of issues in (to my knowledge) all versions of Minecraft up to now.
Examples of the implications are:
1) It is impossible to specify the position of an entity using commands to any precision better than 1/32 of a block.
This can be seen for instance after:
/summon Giant 0 64.00 0 {NoAI:1}
/summon Giant 0 64.02 0 {NoAI:1}
Both Giants will appear to be in the same position. However, a third Giant summoned at:
/summon Giant 0 64.04 0 {NoAI:1}
will appear to hover 1/32 of a block higher than the other two giants.
2) This is probably also the most common cause for MC-4. This can easily be reproduced with the following commands:
/setblock 1 80 1 stone
/summon Item 0.9 81 0.9 {Item:{id:1,Count:1}}
For the client, the summoned item will visually appear to fall off the block. It then appears to teleport back to the top of the block every other second, only to start falling again.
The reason for this is that the sever knows that the item is at the given coordinates (0.9, 81, 0.9)
. The item cannot fall down from there as the item's hitbox touches the stone block. In mathematical terms this is: 0.9 + 0.125 > 1.0, where 0.125 is half the width of the item's hitbox.
Now the client only knows what the server tells it via packets. However, the packets are created in the following manner:
/* pseudo java code */
packetOut.posX = (int)MathHelper.floor_double(entity.posX * 32.0D);
packetOut.posY = (int)MathHelper.floor_double(entity.posY * 32.0D);
packetOut.posZ = (int)MathHelper.floor_double(entity.posZ * 32.0D);
The information is then recovered from the packet by the client with:
/* pseudo java code */
double posX = (double)packetIn.getPosX() / 32.0D;
double posY = (double)packetIn.getPosY() / 32.0D;
double posZ = (double)packetIn.getPosZ() / 32.0D;
Thus, the client can only know about the position of the item (and any other entity) to a precision of 1/32 of a block.
So the client thinks the item is at (floor(0.9 * 32), 81, floor(0.9 * 32)) = (0.875, 81, 0.875)
. At this position the item can fall down, as the item's hitbox does just about not touch the stone block. In mathematical terms, 0.875 + 0.125 ≯ 1.0. As a result, the item appears to fall down for the client while the server keeps it on top of the block (i.e. MC-4).
But it is not just the position of entities that is affected. Entity rotations are only stored to the nearest 1/256 of a full rotation (~1.41°). Also velocities are stored to the nearest 1/8000 block per tick. Furthermore, fixing this bug would allow map makers to use high precision entity manipulation to get rid of the Z-Fighting effect in their creations, by choosing small differences in positions.
Possible Fix
As a test I wrote a mod to mostly fix this issue by changing the variable types in the entity packets (see below for a list) from ints to doubles/floates and got rid of all occurences of multiplication/division factors involved. This means that rather than storing some discrete data, the packets contain the exact values used in the rest of the game code. As a result MC-4 seemed to be fixed as I could no longer reproduce it, and I was able to get rid of Z-fighting effects by teleporting/summoning entities to very slightly different coordinates.
I changed the following classes in my fix-mod (I only made it for 1.8.0 and single player, using MCP):
NetHandlerPlayClient.java
Entity.java
EntityTrackerEntry.java
S0EPacketSpawnObject.java
S2CPacketSpawnGlobalEntity.java
S0CPacketSpawnPlayer.java
S18PacketEntityTeleport.java
S0FPacketSpawnMob.java
S14PacketEntity.java
I noticed that in NetHandlerPlayClient.java the code that processes the S11PacketSpawnExperienceOrb packets (around line 456) does not have the '/ 32.0D' conversion (which I removed everywhere else by writing this mod). This is a bug that seems to be described by MC-11601.
Related issues
relates to
Attachments
Comments


Relates to or duplicated by:
This is a pretty good and informative report!
Maybe Text Formatting Notation Help can help you with the formatting of this report.
Confirmed for
15w35c with the item
Just use the following command in a command block
/summon Item ~-0.6 ~1 ~-0.6 {Item:{id:stone,Count:1}}

@unknown Please do not hit save when making constant edits, all watchers will get repeated emails each time. There is a preview button you can use if you are unsure of what the edits will look like.

I can confirm as for ArmorStands, I make many mainly aesthetical custom command creations, and due to the odd sizes (NOT full pixels) of custom heads/skulls at ArmorStands it's close to impossible to get them aligned properly at the very edge of a regular MC block (at least the client cannot display it) by teleporting them with tiny bits of values.
Either they are a tad too far away from the edge, or a tad over it, so they are unusable for those creations who rely on pixel-exactness.
Same goes for the rotation values. Not all of them are being displayed, so adjustments here to balance out the odd skull sizes on ArmorStands isn't really possible either.
I'll post some screenshots.

First picture with the Quartz blocks on small Armorstands:
regular MC blocks can be teleported to the very edge of a regular MC block, because their pixel sizes are fix (7 for small, 10 for normal Armorstands).
Other 3 pictures: Due to the odd pixelsize custom heads got on ArmorStands, it is close to impossible to get them aligned to the very edge of a regular MC block, because the client cannot display tiny bits of teleportation, and also not rotation.

Although this is a good fix, there is probably a good reason why those values are int's. Floats and doubles take noticeably more network bandwidth to encode and transmit. Scale that up to 50 players at once and your network is struggling to keep up.

Unless the there is some data size conversion, ints and floats should both be 4 bytes in size, so a conversion between float and double should, in theory, yield better results without compromise to the network traffic. While the conversion may result in some loss in precision, the results should still be less than 1/32 off from the correct position.

I just did some more testing and code digging and as far as I can tell there are two types of packets that are called rather often:
S14PacketEntity, which exists in 3 variants:
S15PacketEntityRelMove
S16PacketEntityLook
S17PacketEntityLookMove
S18PacketEntityTeleport
The S14PacketEntity packets do indeed contain size optimised data. Single bytes represent an offset to the current position in 1/32 blocks (which allows for changes of about +-4 blocks).
Assuming a boolean is one byte, then a S14PacketEntity packet would (probably) have a size of 11 bytes.
The S18PacketEntityTeleport seems to be called rather often as well, in particular it seems to be called when an entity moves fairly quickly, e.g. whenever it jumps. This packet contains the absolute positions in 1/32 blocks in the form of ints. Again assuming a boolean is one byte, then a S18PacketEntityTeleport packet would (probably) have a size of 19 bytes.
The ints in the S18PacketEntityTeleport class could easily be replaced with floats, which for the most part would already fix the issues I described, without increasing the packet sizes at all. Furthermore one could use a form of half-precision floats (2 bytes) or other minifloats instead of the one-byte integers, which would increase the resolution considerably, without increasing the packet sizes too much.
All the other packets concerned (S0FPacketSpawnMob, S0EPacketSpawnObject etc.) are called less often and use ints, just like S18PacketEntityTeleport. So they should probably also use doubles or at least floats instead.
When we use something other than the true internal representation of these values we're going to have this problem exist, it will just become less and less obvious (and thus harder to reproduce 😃).
This would mean we'd be using doubles for each x/y/z we send over the wire inflating the packetsizes significantly.
There are some other solutions for this, like bundling all of the movement within a chunk together, this at least drops the overhead of the packet-headers (which for these packets is quite significant) but is going to be a significant change to how we collect+send these deltas. Another solution is to 'on sync' truncate the value on the server like we do over the network, this might however lead to weird jumping/sliding behavior on the server. A bit more drastic solution is to simply make every single thing integer based, subdivide a block in 256 and snap anything and everything to that grid, this allows us to send deltas in whatever size because we have absolute precision, but this obviously is a MAJOR change in the whole codebase.
I'm not really sure what to do, but from all this above, looking into bundling data per chunk and actually using doubles might be worthwhile to investigate eventually.

Using the internal representation would be preferable to making it harder to reproduce.
Bundling the packets to the chunks seems like a good option to me. The grid-snapping might cause problems with the motion (assuming ints are used for the motion as well). This would become especially noticeable at slow speed and small angles.
Also I just did a few tests and it seems that about three quarters of the S15PacketEntityRelMove packets store a Y-change of zero. This is probably due to all the mobs that are moving while staying on the ground. It would be unnecessary to store the full 8 bytes of a double for this very common case. So separating ground motion and other motion could be an option to consider.

I just thought of adding a TinyEntityMove packet, which moves the entity inside 1/32 of a block with a precision of 1/32. This packet could be sent by the server if the entity is not moving much or not at all to get a higher precision. Or you could add a boolean to the existing packet for this.

I'm pretty sure this was fixed in 1.9 (protocol diff).