Skip to content

Allow Literals in 'Size of' #7961

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

67 changes: 37 additions & 30 deletions src/main/java/ch/njol/skript/expressions/ExprAmount.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<Number> {

Expand All @@ -63,40 +57,47 @@ public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelaye
this.any = (Expression<AnyAmount>) 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;
}
}
return true;
}

@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<String, ?>) var);
}
}
return new Long[]{(long) currentSize};
}
return new Long[]{(long) exprs.getArray(e).length};
return new Long[]{(long) exprs.getArray(event).length};
}

@Override
Expand All @@ -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;
Expand All @@ -138,13 +139,19 @@ public void change(Event event, Object @Nullable [] delta, ChangeMode mode) {
}
}

@SuppressWarnings("unchecked")
private static int getRecursiveSize(Map<String, ?> 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<String, ?> 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<String, ?>) value);
if (value instanceof Map<?, ?> nestedMap)
count += getRecursiveSize(nestedMap, false);
else
count++;
}
Expand Down
15 changes: 13 additions & 2 deletions src/test/skript/tests/syntaxes/expressions/ExprAmount.sk
Original file line number Diff line number Diff line change
@@ -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"