minecraft-src/net/minecraft/world/level/levelgen/VerticalAnchor.java
2025-07-04 01:41:11 +03:00

104 lines
3.5 KiB
Java

package net.minecraft.world.level.levelgen;
import com.mojang.datafixers.util.Either;
import com.mojang.serialization.Codec;
import java.util.function.Function;
import net.minecraft.world.level.dimension.DimensionType;
/**
* Represents a resolvable height value, or y coordinate, based on the world minimum and maximum height.
* Can take one of the following three forms:
* <ul>
* <li>An absolute y value ({@link Absolute}).</li>
* <li>A height above the lowest valid y value in the level ({@link AboveBottom}).</li>
* <li>A height below the highest valid y value in the level ({@link BelowTop}).</li>
* </ul>
*/
public interface VerticalAnchor {
Codec<VerticalAnchor> CODEC = Codec.xor(VerticalAnchor.Absolute.CODEC, Codec.xor(VerticalAnchor.AboveBottom.CODEC, VerticalAnchor.BelowTop.CODEC))
.xmap(VerticalAnchor::merge, VerticalAnchor::split);
VerticalAnchor BOTTOM = aboveBottom(0);
VerticalAnchor TOP = belowTop(0);
static VerticalAnchor absolute(int value) {
return new VerticalAnchor.Absolute(value);
}
static VerticalAnchor aboveBottom(int value) {
return new VerticalAnchor.AboveBottom(value);
}
static VerticalAnchor belowTop(int value) {
return new VerticalAnchor.BelowTop(value);
}
static VerticalAnchor bottom() {
return BOTTOM;
}
static VerticalAnchor top() {
return TOP;
}
private static VerticalAnchor merge(Either<VerticalAnchor.Absolute, Either<VerticalAnchor.AboveBottom, VerticalAnchor.BelowTop>> anchor) {
return anchor.map(Function.identity(), Either::unwrap);
}
private static Either<VerticalAnchor.Absolute, Either<VerticalAnchor.AboveBottom, VerticalAnchor.BelowTop>> split(VerticalAnchor anchor) {
return anchor instanceof VerticalAnchor.Absolute
? Either.left((VerticalAnchor.Absolute)anchor)
: Either.right(
anchor instanceof VerticalAnchor.AboveBottom ? Either.left((VerticalAnchor.AboveBottom)anchor) : Either.right((VerticalAnchor.BelowTop)anchor)
);
}
int resolveY(WorldGenerationContext context);
public record AboveBottom(int offset) implements VerticalAnchor {
public static final Codec<VerticalAnchor.AboveBottom> CODEC = Codec.intRange(DimensionType.MIN_Y, DimensionType.MAX_Y)
.fieldOf("above_bottom")
.<VerticalAnchor.AboveBottom>xmap(VerticalAnchor.AboveBottom::new, VerticalAnchor.AboveBottom::offset)
.codec();
@Override
public int resolveY(WorldGenerationContext context) {
return context.getMinGenY() + this.offset;
}
public String toString() {
return this.offset + " above bottom";
}
}
public record Absolute(int y) implements VerticalAnchor {
public static final Codec<VerticalAnchor.Absolute> CODEC = Codec.intRange(DimensionType.MIN_Y, DimensionType.MAX_Y)
.fieldOf("absolute")
.<VerticalAnchor.Absolute>xmap(VerticalAnchor.Absolute::new, VerticalAnchor.Absolute::y)
.codec();
@Override
public int resolveY(WorldGenerationContext context) {
return this.y;
}
public String toString() {
return this.y + " absolute";
}
}
public record BelowTop(int offset) implements VerticalAnchor {
public static final Codec<VerticalAnchor.BelowTop> CODEC = Codec.intRange(DimensionType.MIN_Y, DimensionType.MAX_Y)
.fieldOf("below_top")
.<VerticalAnchor.BelowTop>xmap(VerticalAnchor.BelowTop::new, VerticalAnchor.BelowTop::offset)
.codec();
@Override
public int resolveY(WorldGenerationContext context) {
return context.getGenDepth() - 1 + context.getMinGenY() - this.offset;
}
public String toString() {
return this.offset + " below top";
}
}
}