mojira.dev
MC-249136

Freeze/server-side lag spike sometimes occurs when attempting to locate a buried treasure or opening/breaking a chest containing a map

The bug

A server-side lag spike sometimes occurs when attempting to locate a buried treasure or opening/breaking a chest containing a map. Some players have reported crashes caused by this issue, one of which is attached.

Code analysis

Code analysis by @unknown can be found in this comment.

Linked issues

Attachments

Comments

ampolive

Clones MC-236740, although not nearly as bad.

Nathan

I have this happen in 22w14a and 15a but it actually crashes my server.

Seed: 1248939201

Coords of close chest that will crash server reliably: /execute in minecraft:overworld run tp @s -170.76 64.00 488.14 -367.35 52.65

I will attach a crash report if this lets me. When I run in normal mode there's only a lag but running as a docker container as server it crashes 100% of the time.

Nathan

This is my docker-compose config

version: '3'services:
  minecraft:
    ports:
      - "25584:25565"
    networks:
      - minecraft
    volumes:
      - "/opt/minecraft_snapshot/data:/data"
    environment:
      VERSION: "22w15a"
      EULA: "TRUE"
      TZ: "US/Mountain"
      MAX_MEMORY: 16G
      MAX_BUILD_HEIGHT: 320
      VIEW_DISTANCE: 10
      MAX_PLAYERS: 5
      CONSOLE: "false"
    image: itzg/minecraft-server:java17
    restart: always
    logging:
      driver: loki
      options:
        loki-url: "http://192.168.1.110:3100/loki/api/v1/push"
  exporter:
    image: 'nkimball/minecraft_exporter:v6'
    environment:
      RCON_HOST: minecraft
      RCON_PORT: 25585
      RCON_PASSWORD: redacted
    ports:
      - 9784:8000
    networks:
      - minecraft
    volumes:
      - /opt/minecraft_snapshot/data/Snapshot:/world:ro
    depends_on: 
      - minecraft
    restart: alwaysnetworks:
  minecraft:
    driver_opts:
      com.docker.network.bridge.name: br_snapshot
Nathan

Also I should note if I play a regular game and open to LAN it doesn't crash, only the server.jar.

ampolive

This actually seems to also affect other things that are relatively rare, including specific villages (if you search for a snowy village about 4000-5000 blocks away, the lag spike will be very similar). I don't know if it is the same issue.
Edit: it's not the same issue, that is MC-250276.

Nathan

It's not all boxes with treasure maps either. I teleported around the world seed I posted above and was able to find a shipwreck with a treasure map box that did work @ /execute in minecraft:overworld run tp @s -1402.83 62.00 -970.55 -627.30 31.80

Xi Sigma

Was also just affected by this.

Disregard. Was a memory issue combined with a slow hard drive.

MadVillager

Ran into this on release version 1.19 ~20 seconds of lag on a single-player world.

On our multiplayer server, it actually times out and crashes due to our watchdog timer. This crash also resulted in duplicated items. We are using Paper, which I understand is not Vanilla, so this part may not be relevant. I do not have a log file (not the server admin), but I can report in our case it hangs without any clear error message until Paper shuts it down.

Seed: -1417780687

Location of Chest: 386, 48, 686 (It has a Buried Treasure map)

EDIT: Not all maps crash/have the same lag spike. My suggestion is it may depend on how far away the X-marks the spot is on the map.

Doobliheim

This is affecting me as well with v1.19. I tried it on a server first, which was being killed by Watchdog after a tick exceeded 60 seconds. I moved to single player with the same seed and tried opening the underwater chest, and it did eventually open correctly without crashing, although the entire game stopped processing ticks during that time.

Seed: 1986624035365542

Chest coordinates: -259, 35, -1533

Chest contains a treasure map.

 

neropatti

Ran into this on vanilla 1.19.2. Opening the chest caused the integrated server to freeze for over a minute.

Seed: 631889363082005995

