Code/net/minecraft/world/level/levelgen/structure/Structure.java

312 lines
14 KiB
Java

package net.minecraft.world.level.levelgen.structure;
import com.mojang.datafixers.util.Either;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import com.mojang.serialization.codecs.RecordCodecBuilder.Instance;
import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderSet;
import net.minecraft.core.QuartPos;
import net.minecraft.core.RegistryAccess;
import net.minecraft.core.RegistryCodecs;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.RegistryFileCodec;
import net.minecraft.resources.ResourceKey;
import net.minecraft.util.RandomSource;
import net.minecraft.util.StringRepresentable;
import net.minecraft.util.profiling.jfr.JvmProfiler;
import net.minecraft.util.profiling.jfr.callback.ProfiledDuration;
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.StructureManager;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.chunk.ChunkGenerator;
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.WorldgenRandom;
import net.minecraft.world.level.levelgen.structure.pieces.PiecesContainer;
import net.minecraft.world.level.levelgen.structure.pieces.StructurePiecesBuilder;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
public abstract class Structure {
public static final Codec<Structure> DIRECT_CODEC = BuiltInRegistries.STRUCTURE_TYPE.byNameCodec().dispatch(Structure::type, StructureType::codec);
public static final Codec<Holder<Structure>> CODEC = RegistryFileCodec.create(Registries.STRUCTURE, DIRECT_CODEC);
protected final Structure.StructureSettings settings;
public static <S extends Structure> RecordCodecBuilder<S, Structure.StructureSettings> settingsCodec(Instance<S> p_226568_) {
return Structure.StructureSettings.CODEC.forGetter(p_226595_ -> p_226595_.settings);
}
public static <S extends Structure> MapCodec<S> simpleCodec(Function<Structure.StructureSettings, S> p_226608_) {
return RecordCodecBuilder.mapCodec(p_226611_ -> p_226611_.group(settingsCodec(p_226611_)).apply(p_226611_, p_226608_));
}
protected Structure(Structure.StructureSettings p_226558_) {
this.settings = p_226558_;
}
public HolderSet<Biome> biomes() {
return this.settings.biomes;
}
public Map<MobCategory, StructureSpawnOverride> spawnOverrides() {
return this.settings.spawnOverrides;
}
public GenerationStep.Decoration step() {
return this.settings.step;
}
public TerrainAdjustment terrainAdaptation() {
return this.settings.terrainAdaptation;
}
public BoundingBox adjustBoundingBox(BoundingBox p_226570_) {
return this.terrainAdaptation() != TerrainAdjustment.NONE ? p_226570_.inflatedBy(12) : p_226570_;
}
public StructureStart generate(
Holder<Structure> p_378494_,
ResourceKey<Level> p_376569_,
RegistryAccess p_226597_,
ChunkGenerator p_226598_,
BiomeSource p_226599_,
RandomState p_226600_,
StructureTemplateManager p_226601_,
long p_226602_,
ChunkPos p_226603_,
int p_226604_,
LevelHeightAccessor p_226605_,
Predicate<Holder<Biome>> p_226606_
) {
ProfiledDuration profiledduration = JvmProfiler.INSTANCE.onStructureGenerate(p_226603_, p_376569_, p_378494_);
Structure.GenerationContext structure$generationcontext = new Structure.GenerationContext(
p_226597_, p_226598_, p_226599_, p_226600_, p_226601_, p_226602_, p_226603_, p_226605_, p_226606_
);
Optional<Structure.GenerationStub> optional = this.findValidGenerationPoint(structure$generationcontext);
if (optional.isPresent()) {
StructurePiecesBuilder structurepiecesbuilder = optional.get().getPiecesBuilder();
StructureStart structurestart = new StructureStart(this, p_226603_, p_226604_, structurepiecesbuilder.build());
if (structurestart.isValid()) {
if (profiledduration != null) {
profiledduration.finish(true);
}
return structurestart;
}
}
if (profiledduration != null) {
profiledduration.finish(false);
}
return StructureStart.INVALID_START;
}
protected static Optional<Structure.GenerationStub> onTopOfChunkCenter(
Structure.GenerationContext p_226586_, Heightmap.Types p_226587_, Consumer<StructurePiecesBuilder> p_226588_
) {
ChunkPos chunkpos = p_226586_.chunkPos();
int i = chunkpos.getMiddleBlockX();
int j = chunkpos.getMiddleBlockZ();
int k = p_226586_.chunkGenerator().getFirstOccupiedHeight(i, j, p_226587_, p_226586_.heightAccessor(), p_226586_.randomState());
return Optional.of(new Structure.GenerationStub(new BlockPos(i, k, j), p_226588_));
}
private static boolean isValidBiome(Structure.GenerationStub p_263042_, Structure.GenerationContext p_263005_) {
BlockPos blockpos = p_263042_.position();
return p_263005_.validBiome
.test(
p_263005_.chunkGenerator
.getBiomeSource()
.getNoiseBiome(
QuartPos.fromBlock(blockpos.getX()),
QuartPos.fromBlock(blockpos.getY()),
QuartPos.fromBlock(blockpos.getZ()),
p_263005_.randomState.sampler()
)
);
}
public void afterPlace(
WorldGenLevel p_226560_,
StructureManager p_226561_,
ChunkGenerator p_226562_,
RandomSource p_226563_,
BoundingBox p_226564_,
ChunkPos p_226565_,
PiecesContainer p_226566_
) {
}
private static int[] getCornerHeights(Structure.GenerationContext p_226614_, int p_226615_, int p_226616_, int p_226617_, int p_226618_) {
ChunkGenerator chunkgenerator = p_226614_.chunkGenerator();
LevelHeightAccessor levelheightaccessor = p_226614_.heightAccessor();
RandomState randomstate = p_226614_.randomState();
return new int[]{
chunkgenerator.getFirstOccupiedHeight(p_226615_, p_226617_, Heightmap.Types.WORLD_SURFACE_WG, levelheightaccessor, randomstate),
chunkgenerator.getFirstOccupiedHeight(p_226615_, p_226617_ + p_226618_, Heightmap.Types.WORLD_SURFACE_WG, levelheightaccessor, randomstate),
chunkgenerator.getFirstOccupiedHeight(p_226615_ + p_226616_, p_226617_, Heightmap.Types.WORLD_SURFACE_WG, levelheightaccessor, randomstate),
chunkgenerator.getFirstOccupiedHeight(p_226615_ + p_226616_, p_226617_ + p_226618_, Heightmap.Types.WORLD_SURFACE_WG, levelheightaccessor, randomstate)
};
}
public static int getMeanFirstOccupiedHeight(Structure.GenerationContext p_334739_, int p_329786_, int p_332089_, int p_333818_, int p_333198_) {
int[] aint = getCornerHeights(p_334739_, p_329786_, p_332089_, p_333818_, p_333198_);
return (aint[0] + aint[1] + aint[2] + aint[3]) / 4;
}
protected static int getLowestY(Structure.GenerationContext p_226573_, int p_226574_, int p_226575_) {
ChunkPos chunkpos = p_226573_.chunkPos();
int i = chunkpos.getMinBlockX();
int j = chunkpos.getMinBlockZ();
return getLowestY(p_226573_, i, j, p_226574_, p_226575_);
}
protected static int getLowestY(Structure.GenerationContext p_226577_, int p_226578_, int p_226579_, int p_226580_, int p_226581_) {
int[] aint = getCornerHeights(p_226577_, p_226578_, p_226580_, p_226579_, p_226581_);
return Math.min(Math.min(aint[0], aint[1]), Math.min(aint[2], aint[3]));
}
@Deprecated
protected BlockPos getLowestYIn5by5BoxOffset7Blocks(Structure.GenerationContext p_226583_, Rotation p_226584_) {
int i = 5;
int j = 5;
if (p_226584_ == Rotation.CLOCKWISE_90) {
i = -5;
} else if (p_226584_ == Rotation.CLOCKWISE_180) {
i = -5;
j = -5;
} else if (p_226584_ == Rotation.COUNTERCLOCKWISE_90) {
j = -5;
}
ChunkPos chunkpos = p_226583_.chunkPos();
int k = chunkpos.getBlockX(7);
int l = chunkpos.getBlockZ(7);
return new BlockPos(k, getLowestY(p_226583_, k, l, i, j), l);
}
protected abstract Optional<Structure.GenerationStub> findGenerationPoint(Structure.GenerationContext p_226571_);
public Optional<Structure.GenerationStub> findValidGenerationPoint(Structure.GenerationContext p_263060_) {
return this.findGenerationPoint(p_263060_).filter(p_262911_ -> isValidBiome(p_262911_, p_263060_));
}
public abstract StructureType<?> type();
public record GenerationContext(
RegistryAccess registryAccess,
ChunkGenerator chunkGenerator,
BiomeSource biomeSource,
RandomState randomState,
StructureTemplateManager structureTemplateManager,
WorldgenRandom random,
long seed,
ChunkPos chunkPos,
LevelHeightAccessor heightAccessor,
Predicate<Holder<Biome>> validBiome
) {
public GenerationContext(
RegistryAccess p_226632_,
ChunkGenerator p_226633_,
BiomeSource p_226634_,
RandomState p_226635_,
StructureTemplateManager p_226636_,
long p_226637_,
ChunkPos p_226638_,
LevelHeightAccessor p_226639_,
Predicate<Holder<Biome>> p_226640_
) {
this(p_226632_, p_226633_, p_226634_, p_226635_, p_226636_, makeRandom(p_226637_, p_226638_), p_226637_, p_226638_, p_226639_, p_226640_);
}
private static WorldgenRandom makeRandom(long p_226654_, ChunkPos p_226655_) {
WorldgenRandom worldgenrandom = new WorldgenRandom(new LegacyRandomSource(0L));
worldgenrandom.setLargeFeatureSeed(p_226654_, p_226655_.x, p_226655_.z);
return worldgenrandom;
}
}
public record GenerationStub(BlockPos position, Either<Consumer<StructurePiecesBuilder>, StructurePiecesBuilder> generator) {
public GenerationStub(BlockPos p_226675_, Consumer<StructurePiecesBuilder> p_226676_) {
this(p_226675_, Either.left(p_226676_));
}
public StructurePiecesBuilder getPiecesBuilder() {
return this.generator.map(p_226681_ -> {
StructurePiecesBuilder structurepiecesbuilder = new StructurePiecesBuilder();
p_226681_.accept(structurepiecesbuilder);
return structurepiecesbuilder;
}, p_226679_ -> (StructurePiecesBuilder)p_226679_);
}
}
public record StructureSettings(
HolderSet<Biome> biomes, Map<MobCategory, StructureSpawnOverride> spawnOverrides, GenerationStep.Decoration step, TerrainAdjustment terrainAdaptation
) {
static final Structure.StructureSettings DEFAULT = new Structure.StructureSettings(
HolderSet.direct(), Map.of(), GenerationStep.Decoration.SURFACE_STRUCTURES, TerrainAdjustment.NONE
);
public static final MapCodec<Structure.StructureSettings> CODEC = RecordCodecBuilder.mapCodec(
p_341910_ -> p_341910_.group(
RegistryCodecs.homogeneousList(Registries.BIOME).fieldOf("biomes").forGetter(Structure.StructureSettings::biomes),
Codec.simpleMap(MobCategory.CODEC, StructureSpawnOverride.CODEC, StringRepresentable.keys(MobCategory.values()))
.fieldOf("spawn_overrides")
.forGetter(Structure.StructureSettings::spawnOverrides),
GenerationStep.Decoration.CODEC.fieldOf("step").forGetter(Structure.StructureSettings::step),
TerrainAdjustment.CODEC.optionalFieldOf("terrain_adaptation", DEFAULT.terrainAdaptation).forGetter(Structure.StructureSettings::terrainAdaptation)
)
.apply(p_341910_, Structure.StructureSettings::new)
);
public StructureSettings(HolderSet<Biome> p_345322_) {
this(p_345322_, DEFAULT.spawnOverrides, DEFAULT.step, DEFAULT.terrainAdaptation);
}
public static class Builder {
private final HolderSet<Biome> biomes;
private Map<MobCategory, StructureSpawnOverride> spawnOverrides = Structure.StructureSettings.DEFAULT.spawnOverrides;
private GenerationStep.Decoration step = Structure.StructureSettings.DEFAULT.step;
private TerrainAdjustment terrainAdaption = Structure.StructureSettings.DEFAULT.terrainAdaptation;
public Builder(HolderSet<Biome> p_345430_) {
this.biomes = p_345430_;
}
public Structure.StructureSettings.Builder spawnOverrides(Map<MobCategory, StructureSpawnOverride> p_344031_) {
this.spawnOverrides = p_344031_;
return this;
}
public Structure.StructureSettings.Builder generationStep(GenerationStep.Decoration p_342290_) {
this.step = p_342290_;
return this;
}
public Structure.StructureSettings.Builder terrainAdapation(TerrainAdjustment p_344665_) {
this.terrainAdaption = p_344665_;
return this;
}
public Structure.StructureSettings build() {
return new Structure.StructureSettings(this.biomes, this.spawnOverrides, this.step, this.terrainAdaption);
}
}
}
}