Villages are persisted to NBT, yet still destroyed/recreated on chunk reload
The bug
Villages and all of their doors are written to the NBT. However, once a chunk containing village doors is unloaded those doors are removed from the village (and the village possibly destroyed if its the last door)
When the player enters the area again, a completely new village is recreated from scratch.
It seems the intent from writing villages to the NBT is to keep villages and their door associations correctly intact. However, this is not the case when travelling far away or to another dimension.
Suggestion: Don't remove a door from a village if the chunk containing the door is unloaded.
How to reproduce
- Place a wooden door and two blocks behind it a solid block (for example sandstone)
- Summon a villager
- Pause the game and inspect the villages.dat file using for example the tool NBTExplorer
→ The village data contains the door data - Kill the villager and wait one minute
- Pause the game and inspect the file again (with NBTExplorer you have to reopen it, refreshing does not always work)
→ The village does not contain the door anymore
The reason
The following is based on decompiled version of Minecraft 1.9 using MCP 9.24 beta. All method and class names are the names used in the decompiled version.
A door is added to a village if a wooden door is in a cuboid based on the villager's position with the following size:
- x: -16 to 15
- y: -4 to 3
- z: -16 to 15
If a door is already part of a village its net.minecraft.village.VillageDoorInfo.lastActivityTimestamp gets updated. If the difference between the current time and the timestamp is greater than 1200 ticks (1 minute) the door is removed by the method net.minecraft.village.Village.removeDeadAndOutOfRangeDoors().
One approach to changing this could be saving a village if all the chunks that are part of the village are unloaded instead of removing doors. There might be other checks needed to make sure this is not exploited for iron farms.
Linked Issues
Created Issue:
Villages are persisted to NBT, yet still destroyed/recreated on chunk reload
Villages and all of their doors are written to the NBT. However, once a chunk containing village doors is unloaded those doors are removed from the village (and the village possibly destroyed if its the last door)
When the player enters the area again, a completely new village is recreated from scratch.
It seems the intent from writing villages to the NBT is to keep villages and their door associations correctly intact. However, this is not the case when travelling far away or to another dimension.
Suggestion: Don't remove a door from a village if the chunk containing the doors are unloaded.
Villages and all of their doors are written to the NBT. However, once a chunk containing village doors is unloaded those doors are removed from the village (and the village possibly destroyed if its the last door)
When the player enters the area again, a completely new village is recreated from scratch.
It seems the intent from writing villages to the NBT is to keep villages and their door associations correctly intact. However, this is not the case when travelling far away or to another dimension.
Suggestion: Don't remove a door from a village if the chunk containing the door
s areunloaded.Villages and all of their doors are written to the NBT. However, once a chunk containing village doors is unloaded those doors are removed from the village (and the village possibly destroyed if its the last door)
When the player enters the area again, a completely new village is recreated from scratch.
It seems the intent from writing villages to the NBT is to keep villages and their door associations correctly intact. However, this is not the case when travelling far away or to another dimension.
Suggestion: Don't remove a door from a village if the chunk containing the door is unloaded.
relates to
This ticket is incomplete without the requested information, no response has been received within a reasonable time and we are assuming the issue has been resolved. If you are still experiencing this issue, we can reopen it at your request.
Villages and all of their doors are written to the NBT. However, once a chunk containing village doors is unloaded those doors are removed from the village (and the village possibly destroyed if its the last door)
When the player enters the area again, a completely new village is recreated from scratch.
It seems the intent from writing villages to the NBT is to keep villages and their door associations correctly intact. However, this is not the case when travelling far away or to another dimension.
Suggestion: Don't remove a door from a village if the chunk containing the door is unloaded.
Code analysis by Marcono1234 can be found in this comment.
Villages and all of their doors are written to the NBT. However, once a chunk containing village doors is unloaded those doors are removed from the village (and the village possibly destroyed if its the last door)
When the player enters the area again, a completely new village is recreated from scratch.
It seems the intent from writing villages to the NBT is to keep villages and their door associations correctly intact. However, this is not the case when travelling far away or to another dimension.
Suggestion: Don't remove a door from a village if the chunk containing the door is unloaded.
Code analysis
byMarcono1234can be found in this comment.Villages and all of their doors are written to the NBT. However, once a chunk containing village doors is unloaded those doors are removed from the village (and the village possibly destroyed if its the last door)
When the player enters the area again, a completely new village is recreated from scratch.
It seems the intent from writing villages to the NBT is to keep villages and their door associations correctly intact. However, this is not the case when travelling far away or to another dimension.
Suggestion: Don't remove a door from a village if the chunk containing the door is unloaded.
Code analysis can be found in this comment.
Villages and all of their doors are written to the NBT. However, once a chunk containing village doors is unloaded those doors are removed from the village (and the village possibly destroyed if its the last door)
When the player enters the area again, a completely new village is recreated from scratch.
It seems the intent from writing villages to the NBT is to keep villages and their door associations correctly intact. However, this is not the case when travelling far away or to another dimension.
Suggestion: Don't remove a door from a village if the chunk containing the door is unloaded.
Code analysis can be found in this comment.
The bug
Villages and all of their doors are written to the NBT. However, once a chunk containing village doors is unloaded those doors are removed from the village (and the village possibly destroyed if its the last door)
When the player enters the area again, a completely new village is recreated from scratch.
It seems the intent from writing villages to the NBT is to keep villages and their door associations correctly intact. However, this is not the case when travelling far away or to another dimension.
Suggestion: Don't remove a door from a village if the chunk containing the door is unloaded.
How to reproduce
- Place a wooden door and two blocks behind it a solid block (for example sandstone)
- Summon a villager
- Pause the game and inspect the villages.dat file using for example the tool NBTExplorer
→ The village data contains the door data- Kill the villager and wait one minute
- Pause the game and inspect the file again (with NBTExplorer you have to reopen it, refreshing does not always work)
→ The village does not contain the door anymoreThe reason
Code analysis can be found in this comment.
The bug
Villages and all of their doors are written to the NBT. However, once a chunk containing village doors is unloaded those doors are removed from the village (and the village possibly destroyed if its the last door)
When the player enters the area again, a completely new village is recreated from scratch.
It seems the intent from writing villages to the NBT is to keep villages and their door associations correctly intact. However, this is not the case when travelling far away or to another dimension.
Suggestion: Don't remove a door from a village if the chunk containing the door is unloaded.
How to reproduce
- Place a wooden door and two blocks behind it a solid block (for example sandstone)
- Summon a villager
- Pause the game and inspect the villages.dat file using for example the tool NBTExplorer
→ The village data contains the door data- Kill the villager and wait one minute
- Pause the game and inspect the file again (with NBTExplorer you have to reopen it, refreshing does not always work)
→ The village does not contain the door anymoreThe reason
Code analysis can be found inthis comment.The bug
Villages and all of their doors are written to the NBT. However, once a chunk containing village doors is unloaded those doors are removed from the village (and the village possibly destroyed if its the last door)
When the player enters the area again, a completely new village is recreated from scratch.
It seems the intent from writing villages to the NBT is to keep villages and their door associations correctly intact. However, this is not the case when travelling far away or to another dimension.
Suggestion: Don't remove a door from a village if the chunk containing the door is unloaded.
How to reproduce
- Place a wooden door and two blocks behind it a solid block (for example sandstone)
- Summon a villager
- Pause the game and inspect the villages.dat file using for example the tool NBTExplorer
→ The village data contains the door data- Kill the villager and wait one minute
- Pause the game and inspect the file again (with NBTExplorer you have to reopen it, refreshing does not always work)
→ The village does not contain the door anymoreThe reason
The following is based on decompiled version of Minecraft 1.9 using MCP 9.24 beta. All method and class names are the names used in the decompiled version.
A door is added to a village if a wooden door is in a cuboid based on the villager's position with the following size:
- x: -16 to 15
- y: -4 to 3
- z: -16 to 15
If a door is already part of a village its net.minecraft.village.VillageDoorInfo.lastActivityTimestamp gets updated. If the difference between the current time and the timestamp is greater than 1200 ticks (1 minute) the door is removed by the method net.minecraft.village.Village.removeDeadAndOutOfRangeDoors().
One approach to changing this could be saving a village if all the chunks that are part of the village are unloaded instead of removing doors. There might be other checks needed to make sure this is not exploited for iron farms.
is duplicated by
is duplicated by
Kabo, have you actually tested this solution, and found it to be working? I'm inclined to believe there would be problems with using the existing code, considering MC-10841.
And considering just how much code has changed in the snapshot, I'm not sure it's safe to assume anything about reusing any currently existing code.
Without considering those two points, that does sound like a good solution – as you say, those structures are already created in memory when the chunk is loaded, so there shouldn't be much of a performance hit. It might actually be an improvement, depending on the cost of saving and loading those structures versus regenerating them. My comments were primarily intended to deter general arguments from ignorance, of the "I don't know anything about it so it must be easy", or "I don't understand why they're taking so long to do this obvious thing" variety. I hoped that explaining the sort of complications involved in this situation might encourage people to think a little more in the future, rather than yelling at people to hurry up and implement solutions that everyone may regret later.
That one is basically 98% probability. Considering the context, it will randomize the timing of when they decide to get in. That should reduce the chance of everybody rushing to the same door at once, but unfortunately, the restriction timers had their effect rather dysfunctional, so...
The best idea in your suggestion is the idea to calculate the villagers near the door (bypasses the currently failing counter). However, it also makes it either-or; either counter only, or distance only (for distant ones); the current math mixes both in order to do both: spreading villagers in houses and keeping travel distances short, in a smooth way. There is no need to adjust that mixing behavior, as long as the distance weight and villager counting work properly. (However, as a temporary adjustment, yours is just as valid as the changes proposed by me; it does improve the situation.)
Note that while your change may get better counting of villagers already inside, it does not count villagers still on the way to that door. That is one of the problems making the current algorithm near useless; villagers will go to just one to few doors, then keep fighting in front of for a while, until some time later possibly choose another one. Ideally, most of them should choose different houses before even starting to move anywhere for that night, and the few that end up choosing the same houses with another villager would consider the situation acceptable once they realize they have to share the house or to run possibly a long distance across the village; unless there is a vacant one nearby.
The thing is, if you want to try to "fix it good", you need to consider multiple bugs/design flaws/issues/improvements at once; while it might be possible to get a nice improvement by adjusting one part of it, the rest will come back haunting sooner or later. Hint: take a look at MC-10841 and think how it affects this issue, too.
Does MC-10841 describe your issue?
This would be so epic if it gets fixed
Can confirm (by observing some added console logging for each door/village addition/removal activity).
Additionally, during loading the world, the doors and the village under testing was removed twice, yet no signs of adding them back. Yet, the village is there (as if there was still a third entry that was kept). Something weird, though not dangerous in that.
Also, related to
MC-78.Any changes to this have lots to do with
MC-78, (and its related issues), as the village behavior depends strongly on the doors.Note that simply keeping the door knowledge of a village even when the containing chunks get unloaded (as suggested in the description) may have some undesired effects unless compensated in other related code. For example, if doors are not dropped, the village center and radius stay the same. Then villagers would, over the day, move randomly over the full the village area. Once they decide to move to a spot that is unloaded, they get "stuck" there. This may lead to "pushing" the villagers (and golems) to one side of the village, with its possible side-effects, like dropping (temporarily) the doors on the nearer side of the village. (And that was just one example that came to my mind).
EDIT:
Apparently, if one moves far enough to get the village removed by chunk unloading, it will still survive in the saved data (but only for some special case). When the world is loaded again (while being as far away), the doors and village gets either removed twice, but its data is still there (as it will not be "found" again while approaching it), or it and its doors get scanned through and village created, with its chunks still supposedly unloaded (i.e. it will have to load the needed far away chunks just to check for the doors).
This behavior only goes for one village, the one that was near when the world was created. There are two other villages I've visited, but they seem to behave more or less as expected.
Caveat: There are probably some code paths I've not just spotted which explain some of these mysteries, and I'm testing this the only way possible, i.e. using the MCP decompiled version, which may change some things.
This really should be fixed.
I have a possible brute force fix for the problem pointed out by Markku: When a village exists, don't unload parts of it, only all of it. AKA treat a village as one big chunk for loading/unloading purposes. May cause lag issues esp. with overly large villages, but this is just a brute fix.
this is actually a great idea. but i think it's a bit hard to do. Maybe, minecraft would see what is the chunk present on the village nearest to the player, and, if its in the loading-radius, all the village will be loaded, if it's not on the loading radius, all the village will be unloaded...
Was this fixed by the recent structure fix (or in parallel) (1.6.4)? I remember a Mojanster saying that the only difference between 1.6.2 and 1.6.4 was the structure bug and one concerning villages... I'd like someone to actively test to see if this bug was fixed or addressed in any way, but I don't have the skill set or computer to do so myself.
Is this still a concern in the current Minecraft version? If so, please update the affected versions in order to best aid Mojang ensuring bugs are still valid in the latest releases/pre-releases. If this has been done, we can reopen the issue.
Keep in mind that the "Resolved"-Status on this ticket just means "Answered", and that we are waiting for further information on whether this issue still exists or not. We will reopen it as soon as the requested information has been deliviered.
No response for over a year.
Confirmed for
Please link to this comment in the description
The following is based on decompiled version of Minecraft 1.9 using MCP 9.24 beta. All method and class names are the names used in the decompiled version.
A door is added to a village if a wooden door is in a cuboid based on the villager's position with the following size:
If a door is already part of a village its net.minecraft.village.VillageDoorInfo.lastActivityTimestamp gets updated. If the difference between the current time and the timestamp is greater than 1200 ticks (1 minute) the door is removed by the method net.minecraft.village.Village.removeDeadAndOutOfRangeDoors().
One approach to changing this could be saving a village if all the chunks that are part of the village are unloaded instead of removing doors. There might be other checks needed to make sure this is not exploited for iron farms.
How to reproduce
→ The village data contains the door data
→ The village does not contain the door anymore
changed reporter to Marcono1234
Marcono's steps to reproduce are separate from the bug in question. The bug in question is regarding village doors that are still near villagers getting removed from villages.dat when the chunks unload, whereas Marcono's steps to reproduce are about doors being removed from the village when villagers are no longer nearby (which is not a bug but a feature). The original bug has in fact been fixed in 1.9.
Steps to reproduce the original bug:
1) Ensure you are not in the spawn chunks (/tp @p 1000 ~ 0)
2) Place a villager in a fenced area and a valid village door (see http://minecraft.gamepedia.com/Tutorials/Village_mechanics)
3) Wait a minute for the door to register and then check villages.dat. You'll see an entry for that village with one door
4) Teleport yourself 1000 blocks away (/tp @p 0 ~ 0)
5) Wait a minute for the game to register that the village is no longer loaded.
6) Check villages.dat again. In 1.8 and older, the village you created will no longer be listed. In 1.9 (or at least 1.9.2), it correctly remains listed in villages.dat.
This bug is fixed. If Marcono wants to make a separate report for his "bug" he can but I'd say that the situation in his steps to reproduce works as intended. Villages are supposed to die if they are no longer populated by villagers.
Mark Dykstra I misunderstood the report then, sorry
However I can reproduce what you describe as well for 16w15b
The problem is probably then that the method net.minecraft.village.Village.removeDeadAndOutOfRangeDoors() is not testing if the door position is loaded. This cannot be fixed that easily because the whole concept does not work there anymore. As soon as the door is loaded it will be removed because the tick it was last updated was too long ago.
Does this still affect the current versions of Minecraft? (1.12.2, 1.13-pre3). If so, please update the ticket accordingly.
Is this still a issue in the latest version of the game(currently 1.13.1)?
If so, please add it to the affected versions, thanks!