From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
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 ad4392c3ec8f9f5f910f3be40f6b7dbfed223ca7..366f32b11f39a79210532c614fdbb2230b87d88f 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Cat.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Cat.java
@@ -366,7 +366,7 @@ public class Cat extends TamableAnimal implements VariantHolder<CatVariant> {
         });
         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 924c7a67abe334494c571f9b4c5c8a7d5dfef5b4..bad7031426ae6c750ae4376beb238186e7d65270 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<StructureStart> startsForStructure(ChunkPos pos, Predicate<Structure> predicate) {
-        Map<Structure, LongSet> map = this.level.getChunk(pos.x, pos.z, ChunkStatus.STRUCTURE_REFERENCES).getAllReferences();
+        // Paper start
+        return this.startsForStructure(pos, predicate, null);
+    }
+    public List<StructureStart> startsForStructure(ChunkPos pos, Predicate<Structure> predicate, @Nullable ServerLevelAccessor levelAccessor) {
+        Map<Structure, LongSet> map = (levelAccessor == null ? this.level : levelAccessor).getChunk(pos.x, pos.z, ChunkStatus.STRUCTURE_REFERENCES).getAllReferences();
+        // Paper end
         ImmutableList.Builder<StructureStart> builder = ImmutableList.builder();
 
         for(Map.Entry<Structure, LongSet> entry : map.entrySet()) {
@@ -108,13 +113,18 @@ public class StructureManager {
     }
 
     public StructureStart getStructureWithPieceAt(BlockPos pos, TagKey<Structure> structureTag) {
+        // Paper start
+        return this.getStructureWithPieceAt(pos, structureTag, null);
+    }
+    public StructureStart getStructureWithPieceAt(BlockPos pos, TagKey<Structure> structureTag, @Nullable ServerLevelAccessor levelAccessor) {
+        // Paper end
         Registry<Structure> 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;
             }
