diff --git a/docs/scarpet/Full.md b/docs/scarpet/Full.md index f7a4941b..0dac5b15 100644 --- a/docs/scarpet/Full.md +++ b/docs/scarpet/Full.md @@ -976,16 +976,17 @@ and maps, where the iterator returns all the map keys ### `break(), break(expr), continue(), continue(expr)` These allow to control execution of a loop either skipping current iteration code, using `continue`, or finishing the -current loop, using `break`. `break` and `continue` can only be used inside `for, while, loop, map, filter and reduce` +current loop, using `break`. `break` and `continue` can only be used inside `for`, `c_for`, `while`, `loop`, `map`, +`filter`, `reduce` as well as Minecraft API block loops, `scan` and `volume` functions, while `break` can be used in `first` as well. Outside of the internal expressions of these functions, -calling `break` or `continue` will cause an error. In case of the nexted loops, and more complex setups, use +calling `break` or `continue` will cause an error. In case of the nested loops, and more complex setups, use custom `try` and `throw` setup. Please check corresponding loop function description what `continue` and `break` do in their contexts, but in general case, passed values to `break` and `continue` will be used in place of the return value of the internal iteration expression. -### `cfor(init, condition, increment, body)` +### `c_for(init, condition, increment, body)` `c_for` Mimics c-style tri-arg (plus body) for loops. Return value of `c_for` is number of iterations performed in the loop. Unlike other loops, the `body` is not provided with pre-initialized `_` style variables - all initialization @@ -2073,11 +2074,19 @@ Evaluates expression over area of blocks defined by its center (`cx, cy, cz`), e by `dx, dy, dz` blocks, or optionally in negative with `d` coords, and `p` coords in positive values. `expr` receives `_x, _y, _z` as coords of current analyzed block and `_`, which represents the block itself. +Returns number of successful evaluations of `expr` (with `true` boolean result) unless called in void context, +which would cause the expression not be evaluated for their boolean value. + +`scan` also handles `continue` and `break` statements, using `continue`'s return value to use in place of expression +return value. `break` return value has no effect. + ### `volume(x1, y1, z1, x2, y2, z2, expr)` Evaluates expression for each block in the area, the same as the `scan`function, but using two opposite corners of the rectangular cuboid. Any corners can be specified, its like you would do with `/fill` command. +For return value and handling `break` and `continue` statements, see `scan` function above. + ### `neighbours(x, y, z), neighbours(block), neighbours(l(x,y,z))` Returns the list of 6 neighbouring blocks to the argument. Commonly used with other loop functions like `for`. @@ -2747,6 +2756,32 @@ used to display current events and bounded functions. use `add_to` ro register n unbind a specific function from an event. Function to be bounded to an event needs to have the same number of parameters as the action is attempting to bind to (see list above). All calls in modules loaded via `/script load` that have functions listed above will be automatically bounded and unbounded when script is unloaded. +# Scoreboard + +### `scoreboard()`, `scoreboard(objective)`, `scoreboard(objective, key)`, `scoreboard(objective, key, value)` + +Displays or modifies individual scoreboard values. With no arguments, returns the list of current objectives. +With specified `objective`, lists all keys (players) associated with current objective. With specified `objective`, +`key`, returns current value of the objective for a given player (key). With additional `value` sets a new scoreboard + value, returning previous value associated with the `key`. + +### `scoreboard_add(objective, criterion?)` + +Adds a new objective to scoreboard. If `criterion` is not specified, assumes `'dummy'`. Returns `false` if objective +already existed, `true` otherwise. + +
+scoreboard_add('counter')
+scoreboard_add('lvl','level')
+
+
+### `scoreboard_remove(objective)`
+
+Removes an objective. Returns `true` if objective has existed and has been removed.
+
+### `scoreboard_display(objective, place)`
+
+sets display location for a specified `objective`. If `place` is `null`, then display is cleared.
# Auxiliary aspects
Collection of other methods that control smaller, yet still important aspects of the game
diff --git a/docs/scarpet/api/BlockIterations.md b/docs/scarpet/api/BlockIterations.md
index 304815cf..4f2085ff 100644
--- a/docs/scarpet/api/BlockIterations.md
+++ b/docs/scarpet/api/BlockIterations.md
@@ -8,11 +8,19 @@ Evaluates expression over area of blocks defined by its center (`cx, cy, cz`), e
by `dx, dy, dz` blocks, or optionally in negative with `d` coords, and `p` coords in positive values. `expr`
receives `_x, _y, _z` as coords of current analyzed block and `_`, which represents the block itself.
+Returns number of successful evaluations of `expr` (with `true` boolean result) unless called in void context,
+which would cause the expression not be evaluated for their boolean value.
+
+`scan` also handles `continue` and `break` statements, using `continue`'s return value to use in place of expression
+return value. `break` return value has no effect.
+
### `volume(x1, y1, z1, x2, y2, z2, expr)`
Evaluates expression for each block in the area, the same as the `scan`function, but using two opposite corners of
the rectangular cuboid. Any corners can be specified, its like you would do with `/fill` command.
+For return value and handling `break` and `continue` statements, see `scan` function above.
+
### `neighbours(x, y, z), neighbours(block), neighbours(l(x,y,z))`
Returns the list of 6 neighbouring blocks to the argument. Commonly used with other loop functions like `for`.
diff --git a/docs/scarpet/api/Scoreboard.md b/docs/scarpet/api/Scoreboard.md
new file mode 100644
index 00000000..5e64285b
--- /dev/null
+++ b/docs/scarpet/api/Scoreboard.md
@@ -0,0 +1,26 @@
+# Scoreboard
+
+### `scoreboard()`, `scoreboard(objective)`, `scoreboard(objective, key)`, `scoreboard(objective, key, value)`
+
+Displays or modifies individual scoreboard values. With no arguments, returns the list of current objectives.
+With specified `objective`, lists all keys (players) associated with current objective. With specified `objective`,
+`key`, returns current value of the objective for a given player (key). With additional `value` sets a new scoreboard
+ value, returning previous value associated with the `key`.
+
+### `scoreboard_add(objective, criterion?)`
+
+Adds a new objective to scoreboard. If `criterion` is not specified, assumes `'dummy'`. Returns `false` if objective
+already existed, `true` otherwise.
+
+
+scoreboard_add('counter')
+scoreboard_add('lvl','level')
+
+
+### `scoreboard_remove(objective)`
+
+Removes an objective. Returns `true` if objective has existed and has been removed.
+
+### `scoreboard_display(objective, place)`
+
+sets display location for a specified `objective`. If `place` is `null`, then display is cleared.
diff --git a/docs/scarpet/language/LoopsAndHigherOrderFunctions.md b/docs/scarpet/language/LoopsAndHigherOrderFunctions.md
index 65dc2715..82fdacd3 100644
--- a/docs/scarpet/language/LoopsAndHigherOrderFunctions.md
+++ b/docs/scarpet/language/LoopsAndHigherOrderFunctions.md
@@ -10,16 +10,17 @@ and maps, where the iterator returns all the map keys
### `break(), break(expr), continue(), continue(expr)`
These allow to control execution of a loop either skipping current iteration code, using `continue`, or finishing the
-current loop, using `break`. `break` and `continue` can only be used inside `for, while, loop, map, filter and reduce`
+current loop, using `break`. `break` and `continue` can only be used inside `for`, `c_for`, `while`, `loop`, `map`,
+`filter`, `reduce` as well as Minecraft API block loops, `scan` and `volume`
functions, while `break` can be used in `first` as well. Outside of the internal expressions of these functions,
-calling `break` or `continue` will cause an error. In case of the nexted loops, and more complex setups, use
+calling `break` or `continue` will cause an error. In case of the nested loops, and more complex setups, use
custom `try` and `throw` setup.
Please check corresponding loop function description what `continue` and `break` do in their contexts, but in
general case, passed values to `break` and `continue` will be used in place of the return value of the internal
iteration expression.
-### `cfor(init, condition, increment, body)`
+### `c_for(init, condition, increment, body)`
`c_for` Mimics c-style tri-arg (plus body) for loops. Return value of `c_for` is number of iterations performed in the
loop. Unlike other loops, the `body` is not provided with pre-initialized `_` style variables - all initialization
diff --git a/mergedoc.bat b/mergedoc.bat
index ad269be7..16559437 100644
--- a/mergedoc.bat
+++ b/mergedoc.bat
@@ -1,2 +1,2 @@
-cat docs/scarpet/language/Overview.md docs/scarpet/language/VariablesAndConstants.md docs/scarpet/language/Operators.md docs/scarpet/language/Math.md docs/scarpet/language/SystemFunctions.md docs/scarpet/language/LoopsAndHigherOrderFunctions.md docs/scarpet/language/FunctionsAndControlFlow.md docs/scarpet/language/Containers.md docs/scarpet/api/Overview.md docs/scarpet/api/BlocksAndWorldAccess.md docs/scarpet/api/BlockIterations.md docs/scarpet/api/Entities.md docs/scarpet/api/Inventories.md docs/scarpet/api/Events.md docs/scarpet/api/Auxiliary.md docs/scarpet/api/ScriptCommand.md > docs/scarpet/Full.md
+cat docs/scarpet/language/Overview.md docs/scarpet/language/VariablesAndConstants.md docs/scarpet/language/Operators.md docs/scarpet/language/Math.md docs/scarpet/language/SystemFunctions.md docs/scarpet/language/LoopsAndHigherOrderFunctions.md docs/scarpet/language/FunctionsAndControlFlow.md docs/scarpet/language/Containers.md docs/scarpet/api/Overview.md docs/scarpet/api/BlocksAndWorldAccess.md docs/scarpet/api/BlockIterations.md docs/scarpet/api/Entities.md docs/scarpet/api/Inventories.md docs/scarpet/api/Events.md docs/scarpet/api/Scoreboard.md docs/scarpet/api/Auxiliary.md docs/scarpet/api/ScriptCommand.md > docs/scarpet/Full.md
diff --git a/src/main/java/carpet/mixins/PistonBlockEntity_movableTEMixin.java b/src/main/java/carpet/mixins/PistonBlockEntity_movableTEMixin.java
index 1c261eb5..66d1db90 100644
--- a/src/main/java/carpet/mixins/PistonBlockEntity_movableTEMixin.java
+++ b/src/main/java/carpet/mixins/PistonBlockEntity_movableTEMixin.java
@@ -111,7 +111,7 @@ public abstract class PistonBlockEntity_movableTEMixin extends BlockEntity imple
else
blockState_2 = Block.getRenderingState(this.pushedBlock, this.world, this.pos);
((WorldInterface) (this.world)).setBlockStateWithBlockEntity(this.pos, blockState_2, this.carriedBlockEntity, 3);
- this.world.breakBlock(this.pos, true, null);
+ this.world.breakBlock(this.pos, false, null);
}
}
diff --git a/src/main/java/carpet/script/CarpetExpression.java b/src/main/java/carpet/script/CarpetExpression.java
index 8b94e8b3..ccfaaa71 100644
--- a/src/main/java/carpet/script/CarpetExpression.java
+++ b/src/main/java/carpet/script/CarpetExpression.java
@@ -11,11 +11,13 @@ import carpet.mixins.PointOfInterest_scarpetMixin;
import carpet.mixins.ServerChunkManager_scarpetMixin;
import carpet.script.Fluff.TriFunction;
import carpet.script.bundled.Module;
+import carpet.CarpetSettings;
+import carpet.script.exception.BreakStatement;
import carpet.script.exception.CarpetExpressionException;
+import carpet.script.exception.ContinueStatement;
import carpet.script.exception.ExitStatement;
import carpet.script.exception.ExpressionException;
import carpet.script.exception.InternalExpressionException;
-import carpet.CarpetSettings;
import carpet.script.value.BlockValue;
import carpet.script.value.EntityValue;
import carpet.script.value.FunctionValue;
@@ -73,6 +75,10 @@ import net.minecraft.nbt.StringTag;
import net.minecraft.nbt.Tag;
import net.minecraft.particle.ParticleEffect;
import net.minecraft.predicate.entity.EntityPredicates;
+import net.minecraft.scoreboard.Scoreboard;
+import net.minecraft.scoreboard.ScoreboardCriterion;
+import net.minecraft.scoreboard.ScoreboardObjective;
+import net.minecraft.scoreboard.ScoreboardPlayerScore;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity;
@@ -1254,6 +1260,119 @@ public class CarpetExpression
}
+ public void API_Scoreboard()
+ {
+ // scoreboard(player,'objective')
+ // scoreboard(player, objective, newValue)
+ this.expr.addLazyFunction("scoreboard", -1, (c, t, lv) ->
+ {
+ CarpetContext cc = (CarpetContext)c;
+ Scoreboard scoreboard = cc.s.getMinecraftServer().getScoreboard();
+ if (lv.size()==0)
+ {
+ Value ret = ListValue.wrap(scoreboard.getObjectiveNames().stream().map(StringValue::new).collect(Collectors.toList()));
+ return (_c, _t) -> ret;
+ }
+ String objectiveName = lv.get(0).evalValue(c).getString();
+ ScoreboardObjective objective = scoreboard.getObjective(objectiveName);
+ if (objective == null) throw new InternalExpressionException("Unknown objective: "+objectiveName);
+ if (lv.size()==1)
+ {
+ Value ret = ListValue.wrap(scoreboard.getAllPlayerScores(objective).stream().map(s -> new StringValue(s.getPlayerName())).collect(Collectors.toList()));
+ return (_c, _t) -> ret;
+ }
+ String key;
+ Value keyValue = lv.get(1).evalValue(c);
+ if (keyValue instanceof EntityValue)
+ {
+ Entity e = ((EntityValue) keyValue).getEntity();
+ if (e instanceof PlayerEntity)
+ {
+ key = e.getDisplayName().getString();
+ }
+ else
+ {
+ key = e.getUuidAsString();
+ }
+ }
+ else
+ {
+ key = keyValue.getString();
+ }
+ if (!scoreboard.playerHasObjective(key, objective) && lv.size()==2)
+ return LazyValue.NULL;
+ ScoreboardPlayerScore scoreboardPlayerScore = scoreboard.getPlayerScore(key, objective);
+ Value retval = new NumericValue(scoreboardPlayerScore.getScore());
+ if (lv.size() > 2)
+ {
+ scoreboardPlayerScore.setScore(NumericValue.asNumber(lv.get(2).evalValue(c)).getInt());
+ }
+ return (_c, _t) -> retval;
+ });
+
+ this.expr.addLazyFunction("scoreboard_remove", 1, (c, t, lv)-> {
+ CarpetContext cc = (CarpetContext)c;
+ Scoreboard scoreboard = cc.s.getMinecraftServer().getScoreboard();
+ String objectiveName = lv.get(0).evalValue(c).getString();
+ ScoreboardObjective objective = scoreboard.getObjective(objectiveName);
+ if (objective == null)
+ return LazyValue.FALSE;
+ scoreboard.removeObjective(objective);
+ return LazyValue.TRUE;
+ });
+
+ // objective_add('lvl','level')
+ // objective_add('counter')
+
+ this.expr.addLazyFunction("scoreboard_add", -1, (c, t, lv)-> {
+ CarpetContext cc = (CarpetContext)c;
+ Scoreboard scoreboard = cc.s.getMinecraftServer().getScoreboard();
+ if (lv.size() == 0 || lv.size()>2) throw new InternalExpressionException("'scoreboard_add' should have one or two parameters");
+ String objectiveName = lv.get(0).evalValue(c).getString();
+ ScoreboardCriterion criterion;
+ if (lv.size() == 1 )
+ {
+ criterion = ScoreboardCriterion.DUMMY;
+ }
+ else
+ {
+ String critetionName = lv.get(1).evalValue(c).getString();
+ criterion = ScoreboardCriterion.createStatCriterion(critetionName).orElse(null);
+ if (criterion==null)
+ {
+ throw new InternalExpressionException("Unknown scoreboard criterion: "+critetionName);
+ }
+ }
+
+ ScoreboardObjective objective = scoreboard.getObjective(objectiveName);
+ if (objective != null)
+ return LazyValue.FALSE;
+
+ scoreboard.addObjective(objectiveName, criterion, new LiteralText(objectiveName), criterion.getCriterionType());
+ return LazyValue.TRUE;
+ });
+
+ this.expr.addLazyFunction("scoreboard_display", 2, (c, t, lv) ->
+ {
+ CarpetContext cc = (CarpetContext)c;
+ Scoreboard scoreboard = cc.s.getMinecraftServer().getScoreboard();
+ String location = lv.get(0).evalValue(c).getString();
+ int slot = Scoreboard.getDisplaySlotId(location);
+ if (slot < 0) throw new InternalExpressionException("Invalid objective slot: "+location);
+ Value target = lv.get(1).evalValue(c);
+ if (target instanceof NullValue)
+ {
+ scoreboard.setObjectiveSlot(slot, null);
+ return (_c, _t) -> new NumericValue(slot);
+ }
+ String objectiveString = target.getString();
+ ScoreboardObjective objective = scoreboard.getObjective(objectiveString);
+ if (objective == null) throw new InternalExpressionException("Objective doesn't exist: "+objectiveString);
+ scoreboard.setObjectiveSlot(slot, objective);
+ return (_c, _t) -> new NumericValue(slot);
+ });
+ }
+
public void API_InventoryManipulation()
{
this.expr.addLazyFunction("stack_limit", 1, (c, t, lv) ->
@@ -1823,7 +1942,7 @@ public class CarpetExpression
LazyValue _z = c.getVariable("_z");
LazyValue __ = c.getVariable("_");
int sCount = 0;
- for (int y=cy-yrange; y <= cy+yprange; y++)
+ outer:for (int y=cy-yrange; y <= cy+yprange; y++)
{
int yFinal = y;
c.setVariable("_y", (c_, t_) -> new NumericValue(yFinal).bindTo("_y"));
@@ -1838,7 +1957,19 @@ public class CarpetExpression
c.setVariable("_z", (c_, t_) -> new NumericValue(zFinal).bindTo("_z"));
Value blockValue = BlockValue.fromCoords(((CarpetContext)c), xFinal,yFinal,zFinal).bindTo("_");
c.setVariable( "_", (cc_, t_c) -> blockValue);
- Value result = expr.evalValue(c, t);
+ Value result;
+ try
+ {
+ result = expr.evalValue(c, t);
+ }
+ catch (ContinueStatement notIgnored)
+ {
+ result = notIgnored.retval;
+ }
+ catch (BreakStatement notIgnored)
+ {
+ break outer;
+ }
if (t != Context.VOID && result.getBoolean())
{
sCount += 1;
@@ -1877,7 +2008,7 @@ public class CarpetExpression
LazyValue _z = c.getVariable("_z");
LazyValue __ = c.getVariable("_");
int sCount = 0;
- for (int y=miny; y <= maxy; y++)
+ outer:for (int y=miny; y <= maxy; y++)
{
int yFinal = y;
c.setVariable("_y", (c_, t_) -> new NumericValue(yFinal).bindTo("_y"));
@@ -1891,7 +2022,19 @@ public class CarpetExpression
c.setVariable("_z", (c_, t_) -> new NumericValue(zFinal).bindTo("_z"));
Value blockValue = BlockValue.fromCoords(((CarpetContext)c), xFinal,yFinal,zFinal).bindTo("_");
c.setVariable( "_", (cc_, t_c) -> blockValue);
- Value result = expr.evalValue(c, t);
+ Value result;
+ try
+ {
+ result = expr.evalValue(c, t);
+ }
+ catch (ContinueStatement notIgnored)
+ {
+ result = notIgnored.retval;
+ }
+ catch (BreakStatement notIgnored)
+ {
+ break outer;
+ }
if (t != Context.VOID && result.getBoolean())
{
sCount += 1;
@@ -2714,6 +2857,7 @@ public class CarpetExpression
API_InventoryManipulation();
API_IteratingOverAreasOfBlocks();
API_AuxiliaryAspects();
+ API_Scoreboard();
}
public boolean fillAndScanCommand(ScriptHost host, int x, int y, int z)
diff --git a/src/main/java/carpet/script/value/NumericValue.java b/src/main/java/carpet/script/value/NumericValue.java
index a402e151..087d0f2e 100644
--- a/src/main/java/carpet/script/value/NumericValue.java
+++ b/src/main/java/carpet/script/value/NumericValue.java
@@ -189,4 +189,8 @@ public class NumericValue extends Value
}
+ public int getInt()
+ {
+ return (int)getLong();
+ }
}