Reed Cartwright
- racartwright
- racartwright
- America/Phoenix
- Yes
- No
Between 1.14 and 1.16, Ghasts were changed internally from being a "Mob" to being a "Monster". By default, monsters only spawn when the light level is low. (This is hardcoded in the game and cannot be changed by json-based spawning rules).
Expected Behavior: Ghasts spawn at all light levels.
Actual Behavior: Ghasts only spawn if the light level is below 8.
Consequence: Portal-based ghast farms no longer work because portals emit light.
Demo world: Press a button to switch from a netherwart block floor to a shroomlight floor.
How to fix: Add a Ghast::isDarkEnoughToSpawn() function that always returns true. Example code below. This wasn't needed before when Ghasts were Mobs, but now is needed because they are Monsters.
virtual bool Ghast::isDarkEnoughToSpawn() const override {
return true;
{{}}}Between 1.14 and 1.16, Ghasts were changed internally from being a "Mob" to being a "Monster". By default, monsters only spawn when the light level is low. (This is hardcoded in the game and cannot be changed by json-based spawning rules).
Expected Behavior: Ghasts spawn at all light levels.
Actual Behavior: Ghasts only spawn if the light level is below 8.
Consequence: Portal-based ghast farms no longer work because portals emit light.
Demo world: Press a button to switch from a netherwart block floor to a shroomlight floor.
How to fix: Add a Ghast::isDarkEnoughToSpawn() function that always returns true. Example code below. This wasn't needed before when Ghasts were Mobs, but now is needed because they are Monsters.
virtual bool Ghast::isDarkEnoughToSpawn() const override {
return true;
{{ } }}
Between 1.14 and 1.16, Ghasts were changed internally from being a "Mob" to being a "Monster". By default, monsters only spawn when the light level is low. (This is hardcoded in the game and cannot be changed by json-based spawning rules).
Expected Behavior: Ghasts spawn at all light levels.
Actual Behavior: Ghasts only spawn if the light level is below 8.
Consequence: Portal-based ghast farms no longer work because portals emit light.
Demo world: Press a button to switch from a netherwart block floor to a shroomlight floor.
How to fix: Add a Ghast::isDarkEnoughToSpawn() function that always returns true. Example code below. This wasn't needed before when Ghasts were Mobs, but now is needed because they are Monsters.
virtual bool Ghast::isDarkEnoughToSpawn() const override {
return true;
{{ } }}Between 1.14 and 1.16, Ghasts were changed internally from being a "Mob" to being a "Monster". By default, monsters only spawn when the light level is low. (This is hardcoded in the game and cannot be changed by json-based spawning rules).
Expected Behavior: Ghasts spawn at all light levels.
Actual Behavior: Ghasts only spawn if the light level is below 8.
Consequence: Portal-based ghast farms no longer work because portals emit light.
Demo world: Press a button to switch from a netherwart block floor to a shroomlight floor.
How to fix: Add a Ghast::isDarkEnoughToSpawn() function that always returns true. Example code below. This wasn't needed before when Ghasts were Mobs, but now is needed because they are Monsters.
virtual bool Ghast::isDarkEnoughToSpawn() const override { return true; }
Reed Cartwright: Very interesting! The reason your results are different is apparently because you are only set up to test animal mobs, while I only tested monsters. That suggests that animal and monster spawns use two distinct versions of the surface/cave identification logic, something I never knew before and something that makes this whole issue even more intricate.
I'm going to modify my test rig to work for animals instead of monsters and see if I get the same results as you. Meanwhile, I'd appreciate it if you could translate "reverted back to 1.13 mechanics" into specific differences I should be testing for. There's no way I can trust my memory of how 1.13 spawning worked.
I did some testing on this and here are some takeaways.
1. When new villagers are added to the village, they may be placed in any random location in the hierarchy order. They could become the new leader, the tail, or somewhere in-between. This confirms Pekoneko117's findings. Although Pekoneko117 stated that the entire order is scrambled, more specifically the new villager can be inserted at the beginning, end, or somewhere in the middle of the order. But the previous order remains intact excepting the new insertion.
2. When every bed in the village breaks, the order completely scrambles. This kind of makes sense given that a village is only formed with the first bed.
3. As of 1.20.72, on Nintendo Switch, every time the user logs in and out, the villager hierarchy order reverses. If the villagers were initially in the order 1, 2, 3, 4, upon logging out and back in the order will be 4, 3, 2, 1. However, if you login and out and then in and out again the order is back to it's original. This appears to confirm Reed Cartwright's code observation that "On Android, the implementation of std::unordered_map tends to reverse the order of villagers between saving and loading data to NBT." This reversal problem does not exist on the Windows PC Bedrock version as of 1.20.72.
4. The villager hierarchy theory appears to be true as of 1.20.72 on Nintendo Switch and Windows PC. You can tell the hierarchy order by breaking all the workstations, and placing them down again. The order in which the villagers claim them is the order of their hierarchy. I used Universal Minecraft Tool to verify that the village origin/center point follows the villager hierarchy order and their POI.
The take away problem is that the village origin is unpredictable due to the hierarchy order changing too easily. The solution should include a somewhat easy or at least consistent way to determine the village center so Iron Farms can work reliably. Added villagers should come at the end of the hierarchy order, not somewhere in the middle or beginning.
Workaround:
One potential work around is to expand the village by placing 4 workstations on the outskirts. That is, keep the beds inside the village boundaries and add workstations in the expansion range of the village. Since beds are prioritized as origin points and workstations can expand the village boundaries but won't act as an origin point if there are beds for every villager you can expand the village so the center becomes the geometric center of the village boundaries, allowing you to control where iron golems spawn. This can be done in any natural village meeting the requirements for iron golem spawning.














