Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion code-conventions.md
Original file line number Diff line number Diff line change
Expand Up @@ -303,8 +303,9 @@ Skript **must** run on these MC versions, in one way or another.
If your contribution breaks compatibility for any of these versions we cannot accept it.

Please try to make sure contributions are future-safe, to the best of your ability.
Where possible, avoid using version-specific code to target a feature (e.g. accessing different copies of an internal class via reflection for each minecraft version) as this creates additional maintenance work every time a new version releases.
Where possible, avoid using version-specific code to target a feature (e.g. accessing different copies of an internal class via reflection for each Minecraft version) as this creates additional maintenance work every time a new version releases.
Checking whether a class exists in order to target supported versions is acceptable.
If a feature requires a version check to support older versions, mark it for future cleanup. Above any checks, add a comment stating the target version where the check can be safely removed: `// TODO: UNTIL MC/SKRIPT x.y.z`.

### Support the Target Servers

Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ org.gradle.parallel=true

groupid=ch.njol
name=skript
version=2.15.0
version=2.15.2
jarName=Skript.jar
testEnv=java25/paper-26.1.1
testEnvJavaVersion=25
Expand Down
1 change: 1 addition & 0 deletions src/main/java/ch/njol/skript/SkriptEventHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ private static List<Trigger> getTriggers(Class<? extends Event> event) {
return triggers.asMap().entrySet().stream()
.filter(entry -> entry.getKey().isAssignableFrom(event) && getHandlerList(entry.getKey()) == eventHandlerList)
.flatMap(entry -> entry.getValue().stream())
.distinct()
.collect(Collectors.toList()); // forces evaluation now and prevents us from having to call getTriggers again if very high logging is enabled
}

Expand Down
78 changes: 78 additions & 0 deletions src/main/java/ch/njol/skript/classes/Changer.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package ch.njol.skript.classes;

import ch.njol.skript.expressions.base.WrapperExpression;
import ch.njol.skript.lang.SkriptParser.ParseResult;
import ch.njol.util.Kleenean;
import com.google.common.base.Preconditions;
import org.bukkit.event.Event;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

Expand All @@ -10,8 +14,11 @@
import org.skriptlang.skript.lang.arithmetic.Arithmetics;
import org.skriptlang.skript.lang.arithmetic.OperationInfo;
import org.skriptlang.skript.lang.arithmetic.Operator;
import org.skriptlang.skript.lang.converter.Converters;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;