Chest coordinates: 10069 52 8909

QuirkySmirkyIan

Same here but really severe using 1.19.2 with paper which isn't vanilla but others are reporting it so I thought I should mention my side. My server crashes every time it tries to open a treasure map chest and if I log out and log back in it makes the treasure map point to no treasure. Also the locate command crashes things as well...

isXander

When profiling the server, it seems the issue is when it tries to get the structure position. What seems to be happening is when it tries to sample the heightmap it is taking a very long time, I don't know why.

[media]
mrsprew

I have the same issue on my server, this is what I was able to capture.

 

[16:55:01 ERROR]: Total packets processed on the main thread for all players: 1207
[16:55:01 ERROR]: ------------------------------
[16:55:01 ERROR]: Current Thread: Server thread
[16:55:01 ERROR]:       PID: 24 | Suspended: false | Native: false | State: RUNNABLE
[16:55:01 ERROR]:       Stack:
[16:55:01 ERROR]:               java.base@17.0.2/java.lang.Thread.yield(Native Method)
[16:55:01 ERROR]:               net.minecraft.util.thread.BlockableEventLoop.waitForTasks(BlockableEventLoop.java:147)
[16:55:01 ERROR]:               net.minecraft.util.thread.BlockableEventLoop.managedBlock(BlockableEventLoop.java:137)
[16:55:01 ERROR]:               net.minecraft.server.level.ServerChunkCache.getChunk(ServerChunkCache.java:484)
[16:55:01 ERROR]:               net.minecraft.world.level.Level.getChunk(Level.java:503)
[16:55:01 ERROR]:               net.minecraft.world.level.LevelReader.getChunk(LevelReader.java:134)
[16:55:01 ERROR]:               net.minecraft.world.level.chunk.ChunkGenerator.getStructureGeneratingAt(ChunkGenerator.java:490)
[16:55:01 ERROR]:               net.minecraft.world.level.chunk.ChunkGenerator.getNearestGeneratedStructure(ChunkGenerator.java:453)
[16:55:01 ERROR]:               net.minecraft.world.level.chunk.ChunkGenerator.findNearestMapStructure(ChunkGenerator.java:382)
[16:55:01 ERROR]:               net.minecraft.server.level.ServerLevel.findNearestMapStructure(ServerLevel.java:1904)
[16:55:01 ERROR]:               net.minecraft.world.level.storage.loot.functions.ExplorationMapFunction.run(ExplorationMapFunction.java:80)
[16:55:01 ERROR]:               net.minecraft.world.level.storage.loot.functions.LootItemConditionalFunction.apply(LootItemConditionalFunction.java:30)
[16:55:01 ERROR]:               net.minecraft.world.level.storage.loot.functions.ExplorationMapFunction.apply(ExplorationMapFunction.java:30)
[16:55:01 ERROR]:               net.minecraft.world.level.storage.loot.functions.LootItemFunctions.lambda$compose$1(LootItemFunctions.java:58)
[16:55:01 ERROR]:               net.minecraft.world.level.storage.loot.functions.LootItemFunctions$$Lambda$4226/0x0000000801491118.apply(Unknown Source)
[16:55:01 ERROR]:               net.minecraft.world.level.storage.loot.functions.LootItemFunction.decorate(LootItemFunction.java:13)
[16:55:01 ERROR]:               net.minecraft.world.level.storage.loot.functions.LootItemFunction$$Lambda$7344/0x00000008020735a0.accept(Unknown Source)
[16:55:01 ERROR]:               net.minecraft.world.level.storage.loot.entries.LootItem.createItemStack(LootItem.java:32)
[16:55:01 ERROR]:               net.minecraft.world.level.storage.loot.entries.LootPoolSingletonContainer$1.createItemStack(LootPoolSingletonContainer.java:31)
[16:55:01 ERROR]:               net.minecraft.world.level.storage.loot.LootPool.addRandomItem(LootPool.java:71)
[16:55:01 ERROR]:               net.minecraft.world.level.storage.loot.LootPool.addRandomItems(LootPool.java:93)
[16:55:01 ERROR]:               net.minecraft.world.level.storage.loot.LootTable.getRandomItemsRaw(LootTable.java:95)
[16:55:01 ERROR]:               net.minecraft.world.level.storage.loot.LootTable.getRandomItems(LootTable.java:106)
[16:55:01 ERROR]:               net.minecraft.world.level.storage.loot.LootTable.getRandomItems(LootTable.java:113)
[16:55:01 ERROR]:               net.minecraft.world.level.storage.loot.LootTable.fillInventory(LootTable.java:141)
[16:55:01 ERROR]:               net.minecraft.world.level.storage.loot.LootTable.fill(LootTable.java:136)
[16:55:01 ERROR]:               net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity.unpackLootTable(RandomizableContainerBlockEntity.java:85)
[16:55:01 ERROR]:               net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity.getItem(RandomizableContainerBlockEntity.java:110)
[16:55:01 ERROR]:               net.minecraft.world.Containers.dropContents(Containers.java:22)
[16:55:01 ERROR]:               net.minecraft.world.Containers.dropContents(Containers.java:13)
[16:55:01 ERROR]:               net.minecraft.world.level.block.ChestBlock.onRemove(ChestBlock.java:253)
[16:55:01 ERROR]:               net.minecraft.world.level.block.state.BlockBehaviour$BlockStateBase.onRemove(BlockBehaviour.java:1009)
[16:55:01 ERROR]:               net.minecraft.world.level.chunk.LevelChunk.setBlockState(LevelChunk.java:595)
[16:55:01 ERROR]:               net.minecraft.world.level.Level.setBlock(Level.java:552)
[16:55:01 ERROR]:               net.minecraft.world.level.Level.setBlock(Level.java:514)
[16:55:01 ERROR]:               net.minecraft.world.level.Level.removeBlock(Level.java:678)
[16:55:01 ERROR]:               net.minecraft.server.level.ServerPlayerGameMode.destroyBlock(ServerPlayerGameMode.java:414)
[16:55:01 ERROR]:               net.minecraft.server.level.ServerPlayerGameMode.destroyAndAck(ServerPlayerGameMode.java:328)
[16:55:01 ERROR]:               net.minecraft.server.level.ServerPlayerGameMode.handleBlockBreakAction(ServerPlayerGameMode.java:292)
[16:55:01 ERROR]:               net.minecraft.server.network.ServerGamePacketListenerImpl.handlePlayerAction(ServerGamePacketListenerImpl.java:1882)
[16:55:01 ERROR]:               net.minecraft.network.protocol.game.ServerboundPlayerActionPacket.handle(ServerboundPlayerActionPacket.java:42)
[16:55:01 ERROR]:               net.minecraft.network.protocol.game.ServerboundPlayerActionPacket.a(ServerboundPlayerActionPacket.java:15)
[16:55:01 ERROR]:               net.minecraft.network.protocol.PacketUtils.lambda$ensureRunningOnSameThread$1(PacketUtils.java:51)
[16:55:01 ERROR]:               net.minecraft.network.protocol.PlayerConnectionUtils$$Lambda$6653/0x0000000801f776f8.run(Unknown Source)
[16:55:01 ERROR]:               net.minecraft.server.TickTask.run(TickTask.java:18)
[16:55:01 ERROR]:               net.minecraft.util.thread.BlockableEventLoop.doRunTask(BlockableEventLoop.java:153)
[16:55:01 ERROR]:               net.minecraft.util.thread.ReentrantBlockableEventLoop.doRunTask(ReentrantBlockableEventLoop.java:24)
[16:55:01 ERROR]:               net.minecraft.server.MinecraftServer.doRunTask(MinecraftServer.java:1361)
[16:55:01 ERROR]:               net.minecraft.server.MinecraftServer.d(MinecraftServer.java:185)
[16:55:01 ERROR]:               net.minecraft.util.thread.BlockableEventLoop.pollTask(BlockableEventLoop.java:126)
[16:55:01 ERROR]:               net.minecraft.server.MinecraftServer.pollTaskInternal(MinecraftServer.java:1338)
[16:55:01 ERROR]:               net.minecraft.server.MinecraftServer.pollTask(MinecraftServer.java:1331)
[16:55:01 ERROR]:               net.minecraft.util.thread.BlockableEventLoop.managedBlock(BlockableEventLoop.java:136)
[16:55:01 ERROR]:               net.minecraft.server.MinecraftServer.waitUntilNextTick(MinecraftServer.java:1309)
[16:55:01 ERROR]:               net.minecraft.server.MinecraftServer.runServer(MinecraftServer.java:1197)
[16:55:01 ERROR]:               net.minecraft.server.MinecraftServer.lambda$spin$0(MinecraftServer.java:305)
[16:55:01 ERROR]:               net.minecraft.server.MinecraftServer$$Lambda$4326/0x00000008014d26e0.run(Unknown Source)
[16:55:01 ERROR]:               java.base@17.0.2/java.lang.Thread.run(Thread.java:833)

