diff --git a/src/main/java/carpet/script/CarpetExpression.java b/src/main/java/carpet/script/CarpetExpression.java index 7ec510d4..24ecf6b7 100644 --- a/src/main/java/carpet/script/CarpetExpression.java +++ b/src/main/java/carpet/script/CarpetExpression.java @@ -102,6 +102,7 @@ import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.ChunkStatus; import net.minecraft.world.chunk.WorldChunk; import net.minecraft.world.dimension.DimensionType; +import net.minecraft.world.gen.ChunkRandom; import net.minecraft.world.loot.context.LootContext; import net.minecraft.world.loot.context.LootContextParameters; import org.apache.commons.lang3.tuple.Pair; @@ -607,6 +608,8 @@ public class CarpetExpression *
Numeric function, indicating hardness of a block.
*blast_resistance(pos)Numeric function, indicating blast_resistance of a block.
+ *in_slime_chunk(pos)Boolean indicating if the given block position is in a slime chunk.
*top(type, pos)Returns the Y value of the topmost block at given x, z coords (y value of a block is not important), according to the @@ -623,7 +626,7 @@ public class CarpetExpression * top('ocean_floor', x, y, z) => 41 * *
loaded(pos)Boolean function, true if the block is accessible forthe game mechanics. + *
Boolean function, true if the block is accessible for the game mechanics.
* Normally scarpet doesn't check if operates on
* loaded area - the game will automatically load missing blocks. We see this as advantage.
* Vanilla fill/clone commands only check the specified corners for loadness.
seed()Returns current world seed.
*current_dimension()Returns current dimension that the script runs in.
*in_dimension(smth, expr)rand(expr)rand(expr), rand(expr, seed)returns a random number from 0.0
* (inclusive) to expr (exclusive).
* In boolean context (in conditions, boolean functions, or bool), returns
* false if the randomly selected value is less than 1. This means that rand(2) returns true half
- * of the time and rand(5) returns true for 80% (4/5) of the time
rand(5) returns true for 80% (4/5) of the time. If seed is not provided, uses a random seed.
+ * If seed is provided, each consecutive call to rand() will act like 'next' call to the same random object.
+ * Scarpet keeps track of up to 1024 custom random number generators, so if you exceed this number (per app), then your
+ * random sequence will revert to the beginning.
*
* map(range(10), floor(rand(10))) => [5, 8, 0, 6, 9, 3, 9, 9, 1, 8]
* map(range(10), bool(rand(2))) => [1, 1, 1, 0, 0, 1, 1, 0, 0, 0]
@@ -2982,7 +2985,12 @@ public class Expression
addUnaryFunction("type", v -> new StringValue(v.getTypeString()));
addUnaryFunction("length", v -> new NumericValue(v.length()));
- addLazyFunction("rand", 1, (c, t, lv) -> {
+ addLazyFunction("rand", -1, (c, t, lv) -> {
+ int argsize = lv.size();
+ Random randomizer = Expression.randomizer;
+ if (argsize != 1 && argsize != 2)
+ throw new InternalExpressionException("'rand' takes one (range) or two arguments (range and seed)");
+ if (argsize == 2) randomizer = c.host.getRandom(NumericValue.asNumber(lv.get(1).evalValue(c)).getLong());
Value argument = lv.get(0).evalValue(c);
if (argument instanceof ListValue)
{
diff --git a/src/main/java/carpet/script/ScriptHost.java b/src/main/java/carpet/script/ScriptHost.java
index ad2ba58f..63ef1dc2 100644
--- a/src/main/java/carpet/script/ScriptHost.java
+++ b/src/main/java/carpet/script/ScriptHost.java
@@ -4,11 +4,13 @@ import carpet.script.bundled.Module;
import carpet.script.exception.InternalExpressionException;
import carpet.script.value.FunctionValue;
import carpet.script.value.Value;
+import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.stream.Stream;
@@ -16,6 +18,14 @@ import java.util.stream.Stream;
public abstract class ScriptHost
{
public static Map systemGlobals = new ConcurrentHashMap<>();
+ private static Map randomizers = new Long2ObjectOpenHashMap<>();
+
+ public Random getRandom(long aLong)
+ {
+ if (randomizers.size() > 1024)
+ randomizers.clear();
+ return randomizers.computeIfAbsent(aLong, Random::new);
+ }
public static class ModuleData