diff --git a/src/main/java/ch/njol/skript/expressions/ExprAmount.java b/src/main/java/ch/njol/skript/expressions/ExprAmount.java index 375f01cdb36..93f2edb5c7b 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprAmount.java +++ b/src/main/java/ch/njol/skript/expressions/ExprAmount.java @@ -2,18 +2,12 @@ import ch.njol.skript.Skript; import ch.njol.skript.classes.Changer.ChangeMode; -import ch.njol.skript.doc.Description; -import ch.njol.skript.doc.Examples; -import ch.njol.skript.doc.Name; -import ch.njol.skript.doc.Since; -import ch.njol.skript.lang.Expression; -import ch.njol.skript.lang.ExpressionList; -import ch.njol.skript.lang.ExpressionType; -import ch.njol.skript.lang.Literal; +import ch.njol.skript.doc.*; +import ch.njol.skript.lang.*; import ch.njol.skript.lang.SkriptParser.ParseResult; -import ch.njol.skript.lang.Variable; import ch.njol.skript.lang.util.SimpleExpression; import ch.njol.skript.lang.util.common.AnyAmount; +import ch.njol.skript.util.LiteralUtils; import ch.njol.util.Kleenean; import ch.njol.util.coll.CollectionUtils; import org.bukkit.event.Event; @@ -39,7 +33,7 @@ "", "Where using %size of {list::*}% will only return 3 (the first layer of indices only), while %recursive size of {list::*}% will return 6 (the entire list)", "Please note that getting a list's recursive size can cause lag if the list is large, so only use this expression if you need to!"}) -@Examples({"message \"There are %number of all players% players online!\""}) +@Example("message \"There are %number of all players% players online!\"") @Since("1.0") public class ExprAmount extends SimpleExpression { @@ -63,18 +57,25 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye this.any = (Expression) exprs[0]; return true; } - this.exprs = exprs[0] instanceof ExpressionList ? (ExpressionList) exprs[0] : new ExpressionList<>(new Expression[]{exprs[0]}, Object.class, false); + + this.exprs = exprs[0] instanceof ExpressionList exprList + ? exprList + : new ExpressionList<>(new Expression[]{ exprs[0] }, Object.class, false); + + this.exprs = (ExpressionList) LiteralUtils.defendExpression(this.exprs); + if (!LiteralUtils.canInitSafely(this.exprs)) { + return false; + } + + if (this.exprs.isSingle()) { + Skript.error("'" + this.exprs.toString(null, Skript.debug()) + "' can only ever have one value at most, thus the 'amount of ...' expression is useless. Use '... exists' instead to find out whether the expression has a value."); + return false; + } + this.recursive = matchedPattern == 2; for (Expression expr : this.exprs.getExpressions()) { - if (expr instanceof Literal) { - return false; - } - if (expr.isSingle()) { - Skript.error("'" + expr.toString(null, false) + "' can only ever have one value at most, thus the 'amount of ...' expression is useless. Use '... exists' instead to find out whether the expression has a value."); - return false; - } if (recursive && !(expr instanceof Variable)) { - Skript.error("Getting the recursive size of a list only applies to variables, thus the '" + expr.toString(null, false) + "' expression is useless."); + Skript.error("Getting the recursive size of a list only applies to variables, thus the '" + expr.toString(null, Skript.debug()) + "' expression is useless."); return false; } } @@ -82,21 +83,21 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye } @Override - @SuppressWarnings("unchecked") - protected Number[] get(Event e) { + protected Number[] get(Event event) { if (any != null) - return new Number[] {any.getOptionalSingle(e).orElse(() -> 0).amount()}; + return new Number[] {any.getOptionalSingle(event).orElse(() -> 0).amount()}; if (recursive) { int currentSize = 0; for (Expression expr : exprs.getExpressions()) { - Object var = ((Variable) expr).getRaw(e); + Object var = ((Variable) expr).getRaw(event); if (var != null) { // Should already be a map + // noinspection unchecked currentSize += getRecursiveSize((Map) var); } } return new Long[]{(long) currentSize}; } - return new Long[]{(long) exprs.getArray(e).length}; + return new Long[]{(long) exprs.getArray(event).length}; } @Override @@ -111,7 +112,7 @@ protected Number[] get(Event e) { } @Override - public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { + public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { if (any == null) { super.change(event, delta, mode); return; @@ -138,13 +139,19 @@ public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { } } - @SuppressWarnings("unchecked") - private static int getRecursiveSize(Map map) { + private static int getRecursiveSize(Map map) { + return getRecursiveSize(map, true); + } + + private static int getRecursiveSize(Map map, boolean skipNull) { int count = 0; - for (Map.Entry entry : map.entrySet()) { + for (Map.Entry entry : map.entrySet()) { + if (skipNull && entry.getKey() == null) + continue; // when getting the recursive size of {a::*}, ignore {a} + Object value = entry.getValue(); - if (value instanceof Map) - count += getRecursiveSize((Map) value); + if (value instanceof Map nestedMap) + count += getRecursiveSize(nestedMap, false); else count++; } diff --git a/src/test/skript/tests/syntaxes/expressions/ExprAmount.sk b/src/test/skript/tests/syntaxes/expressions/ExprAmount.sk index d4cc336b031..a0a21793517 100644 --- a/src/test/skript/tests/syntaxes/expressions/ExprAmount.sk +++ b/src/test/skript/tests/syntaxes/expressions/ExprAmount.sk @@ -1,12 +1,23 @@ test "amount of objects": set {_objects::*} to (1 and 2) set {_amount} to amount of {_objects::*} - assert {_amount} is 2 with "was wrong" + assert {_amount} is 2 with "size of list was wrong - 1" + set {_objects::*} to ("hello", "there" and 1) set {_amount} to amount of {_objects::*} - assert {_amount} is 3 with "was wrong" + assert {_amount} is 3 with "size of list was wrong - 2" + + assert size of (1, 2 and 3) is 3 with "size of literal list was wrong" + assert size of (1, {_objects::*} and 3) is 5 with "size of mixed list was wrong" test "amount of items": assert amount of (3 of stone) is 3 with "was wrong" set {_item} to 3 of stone assert amount of {_item} is 3 with "was wrong" + +test "recursive size": + set {_a} to 1 + set {_a::*} to 1, 2 and 3 + set {_a::1::*} to 1 and 2 + set {_a::1::1::1::1::1} to 5 + assert recursive size of {_a::*} is 6 with "recursive size was wrong"