/* * Decompiled with CFR 0.152. * * Could not load the following classes: * com.google.common.collect.ImmutableList * com.mojang.datafixers.kinds.App * com.mojang.datafixers.kinds.Applicative * com.mojang.serialization.Codec * com.mojang.serialization.MapCodec * com.mojang.serialization.codecs.RecordCodecBuilder * it.unimi.dsi.fastutil.longs.Long2FloatLinkedOpenHashMap * org.jspecify.annotations.Nullable */ package net.minecraft.world.level.biome; import com.google.common.collect.ImmutableList; import com.mojang.datafixers.kinds.App; import com.mojang.datafixers.kinds.Applicative; import com.mojang.serialization.Codec; import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import it.unimi.dsi.fastutil.longs.Long2FloatLinkedOpenHashMap; import java.util.List; import java.util.Optional; 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.util.Mth; import net.minecraft.util.RandomSource; import net.minecraft.util.StringRepresentable; import net.minecraft.world.attribute.EnvironmentAttribute; import net.minecraft.world.attribute.EnvironmentAttributeMap; import net.minecraft.world.attribute.modifier.AttributeModifier; 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.biome.BiomeGenerationSettings; import net.minecraft.world.level.biome.BiomeSpecialEffects; import net.minecraft.world.level.biome.MobSpawnSettings; 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; import org.jspecify.annotations.Nullable; public final class Biome { public static final Codec DIRECT_CODEC = RecordCodecBuilder.create(i -> i.group((App)ClimateSettings.CODEC.forGetter(b -> b.climateSettings), (App)EnvironmentAttributeMap.CODEC_ONLY_POSITIONAL.optionalFieldOf("attributes", (Object)EnvironmentAttributeMap.EMPTY).forGetter(b -> b.attributes), (App)BiomeSpecialEffects.CODEC.fieldOf("effects").forGetter(b -> b.specialEffects), (App)BiomeGenerationSettings.CODEC.forGetter(b -> b.generationSettings), (App)MobSpawnSettings.CODEC.forGetter(b -> b.mobSettings)).apply((Applicative)i, Biome::new)); public static final Codec NETWORK_CODEC = RecordCodecBuilder.create(i -> i.group((App)ClimateSettings.CODEC.forGetter(b -> b.climateSettings), (App)EnvironmentAttributeMap.NETWORK_CODEC.optionalFieldOf("attributes", (Object)EnvironmentAttributeMap.EMPTY).forGetter(b -> b.attributes), (App)BiomeSpecialEffects.CODEC.fieldOf("effects").forGetter(b -> b.specialEffects)).apply((Applicative)i, (climateSettings, attributes, specialEffects) -> new Biome((ClimateSettings)climateSettings, (EnvironmentAttributeMap)attributes, (BiomeSpecialEffects)specialEffects, BiomeGenerationSettings.EMPTY, MobSpawnSettings.EMPTY))); public static final Codec> CODEC = RegistryFileCodec.create(Registries.BIOME, DIRECT_CODEC); public static final Codec> LIST_CODEC = RegistryCodecs.homogeneousList(Registries.BIOME, DIRECT_CODEC); private static final PerlinSimplexNoise TEMPERATURE_NOISE = new PerlinSimplexNoise((RandomSource)new WorldgenRandom(new LegacyRandomSource(1234L)), (List)ImmutableList.of((Object)0)); private static final PerlinSimplexNoise FROZEN_TEMPERATURE_NOISE = new PerlinSimplexNoise((RandomSource)new WorldgenRandom(new LegacyRandomSource(3456L)), (List)ImmutableList.of((Object)-2, (Object)-1, (Object)0)); @Deprecated(forRemoval=true) public static final PerlinSimplexNoise BIOME_INFO_NOISE = new PerlinSimplexNoise((RandomSource)new WorldgenRandom(new LegacyRandomSource(2345L)), (List)ImmutableList.of((Object)0)); private static final int TEMPERATURE_CACHE_SIZE = 1024; private final ClimateSettings climateSettings; private final BiomeGenerationSettings generationSettings; private final MobSpawnSettings mobSettings; private final EnvironmentAttributeMap attributes; private final BiomeSpecialEffects specialEffects; private final ThreadLocal temperatureCache = ThreadLocal.withInitial(() -> { Long2FloatLinkedOpenHashMap map = new Long2FloatLinkedOpenHashMap(1024, 0.25f){ protected void rehash(int newN) { } }; map.defaultReturnValue(Float.NaN); return map; }); private Biome(ClimateSettings climateSettings, EnvironmentAttributeMap attributes, BiomeSpecialEffects specialEffects, BiomeGenerationSettings generationSettings, MobSpawnSettings mobSettings) { this.climateSettings = climateSettings; this.generationSettings = generationSettings; this.mobSettings = mobSettings; this.attributes = attributes; this.specialEffects = specialEffects; } public MobSpawnSettings getMobSettings() { return this.mobSettings; } public boolean hasPrecipitation() { return this.climateSettings.hasPrecipitation(); } public Precipitation getPrecipitationAt(BlockPos pos, int seaLevel) { if (!this.hasPrecipitation()) { return Precipitation.NONE; } return this.coldEnoughToSnow(pos, seaLevel) ? Precipitation.SNOW : Precipitation.RAIN; } private float getHeightAdjustedTemperature(BlockPos pos, int seaLevel) { float adjustedTemperature = this.climateSettings.temperatureModifier.modifyTemperature(pos, this.getBaseTemperature()); int snowLevel = seaLevel + 17; if (pos.getY() > snowLevel) { float v = (float)(TEMPERATURE_NOISE.getValue((float)pos.getX() / 8.0f, (float)pos.getZ() / 8.0f, false) * 8.0); return adjustedTemperature - (v + (float)pos.getY() - (float)snowLevel) * 0.05f / 40.0f; } return adjustedTemperature; } @Deprecated private float getTemperature(BlockPos pos, int seaLevel) { long key = pos.asLong(); Long2FloatLinkedOpenHashMap cache = this.temperatureCache.get(); float cached = cache.get(key); if (!Float.isNaN(cached)) { return cached; } float temp = this.getHeightAdjustedTemperature(pos, seaLevel); if (cache.size() == 1024) { cache.removeFirstFloat(); } cache.put(key, temp); return temp; } public boolean shouldFreeze(LevelReader level, BlockPos pos) { return this.shouldFreeze(level, pos, true); } public boolean shouldFreeze(LevelReader level, BlockPos pos, boolean checkNeighbors) { if (this.warmEnoughToRain(pos, level.getSeaLevel())) { return false; } if (level.isInsideBuildHeight(pos.getY()) && level.getBrightness(LightLayer.BLOCK, pos) < 10) { BlockState blockState = level.getBlockState(pos); FluidState fluidState = level.getFluidState(pos); if (fluidState.getType() == Fluids.WATER && blockState.getBlock() instanceof LiquidBlock) { boolean surroundedByWater; if (!checkNeighbors) { return true; } boolean bl = surroundedByWater = level.isWaterAt(pos.west()) && level.isWaterAt(pos.east()) && level.isWaterAt(pos.north()) && level.isWaterAt(pos.south()); if (!surroundedByWater) { return true; } } } return false; } public boolean coldEnoughToSnow(BlockPos pos, int seaLevel) { return !this.warmEnoughToRain(pos, seaLevel); } public boolean warmEnoughToRain(BlockPos pos, int seaLevel) { return this.getTemperature(pos, seaLevel) >= 0.15f; } public boolean shouldMeltFrozenOceanIcebergSlightly(BlockPos pos, int seaLevel) { return this.getTemperature(pos, seaLevel) > 0.1f; } public boolean shouldSnow(LevelReader level, BlockPos pos) { BlockState state; if (this.getPrecipitationAt(pos, level.getSeaLevel()) != Precipitation.SNOW) { return false; } return level.isInsideBuildHeight(pos.getY()) && level.getBrightness(LightLayer.BLOCK, pos) < 10 && ((state = level.getBlockState(pos)).isAir() || state.is(Blocks.SNOW)) && Blocks.SNOW.defaultBlockState().canSurvive(level, pos); } public BiomeGenerationSettings getGenerationSettings() { return this.generationSettings; } public int getGrassColor(double x, double z) { int baseGrassColor = this.getBaseGrassColor(); return this.specialEffects.grassColorModifier().modifyColor(x, z, baseGrassColor); } private int getBaseGrassColor() { Optional colorOverride = this.specialEffects.grassColorOverride(); if (colorOverride.isPresent()) { return colorOverride.get(); } return this.getGrassColorFromTexture(); } private int getGrassColorFromTexture() { double temp = Mth.clamp(this.climateSettings.temperature, 0.0f, 1.0f); double rain = Mth.clamp(this.climateSettings.downfall, 0.0f, 1.0f); return GrassColor.get(temp, rain); } public int getFoliageColor() { return this.specialEffects.foliageColorOverride().orElseGet(this::getFoliageColorFromTexture); } private int getFoliageColorFromTexture() { double temp = Mth.clamp(this.climateSettings.temperature, 0.0f, 1.0f); double rain = Mth.clamp(this.climateSettings.downfall, 0.0f, 1.0f); return FoliageColor.get(temp, rain); } public int getDryFoliageColor() { return this.specialEffects.dryFoliageColorOverride().orElseGet(this::getDryFoliageColorFromTexture); } private int getDryFoliageColorFromTexture() { double temp = Mth.clamp(this.climateSettings.temperature, 0.0f, 1.0f); double rain = Mth.clamp(this.climateSettings.downfall, 0.0f, 1.0f); return DryFoliageColor.get(temp, rain); } public float getBaseTemperature() { return this.climateSettings.temperature; } public EnvironmentAttributeMap getAttributes() { return this.attributes; } public BiomeSpecialEffects getSpecialEffects() { return this.specialEffects; } public int getWaterColor() { return this.specialEffects.waterColor(); } private record ClimateSettings(boolean hasPrecipitation, float temperature, TemperatureModifier temperatureModifier, float downfall) { public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(i -> i.group((App)Codec.BOOL.fieldOf("has_precipitation").forGetter(b -> b.hasPrecipitation), (App)Codec.FLOAT.fieldOf("temperature").forGetter(b -> Float.valueOf(b.temperature)), (App)TemperatureModifier.CODEC.optionalFieldOf("temperature_modifier", (Object)TemperatureModifier.NONE).forGetter(b -> b.temperatureModifier), (App)Codec.FLOAT.fieldOf("downfall").forGetter(b -> Float.valueOf(b.downfall))).apply((Applicative)i, ClimateSettings::new)); } public static enum Precipitation implements StringRepresentable { NONE("none"), RAIN("rain"), SNOW("snow"); public static final Codec CODEC; private final String name; private Precipitation(String name) { this.name = name; } @Override public String getSerializedName() { return this.name; } static { CODEC = StringRepresentable.fromEnum(Precipitation::values); } } public static enum TemperatureModifier implements StringRepresentable { NONE("none"){ @Override public float modifyTemperature(BlockPos pos, float baseTemperature) { return baseTemperature; } } , FROZEN("frozen"){ @Override public float modifyTemperature(BlockPos pos, float baseTemperature) { double groundValueSmallVariation; double groundValueEdgeVariation; double groundValueLargeVariation = FROZEN_TEMPERATURE_NOISE.getValue((double)pos.getX() * 0.05, (double)pos.getZ() * 0.05, false) * 7.0; double icePatches = groundValueLargeVariation + (groundValueEdgeVariation = BIOME_INFO_NOISE.getValue((double)pos.getX() * 0.2, (double)pos.getZ() * 0.2, false)); if (icePatches < 0.3 && (groundValueSmallVariation = BIOME_INFO_NOISE.getValue((double)pos.getX() * 0.09, (double)pos.getZ() * 0.09, false)) < 0.8) { return 0.2f; } return baseTemperature; } }; private final String name; public static final Codec CODEC; public abstract float modifyTemperature(BlockPos var1, float var2); private TemperatureModifier(String name) { this.name = name; } public String getName() { return this.name; } @Override public String getSerializedName() { return this.name; } static { CODEC = StringRepresentable.fromEnum(TemperatureModifier::values); } } public static class BiomeBuilder { private boolean hasPrecipitation = true; private @Nullable Float temperature; private TemperatureModifier temperatureModifier = TemperatureModifier.NONE; private @Nullable Float downfall; private final EnvironmentAttributeMap.Builder attributes = EnvironmentAttributeMap.builder(); private @Nullable BiomeSpecialEffects specialEffects; private @Nullable MobSpawnSettings mobSpawnSettings; private @Nullable BiomeGenerationSettings generationSettings; public BiomeBuilder hasPrecipitation(boolean hasPrecipitation) { this.hasPrecipitation = hasPrecipitation; return this; } public BiomeBuilder temperature(float temperature) { this.temperature = Float.valueOf(temperature); return this; } public BiomeBuilder downfall(float downfall) { this.downfall = Float.valueOf(downfall); return this; } public BiomeBuilder putAttributes(EnvironmentAttributeMap attributes) { this.attributes.putAll(attributes); return this; } public BiomeBuilder putAttributes(EnvironmentAttributeMap.Builder attributes) { return this.putAttributes(attributes.build()); } public BiomeBuilder setAttribute(EnvironmentAttribute attribute, Value value) { this.attributes.set(attribute, value); return this; } public BiomeBuilder modifyAttribute(EnvironmentAttribute attribute, AttributeModifier modifier, Parameter value) { this.attributes.modify(attribute, modifier, value); return this; } public BiomeBuilder specialEffects(BiomeSpecialEffects specialEffects) { this.specialEffects = specialEffects; return this; } public BiomeBuilder mobSpawnSettings(MobSpawnSettings mobSpawnSettings) { this.mobSpawnSettings = mobSpawnSettings; return this; } public BiomeBuilder generationSettings(BiomeGenerationSettings generationSettings) { this.generationSettings = generationSettings; return this; } public BiomeBuilder temperatureAdjustment(TemperatureModifier temperatureModifier) { this.temperatureModifier = temperatureModifier; return this; } public Biome build() { if (this.temperature == null || this.downfall == null || this.specialEffects == null || this.mobSpawnSettings == null || this.generationSettings == null) { throw new IllegalStateException("You are missing parameters to build a proper biome\n" + String.valueOf(this)); } return new Biome(new ClimateSettings(this.hasPrecipitation, this.temperature.floatValue(), this.temperatureModifier, this.downfall.floatValue()), this.attributes.build(), this.specialEffects, this.generationSettings, this.mobSpawnSettings); } public String toString() { return "BiomeBuilder{\nhasPrecipitation=" + this.hasPrecipitation + ",\ntemperature=" + this.temperature + ",\ntemperatureModifier=" + String.valueOf(this.temperatureModifier) + ",\ndownfall=" + this.downfall + ",\nspecialEffects=" + String.valueOf(this.specialEffects) + ",\nmobSpawnSettings=" + String.valueOf(this.mobSpawnSettings) + ",\ngenerationSettings=" + String.valueOf(this.generationSettings) + ",\n}"; } } }