791 lines
30 KiB
Java
791 lines
30 KiB
Java
package net.minecraft.world.level.levelgen;
|
|
|
|
import com.google.common.collect.Lists;
|
|
import it.unimi.dsi.fastutil.longs.Long2IntMap;
|
|
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import javax.annotation.Nullable;
|
|
import net.minecraft.core.QuartPos;
|
|
import net.minecraft.core.SectionPos;
|
|
import net.minecraft.server.level.ColumnPos;
|
|
import net.minecraft.util.KeyDispatchDataCodec;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.world.level.ChunkPos;
|
|
import net.minecraft.world.level.biome.Climate;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
|
import net.minecraft.world.level.levelgen.blending.Blender;
|
|
import net.minecraft.world.level.levelgen.material.MaterialRuleList;
|
|
|
|
public class NoiseChunk implements DensityFunction.ContextProvider, DensityFunction.FunctionContext {
|
|
private final NoiseSettings noiseSettings;
|
|
final int cellCountXZ;
|
|
final int cellCountY;
|
|
final int cellNoiseMinY;
|
|
private final int firstCellX;
|
|
private final int firstCellZ;
|
|
final int firstNoiseX;
|
|
final int firstNoiseZ;
|
|
final List<NoiseChunk.NoiseInterpolator> interpolators;
|
|
final List<NoiseChunk.CacheAllInCell> cellCaches;
|
|
private final Map<DensityFunction, DensityFunction> wrapped = new HashMap<>();
|
|
private final Long2IntMap preliminarySurfaceLevel = new Long2IntOpenHashMap();
|
|
private final Aquifer aquifer;
|
|
private final DensityFunction initialDensityNoJaggedness;
|
|
private final NoiseChunk.BlockStateFiller blockStateRule;
|
|
private final Blender blender;
|
|
private final NoiseChunk.FlatCache blendAlpha;
|
|
private final NoiseChunk.FlatCache blendOffset;
|
|
private final DensityFunctions.BeardifierOrMarker beardifier;
|
|
private long lastBlendingDataPos = ChunkPos.INVALID_CHUNK_POS;
|
|
private Blender.BlendingOutput lastBlendingOutput = new Blender.BlendingOutput(1.0, 0.0);
|
|
final int noiseSizeXZ;
|
|
final int cellWidth;
|
|
final int cellHeight;
|
|
boolean interpolating;
|
|
boolean fillingCell;
|
|
private int cellStartBlockX;
|
|
int cellStartBlockY;
|
|
private int cellStartBlockZ;
|
|
int inCellX;
|
|
int inCellY;
|
|
int inCellZ;
|
|
long interpolationCounter;
|
|
long arrayInterpolationCounter;
|
|
int arrayIndex;
|
|
private final DensityFunction.ContextProvider sliceFillingContextProvider = new DensityFunction.ContextProvider() {
|
|
@Override
|
|
public DensityFunction.FunctionContext forIndex(int p_209253_) {
|
|
NoiseChunk.this.cellStartBlockY = (p_209253_ + NoiseChunk.this.cellNoiseMinY) * NoiseChunk.this.cellHeight;
|
|
NoiseChunk.this.interpolationCounter++;
|
|
NoiseChunk.this.inCellY = 0;
|
|
NoiseChunk.this.arrayIndex = p_209253_;
|
|
return NoiseChunk.this;
|
|
}
|
|
|
|
@Override
|
|
public void fillAllDirectly(double[] p_209255_, DensityFunction p_209256_) {
|
|
for (int i2 = 0; i2 < NoiseChunk.this.cellCountY + 1; i2++) {
|
|
NoiseChunk.this.cellStartBlockY = (i2 + NoiseChunk.this.cellNoiseMinY) * NoiseChunk.this.cellHeight;
|
|
NoiseChunk.this.interpolationCounter++;
|
|
NoiseChunk.this.inCellY = 0;
|
|
NoiseChunk.this.arrayIndex = i2;
|
|
p_209255_[i2] = p_209256_.compute(NoiseChunk.this);
|
|
}
|
|
}
|
|
};
|
|
|
|
public static NoiseChunk forChunk(
|
|
ChunkAccess p_224353_,
|
|
RandomState p_224354_,
|
|
DensityFunctions.BeardifierOrMarker p_224355_,
|
|
NoiseGeneratorSettings p_224356_,
|
|
Aquifer.FluidPicker p_224357_,
|
|
Blender p_224358_
|
|
) {
|
|
NoiseSettings noisesettings = p_224356_.noiseSettings().clampToHeightAccessor(p_224353_);
|
|
ChunkPos chunkpos = p_224353_.getPos();
|
|
int i = 16 / noisesettings.getCellWidth();
|
|
return new NoiseChunk(i, p_224354_, chunkpos.getMinBlockX(), chunkpos.getMinBlockZ(), noisesettings, p_224355_, p_224356_, p_224357_, p_224358_);
|
|
}
|
|
|
|
public NoiseChunk(
|
|
int p_224343_,
|
|
RandomState p_224344_,
|
|
int p_224345_,
|
|
int p_224346_,
|
|
NoiseSettings p_224347_,
|
|
DensityFunctions.BeardifierOrMarker p_224348_,
|
|
NoiseGeneratorSettings p_224349_,
|
|
Aquifer.FluidPicker p_224350_,
|
|
Blender p_224351_
|
|
) {
|
|
this.noiseSettings = p_224347_;
|
|
this.cellWidth = p_224347_.getCellWidth();
|
|
this.cellHeight = p_224347_.getCellHeight();
|
|
this.cellCountXZ = p_224343_;
|
|
this.cellCountY = Mth.floorDiv(p_224347_.height(), this.cellHeight);
|
|
this.cellNoiseMinY = Mth.floorDiv(p_224347_.minY(), this.cellHeight);
|
|
this.firstCellX = Math.floorDiv(p_224345_, this.cellWidth);
|
|
this.firstCellZ = Math.floorDiv(p_224346_, this.cellWidth);
|
|
this.interpolators = Lists.newArrayList();
|
|
this.cellCaches = Lists.newArrayList();
|
|
this.firstNoiseX = QuartPos.fromBlock(p_224345_);
|
|
this.firstNoiseZ = QuartPos.fromBlock(p_224346_);
|
|
this.noiseSizeXZ = QuartPos.fromBlock(p_224343_ * this.cellWidth);
|
|
this.blender = p_224351_;
|
|
this.beardifier = p_224348_;
|
|
this.blendAlpha = new NoiseChunk.FlatCache(new NoiseChunk.BlendAlpha(), false);
|
|
this.blendOffset = new NoiseChunk.FlatCache(new NoiseChunk.BlendOffset(), false);
|
|
|
|
for (int i = 0; i <= this.noiseSizeXZ; i++) {
|
|
int j = this.firstNoiseX + i;
|
|
int k = QuartPos.toBlock(j);
|
|
|
|
for (int l = 0; l <= this.noiseSizeXZ; l++) {
|
|
int i1 = this.firstNoiseZ + l;
|
|
int j1 = QuartPos.toBlock(i1);
|
|
Blender.BlendingOutput blender$blendingoutput = p_224351_.blendOffsetAndFactor(k, j1);
|
|
this.blendAlpha.values[i][l] = blender$blendingoutput.alpha();
|
|
this.blendOffset.values[i][l] = blender$blendingoutput.blendingOffset();
|
|
}
|
|
}
|
|
|
|
NoiseRouter noiserouter = p_224344_.router();
|
|
NoiseRouter noiserouter1 = noiserouter.mapAll(this::wrap);
|
|
if (!p_224349_.isAquifersEnabled()) {
|
|
this.aquifer = Aquifer.createDisabled(p_224350_);
|
|
} else {
|
|
int k1 = SectionPos.blockToSectionCoord(p_224345_);
|
|
int l1 = SectionPos.blockToSectionCoord(p_224346_);
|
|
this.aquifer = Aquifer.create(
|
|
this, new ChunkPos(k1, l1), noiserouter1, p_224344_.aquiferRandom(), p_224347_.minY(), p_224347_.height(), p_224350_
|
|
);
|
|
}
|
|
|
|
List<NoiseChunk.BlockStateFiller> list = new ArrayList<>();
|
|
DensityFunction densityfunction = DensityFunctions.cacheAllInCell(
|
|
DensityFunctions.add(noiserouter1.finalDensity(), DensityFunctions.BeardifierMarker.INSTANCE)
|
|
)
|
|
.mapAll(this::wrap);
|
|
list.add(p_209217_ -> this.aquifer.computeSubstance(p_209217_, densityfunction.compute(p_209217_)));
|
|
if (p_224349_.oreVeinsEnabled()) {
|
|
list.add(OreVeinifier.create(noiserouter1.veinToggle(), noiserouter1.veinRidged(), noiserouter1.veinGap(), p_224344_.oreRandom()));
|
|
}
|
|
|
|
this.blockStateRule = new MaterialRuleList(list.toArray(new NoiseChunk.BlockStateFiller[0]));
|
|
this.initialDensityNoJaggedness = noiserouter1.initialDensityWithoutJaggedness();
|
|
}
|
|
|
|
protected Climate.Sampler cachedClimateSampler(NoiseRouter p_224360_, List<Climate.ParameterPoint> p_224361_) {
|
|
return new Climate.Sampler(
|
|
p_224360_.temperature().mapAll(this::wrap),
|
|
p_224360_.vegetation().mapAll(this::wrap),
|
|
p_224360_.continents().mapAll(this::wrap),
|
|
p_224360_.erosion().mapAll(this::wrap),
|
|
p_224360_.depth().mapAll(this::wrap),
|
|
p_224360_.ridges().mapAll(this::wrap),
|
|
p_224361_
|
|
);
|
|
}
|
|
|
|
@Nullable
|
|
protected BlockState getInterpolatedState() {
|
|
return this.blockStateRule.calculate(this);
|
|
}
|
|
|
|
@Override
|
|
public int blockX() {
|
|
return this.cellStartBlockX + this.inCellX;
|
|
}
|
|
|
|
@Override
|
|
public int blockY() {
|
|
return this.cellStartBlockY + this.inCellY;
|
|
}
|
|
|
|
@Override
|
|
public int blockZ() {
|
|
return this.cellStartBlockZ + this.inCellZ;
|
|
}
|
|
|
|
public int preliminarySurfaceLevel(int p_198257_, int p_198258_) {
|
|
int i = QuartPos.toBlock(QuartPos.fromBlock(p_198257_));
|
|
int j = QuartPos.toBlock(QuartPos.fromBlock(p_198258_));
|
|
return this.preliminarySurfaceLevel.computeIfAbsent(ColumnPos.asLong(i, j), this::computePreliminarySurfaceLevel);
|
|
}
|
|
|
|
private int computePreliminarySurfaceLevel(long p_198250_) {
|
|
int i = ColumnPos.getX(p_198250_);
|
|
int j = ColumnPos.getZ(p_198250_);
|
|
int k = this.noiseSettings.minY();
|
|
|
|
for (int l = k + this.noiseSettings.height(); l >= k; l -= this.cellHeight) {
|
|
if (this.initialDensityNoJaggedness.compute(new DensityFunction.SinglePointContext(i, l, j)) > 0.390625) {
|
|
return l;
|
|
}
|
|
}
|
|
|
|
return Integer.MAX_VALUE;
|
|
}
|
|
|
|
@Override
|
|
public Blender getBlender() {
|
|
return this.blender;
|
|
}
|
|
|
|
private void fillSlice(boolean p_209221_, int p_209222_) {
|
|
this.cellStartBlockX = p_209222_ * this.cellWidth;
|
|
this.inCellX = 0;
|
|
|
|
for (int i = 0; i < this.cellCountXZ + 1; i++) {
|
|
int j = this.firstCellZ + i;
|
|
this.cellStartBlockZ = j * this.cellWidth;
|
|
this.inCellZ = 0;
|
|
this.arrayInterpolationCounter++;
|
|
|
|
for (NoiseChunk.NoiseInterpolator noisechunk$noiseinterpolator : this.interpolators) {
|
|
double[] adouble = (p_209221_ ? noisechunk$noiseinterpolator.slice0 : noisechunk$noiseinterpolator.slice1)[i];
|
|
noisechunk$noiseinterpolator.fillArray(adouble, this.sliceFillingContextProvider);
|
|
}
|
|
}
|
|
|
|
this.arrayInterpolationCounter++;
|
|
}
|
|
|
|
public void initializeForFirstCellX() {
|
|
if (this.interpolating) {
|
|
throw new IllegalStateException("Staring interpolation twice");
|
|
} else {
|
|
this.interpolating = true;
|
|
this.interpolationCounter = 0L;
|
|
this.fillSlice(true, this.firstCellX);
|
|
}
|
|
}
|
|
|
|
public void advanceCellX(int p_188750_) {
|
|
this.fillSlice(false, this.firstCellX + p_188750_ + 1);
|
|
this.cellStartBlockX = (this.firstCellX + p_188750_) * this.cellWidth;
|
|
}
|
|
|
|
public NoiseChunk forIndex(int p_209240_) {
|
|
int i = Math.floorMod(p_209240_, this.cellWidth);
|
|
int j = Math.floorDiv(p_209240_, this.cellWidth);
|
|
int k = Math.floorMod(j, this.cellWidth);
|
|
int l = this.cellHeight - 1 - Math.floorDiv(j, this.cellWidth);
|
|
this.inCellX = k;
|
|
this.inCellY = l;
|
|
this.inCellZ = i;
|
|
this.arrayIndex = p_209240_;
|
|
return this;
|
|
}
|
|
|
|
@Override
|
|
public void fillAllDirectly(double[] p_209224_, DensityFunction p_209225_) {
|
|
this.arrayIndex = 0;
|
|
|
|
for (int i = this.cellHeight - 1; i >= 0; i--) {
|
|
this.inCellY = i;
|
|
|
|
for (int j = 0; j < this.cellWidth; j++) {
|
|
this.inCellX = j;
|
|
|
|
for (int k = 0; k < this.cellWidth; k++) {
|
|
this.inCellZ = k;
|
|
p_209224_[this.arrayIndex++] = p_209225_.compute(this);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void selectCellYZ(int p_188811_, int p_188812_) {
|
|
for (NoiseChunk.NoiseInterpolator noisechunk$noiseinterpolator : this.interpolators) {
|
|
noisechunk$noiseinterpolator.selectCellYZ(p_188811_, p_188812_);
|
|
}
|
|
|
|
this.fillingCell = true;
|
|
this.cellStartBlockY = (p_188811_ + this.cellNoiseMinY) * this.cellHeight;
|
|
this.cellStartBlockZ = (this.firstCellZ + p_188812_) * this.cellWidth;
|
|
this.arrayInterpolationCounter++;
|
|
|
|
for (NoiseChunk.CacheAllInCell noisechunk$cacheallincell : this.cellCaches) {
|
|
noisechunk$cacheallincell.noiseFiller.fillArray(noisechunk$cacheallincell.values, this);
|
|
}
|
|
|
|
this.arrayInterpolationCounter++;
|
|
this.fillingCell = false;
|
|
}
|
|
|
|
public void updateForY(int p_209192_, double p_209193_) {
|
|
this.inCellY = p_209192_ - this.cellStartBlockY;
|
|
|
|
for (NoiseChunk.NoiseInterpolator noisechunk$noiseinterpolator : this.interpolators) {
|
|
noisechunk$noiseinterpolator.updateForY(p_209193_);
|
|
}
|
|
}
|
|
|
|
public void updateForX(int p_209231_, double p_209232_) {
|
|
this.inCellX = p_209231_ - this.cellStartBlockX;
|
|
|
|
for (NoiseChunk.NoiseInterpolator noisechunk$noiseinterpolator : this.interpolators) {
|
|
noisechunk$noiseinterpolator.updateForX(p_209232_);
|
|
}
|
|
}
|
|
|
|
public void updateForZ(int p_209242_, double p_209243_) {
|
|
this.inCellZ = p_209242_ - this.cellStartBlockZ;
|
|
this.interpolationCounter++;
|
|
|
|
for (NoiseChunk.NoiseInterpolator noisechunk$noiseinterpolator : this.interpolators) {
|
|
noisechunk$noiseinterpolator.updateForZ(p_209243_);
|
|
}
|
|
}
|
|
|
|
public void stopInterpolation() {
|
|
if (!this.interpolating) {
|
|
throw new IllegalStateException("Staring interpolation twice");
|
|
} else {
|
|
this.interpolating = false;
|
|
}
|
|
}
|
|
|
|
public void swapSlices() {
|
|
this.interpolators.forEach(NoiseChunk.NoiseInterpolator::swapSlices);
|
|
}
|
|
|
|
public Aquifer aquifer() {
|
|
return this.aquifer;
|
|
}
|
|
|
|
protected int cellWidth() {
|
|
return this.cellWidth;
|
|
}
|
|
|
|
protected int cellHeight() {
|
|
return this.cellHeight;
|
|
}
|
|
|
|
Blender.BlendingOutput getOrComputeBlendingOutput(int p_209245_, int p_209246_) {
|
|
long i = ChunkPos.asLong(p_209245_, p_209246_);
|
|
if (this.lastBlendingDataPos == i) {
|
|
return this.lastBlendingOutput;
|
|
} else {
|
|
this.lastBlendingDataPos = i;
|
|
Blender.BlendingOutput blender$blendingoutput = this.blender.blendOffsetAndFactor(p_209245_, p_209246_);
|
|
this.lastBlendingOutput = blender$blendingoutput;
|
|
return blender$blendingoutput;
|
|
}
|
|
}
|
|
|
|
protected DensityFunction wrap(DensityFunction p_209214_) {
|
|
return this.wrapped.computeIfAbsent(p_209214_, this::wrapNew);
|
|
}
|
|
|
|
private DensityFunction wrapNew(DensityFunction p_209234_) {
|
|
if (p_209234_ instanceof DensityFunctions.Marker densityfunctions$marker) {
|
|
return (DensityFunction)(switch (densityfunctions$marker.type()) {
|
|
case Interpolated -> new NoiseChunk.NoiseInterpolator(densityfunctions$marker.wrapped());
|
|
case FlatCache -> new NoiseChunk.FlatCache(densityfunctions$marker.wrapped(), true);
|
|
case Cache2D -> new NoiseChunk.Cache2D(densityfunctions$marker.wrapped());
|
|
case CacheOnce -> new NoiseChunk.CacheOnce(densityfunctions$marker.wrapped());
|
|
case CacheAllInCell -> new NoiseChunk.CacheAllInCell(densityfunctions$marker.wrapped());
|
|
});
|
|
} else {
|
|
if (this.blender != Blender.empty()) {
|
|
if (p_209234_ == DensityFunctions.BlendAlpha.INSTANCE) {
|
|
return this.blendAlpha;
|
|
}
|
|
|
|
if (p_209234_ == DensityFunctions.BlendOffset.INSTANCE) {
|
|
return this.blendOffset;
|
|
}
|
|
}
|
|
|
|
if (p_209234_ == DensityFunctions.BeardifierMarker.INSTANCE) {
|
|
return this.beardifier;
|
|
} else {
|
|
return p_209234_ instanceof DensityFunctions.HolderHolder densityfunctions$holderholder
|
|
? densityfunctions$holderholder.function().value()
|
|
: p_209234_;
|
|
}
|
|
}
|
|
}
|
|
|
|
class BlendAlpha implements NoiseChunk.NoiseChunkDensityFunction {
|
|
@Override
|
|
public DensityFunction wrapped() {
|
|
return DensityFunctions.BlendAlpha.INSTANCE;
|
|
}
|
|
|
|
@Override
|
|
public DensityFunction mapAll(DensityFunction.Visitor p_224365_) {
|
|
return this.wrapped().mapAll(p_224365_);
|
|
}
|
|
|
|
@Override
|
|
public double compute(DensityFunction.FunctionContext p_209264_) {
|
|
return NoiseChunk.this.getOrComputeBlendingOutput(p_209264_.blockX(), p_209264_.blockZ()).alpha();
|
|
}
|
|
|
|
@Override
|
|
public void fillArray(double[] p_209266_, DensityFunction.ContextProvider p_209267_) {
|
|
p_209267_.fillAllDirectly(p_209266_, this);
|
|
}
|
|
|
|
@Override
|
|
public double minValue() {
|
|
return 0.0;
|
|
}
|
|
|
|
@Override
|
|
public double maxValue() {
|
|
return 1.0;
|
|
}
|
|
|
|
@Override
|
|
public KeyDispatchDataCodec<? extends DensityFunction> codec() {
|
|
return DensityFunctions.BlendAlpha.CODEC;
|
|
}
|
|
}
|
|
|
|
class BlendOffset implements NoiseChunk.NoiseChunkDensityFunction {
|
|
@Override
|
|
public DensityFunction wrapped() {
|
|
return DensityFunctions.BlendOffset.INSTANCE;
|
|
}
|
|
|
|
@Override
|
|
public DensityFunction mapAll(DensityFunction.Visitor p_224368_) {
|
|
return this.wrapped().mapAll(p_224368_);
|
|
}
|
|
|
|
@Override
|
|
public double compute(DensityFunction.FunctionContext p_209276_) {
|
|
return NoiseChunk.this.getOrComputeBlendingOutput(p_209276_.blockX(), p_209276_.blockZ()).blendingOffset();
|
|
}
|
|
|
|
@Override
|
|
public void fillArray(double[] p_209278_, DensityFunction.ContextProvider p_209279_) {
|
|
p_209279_.fillAllDirectly(p_209278_, this);
|
|
}
|
|
|
|
@Override
|
|
public double minValue() {
|
|
return Double.NEGATIVE_INFINITY;
|
|
}
|
|
|
|
@Override
|
|
public double maxValue() {
|
|
return Double.POSITIVE_INFINITY;
|
|
}
|
|
|
|
@Override
|
|
public KeyDispatchDataCodec<? extends DensityFunction> codec() {
|
|
return DensityFunctions.BlendOffset.CODEC;
|
|
}
|
|
}
|
|
|
|
@FunctionalInterface
|
|
public interface BlockStateFiller {
|
|
@Nullable
|
|
BlockState calculate(DensityFunction.FunctionContext p_209283_);
|
|
}
|
|
|
|
static class Cache2D implements DensityFunctions.MarkerOrMarked, NoiseChunk.NoiseChunkDensityFunction {
|
|
private final DensityFunction function;
|
|
private long lastPos2D = ChunkPos.INVALID_CHUNK_POS;
|
|
private double lastValue;
|
|
|
|
Cache2D(DensityFunction p_209288_) {
|
|
this.function = p_209288_;
|
|
}
|
|
|
|
@Override
|
|
public double compute(DensityFunction.FunctionContext p_209290_) {
|
|
int i = p_209290_.blockX();
|
|
int j = p_209290_.blockZ();
|
|
long k = ChunkPos.asLong(i, j);
|
|
if (this.lastPos2D == k) {
|
|
return this.lastValue;
|
|
} else {
|
|
this.lastPos2D = k;
|
|
double d0 = this.function.compute(p_209290_);
|
|
this.lastValue = d0;
|
|
return d0;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void fillArray(double[] p_209292_, DensityFunction.ContextProvider p_209293_) {
|
|
this.function.fillArray(p_209292_, p_209293_);
|
|
}
|
|
|
|
@Override
|
|
public DensityFunction wrapped() {
|
|
return this.function;
|
|
}
|
|
|
|
@Override
|
|
public DensityFunctions.Marker.Type type() {
|
|
return DensityFunctions.Marker.Type.Cache2D;
|
|
}
|
|
}
|
|
|
|
class CacheAllInCell implements DensityFunctions.MarkerOrMarked, NoiseChunk.NoiseChunkDensityFunction {
|
|
final DensityFunction noiseFiller;
|
|
final double[] values;
|
|
|
|
CacheAllInCell(final DensityFunction p_209301_) {
|
|
this.noiseFiller = p_209301_;
|
|
this.values = new double[NoiseChunk.this.cellWidth * NoiseChunk.this.cellWidth * NoiseChunk.this.cellHeight];
|
|
NoiseChunk.this.cellCaches.add(this);
|
|
}
|
|
|
|
@Override
|
|
public double compute(DensityFunction.FunctionContext p_209303_) {
|
|
if (p_209303_ != NoiseChunk.this) {
|
|
return this.noiseFiller.compute(p_209303_);
|
|
} else if (!NoiseChunk.this.interpolating) {
|
|
throw new IllegalStateException("Trying to sample interpolator outside the interpolation loop");
|
|
} else {
|
|
int i = NoiseChunk.this.inCellX;
|
|
int j = NoiseChunk.this.inCellY;
|
|
int k = NoiseChunk.this.inCellZ;
|
|
return i >= 0 && j >= 0 && k >= 0 && i < NoiseChunk.this.cellWidth && j < NoiseChunk.this.cellHeight && k < NoiseChunk.this.cellWidth
|
|
? this.values[((NoiseChunk.this.cellHeight - 1 - j) * NoiseChunk.this.cellWidth + i) * NoiseChunk.this.cellWidth + k]
|
|
: this.noiseFiller.compute(p_209303_);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void fillArray(double[] p_209305_, DensityFunction.ContextProvider p_209306_) {
|
|
p_209306_.fillAllDirectly(p_209305_, this);
|
|
}
|
|
|
|
@Override
|
|
public DensityFunction wrapped() {
|
|
return this.noiseFiller;
|
|
}
|
|
|
|
@Override
|
|
public DensityFunctions.Marker.Type type() {
|
|
return DensityFunctions.Marker.Type.CacheAllInCell;
|
|
}
|
|
}
|
|
|
|
class CacheOnce implements DensityFunctions.MarkerOrMarked, NoiseChunk.NoiseChunkDensityFunction {
|
|
private final DensityFunction function;
|
|
private long lastCounter;
|
|
private long lastArrayCounter;
|
|
private double lastValue;
|
|
@Nullable
|
|
private double[] lastArray;
|
|
|
|
CacheOnce(final DensityFunction p_209317_) {
|
|
this.function = p_209317_;
|
|
}
|
|
|
|
@Override
|
|
public double compute(DensityFunction.FunctionContext p_209319_) {
|
|
if (p_209319_ != NoiseChunk.this) {
|
|
return this.function.compute(p_209319_);
|
|
} else if (this.lastArray != null && this.lastArrayCounter == NoiseChunk.this.arrayInterpolationCounter) {
|
|
return this.lastArray[NoiseChunk.this.arrayIndex];
|
|
} else if (this.lastCounter == NoiseChunk.this.interpolationCounter) {
|
|
return this.lastValue;
|
|
} else {
|
|
this.lastCounter = NoiseChunk.this.interpolationCounter;
|
|
double d0 = this.function.compute(p_209319_);
|
|
this.lastValue = d0;
|
|
return d0;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void fillArray(double[] p_209321_, DensityFunction.ContextProvider p_209322_) {
|
|
if (this.lastArray != null && this.lastArrayCounter == NoiseChunk.this.arrayInterpolationCounter) {
|
|
System.arraycopy(this.lastArray, 0, p_209321_, 0, p_209321_.length);
|
|
} else {
|
|
this.wrapped().fillArray(p_209321_, p_209322_);
|
|
if (this.lastArray != null && this.lastArray.length == p_209321_.length) {
|
|
System.arraycopy(p_209321_, 0, this.lastArray, 0, p_209321_.length);
|
|
} else {
|
|
this.lastArray = (double[])p_209321_.clone();
|
|
}
|
|
|
|
this.lastArrayCounter = NoiseChunk.this.arrayInterpolationCounter;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public DensityFunction wrapped() {
|
|
return this.function;
|
|
}
|
|
|
|
@Override
|
|
public DensityFunctions.Marker.Type type() {
|
|
return DensityFunctions.Marker.Type.CacheOnce;
|
|
}
|
|
}
|
|
|
|
class FlatCache implements DensityFunctions.MarkerOrMarked, NoiseChunk.NoiseChunkDensityFunction {
|
|
private final DensityFunction noiseFiller;
|
|
final double[][] values;
|
|
|
|
FlatCache(final DensityFunction p_209330_, final boolean p_209331_) {
|
|
this.noiseFiller = p_209330_;
|
|
this.values = new double[NoiseChunk.this.noiseSizeXZ + 1][NoiseChunk.this.noiseSizeXZ + 1];
|
|
if (p_209331_) {
|
|
for (int i = 0; i <= NoiseChunk.this.noiseSizeXZ; i++) {
|
|
int j = NoiseChunk.this.firstNoiseX + i;
|
|
int k = QuartPos.toBlock(j);
|
|
|
|
for (int l = 0; l <= NoiseChunk.this.noiseSizeXZ; l++) {
|
|
int i1 = NoiseChunk.this.firstNoiseZ + l;
|
|
int j1 = QuartPos.toBlock(i1);
|
|
this.values[i][l] = p_209330_.compute(new DensityFunction.SinglePointContext(k, 0, j1));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public double compute(DensityFunction.FunctionContext p_209333_) {
|
|
int i = QuartPos.fromBlock(p_209333_.blockX());
|
|
int j = QuartPos.fromBlock(p_209333_.blockZ());
|
|
int k = i - NoiseChunk.this.firstNoiseX;
|
|
int l = j - NoiseChunk.this.firstNoiseZ;
|
|
int i1 = this.values.length;
|
|
return k >= 0 && l >= 0 && k < i1 && l < i1 ? this.values[k][l] : this.noiseFiller.compute(p_209333_);
|
|
}
|
|
|
|
@Override
|
|
public void fillArray(double[] p_209335_, DensityFunction.ContextProvider p_209336_) {
|
|
p_209336_.fillAllDirectly(p_209335_, this);
|
|
}
|
|
|
|
@Override
|
|
public DensityFunction wrapped() {
|
|
return this.noiseFiller;
|
|
}
|
|
|
|
@Override
|
|
public DensityFunctions.Marker.Type type() {
|
|
return DensityFunctions.Marker.Type.FlatCache;
|
|
}
|
|
}
|
|
|
|
interface NoiseChunkDensityFunction extends DensityFunction {
|
|
DensityFunction wrapped();
|
|
|
|
@Override
|
|
default double minValue() {
|
|
return this.wrapped().minValue();
|
|
}
|
|
|
|
@Override
|
|
default double maxValue() {
|
|
return this.wrapped().maxValue();
|
|
}
|
|
}
|
|
|
|
public class NoiseInterpolator implements DensityFunctions.MarkerOrMarked, NoiseChunk.NoiseChunkDensityFunction {
|
|
double[][] slice0;
|
|
double[][] slice1;
|
|
private final DensityFunction noiseFiller;
|
|
private double noise000;
|
|
private double noise001;
|
|
private double noise100;
|
|
private double noise101;
|
|
private double noise010;
|
|
private double noise011;
|
|
private double noise110;
|
|
private double noise111;
|
|
private double valueXZ00;
|
|
private double valueXZ10;
|
|
private double valueXZ01;
|
|
private double valueXZ11;
|
|
private double valueZ0;
|
|
private double valueZ1;
|
|
private double value;
|
|
|
|
NoiseInterpolator(final DensityFunction p_209345_) {
|
|
this.noiseFiller = p_209345_;
|
|
this.slice0 = this.allocateSlice(NoiseChunk.this.cellCountY, NoiseChunk.this.cellCountXZ);
|
|
this.slice1 = this.allocateSlice(NoiseChunk.this.cellCountY, NoiseChunk.this.cellCountXZ);
|
|
NoiseChunk.this.interpolators.add(this);
|
|
}
|
|
|
|
private double[][] allocateSlice(int p_188855_, int p_188856_) {
|
|
int i = p_188856_ + 1;
|
|
int j = p_188855_ + 1;
|
|
double[][] adouble = new double[i][j];
|
|
|
|
for (int k = 0; k < i; k++) {
|
|
adouble[k] = new double[j];
|
|
}
|
|
|
|
return adouble;
|
|
}
|
|
|
|
void selectCellYZ(int p_188864_, int p_188865_) {
|
|
this.noise000 = this.slice0[p_188865_][p_188864_];
|
|
this.noise001 = this.slice0[p_188865_ + 1][p_188864_];
|
|
this.noise100 = this.slice1[p_188865_][p_188864_];
|
|
this.noise101 = this.slice1[p_188865_ + 1][p_188864_];
|
|
this.noise010 = this.slice0[p_188865_][p_188864_ + 1];
|
|
this.noise011 = this.slice0[p_188865_ + 1][p_188864_ + 1];
|
|
this.noise110 = this.slice1[p_188865_][p_188864_ + 1];
|
|
this.noise111 = this.slice1[p_188865_ + 1][p_188864_ + 1];
|
|
}
|
|
|
|
void updateForY(double p_188851_) {
|
|
this.valueXZ00 = Mth.lerp(p_188851_, this.noise000, this.noise010);
|
|
this.valueXZ10 = Mth.lerp(p_188851_, this.noise100, this.noise110);
|
|
this.valueXZ01 = Mth.lerp(p_188851_, this.noise001, this.noise011);
|
|
this.valueXZ11 = Mth.lerp(p_188851_, this.noise101, this.noise111);
|
|
}
|
|
|
|
void updateForX(double p_188862_) {
|
|
this.valueZ0 = Mth.lerp(p_188862_, this.valueXZ00, this.valueXZ10);
|
|
this.valueZ1 = Mth.lerp(p_188862_, this.valueXZ01, this.valueXZ11);
|
|
}
|
|
|
|
void updateForZ(double p_188867_) {
|
|
this.value = Mth.lerp(p_188867_, this.valueZ0, this.valueZ1);
|
|
}
|
|
|
|
@Override
|
|
public double compute(DensityFunction.FunctionContext p_209347_) {
|
|
if (p_209347_ != NoiseChunk.this) {
|
|
return this.noiseFiller.compute(p_209347_);
|
|
} else if (!NoiseChunk.this.interpolating) {
|
|
throw new IllegalStateException("Trying to sample interpolator outside the interpolation loop");
|
|
} else {
|
|
return NoiseChunk.this.fillingCell
|
|
? Mth.lerp3(
|
|
(double)NoiseChunk.this.inCellX / NoiseChunk.this.cellWidth,
|
|
(double)NoiseChunk.this.inCellY / NoiseChunk.this.cellHeight,
|
|
(double)NoiseChunk.this.inCellZ / NoiseChunk.this.cellWidth,
|
|
this.noise000,
|
|
this.noise100,
|
|
this.noise010,
|
|
this.noise110,
|
|
this.noise001,
|
|
this.noise101,
|
|
this.noise011,
|
|
this.noise111
|
|
)
|
|
: this.value;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void fillArray(double[] p_209349_, DensityFunction.ContextProvider p_209350_) {
|
|
if (NoiseChunk.this.fillingCell) {
|
|
p_209350_.fillAllDirectly(p_209349_, this);
|
|
} else {
|
|
this.wrapped().fillArray(p_209349_, p_209350_);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public DensityFunction wrapped() {
|
|
return this.noiseFiller;
|
|
}
|
|
|
|
private void swapSlices() {
|
|
double[][] adouble = this.slice0;
|
|
this.slice0 = this.slice1;
|
|
this.slice1 = adouble;
|
|
}
|
|
|
|
@Override
|
|
public DensityFunctions.Marker.Type type() {
|
|
return DensityFunctions.Marker.Type.Interpolated;
|
|
}
|
|
}
|
|
} |