diff --git a/nms-patches/net/minecraft/world/level/chunk/storage/ChunkRegionLoader.patch b/nms-patches/net/minecraft/world/level/chunk/storage/ChunkRegionLoader.patch index 4f2cd8bb0..e9f8d8280 100644 --- a/nms-patches/net/minecraft/world/level/chunk/storage/ChunkRegionLoader.patch +++ b/nms-patches/net/minecraft/world/level/chunk/storage/ChunkRegionLoader.patch @@ -114,3 +114,16 @@ return nbttagcompound; } +@@ -545,6 +563,12 @@ + StructureStart structurestart = StructureStart.loadStaticStart(structurepieceserializationcontext, nbttagcompound1.getCompound(s), i); + + if (structurestart != null) { ++ // CraftBukkit start - load persistent data for structure start ++ net.minecraft.nbt.NBTBase persistentBase = nbttagcompound1.getCompound(s).get("StructureBukkitValues"); ++ if (persistentBase instanceof NBTTagCompound) { ++ structurestart.persistentDataContainer.putAll((NBTTagCompound) persistentBase); ++ } ++ // CraftBukkit end + map.put(structure, structurestart); + } + } diff --git a/nms-patches/net/minecraft/world/level/levelgen/structure/StructureStart.patch b/nms-patches/net/minecraft/world/level/levelgen/structure/StructureStart.patch index f94fcf519..d951f9772 100644 --- a/nms-patches/net/minecraft/world/level/levelgen/structure/StructureStart.patch +++ b/nms-patches/net/minecraft/world/level/levelgen/structure/StructureStart.patch @@ -1,14 +1,19 @@ --- a/net/minecraft/world/level/levelgen/structure/StructureStart.java +++ b/net/minecraft/world/level/levelgen/structure/StructureStart.java -@@ -31,6 +31,7 @@ - private int references; +@@ -32,6 +32,12 @@ @Nullable private volatile StructureBoundingBox cachedBoundingBox; -+ public org.bukkit.event.world.AsyncStructureGenerateEvent.Cause generationEventCause = org.bukkit.event.world.AsyncStructureGenerateEvent.Cause.WORLD_GENERATION; // CraftBukkit ++ // CraftBukkit start ++ private static final org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry(); ++ public org.bukkit.craftbukkit.persistence.DirtyCraftPersistentDataContainer persistentDataContainer = new org.bukkit.craftbukkit.persistence.DirtyCraftPersistentDataContainer(DATA_TYPE_REGISTRY); ++ public org.bukkit.event.world.AsyncStructureGenerateEvent.Cause generationEventCause = org.bukkit.event.world.AsyncStructureGenerateEvent.Cause.WORLD_GENERATION; ++ // CraftBukkit end ++ public StructureStart(Structure structure, ChunkCoordIntPair chunkcoordintpair, int i, PiecesContainer piecescontainer) { this.structure = structure; -@@ -91,6 +92,8 @@ + this.chunkPos = chunkcoordintpair; +@@ -91,6 +97,8 @@ StructureBoundingBox structureboundingbox1 = ((StructurePiece) list.get(0)).boundingBox; BlockPosition blockposition = structureboundingbox1.getCenter(); BlockPosition blockposition1 = new BlockPosition(blockposition.getX(), structureboundingbox1.minY(), blockposition.getZ()); @@ -17,7 +22,7 @@ Iterator iterator = list.iterator(); while (iterator.hasNext()) { -@@ -100,6 +103,18 @@ +@@ -100,6 +108,18 @@ structurepiece.postProcess(generatoraccessseed, structuremanager, chunkgenerator, randomsource, structureboundingbox, chunkcoordintpair, blockposition1); } } @@ -36,3 +41,15 @@ this.structure.afterPlace(generatoraccessseed, structuremanager, chunkgenerator, randomsource, structureboundingbox, chunkcoordintpair, this.pieceContainer); } +@@ -107,6 +127,11 @@ + + public NBTTagCompound createTag(StructurePieceSerializationContext structurepieceserializationcontext, ChunkCoordIntPair chunkcoordintpair) { + NBTTagCompound nbttagcompound = new NBTTagCompound(); ++ // CraftBukkit start - store persistent data in nbt ++ if (!persistentDataContainer.isEmpty()) { ++ nbttagcompound.put("StructureBukkitValues", persistentDataContainer.toTagCompound()); ++ } ++ // CraftBukkit end + + if (this.isValid()) { + nbttagcompound.putString("id", structurepieceserializationcontext.registryAccess().registryOrThrow(Registries.STRUCTURE).getKey(this.structure).toString()); diff --git a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java index 96144bab2..447b0ef69 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java @@ -48,6 +48,8 @@ import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.data.CraftBlockData; import org.bukkit.entity.Entity; +import org.bukkit.generator.structure.GeneratedStructure; +import org.bukkit.generator.structure.Structure; import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.plugin.Plugin; @@ -363,6 +365,16 @@ public class CraftChunk implements Chunk { return LoadLevel.values()[chunk.getFullStatus().ordinal()]; } + @Override + public Collection getStructures() { + return getCraftWorld().getStructures(getX(), getZ()); + } + + @Override + public Collection getStructures(Structure structure) { + return getCraftWorld().getStructures(getX(), getZ(), structure); + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index 3faf9a9a7..55e277aa7 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -27,6 +27,8 @@ import java.util.stream.Collectors; import net.minecraft.core.BlockPosition; import net.minecraft.core.Holder; import net.minecraft.core.HolderSet; +import net.minecraft.core.IRegistry; +import net.minecraft.core.registries.Registries; import net.minecraft.nbt.NBTBase; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; @@ -62,6 +64,7 @@ import net.minecraft.world.level.biome.Climate; import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.IChunkAccess; import net.minecraft.world.level.chunk.ProtoChunkExtension; +import net.minecraft.world.level.levelgen.structure.StructureStart; import net.minecraft.world.level.storage.SavedFile; import net.minecraft.world.phys.AxisAlignedBB; import net.minecraft.world.phys.MovingObjectPosition; @@ -100,6 +103,7 @@ import org.bukkit.craftbukkit.block.data.CraftBlockData; import org.bukkit.craftbukkit.boss.CraftDragonBattle; import org.bukkit.craftbukkit.entity.CraftEntity; import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.generator.structure.CraftGeneratedStructure; import org.bukkit.craftbukkit.generator.structure.CraftStructure; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.metadata.BlockMetadataStore; @@ -130,6 +134,7 @@ import org.bukkit.event.world.TimeSkipEvent; import org.bukkit.generator.BiomeProvider; import org.bukkit.generator.BlockPopulator; import org.bukkit.generator.ChunkGenerator; +import org.bukkit.generator.structure.GeneratedStructure; import org.bukkit.generator.structure.Structure; import org.bukkit.generator.structure.StructureType; import org.bukkit.inventory.ItemStack; @@ -1981,6 +1986,30 @@ public class CraftWorld extends CraftRegionAccessor implements World { return (getHandle().getDragonFight() == null) ? null : new CraftDragonBattle(getHandle().getDragonFight()); } + @Override + public Collection getStructures(int x, int z) { + return getStructures(x, z, struct -> true); + } + + @Override + public Collection getStructures(int x, int z, Structure structure) { + Preconditions.checkArgument(structure != null, "Structure cannot be null"); + + IRegistry registry = CraftRegistry.getMinecraftRegistry(Registries.STRUCTURE); + MinecraftKey key = registry.getKey(CraftStructure.bukkitToMinecraft(structure)); + + return getStructures(x, z, struct -> registry.getKey(struct).equals(key)); + } + + private List getStructures(int x, int z, Predicate predicate) { + List structures = new ArrayList<>(); + for (StructureStart start : getHandle().structureManager().startsForStructure(new ChunkCoordIntPair(x, z), predicate)) { + structures.add(new CraftGeneratedStructure(start)); + } + + return structures; + } + @Override public PersistentDataContainer getPersistentDataContainer() { return persistentDataContainer; diff --git a/src/main/java/org/bukkit/craftbukkit/generator/structure/CraftGeneratedStructure.java b/src/main/java/org/bukkit/craftbukkit/generator/structure/CraftGeneratedStructure.java new file mode 100644 index 000000000..99aee229a --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/generator/structure/CraftGeneratedStructure.java @@ -0,0 +1,52 @@ +package org.bukkit.craftbukkit.generator.structure; + +import com.google.common.collect.ImmutableList; +import java.util.Collection; +import java.util.List; +import net.minecraft.world.level.levelgen.structure.StructureBoundingBox; +import net.minecraft.world.level.levelgen.structure.StructureStart; +import org.bukkit.generator.structure.GeneratedStructure; +import org.bukkit.generator.structure.Structure; +import org.bukkit.generator.structure.StructurePiece; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.util.BoundingBox; + +public class CraftGeneratedStructure implements GeneratedStructure { + + private final StructureStart handle; + private List pieces; + + public CraftGeneratedStructure(StructureStart handle) { + this.handle = handle; + } + + @Override + public BoundingBox getBoundingBox() { + StructureBoundingBox bb = handle.getBoundingBox(); + return new BoundingBox(bb.minX(), bb.minY(), bb.minZ(), bb.maxX(), bb.maxY(), bb.maxZ()); + } + + @Override + public Structure getStructure() { + return CraftStructure.minecraftToBukkit(handle.getStructure()); + } + + @Override + public Collection getPieces() { + if (pieces == null) { // Cache the pieces on first request + ImmutableList.Builder builder = new ImmutableList.Builder<>(); + for (net.minecraft.world.level.levelgen.structure.StructurePiece piece : handle.getPieces()) { + builder.add(new CraftStructurePiece(piece)); + } + + pieces = builder.build(); + } + + return this.pieces; + } + + @Override + public PersistentDataContainer getPersistentDataContainer() { + return handle.persistentDataContainer; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/generator/structure/CraftStructurePiece.java b/src/main/java/org/bukkit/craftbukkit/generator/structure/CraftStructurePiece.java new file mode 100644 index 000000000..91cc6dc65 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/generator/structure/CraftStructurePiece.java @@ -0,0 +1,20 @@ +package org.bukkit.craftbukkit.generator.structure; + +import net.minecraft.world.level.levelgen.structure.StructureBoundingBox; +import org.bukkit.generator.structure.StructurePiece; +import org.bukkit.util.BoundingBox; + +public class CraftStructurePiece implements StructurePiece { + + private final net.minecraft.world.level.levelgen.structure.StructurePiece handle; + + public CraftStructurePiece(net.minecraft.world.level.levelgen.structure.StructurePiece handle) { + this.handle = handle; + } + + @Override + public BoundingBox getBoundingBox() { + StructureBoundingBox bb = handle.getBoundingBox(); + return new BoundingBox(bb.minX(), bb.minY(), bb.minZ(), bb.maxX(), bb.maxY(), bb.maxZ()); + } +}