diff --git a/src/main/java/ch/njol/skript/effects/EffChange.java b/src/main/java/ch/njol/skript/effects/EffChange.java index 06128212b65..71bf0f413fc 100644 --- a/src/main/java/ch/njol/skript/effects/EffChange.java +++ b/src/main/java/ch/njol/skript/effects/EffChange.java @@ -1,25 +1,5 @@ package ch.njol.skript.effects; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.logging.Level; - -import ch.njol.skript.expressions.ExprParse; -import ch.njol.skript.lang.Effect; -import ch.njol.skript.lang.Expression; -import ch.njol.skript.lang.ExpressionList; -import ch.njol.skript.lang.KeyProviderExpression; -import ch.njol.skript.lang.KeyReceiverExpression; -import ch.njol.skript.lang.SkriptParser; -import ch.njol.skript.lang.SyntaxStringBuilder; -import ch.njol.skript.lang.Variable; -import ch.njol.skript.util.LiteralUtils; -import ch.njol.skript.variables.HintManager; -import org.skriptlang.skript.lang.script.ScriptWarning; -import org.bukkit.event.Event; -import org.jetbrains.annotations.Nullable; - import ch.njol.skript.Skript; import ch.njol.skript.SkriptConfig; import ch.njol.skript.classes.Changer; @@ -29,13 +9,25 @@ import ch.njol.skript.doc.Examples; import ch.njol.skript.doc.Name; import ch.njol.skript.doc.Since; +import ch.njol.skript.expressions.ExprParse; +import ch.njol.skript.lang.*; import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.log.CountingLogHandler; import ch.njol.skript.log.ErrorQuality; import ch.njol.skript.log.ParseLogHandler; import ch.njol.skript.registrations.Classes; +import ch.njol.skript.util.LiteralUtils; import ch.njol.skript.util.Patterns; +import ch.njol.skript.variables.HintManager; import ch.njol.util.Kleenean; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.lang.script.ScriptWarning; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.logging.Level; @Name("Change: Set/Add/Remove/Remove All/Delete/Reset") @Description({ @@ -288,7 +280,7 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye hintManager.add(variable, hints); } } - if (!variable.isLocal()) { + if (!variable.isLocal() && !variable.isEphemeral()) { ClassInfo changerInfo = Classes.getSuperClassInfo(changer.getReturnType()); if (changerInfo.getC() != Object.class && changerInfo.getSerializer() == null && changerInfo.getSerializeAs() == null && !SkriptConfig.disableObjectCannotBeSavedWarnings.value() diff --git a/src/main/java/ch/njol/skript/lang/Variable.java b/src/main/java/ch/njol/skript/lang/Variable.java index fa33d953e0f..d626aba031d 100644 --- a/src/main/java/ch/njol/skript/lang/Variable.java +++ b/src/main/java/ch/njol/skript/lang/Variable.java @@ -1,13 +1,5 @@ package ch.njol.skript.lang; -import java.lang.reflect.Array; -import java.util.*; -import java.util.Map.Entry; -import java.util.NoSuchElementException; -import java.util.TreeMap; -import java.util.function.Predicate; -import java.util.function.Function; - import ch.njol.skript.Skript; import ch.njol.skript.SkriptAPIException; import ch.njol.skript.SkriptConfig; @@ -15,11 +7,6 @@ import ch.njol.skript.classes.Changer.ChangeMode; import ch.njol.skript.classes.Changer.ChangerUtils; import ch.njol.skript.classes.ClassInfo; -import com.google.common.collect.Iterators; -import org.apache.commons.lang3.ArrayUtils; -import org.skriptlang.skript.lang.arithmetic.Arithmetics; -import org.skriptlang.skript.lang.arithmetic.OperationInfo; -import org.skriptlang.skript.lang.arithmetic.Operator; import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.lang.parser.ParserInstance; import ch.njol.skript.lang.util.SimpleExpression; @@ -34,23 +21,34 @@ import ch.njol.util.coll.CollectionUtils; import ch.njol.util.coll.iterator.EmptyIterator; import ch.njol.util.coll.iterator.SingleItemIterator; +import com.google.common.collect.Iterators; +import org.apache.commons.lang3.ArrayUtils; import org.bukkit.Bukkit; -import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +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.comparator.Comparators; import org.skriptlang.skript.lang.comparator.Relation; import org.skriptlang.skript.lang.converter.Converters; import org.skriptlang.skript.lang.script.Script; import org.skriptlang.skript.lang.script.ScriptWarning; +import java.lang.reflect.Array; +import java.util.*; +import java.util.Map.Entry; +import java.util.function.Function; +import java.util.function.Predicate; + public class Variable implements Expression, KeyReceiverExpression, KeyProviderExpression { private final static String SINGLE_SEPARATOR_CHAR = ":"; public final static String SEPARATOR = SINGLE_SEPARATOR_CHAR + SINGLE_SEPARATOR_CHAR; public final static String LOCAL_VARIABLE_TOKEN = "_"; + public static final String EPHEMERAL_VARIABLE_TOKEN = "-"; private static final char[] reservedTokens = {'~', '.', '+', '$', '!', '&', '^', '*'}; /** @@ -67,13 +65,14 @@ public class Variable implements Expression, KeyReceiverExpression, Key private final Class[] types; private final boolean local; + private final boolean ephemeral; private final boolean list; private final @Nullable Variable source; private final Map cache = new WeakHashMap<>(); @SuppressWarnings("unchecked") - private Variable(VariableString name, Class[] types, boolean local, boolean list, @Nullable Variable source) { + private Variable(VariableString name, Class[] types, boolean local, boolean ephemeral, boolean list, @Nullable Variable source) { assert types.length > 0; assert name.isSimple() || name.getMode() == StringMode.VARIABLE_NAME; @@ -83,6 +82,7 @@ private Variable(VariableString name, Class[] types, boolean local, this.script = parser.isActive() ? parser.getCurrentScript() : null; this.local = local; + this.ephemeral = ephemeral; this.list = list; this.name = name; @@ -160,10 +160,14 @@ else if (character == '%') } /** - * Prints errors + * Creates a new variable instance with the given name and types. Prints errors. + * @param name The raw name of the variable. + * @param types The types this variable is expected to be. + * @return A new variable instance, or null if the name is invalid or the variable could not be created. + * @param The supertype the variable is expected to be. */ public static @Nullable Variable newInstance(String name, Class[] types) { - name = "" + name.trim(); + name = name.trim(); if (!isValidVariableName(name, true, true)) return null; VariableString variableString = VariableString.newInstance( @@ -172,17 +176,28 @@ else if (character == '%') return null; boolean isLocal = name.startsWith(LOCAL_VARIABLE_TOKEN); + boolean isEphemeral = name.startsWith(EPHEMERAL_VARIABLE_TOKEN); boolean isPlural = name.endsWith(SEPARATOR + "*"); ParserInstance parser = ParserInstance.get(); Script currentScript = parser.isActive() ? parser.getCurrentScript() : null; + + // check for 'starting with expression' warning if (currentScript != null && !SkriptConfig.disableVariableStartingWithExpressionWarnings.value() - && !currentScript.suppressesWarning(ScriptWarning.VARIABLE_STARTS_WITH_EXPRESSION) - && (isLocal ? name.substring(LOCAL_VARIABLE_TOKEN.length()) : name).startsWith("%")) { - Skript.warning("Starting a variable's name with an expression is discouraged ({" + name + "}). " + - "You could prefix it with the script's name: " + - "{" + StringUtils.substring(currentScript.getConfig().getFileName(), 0, -3) + SEPARATOR + name + "}"); + && !currentScript.suppressesWarning(ScriptWarning.VARIABLE_STARTS_WITH_EXPRESSION)) { + + String strippedName = name; + if (isLocal) { + strippedName = strippedName.substring(LOCAL_VARIABLE_TOKEN.length()); + } else if (isEphemeral) { + strippedName = strippedName.substring(EPHEMERAL_VARIABLE_TOKEN.length()); + } + if (strippedName.startsWith("%")) { + Skript.warning("Starting a variable's name with an expression is discouraged ({" + name + "}). " + + "You could prefix it with the script's name: " + + "{" + StringUtils.substring(currentScript.getConfig().getFileName(), 0, -3) + SEPARATOR + name + "}"); + } } // Check for local variable type hints @@ -191,7 +206,7 @@ else if (character == '%') if (!hints.isEmpty()) { // Type hint(s) available if (types[0] == Object.class) { // Object is generic, so we initialize with the hints instead //noinspection unchecked - return new Variable<>(variableString, hints.toArray(new Class[0]), true, isPlural, null); + return new Variable<>(variableString, hints.toArray(new Class[0]), true, isEphemeral, isPlural, null); } List> potentialTypes = new ArrayList<>(); @@ -205,7 +220,7 @@ else if (character == '%') } if (!potentialTypes.isEmpty()) { // Hint matches, use variable with exactly correct type //noinspection unchecked - return new Variable<>(variableString, potentialTypes.toArray(Class[]::new), true, isPlural, null); + return new Variable<>(variableString, potentialTypes.toArray(Class[]::new), true, isEphemeral, isPlural, null); } // Hint exists and does NOT match any types requested @@ -223,7 +238,7 @@ else if (character == '%') } } - return new Variable<>(variableString, types, isLocal, isPlural, null); + return new Variable<>(variableString, types, isLocal, isEphemeral, isPlural, null); } @Override @@ -231,10 +246,23 @@ public boolean init(Expression[] expressions, int matchedPattern, Kleenean is throw new UnsupportedOperationException(); } + /** + * @return Whether this variable is a local variable, i.e. starts with {@link #LOCAL_VARIABLE_TOKEN}. + */ public boolean isLocal() { return local; } + /** + * @return Whether this variable is an ephemeral variable, i.e. starts with {@link #EPHEMERAL_VARIABLE_TOKEN}. + */ + public boolean isEphemeral() { + return ephemeral; + } + + /** + * @return Whether this variable is a list variable, i.e. ends with {@link #SEPARATOR + "*"}. + */ public boolean isList() { return list; } @@ -296,7 +324,7 @@ public Variable getConvertedExpression(Class... to) { if (!converterExists) { return null; } - return new Variable<>(name, to, local, list, this); + return new Variable<>(name, to, local, ephemeral, list, this); } /** diff --git a/src/main/java/ch/njol/skript/variables/FlatFileStorage.java b/src/main/java/ch/njol/skript/variables/FlatFileStorage.java index 5c75dc6ab34..bc76ab838eb 100644 --- a/src/main/java/ch/njol/skript/variables/FlatFileStorage.java +++ b/src/main/java/ch/njol/skript/variables/FlatFileStorage.java @@ -456,7 +456,7 @@ public final void saveVariables(boolean finalSave) { */ @SuppressWarnings("unchecked") private void save(PrintWriter pw, String parent, TreeMap map) { - if (parent.startsWith(Variables.EPHEMERAL_VARIABLE_PREFIX)) + if (parent.startsWith(Variable.EPHEMERAL_VARIABLE_TOKEN)) // Skip ephemeral variables return; @@ -475,7 +475,7 @@ private void save(PrintWriter pw, String parent, TreeMap map) { // Remove variable separator if needed String name = childKey == null ? parent.substring(0, parent.length() - Variable.SEPARATOR.length()) : parent + childKey; - if (name.startsWith(Variables.EPHEMERAL_VARIABLE_PREFIX)) + if (name.startsWith(Variable.EPHEMERAL_VARIABLE_TOKEN)) // Skip ephemeral variables continue; diff --git a/src/main/java/ch/njol/skript/variables/Variables.java b/src/main/java/ch/njol/skript/variables/Variables.java index adf1b0c4e6a..7411ef75e8d 100644 --- a/src/main/java/ch/njol/skript/variables/Variables.java +++ b/src/main/java/ch/njol/skript/variables/Variables.java @@ -82,8 +82,6 @@ public class Variables { */ private static final String CONFIGURATION_SERIALIZABLE_PREFIX = "ConfigurationSerializable_"; - public static final String EPHEMERAL_VARIABLE_PREFIX = "-"; - private final static Multimap, String> TYPES = HashMultimap.create(); // Register some things with Yggdrasil @@ -889,7 +887,7 @@ public static SerializedVariable serialize(String name, @Nullable Object value) * @param value the value of the variable. */ private static void saveVariableChange(String name, @Nullable Object value) { - if (name.startsWith(Variables.EPHEMERAL_VARIABLE_PREFIX)) + if (name.startsWith(Variable.EPHEMERAL_VARIABLE_TOKEN)) return; saveQueue.add(serialize(name, value)); }