From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Spottedleaf Date: Sat, 12 Mar 2022 06:31:13 -0800 Subject: [PATCH] Fix swamp hut cat generation deadlock The worldgen thread will attempt to get structure references via the world's getChunkAt method, which is fine if the gen is not cancelled - but if the chunk was unloaded, the call will block indefinitely. Instead of using the world state, we use the already supplied ServerLevelAccessor which will always have the chunk available. diff --git a/src/main/java/net/minecraft/world/entity/animal/Cat.java b/src/main/java/net/minecraft/world/entity/animal/Cat.java index 534630b0161c8d869e49e7a59572193550be0671..a744cb70ac719eae376fb2ab2271e4f8ac7b12f2 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Cat.java +++ b/src/main/java/net/minecraft/world/entity/animal/Cat.java @@ -364,7 +364,7 @@ public class Cat extends TamableAnimal implements VariantHolder { }); ServerLevel worldserver = world.getLevel(); - if (worldserver.structureManager().getStructureWithPieceAt(this.blockPosition(), StructureTags.CATS_SPAWN_AS_BLACK).isValid()) { + if (worldserver.structureManager().getStructureWithPieceAt(this.blockPosition(), StructureTags.CATS_SPAWN_AS_BLACK, world).isValid()) { // Paper - fix deadlock this.setVariant((CatVariant) BuiltInRegistries.CAT_VARIANT.getOrThrow(CatVariant.ALL_BLACK)); this.setPersistenceRequired(); } diff --git a/src/main/java/net/minecraft/world/level/StructureManager.java b/src/main/java/net/minecraft/world/level/StructureManager.java index b33a015b834873f279bf33a64974ef440a37df79..09c85ed428b8eaf51f8b3c6e45cce925f05ab354 100644 --- a/src/main/java/net/minecraft/world/level/StructureManager.java +++ b/src/main/java/net/minecraft/world/level/StructureManager.java @@ -44,7 +44,12 @@ public class StructureManager { } public List startsForStructure(ChunkPos pos, Predicate predicate) { - Map map = this.level.getChunk(pos.x, pos.z, ChunkStatus.STRUCTURE_REFERENCES).getAllReferences(); + // Paper start + return this.startsForStructure(pos, predicate, null); + } + public List startsForStructure(ChunkPos pos, Predicate predicate, @Nullable ServerLevelAccessor levelAccessor) { + Map map = (levelAccessor == null ? this.level : levelAccessor).getChunk(pos.x, pos.z, ChunkStatus.STRUCTURE_REFERENCES).getAllReferences(); + // Paper end ImmutableList.Builder builder = ImmutableList.builder(); for(Map.Entry entry : map.entrySet()) { @@ -108,13 +113,18 @@ public class StructureManager { } public StructureStart getStructureWithPieceAt(BlockPos pos, TagKey structureTag) { + // Paper start + return this.getStructureWithPieceAt(pos, structureTag, null); + } + public StructureStart getStructureWithPieceAt(BlockPos pos, TagKey structureTag, @Nullable ServerLevelAccessor levelAccessor) { + // Paper end Registry registry = this.registryAccess().registryOrThrow(Registries.STRUCTURE); for(StructureStart structureStart : this.startsForStructure(new ChunkPos(pos), (structure) -> { return registry.getHolder(registry.getId(structure)).map((reference) -> { return reference.is(structureTag); }).orElse(false); - })) { + }, levelAccessor)) { // Paper if (this.structureHasPieceAt(pos, structureStart)) { return structureStart; }