/**
Expand Down Expand Up @@ -84,6 +91,77 @@ public static boolean acceptsChange(@NotNull Expression<?> expression, ChangeMod
return acceptsChangeTypes(validTypes, types);
}

/**
* Tests whether an expression accepts changes of a certain type.
* If multiple types are given it test for whether any of the types is accepted.
* This method goes further than {@link #acceptsChange(Expression, ChangeMode, Class[])} by considering
* {@link Converters} and attempting to convert {@code expression} to accept at least one of {@code types}.
*
* @param expression The expression to test (and potentially convert)
* @param mode The ChangeMode to use in the test
* @param types The types to test for
* @return {@code expression} (or a conversion of it) that allows {@link #change(Object[], Object[], ChangeMode)}
* to be called with one of {@code types} (as a delta value).
* Returns {@code null} if no such conversion of {@code expression} exists.
*/
@ApiStatus.Internal
public static @Nullable <T> Expression<T> acceptsChangeWithConverters(@NotNull Expression<T> expression, ChangeMode mode, Class<?>... types) {
Class<?>[] validTypes = expression.acceptChange(mode);
if (validTypes == null)
return null;

for (int i = 0; i < validTypes.length; i++) {
if (validTypes[i].isArray()) {
validTypes[i] = validTypes[i].getComponentType();
}
}

if (acceptsChangeTypes(validTypes, types)) {
return expression;
}

for (Class<?> type : types) {
if (Converters.converterExists(type, validTypes)) {
class ChangeWrapper extends WrapperExpression<T> {
public ChangeWrapper(Expression<T> expression) {
super(expression);
}

@Override
public boolean init(Expression<?>[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
throw new UnsupportedOperationException();
}

@Override
public void change(Event event, @Nullable Object[] delta, ChangeMode mode) {
super.change(event, Converters.convert(delta, validTypes, Object.class), mode);
}

@Override
public <R> void changeInPlace(Event event, Function<T, R> changeFunction, boolean getAll) {
T[] values = getAll ? getAll(event) : getArray(event);
if (values.length == 0)
return;

List<R> newValues = new ArrayList<>();
for (T value : values) {
newValues.add(changeFunction.apply(value));
}
change(event, newValues.toArray(), ChangeMode.SET);
}

@Override
public String toString(@Nullable Event event, boolean debug) {
return getExpr().toString(event, debug);
}
}
return new ChangeWrapper(expression);
}
}

return null;
}

/**
* Tests whether any of the given types is accepted by the given array of valid types.
*
Expand Down
12 changes: 7 additions & 5 deletions src/main/java/ch/njol/skript/command/Commands.java
Original file line number Diff line number Diff line change
Expand Up @@ -189,23 +189,25 @@ static boolean handleEffectCommand(CommandSender sender, String command) {
Effect effect = Effect.parse(command, null);
parserInstance.deleteCurrentEvent();

TextComponentParser textParser = TextComponentParser.instance();
if (effect != null) {
log.clear(); // ignore warnings and stuff
log.printLog();
if (!effectCommand.isCancelled()) {
sender.sendRichMessage("<gray>Executing '" + TextComponentParser.instance().escape(command) + "'");
sender.sendMessage(textParser.parse("<gray>Executing '" + textParser.escape(command) + "'"));
if (SkriptConfig.logEffectCommands.value() && !(sender instanceof ConsoleCommandSender))
Skript.info(sender.getName() + " issued effect command: " + TextComponentParser.instance().escape(command));
Skript.info(sender.getName() + " issued effect command: " + textParser.escape(command));
TriggerItem.walk(effect, effectCommand);
Variables.removeLocals(effectCommand);
} else {
sender.sendRichMessage("<red>Your effect command '" + TextComponentParser.instance().escape(command) + "' was cancelled.");
sender.sendMessage(textParser.parse("<red>Your effect command '" + textParser.escape(command) + "' was cancelled."));
}
} else {
if (sender == Bukkit.getConsoleSender()) // log as SEVERE instead of INFO like printErrors below
SkriptLogger.LOGGER.severe("Error in: " + TextComponentParser.instance().escape(command));
// No need to escape command here, logger will do it
SkriptLogger.LOGGER.severe("Error in: " + command);
else
sender.sendRichMessage("<red>Error in: <gray>" + TextComponentParser.instance().escape(command));
sender.sendMessage(textParser.parse("<red>Error in: <gray>" + textParser.escape(command)));
// TODO errors likely need to be escaped too
log.printErrors(sender, "(No specific information is available)");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
import ch.njol.skript.Skript;
import ch.njol.skript.doc.*;
import ch.njol.skript.lang.Condition;
import ch.njol.skript.lang.EventRestrictedSyntax;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.SkriptParser.ParseResult;
import ch.njol.util.Kleenean;
import ch.njol.util.coll.CollectionUtils;
import com.destroystokyo.paper.event.player.PlayerElytraBoostEvent;
import org.bukkit.event.Event;
import org.jetbrains.annotations.Nullable;
Expand All @@ -18,7 +20,7 @@
prevent the used firework from being consumed
""")
@Since("2.10")
public class CondElytraBoostConsume extends Condition {
public class CondElytraBoostConsume extends Condition implements EventRestrictedSyntax {

static {
if (Skript.classExists("com.destroystokyo.paper.event.player.PlayerElytraBoostEvent")) {
Expand All @@ -32,14 +34,15 @@ public class CondElytraBoostConsume extends Condition {

@Override
public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
if (!getParser().isCurrentEvent(PlayerElytraBoostEvent.class)) {
Skript.error("This condition can only be used in an 'elytra boost' event.");
return false;
}
checkConsume = matchedPattern == 0;
return true;
}

@Override
public Class<? extends Event>[] supportedEvents() {
return CollectionUtils.array(PlayerElytraBoostEvent.class);
}

@Override
public boolean check(Event event) {
if (!(event instanceof PlayerElytraBoostEvent boostEvent))
Expand Down
13 changes: 8 additions & 5 deletions src/main/java/ch/njol/skript/conditions/CondLeashWillDrop.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package ch.njol.skript.conditions;

import ch.njol.skript.lang.EventRestrictedSyntax;
import ch.njol.util.coll.CollectionUtils;
import org.bukkit.event.Event;
import org.bukkit.event.entity.EntityUnleashEvent;
import org.jetbrains.annotations.Nullable;
Expand All @@ -23,7 +25,7 @@
@Keywords("lead")
@Events("Leash / Unleash")
@Since("2.10")
public class CondLeashWillDrop extends Condition {
public class CondLeashWillDrop extends Condition implements EventRestrictedSyntax {

static {
// TODO - remove this when Spigot support is dropped
Expand All @@ -33,14 +35,15 @@ public class CondLeashWillDrop extends Condition {

@Override
public boolean init(Expression<?>[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
if (!getParser().isCurrentEvent(EntityUnleashEvent.class)) {
Skript.error("The 'leash will drop' condition can only be used in an 'unleash' event");
return false;
}
setNegated(parseResult.hasTag("not"));
return true;
}

@Override
public Class<? extends Event>[] supportedEvents() {
return CollectionUtils.array(EntityUnleashEvent.class);
}

@Override
public boolean check(Event event) {
if (!(event instanceof EntityUnleashEvent unleashEvent))
Expand Down
13 changes: 8 additions & 5 deletions src/main/java/ch/njol/skript/conditions/CondResourcePack.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package ch.njol.skript.conditions;

import ch.njol.skript.lang.EventRestrictedSyntax;
import ch.njol.util.coll.CollectionUtils;
import org.bukkit.event.Event;
import org.bukkit.event.player.PlayerResourcePackStatusEvent;
import org.bukkit.event.player.PlayerResourcePackStatusEvent.Status;
Expand All @@ -25,7 +27,7 @@
""")
@Since("2.4")
@Events("resource pack request response")
public class CondResourcePack extends Condition {
public class CondResourcePack extends Condition implements EventRestrictedSyntax {

static {
Skript.registerCondition(CondResourcePack.class,
Expand All @@ -39,14 +41,15 @@ public class CondResourcePack extends Condition {
@SuppressWarnings({"unchecked", "null"})
@Override
public boolean init(final Expression<?>[] exprs, final int matchedPattern, final Kleenean isDelayed, final ParseResult parseResult) {
if (!getParser().isCurrentEvent(PlayerResourcePackStatusEvent.class)) {
Skript.error("The resource pack condition can't be used outside of a resource pack response event");
return false;
}
states = (Expression<Status>) exprs[0];
setNegated(matchedPattern == 1);
return true;
}

@Override
public Class<? extends Event>[] supportedEvents() {
return CollectionUtils.array(PlayerResourcePackStatusEvent.class);
}

@Override
public boolean check(Event e) {
Expand Down
13 changes: 8 additions & 5 deletions src/main/java/ch/njol/skript/conditions/CondRespawnLocation.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
import ch.njol.skript.doc.RequiredPlugins;
import ch.njol.skript.doc.Since;
import ch.njol.skript.lang.Condition;
import ch.njol.skript.lang.EventRestrictedSyntax;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.SkriptParser.ParseResult;
import ch.njol.util.Kleenean;
import ch.njol.util.coll.CollectionUtils;
import org.bukkit.event.Event;
import org.bukkit.event.player.PlayerRespawnEvent;
import org.jetbrains.annotations.Nullable;
Expand All @@ -25,7 +27,7 @@
@RequiredPlugins("Minecraft 1.16+")
@Since("2.7")
@Events("respawn")
public class CondRespawnLocation extends Condition {
public class CondRespawnLocation extends Condition implements EventRestrictedSyntax {

static {
Skript.registerCondition(CondRespawnLocation.class, "[the] respawn location (was|is)[1:(n'| no)t] [a] (:bed|respawn anchor)");
Expand All @@ -35,15 +37,16 @@ public class CondRespawnLocation extends Condition {

@Override
public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
if (!getParser().isCurrentEvent(PlayerRespawnEvent.class)) {
Skript.error("The 'respawn location' condition may only be used in a respawn event");
return false;
}
setNegated(parseResult.mark == 1);
bedSpawn = parseResult.hasTag("bed");
return true;
}

@Override
public Class<? extends Event>[] supportedEvents() {
return CollectionUtils.array(PlayerRespawnEvent.class);
}

@Override
public boolean check(Event event) {
if (event instanceof PlayerRespawnEvent) {
Expand Down
13 changes: 8 additions & 5 deletions src/main/java/ch/njol/skript/conditions/CondWillHatch.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
import ch.njol.skript.doc.Name;
import ch.njol.skript.doc.Since;
import ch.njol.skript.lang.Condition;
import ch.njol.skript.lang.EventRestrictedSyntax;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.SkriptParser.ParseResult;
import ch.njol.util.Kleenean;
import ch.njol.util.coll.CollectionUtils;
import org.bukkit.event.Event;
import org.bukkit.event.player.PlayerEggThrowEvent;
import org.jetbrains.annotations.Nullable;
Expand All @@ -23,7 +25,7 @@
""")
@Events("Egg Throw")
@Since("2.7")
public class CondWillHatch extends Condition {
public class CondWillHatch extends Condition implements EventRestrictedSyntax {

static {
Skript.registerCondition(CondWillHatch.class,
Expand All @@ -33,14 +35,15 @@ public class CondWillHatch extends Condition {

@Override
public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
if (!getParser().isCurrentEvent(PlayerEggThrowEvent.class)) {
Skript.error("You can't use the 'egg will hatch' condition outside of a Player Egg Throw event.");
return false;
}
setNegated(!parseResult.hasTag("will"));
return true;
}

@Override
public Class<? extends Event>[] supportedEvents() {
return CollectionUtils.array(PlayerEggThrowEvent.class);
}

@Override
public boolean check(Event event) {
if (!(event instanceof PlayerEggThrowEvent))
Expand Down
13 changes: 8 additions & 5 deletions src/main/java/ch/njol/skript/effects/EffCancelCooldown.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package ch.njol.skript.effects;

import ch.njol.skript.lang.EventRestrictedSyntax;
import ch.njol.util.coll.CollectionUtils;
import org.bukkit.event.Event;
import org.jetbrains.annotations.Nullable;

Expand Down Expand Up @@ -30,7 +32,7 @@
set the player's display name to arg-1
""")
@Since("2.2-dev34")
public class EffCancelCooldown extends Effect {
public class EffCancelCooldown extends Effect implements EventRestrictedSyntax {

static {
Skript.registerEffect(EffCancelCooldown.class,
Expand All @@ -42,14 +44,15 @@ public class EffCancelCooldown extends Effect {

@Override
public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) {
if (!getParser().isCurrentEvent(ScriptCommandEvent.class)) {
Skript.error("The cancel cooldown effect may only be used in a command", ErrorQuality.SEMANTIC_ERROR);
return false;
}
cancel = matchedPattern == 0;
return true;
}

@Override
public Class<? extends Event>[] supportedEvents() {
return CollectionUtils.array(ScriptCommandEvent.class);
}

@Override
protected void execute(Event e) {
if (!(e instanceof ScriptCommandEvent))
Expand Down
Loading