package net.minecraft.world.level; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList.Builder; import it.unimi.dsi.fastutil.longs.LongIterator; import it.unimi.dsi.fastutil.longs.LongSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.function.Consumer; import java.util.function.Predicate; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.HolderSet; import net.minecraft.core.Registry; import net.minecraft.core.RegistryAccess; import net.minecraft.core.SectionPos; import net.minecraft.core.registries.Registries; import net.minecraft.server.level.WorldGenRegion; import net.minecraft.tags.TagKey; import net.minecraft.world.level.chunk.StructureAccess; import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.levelgen.WorldOptions; import net.minecraft.world.level.levelgen.structure.Structure; import net.minecraft.world.level.levelgen.structure.StructureCheck; import net.minecraft.world.level.levelgen.structure.StructureCheckResult; import net.minecraft.world.level.levelgen.structure.StructurePiece; import net.minecraft.world.level.levelgen.structure.StructureStart; import net.minecraft.world.level.levelgen.structure.placement.StructurePlacement; import org.jetbrains.annotations.Nullable; public class StructureManager { private final LevelAccessor level; private final WorldOptions worldOptions; private final StructureCheck structureCheck; public StructureManager(LevelAccessor level, WorldOptions worldOptions, StructureCheck structureCheck) { this.level = level; this.worldOptions = worldOptions; this.structureCheck = structureCheck; } public StructureManager forWorldGenRegion(WorldGenRegion region) { if (region.getLevel() != this.level) { throw new IllegalStateException("Using invalid structure manager (source level: " + region.getLevel() + ", region: " + region); } else { return new StructureManager(region, this.worldOptions, this.structureCheck); } } public List startsForStructure(ChunkPos chunkPos, Predicate structurePredicate) { Map map = this.level.getChunk(chunkPos.x, chunkPos.z, ChunkStatus.STRUCTURE_REFERENCES).getAllReferences(); Builder builder = ImmutableList.builder(); for (Entry entry : map.entrySet()) { Structure structure = (Structure)entry.getKey(); if (structurePredicate.test(structure)) { this.fillStartsForStructure(structure, (LongSet)entry.getValue(), builder::add); } } return builder.build(); } public List startsForStructure(SectionPos sectionPos, Structure structure) { LongSet longSet = this.level.getChunk(sectionPos.x(), sectionPos.z(), ChunkStatus.STRUCTURE_REFERENCES).getReferencesForStructure(structure); Builder builder = ImmutableList.builder(); this.fillStartsForStructure(structure, longSet, builder::add); return builder.build(); } public void fillStartsForStructure(Structure structure, LongSet structureRefs, Consumer startConsumer) { LongIterator var4 = structureRefs.iterator(); while (var4.hasNext()) { long l = (Long)var4.next(); SectionPos sectionPos = SectionPos.of(new ChunkPos(l), this.level.getMinSectionY()); StructureStart structureStart = this.getStartForStructure( sectionPos, structure, this.level.getChunk(sectionPos.x(), sectionPos.z(), ChunkStatus.STRUCTURE_STARTS) ); if (structureStart != null && structureStart.isValid()) { startConsumer.accept(structureStart); } } } @Nullable public StructureStart getStartForStructure(SectionPos sectionPos, Structure structure, StructureAccess structureAccess) { return structureAccess.getStartForStructure(structure); } public void setStartForStructure(SectionPos sectionPos, Structure structure, StructureStart structureStart, StructureAccess structureAccess) { structureAccess.setStartForStructure(structure, structureStart); } public void addReferenceForStructure(SectionPos sectionPos, Structure structure, long reference, StructureAccess structureAccess) { structureAccess.addReferenceForStructure(structure, reference); } public boolean shouldGenerateStructures() { return this.worldOptions.generateStructures(); } public StructureStart getStructureAt(BlockPos pos, Structure structure) { for (StructureStart structureStart : this.startsForStructure(SectionPos.of(pos), structure)) { if (structureStart.getBoundingBox().isInside(pos)) { return structureStart; } } return StructureStart.INVALID_START; } public StructureStart getStructureWithPieceAt(BlockPos pos, TagKey structureTag) { return this.getStructureWithPieceAt(pos, holder -> holder.is(structureTag)); } public StructureStart getStructureWithPieceAt(BlockPos pos, HolderSet structures) { return this.getStructureWithPieceAt(pos, structures::contains); } public StructureStart getStructureWithPieceAt(BlockPos pos, Predicate> predicate) { Registry registry = this.registryAccess().lookupOrThrow(Registries.STRUCTURE); for (StructureStart structureStart : this.startsForStructure( new ChunkPos(pos), structure -> (Boolean)registry.get(registry.getId(structure)).map(predicate::test).orElse(false) )) { if (this.structureHasPieceAt(pos, structureStart)) { return structureStart; } } return StructureStart.INVALID_START; } public StructureStart getStructureWithPieceAt(BlockPos pos, Structure structure) { for (StructureStart structureStart : this.startsForStructure(SectionPos.of(pos), structure)) { if (this.structureHasPieceAt(pos, structureStart)) { return structureStart; } } return StructureStart.INVALID_START; } public boolean structureHasPieceAt(BlockPos pos, StructureStart structureStart) { for (StructurePiece structurePiece : structureStart.getPieces()) { if (structurePiece.getBoundingBox().isInside(pos)) { return true; } } return false; } public boolean hasAnyStructureAt(BlockPos pos) { SectionPos sectionPos = SectionPos.of(pos); return this.level.getChunk(sectionPos.x(), sectionPos.z(), ChunkStatus.STRUCTURE_REFERENCES).hasAnyStructureReferences(); } public Map getAllStructuresAt(BlockPos pos) { SectionPos sectionPos = SectionPos.of(pos); return this.level.getChunk(sectionPos.x(), sectionPos.z(), ChunkStatus.STRUCTURE_REFERENCES).getAllReferences(); } public StructureCheckResult checkStructurePresence(ChunkPos chunkPos, Structure structure, StructurePlacement placement, boolean skipKnownStructures) { return this.structureCheck.checkStart(chunkPos, structure, placement, skipKnownStructures); } public void addReference(StructureStart structureStart) { structureStart.addReference(); this.structureCheck.incrementReference(structureStart.getChunkPos(), structureStart.getStructure()); } public RegistryAccess registryAccess() { return this.level.registryAccess(); } }