minecraft-src/net/minecraft/world/level/levelgen/SurfaceRules.java
2025-07-04 02:49:36 +03:00

708 lines
27 KiB
Java

package net.minecraft.world.level.levelgen;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.KeyDispatchDataCodec;
import net.minecraft.util.Mth;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.levelgen.SurfaceRules.BiomeConditionSource.1BiomeCondition;
import net.minecraft.world.level.levelgen.SurfaceRules.Context.AbovePreliminarySurfaceCondition;
import net.minecraft.world.level.levelgen.SurfaceRules.Context.HoleCondition;
import net.minecraft.world.level.levelgen.SurfaceRules.Context.SteepMaterialCondition;
import net.minecraft.world.level.levelgen.SurfaceRules.Context.TemperatureHelperCondition;
import net.minecraft.world.level.levelgen.SurfaceRules.NoiseThresholdConditionSource.1NoiseThresholdCondition;
import net.minecraft.world.level.levelgen.SurfaceRules.StoneDepthCheck.1StoneDepthCondition;
import net.minecraft.world.level.levelgen.SurfaceRules.VerticalGradientConditionSource.1VerticalGradientCondition;
import net.minecraft.world.level.levelgen.SurfaceRules.WaterConditionSource.1WaterCondition;
import net.minecraft.world.level.levelgen.SurfaceRules.YConditionSource.1YCondition;
import net.minecraft.world.level.levelgen.placement.CaveSurface;
import net.minecraft.world.level.levelgen.synth.NormalNoise;
import net.minecraft.world.level.levelgen.synth.NormalNoise.NoiseParameters;
import org.jetbrains.annotations.Nullable;
public class SurfaceRules {
public static final SurfaceRules.ConditionSource ON_FLOOR = stoneDepthCheck(0, false, CaveSurface.FLOOR);
public static final SurfaceRules.ConditionSource UNDER_FLOOR = stoneDepthCheck(0, true, CaveSurface.FLOOR);
public static final SurfaceRules.ConditionSource DEEP_UNDER_FLOOR = stoneDepthCheck(0, true, 6, CaveSurface.FLOOR);
public static final SurfaceRules.ConditionSource VERY_DEEP_UNDER_FLOOR = stoneDepthCheck(0, true, 30, CaveSurface.FLOOR);
public static final SurfaceRules.ConditionSource ON_CEILING = stoneDepthCheck(0, false, CaveSurface.CEILING);
public static final SurfaceRules.ConditionSource UNDER_CEILING = stoneDepthCheck(0, true, CaveSurface.CEILING);
public static SurfaceRules.ConditionSource stoneDepthCheck(int offset, boolean addSurfaceDepth, CaveSurface surfaceType) {
return new SurfaceRules.StoneDepthCheck(offset, addSurfaceDepth, 0, surfaceType);
}
public static SurfaceRules.ConditionSource stoneDepthCheck(int offset, boolean addSurfaceDepth, int secondaryDepthRange, CaveSurface surfaceType) {
return new SurfaceRules.StoneDepthCheck(offset, addSurfaceDepth, secondaryDepthRange, surfaceType);
}
public static SurfaceRules.ConditionSource not(SurfaceRules.ConditionSource target) {
return new SurfaceRules.NotConditionSource(target);
}
public static SurfaceRules.ConditionSource yBlockCheck(VerticalAnchor anchor, int surfaceDepthMultiplier) {
return new SurfaceRules.YConditionSource(anchor, surfaceDepthMultiplier, false);
}
public static SurfaceRules.ConditionSource yStartCheck(VerticalAnchor anchor, int surfaceDepthMultiplier) {
return new SurfaceRules.YConditionSource(anchor, surfaceDepthMultiplier, true);
}
public static SurfaceRules.ConditionSource waterBlockCheck(int offset, int surfaceDepthMultiplier) {
return new SurfaceRules.WaterConditionSource(offset, surfaceDepthMultiplier, false);
}
public static SurfaceRules.ConditionSource waterStartCheck(int offset, int surfaceDepthMultiplier) {
return new SurfaceRules.WaterConditionSource(offset, surfaceDepthMultiplier, true);
}
@SafeVarargs
public static SurfaceRules.ConditionSource isBiome(ResourceKey<Biome>... biomes) {
return isBiome(List.of(biomes));
}
private static SurfaceRules.BiomeConditionSource isBiome(List<ResourceKey<Biome>> biomes) {
return new SurfaceRules.BiomeConditionSource(biomes);
}
public static SurfaceRules.ConditionSource noiseCondition(ResourceKey<NoiseParameters> noise, double minThreshold) {
return noiseCondition(noise, minThreshold, Double.MAX_VALUE);
}
public static SurfaceRules.ConditionSource noiseCondition(ResourceKey<NoiseParameters> noise, double minThreshold, double maxThreshold) {
return new SurfaceRules.NoiseThresholdConditionSource(noise, minThreshold, maxThreshold);
}
public static SurfaceRules.ConditionSource verticalGradient(String randomName, VerticalAnchor trueAtAndBelow, VerticalAnchor falseAtAndAbove) {
return new SurfaceRules.VerticalGradientConditionSource(ResourceLocation.parse(randomName), trueAtAndBelow, falseAtAndAbove);
}
public static SurfaceRules.ConditionSource steep() {
return SurfaceRules.Steep.INSTANCE;
}
public static SurfaceRules.ConditionSource hole() {
return SurfaceRules.Hole.INSTANCE;
}
public static SurfaceRules.ConditionSource abovePreliminarySurface() {
return SurfaceRules.AbovePreliminarySurface.INSTANCE;
}
public static SurfaceRules.ConditionSource temperature() {
return SurfaceRules.Temperature.INSTANCE;
}
public static SurfaceRules.RuleSource ifTrue(SurfaceRules.ConditionSource ifTrue, SurfaceRules.RuleSource thenRun) {
return new SurfaceRules.TestRuleSource(ifTrue, thenRun);
}
public static SurfaceRules.RuleSource sequence(SurfaceRules.RuleSource... rules) {
if (rules.length == 0) {
throw new IllegalArgumentException("Need at least 1 rule for a sequence");
} else {
return new SurfaceRules.SequenceRuleSource(Arrays.asList(rules));
}
}
public static SurfaceRules.RuleSource state(BlockState resultState) {
return new SurfaceRules.BlockRuleSource(resultState);
}
public static SurfaceRules.RuleSource bandlands() {
return SurfaceRules.Bandlands.INSTANCE;
}
static <A> MapCodec<? extends A> register(Registry<MapCodec<? extends A>> registry, String name, KeyDispatchDataCodec<? extends A> codec) {
return Registry.register(registry, name, codec.codec());
}
static enum AbovePreliminarySurface implements SurfaceRules.ConditionSource {
INSTANCE;
static final KeyDispatchDataCodec<SurfaceRules.AbovePreliminarySurface> CODEC = KeyDispatchDataCodec.of(MapCodec.unit(INSTANCE));
@Override
public KeyDispatchDataCodec<? extends SurfaceRules.ConditionSource> codec() {
return CODEC;
}
public SurfaceRules.Condition apply(SurfaceRules.Context context) {
return context.abovePreliminarySurface;
}
}
static enum Bandlands implements SurfaceRules.RuleSource {
INSTANCE;
static final KeyDispatchDataCodec<SurfaceRules.Bandlands> CODEC = KeyDispatchDataCodec.of(MapCodec.unit(INSTANCE));
@Override
public KeyDispatchDataCodec<? extends SurfaceRules.RuleSource> codec() {
return CODEC;
}
public SurfaceRules.SurfaceRule apply(SurfaceRules.Context context) {
return context.system::getBand;
}
}
static final class BiomeConditionSource implements SurfaceRules.ConditionSource {
static final KeyDispatchDataCodec<SurfaceRules.BiomeConditionSource> CODEC = KeyDispatchDataCodec.of(
ResourceKey.codec(Registries.BIOME).listOf().fieldOf("biome_is").xmap(SurfaceRules::isBiome, biomeConditionSource -> biomeConditionSource.biomes)
);
private final List<ResourceKey<Biome>> biomes;
final Predicate<ResourceKey<Biome>> biomeNameTest;
BiomeConditionSource(List<ResourceKey<Biome>> biomes) {
this.biomes = biomes;
this.biomeNameTest = Set.copyOf(biomes)::contains;
}
@Override
public KeyDispatchDataCodec<? extends SurfaceRules.ConditionSource> codec() {
return CODEC;
}
public SurfaceRules.Condition apply(SurfaceRules.Context context) {
return new 1BiomeCondition(this, context);
}
public boolean equals(Object object) {
if (this == object) {
return true;
} else {
return object instanceof SurfaceRules.BiomeConditionSource biomeConditionSource ? this.biomes.equals(biomeConditionSource.biomes) : false;
}
}
public int hashCode() {
return this.biomes.hashCode();
}
public String toString() {
return "BiomeConditionSource[biomes=" + this.biomes + "]";
}
}
record BlockRuleSource(BlockState resultState, SurfaceRules.StateRule rule) implements SurfaceRules.RuleSource {
static final KeyDispatchDataCodec<SurfaceRules.BlockRuleSource> CODEC = KeyDispatchDataCodec.of(
BlockState.CODEC.<SurfaceRules.BlockRuleSource>xmap(SurfaceRules.BlockRuleSource::new, SurfaceRules.BlockRuleSource::resultState).fieldOf("result_state")
);
BlockRuleSource(BlockState resultState) {
this(resultState, new SurfaceRules.StateRule(resultState));
}
@Override
public KeyDispatchDataCodec<? extends SurfaceRules.RuleSource> codec() {
return CODEC;
}
public SurfaceRules.SurfaceRule apply(SurfaceRules.Context context) {
return this.rule;
}
}
interface Condition {
boolean test();
}
public interface ConditionSource extends Function<SurfaceRules.Context, SurfaceRules.Condition> {
Codec<SurfaceRules.ConditionSource> CODEC = BuiltInRegistries.MATERIAL_CONDITION
.byNameCodec()
.dispatch(conditionSource -> conditionSource.codec().codec(), Function.identity());
static MapCodec<? extends SurfaceRules.ConditionSource> bootstrap(Registry<MapCodec<? extends SurfaceRules.ConditionSource>> registry) {
SurfaceRules.register(registry, "biome", SurfaceRules.BiomeConditionSource.CODEC);
SurfaceRules.register(registry, "noise_threshold", SurfaceRules.NoiseThresholdConditionSource.CODEC);
SurfaceRules.register(registry, "vertical_gradient", SurfaceRules.VerticalGradientConditionSource.CODEC);
SurfaceRules.register(registry, "y_above", SurfaceRules.YConditionSource.CODEC);
SurfaceRules.register(registry, "water", SurfaceRules.WaterConditionSource.CODEC);
SurfaceRules.register(registry, "temperature", SurfaceRules.Temperature.CODEC);
SurfaceRules.register(registry, "steep", SurfaceRules.Steep.CODEC);
SurfaceRules.register(registry, "not", SurfaceRules.NotConditionSource.CODEC);
SurfaceRules.register(registry, "hole", SurfaceRules.Hole.CODEC);
SurfaceRules.register(registry, "above_preliminary_surface", SurfaceRules.AbovePreliminarySurface.CODEC);
return SurfaceRules.register(registry, "stone_depth", SurfaceRules.StoneDepthCheck.CODEC);
}
KeyDispatchDataCodec<? extends SurfaceRules.ConditionSource> codec();
}
protected static final class Context {
private static final int HOW_FAR_BELOW_PRELIMINARY_SURFACE_LEVEL_TO_BUILD_SURFACE = 8;
private static final int SURFACE_CELL_BITS = 4;
private static final int SURFACE_CELL_SIZE = 16;
private static final int SURFACE_CELL_MASK = 15;
final SurfaceSystem system;
final SurfaceRules.Condition temperature = new TemperatureHelperCondition(this);
final SurfaceRules.Condition steep = new SteepMaterialCondition(this);
final SurfaceRules.Condition hole = new HoleCondition(this);
final SurfaceRules.Condition abovePreliminarySurface = new AbovePreliminarySurfaceCondition(this);
final RandomState randomState;
final ChunkAccess chunk;
private final NoiseChunk noiseChunk;
private final Function<BlockPos, Holder<Biome>> biomeGetter;
final WorldGenerationContext context;
private long lastPreliminarySurfaceCellOrigin = Long.MAX_VALUE;
private final int[] preliminarySurfaceCache = new int[4];
long lastUpdateXZ = -9223372036854775807L;
int blockX;
int blockZ;
int surfaceDepth;
private long lastSurfaceDepth2Update = this.lastUpdateXZ - 1L;
private double surfaceSecondary;
private long lastMinSurfaceLevelUpdate = this.lastUpdateXZ - 1L;
private int minSurfaceLevel;
long lastUpdateY = -9223372036854775807L;
final BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
Supplier<Holder<Biome>> biome;
int blockY;
int waterHeight;
int stoneDepthBelow;
int stoneDepthAbove;
protected Context(
SurfaceSystem system,
RandomState randomState,
ChunkAccess chunk,
NoiseChunk noiseChunk,
Function<BlockPos, Holder<Biome>> biomeGetter,
Registry<Biome> biomeRegistry,
WorldGenerationContext context
) {
this.system = system;
this.randomState = randomState;
this.chunk = chunk;
this.noiseChunk = noiseChunk;
this.biomeGetter = biomeGetter;
this.context = context;
}
protected void updateXZ(int blockX, int blockZ) {
this.lastUpdateXZ++;
this.lastUpdateY++;
this.blockX = blockX;
this.blockZ = blockZ;
this.surfaceDepth = this.system.getSurfaceDepth(blockX, blockZ);
}
protected void updateY(int stoneDepthAbove, int stoneDepthBelow, int waterHeight, int blockX, int blockY, int blockZ) {
this.lastUpdateY++;
this.biome = Suppliers.memoize(() -> (Holder<Biome>)this.biomeGetter.apply(this.pos.set(blockX, blockY, blockZ)));
this.blockY = blockY;
this.waterHeight = waterHeight;
this.stoneDepthBelow = stoneDepthBelow;
this.stoneDepthAbove = stoneDepthAbove;
}
protected double getSurfaceSecondary() {
if (this.lastSurfaceDepth2Update != this.lastUpdateXZ) {
this.lastSurfaceDepth2Update = this.lastUpdateXZ;
this.surfaceSecondary = this.system.getSurfaceSecondary(this.blockX, this.blockZ);
}
return this.surfaceSecondary;
}
public int getSeaLevel() {
return this.system.getSeaLevel();
}
private static int blockCoordToSurfaceCell(int blockCoord) {
return blockCoord >> 4;
}
private static int surfaceCellToBlockCoord(int surfaceCell) {
return surfaceCell << 4;
}
protected int getMinSurfaceLevel() {
if (this.lastMinSurfaceLevelUpdate != this.lastUpdateXZ) {
this.lastMinSurfaceLevelUpdate = this.lastUpdateXZ;
int i = blockCoordToSurfaceCell(this.blockX);
int j = blockCoordToSurfaceCell(this.blockZ);
long l = ChunkPos.asLong(i, j);
if (this.lastPreliminarySurfaceCellOrigin != l) {
this.lastPreliminarySurfaceCellOrigin = l;
this.preliminarySurfaceCache[0] = this.noiseChunk.preliminarySurfaceLevel(surfaceCellToBlockCoord(i), surfaceCellToBlockCoord(j));
this.preliminarySurfaceCache[1] = this.noiseChunk.preliminarySurfaceLevel(surfaceCellToBlockCoord(i + 1), surfaceCellToBlockCoord(j));
this.preliminarySurfaceCache[2] = this.noiseChunk.preliminarySurfaceLevel(surfaceCellToBlockCoord(i), surfaceCellToBlockCoord(j + 1));
this.preliminarySurfaceCache[3] = this.noiseChunk.preliminarySurfaceLevel(surfaceCellToBlockCoord(i + 1), surfaceCellToBlockCoord(j + 1));
}
int k = Mth.floor(
Mth.lerp2(
(this.blockX & 15) / 16.0F,
(this.blockZ & 15) / 16.0F,
this.preliminarySurfaceCache[0],
this.preliminarySurfaceCache[1],
this.preliminarySurfaceCache[2],
this.preliminarySurfaceCache[3]
)
);
this.minSurfaceLevel = k + this.surfaceDepth - 8;
}
return this.minSurfaceLevel;
}
}
static enum Hole implements SurfaceRules.ConditionSource {
INSTANCE;
static final KeyDispatchDataCodec<SurfaceRules.Hole> CODEC = KeyDispatchDataCodec.of(MapCodec.unit(INSTANCE));
@Override
public KeyDispatchDataCodec<? extends SurfaceRules.ConditionSource> codec() {
return CODEC;
}
public SurfaceRules.Condition apply(SurfaceRules.Context context) {
return context.hole;
}
}
abstract static class LazyCondition implements SurfaceRules.Condition {
protected final SurfaceRules.Context context;
private long lastUpdate;
@Nullable
Boolean result;
protected LazyCondition(SurfaceRules.Context context) {
this.context = context;
this.lastUpdate = this.getContextLastUpdate() - 1L;
}
@Override
public boolean test() {
long l = this.getContextLastUpdate();
if (l == this.lastUpdate) {
if (this.result == null) {
throw new IllegalStateException("Update triggered but the result is null");
} else {
return this.result;
}
} else {
this.lastUpdate = l;
this.result = this.compute();
return this.result;
}
}
protected abstract long getContextLastUpdate();
protected abstract boolean compute();
}
abstract static class LazyXZCondition extends SurfaceRules.LazyCondition {
protected LazyXZCondition(SurfaceRules.Context context) {
super(context);
}
@Override
protected long getContextLastUpdate() {
return this.context.lastUpdateXZ;
}
}
abstract static class LazyYCondition extends SurfaceRules.LazyCondition {
protected LazyYCondition(SurfaceRules.Context context) {
super(context);
}
@Override
protected long getContextLastUpdate() {
return this.context.lastUpdateY;
}
}
record NoiseThresholdConditionSource(ResourceKey<NoiseParameters> noise, double minThreshold, double maxThreshold) implements SurfaceRules.ConditionSource {
static final KeyDispatchDataCodec<SurfaceRules.NoiseThresholdConditionSource> CODEC = KeyDispatchDataCodec.of(
RecordCodecBuilder.mapCodec(
instance -> instance.group(
ResourceKey.codec(Registries.NOISE).fieldOf("noise").forGetter(SurfaceRules.NoiseThresholdConditionSource::noise),
Codec.DOUBLE.fieldOf("min_threshold").forGetter(SurfaceRules.NoiseThresholdConditionSource::minThreshold),
Codec.DOUBLE.fieldOf("max_threshold").forGetter(SurfaceRules.NoiseThresholdConditionSource::maxThreshold)
)
.apply(instance, SurfaceRules.NoiseThresholdConditionSource::new)
)
);
@Override
public KeyDispatchDataCodec<? extends SurfaceRules.ConditionSource> codec() {
return CODEC;
}
public SurfaceRules.Condition apply(SurfaceRules.Context context) {
NormalNoise normalNoise = context.randomState.getOrCreateNoise(this.noise);
return new 1NoiseThresholdCondition(this, context, normalNoise);
}
}
record NotCondition(SurfaceRules.Condition target) implements SurfaceRules.Condition {
@Override
public boolean test() {
return !this.target.test();
}
}
record NotConditionSource(SurfaceRules.ConditionSource target) implements SurfaceRules.ConditionSource {
static final KeyDispatchDataCodec<SurfaceRules.NotConditionSource> CODEC = KeyDispatchDataCodec.of(
SurfaceRules.ConditionSource.CODEC
.<SurfaceRules.NotConditionSource>xmap(SurfaceRules.NotConditionSource::new, SurfaceRules.NotConditionSource::target)
.fieldOf("invert")
);
@Override
public KeyDispatchDataCodec<? extends SurfaceRules.ConditionSource> codec() {
return CODEC;
}
public SurfaceRules.Condition apply(SurfaceRules.Context context) {
return new SurfaceRules.NotCondition((SurfaceRules.Condition)this.target.apply(context));
}
}
public interface RuleSource extends Function<SurfaceRules.Context, SurfaceRules.SurfaceRule> {
Codec<SurfaceRules.RuleSource> CODEC = BuiltInRegistries.MATERIAL_RULE.byNameCodec().dispatch(ruleSource -> ruleSource.codec().codec(), Function.identity());
static MapCodec<? extends SurfaceRules.RuleSource> bootstrap(Registry<MapCodec<? extends SurfaceRules.RuleSource>> registry) {
SurfaceRules.register(registry, "bandlands", SurfaceRules.Bandlands.CODEC);
SurfaceRules.register(registry, "block", SurfaceRules.BlockRuleSource.CODEC);
SurfaceRules.register(registry, "sequence", SurfaceRules.SequenceRuleSource.CODEC);
return SurfaceRules.register(registry, "condition", SurfaceRules.TestRuleSource.CODEC);
}
KeyDispatchDataCodec<? extends SurfaceRules.RuleSource> codec();
}
record SequenceRule(List<SurfaceRules.SurfaceRule> rules) implements SurfaceRules.SurfaceRule {
@Nullable
@Override
public BlockState tryApply(int i, int j, int k) {
for (SurfaceRules.SurfaceRule surfaceRule : this.rules) {
BlockState blockState = surfaceRule.tryApply(i, j, k);
if (blockState != null) {
return blockState;
}
}
return null;
}
}
record SequenceRuleSource(List<SurfaceRules.RuleSource> sequence) implements SurfaceRules.RuleSource {
static final KeyDispatchDataCodec<SurfaceRules.SequenceRuleSource> CODEC = KeyDispatchDataCodec.of(
SurfaceRules.RuleSource.CODEC
.listOf()
.<SurfaceRules.SequenceRuleSource>xmap(SurfaceRules.SequenceRuleSource::new, SurfaceRules.SequenceRuleSource::sequence)
.fieldOf("sequence")
);
@Override
public KeyDispatchDataCodec<? extends SurfaceRules.RuleSource> codec() {
return CODEC;
}
public SurfaceRules.SurfaceRule apply(SurfaceRules.Context context) {
if (this.sequence.size() == 1) {
return (SurfaceRules.SurfaceRule)((SurfaceRules.RuleSource)this.sequence.get(0)).apply(context);
} else {
Builder<SurfaceRules.SurfaceRule> builder = ImmutableList.builder();
for (SurfaceRules.RuleSource ruleSource : this.sequence) {
builder.add((SurfaceRules.SurfaceRule)ruleSource.apply(context));
}
return new SurfaceRules.SequenceRule(builder.build());
}
}
}
record StateRule(BlockState state) implements SurfaceRules.SurfaceRule {
@Override
public BlockState tryApply(int i, int j, int k) {
return this.state;
}
}
static enum Steep implements SurfaceRules.ConditionSource {
INSTANCE;
static final KeyDispatchDataCodec<SurfaceRules.Steep> CODEC = KeyDispatchDataCodec.of(MapCodec.unit(INSTANCE));
@Override
public KeyDispatchDataCodec<? extends SurfaceRules.ConditionSource> codec() {
return CODEC;
}
public SurfaceRules.Condition apply(SurfaceRules.Context context) {
return context.steep;
}
}
record StoneDepthCheck(int offset, boolean addSurfaceDepth, int secondaryDepthRange, CaveSurface surfaceType) implements SurfaceRules.ConditionSource {
static final KeyDispatchDataCodec<SurfaceRules.StoneDepthCheck> CODEC = KeyDispatchDataCodec.of(
RecordCodecBuilder.mapCodec(
instance -> instance.group(
Codec.INT.fieldOf("offset").forGetter(SurfaceRules.StoneDepthCheck::offset),
Codec.BOOL.fieldOf("add_surface_depth").forGetter(SurfaceRules.StoneDepthCheck::addSurfaceDepth),
Codec.INT.fieldOf("secondary_depth_range").forGetter(SurfaceRules.StoneDepthCheck::secondaryDepthRange),
CaveSurface.CODEC.fieldOf("surface_type").forGetter(SurfaceRules.StoneDepthCheck::surfaceType)
)
.apply(instance, SurfaceRules.StoneDepthCheck::new)
)
);
@Override
public KeyDispatchDataCodec<? extends SurfaceRules.ConditionSource> codec() {
return CODEC;
}
public SurfaceRules.Condition apply(SurfaceRules.Context context) {
boolean bl = this.surfaceType == CaveSurface.CEILING;
return new 1StoneDepthCondition(this, context, bl);
}
}
protected interface SurfaceRule {
@Nullable
BlockState tryApply(int i, int j, int k);
}
static enum Temperature implements SurfaceRules.ConditionSource {
INSTANCE;
static final KeyDispatchDataCodec<SurfaceRules.Temperature> CODEC = KeyDispatchDataCodec.of(MapCodec.unit(INSTANCE));
@Override
public KeyDispatchDataCodec<? extends SurfaceRules.ConditionSource> codec() {
return CODEC;
}
public SurfaceRules.Condition apply(SurfaceRules.Context context) {
return context.temperature;
}
}
record TestRule(SurfaceRules.Condition condition, SurfaceRules.SurfaceRule followup) implements SurfaceRules.SurfaceRule {
@Nullable
@Override
public BlockState tryApply(int i, int j, int k) {
return !this.condition.test() ? null : this.followup.tryApply(i, j, k);
}
}
record TestRuleSource(SurfaceRules.ConditionSource ifTrue, SurfaceRules.RuleSource thenRun) implements SurfaceRules.RuleSource {
static final KeyDispatchDataCodec<SurfaceRules.TestRuleSource> CODEC = KeyDispatchDataCodec.of(
RecordCodecBuilder.mapCodec(
instance -> instance.group(
SurfaceRules.ConditionSource.CODEC.fieldOf("if_true").forGetter(SurfaceRules.TestRuleSource::ifTrue),
SurfaceRules.RuleSource.CODEC.fieldOf("then_run").forGetter(SurfaceRules.TestRuleSource::thenRun)
)
.apply(instance, SurfaceRules.TestRuleSource::new)
)
);
@Override
public KeyDispatchDataCodec<? extends SurfaceRules.RuleSource> codec() {
return CODEC;
}
public SurfaceRules.SurfaceRule apply(SurfaceRules.Context context) {
return new SurfaceRules.TestRule((SurfaceRules.Condition)this.ifTrue.apply(context), (SurfaceRules.SurfaceRule)this.thenRun.apply(context));
}
}
record VerticalGradientConditionSource(ResourceLocation randomName, VerticalAnchor trueAtAndBelow, VerticalAnchor falseAtAndAbove)
implements SurfaceRules.ConditionSource {
static final KeyDispatchDataCodec<SurfaceRules.VerticalGradientConditionSource> CODEC = KeyDispatchDataCodec.of(
RecordCodecBuilder.mapCodec(
instance -> instance.group(
ResourceLocation.CODEC.fieldOf("random_name").forGetter(SurfaceRules.VerticalGradientConditionSource::randomName),
VerticalAnchor.CODEC.fieldOf("true_at_and_below").forGetter(SurfaceRules.VerticalGradientConditionSource::trueAtAndBelow),
VerticalAnchor.CODEC.fieldOf("false_at_and_above").forGetter(SurfaceRules.VerticalGradientConditionSource::falseAtAndAbove)
)
.apply(instance, SurfaceRules.VerticalGradientConditionSource::new)
)
);
@Override
public KeyDispatchDataCodec<? extends SurfaceRules.ConditionSource> codec() {
return CODEC;
}
public SurfaceRules.Condition apply(SurfaceRules.Context context) {
int i = this.trueAtAndBelow().resolveY(context.context);
int j = this.falseAtAndAbove().resolveY(context.context);
PositionalRandomFactory positionalRandomFactory = context.randomState.getOrCreateRandomFactory(this.randomName());
return new 1VerticalGradientCondition(this, context, i, j, positionalRandomFactory);
}
}
record WaterConditionSource(int offset, int surfaceDepthMultiplier, boolean addStoneDepth) implements SurfaceRules.ConditionSource {
static final KeyDispatchDataCodec<SurfaceRules.WaterConditionSource> CODEC = KeyDispatchDataCodec.of(
RecordCodecBuilder.mapCodec(
instance -> instance.group(
Codec.INT.fieldOf("offset").forGetter(SurfaceRules.WaterConditionSource::offset),
Codec.intRange(-20, 20).fieldOf("surface_depth_multiplier").forGetter(SurfaceRules.WaterConditionSource::surfaceDepthMultiplier),
Codec.BOOL.fieldOf("add_stone_depth").forGetter(SurfaceRules.WaterConditionSource::addStoneDepth)
)
.apply(instance, SurfaceRules.WaterConditionSource::new)
)
);
@Override
public KeyDispatchDataCodec<? extends SurfaceRules.ConditionSource> codec() {
return CODEC;
}
public SurfaceRules.Condition apply(SurfaceRules.Context context) {
return new 1WaterCondition(this, context);
}
}
record YConditionSource(VerticalAnchor anchor, int surfaceDepthMultiplier, boolean addStoneDepth) implements SurfaceRules.ConditionSource {
static final KeyDispatchDataCodec<SurfaceRules.YConditionSource> CODEC = KeyDispatchDataCodec.of(
RecordCodecBuilder.mapCodec(
instance -> instance.group(
VerticalAnchor.CODEC.fieldOf("anchor").forGetter(SurfaceRules.YConditionSource::anchor),
Codec.intRange(-20, 20).fieldOf("surface_depth_multiplier").forGetter(SurfaceRules.YConditionSource::surfaceDepthMultiplier),
Codec.BOOL.fieldOf("add_stone_depth").forGetter(SurfaceRules.YConditionSource::addStoneDepth)
)
.apply(instance, SurfaceRules.YConditionSource::new)
)
);
@Override
public KeyDispatchDataCodec<? extends SurfaceRules.ConditionSource> codec() {
return CODEC;
}
public SurfaceRules.Condition apply(SurfaceRules.Context context) {
return new 1YCondition(this, context);
}
}
}