Hope this gets fixed.

 

Javier Rodríguez Castillo
Apollo

The length of time of the lag spike when getting a treasure map seems to be significantly reduced in 1.19.3 pre-2, but I can't comment for sure whether or not it's been fully fixed.

ampolive

I can notice improvements, but this is still not fixed in 1.19.3 Pre-release 2.

itsTyrion

That moment when even a modern Ryzen 9 CPU is not enough to circumvent this issue completely if the treasure is futher away. Not with PaperMC either. Only pregenning more blocks or disabling works ._.

Arisa Bot

⚠️ Your bug report has been marked as private, as it contains some sensitive privacy information (e.g. an email address or session ID).

-- I am a bot. This action was performed automatically! If you think it was incorrect, please notify us on Discord or Reddit

isXander

This is because when generating the loot table, it has to locate a valid buried treasure. This takes time because there are no existing chunks that have a buried treasure strucutre, so it has to generate chunks.

Due to the hidden nature of buried treasure, I think it would be safe to just highly increase the spawn rate of buried treasure, so it is more likely to be closer to treasure maps.

Apollo

If the issue was that the structure was far away, this issue would have happened in all versions 1.18+ the same way, but the issue just didn't exist in 1.18.x. It's only 1.19.x where the effects are to the point where servers consistently crash with buried treasure not too far away.

