From 6f5d41e0a8020b5e7a44d73fbbe8bd019e00d4a4 Mon Sep 17 00:00:00 2001
From: Efnilite <35348263+Efnilite@users.noreply.github.com>
Date: Thu, 17 Jul 2025 20:52:08 +0200
Subject: [PATCH 01/20] Verbose asserts for contains (#8000)
---
.../njol/skript/conditions/CondContains.java | 28 ++++++++++++++++++-
1 file changed, 27 insertions(+), 1 deletion(-)
diff --git a/src/main/java/ch/njol/skript/conditions/CondContains.java b/src/main/java/ch/njol/skript/conditions/CondContains.java
index 0e713bfeb44..1aa5d9ac245 100644
--- a/src/main/java/ch/njol/skript/conditions/CondContains.java
+++ b/src/main/java/ch/njol/skript/conditions/CondContains.java
@@ -3,6 +3,7 @@
import ch.njol.skript.Skript;
import ch.njol.skript.SkriptConfig;
import ch.njol.skript.aliases.ItemType;
+import ch.njol.skript.lang.VerboseAssert;
import ch.njol.skript.lang.util.common.AnyContains;
import ch.njol.skript.util.LiteralUtils;
import org.skriptlang.skript.lang.comparator.Relation;
@@ -24,7 +25,9 @@
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
+import java.util.List;
import java.util.Objects;
+import java.util.StringJoiner;
@Name("Contains")
@Description("Checks whether an inventory contains an item, a text contains another piece of text, "
@@ -34,7 +37,7 @@
"player has 4 flint and 2 iron ingots",
"{list::*} contains 5"})
@Since("1.0")
-public class CondContains extends Condition {
+public class CondContains extends Condition implements VerboseAssert {
static {
Skript.registerCondition(CondContains.class,
@@ -157,6 +160,29 @@ public boolean check(Event event) {
};
}
+ @Override
+ public String getExpectedMessage(Event event) {
+ StringJoiner joiner = new StringJoiner(" ");
+ joiner.add("to");
+ if (isNegated()) {
+ joiner.add("not");
+ }
+ joiner.add("find %s".formatted(VerboseAssert.getExpressionValue(items, event)));
+ return joiner.toString();
+ }
+
+ @Override
+ public String getReceivedMessage(Event event) {
+ StringJoiner joiner = new StringJoiner(" ");
+ if (!isNegated()) {
+ joiner.add("no");
+ } else {
+ joiner.add("a");
+ }
+ joiner.add("match in %s".formatted(VerboseAssert.getExpressionValue(containers, event)));
+ return joiner.toString();
+ }
+
@Override
public String toString(@Nullable Event e, boolean debug) {
return containers.toString(e, debug) + (isNegated() ? " doesn't contain " : " contains ") + items.toString(e, debug);
From b6974f16a1961e001c2391319777afb93ead09f1 Mon Sep 17 00:00:00 2001
From: LimeGlass <16087552+TheLimeGlass@users.noreply.github.com>
Date: Thu, 17 Jul 2025 13:08:56 -0600
Subject: [PATCH 02/20] Add term 'launch' to projectile launch event (#8009)
---
src/main/java/ch/njol/skript/events/SimpleEvents.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/ch/njol/skript/events/SimpleEvents.java b/src/main/java/ch/njol/skript/events/SimpleEvents.java
index a67711130da..993b9316d4e 100644
--- a/src/main/java/ch/njol/skript/events/SimpleEvents.java
+++ b/src/main/java/ch/njol/skript/events/SimpleEvents.java
@@ -248,7 +248,7 @@ public class SimpleEvents {
.examples("on projectile collide:",
"\tteleport shooter of event-projectile to event-entity")
.since("2.5");
- Skript.registerEvent("Shoot", SimpleEvent.class, ProjectileLaunchEvent.class, "[projectile] shoot")
+ Skript.registerEvent("Shoot", SimpleEvent.class, ProjectileLaunchEvent.class, "[projectile] (shoot|launch)")
.description("Called whenever a projectile is shot. Use the shooter expression to get who shot the projectile.")
.examples("on shoot:",
"\tif projectile is an arrow:",
From b4a514a8043b8938c6ea039970bb88925a76dec6 Mon Sep 17 00:00:00 2001
From: Efnilite <35348263+Efnilite@users.noreply.github.com>
Date: Thu, 24 Jul 2025 17:46:03 +0200
Subject: [PATCH 03/20] Fix function overloading for convertable arguments
(#8046)
---
.../lang/function/FunctionReference.java | 6 +-
.../lang/function/FunctionRegistry.java | 80 ++++++++++++++-----
.../njol/skript/lang/function/Functions.java | 10 ++-
.../lang/function/FunctionRegistryTest.java | 46 ++++++++++-
.../skript/tests/misc/function overloading.sk | 22 +++++
5 files changed, 136 insertions(+), 28 deletions(-)
diff --git a/src/main/java/ch/njol/skript/lang/function/FunctionReference.java b/src/main/java/ch/njol/skript/lang/function/FunctionReference.java
index 7cc7fdfc745..e31ffdfb707 100644
--- a/src/main/java/ch/njol/skript/lang/function/FunctionReference.java
+++ b/src/main/java/ch/njol/skript/lang/function/FunctionReference.java
@@ -4,10 +4,7 @@
import ch.njol.skript.SkriptAPIException;
import ch.njol.skript.classes.ClassInfo;
import ch.njol.skript.config.Node;
-import ch.njol.skript.lang.Expression;
-import ch.njol.skript.lang.KeyProviderExpression;
-import ch.njol.skript.lang.KeyedValue;
-import ch.njol.skript.lang.SkriptParser;
+import ch.njol.skript.lang.*;
import ch.njol.skript.lang.function.FunctionRegistry.Retrieval;
import ch.njol.skript.lang.function.FunctionRegistry.RetrievalResult;
import ch.njol.skript.log.RetainingLogHandler;
@@ -326,7 +323,6 @@ private Function> getRegisteredFunction() {
}
Retrieval> attempt = FunctionRegistry.getRegistry().getFunction(script, functionName, parameterTypes);
-
if (attempt.result() == RetrievalResult.EXACT) {
return attempt.retrieved();
}
diff --git a/src/main/java/ch/njol/skript/lang/function/FunctionRegistry.java b/src/main/java/ch/njol/skript/lang/function/FunctionRegistry.java
index 0274257cea5..09ba1f4978b 100644
--- a/src/main/java/ch/njol/skript/lang/function/FunctionRegistry.java
+++ b/src/main/java/ch/njol/skript/lang/function/FunctionRegistry.java
@@ -280,14 +280,13 @@ record Retrieval(
@NotNull String name,
@NotNull Class>... args
) {
- if (namespace == null) {
- return getFunction(GLOBAL_NAMESPACE, FunctionIdentifier.of(name, false, args));
+ Retrieval> attempt = null;
+ if (namespace != null) {
+ attempt = getFunction(new NamespaceIdentifier(namespace),
+ FunctionIdentifier.of(name, true, args));
}
-
- Retrieval> attempt = getFunction(new NamespaceIdentifier(namespace),
- FunctionIdentifier.of(name, true, args));
- if (attempt.result() == RetrievalResult.NOT_REGISTERED) {
- return getFunction(GLOBAL_NAMESPACE, FunctionIdentifier.of(name, false, args));
+ if (attempt == null || attempt.result() == RetrievalResult.NOT_REGISTERED) {
+ attempt = getFunction(GLOBAL_NAMESPACE, FunctionIdentifier.of(name, false, args));
}
return attempt;
}
@@ -312,7 +311,7 @@ record Retrieval(
return new Retrieval<>(RetrievalResult.NOT_REGISTERED, null, null);
}
- Set candidates = candidates(provided, existing);
+ Set candidates = candidates(provided, existing, false);
if (candidates.isEmpty()) {
Skript.debug("Failed to find a function for '%s'", provided.name);
return new Retrieval<>(RetrievalResult.NOT_REGISTERED, null, null);
@@ -353,14 +352,45 @@ public Retrieval> getSignature(
@NotNull String name,
@NotNull Class>... args
) {
- if (namespace == null) {
- return getSignature(GLOBAL_NAMESPACE, FunctionIdentifier.of(name, false, args));
+ Retrieval> attempt = null;
+ if (namespace != null) {
+ attempt = getSignature(new NamespaceIdentifier(namespace),
+ FunctionIdentifier.of(name, true, args), false);
+ }
+ if (attempt == null || attempt.result() == RetrievalResult.NOT_REGISTERED) {
+ attempt = getSignature(GLOBAL_NAMESPACE, FunctionIdentifier.of(name, false, args), false);
+ }
+ return attempt;
+ }
+
+ /**
+ * Gets the signature for a function with the given name and arguments. If no local function is found,
+ * checks for global functions. If {@code namespace} is null, only global signatures will be checked.
+ *
+ * This function checks performs no argument conversions, and is only used for determining whether a
+ * signature already exists with the exact specified arguments. In almost all cases, {@link #getSignature(String, String, Class[])}
+ * should be used.
+ *
+ *
+ * @param namespace The namespace to get the function from.
+ * Usually represents the path of the script this function is registered in.
+ * @param name The name of the function.
+ * @param args The types of the arguments of the function.
+ * @return The signature for the function with the given name and argument types, or null if no such function exists.
+ */
+ Retrieval> getExactSignature(
+ @Nullable String namespace,
+ @NotNull String name,
+ @NotNull Class>... args
+ ) {
+ Retrieval> attempt = null;
+ if (namespace != null) {
+ attempt = getSignature(new NamespaceIdentifier(namespace),
+ FunctionIdentifier.of(name, true, args), true);
}
- Retrieval> attempt = getSignature(new NamespaceIdentifier(namespace),
- FunctionIdentifier.of(name, true, args));
- if (attempt.result() == RetrievalResult.NOT_REGISTERED) {
- return getSignature(GLOBAL_NAMESPACE, FunctionIdentifier.of(name, false, args));
+ if (attempt == null || attempt.result() == RetrievalResult.NOT_REGISTERED) {
+ attempt = getSignature(GLOBAL_NAMESPACE, FunctionIdentifier.of(name, false, args), true);
}
return attempt;
}
@@ -370,10 +400,12 @@ public Retrieval> getSignature(
*
* @param namespace The namespace to get the function from.
* @param provided The provided identifier of the function.
+ * @param exact When false, will convert arguments to different types to attempt to find a match.
+ * When true, will not convert arguments.
* @return The signature for the function with the given name and argument types, or null if no such signature exists
* in the specified namespace.
*/
- private Retrieval> getSignature(@NotNull NamespaceIdentifier namespace, @NotNull FunctionIdentifier provided) {
+ private Retrieval> getSignature(@NotNull NamespaceIdentifier namespace, @NotNull FunctionIdentifier provided, boolean exact) {
Preconditions.checkNotNull(namespace, "namespace cannot be null");
Preconditions.checkNotNull(provided, "provided cannot be null");
@@ -383,7 +415,7 @@ private Retrieval> getSignature(@NotNull NamespaceIdentifier namesp
return new Retrieval<>(RetrievalResult.NOT_REGISTERED, null, null);
}
- Set candidates = candidates(provided, ns.identifiers.get(provided.name));
+ Set candidates = candidates(provided, ns.identifiers.get(provided.name), exact);
if (candidates.isEmpty()) {
Skript.debug("Failed to find a signature for '%s'", provided.name);
return new Retrieval<>(RetrievalResult.NOT_REGISTERED, null, null);
@@ -415,11 +447,14 @@ private Retrieval> getSignature(@NotNull NamespaceIdentifier namesp
*
* @param provided The provided function.
* @param existing The existing functions with the same name.
+ * @param exact When false, will convert arguments to different types to attempt to find a match.
+ * When true, will not convert arguments.
* @return An unmodifiable list of candidates for the provided function.
*/
private static @Unmodifiable @NotNull Set candidates(
@NotNull FunctionIdentifier provided,
- Set existing
+ Set existing,
+ boolean exact
) {
Set candidates = new HashSet<>();
@@ -459,8 +494,15 @@ private Retrieval> getSignature(@NotNull NamespaceIdentifier namesp
candidateType = candidate.args[i];
}
- if (!Converters.converterExists(provided.args[i], candidateType)) {
- continue candidates;
+ Class> providedArg = provided.args[i];
+ if (exact) {
+ if (providedArg != candidateType) {
+ continue candidates;
+ }
+ } else {
+ if (!Converters.converterExists(providedArg, candidateType)) {
+ continue candidates;
+ }
}
}
diff --git a/src/main/java/ch/njol/skript/lang/function/Functions.java b/src/main/java/ch/njol/skript/lang/function/Functions.java
index 909ae8127da..637f61b005d 100644
--- a/src/main/java/ch/njol/skript/lang/function/Functions.java
+++ b/src/main/java/ch/njol/skript/lang/function/Functions.java
@@ -161,14 +161,18 @@ public static JavaFunction> registerFunction(JavaFunction> function) {
Parameter>[] parameters = signature.parameters;
if (parameters.length == 1 && !parameters[0].isSingleValue()) {
- existing = FunctionRegistry.getRegistry().getSignature(signature.script, signature.getName(), parameters[0].type.getC().arrayType());
+ existing = FunctionRegistry.getRegistry().getExactSignature(signature.script, signature.getName(), parameters[0].type.getC().arrayType());
} else {
Class>[] types = new Class>[parameters.length];
for (int i = 0; i < parameters.length; i++) {
- types[i] = parameters[i].type.getC();
+ if (parameters[i].isSingleValue()) {
+ types[i] = parameters[i].type.getC();
+ } else {
+ types[i] = parameters[i].type.getC().arrayType();
+ }
}
- existing = FunctionRegistry.getRegistry().getSignature(signature.script, signature.getName(), types);
+ existing = FunctionRegistry.getRegistry().getExactSignature(signature.script, signature.getName(), types);
}
// if this function has already been registered, only allow it if one function is local and one is global.
diff --git a/src/test/java/ch/njol/skript/lang/function/FunctionRegistryTest.java b/src/test/java/ch/njol/skript/lang/function/FunctionRegistryTest.java
index e7b39f27f1a..d4896dbf59e 100644
--- a/src/test/java/ch/njol/skript/lang/function/FunctionRegistryTest.java
+++ b/src/test/java/ch/njol/skript/lang/function/FunctionRegistryTest.java
@@ -1,10 +1,12 @@
package ch.njol.skript.lang.function;
import ch.njol.skript.SkriptAPIException;
-import ch.njol.skript.lang.function.FunctionRegistry.RetrievalResult;
import ch.njol.skript.lang.function.FunctionRegistry.FunctionIdentifier;
+import ch.njol.skript.lang.function.FunctionRegistry.RetrievalResult;
import ch.njol.skript.lang.util.SimpleLiteral;
import ch.njol.skript.registrations.DefaultClasses;
+import org.bukkit.OfflinePlayer;
+import org.bukkit.entity.Player;
import org.jetbrains.annotations.Nullable;
import org.junit.Test;
@@ -419,4 +421,46 @@ public void testRemoveGlobalScriptFunctions8015() {
assertEquals(RetrievalResult.NOT_REGISTERED, registry.getSignature(null, FUNCTION_NAME).result());
}
+ private static final Function TEST_FUNCTION_P = new SimpleJavaFunction<>(FUNCTION_NAME,
+ new Parameter[]{
+ new Parameter<>("a", DefaultClasses.PLAYER, true, null)
+ }, DefaultClasses.BOOLEAN, true) {
+ @Override
+ public Boolean @Nullable [] executeSimple(Object[][] params) {
+ return new Boolean[]{true};
+ }
+ };
+
+ private static final Function TEST_FUNCTION_OP = new SimpleJavaFunction<>(FUNCTION_NAME,
+ new Parameter[]{
+ new Parameter<>("a", DefaultClasses.OFFLINE_PLAYER, true, null)
+ }, DefaultClasses.BOOLEAN, true) {
+ @Override
+ public Boolean @Nullable [] executeSimple(Object[][] params) {
+ return new Boolean[]{true};
+ }
+ };
+
+ @Test
+ public void testGetExactSignature() {
+ assertSame(RetrievalResult.NOT_REGISTERED, registry.getSignature(null, FUNCTION_NAME, Player.class).result());
+ assertNull(registry.getSignature(null, FUNCTION_NAME, Player.class).retrieved());
+ assertNull(registry.getFunction(null, FUNCTION_NAME, Player.class).retrieved());
+ assertSame(RetrievalResult.NOT_REGISTERED, registry.getSignature(null, FUNCTION_NAME, OfflinePlayer.class).result());
+ assertNull(registry.getSignature(null, FUNCTION_NAME, OfflinePlayer.class).retrieved());
+ assertNull(registry.getFunction(null, FUNCTION_NAME, OfflinePlayer.class).retrieved());
+
+ registry.register(null, TEST_FUNCTION_P);
+
+ assertSame(RetrievalResult.EXACT, registry.getExactSignature(null, FUNCTION_NAME, Player.class).result());
+ assertEquals(TEST_FUNCTION_P.getSignature(), registry.getExactSignature(null, FUNCTION_NAME, Player.class).retrieved());
+ assertNull(registry.getExactSignature(null, FUNCTION_NAME, OfflinePlayer.class).retrieved());
+
+ assertEquals(TEST_FUNCTION_P.getSignature(), registry.getSignature(null, FUNCTION_NAME, Player.class).retrieved());
+ assertEquals(TEST_FUNCTION_P.getSignature(), registry.getSignature(null, FUNCTION_NAME, OfflinePlayer.class).retrieved());
+
+ registry.remove(TEST_FUNCTION_P.getSignature());
+ registry.remove(TEST_FUNCTION_OP.getSignature());
+ }
+
}
diff --git a/src/test/skript/tests/misc/function overloading.sk b/src/test/skript/tests/misc/function overloading.sk
index d7b3836508d..2e47b7d8621 100644
--- a/src/test/skript/tests/misc/function overloading.sk
+++ b/src/test/skript/tests/misc/function overloading.sk
@@ -63,3 +63,25 @@ parse:
test "function overloading with different return types":
assert size of {FunctionOverloading3::parse::*} = 1
assert {FunctionOverloading3::parse::1} contains "Function 'overloaded3' with the same argument types already exists in script"
+
+function overloading_supertype1(p: offlineplayer):
+ stop
+
+parse:
+ results: {FunctionOverloadingSupertype1::parse::*}
+ code:
+ function overloading_supertype1(n: player):
+ stop
+
+function overloading_supertype2(p: player):
+ stop
+
+parse:
+ results: {FunctionOverloadingSupertype2::parse::*}
+ code:
+ function overloading_supertype2(n: offlineplayer):
+ stop
+
+test "function overloading with supertype":
+ assert {FunctionOverloadingSupertype1::parse::*} is not set
+ assert {FunctionOverloadingSupertype2::parse::*} is not set
From 65866967f90c1af44f31e1898bf3635b5224e18c Mon Sep 17 00:00:00 2001
From: SirSmurfy2 <82696841+Absolutionism@users.noreply.github.com>
Date: Fri, 25 Jul 2025 10:43:12 -0400
Subject: [PATCH 04/20] Paper 1.21.8 Update (#8054)
---
build.gradle | 4 ++--
gradle.properties | 2 +-
.../java/ch/njol/skript/util/BlockStateBlock.java | 15 +++++++++++++++
.../ch/njol/skript/util/DelayedChangeBlock.java | 15 +++++++++++++++
.../{paper-1.21.7.json => paper-1.21.8.json} | 4 ++--
5 files changed, 35 insertions(+), 5 deletions(-)
rename src/test/skript/environments/java21/{paper-1.21.7.json => paper-1.21.8.json} (85%)
diff --git a/build.gradle b/build.gradle
index 465c05465c8..73d3fbdedce 100644
--- a/build.gradle
+++ b/build.gradle
@@ -29,7 +29,7 @@ dependencies {
shadow group: 'org.bstats', name: 'bstats-bukkit', version: '3.1.0'
shadow group: 'net.kyori', name: 'adventure-text-serializer-bungeecord', version: '4.4.0'
- implementation group: 'io.papermc.paper', name: 'paper-api', version: '1.21.7-R0.1-SNAPSHOT'
+ implementation group: 'io.papermc.paper', name: 'paper-api', version: '1.21.8-R0.1-SNAPSHOT'
implementation group: 'com.google.code.findbugs', name: 'findbugs', version: '3.0.1'
// bundled with Minecraft 1.19.4+ for display entity transforms
@@ -246,7 +246,7 @@ void createTestTask(String name, String desc, String environments, int javaVersi
def java21 = 21
def java17 = 17
-def latestEnv = 'java21/paper-1.21.7.json'
+def latestEnv = 'java21/paper-1.21.8.json'
def latestJava = java21
def oldestJava = java17
diff --git a/gradle.properties b/gradle.properties
index dcba4acbd6a..669a8aae315 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -7,5 +7,5 @@ groupid=ch.njol
name=skript
version=2.12.0
jarName=Skript.jar
-testEnv=java21/paper-1.21.7
+testEnv=java21/paper-1.21.8
testEnvJavaVersion=21
diff --git a/src/main/java/ch/njol/skript/util/BlockStateBlock.java b/src/main/java/ch/njol/skript/util/BlockStateBlock.java
index d51eccacef4..23973db4781 100644
--- a/src/main/java/ch/njol/skript/util/BlockStateBlock.java
+++ b/src/main/java/ch/njol/skript/util/BlockStateBlock.java
@@ -338,6 +338,21 @@ public void run() {
}
}
+ @Override
+ public boolean breakNaturally(@NotNull ItemStack tool, boolean triggerEffect, boolean dropExperience, boolean forceEffect) {
+ if (delayChanges) {
+ Bukkit.getScheduler().scheduleSyncDelayedTask(Skript.getInstance(), new Runnable() {
+ @Override
+ public void run() {
+ state.getBlock().breakNaturally(tool, triggerEffect, dropExperience, forceEffect);
+ }
+ });
+ return true;
+ } else {
+ return false;
+ }
+ }
+
@Override
public void tick() {
state.getBlock().tick();
diff --git a/src/main/java/ch/njol/skript/util/DelayedChangeBlock.java b/src/main/java/ch/njol/skript/util/DelayedChangeBlock.java
index 687639d94a0..f4916284a85 100644
--- a/src/main/java/ch/njol/skript/util/DelayedChangeBlock.java
+++ b/src/main/java/ch/njol/skript/util/DelayedChangeBlock.java
@@ -339,6 +339,21 @@ public void run() {
}
}
+ @Override
+ public boolean breakNaturally(@NotNull ItemStack tool, boolean triggerEffect, boolean dropExperience, boolean forceEffect) {
+ if (newState != null) {
+ return false;
+ } else {
+ Bukkit.getScheduler().scheduleSyncDelayedTask(Skript.getInstance(), new Runnable() {
+ @Override
+ public void run() {
+ block.breakNaturally(tool, triggerEffect, dropExperience, forceEffect);
+ }
+ });
+ return true;
+ }
+ }
+
@Override
public void tick() {
block.tick();
diff --git a/src/test/skript/environments/java21/paper-1.21.7.json b/src/test/skript/environments/java21/paper-1.21.8.json
similarity index 85%
rename from src/test/skript/environments/java21/paper-1.21.7.json
rename to src/test/skript/environments/java21/paper-1.21.8.json
index 30ad4211522..935cdc8fba7 100644
--- a/src/test/skript/environments/java21/paper-1.21.7.json
+++ b/src/test/skript/environments/java21/paper-1.21.8.json
@@ -1,11 +1,11 @@
{
- "name": "paper-1.21.7",
+ "name": "paper-1.21.8",
"resources": [
{"source": "server.properties.generic", "target": "server.properties"}
],
"paperDownloads": [
{
- "version": "1.21.7",
+ "version": "1.21.8",
"target": "paperclip.jar"
}
],
From 0115e305d41328d2e6adb8b093dfed1a789d27c9 Mon Sep 17 00:00:00 2001
From: Pesek <42549665+Pesekjak@users.noreply.github.com>
Date: Fri, 25 Jul 2025 16:52:26 +0200
Subject: [PATCH 05/20] Checkstyle tab width fix (#8066)
---
checkstyle.xml | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/checkstyle.xml b/checkstyle.xml
index 42794bbeccb..a4006e8fedd 100644
--- a/checkstyle.xml
+++ b/checkstyle.xml
@@ -9,6 +9,8 @@
+
+
@@ -25,7 +27,7 @@
-
+
@@ -35,11 +37,11 @@
-
-
-
-
-
+
+
+
+
+
From 74ad10ce0adf35f5c4635885d4b38a084b1faf35 Mon Sep 17 00:00:00 2001
From: Patrick Miller
Date: Fri, 25 Jul 2025 11:12:26 -0400
Subject: [PATCH 06/20] Fix potential resolution failure with single list
parameter function calls (#8071)
---
.../ch/njol/skript/lang/function/FunctionRegistry.java | 2 +-
...-single list parameter functions can fail to resolve.sk | 7 +++++++
2 files changed, 8 insertions(+), 1 deletion(-)
create mode 100644 src/test/skript/tests/regressions/8070-single list parameter functions can fail to resolve.sk
diff --git a/src/main/java/ch/njol/skript/lang/function/FunctionRegistry.java b/src/main/java/ch/njol/skript/lang/function/FunctionRegistry.java
index 09ba1f4978b..c7619fed68f 100644
--- a/src/main/java/ch/njol/skript/lang/function/FunctionRegistry.java
+++ b/src/main/java/ch/njol/skript/lang/function/FunctionRegistry.java
@@ -470,7 +470,7 @@ private Retrieval> getSignature(@NotNull NamespaceIdentifier namesp
// make sure all types in the passed array are valid for the array parameter
Class> arrayType = candidate.args[0].componentType();
for (Class> arrayArg : provided.args) {
- if (!Converters.converterExists(arrayType, arrayArg)) {
+ if (!Converters.converterExists(arrayArg, arrayType)) {
continue candidates;
}
}
diff --git a/src/test/skript/tests/regressions/8070-single list parameter functions can fail to resolve.sk b/src/test/skript/tests/regressions/8070-single list parameter functions can fail to resolve.sk
new file mode 100644
index 00000000000..b8aa7389ea3
--- /dev/null
+++ b/src/test/skript/tests/regressions/8070-single list parameter functions can fail to resolve.sk
@@ -0,0 +1,7 @@
+local function test(p: potion effect types):
+ stop
+
+test "single list parameter functions":
+ parse:
+ test(night vision and glowing)
+ assert last parse logs is not set with "function call failed to parse"
From 2d8f8eb588487b26411ba46045bb278bc27d3c4f Mon Sep 17 00:00:00 2001
From: LimeGlass <16087552+TheLimeGlass@users.noreply.github.com>
Date: Fri, 25 Jul 2025 10:04:49 -0600
Subject: [PATCH 07/20] Make has potion effect types optional (#8010)
---
.../njol/skript/conditions/CondHasPotion.java | 51 +++++++++++--------
.../syntaxes/conditions/CondHasPotion.sk | 8 +++
2 files changed, 38 insertions(+), 21 deletions(-)
create mode 100644 src/test/skript/tests/syntaxes/conditions/CondHasPotion.sk
diff --git a/src/main/java/ch/njol/skript/conditions/CondHasPotion.java b/src/main/java/ch/njol/skript/conditions/CondHasPotion.java
index b71b6298d27..f8e33aefe26 100644
--- a/src/main/java/ch/njol/skript/conditions/CondHasPotion.java
+++ b/src/main/java/ch/njol/skript/conditions/CondHasPotion.java
@@ -4,39 +4,46 @@
import ch.njol.skript.conditions.base.PropertyCondition;
import ch.njol.skript.conditions.base.PropertyCondition.PropertyType;
import ch.njol.skript.doc.Description;
-import ch.njol.skript.doc.Examples;
+import ch.njol.skript.doc.Example;
import ch.njol.skript.doc.Name;
import ch.njol.skript.doc.Since;
import ch.njol.skript.lang.Condition;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.SkriptParser.ParseResult;
import ch.njol.util.Kleenean;
+
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.Event;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.Nullable;
@Name("Has Potion")
-@Description("Checks whether the given living entities have specific potion effects.")
-@Examples({"if player has potion speed:",
- "\tsend \"You are sonic!\"",
- "",
- "if all players have potion effects speed and haste:",
- "\tbroadcast \"You are ready to MINE!\""})
+@Description("Checks whether the given living entities have potion effects.")
+@Example("""
+ if player has potion speed:
+ send "You are sonic!"
+ if all players have potion effects speed and haste:
+ broadcast "You are ready to MINE!"
+ """)
@Since("2.6.1")
public class CondHasPotion extends Condition {
static {
- Skript.registerCondition(CondHasPotion.class,
- "%livingentities% (has|have) potion[s] [effect[s]] %potioneffecttypes%",
- "%livingentities% (doesn't|does not|do not|don't) have potion[s] [effect[s]] %potioneffecttypes%");
+ Skript.registerCondition(
+ CondHasPotion.class,
+ PropertyCondition.getPatterns(
+ PropertyType.HAVE,
+ "([any] potion effect[s]|potion[s] [effect[s]] %-potioneffecttypes%)",
+ "livingentities"
+ )
+ );
}
-
- private Expression livingEntities;
+
private Expression potionEffects;
+ private Expression livingEntities;
@Override
- @SuppressWarnings({"unchecked", "null"})
+ @SuppressWarnings("unchecked")
public boolean init(Expression>[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
livingEntities = (Expression) exprs[0];
potionEffects = (Expression) exprs[1];
@@ -45,17 +52,19 @@ public boolean init(Expression>[] exprs, int matchedPattern, Kleenean isDelaye
}
@Override
- public boolean check(Event e) {
- return livingEntities.check(e,
- livingEntity -> potionEffects.check(e,
- livingEntity::hasPotionEffect
- ), isNegated());
+ public boolean check(Event event) {
+ if (potionEffects == null) {
+ return livingEntities.check(event, entity -> !entity.getActivePotionEffects().isEmpty(), isNegated());
+ }
+ return livingEntities.check(event,
+ entity -> potionEffects.check(event, entity::hasPotionEffect),
+ isNegated());
}
@Override
- public String toString(@Nullable Event e, boolean debug) {
- return PropertyCondition.toString(this, PropertyType.HAVE, e, debug, livingEntities,
- "potion " + potionEffects.toString(e, debug));
+ public String toString(@Nullable Event event, boolean debug) {
+ String effects = (potionEffects == null) ? "any potion effect" : "potion " + potionEffects.toString(event, debug);
+ return PropertyCondition.toString(this, PropertyType.HAVE, event, debug, livingEntities, effects);
}
}
diff --git a/src/test/skript/tests/syntaxes/conditions/CondHasPotion.sk b/src/test/skript/tests/syntaxes/conditions/CondHasPotion.sk
new file mode 100644
index 00000000000..eee7b58b5fc
--- /dev/null
+++ b/src/test/skript/tests/syntaxes/conditions/CondHasPotion.sk
@@ -0,0 +1,8 @@
+test "has potion":
+ spawn a pig at event-location
+ apply ambient strength of tier 5 to last spawned pig for 10 seconds
+
+ assert last spawned pig has any potion effect with "pig has no potion effect"
+ assert last spawned pig has potion effect strength with "pig has strength potion effect"
+
+ clear last spawned pig
From ce32116228a2fa8d3d9927874ab6dba02f2730a8 Mon Sep 17 00:00:00 2001
From: Patrick Miller
Date: Fri, 25 Jul 2025 12:37:58 -0400
Subject: [PATCH 08/20] Fix expression section claim releasing (#8082)
---
src/main/java/ch/njol/skript/lang/Statement.java | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/src/main/java/ch/njol/skript/lang/Statement.java b/src/main/java/ch/njol/skript/lang/Statement.java
index b8154d85789..1435e331dc8 100644
--- a/src/main/java/ch/njol/skript/lang/Statement.java
+++ b/src/main/java/ch/njol/skript/lang/Statement.java
@@ -51,9 +51,23 @@ public abstract class Statement extends TriggerItem implements SyntaxElement {
var iterator = Skript.instance().syntaxRegistry().syntaxes(org.skriptlang.skript.registration.SyntaxRegistry.STATEMENT).iterator();
Section.SectionContext sectionContext = ParserInstance.get().getData(Section.SectionContext.class);
if (node != null) {
+ var wrappedIterator = new Iterator<>() {
+ @Override
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+
+ @Override
+ public org.skriptlang.skript.registration.SyntaxInfo extends Statement> next() {
+ // it is possible that the section would have been claimed during the attempt to parse the previous info
+ // as a result, we need to "unclaim" it
+ sectionContext.owner = null;
+ return iterator.next();
+ }
+ };
statement = sectionContext.modify(node, items, () -> {
//noinspection unchecked,rawtypes
- Statement parsed = (Statement) SkriptParser.parse(input, (Iterator) iterator, defaultError);
+ Statement parsed = (Statement) SkriptParser.parse(input, (Iterator) wrappedIterator, defaultError);
if (parsed != null && !sectionContext.claimed()) {
Skript.error("The line '" + input + "' is a valid statement but cannot function as a section (:) because there is no syntax in the line to manage it.");
return null;
From dbbe9161df871421d383fee74dfe95be31b6c703 Mon Sep 17 00:00:00 2001
From: Patrick Miller
Date: Fri, 25 Jul 2025 14:15:04 -0400
Subject: [PATCH 09/20] Improve ExprXOf Literal Handling (#8081)
---
.../ch/njol/skript/expressions/ExprXOf.java | 85 +++++++++++++------
.../simplification/SimplifiedLiteral.java | 29 +++----
.../njol/skript/lang/util/SimpleLiteral.java | 14 +--
.../tests/syntaxes/expressions/ExprXOf.sk | 5 ++
4 files changed, 82 insertions(+), 51 deletions(-)
diff --git a/src/main/java/ch/njol/skript/expressions/ExprXOf.java b/src/main/java/ch/njol/skript/expressions/ExprXOf.java
index 29aea04ada8..d8df50519c9 100644
--- a/src/main/java/ch/njol/skript/expressions/ExprXOf.java
+++ b/src/main/java/ch/njol/skript/expressions/ExprXOf.java
@@ -4,6 +4,7 @@
import ch.njol.skript.aliases.ItemType;
import ch.njol.skript.doc.Description;
import ch.njol.skript.doc.Examples;
+import ch.njol.skript.doc.Keywords;
import ch.njol.skript.doc.Name;
import ch.njol.skript.doc.Since;
import ch.njol.skript.entity.EntityType;
@@ -12,77 +13,105 @@
import ch.njol.skript.lang.ExpressionType;
import ch.njol.skript.lang.Literal;
import ch.njol.skript.lang.SkriptParser.ParseResult;
+import ch.njol.skript.lang.simplification.SimplifiedLiteral;
import ch.njol.util.Kleenean;
-import ch.njol.util.coll.CollectionUtils;
import org.bukkit.event.Event;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
-@Name("X of Item")
-@Description("An expression to be able to use a certain amount of items where the amount can be any expression. Please note that this expression is not stable and might be replaced in the future.")
+@Name("X of Item/Entity Type")
+@Description("An expression for using an item or entity type with a different amount.")
@Examples("give level of player of iron pickaxes to the player")
@Since("1.2")
+@Keywords("amount")
public class ExprXOf extends PropertyExpression