mojira.dev
MC-10841

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

  1. Place a wooden door and two blocks behind it a solid block (for example sandstone)

  2. Summon a villager

  3. Pause the game and inspect the villages.dat file using for example the tool NBTExplorer
    → The village data contains the door data

  4. Kill the villager and wait one minute

  5. 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.

Comments 16

brettbalsewich

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.

Christopher Durham

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.

Pedro M. Zamboni

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...

6 more comments

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.

@unknown 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.

Uriel Salischiker

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!

Tango Tek

marcono1234

(Unassigned)

Community Consensus

Snapshot 13w10a, Minecraft 1.5, Minecraft 1.9, Minecraft 1.9.1 Pre-Release 1, Minecraft 1.9.1 Pre-Release 2, Minecraft 1.9.1 Pre-Release 3, Minecraft 1.9.1, Minecraft 1.9.2, Minecraft 16w15b

Retrieved