FaRo1

The comments here seem like it got a lot worse in some version, so probably the distance of the search is not the only problem. But in case this cannot be fixed in a good way (seems like a computationally hard problem to me), here's an idea for an almost-fix:
While the current set of datapacks would cause such a map to be created, an earlier action (ship or ruin gets generated, villager takes job) could start a new thread that searches for the treasure. The resulting map could be added to a new item tag of the chest or villager that normally does nothing in regular gameplay, but once the chest is opened or the villager is unlocked far enough, the item gets moved into the slot/trade. That way, there's no lag and no timeout.

The problem then still exists if a datapack gets enabled, disabled or reloaded that changes the loot table, but that should almost never happen in regular Survival gameplay, meaning that this issue would affect way less players and way more rarely.
I'm not sure whether removing the treasure chest changes anything about the map (MC-108082 seems to suggest that it doesn't), if that's the case, then that's an edge case that my idea does not cover. Maybe someone else has an idea how to solve that. Maybe a server-wide cache for treasures, similar to portals, regular maps and villager POIs?
The idea works for things that can have NBT, but not for /loot or if a custom datapack adds it to fishing, cat/villager gifts, bartering or advancement rewards. Those would then still be laggy, but I've personally never seen this, except maybe in a loot table randomiser (in which people usually don't even bother with any of these things, because breaking blocks already gives them almost everything).

