Steps to reproduce
Load
in Windows 10.
Break the nearest bed to the player.
Load a fresh copy of
on an ARM device.
Break the nearest bed to the player.
Expected result
In steps (2) and (4) the villager from the broken bed does the same thing.
Actual result
In step (2) the villager links to one of the beds in the farther away village. In step (4) the villager does not link to any bed.
Code analysis provided in this comment.
Hi,
Since 1.13 villages behave weirdly.
I made this world to demonstrate it.
On windows, if you break one of the bed the villagers are in (right in front of you when you load the world), the villager will link on the village on the left.
On Android the village will stay there and not link to any free bed.
I believe this is a bug in the way the game finds the closest village.
Linked issues
relates to 1
Attachments
Comments 9
Your expectation that you should observe the same behavior on both platforms is unjustified. I'm sure you've done lots of experiments that led you to expect a villager to join the closest village, because it usually works out that way, but I can assure you (based on my own experiments) that there's no such algorithm in the game.
I know, for example, that a villager can only join a village that's in a ticking area. You can construct an experiment wherein a villager is closer to village A than village B, but position the player so that village B is within the player's ticking area while village A isn't. The villager will not join village A in that case, and it might or might not join village B. The "closest village" rule is too simple to be reliable, because it doesn't account for the ticking area test that the game actually uses.
I realize that this doesn't explain what's happening in your case, but what it does do is demonstrate that the algorithm isn't as simple as you've assumed. There could be a difference between the worlds in your two platforms that accounts for the results, and you're simply not aware that the difference is there or that it matters in this case.
I'm also not clear on what your circles are supposed to represent. In all my own experiments with villages, I've never seen anything that was based on a circular or spherical range around a village center. As far as I've ever seen, ranges related to villages are based on the distance to a village boundary. (Incidentally, since V&P the game doesn't keep track of village centers any more. The center is simply calculated from the rectangular village boundaries if it's needed. And in case you're not aware of it, it's not always the case that the village center coincides with a bed, bell, or workstation.)
Unfortunately, Mojang doesn't document the algorithms underlying the game mechanics (for a lot of very good reasons), so when we infer rules for game mechanics from experiments, they can only be rules of thumb. If such a rule is violated by the game, it's much more likely to be because your experiments aren't sophisticated enough to detect all the variables that the underlying algorithm depends on, than that it's a bug.
I've looked at the code, and there is a method called fetchClosestVillage in the VillageManager class that is used to distribute poi and villagers amongst villages.
The fact that you can't find that it's the closest village that is used, is because this particular method is bugged. Note that there is a limit to join a village of 96 on x-z and 38 on y.
To go into the specific of this bug, the methods computes the euclidian distance between a villager/poi and a village centers.
Since 1.13, it substract the "approximateRadius" which for square villages resumes as (x/2+z/2)*0.6, so roughly 38.4 blocks for a standard 64x64 village.
This gives a floating point value that is negative when you are less than 38.4 blocks away from a village in a sphere.
The error in the code is casting this negative floating point to an unsigned integer, which results in undefined behaviour in C++.
On Arm devices, results is 0, on x86 devices it's (2^64)-1-value).
I've also looked at the code and he is right fetchClosetVillage has a programming error that causes different behavior on ARM and Intel processors.
Under the circumstances, my previous comment doesn't apply. Since there are multiple votes for this issue, I'll confirm it and pass it along.
Reconfirmed in 1.16.201 using the test world on my Windows 10 PC and on my iPhone 8.
UPDATE: I have been told by code-diggers in outside conversation that the function causing this bug was replaced by a re-written function sometime during 1.16.0 to 1.16.200 so that the bug can no longer occur. The results I got testing with my iPhone were due to inherent randomness in how village dwellers lists are ordered each time you load a village, and not due to different device hardware as was described in comments above.
So I did a bit of testing and this is what I found...
The circle has a ~38 blocks radius and is centered on the village center.
The fact that it doesn't behave the same way on android and windows makes me think of an undefined C behaviour, like casting a negative signed value to unsigned.
Also I can confirm this still happens in beta 1.14.4