minecraft-src/net/minecraft/world/level/chunk/ChunkGenerator.java
2025-07-04 03:45:38 +03:00

634 lines
25 KiB
Java

package net.minecraft.world.level.chunk;
import com.google.common.base.Suppliers;
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import it.unimi.dsi.fastutil.ints.IntArraySet;
import it.unimi.dsi.fastutil.ints.IntSet;
import it.unimi.dsi.fastutil.longs.LongSet;
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
import it.unimi.dsi.fastutil.objects.ObjectArraySet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.Map.Entry;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import net.minecraft.CrashReport;
import net.minecraft.CrashReportCategory;
import net.minecraft.CrashReportDetail;
import net.minecraft.ReportedException;
import net.minecraft.SharedConstants;
import net.minecraft.Util;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderLookup;
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.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.protocol.game.DebugPackets;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.WorldGenRegion;
import net.minecraft.util.random.WeightedList;
import net.minecraft.world.entity.MobCategory;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.NoiseColumn;
import net.minecraft.world.level.StructureManager;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeGenerationSettings;
import net.minecraft.world.level.biome.BiomeManager;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.biome.FeatureSorter;
import net.minecraft.world.level.biome.MobSpawnSettings;
import net.minecraft.world.level.biome.FeatureSorter.StepFeatureData;
import net.minecraft.world.level.chunk.status.ChunkStatus;
import net.minecraft.world.level.levelgen.GenerationStep;
import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.levelgen.LegacyRandomSource;
import net.minecraft.world.level.levelgen.RandomState;
import net.minecraft.world.level.levelgen.RandomSupport;
import net.minecraft.world.level.levelgen.WorldgenRandom;
import net.minecraft.world.level.levelgen.XoroshiroRandomSource;
import net.minecraft.world.level.levelgen.blending.Blender;
import net.minecraft.world.level.levelgen.placement.PlacedFeature;
import net.minecraft.world.level.levelgen.structure.BoundingBox;
import net.minecraft.world.level.levelgen.structure.Structure;
import net.minecraft.world.level.levelgen.structure.StructureCheckResult;
import net.minecraft.world.level.levelgen.structure.StructureSet;
import net.minecraft.world.level.levelgen.structure.StructureSpawnOverride;
import net.minecraft.world.level.levelgen.structure.StructureStart;
import net.minecraft.world.level.levelgen.structure.StructureSet.StructureSelectionEntry;
import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement;
import net.minecraft.world.level.levelgen.structure.placement.RandomSpreadStructurePlacement;
import net.minecraft.world.level.levelgen.structure.placement.StructurePlacement;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
import org.apache.commons.lang3.mutable.MutableBoolean;
import org.jetbrains.annotations.Nullable;
public abstract class ChunkGenerator {
public static final Codec<ChunkGenerator> CODEC = BuiltInRegistries.CHUNK_GENERATOR.byNameCodec().dispatchStable(ChunkGenerator::codec, Function.identity());
protected final BiomeSource biomeSource;
private final Supplier<List<StepFeatureData>> featuresPerStep;
private final Function<Holder<Biome>, BiomeGenerationSettings> generationSettingsGetter;
public ChunkGenerator(BiomeSource biomeSource) {
this(biomeSource, holder -> ((Biome)holder.value()).getGenerationSettings());
}
public ChunkGenerator(BiomeSource biomeSource, Function<Holder<Biome>, BiomeGenerationSettings> generationSettingsGetter) {
this.biomeSource = biomeSource;
this.generationSettingsGetter = generationSettingsGetter;
this.featuresPerStep = Suppliers.memoize(
() -> FeatureSorter.buildFeaturesPerStep(
List.copyOf(biomeSource.possibleBiomes()), holder -> ((BiomeGenerationSettings)generationSettingsGetter.apply(holder)).features(), true
)
);
}
public void validate() {
this.featuresPerStep.get();
}
protected abstract MapCodec<? extends ChunkGenerator> codec();
public ChunkGeneratorStructureState createState(HolderLookup<StructureSet> structureSetLookup, RandomState randomState, long seed) {
return ChunkGeneratorStructureState.createForNormal(randomState, seed, this.biomeSource, structureSetLookup);
}
public Optional<ResourceKey<MapCodec<? extends ChunkGenerator>>> getTypeNameForDataFixer() {
return BuiltInRegistries.CHUNK_GENERATOR.getResourceKey(this.codec());
}
public CompletableFuture<ChunkAccess> createBiomes(RandomState randomState, Blender blender, StructureManager structureManager, ChunkAccess chunk) {
return CompletableFuture.supplyAsync(() -> {
chunk.fillBiomesFromNoise(this.biomeSource, randomState.sampler());
return chunk;
}, Util.backgroundExecutor().forName("init_biomes"));
}
public abstract void applyCarvers(
WorldGenRegion level, long seed, RandomState random, BiomeManager biomeManager, StructureManager structureManager, ChunkAccess chunk
);
@Nullable
public Pair<BlockPos, Holder<Structure>> findNearestMapStructure(
ServerLevel level, HolderSet<Structure> structure, BlockPos pos, int searchRadius, boolean skipKnownStructures
) {
ChunkGeneratorStructureState chunkGeneratorStructureState = level.getChunkSource().getGeneratorState();
Map<StructurePlacement, Set<Holder<Structure>>> map = new Object2ObjectArrayMap<>();
for (Holder<Structure> holder : structure) {
for (StructurePlacement structurePlacement : chunkGeneratorStructureState.getPlacementsForStructure(holder)) {
((Set)map.computeIfAbsent(structurePlacement, structurePlacementx -> new ObjectArraySet())).add(holder);
}
}
if (map.isEmpty()) {
return null;
} else {
Pair<BlockPos, Holder<Structure>> pair = null;
double d = Double.MAX_VALUE;
StructureManager structureManager = level.structureManager();
List<Entry<StructurePlacement, Set<Holder<Structure>>>> list = new ArrayList(map.size());
for (Entry<StructurePlacement, Set<Holder<Structure>>> entry : map.entrySet()) {
StructurePlacement structurePlacement2 = (StructurePlacement)entry.getKey();
if (structurePlacement2 instanceof ConcentricRingsStructurePlacement concentricRingsStructurePlacement) {
Pair<BlockPos, Holder<Structure>> pair2 = this.getNearestGeneratedStructure(
(Set<Holder<Structure>>)entry.getValue(), level, structureManager, pos, skipKnownStructures, concentricRingsStructurePlacement
);
if (pair2 != null) {
BlockPos blockPos = pair2.getFirst();
double e = pos.distSqr(blockPos);
if (e < d) {
d = e;
pair = pair2;
}
}
} else if (structurePlacement2 instanceof RandomSpreadStructurePlacement) {
list.add(entry);
}
}
if (!list.isEmpty()) {
int i = SectionPos.blockToSectionCoord(pos.getX());
int j = SectionPos.blockToSectionCoord(pos.getZ());
for (int k = 0; k <= searchRadius; k++) {
boolean bl = false;
for (Entry<StructurePlacement, Set<Holder<Structure>>> entry2 : list) {
RandomSpreadStructurePlacement randomSpreadStructurePlacement = (RandomSpreadStructurePlacement)entry2.getKey();
Pair<BlockPos, Holder<Structure>> pair3 = getNearestGeneratedStructure(
(Set<Holder<Structure>>)entry2.getValue(),
level,
structureManager,
i,
j,
k,
skipKnownStructures,
chunkGeneratorStructureState.getLevelSeed(),
randomSpreadStructurePlacement
);
if (pair3 != null) {
bl = true;
double f = pos.distSqr(pair3.getFirst());
if (f < d) {
d = f;
pair = pair3;
}
}
}
if (bl) {
return pair;
}
}
}
return pair;
}
}
@Nullable
private Pair<BlockPos, Holder<Structure>> getNearestGeneratedStructure(
Set<Holder<Structure>> structureHoldersSet,
ServerLevel level,
StructureManager structureManager,
BlockPos pos,
boolean skipKnownStructures,
ConcentricRingsStructurePlacement placement
) {
List<ChunkPos> list = level.getChunkSource().getGeneratorState().getRingPositionsFor(placement);
if (list == null) {
throw new IllegalStateException("Somehow tried to find structures for a placement that doesn't exist");
} else {
Pair<BlockPos, Holder<Structure>> pair = null;
double d = Double.MAX_VALUE;
BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
for (ChunkPos chunkPos : list) {
mutableBlockPos.set(SectionPos.sectionToBlockCoord(chunkPos.x, 8), 32, SectionPos.sectionToBlockCoord(chunkPos.z, 8));
double e = mutableBlockPos.distSqr(pos);
boolean bl = pair == null || e < d;
if (bl) {
Pair<BlockPos, Holder<Structure>> pair2 = getStructureGeneratingAt(structureHoldersSet, level, structureManager, skipKnownStructures, placement, chunkPos);
if (pair2 != null) {
pair = pair2;
d = e;
}
}
}
return pair;
}
}
@Nullable
private static Pair<BlockPos, Holder<Structure>> getNearestGeneratedStructure(
Set<Holder<Structure>> structureHoldersSet,
LevelReader level,
StructureManager structureManager,
int x,
int y,
int z,
boolean skipKnownStructures,
long seed,
RandomSpreadStructurePlacement spreadPlacement
) {
int i = spreadPlacement.spacing();
for (int j = -z; j <= z; j++) {
boolean bl = j == -z || j == z;
for (int k = -z; k <= z; k++) {
boolean bl2 = k == -z || k == z;
if (bl || bl2) {
int l = x + i * j;
int m = y + i * k;
ChunkPos chunkPos = spreadPlacement.getPotentialStructureChunk(seed, l, m);
Pair<BlockPos, Holder<Structure>> pair = getStructureGeneratingAt(
structureHoldersSet, level, structureManager, skipKnownStructures, spreadPlacement, chunkPos
);
if (pair != null) {
return pair;
}
}
}
}
return null;
}
@Nullable
private static Pair<BlockPos, Holder<Structure>> getStructureGeneratingAt(
Set<Holder<Structure>> structureHoldersSet,
LevelReader level,
StructureManager structureManager,
boolean skipKnownStructures,
StructurePlacement placement,
ChunkPos chunkPos
) {
for (Holder<Structure> holder : structureHoldersSet) {
StructureCheckResult structureCheckResult = structureManager.checkStructurePresence(chunkPos, holder.value(), placement, skipKnownStructures);
if (structureCheckResult != StructureCheckResult.START_NOT_PRESENT) {
if (!skipKnownStructures && structureCheckResult == StructureCheckResult.START_PRESENT) {
return Pair.of(placement.getLocatePos(chunkPos), holder);
}
ChunkAccess chunkAccess = level.getChunk(chunkPos.x, chunkPos.z, ChunkStatus.STRUCTURE_STARTS);
StructureStart structureStart = structureManager.getStartForStructure(SectionPos.bottomOf(chunkAccess), holder.value(), chunkAccess);
if (structureStart != null && structureStart.isValid() && (!skipKnownStructures || tryAddReference(structureManager, structureStart))) {
return Pair.of(placement.getLocatePos(structureStart.getChunkPos()), holder);
}
}
}
return null;
}
private static boolean tryAddReference(StructureManager structureManager, StructureStart structureStart) {
if (structureStart.canBeReferenced()) {
structureManager.addReference(structureStart);
return true;
} else {
return false;
}
}
public void applyBiomeDecoration(WorldGenLevel level, ChunkAccess chunk, StructureManager structureManager) {
ChunkPos chunkPos = chunk.getPos();
if (!SharedConstants.debugVoidTerrain(chunkPos)) {
SectionPos sectionPos = SectionPos.of(chunkPos, level.getMinSectionY());
BlockPos blockPos = sectionPos.origin();
Registry<Structure> registry = level.registryAccess().lookupOrThrow(Registries.STRUCTURE);
Map<Integer, List<Structure>> map = (Map<Integer, List<Structure>>)registry.stream().collect(Collectors.groupingBy(structure -> structure.step().ordinal()));
List<StepFeatureData> list = (List<StepFeatureData>)this.featuresPerStep.get();
WorldgenRandom worldgenRandom = new WorldgenRandom(new XoroshiroRandomSource(RandomSupport.generateUniqueSeed()));
long l = worldgenRandom.setDecorationSeed(level.getSeed(), blockPos.getX(), blockPos.getZ());
Set<Holder<Biome>> set = new ObjectArraySet<>();
ChunkPos.rangeClosed(sectionPos.chunk(), 1).forEach(chunkPosx -> {
ChunkAccess chunkAccess = level.getChunk(chunkPosx.x, chunkPosx.z);
for (LevelChunkSection levelChunkSection : chunkAccess.getSections()) {
levelChunkSection.getBiomes().getAll(set::add);
}
});
set.retainAll(this.biomeSource.possibleBiomes());
int i = list.size();
try {
Registry<PlacedFeature> registry2 = level.registryAccess().lookupOrThrow(Registries.PLACED_FEATURE);
int j = Math.max(GenerationStep.Decoration.values().length, i);
for (int k = 0; k < j; k++) {
int m = 0;
if (structureManager.shouldGenerateStructures()) {
for (Structure structure : (List)map.getOrDefault(k, Collections.emptyList())) {
worldgenRandom.setFeatureSeed(l, m, k);
Supplier<String> supplier = () -> (String)registry.getResourceKey(structure).map(Object::toString).orElseGet(structure::toString);
try {
level.setCurrentlyGenerating(supplier);
structureManager.startsForStructure(sectionPos, structure)
.forEach(structureStart -> structureStart.placeInChunk(level, structureManager, this, worldgenRandom, getWritableArea(chunk), chunkPos));
} catch (Exception var29) {
CrashReport crashReport = CrashReport.forThrowable(var29, "Feature placement");
crashReport.addCategory("Feature").setDetail("Description", supplier::get);
throw new ReportedException(crashReport);
}
m++;
}
}
if (k < i) {
IntSet intSet = new IntArraySet();
for (Holder<Biome> holder : set) {
List<HolderSet<PlacedFeature>> list3 = ((BiomeGenerationSettings)this.generationSettingsGetter.apply(holder)).features();
if (k < list3.size()) {
HolderSet<PlacedFeature> holderSet = (HolderSet<PlacedFeature>)list3.get(k);
StepFeatureData stepFeatureData = (StepFeatureData)list.get(k);
holderSet.stream().map(Holder::value).forEach(placedFeaturex -> intSet.add(stepFeatureData.indexMapping().applyAsInt(placedFeaturex)));
}
}
int n = intSet.size();
int[] is = intSet.toIntArray();
Arrays.sort(is);
StepFeatureData stepFeatureData2 = (StepFeatureData)list.get(k);
for (int o = 0; o < n; o++) {
int p = is[o];
PlacedFeature placedFeature = (PlacedFeature)stepFeatureData2.features().get(p);
Supplier<String> supplier2 = () -> (String)registry2.getResourceKey(placedFeature).map(Object::toString).orElseGet(placedFeature::toString);
worldgenRandom.setFeatureSeed(l, p, k);
try {
level.setCurrentlyGenerating(supplier2);
placedFeature.placeWithBiomeCheck(level, this, worldgenRandom, blockPos);
} catch (Exception var30) {
CrashReport crashReport2 = CrashReport.forThrowable(var30, "Feature placement");
crashReport2.addCategory("Feature").setDetail("Description", supplier2::get);
throw new ReportedException(crashReport2);
}
}
}
}
level.setCurrentlyGenerating(null);
} catch (Exception var31) {
CrashReport crashReport3 = CrashReport.forThrowable(var31, "Biome decoration");
crashReport3.addCategory("Generation").setDetail("CenterX", chunkPos.x).setDetail("CenterZ", chunkPos.z).setDetail("Decoration Seed", l);
throw new ReportedException(crashReport3);
}
}
}
private static BoundingBox getWritableArea(ChunkAccess chunk) {
ChunkPos chunkPos = chunk.getPos();
int i = chunkPos.getMinBlockX();
int j = chunkPos.getMinBlockZ();
LevelHeightAccessor levelHeightAccessor = chunk.getHeightAccessorForGeneration();
int k = levelHeightAccessor.getMinY() + 1;
int l = levelHeightAccessor.getMaxY();
return new BoundingBox(i, k, j, i + 15, l, j + 15);
}
public abstract void buildSurface(WorldGenRegion level, StructureManager structureManager, RandomState random, ChunkAccess chunk);
public abstract void spawnOriginalMobs(WorldGenRegion level);
public int getSpawnHeight(LevelHeightAccessor level) {
return 64;
}
public BiomeSource getBiomeSource() {
return this.biomeSource;
}
public abstract int getGenDepth();
public WeightedList<MobSpawnSettings.SpawnerData> getMobsAt(Holder<Biome> biome, StructureManager structureManager, MobCategory category, BlockPos pos) {
Map<Structure, LongSet> map = structureManager.getAllStructuresAt(pos);
for (Entry<Structure, LongSet> entry : map.entrySet()) {
Structure structure = (Structure)entry.getKey();
StructureSpawnOverride structureSpawnOverride = (StructureSpawnOverride)structure.spawnOverrides().get(category);
if (structureSpawnOverride != null) {
MutableBoolean mutableBoolean = new MutableBoolean(false);
Predicate<StructureStart> predicate = structureSpawnOverride.boundingBox() == StructureSpawnOverride.BoundingBoxType.PIECE
? structureStart -> structureManager.structureHasPieceAt(pos, structureStart)
: structureStart -> structureStart.getBoundingBox().isInside(pos);
structureManager.fillStartsForStructure(structure, (LongSet)entry.getValue(), structureStart -> {
if (mutableBoolean.isFalse() && predicate.test(structureStart)) {
mutableBoolean.setTrue();
}
});
if (mutableBoolean.isTrue()) {
return structureSpawnOverride.spawns();
}
}
}
return biome.value().getMobSettings().getMobs(category);
}
public void createStructures(
RegistryAccess registryAccess,
ChunkGeneratorStructureState structureState,
StructureManager structureManager,
ChunkAccess chunk,
StructureTemplateManager structureTemplateManager,
ResourceKey<Level> level
) {
ChunkPos chunkPos = chunk.getPos();
SectionPos sectionPos = SectionPos.bottomOf(chunk);
RandomState randomState = structureState.randomState();
structureState.possibleStructureSets()
.forEach(
holder -> {
StructurePlacement structurePlacement = ((StructureSet)holder.value()).placement();
List<StructureSelectionEntry> list = ((StructureSet)holder.value()).structures();
for (StructureSelectionEntry structureSelectionEntry : list) {
StructureStart structureStart = structureManager.getStartForStructure(sectionPos, structureSelectionEntry.structure().value(), chunk);
if (structureStart != null && structureStart.isValid()) {
return;
}
}
if (structurePlacement.isStructureChunk(structureState, chunkPos.x, chunkPos.z)) {
if (list.size() == 1) {
this.tryGenerateStructure(
(StructureSelectionEntry)list.get(0),
structureManager,
registryAccess,
randomState,
structureTemplateManager,
structureState.getLevelSeed(),
chunk,
chunkPos,
sectionPos,
level
);
} else {
ArrayList<StructureSelectionEntry> arrayList = new ArrayList(list.size());
arrayList.addAll(list);
WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L));
worldgenRandom.setLargeFeatureSeed(structureState.getLevelSeed(), chunkPos.x, chunkPos.z);
int i = 0;
for (StructureSelectionEntry structureSelectionEntry2 : arrayList) {
i += structureSelectionEntry2.weight();
}
while (!arrayList.isEmpty()) {
int j = worldgenRandom.nextInt(i);
int k = 0;
for (StructureSelectionEntry structureSelectionEntry3 : arrayList) {
j -= structureSelectionEntry3.weight();
if (j < 0) {
break;
}
k++;
}
StructureSelectionEntry structureSelectionEntry4 = (StructureSelectionEntry)arrayList.get(k);
if (this.tryGenerateStructure(
structureSelectionEntry4,
structureManager,
registryAccess,
randomState,
structureTemplateManager,
structureState.getLevelSeed(),
chunk,
chunkPos,
sectionPos,
level
)) {
return;
}
arrayList.remove(k);
i -= structureSelectionEntry4.weight();
}
}
}
}
);
}
private boolean tryGenerateStructure(
StructureSelectionEntry structureSelectionEntry,
StructureManager structureManager,
RegistryAccess registryAccess,
RandomState random,
StructureTemplateManager structureTemplateManager,
long seed,
ChunkAccess chunk,
ChunkPos chunkPos,
SectionPos sectionPos,
ResourceKey<Level> level
) {
Structure structure = structureSelectionEntry.structure().value();
int i = fetchReferences(structureManager, chunk, sectionPos, structure);
HolderSet<Biome> holderSet = structure.biomes();
Predicate<Holder<Biome>> predicate = holderSet::contains;
StructureStart structureStart = structure.generate(
structureSelectionEntry.structure(), level, registryAccess, this, this.biomeSource, random, structureTemplateManager, seed, chunkPos, i, chunk, predicate
);
if (structureStart.isValid()) {
structureManager.setStartForStructure(sectionPos, structure, structureStart, chunk);
return true;
} else {
return false;
}
}
private static int fetchReferences(StructureManager structureManager, ChunkAccess chunk, SectionPos sectionPos, Structure structure) {
StructureStart structureStart = structureManager.getStartForStructure(sectionPos, structure, chunk);
return structureStart != null ? structureStart.getReferences() : 0;
}
public void createReferences(WorldGenLevel level, StructureManager structureManager, ChunkAccess chunk) {
int i = 8;
ChunkPos chunkPos = chunk.getPos();
int j = chunkPos.x;
int k = chunkPos.z;
int l = chunkPos.getMinBlockX();
int m = chunkPos.getMinBlockZ();
SectionPos sectionPos = SectionPos.bottomOf(chunk);
for (int n = j - 8; n <= j + 8; n++) {
for (int o = k - 8; o <= k + 8; o++) {
long p = ChunkPos.asLong(n, o);
for (StructureStart structureStart : level.getChunk(n, o).getAllStarts().values()) {
try {
if (structureStart.isValid() && structureStart.getBoundingBox().intersects(l, m, l + 15, m + 15)) {
structureManager.addReferenceForStructure(sectionPos, structureStart.getStructure(), p, chunk);
DebugPackets.sendStructurePacket(level, structureStart);
}
} catch (Exception var21) {
CrashReport crashReport = CrashReport.forThrowable(var21, "Generating structure reference");
CrashReportCategory crashReportCategory = crashReport.addCategory("Structure");
Optional<? extends Registry<Structure>> optional = level.registryAccess().lookup(Registries.STRUCTURE);
crashReportCategory.setDetail(
"Id", (CrashReportDetail<String>)(() -> (String)optional.map(registry -> registry.getKey(structureStart.getStructure()).toString()).orElse("UNKNOWN"))
);
crashReportCategory.setDetail(
"Name", (CrashReportDetail<String>)(() -> BuiltInRegistries.STRUCTURE_TYPE.getKey(structureStart.getStructure().type()).toString())
);
crashReportCategory.setDetail("Class", (CrashReportDetail<String>)(() -> structureStart.getStructure().getClass().getCanonicalName()));
throw new ReportedException(crashReport);
}
}
}
}
}
public abstract CompletableFuture<ChunkAccess> fillFromNoise(Blender blender, RandomState randomState, StructureManager structureManager, ChunkAccess chunk);
public abstract int getSeaLevel();
public abstract int getMinY();
public abstract int getBaseHeight(int x, int z, Heightmap.Types type, LevelHeightAccessor level, RandomState random);
public abstract NoiseColumn getBaseColumn(int x, int z, LevelHeightAccessor height, RandomState random);
public int getFirstFreeHeight(int x, int z, Heightmap.Types type, LevelHeightAccessor level, RandomState random) {
return this.getBaseHeight(x, z, type, level, random);
}
public int getFirstOccupiedHeight(int x, int z, Heightmap.Types types, LevelHeightAccessor level, RandomState random) {
return this.getBaseHeight(x, z, types, level, random) - 1;
}
public abstract void addDebugScreenInfo(List<String> info, RandomState random, BlockPos pos);
@Deprecated
public BiomeGenerationSettings getBiomeGenerationSettings(Holder<Biome> biome) {
return (BiomeGenerationSettings)this.generationSettingsGetter.apply(biome);
}
}