abfielder

Still happening in 1.20 and more noticeable especially as the new armour trims are encouraging people to go looking for shipwrecks.

diskria

Can someone explain to me why the villagers don't lag when I buy a map that leads to a woodland mansion, which can be thousands of blocks from the village?

But for some reason these ships freeze, it's already unbearable! reproduced in 1.20.1

Chase

I don't know if anyone else has this issue, or if this is related (although I'm sure it is) but, because the freeze/lag from opening/breaking a chest with a buried treasure map in it is so bad, the map itself is loaded as an empty map. It still has the title "Buried Treasure Map", but when it's held in the player's hand, it's displayed as an empty, unused map. When right-clicking, it acts like an empty map and shows the area around the player, completely removing the functionality of it being a treasure map.

I've noticed this just now while playing 1.20.1. But I swear that last month, I was playing on a Survival world in the same version (although it was initially created in 1.20) but this was not an issue at all for me then. So I don't know at all what causes the lag or the failure of the map being properly a buried treasure map.

In case it has any impact, I always set my render distance to 16 and my simulation distance to 12. I do play with OptiFine and/or Fabric, but I've tried loading in a completely vanilla client and it all persists regardless.

Bytzo

On multiplayer servers, I have also experienced this freeze when others were exploring shipwrecks. After some attempts over the months, I think I might have a possible solution.

Code Analysis

When using the /locate command on buried treasure, or when buried treasure maps are generated, eventually the getNearestGeneratedStructure() method (the random spread one, not the concentric rings one) in net.minecraft.world.level.chunk.ChunkGenerator is called. This loops over potential structure chunks around the player according to each structure's spread and calls several other methods to determine whether or not the structure can generate there. This includes the findValidGenerationPoint() method in net.minecraft.world.level.levelgen.structure.Structure, which is called to return a valid generation point if the generation point is in a valid biome for that structure.

The buried treasure structure has a spread of 1. This means that every single chunk around the player will searched until a buried treasure structure is found. In comparison, other structures usually have much larger spread, meaning only a few specific chunks around the player will be searched. Buried treasure structures are still kept rare despite their small spread using the LEGACY_TYPE_2 frequency reduction method.

While a structure having a spread of 1 alone does not cause a lag spike, its combination with other factors of the buried treasure structure can. The buried treasure structure must calculate the terrain height in order to find its generation point. findGenerationPoint() calls onTopOfChunkCenter() in net.minecraft.world.level.levelgen.structure.structures.BuriedTreasureStructure. And since findGenerationPoint() is called for every potential structure chunk through findValidGenerationPoint(), a small spread size of 1 causes the terrain height to be calculated many, many times, creating the observable lag spike.

Code Fix

Similar to normal world generation in the createStructures() method in net.minecraft.world.level.chunk.ChunkGenerator, the return value of the method isStructureChunk() in net.minecraft.world.level.levelgen.structure.placement.StructurePlacement can be checked before attempting to find a valid generation point in potential structure chunks. This way, potential structure chunks that are not valid structure chunks according to the frequency reduction method are skipped and the terrain height does not have to be calculated many times for buried treasure.

One possible place where this check could be implemented is in the canCreateStructure() method in net.minecraft.world.level.levelgen.structure.StructureCheck, which returns whether or not a structure can be generated in a certain chunk.

private boolean canCreateStructure(ChunkPos chunkPos, Structure structure) {
    // Get the current structure in a holder.
    var structureHolder = this.registryAccess.registryOrThrow(Registries.STRUCTURE).wrapAsHolder(structure);

    // Loop through each placement in the structure holder.
    for (var placement : this.generatorState.getPlacementsForStructure(structureHolder)) {
        // Only if the chunk is a valid structure chunk according to the placement...
        if (placement.isStructureChunk(this.generatorState, chunkPos.x, chunkPos.z)) {
            // ...continue looking for a valid generation point to determine whether or not a structure will be generated.
            return structure.findValidGenerationPoint(new Structure.GenerationContext(this.registryAccess, this.chunkGenerator, this.biomeSource, this.randomState, this.structureTemplateManager, this.seed, chunkPos, this.heightAccessor, structure.biomes()::contains)).isPresent();
        }
    }

    // If all placements were not in structure chunks, return false.
    return false;
}

