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 5ad968a2f1add27da0d6a858e683d5d771128092..e44352857272a2a4027c67bd25a28a9498b7bb49 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Cat.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Cat.java
@@ -361,7 +361,7 @@ public class Cat extends TamableAnimal {
         });
         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.setCatVariant(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 e7445c1ff0d1e3e989fcd8d3630dd5269a64598d..64ca546a905d69a795bbdafb4f9860b31cd863d1 100644
--- a/src/main/java/net/minecraft/world/level/StructureManager.java
+++ b/src/main/java/net/minecraft/world/level/StructureManager.java
@@ -43,7 +43,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()) {
@@ -107,13 +112,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(Registry.STRUCTURE_REGISTRY);
 
         for(StructureStart structureStart : this.startsForStructure(new ChunkPos(pos), (structure) -> {
             return registry.getHolder(registry.getId(structure)).map((holder) -> {
                 return holder.is(structureTag);
             }).orElse(false);
-        })) {
+        }, levelAccessor)) { // Paper
             if (this.structureHasPieceAt(pos, structureStart)) {
                 return structureStart;
             }
