Skip to content

Commit 47466aa

Browse files
Region flags (changing)
1 parent 582f85c commit 47466aa

File tree

2 files changed

+185
-5
lines changed

2 files changed

+185
-5
lines changed

src/main/java/org/skriptlang/skriptworldguard/elements/expressions/ExprRegionFlag.java

Lines changed: 180 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,30 @@
11
package org.skriptlang.skriptworldguard.elements.expressions;
22

33
import ch.njol.skript.Skript;
4+
import ch.njol.skript.classes.Changer.ChangeMode;
45
import ch.njol.skript.doc.Description;
56
import ch.njol.skript.doc.Example;
67
import ch.njol.skript.doc.Name;
78
import ch.njol.skript.doc.Since;
9+
import ch.njol.skript.entity.EntityData;
810
import ch.njol.skript.expressions.base.PropertyExpression;
911
import ch.njol.skript.lang.Expression;
1012
import ch.njol.skript.lang.Literal;
1113
import ch.njol.skript.lang.SkriptParser.ParseResult;
1214
import ch.njol.skript.lang.SyntaxStringBuilder;
1315
import ch.njol.skript.lang.util.SimpleExpression;
16+
import ch.njol.skript.registrations.Classes;
17+
import ch.njol.skript.util.Utils;
1418
import ch.njol.util.Kleenean;
19+
import ch.njol.util.Math2;
20+
import com.google.common.collect.Sets;
21+
import com.sk89q.worldguard.protection.flags.Flag;
1522
import org.bukkit.event.Event;
1623
import org.jetbrains.annotations.Nullable;
24+
import org.skriptlang.skript.lang.arithmetic.Arithmetics;
25+
import org.skriptlang.skript.lang.arithmetic.Operator;
26+
import org.skriptlang.skript.lang.converter.Converter;
27+
import org.skriptlang.skript.lang.converter.Converters;
1728
import org.skriptlang.skript.registration.SyntaxRegistry;
1829
import org.skriptlang.skriptworldguard.worldguard.WorldGuardFlag;
1930
import org.skriptlang.skriptworldguard.worldguard.WorldGuardRegion;
@@ -22,6 +33,7 @@
2233
import java.util.ArrayList;
2334
import java.util.Arrays;
2435
import java.util.List;
36+
import java.util.Set;
2537
import java.util.function.Function;
2638

2739
@Name("Region Flag")
@@ -78,7 +90,6 @@ public boolean init(Expression<?>[] expressions, int matchedPattern, Kleenean is
7890
return new Object[0];
7991
}
8092
}
81-
8293
WorldGuardRegion[] regions = this.regions.getArray(event);
8394

8495
List<Object> values = new ArrayList<>();
@@ -105,6 +116,174 @@ public boolean init(Expression<?>[] expressions, int matchedPattern, Kleenean is
105116
return values.toArray((Object[]) Array.newInstance(getReturnType(), values.size()));
106117
}
107118

