/* * Decompiled with CFR 0.152. * * Could not load the following classes: * com.google.common.annotations.VisibleForTesting * it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap * org.jspecify.annotations.Nullable */ package net.minecraft.world.attribute; import com.google.common.annotations.VisibleForTesting; import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap; import java.lang.runtime.SwitchBootstraps; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.function.LongSupplier; import java.util.stream.Stream; import net.minecraft.SharedConstants; import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; import net.minecraft.core.RegistryAccess; import net.minecraft.core.registries.Registries; import net.minecraft.world.attribute.EnvironmentAttribute; import net.minecraft.world.attribute.EnvironmentAttributeLayer; import net.minecraft.world.attribute.EnvironmentAttributeMap; import net.minecraft.world.attribute.EnvironmentAttributeReader; import net.minecraft.world.attribute.SpatialAttributeInterpolator; import net.minecraft.world.attribute.WeatherAttributes; import net.minecraft.world.level.Level; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.BiomeManager; import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.phys.Vec3; import net.minecraft.world.timeline.Timeline; import org.jspecify.annotations.Nullable; public class EnvironmentAttributeSystem implements EnvironmentAttributeReader { private final Map, ValueSampler> attributeSamplers = new Reference2ObjectOpenHashMap(); private EnvironmentAttributeSystem(Map, List>> layersByAttribute) { layersByAttribute.forEach((attribute, layers) -> this.attributeSamplers.put((EnvironmentAttribute)attribute, this.bakeLayerSampler((EnvironmentAttribute)attribute, (List>)layers))); } private ValueSampler bakeLayerSampler(EnvironmentAttribute attribute, List> untypedLayers) { Object e; ArrayList layers = new ArrayList(untypedLayers); Value constantBaseValue = attribute.defaultValue(); while (!layers.isEmpty() && (e = layers.getFirst()) instanceof EnvironmentAttributeLayer.Constant) { EnvironmentAttributeLayer.Constant constantLayer = (EnvironmentAttributeLayer.Constant)e; constantBaseValue = constantLayer.applyConstant(constantBaseValue); layers.removeFirst(); } boolean isAffectedByPosition = layers.stream().anyMatch(layer -> layer instanceof EnvironmentAttributeLayer.Positional); return new ValueSampler(attribute, constantBaseValue, List.copyOf(layers), isAffectedByPosition); } public static Builder builder() { return new Builder(); } private static void addDefaultLayers(Builder builder, Level level) { RegistryAccess registries = level.registryAccess(); BiomeManager biomeManager = level.getBiomeManager(); LongSupplier dayTimeGetter = level::getDayTime; EnvironmentAttributeSystem.addDimensionLayer(builder, level.dimensionType()); EnvironmentAttributeSystem.addBiomeLayer(builder, registries.lookupOrThrow(Registries.BIOME), biomeManager); level.dimensionType().timelines().forEach(timeline -> builder.addTimelineLayer((Holder)timeline, dayTimeGetter)); if (level.canHaveWeather()) { WeatherAttributes.addBuiltinLayers(builder, WeatherAttributes.WeatherAccess.from(level)); } } private static void addDimensionLayer(Builder builder, DimensionType dimensionType) { builder.addConstantLayer(dimensionType.attributes()); } private static void addBiomeLayer(Builder builder, HolderLookup biomes, BiomeManager biomeManager) { Stream attributesProvidedByBiomes = biomes.listElements().flatMap(biome -> ((Biome)biome.value()).getAttributes().keySet().stream()).distinct(); attributesProvidedByBiomes.forEach(attribute -> EnvironmentAttributeSystem.addBiomeLayerForAttribute(builder, attribute, biomeManager)); } private static void addBiomeLayerForAttribute(Builder builder, EnvironmentAttribute attribute, BiomeManager biomeManager) { builder.addPositionalLayer(attribute, (baseValue, pos, biomeWeights) -> { if (biomeWeights != null && attribute.isSpatiallyInterpolated()) { return biomeWeights.applyAttributeLayer(attribute, baseValue); } Holder biome = biomeManager.getNoiseBiomeAtPosition(pos.x, pos.y, pos.z); return biome.value().getAttributes().applyModifier(attribute, baseValue); }); } public void invalidateTickCache() { this.attributeSamplers.values().forEach(ValueSampler::invalidateTickCache); } private @Nullable ValueSampler getValueSampler(EnvironmentAttribute attribute) { return this.attributeSamplers.get(attribute); } @Override public Value getDimensionValue(EnvironmentAttribute attribute) { if (SharedConstants.IS_RUNNING_IN_IDE && attribute.isPositional()) { throw new IllegalStateException("Position must always be provided for positional attribute " + String.valueOf(attribute)); } ValueSampler sampler = this.getValueSampler(attribute); if (sampler == null) { return attribute.defaultValue(); } return sampler.getDimensionValue(); } @Override public Value getValue(EnvironmentAttribute attribute, Vec3 pos, @Nullable SpatialAttributeInterpolator biomeInterpolator) { ValueSampler sampler = this.getValueSampler(attribute); if (sampler == null) { return attribute.defaultValue(); } return sampler.getValue(pos, biomeInterpolator); } @VisibleForTesting Value getConstantBaseValue(EnvironmentAttribute attribute) { ValueSampler sampler = this.getValueSampler(attribute); return sampler != null ? sampler.baseValue : attribute.defaultValue(); } @VisibleForTesting boolean isAffectedByPosition(EnvironmentAttribute attribute) { ValueSampler sampler = this.getValueSampler(attribute); return sampler != null && sampler.isAffectedByPosition; } private static class ValueSampler { private final EnvironmentAttribute attribute; private final Value baseValue; private final List> layers; private final boolean isAffectedByPosition; private @Nullable Value cachedTickValue; private int cacheTickId; private ValueSampler(EnvironmentAttribute attribute, Value baseValue, List> layers, boolean isAffectedByPosition) { this.attribute = attribute; this.baseValue = baseValue; this.layers = layers; this.isAffectedByPosition = isAffectedByPosition; } public void invalidateTickCache() { this.cachedTickValue = null; ++this.cacheTickId; } public Value getDimensionValue() { if (this.cachedTickValue != null) { return this.cachedTickValue; } Value result = this.computeValueNotPositional(); this.cachedTickValue = result; return result; } public Value getValue(Vec3 pos, @Nullable SpatialAttributeInterpolator biomeInterpolator) { if (!this.isAffectedByPosition) { return this.getDimensionValue(); } return this.computeValuePositional(pos, biomeInterpolator); } private Value computeValuePositional(Vec3 pos, @Nullable SpatialAttributeInterpolator biomeInterpolator) { Value result = this.baseValue; for (EnvironmentAttributeLayer layer : this.layers) { EnvironmentAttributeLayer environmentAttributeLayer; Objects.requireNonNull(layer); int n = 0; result = switch (SwitchBootstraps.typeSwitch("typeSwitch", new Object[]{EnvironmentAttributeLayer.Constant.class, EnvironmentAttributeLayer.TimeBased.class, EnvironmentAttributeLayer.Positional.class}, environmentAttributeLayer, n)) { default -> throw new MatchException(null, null); case 0 -> { EnvironmentAttributeLayer.Constant constantLayer = (EnvironmentAttributeLayer.Constant)environmentAttributeLayer; yield constantLayer.applyConstant(result); } case 1 -> { EnvironmentAttributeLayer.TimeBased timeBasedLayer = (EnvironmentAttributeLayer.TimeBased)environmentAttributeLayer; yield timeBasedLayer.applyTimeBased(result, this.cacheTickId); } case 2 -> { EnvironmentAttributeLayer.Positional positionalLayer = (EnvironmentAttributeLayer.Positional)environmentAttributeLayer; yield positionalLayer.applyPositional(result, Objects.requireNonNull(pos), biomeInterpolator); } }; } return this.attribute.sanitizeValue(result); } private Value computeValueNotPositional() { Value result = this.baseValue; for (EnvironmentAttributeLayer layer : this.layers) { EnvironmentAttributeLayer environmentAttributeLayer; Objects.requireNonNull(layer); int n = 0; result = switch (SwitchBootstraps.typeSwitch("typeSwitch", new Object[]{EnvironmentAttributeLayer.Constant.class, EnvironmentAttributeLayer.TimeBased.class, EnvironmentAttributeLayer.Positional.class}, environmentAttributeLayer, n)) { default -> throw new MatchException(null, null); case 0 -> { EnvironmentAttributeLayer.Constant constantLayer = (EnvironmentAttributeLayer.Constant)environmentAttributeLayer; yield constantLayer.applyConstant(result); } case 1 -> { EnvironmentAttributeLayer.TimeBased timeBasedLayer = (EnvironmentAttributeLayer.TimeBased)environmentAttributeLayer; yield timeBasedLayer.applyTimeBased(result, this.cacheTickId); } case 2 -> { EnvironmentAttributeLayer.Positional ignored = (EnvironmentAttributeLayer.Positional)environmentAttributeLayer; yield result; } }; } return this.attribute.sanitizeValue(result); } } public static class Builder { private final Map, List>> layersByAttribute = new HashMap(); private Builder() { } public Builder addDefaultLayers(Level level) { EnvironmentAttributeSystem.addDefaultLayers(this, level); return this; } public Builder addConstantLayer(EnvironmentAttributeMap attributeMap) { for (EnvironmentAttribute attribute : attributeMap.keySet()) { this.addConstantEntry(attribute, attributeMap); } return this; } private Builder addConstantEntry(EnvironmentAttribute attribute, EnvironmentAttributeMap attributeMap) { EnvironmentAttributeMap.Entry entry = attributeMap.get(attribute); if (entry == null) { throw new IllegalArgumentException("Missing attribute " + String.valueOf(attribute)); } return this.addConstantLayer(attribute, entry::applyModifier); } public Builder addConstantLayer(EnvironmentAttribute attribute, EnvironmentAttributeLayer.Constant layer) { return this.addLayer(attribute, layer); } public Builder addTimeBasedLayer(EnvironmentAttribute attribute, EnvironmentAttributeLayer.TimeBased layer) { return this.addLayer(attribute, layer); } public Builder addPositionalLayer(EnvironmentAttribute attribute, EnvironmentAttributeLayer.Positional layer) { return this.addLayer(attribute, layer); } private Builder addLayer(EnvironmentAttribute attribute, EnvironmentAttributeLayer layer) { this.layersByAttribute.computeIfAbsent(attribute, t -> new ArrayList()).add(layer); return this; } public Builder addTimelineLayer(Holder timeline, LongSupplier dayTimeGetter) { for (EnvironmentAttribute attribute : timeline.value().attributes()) { this.addTimelineLayerForAttribute(timeline, attribute, dayTimeGetter); } return this; } private void addTimelineLayerForAttribute(Holder timeline, EnvironmentAttribute attribute, LongSupplier dayTimeGetter) { this.addTimeBasedLayer(attribute, timeline.value().createTrackSampler(attribute, dayTimeGetter)); } public EnvironmentAttributeSystem build() { return new EnvironmentAttributeSystem(this.layersByAttribute); } } }