Code/net/minecraft/world/level/biome/Biome.java

427 lines
17 KiB
Java

package net.minecraft.world.level.biome;
import com.google.common.collect.ImmutableList;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import com.mojang.serialization.codecs.RecordCodecBuilder.Instance;
import it.unimi.dsi.fastutil.longs.Long2FloatLinkedOpenHashMap;
import java.util.Optional;
import javax.annotation.Nullable;
import net.minecraft.Util;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderSet;
import net.minecraft.core.RegistryCodecs;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.RegistryFileCodec;
import net.minecraft.sounds.Music;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.util.Mth;
import net.minecraft.util.StringRepresentable;
import net.minecraft.util.random.WeightedList;
import net.minecraft.world.level.DryFoliageColor;
import net.minecraft.world.level.FoliageColor;
import net.minecraft.world.level.GrassColor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.LiquidBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.LegacyRandomSource;
import net.minecraft.world.level.levelgen.WorldgenRandom;
import net.minecraft.world.level.levelgen.synth.PerlinSimplexNoise;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.material.Fluids;
public final class Biome {
public static final Codec<Biome> DIRECT_CODEC = RecordCodecBuilder.create(
p_220544_ -> p_220544_.group(
Biome.ClimateSettings.CODEC.forGetter(p_151717_ -> p_151717_.climateSettings),
BiomeSpecialEffects.CODEC.fieldOf("effects").forGetter(p_220550_ -> p_220550_.specialEffects),
BiomeGenerationSettings.CODEC.forGetter(p_220548_ -> p_220548_.generationSettings),
MobSpawnSettings.CODEC.forGetter(p_220546_ -> p_220546_.mobSettings)
)
.apply(p_220544_, Biome::new)
);
public static final Codec<Biome> NETWORK_CODEC = RecordCodecBuilder.create(
p_220540_ -> p_220540_.group(
Biome.ClimateSettings.CODEC.forGetter(p_220542_ -> p_220542_.climateSettings),
BiomeSpecialEffects.CODEC.fieldOf("effects").forGetter(p_220538_ -> p_220538_.specialEffects)
)
.apply(p_220540_, (p_220535_, p_220536_) -> new Biome(p_220535_, p_220536_, BiomeGenerationSettings.EMPTY, MobSpawnSettings.EMPTY))
);
public static final Codec<Holder<Biome>> CODEC = RegistryFileCodec.create(Registries.BIOME, DIRECT_CODEC);
public static final Codec<HolderSet<Biome>> LIST_CODEC = RegistryCodecs.homogeneousList(Registries.BIOME, DIRECT_CODEC);
private static final PerlinSimplexNoise TEMPERATURE_NOISE = new PerlinSimplexNoise(new WorldgenRandom(new LegacyRandomSource(1234L)), ImmutableList.of(0));
static final PerlinSimplexNoise FROZEN_TEMPERATURE_NOISE = new PerlinSimplexNoise(new WorldgenRandom(new LegacyRandomSource(3456L)), ImmutableList.of(-2, -1, 0));
@Deprecated(
forRemoval = true
)
public static final PerlinSimplexNoise BIOME_INFO_NOISE = new PerlinSimplexNoise(new WorldgenRandom(new LegacyRandomSource(2345L)), ImmutableList.of(0));
private static final int TEMPERATURE_CACHE_SIZE = 1024;
private final Biome.ClimateSettings climateSettings;
private final BiomeGenerationSettings generationSettings;
private final MobSpawnSettings mobSettings;
private final BiomeSpecialEffects specialEffects;
private final ThreadLocal<Long2FloatLinkedOpenHashMap> temperatureCache = ThreadLocal.withInitial(() -> Util.make(() -> {
Long2FloatLinkedOpenHashMap long2floatlinkedopenhashmap = new Long2FloatLinkedOpenHashMap(1024, 0.25F) {
@Override
protected void rehash(int p_47580_) {
}
};
long2floatlinkedopenhashmap.defaultReturnValue(Float.NaN);
return long2floatlinkedopenhashmap;
}));
Biome(Biome.ClimateSettings p_220530_, BiomeSpecialEffects p_220531_, BiomeGenerationSettings p_220532_, MobSpawnSettings p_220533_) {
this.climateSettings = p_220530_;
this.generationSettings = p_220532_;
this.mobSettings = p_220533_;
this.specialEffects = p_220531_;
}
public int getSkyColor() {
return this.specialEffects.getSkyColor();
}
public MobSpawnSettings getMobSettings() {
return this.mobSettings;
}
public boolean hasPrecipitation() {
return this.climateSettings.hasPrecipitation();
}
public Biome.Precipitation getPrecipitationAt(BlockPos p_265163_, int p_366614_) {
if (!this.hasPrecipitation()) {
return Biome.Precipitation.NONE;
} else {
return this.coldEnoughToSnow(p_265163_, p_366614_) ? Biome.Precipitation.SNOW : Biome.Precipitation.RAIN;
}
}
private float getHeightAdjustedTemperature(BlockPos p_47529_, int p_368747_) {
float f = this.climateSettings.temperatureModifier.modifyTemperature(p_47529_, this.getBaseTemperature());
int i = p_368747_ + 17;
if (p_47529_.getY() > i) {
float f1 = (float)(TEMPERATURE_NOISE.getValue(p_47529_.getX() / 8.0F, p_47529_.getZ() / 8.0F, false) * 8.0);
return f - (f1 + p_47529_.getY() - i) * 0.05F / 40.0F;
} else {
return f;
}
}
@Deprecated
private float getTemperature(BlockPos p_47506_, int p_365043_) {
long i = p_47506_.asLong();
Long2FloatLinkedOpenHashMap long2floatlinkedopenhashmap = this.temperatureCache.get();
float f = long2floatlinkedopenhashmap.get(i);
if (!Float.isNaN(f)) {
return f;
} else {
float f1 = this.getHeightAdjustedTemperature(p_47506_, p_365043_);
if (long2floatlinkedopenhashmap.size() == 1024) {
long2floatlinkedopenhashmap.removeFirstFloat();
}
long2floatlinkedopenhashmap.put(i, f1);
return f1;
}
}
public boolean shouldFreeze(LevelReader p_47478_, BlockPos p_47479_) {
return this.shouldFreeze(p_47478_, p_47479_, true);
}
public boolean shouldFreeze(LevelReader p_47481_, BlockPos p_47482_, boolean p_47483_) {
if (this.warmEnoughToRain(p_47482_, p_47481_.getSeaLevel())) {
return false;
} else {
if (p_47481_.isInsideBuildHeight(p_47482_.getY()) && p_47481_.getBrightness(LightLayer.BLOCK, p_47482_) < 10) {
BlockState blockstate = p_47481_.getBlockState(p_47482_);
FluidState fluidstate = p_47481_.getFluidState(p_47482_);
if (fluidstate.getType() == Fluids.WATER && blockstate.getBlock() instanceof LiquidBlock) {
if (!p_47483_) {
return true;
}
boolean flag = p_47481_.isWaterAt(p_47482_.west())
&& p_47481_.isWaterAt(p_47482_.east())
&& p_47481_.isWaterAt(p_47482_.north())
&& p_47481_.isWaterAt(p_47482_.south());
if (!flag) {
return true;
}
}
}
return false;
}
}
public boolean coldEnoughToSnow(BlockPos p_198905_, int p_362496_) {
return !this.warmEnoughToRain(p_198905_, p_362496_);
}
public boolean warmEnoughToRain(BlockPos p_198907_, int p_362136_) {
return this.getTemperature(p_198907_, p_362136_) >= 0.15F;
}
public boolean shouldMeltFrozenOceanIcebergSlightly(BlockPos p_198909_, int p_365025_) {
return this.getTemperature(p_198909_, p_365025_) > 0.1F;
}
public boolean shouldSnow(LevelReader p_47520_, BlockPos p_47521_) {
if (this.warmEnoughToRain(p_47521_, p_47520_.getSeaLevel())) {
return false;
} else {
if (p_47520_.isInsideBuildHeight(p_47521_.getY()) && p_47520_.getBrightness(LightLayer.BLOCK, p_47521_) < 10) {
BlockState blockstate = p_47520_.getBlockState(p_47521_);
if ((blockstate.isAir() || blockstate.is(Blocks.SNOW)) && Blocks.SNOW.defaultBlockState().canSurvive(p_47520_, p_47521_)) {
return true;
}
}
return false;
}
}
public BiomeGenerationSettings getGenerationSettings() {
return this.generationSettings;
}
public int getFogColor() {
return this.specialEffects.getFogColor();
}
public int getGrassColor(double p_47465_, double p_47466_) {
int i = this.getBaseGrassColor();
return this.specialEffects.getGrassColorModifier().modifyColor(p_47465_, p_47466_, i);
}
private int getBaseGrassColor() {
Optional<Integer> optional = this.specialEffects.getGrassColorOverride();
return optional.isPresent() ? optional.get() : this.getGrassColorFromTexture();
}
private int getGrassColorFromTexture() {
double d0 = Mth.clamp(this.climateSettings.temperature, 0.0F, 1.0F);
double d1 = Mth.clamp(this.climateSettings.downfall, 0.0F, 1.0F);
return GrassColor.get(d0, d1);
}
public int getFoliageColor() {
return this.specialEffects.getFoliageColorOverride().orElseGet(this::getFoliageColorFromTexture);
}
private int getFoliageColorFromTexture() {
double d0 = Mth.clamp(this.climateSettings.temperature, 0.0F, 1.0F);
double d1 = Mth.clamp(this.climateSettings.downfall, 0.0F, 1.0F);
return FoliageColor.get(d0, d1);
}
public int getDryFoliageColor() {
return this.specialEffects.getDryFoliageColorOverride().orElseGet(this::getDryFoliageColorFromTexture);
}
private int getDryFoliageColorFromTexture() {
double d0 = Mth.clamp(this.climateSettings.temperature, 0.0F, 1.0F);
double d1 = Mth.clamp(this.climateSettings.downfall, 0.0F, 1.0F);
return DryFoliageColor.get(d0, d1);
}
public float getBaseTemperature() {
return this.climateSettings.temperature;
}
public BiomeSpecialEffects getSpecialEffects() {
return this.specialEffects;
}
public int getWaterColor() {
return this.specialEffects.getWaterColor();
}
public int getWaterFogColor() {
return this.specialEffects.getWaterFogColor();
}
public Optional<AmbientParticleSettings> getAmbientParticle() {
return this.specialEffects.getAmbientParticleSettings();
}
public Optional<Holder<SoundEvent>> getAmbientLoop() {
return this.specialEffects.getAmbientLoopSoundEvent();
}
public Optional<AmbientMoodSettings> getAmbientMood() {
return this.specialEffects.getAmbientMoodSettings();
}
public Optional<AmbientAdditionsSettings> getAmbientAdditions() {
return this.specialEffects.getAmbientAdditionsSettings();
}
public Optional<WeightedList<Music>> getBackgroundMusic() {
return this.specialEffects.getBackgroundMusic();
}
public float getBackgroundMusicVolume() {
return this.specialEffects.getBackgroundMusicVolume();
}
public static class BiomeBuilder {
private boolean hasPrecipitation = true;
@Nullable
private Float temperature;
private Biome.TemperatureModifier temperatureModifier = Biome.TemperatureModifier.NONE;
@Nullable
private Float downfall;
@Nullable
private BiomeSpecialEffects specialEffects;
@Nullable
private MobSpawnSettings mobSpawnSettings;
@Nullable
private BiomeGenerationSettings generationSettings;
public Biome.BiomeBuilder hasPrecipitation(boolean p_265480_) {
this.hasPrecipitation = p_265480_;
return this;
}
public Biome.BiomeBuilder temperature(float p_47610_) {
this.temperature = p_47610_;
return this;
}
public Biome.BiomeBuilder downfall(float p_47612_) {
this.downfall = p_47612_;
return this;
}
public Biome.BiomeBuilder specialEffects(BiomeSpecialEffects p_47604_) {
this.specialEffects = p_47604_;
return this;
}
public Biome.BiomeBuilder mobSpawnSettings(MobSpawnSettings p_47606_) {
this.mobSpawnSettings = p_47606_;
return this;
}
public Biome.BiomeBuilder generationSettings(BiomeGenerationSettings p_47602_) {
this.generationSettings = p_47602_;
return this;
}
public Biome.BiomeBuilder temperatureAdjustment(Biome.TemperatureModifier p_47600_) {
this.temperatureModifier = p_47600_;
return this;
}
public Biome build() {
if (this.temperature != null && this.downfall != null && this.specialEffects != null && this.mobSpawnSettings != null && this.generationSettings != null) {
return new Biome(
new Biome.ClimateSettings(this.hasPrecipitation, this.temperature, this.temperatureModifier, this.downfall), this.specialEffects, this.generationSettings, this.mobSpawnSettings
);
} else {
throw new IllegalStateException("You are missing parameters to build a proper biome\n" + this);
}
}
@Override
public String toString() {
return "BiomeBuilder{\nhasPrecipitation="
+ this.hasPrecipitation
+ ",\ntemperature="
+ this.temperature
+ ",\ntemperatureModifier="
+ this.temperatureModifier
+ ",\ndownfall="
+ this.downfall
+ ",\nspecialEffects="
+ this.specialEffects
+ ",\nmobSpawnSettings="
+ this.mobSpawnSettings
+ ",\ngenerationSettings="
+ this.generationSettings
+ ",\n}";
}
}
record ClimateSettings(boolean hasPrecipitation, float temperature, Biome.TemperatureModifier temperatureModifier, float downfall) {
public static final MapCodec<Biome.ClimateSettings> CODEC = RecordCodecBuilder.mapCodec(
p_264995_ -> p_264995_.group(
Codec.BOOL.fieldOf("has_precipitation").forGetter(p_264996_ -> p_264996_.hasPrecipitation),
Codec.FLOAT.fieldOf("temperature").forGetter(p_151737_ -> p_151737_.temperature),
Biome.TemperatureModifier.CODEC
.optionalFieldOf("temperature_modifier", Biome.TemperatureModifier.NONE)
.forGetter(p_151735_ -> p_151735_.temperatureModifier),
Codec.FLOAT.fieldOf("downfall").forGetter(p_151733_ -> p_151733_.downfall)
)
.apply(p_264995_, Biome.ClimateSettings::new)
);
}
public static enum Precipitation implements StringRepresentable {
NONE("none"),
RAIN("rain"),
SNOW("snow");
public static final Codec<Biome.Precipitation> CODEC = StringRepresentable.fromEnum(Biome.Precipitation::values);
private final String name;
private Precipitation(final String p_311702_) {
this.name = p_311702_;
}
@Override
public String getSerializedName() {
return this.name;
}
}
public static enum TemperatureModifier implements StringRepresentable {
NONE("none") {
@Override
public float modifyTemperature(BlockPos p_47767_, float p_47768_) {
return p_47768_;
}
},
FROZEN("frozen") {
@Override
public float modifyTemperature(BlockPos p_47774_, float p_47775_) {
double d0 = Biome.FROZEN_TEMPERATURE_NOISE.getValue(p_47774_.getX() * 0.05, p_47774_.getZ() * 0.05, false) * 7.0;
double d1 = Biome.BIOME_INFO_NOISE.getValue(p_47774_.getX() * 0.2, p_47774_.getZ() * 0.2, false);
double d2 = d0 + d1;
if (d2 < 0.3) {
double d3 = Biome.BIOME_INFO_NOISE.getValue(p_47774_.getX() * 0.09, p_47774_.getZ() * 0.09, false);
if (d3 < 0.8) {
return 0.2F;
}
}
return p_47775_;
}
};
private final String name;
public static final Codec<Biome.TemperatureModifier> CODEC = StringRepresentable.fromEnum(Biome.TemperatureModifier::values);
public abstract float modifyTemperature(BlockPos p_47754_, float p_47755_);
TemperatureModifier(final String p_47745_) {
this.name = p_47745_;
}
public String getName() {
return this.name;
}
@Override
public String getSerializedName() {
return this.name;
}
}
}