diff --git a/src/main/java/carpet/script/Expression.java b/src/main/java/carpet/script/Expression.java index e1008165..cc275fa7 100644 --- a/src/main/java/carpet/script/Expression.java +++ b/src/main/java/carpet/script/Expression.java @@ -2732,6 +2732,30 @@ public class Expression * map(range(10), str('%.1f',rand(_))) => [0.0, 0.4, 0.6, 1.9, 2.8, 3.8, 5.3, 2.2, 1.6, 5.6] * * + *
perlin(x), perlin(x,y), perlin(x,y,z), perlin(x,y,z,seed)returns a noise value from 0.0 to 1.0 (roughly) for 1, 2 or 3 dimensional coordinate. The default seed it samples from is 0, but seed can be
+ * specified as a 4th argument as well. In case you need 1D or 2D noise values with custom seed, use null
+ * for z, or y and z arguments respectively.
Perlin noise is based on a square grid and generates rougher maps comparing to Simplex, which is creamier, + * but the in-game implementation allows to sample up to 3D noise. Querying for lower-dimensional result, rather than + * affixing unused dimensions to constants has a speed benefit, + *
+ *Thou shall not sample from noise changing seed frequently. Scarpet will keep track of the last 256 perlin seeds used for sampling
+ * providing similar speed comparing to the default seed of 0. In case the app engine uses more than 256 seeds at the same time,
+ * switching between them can get much more expensive.
simplex(x,y), simplex(x,y,seed)returns a noise value from 0.0 to 1.0 (roughly) for 2 dimensional coordinate.
+ * The default seed it samples from is 0, but seed can be
+ * specified as a 3rd argument as well
Simplex noise is based on a triangular grid and generates smoother maps comparing to Perlin, + * but the in-game implementation only allows to sample 2D noise. To sample 1D simplex noise, affix other coordinate + * to a constant. + *
+ *Thou shall not sample from noise changing seed frequently. Scarpet will keep track of the last 256 simplex seeds used for sampling
+ * providing similar speed comparing to the default seed of 0. In case the app engine uses more than 256 seeds at the same time,
+ * switching between them can get much more expensive.
print(expr)prints the value of the expression to chat.
* Passes the result of the argument to the output unchanged, so print-statements can
@@ -2975,46 +2999,60 @@ public class Expression
return (cc, tt) -> retval;
});
- addLazyFunction("perlin", 3, (c, t, lv) -> {
- // add seed cache
- Value ret;
- Value x = lv.get(0).evalValue(c);
- Value y = lv.get(1).evalValue(c);
- Value z = lv.get(2).evalValue(c);
+ addLazyFunction("perlin", -1, (c, t, lv) -> {
+ PerlinNoiseSampler sampler;
+ Value x, y, z;
- if (z instanceof NullValue)
+ if (lv.size() >= 4)
{
- if (y instanceof NullValue)
- {
- ret = new NumericValue(PerlinNoiseSampler.instance.sample1d(
- NumericValue.asNumber(x).getDouble()
- ));
- }
- else
- {
- ret = new NumericValue(PerlinNoiseSampler.instance.sample2d(
- NumericValue.asNumber(x).getDouble(),
- NumericValue.asNumber(y).getDouble()
- ));
- }
+ x = lv.get(0).evalValue(c);
+ y = lv.get(1).evalValue(c);
+ z = lv.get(2).evalValue(c);
+ sampler = PerlinNoiseSampler.getPerlin(NumericValue.asNumber(lv.get(3).evalValue(c)).getLong());
}
else
{
- ret = new NumericValue(PerlinNoiseSampler.instance.sample3d(
+ sampler = PerlinNoiseSampler.instance;
+ y = Value.NULL;
+ z = Value.NULL;
+ if (lv.size() == 0 )
+ throw new InternalExpressionException("'perlin' requires at least one dimension to sample from");
+ x = NumericValue.asNumber(lv.get(0).evalValue(c));
+ if (lv.size() > 1)
+ {
+ y = NumericValue.asNumber(lv.get(1).evalValue(c));
+ if (lv.size() > 2)
+ z = NumericValue.asNumber(lv.get(2).evalValue(c));
+ }
+ }
+
+ double result;
+
+ if (z instanceof NullValue)
+ if (y instanceof NullValue)
+ result = sampler.sample1d(NumericValue.asNumber(x).getDouble());
+ else
+ result = sampler.sample2d(NumericValue.asNumber(x).getDouble(), NumericValue.asNumber(y).getDouble());
+ else
+ result = sampler.sample3d(
NumericValue.asNumber(x).getDouble(),
NumericValue.asNumber(y).getDouble(),
- NumericValue.asNumber(z).getDouble()
- ));
- }
+ NumericValue.asNumber(z).getDouble());
+ Value ret = new NumericValue(result);
return (cc, tt) -> ret;
});
- addLazyFunction("simplex", 2, (c, t, lv) -> {
- // add seed cache
+ addLazyFunction("simplex", -1, (c, t, lv) -> {
+ SimplexNoiseSampler sampler;
+ if (lv.size() == 2)
+ sampler = SimplexNoiseSampler.instance;
+ else if (lv.size() == 3)
+ sampler = SimplexNoiseSampler.getSimplex(NumericValue.asNumber(lv.get(2).evalValue(c)).getLong());
+ else
+ throw new InternalExpressionException("'simplex' requires two or three arguments");
double x = NumericValue.asNumber(lv.get(0).evalValue(c)).getDouble();
double y = NumericValue.asNumber(lv.get(1).evalValue(c)).getDouble();
- //double z = NumericValue.asNumber(lv.get(2).evalValue(c)).getDouble();
- Value value = new NumericValue(SimplexNoiseSampler.instance.sample(x,y));
+ Value value = new NumericValue(sampler.sample(x,y));
return (cc, tt) -> value;
});
diff --git a/src/main/java/carpet/script/utils/PerlinNoiseSampler.java b/src/main/java/carpet/script/utils/PerlinNoiseSampler.java
index 300df75c..c57973d9 100644
--- a/src/main/java/carpet/script/utils/PerlinNoiseSampler.java
+++ b/src/main/java/carpet/script/utils/PerlinNoiseSampler.java
@@ -1,7 +1,11 @@
package carpet.script.utils;
+import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
+
+import java.util.Map;
import java.util.Random;
+// extracted from import net.minecraft.util.math.noise.PerlinNoiseSampler
public class PerlinNoiseSampler {
protected static final int[][] gradients3d = new int[][]{
{1, 1, 0}, {-1, 1, 0}, {1, -1, 0}, {-1, -1, 0},
@@ -17,6 +21,14 @@ public class PerlinNoiseSampler {
public final double originY;
public final double originZ;
public static PerlinNoiseSampler instance = new PerlinNoiseSampler(new Random(0));
+ public static Map