Note that access to the chunk generator state in StructureCheck is needed in order to call isStructureChunk(). When constructing net.minecraft.world.level.levelgen.structure.StructureCheck in net.minecraft.server.level.ServerLevel, the chunk generator state can passed to StructureCheck by calling getGeneratorState() on the field chunkSource.

Impact

In Minecraft 1.20.4, I measured the time it took to locate a buried treasure structure using the /locate command after creating a fresh world with seed 6071974100908662531, both without and with the potential fix.

Structure

Without fix

With fix

Difference

Buried Treasure

7329ms

138ms

-7191ms

At least for this trial, there was a 5211% increase in speed! To be sure that the fix was not negatively impacting other things, I also measured the time to locate other structures both without and with the potential fix.

Structure

Without fix

With fix

Difference

Shipwreck

18ms

34ms

+16ms

Mansion

95ms

81ms

-14ms

Pillager Outpost

110ms

104ms

-6ms

Mineshaft

0ms

0ms

0ms

Igloo

76ms

68ms

-8ms

Swamp Hut

441ms

445ms

+4ms

Buried Treasure (again)

7399ms

155ms

-7244ms

Results indicated that there were no significant changes in the speed of locating other structures without and with the potential fix.

Fix Implementation

I have implemented the fix outlined above in a FabricMC mod for testing purposes, which seems to be successful in resolving the issue. It can be run on both the client and the server. The source code for the mod can be accessed here: https://github.com/bytzo/mc-249136.

ampolive

I've tested this in three separate world and it seems significantly better on 24w04a. Is anyone still able to reproduce this issue on 24w04a?

Bytzo

This appears to be fixed in Minecraft version 24w04a. I have tested this on the game client and have looked at the code, which both indicate this being fixed.

The method isStructureChunk in StructurePlacement was refactored so that the logic for using a structure's frequency reduction method is in its own method, called applyAdditionalChunkRestrictions. This method is then used before starting to check for a structure in checkStart.

This is a much better solution than the solution I previously wrote since the logic for the frequency reduction method does not require access to a ChunkGeneratorStructureState, so refactoring it out allows for a much cleaner check in StructureCheck. I wrote my solution was in a way so that the game logic would not have to be copied to the mod containing the fix, and I determined that extracting the logic from isStructureChunk would be difficult. So, instead I used the whole method which required a very messy way of accessing a ChunkGeneratorStructureState and structure placement within StructureCheck.

Since this appears to be fixed as of now, I believe this issue can be marked as resolved.

Bytzo

Oops, it looks like this was already marked as resolved while I was checking and writing the below comment. I probably should have refreshed the page before posting, sorry!

Eagle7z

playing on version 1.20.4, vanilla server running on Linux, issue is definitely not resolved, found 2 separate shipwreck chests causing the server to crash

ampolive

1.20.4 is an affected version. This issue was fixed on 24w04a, a 1.20.5 snapshot.

Jolo_Janssen

I ran into this issue on a 1.21.1 server. The server lagged and then crashed when opening underwater loot chests with buried treasure maps.

ampolive

(Unassigned)

Confirmed

Platform

Normal

Maps, Performance, World generation

buried-treasure-map, lag-spike, map, shipwreck

22w11a, 22w12a, 22w15a, 22w17a, 1.19 Pre-release 1, ..., 23w32a, 23w33a, 1.20.2, 1.20.3 Pre-Release 2, 1.20.4

24w04a

Retrieved