119+
@Override
120+
public Class<?> @Nullable [] acceptChange(ChangeMode mode) {
121+
return switch (mode) {
122+
case ADD, SET, REMOVE, DELETE, RESET ->
123+
new Class[]{flag == null ? Object[].class : flag.valueConverter().fromType()};
124+
default -> null;
125+
};
126+
}
127+
128+
@Override
129+
public void change(Event event, Object @Nullable [] delta, ChangeMode mode) {
130+
WorldGuardFlag<?, ?> flag = this.flag;
131+
if (flag == null) {
132+
String flagName = this.flagName.getSingle(event);
133+
if (flagName == null) {
134+
return;
135+
}
136+
WorldGuardFlag.LookupResult result = WorldGuardFlag.fromName(flagName);
137+
flag = result.flag();
138+
if (flag == null) {
139+
error(result.error());
140+
return;
141+
}
142+
}
143+
WorldGuardRegion[] regions = this.regions.getArray(event);
144+
145+
// verify types
146+
// this will have been done by EffChange if flag is set (due to accurate types)
147+
if (delta != null && this.flag == null) {
148+
Class<?> expectedType = flag.valueConverter().fromType();
149+
if (expectedType.isArray()) {
150+
expectedType = expectedType.getComponentType();
151+
}
152+
153+
// special runtime type handling
154+
// need to manually convert to correct number type
155+
if (Number.class.isAssignableFrom(expectedType)) {
156+
Object[] delta2 = new Object[delta.length];
157+
Converter<Number, ?> converter = Converters.getConverter(Number.class, expectedType);
158+
assert converter != null;
159+
for (int i = 0; i < delta.length; i++) {
160+
if (delta[i] instanceof Number number) {
161+
delta2[i] = converter.convert(number);
162+
}
163+
}
164+
delta = delta2;
165+
}
166+
167+
Class<?> foundType = Utils.getSuperType(Arrays.stream(delta)
168+
.map(Object::getClass)
169+
.toArray(Class[]::new));
170+
171+
if (!expectedType.isAssignableFrom(foundType)) {
172+
String expr = toString(event, Skript.debug());
173+
String add = switch (mode) {
174+
case ADD -> "to add to '" + expr + "'";
175+
case SET -> "to set '" + expr + "' to";
176+
case REMOVE -> "to remove from '" + expr + "'";
177+
default -> throw new IllegalArgumentException("Unexpected mode: " + mode);
178+
};
179+
error("Expected the value " + add + " to be " +
180+
Utils.a(Classes.toString(Classes.getSuperClassInfo(expectedType))) +
181+
" but it was " +
182+
Utils.a(Classes.toString(Classes.getSuperClassInfo(foundType))));
183+
return;
184+
}
185+
if (delta.length > 1 && !flag.valueConverter().fromType().isArray()) {
186+
error(toString(event, Skript.debug()) + " can only have one value " +
187+
(mode == ChangeMode.ADD ? "added to" : "removed from") + " it, not more");
188+
return;
189+
}
190+
}
191+
192+
if (delta != null) { // handle special cases
193+
for (int i = 0; i < delta.length; i++) {
194+
if (delta[i] instanceof EntityData<?> entityData) { // fix comparison issues, e.g. isPlural
195+
delta[i] = EntityData.fromClass(entityData.getType());
196+
}
197+
}
198+
}
199+
200+
switch (mode) {
201+
case SET -> {
202+
assert delta != null;
203+
Object value;
204+
if (flag.valueConverter().fromType().isArray()) {
205+
value = delta;
206+
} else {
207+
value = delta[0];
208+
}
209+
for (WorldGuardRegion region : regions) {
210+
//noinspection unchecked, rawtypes
211+
region.region().setFlag((Flag) flag.flag(), ((Function) flag.valueConverter().toMapper()).apply(value));
212+
}
213+
}
214+
case ADD, REMOVE -> {
215+
assert delta != null;
216+
boolean isRemove = mode == ChangeMode.REMOVE;
217+
if (Number.class.isAssignableFrom(flag.valueConverter().fromType())) {
218+
for (WorldGuardRegion region : regions) {
219+
Object current = region.region().getFlag(flag.flag());
220+
if (current == null) {
221+
current = flag.flag().getDefault();
222+
}
223+
if (current == null) {
224+
continue;
225+
}
226+
//noinspection unchecked, rawtypes
227+
Number mappedCurrent = (Number) ((Function) flag.valueConverter().fromMapper()).apply(current);
228+
229+
// calculate result
230+
Number result = Arithmetics.calculate(isRemove ? Operator.SUBTRACTION : Operator.ADDITION,
231+
mappedCurrent, delta[0], Number.class);
232+
if (result instanceof Long longResult) { // convert to Integer
233+
result = (int) Math2.fit(Integer.MIN_VALUE, longResult, Integer.MAX_VALUE);
234+
}
235+
236+
//noinspection unchecked, rawtypes
237+
region.region().setFlag((Flag) flag.flag(), ((Function) flag.valueConverter().toMapper()).apply(result));
238+
}
239+
} else if (flag.valueConverter().fromType().isArray()) {
240+
Set<?> deltaSet = Set.of(delta);
241+
for (WorldGuardRegion region : regions) {
242+
Object current = region.region().getFlag(flag.flag());
243+
if (current == null) {
244+
current = flag.flag().getDefault();
245+
}
246+
Set<?> mappedSet;
247+
if (current == null) {
248+
if (isRemove) { // nothing to remove
249+
continue;
250+
}
251+
mappedSet = Set.of();
252+
} else {
253+
//noinspection unchecked, rawtypes
254+
Object[] mappedCurrent = (Object[]) ((Function) flag.valueConverter().fromMapper()).apply(current);
255+
mappedSet = Set.of(mappedCurrent);
256+
}
257+
258+
// merge sets
259+
Set<?> valueSet;
260+
if (isRemove) {
261+
valueSet = Sets.difference(mappedSet, deltaSet);
262+
} else {
263+
valueSet = Sets.union(mappedSet, deltaSet);
264+
}
265+
Object[] values = valueSet.toArray();
266+
267+
//noinspection unchecked, rawtypes
268+
region.region().setFlag((Flag) flag.flag(), ((Function) flag.valueConverter().toMapper()).apply(values));
269+
}
270+
} else {
271+
error(toString(event, Skript.debug()) + " can't have values " +
272+
(mode == ChangeMode.ADD ? "added to" : "removed from") + " it");
273+
}
274+
275+
}
276+
case DELETE, RESET -> {
277+
for (WorldGuardRegion region : regions) {
278+
region.region().setFlag(flag.flag(), null);
279+
}
280+
}
281+
default -> {
282+
assert false;
283+
}
284+
}
285+
}
286+
108287
@Override
109288
public boolean isSingle() {
110289
if (flag == null) {

src/main/java/org/skriptlang/skriptworldguard/worldguard/WorldGuardFlag.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package org.skriptlang.skriptworldguard.worldguard;
22

33
import ch.njol.skript.bukkitutil.EntityUtils;
4-
import ch.njol.skript.entity.EntityType;
4+
import ch.njol.skript.entity.EntityData;
55
import ch.njol.skript.util.Date;
66
import ch.njol.skript.util.WeatherType;
77
import com.google.common.collect.ImmutableMap;
@@ -112,6 +112,7 @@ static <T> FlagValueConverter<T, T> simple(Class<T> type) {
112112
to -> new Vector(to.getX(), to.getY(), to.getZ())));
113113

114114
// Additional mappings
115+
// no WorldGuard GameMode -> Bukkit GameMode adapter...
115116
converters.put(com.sk89q.worldedit.world.gamemode.GameMode.class,
116117
new FlagValueConverter<>(GameMode.class, com.sk89q.worldedit.world.gamemode.GameMode.class,
117118
BukkitAdapter::adapt, to -> GameMode.valueOf(to.getName().toUpperCase(Locale.ENGLISH))));
@@ -133,9 +134,9 @@ static <T> FlagValueConverter<T, T> simple(Class<T> type) {
133134
}
134135
}));
135136
converters.put(com.sk89q.worldedit.world.entity.EntityType.class,
136-
new FlagValueConverter<>(EntityType.class, com.sk89q.worldedit.world.entity.EntityType.class,
137-
from -> BukkitAdapter.adapt(EntityUtils.toBukkitEntityType(from.data)),
138-
to -> new EntityType(EntityUtils.toSkriptEntityData(BukkitAdapter.adapt(to)), 1)));
137+
new FlagValueConverter<>(EntityData.class, com.sk89q.worldedit.world.entity.EntityType.class,
138+
from -> BukkitAdapter.adapt(EntityUtils.toBukkitEntityType(from)),
139+
to -> EntityUtils.toSkriptEntityData(BukkitAdapter.adapt(to))));
139140

140141
FLAG_CLASS_MAPPINGS = mappings.build();
141142
FLAG_VALUE_CONVERTERS = converters.build();

0 commit comments

Comments
 (0)