This commit is contained in:
Daniel Mills 2020-10-25 23:07:13 -04:00
parent 460be03a20
commit 4a11ac917b
12 changed files with 564 additions and 19 deletions

View File

@ -1,6 +1,7 @@
package com.volmit.iris.command;
import com.volmit.iris.Iris;
import com.volmit.iris.gen.v2.TestGen;
import com.volmit.iris.util.Command;
import com.volmit.iris.util.MortarCommand;
import com.volmit.iris.util.MortarSender;
@ -58,11 +59,11 @@ public class CommandIris extends MortarCommand
@Override
public boolean handle(MortarSender sender, String[] args)
{
// if(args.length == 1 && args[0].equalsIgnoreCase("test!"))
// {
// TestGen.gen(sender.player());
// return true;
// }
if(args.length == 1 && args[0].equalsIgnoreCase("test!"))
{
TestGen.gen(sender.player());
return true;
}
sender.sendMessage("Iris v" + Iris.instance.getDescription().getVersion() + " by Volmit Software");
printHelp(sender);

View File

@ -1,10 +1,10 @@
package com.volmit.iris.gen.v2;
import org.bukkit.Material;
import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData;
import com.volmit.iris.Iris;
import com.volmit.iris.gen.layer.GenLayerBiome;
import com.volmit.iris.gen.v2.scaffold.layer.ProceduralStream;
import com.volmit.iris.gen.v2.scaffold.stream.Interpolated;
import com.volmit.iris.manager.IrisDataManager;
@ -36,7 +36,11 @@ public class IrisComplex implements DataProvider
private ProceduralStream<IrisBiome> shoreBiomeStream;
private ProceduralStream<IrisBiome> baseBiomeStream;
private ProceduralStream<IrisBiome> trueBiomeStream;
private ProceduralStream<Biome> trueBiomeDerivativeStream;
private ProceduralStream<Double> heightStream;
private ProceduralStream<Double> maxHeightStream;
private ProceduralStream<Double> overlayStream;
private ProceduralStream<Double> heightFluidStream;
private ProceduralStream<BlockData> terrainStream;
private ProceduralStream<BlockData> rockStream;
private ProceduralStream<BlockData> fluidStream;
@ -83,6 +87,8 @@ public class IrisComplex implements DataProvider
.getAllBiomes(this).forEach((b) -> b
.getGenerators()
.forEach((c) -> registerGenerator(c.getCachedGenerator(this)))));
overlayStream = ProceduralStream.ofDouble((x, z) -> 0D);
dimension.getOverlayNoise().forEach((i) -> overlayStream.add((x, z) -> i.get(rng, x, z)));
rockStream = dimension.getRockPalette().getLayerGenerator(rng.nextRNG(), data).stream()
.select(dimension.getRockPalette().getBlockData(data))
.convert((v) -> v.getBlockData());
@ -98,28 +104,32 @@ public class IrisComplex implements DataProvider
-> dimension.getCaveBiomeStyle().create(rng.nextRNG()).stream()
.zoom(r.getCaveBiomeZoom())
.selectRarity(r.getCaveBiomes())
.convertCached((s) -> data.getBiomeLoader().load(s))
.convertCached((s) -> data.getBiomeLoader().load(s)
.setInferredType(InferredType.CAVE))
).convertAware2D((str, x, z) -> str.get(x, z))
.cache2D(1024);
landBiomeStream = regionStream.convertCached((r)
-> dimension.getLandBiomeStyle().create(rng.nextRNG()).stream()
.zoom(r.getLandBiomeZoom())
.selectRarity(r.getLandBiomes())
.convertCached((s) -> data.getBiomeLoader().load(s))
.convertCached((s) -> data.getBiomeLoader().load(s)
.setInferredType(InferredType.LAND))
).convertAware2D((str, x, z) -> str.get(x, z))
.cache2D(1024);
seaBiomeStream = regionStream.convertCached((r)
-> dimension.getSeaBiomeStyle().create(rng.nextRNG()).stream()
.zoom(r.getSeaBiomeZoom())
.selectRarity(r.getSeaBiomes())
.convertCached((s) -> data.getBiomeLoader().load(s))
.convertCached((s) -> data.getBiomeLoader().load(s)
.setInferredType(InferredType.SEA))
).convertAware2D((str, x, z) -> str.get(x, z))
.cache2D(1024);
shoreBiomeStream = regionStream.convertCached((r)
-> dimension.getShoreBiomeStyle().create(rng.nextRNG()).stream()
.zoom(r.getShoreBiomeZoom())
.selectRarity(r.getShoreBiomes())
.convertCached((s) -> data.getBiomeLoader().load(s))
.convertCached((s) -> data.getBiomeLoader().load(s)
.setInferredType(InferredType.SHORE))
).convertAware2D((str, x, z) -> str.get(x, z))
.cache2D(1024);
bridgeStream = dimension.getContinentalStyle().create(rng.nextRNG()).stream()
@ -129,18 +139,28 @@ public class IrisComplex implements DataProvider
.convertAware2D(this::implode)
.cache2D(1024);
heightStream = baseBiomeStream.convertAware2D((b, x, z) -> getHeight(b, x, z, seed))
.forceDouble().add(fluidHeight).roundDouble()
.forceDouble().add(fluidHeight)
.add2D(overlayStream::get).roundDouble()
.cache2D(1024);
trueBiomeStream = heightStream
.convertAware2D((h, x, z) ->
fixBiomeType(h, baseBiomeStream.get(x, z),regionStream.get(x, z), x, z, fluidHeight))
fixBiomeType(h, baseBiomeStream.get(x, z),
regionStream.get(x, z), x, z, fluidHeight))
.cache2D(1024);
trueBiomeDerivativeStream = trueBiomeStream.convert((b) -> b.getDerivative());
heightFluidStream = heightStream.max(fluidHeight);
maxHeightStream = ProceduralStream.ofDouble((x, z) -> 255D);
terrainStream = ProceduralStream.of((x, y, z) -> {
double height = heightStream.get(x, z);
IrisBiome biome = trueBiomeStream.get(x, z);
int depth = (int) (Math.round(height) - y);
int atDepth = 0;
if(y > height && y <= fluidHeight)
{
return fluidStream.get(x, y, z);
}
if(depth < -1)
{
return AIR;
@ -210,7 +230,7 @@ public class IrisComplex implements DataProvider
{
double sh = region.getShoreHeight(x, z);
if(height > fluidHeight && height <= fluidHeight + sh && !biome.isShore())
if(height >= fluidHeight && height <= fluidHeight + sh && !biome.isShore())
{
return shoreBiomeStream.get(x, z);
}
@ -220,11 +240,16 @@ public class IrisComplex implements DataProvider
return landBiomeStream.get(x, z);
}
if(height <= fluidHeight && !biome.isAquatic())
if(height < fluidHeight && !biome.isAquatic())
{
return seaBiomeStream.get(x, z);
}
if(height == fluidHeight && !biome.isShore())
{
return shoreBiomeStream.get(x, z);
}
return biome;
}

View File

@ -3,23 +3,35 @@ package com.volmit.iris.gen.v2;
import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData;
import com.volmit.iris.Iris;
import com.volmit.iris.gen.v2.scaffold.Hunk;
import com.volmit.iris.gen.v2.scaffold.layer.ProceduralStream;
import com.volmit.iris.gen.v2.scaffold.multicore.MultiBurst;
import com.volmit.iris.manager.IrisDataManager;
import com.volmit.iris.object.IrisDimension;
import com.volmit.iris.util.KMap;
import com.volmit.iris.util.M;
import com.volmit.iris.util.PrecisionStopwatch;
import com.volmit.iris.util.RollingSequence;
public class IrisTerrainGenerator
{
private long seed;
private MultiBurst burster;
private IrisDataManager data;
private IrisDimension dimension;
private IrisComplex complex;
private int parallelism;
public IrisTerrainGenerator(long seed, IrisDimension dimension, IrisDataManager data)
{
this.seed = seed;
complex = new IrisComplex();
parallelism = 6;
burster = new MultiBurst((parallelism * parallelism) * 4);
this.data = data;
this.dimension = dimension;
flash();
}
@ -28,9 +40,50 @@ public class IrisTerrainGenerator
complex.flash(seed, dimension, data);
}
private <V, T> void fill2D(ProceduralStream<T> t, Hunk<V> h, double x, double z, ProceduralStream<V> v)
{
if(parallelism <= 1)
{
t.fill2D(h, x * 16, z * 16, v);
}
else
{
t.fill2DParallel(burster.burst(parallelism * parallelism), parallelism, h, x * 16, z * 16, v);
}
}
private <V, T> void fill2DYLock(ProceduralStream<T> t, Hunk<V> h, double x, double z, ProceduralStream<V> v)
{
if(parallelism <= 1)
{
t.fill2DYLocked(h, x * 16, z * 16, v);
}
else
{
t.fill2DParallelYLocked(burster.burst(parallelism * parallelism), parallelism, h, x * 16, z * 16, v);
}
}
public void generateTerrain(int x, int z, Hunk<BlockData> blocks)
{
PrecisionStopwatch p = PrecisionStopwatch.start();
fill2D(complex.getHeightFluidStream(), blocks, x, z, complex.getTerrainStream());
p.end();
}
public void generateBiome(int x, int z, Hunk<Biome> blocks)
{
PrecisionStopwatch p = PrecisionStopwatch.start();
fill2DYLock(complex.getMaxHeightStream(), blocks, x, z, complex.getTrueBiomeDerivativeStream());
p.end();
}
public void generate(int x, int z, Hunk<BlockData> blocks, Hunk<Biome> biomes)
{
// RNG rng = new RNG((((long) x) << 32) | (z & 0xffffffffL));
complex.getHeightStream().fill2D(blocks, x * 16, z * 16, complex.getTerrainStream());
generateTerrain(x, z, blocks);
generateBiome(x, z, biomes);
}
}

View File

@ -5,6 +5,7 @@ import java.util.UUID;
import org.bukkit.World;
import org.bukkit.WorldCreator;
import org.bukkit.block.Biome;
import org.bukkit.entity.Player;
import org.bukkit.generator.ChunkGenerator;
@ -31,7 +32,19 @@ public class TestGen
{
PrecisionStopwatch p = PrecisionStopwatch.start();
ChunkData c = createChunkData(world);
tg.generate(x, z, Hunk.view(c), null);
Hunk<Biome> b = Hunk.create(16, 256, 16);
tg.generate(x, z, Hunk.view(c), b);
for(int i = 0; i < 16; i++)
{
for(int j = 0; j < 256; j++)
{
for(int k = 0; k < 16; k++)
{
biome.setBiome(i, j, k, b.get(i, j, k));
}
}
}
Iris.info("Generated " + x + " " + z + " in " + Form.duration(p.getMilliseconds(), 2));
return c;

View File

@ -282,13 +282,13 @@ public class ArrayHunk<T> implements Hunk<T>
@Override
public int getDepth()
{
return h;
return d;
}
@Override
public int getHeight()
{
return d;
return h;
}
@Override

View File

@ -0,0 +1,156 @@
package com.volmit.iris.gen.v2.scaffold;
import org.bukkit.block.Biome;
import org.bukkit.generator.ChunkGenerator.BiomeGrid;
public class BiomeGridHunkView implements Hunk<Biome>
{
private final BiomeGrid chunk;
public BiomeGridHunkView(BiomeGrid chunk)
{
this.chunk = chunk;
}
@Override
public int getWidth()
{
return 16;
}
@Override
public int getDepth()
{
return 16;
}
@Override
public int getHeight()
{
return 256;
}
@Override
public Hunk<Biome> croppedView(int x1, int y1, int z1, int x2, int y2, int z2)
{
return new HunkView<Biome>(this, x2 - x1, y2 - y1, z2 - z1, x1, y1, z1);
}
@Override
public ArrayHunk<Biome> crop(int x1, int y1, int z1, int x2, int y2, int z2)
{
ArrayHunk<Biome> h = new ArrayHunk<Biome>(x2 - x1, y2 - y1, z2 - z1);
for(int i = x1; i < x2; i++)
{
for(int j = y1; j < y2; j++)
{
for(int k = z1; k < z2; k++)
{
h.set(i - x1, j - y1, k - z1, get(i, j, k));
}
}
}
return h;
}
@Override
public void insert(int offX, int offY, int offZ, Hunk<Biome> hunk, boolean invertY)
{
if(offX + (hunk.getWidth() - 1) >= getWidth() || offY + (hunk.getHeight() - 1) >= getHeight() || offZ + (hunk.getDepth() - 1) >= getDepth() || offX < 0 || offY < 0 || offZ < 0)
{
throw new RuntimeException("Cannot insert hunk " + hunk.getWidth() + "," + hunk.getHeight() + "," + hunk.getDepth() + " into Hunk " + getWidth() + "," + getHeight() + "," + getDepth() + " with offset " + offZ + "," + offY + "," + offZ);
}
for(int i = offX; i < offX + hunk.getWidth(); i++)
{
for(int j = offY; j < offY + hunk.getHeight(); j++)
{
for(int k = offZ; k < offZ + hunk.getDepth(); k++)
{
set(i, j, k, hunk.get(i - offX, j - offY, k - offZ));
}
}
}
}
@Override
public void set(int x, int y, int z, Biome t)
{
if(x >= getWidth() || y >= getHeight() || z >= getDepth())
{
throw new RuntimeException(x + " " + y + " " + z + " is out of the bounds 0,0,0 - " + (getWidth() - 1) + "," + (getHeight() - 1) + "," + (getDepth() - 1));
}
chunk.setBiome(x, y, z, t);
}
@Override
public Biome get(int x, int y, int z)
{
if(x >= getWidth() || y >= getHeight() || z >= getDepth())
{
throw new RuntimeException(x + " " + y + " " + z + " is out of the bounds 0,0,0 - " + (getWidth() - 1) + "," + (getHeight() - 1) + "," + (getDepth() - 1));
}
return chunk.getBiome(x, y, z);
}
@Override
public Biome getClosest(int x, int y, int z)
{
return chunk.getBiome(x >= getWidth() ? getWidth() + 1 : x, y >= getHeight() ? getHeight() - 1 : y, z >= getDepth() ? getDepth() - 1 : z);
}
@Override
public void fill(Biome t)
{
set(0, 0, 0, getWidth(), getHeight(), getDepth(), t);
}
@Override
public Hunk<Biome> getFace(HunkFace f)
{
switch(f)
{
case BOTTOM:
return croppedView(0, 0, 0, getWidth() - 1, 0, getDepth() - 1);
case EAST:
return croppedView(getWidth() - 1, 0, 0, getWidth() - 1, getHeight() - 1, getDepth() - 1);
case NORTH:
return croppedView(0, 0, 0, getWidth() - 1, getHeight() - 1, 0);
case SOUTH:
return croppedView(0, 0, 0, 0, getHeight() - 1, getDepth() - 1);
case TOP:
return croppedView(0, getHeight() - 1, 0, getWidth() - 1, getHeight() - 1, getDepth() - 1);
case WEST:
return croppedView(0, 0, getDepth() - 1, getWidth() - 1, getHeight() - 1, getDepth() - 1);
default:
break;
}
return null;
}
@Override
public Hunk<Biome> getSource()
{
return null;
}
@Override
public void set(int x1, int y1, int z1, int x2, int y2, int z2, Biome t)
{
for(int i = x1; i <= x2; i++)
{
for(int j = y1; j <= y2; j++)
{
for(int k = z1; k <= z2; k++)
{
set(i, j, k, t);
}
}
}
}
}

View File

@ -1,6 +1,8 @@
package com.volmit.iris.gen.v2.scaffold;
import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData;
import org.bukkit.generator.ChunkGenerator.BiomeGrid;
import org.bukkit.generator.ChunkGenerator.ChunkData;
public interface Hunk<T>
@ -15,6 +17,11 @@ public interface Hunk<T>
return new HunkView<T>(src);
}
public static Hunk<Biome> view(BiomeGrid biome)
{
return new BiomeGridHunkView(biome);
}
public static Hunk<BlockData> view(ChunkData src)
{
return new ChunkDataHunkView(src);
@ -93,7 +100,7 @@ public interface Hunk<T>
*/
default void insert(int offX, int offY, int offZ, Hunk<T> hunk)
{
insert(0, 0, 0, hunk, false);
insert(offX, offY, offZ, hunk, false);
}
/**

View File

@ -5,6 +5,7 @@ import java.util.function.Function;
import com.volmit.iris.gen.v2.scaffold.Hunk;
import com.volmit.iris.gen.v2.scaffold.Significance;
import com.volmit.iris.gen.v2.scaffold.multicore.BurstExecutor;
import com.volmit.iris.gen.v2.scaffold.stream.AddingStream;
import com.volmit.iris.gen.v2.scaffold.stream.AwareConversionStream2D;
import com.volmit.iris.gen.v2.scaffold.stream.AwareConversionStream3D;
@ -17,6 +18,8 @@ import com.volmit.iris.gen.v2.scaffold.stream.FittedStream;
import com.volmit.iris.gen.v2.scaffold.stream.ForceDoubleStream;
import com.volmit.iris.gen.v2.scaffold.stream.FunctionStream;
import com.volmit.iris.gen.v2.scaffold.stream.Interpolated;
import com.volmit.iris.gen.v2.scaffold.stream.MaxingStream;
import com.volmit.iris.gen.v2.scaffold.stream.MinningStream;
import com.volmit.iris.gen.v2.scaffold.stream.ModuloStream;
import com.volmit.iris.gen.v2.scaffold.stream.MultiplyingStream;
import com.volmit.iris.gen.v2.scaffold.stream.OffsetStream;
@ -70,11 +73,46 @@ public interface ProceduralStream<T> extends ProceduralLayer, Interpolated<T>
return new AddingStream<>(this, a);
}
default ProceduralStream<T> add2D(Function2<Double, Double, Double> a)
{
return new AddingStream<>(this, a);
}
default ProceduralStream<T> add(double a)
{
return new AddingStream<>(this, a);
}
default ProceduralStream<T> max(Function3<Double, Double, Double, Double> a)
{
return new MaxingStream<>(this, a);
}
default ProceduralStream<T> max(Function2<Double, Double, Double> a)
{
return new MaxingStream<>(this, a);
}
default ProceduralStream<T> max(double a)
{
return new MaxingStream<>(this, a);
}
default ProceduralStream<T> min(Function3<Double, Double, Double, Double> a)
{
return new MinningStream<>(this, a);
}
default ProceduralStream<T> min(Function2<Double, Double, Double> a)
{
return new MinningStream<>(this, a);
}
default ProceduralStream<T> min(double a)
{
return new MinningStream<>(this, a);
}
default ProceduralStream<T> subtract(Function3<Double, Double, Double, Double> a)
{
return new SubtractingStream<>(this, a);
@ -340,6 +378,80 @@ public interface ProceduralStream<T> extends ProceduralLayer, Interpolated<T>
}
}
default <V> void fill2DYLocked(Hunk<V> h, double x, double z, ProceduralStream<V> v)
{
for(int i = 0; i < h.getWidth(); i++)
{
for(int k = 0; k < h.getDepth(); k++)
{
double n = getDouble(i + x, k + z);
V yy = v.get(i + x, k + z);
for(int j = 0; j < Math.min(h.getHeight(), n); j++)
{
h.set(i, j, k, yy);
}
}
}
}
default <V> void fill2DParallel(BurstExecutor burster, int parallelismRooted, Hunk<V> h, double x, double z, ProceduralStream<V> v)
{
parallelismRooted = parallelismRooted % 2 != 0 ? parallelismRooted + 1 : parallelismRooted;
KList<Runnable> future = new KList<>();
int w = h.getWidth() / parallelismRooted;
int d = h.getDepth() / parallelismRooted;
int i, j;
for(i = 0; i < h.getWidth(); i += w)
{
int ii = i;
for(j = 0; j < h.getDepth(); j += d)
{
int jj = j;
Hunk<V> mh = h.crop(i, 0, j, i + w, h.getHeight(), j + d);
burster.queue(() -> fill2D(mh, x + ii, z + jj, v));
future.add(() -> h.insert(ii, 0, jj, mh));
}
}
burster.complete();
for(Runnable vx : future)
{
vx.run();
}
}
default <V> void fill2DParallelYLocked(BurstExecutor burster, int parallelismRooted, Hunk<V> h, double x, double z, ProceduralStream<V> v)
{
parallelismRooted = parallelismRooted % 2 != 0 ? parallelismRooted + 1 : parallelismRooted;
KList<Runnable> future = new KList<>();
int w = h.getWidth() / parallelismRooted;
int d = h.getDepth() / parallelismRooted;
int i, j;
for(i = 0; i < h.getWidth(); i += w)
{
int ii = i;
for(j = 0; j < h.getDepth(); j += d)
{
int jj = j;
Hunk<V> mh = h.crop(i, 0, j, i + w, h.getHeight(), j + d);
burster.queue(() -> fill2DYLocked(mh, x + ii, z + jj, v));
future.add(() -> h.insert(ii, 0, jj, mh));
}
}
burster.complete();
for(Runnable vx : future)
{
vx.run();
}
}
public T get(double x, double z);
public T get(double x, double y, double z);

View File

@ -0,0 +1,46 @@
package com.volmit.iris.gen.v2.scaffold.multicore;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import com.volmit.iris.util.KList;
public class BurstExecutor
{
private ExecutorService executor;
private KList<CompletableFuture<Void>> futures;
public BurstExecutor(ExecutorService executor, int burstSizeEstimate)
{
this.executor = executor;
futures = new KList<CompletableFuture<Void>>(burstSizeEstimate);
}
public CompletableFuture<Void> queue(Runnable r)
{
synchronized(futures)
{
CompletableFuture<Void> c = CompletableFuture.runAsync(r, executor);
futures.add(c);
return c;
}
}
public void complete()
{
synchronized(futures)
{
try
{
CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()])).get();
futures.clear();
}
catch(InterruptedException | ExecutionException e)
{
e.printStackTrace();
}
}
}
}

View File

@ -0,0 +1,24 @@
package com.volmit.iris.gen.v2.scaffold.multicore;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MultiBurst
{
private ExecutorService service;
public MultiBurst(int tc)
{
service = Executors.newWorkStealingPool(tc);
}
public BurstExecutor burst(int estimate)
{
return new BurstExecutor(service, estimate);
}
public BurstExecutor burst()
{
return burst(16);
}
}

View File

@ -0,0 +1,54 @@
package com.volmit.iris.gen.v2.scaffold.stream;
import com.volmit.iris.gen.v2.scaffold.layer.BasicLayer;
import com.volmit.iris.gen.v2.scaffold.layer.ProceduralStream;
import com.volmit.iris.util.Function2;
import com.volmit.iris.util.Function3;
public class MaxingStream<T> extends BasicLayer implements ProceduralStream<T>
{
private final ProceduralStream<T> stream;
private final Function3<Double, Double, Double, Double> add;
public MaxingStream(ProceduralStream<T> stream, Function3<Double, Double, Double, Double> add)
{
super();
this.stream = stream;
this.add = add;
}
public MaxingStream(ProceduralStream<T> stream, Function2<Double, Double, Double> add)
{
this(stream, (x, y, z) -> add.apply(x, z));
}
public MaxingStream(ProceduralStream<T> stream, double add)
{
this(stream, (x, y, z) -> add);
}
@Override
public double toDouble(T t)
{
return stream.toDouble(t);
}
@Override
public T fromDouble(double d)
{
return stream.fromDouble(d);
}
@Override
public T get(double x, double z)
{
return fromDouble(Math.max(add.apply(x, 0D, z), stream.getDouble(x, z)));
}
@Override
public T get(double x, double y, double z)
{
return fromDouble(Math.max(add.apply(x, y, z), stream.getDouble(x, y, z)));
}
}

View File

@ -0,0 +1,54 @@
package com.volmit.iris.gen.v2.scaffold.stream;
import com.volmit.iris.gen.v2.scaffold.layer.BasicLayer;
import com.volmit.iris.gen.v2.scaffold.layer.ProceduralStream;
import com.volmit.iris.util.Function2;
import com.volmit.iris.util.Function3;
public class MinningStream<T> extends BasicLayer implements ProceduralStream<T>
{
private final ProceduralStream<T> stream;
private final Function3<Double, Double, Double, Double> add;
public MinningStream(ProceduralStream<T> stream, Function3<Double, Double, Double, Double> add)
{
super();
this.stream = stream;
this.add = add;
}
public MinningStream(ProceduralStream<T> stream, Function2<Double, Double, Double> add)
{
this(stream, (x, y, z) -> add.apply(x, z));
}
public MinningStream(ProceduralStream<T> stream, double add)
{
this(stream, (x, y, z) -> add);
}
@Override
public double toDouble(T t)
{
return stream.toDouble(t);
}
@Override
public T fromDouble(double d)
{
return stream.fromDouble(d);
}
@Override
public T get(double x, double z)
{
return fromDouble(Math.min(add.apply(x, 0D, z), stream.getDouble(x, z)));
}
@Override
public T get(double x, double y, double z)
{
return fromDouble(Math.min(add.apply(x, y, z), stream.getDouble(x, y, z)));
}
}