Skip to content

Commit 6c4621d

Browse files
committed
better arithmetic changer handling
1 parent 4eab035 commit 6c4621d

3 files changed

Lines changed: 46 additions & 1 deletion

File tree

src/main/java/ch/njol/skript/classes/Changer.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@
66

77
import ch.njol.skript.classes.data.DefaultChangers;
88
import ch.njol.skript.lang.Expression;
9+
import org.skriptlang.skript.lang.arithmetic.Arithmetics;
10+
import org.skriptlang.skript.lang.arithmetic.OperationInfo;
11+
import org.skriptlang.skript.lang.arithmetic.Operator;
12+
13+
import java.util.List;
14+
import java.util.function.Predicate;
915

1016
/**
1117
* An interface to declare changeable values. All Expressions implement something similar like this by default, but refuse any change if {@link Expression#acceptChange(ChangeMode)}
@@ -94,6 +100,29 @@ public static boolean acceptsChangeTypes(Class<?>[] validTypes, Class<?> @NotNul
94100
return false;
95101
}
96102

103+
/**
104+
* Gets the types that can be added/removed via arithmetic for the given type.
105+
* This is used to determine accepted change types for add/remove when no changer is present.
106+
* @param type The type to get arithmetic change types for.
107+
* @param mode Whether to get addition or subtraction types.
108+
* @param filter A filter to apply to the available operations. Used for custom constraints on the operations, like
109+
* ensuring the return type matches the left type.
110+
* @return The types that can be added/removed via arithmetic for the given type and mode, after applying the filter.
111+
* @param <T> The type to get arithmetic change types for.
112+
*/
113+
public static <T> Class<?>[] getArithmeticChangeTypes(Class<T> type, ChangeMode mode, Predicate<OperationInfo<T, ? ,?>> filter) {
114+
List<OperationInfo<T, ?, ?>> opInfos = List.of();
115+
if (mode == ChangeMode.ADD) {
116+
opInfos = Arithmetics.getOperations(Operator.ADDITION, type);
117+
} else if (mode == ChangeMode.REMOVE) {
118+
opInfos = Arithmetics.getOperations(Operator.SUBTRACTION, type);
119+
}
120+
return opInfos.stream()
121+
.filter(filter)
122+
.map(OperationInfo::right)
123+
.toArray(Class[]::new);
124+
}
125+
97126
}
98127

99128
}

src/main/java/org/skriptlang/skript/bukkit/pdc/expressions/ExprPersistentData.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
import java.util.*;
4242
import java.util.function.Consumer;
4343

44+
import static ch.njol.skript.classes.Changer.ChangerUtils.getArithmeticChangeTypes;
45+
4446
@Name("Persistent Data Value")
4547
@Description("""
4648
Provides access to the 'persistent data container' Bukkit provides on many objects. These values are stored on the \
@@ -190,6 +192,7 @@ protected Object[] get(Event event, Object[] source) {
190192
}
191193

192194
if (parsedType != null) {
195+
// we have a specific type to aim for
193196
ClassInfo<?> classInfo = parsedType.getClassInfo();
194197

195198
if (plural) {
@@ -251,8 +254,11 @@ public boolean isSingle() {
251254
if (changer != null) {
252255
yield changer.acceptChange(mode);
253256
}
254-
if (mode == ChangeMode.SET)
257+
if (mode == ChangeMode.SET) {
255258
yield CollectionUtils.array(type.getC());
259+
} else if (mode == ChangeMode.ADD || mode == ChangeMode.REMOVE) {
260+
yield getArithmeticChangeTypes(type.getC(), mode, operation -> type.getC().isAssignableFrom(operation.returnType()));
261+
}
256262
yield null;
257263
}
258264
yield CollectionUtils.array(plural ? Object[].class : Object.class);

src/test/skript/tests/syntaxes/expressions/ExprPersistentData.sk

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,16 @@ test "persistent data add to singular value":
233233
assert {_val} is 12 with "removing from number should work"
234234
delete persistent data tag "skript:add_single" of {_item}
235235

236+
test "persistent data add to singular value of differing type":
237+
set {_item} to a diamond sword
238+
set {_now} to now
239+
set date data tag "date" of {_item} to {_now}
240+
add 1 day to date data tag "date" of {_item}
241+
assert date data tag "date" of {_item} is {_now} + 1 day with "adding to date should work"
242+
parse:
243+
add "hello" to date data tag "date" of {_item}
244+
assert last parse logs contains """hello"" can't be added to date data tag ""date"" of {_item} because the former is not a time span" with "adding incompatible type should error"
245+
236246
test "persistent data add to list":
237247
set {_item} to a diamond sword
238248
# Start with a list, then add to it

0 commit comments

Comments
 (0)