This bug is due to changes to the spawning algorithm in 1.14 to stop surface spawns from being passed downwards by bottom slabs and non-solid blocks. When searching for a surface spawn, the algorithm now terminates early and returns false (instead of continuing downards). However the return value is not checked, causing the game to try to spawn mobs at the location the search terminated.
The Fix: Check the return value and don't try to spawn surface mob if the search function terminated early.
The Bug. When the highest block at a position is glass, leaves, or a similar spawn-proof block, the Spawner::tick algorithm cancels all surface, cave, and mob spawns on that tick.
The Cause. This bug is caused by the hotfix for
MCPE-54241, which was implemented in the wrong location. As a result if the search for a surface spawn position terminates early because it encountered glass, leaves, or a similar block, the game now detects this situation, but will skip the rest of the spawning algorithm.The Fix. Move the test of the return value of the first call to findNextSpawnBlockUnder after structure spawns are processed and right before the call that will spawn surface mobs. findNextSpawnBlockUnder also has to be updated so it doesn't set the the y-coordinate of the search to -1 whenever it encounters a non-spawnable block when search for a surface spawn spot. Make sure that if the test fails, that only the surface spawn is canceled. Cave spawns should occur even if the search for a suitable surface spot was unsuccessful.
An Example. I've uploaded a test world with 4 pillager outpost spawning areas on grass. When they have sky access, surface, cave, and structure spawns occur. When they are under glass or leaves, all spawns are canceled. Only the highest block matters. When stone and glass above the grass and outpost spawns, you get the expected behavior of cave and structure spawns.
Quick fix for mob farms. If you have mob-proofed the top of your far with bottom slabs, use carpet instead.
In the overworld, the search starts at y=256, so carpets at y=255 are okay. William Allard, try peaceful cycling your farm to see if that improves rates.
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.
I cannot reproduce the above behavior in my tests (see attached world and screencap). When slabs pass the surface spawns down, the next available spawning location is a surface spawn, and those after that are not. I believe that the spawning algorithm has reverted back to 1.13 mechanics. Patrols and other surface only mobs are likely to spawn inside bases and in caves again.
Spawning Test 0.mcworld
Note: I've looked at a disassembly of core spawning functions and I'm not finding any differences between 1.13 and 1.14.20.
Monsters are harder to test since they spawn on both the surface and cave. However, monsters and passive mobs are by the same algorithm. If looking at hostile mobs that can spawn on both the surface and cave, its best to check the NBT to see what they are marked as.
Theses are the changes to spawning in 1.14.
1.14.0: surface spawn attempts are no longer passed downwards by non-spawn blocks (glass, leaves, bottom slabs, etc.) Carpet is the one exception. A side effect of this change is that non-spawn blocks (except bottom slabs) now spawn mobs.
1.14.1: non-spawn blocks (except carpet) that are the block with sky access no longer spawn mobs. A side effect of this change is that they also block all spawning for that tick in that chunk.
1.14.20: the changes to spawning in 1.14.0 and 1.14.1 are reversed and the mechanics are back to 1.13. Slabs etc pass surface spawns attempts down.
The list of blocks in 1.14 can be found here: https://docs.google.com/spreadsheets/d/1OXB5wKnD2GNZEhDC8dPo_zsM7djPblf8wZI77oTa1Tk/edit?usp=sharing.
Blocks with SpawnBlock=TRUE are those that mob spawns can be attempted on. Block with SpawnBlock=FALSE will pass surface spawns down if MaterialBlocksMotion = TRUE. (This is from memory and may be slightly off.)
I've looked the assembly code of several functions in 1.14.20 and I can confirm that the changes in 1.14.0 and 1.14.1 have been reverted to 1.13 status. I'm going to need to see a really convincing test world before I believe that mob spawning is different between 1.13 and 1.14.20.
Based on my knowledge of the spawning algorithm in 1.12 onwards, I believe that the following can be implemented without too many changes.
When a structure spawn happens in an outpost, 50% of the time it will try to spawn normal pillagers, and 50% of the time it will try to spawn a captain. However, the captain spawn will fail if there are any other pillagers in a 9x9 chunk area centered on the spawning location. This includes patrols and previous outpost spawns. If you are not having captains spawn, then there is a pillager running around ether above or below ground near the outpost.
The solution is to turn the world to peaceful and do a big circle around your outpost to clear out the mob caps.
AFKing in the wrong location can cause pending ticks to build up. Using complex redstone devices can cause pending ticks to build up.
The issue is that only 100 pending ticks are processed during a game tick in a chunk, and it isn't hard to accidentally make something that generates more pending ticks than that per game tick. A full chunk farm with 256 plants will generate 256 pending ticks if a player automates it with redstone so they all break in the same GT. If someone builds a farm across chunk borders and then AFKs so that only part of the farm is loaded, they can generate pending ticks in the part of the farm that is not loaded.
Thus pending ticks build up faster than they are processed. If it goes on for too long, the pending tick record gets so big that it lags the server whenever it is read from or written to the database. Even if you take care of the issue causing the pending ticks, the problem of lag will prevent the game for processing all the ticks.
The fix is trivial to implement. Limit the pending tick queue in a chunk to something like 4096 ticks. If there are more ticks in the queue than that, the game should silently drop a pending tick request.
There are lots of villager-POI linking issues in Bedrock at the moment, and I'm not sure that MCPE-47212 is related to this one. I can run it by Yodalf and Hey Old Guy to see what they think. They know the village system better than I do.
Here are three picture showing the despawn locations and ticking areas for sim distances of 4, 6, and 8. The player is standing at 0,0. Clearly there is an inconsistency with the scaling.
While we are on the subject of despawning, I want to suggest a slight change in how despawning happens.
1) The beta documentation lists "despawn_from_simulation_edge" as a data-driven configuration option for mob despawning. I assume that this is supposed to despawn any mob that walks outside of simulation range or is in a chunk when it is taken out of simulation range. This would be a good thing. If this can be fully implemented and enabled for mobs, then I suggest that the despawning range be scaled to 16*simulation_distance, with 128 as the max. This would provide parity with Java Edition at simulation distance 8.
2) Scale the spawning distance to 16*simulation_distance-10, with 118 as the max. This would allow any mob to move 10 blocks away from a player before they instantly despawn, regardless of simulation distance.
To be clear. Only on sim-distance 4 does the despawn radius not extend into unloaded chunks. On sim-distances 6 and 8, it extends into unloaded chunks. The other reason why I think it is a typo (44 instead of 54) is because the spawn radius is still 54 in the beta, so lots of things are spawning and instantly despawning at sim-distance 4, which would be inefficient game design.
Here is another view of the issue. Currently in the beta, on simulation distance 4, only the blocks between 24 and 44 distance of a player can spawn mobs (shaded region). This clearly too small, and the majority of a ticking area is lifeless.
The spawning area is much larger in 1.14, and the ticking area has more mobs in it.
This happened to me when I was running Minecraft inside a Windows 10 virtual machine. The virtual machine had its scaling set to 200% for recording and the mouse was extremely sensitive and jerky.
Can someone with access to the 1.16 beta code confirm that this is the difference between distance 4 and distance 6? I'm trying to understand how despawn_from_simulation edge works and interacts with realms or doesn't. Below is my best guess from testing and this thread.
Sim Distance 4 (realms)?
Sim Distance 6 (not realms)?
Note that (at least in 1.14) the game will attempt to spawn mobs in all simulated chunks whose centers that are withing 96 blocks of the player, horizontally. However, the spawning will fail if the mobs are beyond r=54 of the player.
I have a possible solution to this problem that works with the existing (1.14) Bedrock internal architecture. It is a way to implement lazy chunks at sim4 without introducing extra complexity or lag on realms.
It is my understanding that instant despawning at r44 was introduced on sim4 because despawn_at_simulation_edge takes up too much space with a sim4 simulation distance. My proposed solution on sim4 is to add an additional ring of chunks to the simulation ticking area. The ticking area is stored as a vector of offsets relative to the chunk a player is in. This would mean that sim4 would hold the same offsets as sim5. However, the difference between sim4 and sim5 is that on sim4, the outer ring of chunks only process the despawn_at_simulation_edge algorithm.
There are lots of different ways to implement this outer ring of lazy chunks, but the easiest way would be to check if the center of a chunk is more than 66 blocks away from the center of the chunk that the nearest player is in. If a chunk is more than 66 blocks away, the LevelChunk::tick() algorithm should skip most of its work and only process the despawn_at_simulation_edge algorithm.
The game already checks if a chunk is more than 96 blocks away from the nearest player in order to decide whether to run the spawning algorithm or not. The change would slightly tweak the distance calculation (using the center of the player's chunk instead of the player's position) and what the games does when the check fails (run the despawn algorithm). I don't know how despawn_at_simulation_edge is implemented in 1.16 beta, and there might be an easier way to implement this.
With despawn_at_simulation_edge implemented on sim4, the instant despawn at r44 can be removed, resolving this bug report. Also removing the hard-coded r44 will make behavior packs that change despawning mechanics work as expected on realms (data-driven game design), and also make the despawning mechanics match up with Java, within reason (parity).
This is a figure describing my proposal:
Steve is at 0,0. Blue are the sim4 simulated chunks. Green are the sim4 instant despawning chunk. The white donut is the spawning r24-r54 spawning range around the player, and the black circle is the r66 circle centered on the center of the center chunk (x=7,z=7).
I've attached a test world that contains an approximation of an early-game slime farm. Steve has built his work area at y=64 in a slime chunk and has built a slime spawning space at y=16. His goal is to passively collect slimeballs while he is farming, smelting, brewing, etc. (Imagine that Steve has a killing and collection area at y=16 as well.)
In 1.14.60, the farm works as expected. Slimes spawn at y=16 while Steve is at y=64.
In 1.16.0.61, the slime farm does not work as expected. All slimes instantly despawn at y=16, and the farm stops working. All the time that Steve has invested in building his slime farm has gone to waste. In fact, Steve probably will not know why his slime farm has stopped working. This has the same effect as the slime chunk issue that had to be reverted several versions ago.
SlimeChunkTest.mcworld
We can also infer that if Steve made a max slime farm, using all possible spawning spaces between y=0 and y=40, that his rates will be reduced in 1.16. I leave that exercise up to the reader.
I will note that if distance to nearest player is calculated not from the player's position, but to the center of the chunk the player is in (keeping y-level the same) then the instant despawn radius could be 56 on sim4 worlds. If spawning spheres were calculated similarly, then you would have a two-block distance between spawning and despawning.
It wouldn't promote parity like lazy chunks would, but would allow mob farms to use all of their spawning spaces again.
The game already has implemented a new type of chunk: simulation-edge chunks. They have been disabled in sim4 because they take up too much space (relatively). As I have proposed, they can be implemented efficiently on sim4 by adding an additional ring of chunks and disabling everything but simulation-edge despawning in that ring of chunks.
Given that Realms and sim4 simulation distance is one of Minecraft's primary sources of continued revenue, I don't think that shipping hard-coded r44 instant despawning in 1.16 is a good idea. Additionally it goes against parity and data-driven mechanics.
Thanks to GoldenHelmet, I was able to test vertical despawning on 1.16.0.66. The results are consistent with my expectations:
sim4: instant despawing at r44.
sim6: instant despawning at r128
sim8: instant despawning at r128.
For java parity and consistency across simulation distances, the hardcoded r44 instant despawning needs to be removed from sim4/realms, and despawn at simulation edge implemented instead. Here is what it would look like:
The squares are the chunks in a ticking area on sim4. In green chunks, mobs instantly despawn. The white disc is the current spawning sphere, and the black circle is the r44 instant despawning sphere. Removing the r44 instant despawning and using green chunk instant despawning would restore the majority of the spawning volume while still preventing mobs from moving into unloaded chunks. This would also restore vertical drop mob farms and passive slime farms because r128 would be the vertical mob spawning distance.
This would also be a change to promote parity and data-driven game design.
Black squares track the movement of mobs over a several hours test.
I can confirm that thus bug is happening in 1.16 beta. I did some code-digging in 1.14.30 and I can see of two places where the code for finding a wandering position is biased in the NW direction. The location of the new wandering position is ultimately calculated by `RandomPos::generateRandomPos`. This is called by `RandomStrollGoal::_setWantedPosition` via a few intermediate functions. This function has a NW bias in two locations at least, and I don't think they are corrected for.
1) The game calls `RandomPos::_choosePositionOffset` to generate offsets from the mob's current position. In the X and Z directions, the game generates a random integer between 0 and 2D-1 (where D is a parameter), and the subtracts D from the integer. Therefore, in the X and Z directions the random offsets are uniformly distributed in the integers from -a to a-1. Clearly the average offset in the X and Z directions is -0.5.
2) The game calls `floor` on a mob's location before including the offset. If mobs are evenly distributed along a block, then this would also add a -0.5 offset in the X and Z directions.
Taken together, these biases over the long run would add -1 in the X and Z directions per run of `RandomStrollGoal::_setWantedPosition`, and produce the NW bias seen in the image.
The Fix
1) When drawing a random integer for the offset, use 2D+1 as the parameter.
2) Use a `round` instead of `floor` or add 0.5 to the current position before calling floor.
Alternative Fix
1) Keep the existing algorithm, but add 1 to calculated wander position in the X and Z direction to adjust for the biases.
R Code Demonstrating the bug and the fixes
# simulation size
n <- 1000000
# draw the location of a mob uniformly from -10 to 10
x0 <- runif(n,min=-10,max=10)
# Sample a wandering location the Bedrock way
d1 <- sample(seq.int(-10,9),n,replace=TRUE)
x1 <- floor(x0)+d1
print(mean(x1-x0)) # This will print something that is close to -1.
# Fixed algorithm
d2 <- sample(seq.int(-10,10),n,replace=TRUE)
x2 <- floor(x0+0.5)+d2
print(mean(x2-x0)) # This will print something that is close to 0
# Alternative fix
x3 <- x1+1
print(mean(x3-x0)) # This will print something that is close to 0
If I am reading vanilla_1.15/spawn_rules/zombie.json correctly, this bug appears to be back in 1.16.
It looks like when someone added `minecraft:zombie_villager_v2` to the zombie spawn rules, they accidentally reverted the fix for this bug.
This still affects 1.16.0.2 (release).
This bug happens because behavior_packs/vanilla_1.15/spawn_rules/zombie.json removes ""minecraft:spawns_underground": {}," rule.
I attached a diff showing the changes. zombie_diff.txt
I suspect that when the zombie villager was updated to v2, an outdated version of zombie.json was used.
The Mob -> Monster change that I'm referring to happened at the C++ level. In 1.14, the Ghast class was derived from the Mob class. In 1.16, it is derived from the Monster class.
I agree that this bug is likely related to fixing Ghasts not despawning on Peaceful.
I've now gotten a chance to reverse engineer how the new despawning system works in 1.16, and have a proposal to bring proper despawn_from_simulation_edge to sim4.
Mobs are able to be simulation-edge despawned if they have been ticked and are in a chunk that neighbors an unticked chunk. At simulation distance of 4, the result looks like this:
The green chunks are the simulation edge chunks, and they clearly take up a lot of space on sim4. This is why r44 is a viable alternative on sim4.
However, if on sim4, simulation-edge is defined as chunks with two neighbors that are unticked, you get something that looks like this:
This produces a despawning area that on the diagonal is the same as r44, but opens up more area for spawning. This would also allow r128 despawning to function vertically, promoting parity and making sim4 work like sim6.
How to Implement
Update `BlockSource::hasUntickedNeighborChunk` to take a new parameter that represents how many unticked chunks are allowed. Passing `2` would indicate that game is looking for two or more chunks. This would be the default on sim4. On Sim6 and above, the game would pass a `1`. The modification is trivial to implement and can be made to quit as soon as the the 1st or 2nd unticked chunk is found.
The nether has a denser mob cap than the overworld, so you can expect twice as many mobs in the same area as overworld caves. With the reduction in the spawning sphere, you have an unexpected density of mobs around the player. Magma cubes are notable because they split into smaller magma cubes, so by the time you have finished one cubes, many more have spawned.
I will link to a twitter thread where I discussed the new mechanics and how to easily improve them on Realms. https://twitter.com/fragmites/status/1276321957219188736
Spider spawning is not affected by this bug because the code that allows magacubes to spawn in small areas is specific to magma cubes.
Buttons only stop spider spawning if the spider's hitbox overlaps the button's collision box. In Prowl's far design, the buttons are not positioned in a way to stop all spider spawns.
Back to this bug report. Magma Cubes are one of the monsters that use their own function to check for block collisions when they spawn. They do not use Monster::checkSpawnRules() that Skeletons, Creepers, Spiders, etc. use. In fact, LavaSlime::checkSpawnRules() only checks for collisions with liquid blocks or if lava slime is obstructed by existing entities.
I don't know if this is WAI, but large Magma Cubes spawning in 2x2 tunnels is really annoying for players building through basalt deltas.
One solution to this bug is for LavaSlime::checkSpawnRules() to also call Monster::checkSpawnRules() so the standard block checks are done in addition to the Magma Cube specific ones.
Please note that if Monster::checkSpawnRules() is used, then LavaSlime::isDarkEnoughToSpawn() will also need to be defined to always return TRUE, otherwise magma cubes will not spawn in high light levels.
I just tested and 1.16.20 is affected by this bug.
The constant MobSpawnRules::MAX_DEFAULT_SPAWN_DISTANCE and MobSpawnRules::MAX_SPAWN_DISTANCE are now 44, which is why it affects all sim distances not just sim 4.
Because MAX_SPAWN_DISTANCE is set, behavior packs cannot increase the spawn sphere above 44.
Below is my suggestion on how to fix this issue:
This would be equivalent to the implemention of Despawn mechanics. Where sim4 has hard-coded limitations, but the rest of the simulation distances have data-driven behaviors.
Someone edited the wiki in July 2020 to say the Animal Surface cap was 8 instead of 4.
I've gone back to 1.11 and the cap is 4 there, so nothing appears to have changed in the game.
This is probably WAI, but is also not what users are expecting. Population control caps don't seem to make much sense. They are also hardcoded, and some are no longer used.
The thing that seems to be the most unexplained: the game allows for 36 Water_Animals, but only 4 Animals?
Overworld Population Caps (Surface/Cave)
Animal: 4/0
Monster: 8/8
Water_Animal: 36/0
Villager: 0/0
Ambient: 0/2
Cat: 4/0
Pillager 8/8
The End Population Caps (Surface/Cave)
Animal: 4/0
Monster: 10/8
Water_Animal: 36/0
Villager: 0/0
Ambient: 0/2
Cat: 4/0
Pillager 8/8
The Nether Population Caps (Surface/Cave)
Animal: 0/4
Monster: 0/16
Water_Animal: 0/0
Villager: 0/0
Ambient: 0/0
Cat: 0/0
Pillager 0/0
Please don't mark it "Resolved" so quickly. Jay requested an original bug report on the breaking of Mob Farms: https://twitter.com/Mega_Spud/status/1303087436004823046
Thanks, Urielsalis.
I really feel like this is similar to the recent changes to collision boxes for pressure plates that broke certain farms and were reverted.
MCPE-80276I think it is important to discuss if any of the improvements to pathfinding have unintended consequences that should be addressed or not. This is a mechanic that has been in the game for a very, very long time and well established mob farm designs are impacted by it. It is smart for the developers to consider the impact before finalizing the change. If needed, we can post lots of tutorials and let's plays from YouTube that use this mechanic.
Also, I want to make clear that I am specifically talking about buttons here. The other blocks that were updated in connection with buttons are not used in pathfinding-based farms as far as I know.
This is a long standing game mechanic and changing it, while making the game act more reasonable, has the potential to break two types of farms. (1) Farms that use instapush mechanics and (2) really advanced farms that take advantage of mobs spawning in the middle of four blocks.
For mob farms, this mechanic can be worked around by constructing the walls of the farm out of ice or glass which don't prevent most mobs from spawning if they collide with it.
The cause of this mechanic is that mobs spawn according to block positions. Block positions are integers, and mob positions are floats. When the block position is converted to a mob position, the integer coordinates are converted to floats. This means that the bottom of the feet of the mob are centered at the lower-north-west vertex of the block the mob's feet spawn in. Now MobSpawner blocks add 0.5 to the their x, y, and z coordinates to center their spawning in the center of the block, but the Environmental Spawning algorithm doesn't include the adjustment.
If a decision is made to change mob spawning, I recommend that the spawning position be adjusted by a number slightly under 0.5, so as to not impact instapush mechanics. The offset of 0.499938965 would work reasonably well. It's close enough to 0.5 that it will probably not be noticible, but would allow mobs to be pushed in the same directions they currently are when spawning. This would preserve instapush mechanics for farms built within 16k blocks of 0,0.
You can resolve this ticket and the related button pathfinding issues by let mobs only pathfind across buttons placed on the sides of blocks. This will not affect how mobs interact with buttons place on the top or bottom of blocks.
When ClayBlock, GravelBlock, SandBlock, and DirtBlock are fertilized, they call SeaGrass::trySpawnSeaGrass. This function randomly creates SeaGrass and Coral around the fertilized block. CoralFan (and CoralFanHang) are not created by this function. To fix this bug, CoralFan should be added as a possible block that SeaGrass::trySpawnSeaGrass creates. It's probably not worth it to add CoralFanHang.
Portal ticking gold farms are not due to a bug. It's a mechanic available to players due to a core mechanic in the game: whenever a PortalBlock is ticked it will randomly spawn zombie pigmen. This is consistent with how other blocks use their "tick" function to do things in the game, like crops growing. Portal ticking gold farms work because, whenever a portal is lit, all the PortalBlocks will be ticked as they are placed in the game. This is important for testing the viability of a portal and registering the portal with the game. Ticking a block when placed is also a core mechanic and consistent to how other blocks function.
This is clearly an intended game mechanic and not a programming error or oversight. It is deep enough in the mechanics of the game, that I wonder if it was ported over from Java way back when.
Now the game designers may decide in the future to change the mechanic to impact portal ticking gold farms, but this issue should be marked as WAI until they change their minds.
This issue is caused by logic in Skeleton::die() that probably predates the introduction of Strays in the game. When a skeleton killed by a charged creeper, the game checks what type of skeleton it was, and if the skeleton is normal it drops a normal skull, otherwise it drops a wither skull. Potential code fixes for this bug are straight forward (using C++ style pseudocode):
Make Strays Drop Normal Skulls
SkullBlockActor::SkullType skull_type = 0; if(getSkeletonType() == 1) { skull_type = 1; } // ... create and drop skull itemMake Strays Drop No Skulls (Java Parity)
if(getSkeletonType() < 2) { SkullBlockActor::SkullType skull_type = 0; if(getSkeletonType() == 1) { skull_type = 1; } // ... create and drop skull item }Here's my interpretation. Before 1.16.100.57, the 96 block limit was WAI. It is unclear with r128 spawn sphere if it is still is.
Here are the details. In the function LevelChunk::tick, the spawning algorithm, Spawner::tick(), will only run if the horizontal squared distance of the nearest player to the chunk is less than 96*96. This squared distance is calculated from the player's position to the "center" of the chunk, but not the true center. While there is a function, ChunkPos::distanceToSqr , for calculating the distance between a player and a chunk, LevelChunk::tick has its own way for calculating the distance. Whereas ChunkPos::distanceToSqr adds 8 to the NW corner of a chuck when calculating the distance, LevelChunk::tick adds 7.
I suspect that the 96-block limit predates the introduction of the spawn sphere and goes back to when Bedrock had cylindrical spawning. Before 1.16.100.57, the 96-block limit had no noticeable limit on the spawn sphere as the maximum spawn limit was 54 blocks. However, now that the spawn sphere has been raised to 128 blocks it is possible to notice it.
Suggested Fix: (1) Use ChunkPos::distanceToSqr in LevelChunk::tick for consistency with the rest of the codebase, and (2) raise the distance check so every chunks within the 128 spawn sphere has a chance to spawn mobs. This limit is around 148 blocks or so.
Possible Impact: Players that play on high simulation distances will get to use the entire 128 spawn sphere. Players that play on low simulation distances with out ticking areas will not see any impact. Players that do play on low simulation distances with ticking areas will be able to spawn mobs in a larger part of their ticking areas than before. However, because ticking areas require cheats to be enabled, it probably will not be seen as a negative by players that have enabled cheats.
Code Analysis Wandering Traders do not spawn according to the standard environmental spawning algorithm (Spawner::tick). The other mob event added in V&P — the pillager patrol — is data-driven and does use the environmental spawning algorithm to spawn. The code for managing the spawning and despawning of the wandering trader is in the WanderingTraderScheduler class and is called by VillageManager::tick. WanderingTraderScheduler's algorithm for finding a spawn spot for a wandering trader is different than the environmental spawning algorithm's resulting in the Wandering Trader appearing in places where they are not wanted, including underground and on roofs.
Solution Follow the example of the Pillager Patrol and make the WanderTrader spawn according to the environmental spawning algorithm. This will make them follow the spawn logic expected by players. As the environmental spawning algorithm has been receiving lots of bug fixes and new features in 1.14 and 1.16, migrating wander trader spawning to an environmental spawn would allow wandering traders to benefit from the changes.
Impact There is likely no negative impact for players by replacing WanderingTraderScheduler with a Spawner::tick implementation.
Code Analysis With the help of 0ld Guy, PekoNeko, and Yodalf, I have determined why the center of the village can shift around on login and logout. While running, Bedrock stores the POI information of a village in a data structure called a std::unordered_map. This data structure maps a VillagerID to a vector containing POI information for the bed, bell, and workstation that a villager is connected to (or if they aren't connected to any). This data structure is used to quickly look up the POI that a villager is connected to based on the villager's id. While the unordered_map is unordered, it is possible to iterate through a list of its contents; however, the order of this list varies between implementations of the std library and adding and removing villagers to a village can scramble it, as can saving and loading the information to an NBT list. As a result villager order can shuffle between restarts.
Normally the shuffling of villager order is not a problem for an unordered_map; however, when recalculating the bounding box of a village, the game does it in order of villagers in a way that makes the order matter. The game iterates through the data in the unordered_map, and the first POI found is used to construct the initial bounding box of the village. This POI can be considered the origin of the village. Villagers that occur earlier in the iteration are preferred over those that come later, and for a villager, beds have preference, then bells, then workstations when determining the origin POI. After the initial bounding box is set it is expanded as needed to accommodate all the POI in the village. The function that does the recalculation is Village::_calcPOIDist.
The center of the village is the center of the bounding box and is important for constructing iron and raid farms. As long as the bounding box is not recalculated the center of the village will not shift and farms will not break. Adding or removing POI (and some updates to the game) will cause the bounding box to be recalculated. If the order of villagers in the unorderder_map has changed, the identification of the origin POI might also change, changing the village's bounding box and its center.
In Game Workaround When constructing a village, don't add or remove POI after you are finished. (This includes villagers linking and delinking from their POI.) That way the village's center isn't recalculated outside of an update.
Proposed Solution 1 On Android, the implementation of std::unordered_map tends to reverse the order of villagers between saving and loading data to NBT. The solution to maintaining a consistent order is when loading data from NBT, add it to the std::unordered_map started from the end. Here is an example demonstrating is stability: https://gcc.godbolt.org/z/47KdcP. This does not appear to work on Visual Studio's implementation of std::unordered_map and a solution for Win10 will need to be investigated.
Impact None. This fix will add no complexity or performance costs to the game.
Proposed Solution 2 Replace std::unordered_map with std::map. Map orders its data by keys and is stable between saving and loading.
Impact Code complexity is not affected; however, std::map is potentially slower than unordered_map with a large number of villagers in a village. However, since the number of villagers per village tends to be low, std::map might be faster or about even with std::unordered_map.
Proposed Solution 3 Store POI information in a std::vector, and use std::unordered_map to map a villager to an index in this std::vector. The order of the vector would be kept constant between saving and reloading.
Impact This solution adds code complexity and would be potentially faster than std::map approach. It can also be implemented without changing how village information is saved on disk.
Proposed Solution 4 Calculate village boundaries in a way that doesn't depend on the order of villagers in a std::unordered_map. One possibility would be to construct a bounding box of from all the POI first, and then expand it as needed. Consequently, the origin of the village would be deterministically determined by the highest and lowest coordinate of POIs on each axis. The bounding box of the village would be set by the largest bounding box containing both the POI bounding box and a 64x24x64 bounding box centered at the origin of the village / center of the POI bounding box.
Impact This requires no changes with how POI information is stored in memory. This would be consistent with how players expect villages to work and would make easier for players to calculate their village centers. However, this change would impact trading-hall+iron-farm designs as the workstations in the trading hall would influence the center of the village. A solution to that would be to only use beds instead of every poi to calculate the village origin and initial bounding box, and then expand the bounding box as needed to accommodate every other POI.
Code Analysis
Plant growth speed is based on the area around the plant/stem. The maximum growth speed is 10.0. In Java Edition, the probability of growth is
where points is the growth speed. For maximal growth farmland, this works out to be 0.33 chance of growing per random tick to the plant, or 1/4096 chance per game tick. However, because random tick speed defaults to 3 on java and 1 on Bedrock, a 0.33 chance of growing per random tick to the plant is a 1/12288 chance of growth per game tick on Bedrock.
To compensate for this difference, crops on Bedrock like wheat, but not StemBlocks, calculate the probability of growth as
At maximal growth rate, the probability of growth is 1 per random tick to the plant, and 1/4096 chance per game tick, matching Java. However, you will notice that based on this model the growth probability of crops maxes out on bedrock when the growth rate is 5 on bedrock but 9 on Java.
Suggested Change (easy)
Update StemBlock growth rate on Bedrock to match the Crop growth rate.
Suggested Change (better)
The entire growth rate system can be overhauled to improve performance and code quality.
I've advocated for the increase of sim distance on Realms for several months now, so I'm glad for the change. Because of spawning mechanics and view distances, I would rather be running on sim 10 than sim 4. However, making such a big jump on existing realms is going to cause lag. Players have not designed their realm worlds for sim 10, and if they placed a lot of their farms, storage systems, and redstone too close together, then all of those farms will now be loaded at once. This is the source of lag. There is also increased memory and disk usage from increasing the sim distance. This would also contribute to lag.
In my experience with playing on technical servers with BDS, sim 8 and sim 10 struggled when multiple players were on. Sim 6 seemed like the sweet spot.
I can confirm that lag on the realm increased this week with the change over.
The number of players online does affect it (more players means more chunks getting simulated).
I'm joining realms from a PC, and I haven't tested different devices.
Code Analysis: Sim distances are implemented in a rather simple way in the game. Based on sim distance, the game creates a list of offsets representing all the ticked chunks relative to an active player. Every game tick, the game loops through all players and loops through all offsets for every player, and combines the player's position and the offsets to determine every chunk that needs to be simulated. It also includes the chunks in every ticking area as well.
It would not be difficult to allow realms/bds to dynamically scale sim distance based on load or number of players. By loading multiple lists of offsets into memory, the game can dynamically switch between sim distances. Alternatively, multiple lists can be used to prioritize certain chunks over others, such as the sim4 chunks being simulated before sim6, sim8, etc. This way the game can skip simulating outer chunks if a game tick is taking longer than 50 milliseconds.
Code Analysis
Every Dimension has a VillageManager object which controls the creation and running of Villages. The End and Nether's VillagerManger works just like OverWorlds, which is why players can create Villages in the End and Nether.
However, when a village is saved (via VillageManager::saveAllVillages), the game does not record which dimension the village was in, and thus on restart the game has no way to know which VillagerManager object should load the village. Instead Dimension::init runs VillageManager::loadAllVillages only if the dimension is the Overworld. What this means is that loadAllVillages assigns every village in the world database to the Overworld.
The result is that on restart villages in the End and Nether no longer exist, but the game thinks there is a village in the same coordinates in the Overworld. If the player goes back to the village in the End and Nether, it will be recreated from scratch causing POIs to scramble and that sort of thing. Ever time the game is restarted and a new village is created, this causes additional village records to be added to the game save. The only way to clear these records is to visit the location of the village in the Overworld. Then the game will detect that the village no longer exists and then delete it.
Example
Create a Village at 100,100,100 in the End. Restart the game several times while staying in the End Village. Load up and inspect the save game with rbedrock (https://github.com/reedacartwright/rbedrock). You will see that there are multiple villages recorded as being located at 100,100,100. Restart the game again, and you will see an additional village recorded. Next visit 100,100,100 in the Overworld. Close the game and use rbedrock again. You will see that the extra villages will have disappeared.
Proposed Fix
(1) A VillageManager should know what dimension it is operating in and pass that on to any Village it creates.
(2) Village::_saveVillageData creates the "INFO" records for a village and it should save the dimension the Village is in.
(3) VillageManager::loadAllVillages should be run for every dimension and only load a Village if its INFO says it is from the correct dimension.
Alternatively, recall that village records are saved with a key like "VILLAGE_${VillageID}_${DataType}". E.g. "VILLAGE_ee966fd9-9b3c-421f-9312-d6f73b2ec77c_INFO". Instead of saving the dimension of the village as part of the village's INFO record, it can be saved as part of the key, e.g. "VILLAGE_${dimension}_${VillageID}_${DataType}", e.g. "VILLAGE_0_ee966fd9-9b3c-421f-9312-d6f73b2ec77c_INFO". That way a VillageManager object can load data that begins with with "VILLAGE_0_" or "VILLAGE_1_" or "VILLLAGE_2_" as appropriate. This also makes it easy to upgrade existing villages as the Overworld VillageManager can also read in and upgrade legacy Village records.
MCPE-121068,MCPE-117105, andMCPE-104872are all affecting me. I'm running Android x86_64 version through the Linux loader. I suspect that its a problem specific with the Android Intel devices. I've even encountered a crash when connecting to a world with the City Life texture pack enabled. Whenever I'm typing a command and the game shows up a list of blocks in the "complete" menu, the game crashes with a "Mesh" error. I suspect its due to one of the City Life's textures.The bug affects Minecraft compiled for Android running on Intel processors.
Right now, striders have a surface density cap of 3. This is dead code. Striders, like all nether mobs, are not surface mobs, and never spawn on surface spawning spots. Not many people understand the distinction between cave and surface spawns, and that the nether only has cave spawns. This dead code causes confusion as to what the spawning cap is for Striders. It looks like it is 3, but it is actually 4, which is the cave cap for underground animals in the nether.
I do not know what intended behavior is. Are striders supposed to have a cap of 3 or 4? Depending on the answer, the code should either be removed or changed to an underground density cap of 3.
If the animal cap was raised to 8, and both striders and hoglins have a density cap of 4, they would not block one another.
The Linux Loader has been working on creating a patch for this issue. I'm posting the link here because it might help someone at Mojang track down the issue on their end.
https://github.com/minecraft-linux/mcpelauncher-client/blob/992db171afcb8f21e34de8b3d3b7948fc66144ab/src/fake_egl.cpp#L158
This is a code analysis based on 1.16.100 (i.e. before the pending/random ticks system was updated) and a suggestion on how to reimplement portal ticking gold farms in 1.17.
1.16.100: Portal Ticking gold farms worked because one function PortalBlock::tick() was responsible for both testing if a portal was valid on a block update and spawning zombie pigment on a random tick. Basically before 1.17, a block could be ticked randomly and non-randomly and the same set of random and non-random things would happen when a block was ticked. The way active-portal gold farms work is to light and break portals repeatedly to force PortalBlock::tick() to be called, spawning zombie pigmen. It's honestly a really cool mechanic and OP the same way Java's nether roof pigmen farms are OP. On Hard difficulty, the probability that a portal-block spawns a zombie pigman when ticked is 3/2000. For a maximum sized portal, this means that there is an average of 0.66 zombie pigmen spawned per portal lighting. Note: The number of zombie pigment spawned per portal lighting follows a binomial distribution and is well approximated by a Poisson distribution.
Potential 1.17 Fix: Active-portal gold farms can be supported without reverting the existing patches in 1.17. The game needs a specific mechanic where zombie pigmen have a chance to spawn if a portal is lit. This can be done on based on individual portal blocks when they are lit, or by the portal itself based on its size when lit. 1.17 does not need to model existing binomial/poisson distribution of zombie pigmen spawning rates, as long as the average is kept the same. Thus I propose the following mechanic:
When a portal is lit, the chance that a zombie pigman will spawn is height*width*difficulty/2000, where difficulty is 0 (peacful) to 3 (hard) and height/width measure the dimensions of the portal, not including the obsidian border.
Code Analysis (BDS 1.16.100): The code analysis in the report is incorrect. Those two functions are not responsible for ticking chunks.
`TickingAreaView::tick()` is the important function to pay attention to. This is the function that gets called every game tick to tick all the chunks in a ticking area. There is a bool flag passed to `TickingAreaView::tick()`, and that function does something different depending on whether the flag is TRUE or FALSE. I believe it's this flag that is responsible for chunks in ticking areas sometimes not ticking.
`TickingAreaListBase::tick()` ticks all the ticking areas in a dimension and is responsible for setting the flag that gets passed to `TickingAreaView::tick()`. For each ticking area, this flag is true once every 20 ticks, but not all ticking areas will have the flag set at the same time. (I'm simplifying here.)
When the flag is false, all chunks in the ticking area appear to be ticked normally. When the flag is true, the ticks seem to be getting ticked in a random order, or only a random subset get ticked. But I'm not quite sure of this.
My best guess is that ticking areas are supposed to work like this, but in practice they do not:
(1) Every tick: Tick all chunks in ticking area.
(2) Every 20 ticks, randomize the order of chunks in the ticking area.
I would like to add that the availability of symbols in the Linux BDS version of the game allows code diggers like myself to add in depth code analysis to bug reports making it easier to identify and fix the causes of bugs.
I investigated the differences in diamond ore generation between 1.16.221 and 1.17.0. I generated fresh worlds with the same seed in both versions and used rbedrock to compare 49 chunks centered around the world spawn in both versions. I then identified all locations that where diamond ores in either world (both normal and deepslate) in either world. I then grabbed the blocks in these locations in both world and constructed a table to highlight the differences.
A couple observations:
My guess on what is happening: deepslate is causing ore generation to stop. So when the algorithm encounters deepslate, it stops trying to place diamonds. This is why some stone blocks are not being converted into diamonds.Update: I was looking in the wrong location for feature descriptions. Turns out the in 1.17.0 diamond ore veins were made smaller (4 blocks instead of 8 blocks). But this has been fixed in 1.17.10.
Code Analysis: In 1.16.100, the y-level for slime spawning was changed to consider sea level. Specifically, slimes now spawn in slime chunks up to 23 blocks below sea level. On normal worlds, sea level is at y=63 and on flat worlds sea level is at y=5. Clearly this eliminates slime spawning in slime chunks on flat worlds.
Potential Fix: Make sea level data driven. If it was customizable in level.dat, then marketplace creators who create using flat worlds can change the value if they need too.
Code Analysis
Between 1.16.100 and 1.17.0, the lightning code was refactored. In 1.16.100, lightning bolts and skeleton traps were simulated separatly. Lightning bolts only struck the surface, while traps could strike and entity or the surface. This separation was probably due to a patch made to fix the bug mentioned in this report. However, during the refactoring, bolts and traps are now linked in 1.17.0, causing this bug to reemerge.
Lightning is spawned by LevelChunk::tickBlocks(). This function does a lot of things, but I'll focus only on the lightning spawning algorithm. The algorithm looks roughly like this
Now findLightningTarget(pos) can find three different targets
(1) the top rain block in the same vertical column as pos.
(2) a random entity (with entity type 0x1300) in the chunk
(3) a lightning rod near position (1)
The "top rain block" is the block right above the highest block in the column with a material that blocks precipitation.
A lightning rod can only be found if it can see the sky and is getting rained on.
If a random entity is chosen the game does NOT check to see if it can see the sky and is getting rained on. This is why people's pets are getting struck by lightning deep under ground.
Before refactoring, the game would double check that the result of findLigntningTarget(pos) was valid, but this was eliminated in the refactoring, exposing the bug.
*Suggested Fix*
After a random entity is chosen, the game should check that it can see the sky and is getting rained on similar to a lightning rod. If the check fails, the game should fall back to using the random surface block defined by (1).
After reverse engineering iron golem spawning mechanics in 1.17.30. And testing different designs in 1.17.40+ betas, I have developed the following improvement to the iron golem spawning mechanics.
In this algorithm, iron golems will spawn on top of the highest solid block in the search column that is below an air or liquid block also in the search column. If the spawn location is obstructed by blocks or entities, the spawn will fail and another attempt will be made.
Code Analysis
In `Level::tickBlocks()` the game uses signed integer arithmetic to generate the positions of random blocks to tick in a chunk. As a result, the random y level is negative 50% of the time, and BE selects a random block of air underneath the chunk instead of a block in the chunk. This causes the observed loss of 50% of random ticks.
A Proposed Fix
Use unsigned integer arithmetic to generate the positions of random blocks.
I experienced this same problem on a BDS world. A copy of the world can be found here: https://www.dropbox.com/s/3fwf4uzvo6yziln/ClassSMP-trim.zip?dl=0
This was was created last week in 1.17.34. When 1.17.40 came out on Wednesday, I upgraded the sever and enabled the Caves-N-Cliffs experimental toggle. Over the weekend, I noticed that many of the mobs spawner's nbt data had missing `EntityIdentifiers`, and thus have no entity spinning in the mob spawner and don't spawn mobs when the player gets close.
A table of all locations of mob spawners in this world is attached if anyone needs to visually inspect the world: spawner_pos.csv
.
I too can confirm this bug on Windows 10. I tested a world that only contains a creeper farm, and spiders are spawning in the farm.
I suspect that the way the collision box is calculated for buttons has changed in 1.19 preview.
I figured out what changed in 1.18.30 that broke creeper farms.
Code Analysis
When spiders (and most mobs) spawn, the game will cancel the spawning attempt if the mob collides with any block that has an AABB (axis-aligned bounding box). The function used for this is the virtual function BlockLegacy::getAABB() or its overrides. A refactoring occurred between 1.17 and 1.18 that added a boolean parameter to this function. I'll call it param_5. When param_5 is set to false, many blocks return an empty AABB. This is likely used to distinguish different types of AABBs, such as collision boxes or hit boxes. Notably param_5 is set to false when the game checks if a mob collides with any block.
In 1.18.30, ButtonBlock::getAABB() has been added to the game. (Buttons used BlockLegacy::getAABB() in earlier versions.) The dev who wrote this function included logic that returns an empty AABB if param_5 is false. This returns an empty bounding box during mob spawning, causing buttons to stop blocking spider spawns. This isn't a minor inconvenience. Even a small creeper farm can have thousands of buttons that would need to be replaced by an alternative block (if one even exists).
The Fix
Remove the logic in ButtonBlock::getAABB() that returns an empty bounding box if param_5 is false. ButtonBlock::getAABB() should always return an accurate bounding box regardless of the value of param_5. Given how quickly changes to pathfinding on coral fans was fixed, I hope that this bug can be quickly fixed as well.
I use turtle eggs in my drowned farm, and I am unable to replicate this bug in 1.18.30. I think this bug is invalid.
I created a simple test world. Turtle Egg Test.mcworld
In this world is a pen containing a drowned, husk, zombie, and zombified piglin. To verify that turtle eggs attract these mobs, place one on any of the emerald blocks. As expected, if (1) the turtle egg is in the detection range of the mobs, (2) there is an air-block above the turtle egg, and (3) the mobs an find a path to the egg, they will be attracted to it. There is no delay in the attraction.
I have viewed the video claiming to show this bug, and that video is consistent with expected mechanics. When the mobs can't find a path to an egg, they aren't attracted to it. When they can find a path to the egg, they go right for it.
I used rbedrock to analyze a fresh 1.19 world that was run for about 20 minutes or so.
I can confirm that there are actor keys in the database that are not recorded in any chunk's actor digest record. If those keys are from dead or despawned mobs, then the database has a "memory" leak.
I haven't tested if the leak keeps growing the longer the world is simulated. So I don't know if these orphaned actors will eventually be garbage collected.
Steps to Reproduce:
Observed Result:
There are 10 actorprefix keys. Each one holds NBT data for a llama. None of these keys are referenced in any digp record.
Expected Result:
There are 0 actorprefix keys.
I did some additional testing and it appears that, for partial blocks, the preferred block costs are calculated based on the block underneath the partial block. I created a test world with a simple village. The village contains one fletcher, one fletching table, and one bed. When time is set to night, the villager will go to his bed. When time is set to day, the villager will go to his workstation.
Expected Behavior: The villager walks in a straight line between the bed and workstation. Dirt paths all have the same cost (cost of 0) and the best path should be a straight one between the bed and workstation.
Observed behavior: He doesn't take a direct route. Instead he follows the route of the planks below the dirt paths (cost of 1). He avoids walking on the dirt paths that are above blast furnaces (cost of 50).
villager_pathfinding_bug.mcworld
Below are the results of code-digging and comparing 1.19.72 BDS to 1.20.12 BDS.
In 1.19.72, the environmental spawning algorithm [ Spawner::spawnMob() ] and the iron golem spawning algorithm [SpawnUtils::trySpawnMob()] used UpdateBoundingBoxSystem:updateBoundingBoxFromDefinition() to update a mobs bounding box before collision checks.
In 1.20.12, the environmental spawning algorithm does something else while the iron golem spawning algorithm still uses UpdateBoundingBoxSystem:updateBoundingBoxFromDefinition().
I suspect that UpdateBoundingBoxSystem:updateBoundingBoxFromDefinition() broke in 1.20.10.x previews and the environmental spawning system was later patched to use something else. However, the iron golem spawning algorithm hasn't been patched yet.
Dimension::tickRedstone() is the function responsible for evaluating redstone circuits every other game tick. It roughly looks like this:
In the Dimension::Dimension() constructor both redstone_counter and redstone_counter_max are initialized to 2, such that the circuit system will be evaluated on the first time `Dimension::tickRedstone()` is called after startup. This results in a 50/50 chance that a server will evaluate redstone circuits on even or odd ticks, depending on what the game time values is when a server restarts.
You can see this happen in game by triggering a command block to run the command "time query gametime" on a redstone pulse. Sometimes it will output even number and othertimes it will output odd numbers.
For any redstone components that utilize pending ticks or require precise timing, changing the parity of redstone ticks across restarts can cause them to behave in undefined ways.
The solution is likely simple: initialize redstone_counter to 2 or 1 based on whether the game time is odd or even. This would ensure that redstone ticks are synchronized across restarts.
The bug can be reproduced on a fresh world in 1.21.10.22. It isn't related to whether the world is upgraded or not. The game will create structure spawning areas (hard coded spawning areas) in fresh chunks, but it doesn't seem to save them or load them from existing chunks. This is very bad because once the hardcoded spawning areas are lost, structure spawning will also be permanently lost from those chunks.
Steps to Reproduce
The Cause
I inspected the world save using rbedrock and determined that the information for hardcoded spawning areas (chunk data with tag 57) isn't being saved in the world db. The information also does not appear to be moved to another location in the world db. Therefore it appears that the LevelChunk class has a regression that dropped support for saving and loading hardcoded spawning areas.
Mojang appears to have recently ported over biome tags from Java to Bedrock. Several of these tags don't make sense and are irrelevant to Bedrock such as "polar_bears_spawn_on_alternate_blocks" and "without_zombie_sieges". Other tags might be useful for modernizing Bedrock's mob spawning rules, making them more readable by Java devs, and/or make it easier for addons to query biome information. Unfortunately, during the porting process, the following Java code was incorrectly parsed, causing erroneous tags to be added to mangrove swamps, which was not caught when the changes were reviewed.
this.tag(BiomeTags.SPAWNS_WARM_VARIANT_FROGS).add(Biomes.DESERT).add(Biomes.WARM_OCEAN).addTag(BiomeTags.IS_JUNGLE).addTag(BiomeTags.IS_SAVANNA).addTag(BiomeTags.IS_NETHER).addTag(BiomeTags.IS_BADLANDS).add(Biomes.MANGROVE_SWAMP);Proposed Fix
Only the following tags should be in definitions/biomes/mangrove_swamp.biome.json: