178 lines
6.9 KiB
Java
178 lines
6.9 KiB
Java
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<StructureStart> startsForStructure(ChunkPos chunkPos, Predicate<Structure> structurePredicate) {
|
|
Map<Structure, LongSet> map = this.level.getChunk(chunkPos.x, chunkPos.z, ChunkStatus.STRUCTURE_REFERENCES).getAllReferences();
|
|
Builder<StructureStart> builder = ImmutableList.builder();
|
|
|
|
for (Entry<Structure, LongSet> 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<StructureStart> startsForStructure(SectionPos sectionPos, Structure structure) {
|
|
LongSet longSet = this.level.getChunk(sectionPos.x(), sectionPos.z(), ChunkStatus.STRUCTURE_REFERENCES).getReferencesForStructure(structure);
|
|
Builder<StructureStart> builder = ImmutableList.builder();
|
|
this.fillStartsForStructure(structure, longSet, builder::add);
|
|
return builder.build();
|
|
}
|
|
|
|
public void fillStartsForStructure(Structure structure, LongSet structureRefs, Consumer<StructureStart> 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<Structure> structureTag) {
|
|
return this.getStructureWithPieceAt(pos, holder -> holder.is(structureTag));
|
|
}
|
|
|
|
public StructureStart getStructureWithPieceAt(BlockPos pos, HolderSet<Structure> structures) {
|
|
return this.getStructureWithPieceAt(pos, structures::contains);
|
|
}
|
|
|
|
public StructureStart getStructureWithPieceAt(BlockPos pos, Predicate<Holder<Structure>> predicate) {
|
|
Registry<Structure> 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<Structure, LongSet> 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();
|
|
}
|
|
}
|