"));
desc = desc
- .replace("${element.desc-safe}", Joiner.on("\\n").join(description)
+ .replace("${element.desc-safe}", Joiner.on("\\n").join(description)
.replace("\\", "\\\\").replace("\"", "\\\"").replace("\t", " "));
// By Addon
@@ -721,20 +684,13 @@ private String generateClass(String descTemp, ClassInfo> info, @Nullable Strin
String[] examples = getDefaultIfNullOrEmpty(info.getExamples(), "Missing examples.");
desc = desc.replace("${element.examples}", Joiner.on("\n ").join(Documentation.escapeHTML(examples)));
desc = desc.replace("${element.examples-safe}", Joiner.on("\\n").join(Documentation.escapeHTML(examples))
- .replace("\\", "\\\\").replace("\"", "\\\"").replace("\t", " "));
+ .replace("\\", "\\\\").replace("\"", "\\\"").replace("\t", " "));
Keywords keywords = c.getAnnotation(Keywords.class);
desc = desc.replace("${element.keywords}", keywords == null ? "" : Joiner.on(", ").join(keywords.value()));
// Documentation ID
- String ID = info.getDocumentationID() != null ? info.getDocumentationID() : info.getCodeName();
- // Fix duplicated IDs
- if (page != null) {
- if (page.contains("href=\"#" + ID + "\"")) {
- ID = ID + "-" + (StringUtils.countMatches(page, "href=\"#" + ID + "\"") + 1);
- }
- }
- desc = desc.replace("${element.id}", ID);
+ desc = desc.replace("${element.id}", DocumentationIdProvider.getId(info));
// Cancellable
desc = handleIf(desc, "${if cancellable}", false);
@@ -777,14 +733,14 @@ private String generateClass(String descTemp, ClassInfo> info, @Nullable Strin
int nextBracket = desc.indexOf("}", generate);
String data = desc.substring(generate + 11, nextBracket);
toGen.add(data);
-
+
generate = desc.indexOf("${generate", nextBracket);
}
-
+
// Assume element.pattern generate
for (String data : toGen) {
String[] split = data.split(" ");
- String pattern = readFile(new File(template + "/templates/" + split[1]));
+ String pattern = readFile(new File(templateDir + "/templates/" + split[1]));
StringBuilder patterns = new StringBuilder();
String[] lines = getDefaultIfNullOrEmpty(info.getUsage(), "Missing patterns.");
if (lines == null)
@@ -795,15 +751,15 @@ private String generateClass(String descTemp, ClassInfo> info, @Nullable Strin
String parsed = pattern.replace("${element.pattern}", line);
patterns.append(parsed);
}
-
+
desc = desc.replace("${generate element.patterns " + split[1] + "}", patterns.toString());
desc = desc.replace("${generate element.patterns-safe " + split[1] + "}", patterns.toString().replace("\\", "\\\\"));
}
-
+
assert desc != null;
return desc;
}
-
+
private String generateFunction(String descTemp, JavaFunction> info) {
String desc = "";
@@ -819,7 +775,7 @@ private String generateFunction(String descTemp, JavaFunction> info) {
String[] description = getDefaultIfNullOrEmpty(info.getDescription(), "Missing description.");
desc = desc.replace("${element.desc}", Joiner.on("\n").join(description));
desc = desc
- .replace("${element.desc-safe}", Joiner.on("\\n").join(description)
+ .replace("${element.desc-safe}", Joiner.on("\\n").join(description)
.replace("\\", "\\\\").replace("\"", "\\\"").replace("\t", " "));
// By Addon
@@ -832,14 +788,14 @@ private String generateFunction(String descTemp, JavaFunction> info) {
String[] examples = getDefaultIfNullOrEmpty(info.getExamples(), "Missing examples.");
desc = desc.replace("${element.examples}", Joiner.on("\n ").join(Documentation.escapeHTML(examples)));
desc = desc
- .replace("${element.examples-safe}", Joiner.on("\\n").join(examples)
+ .replace("${element.examples-safe}", Joiner.on("\\n").join(examples)
.replace("\\", "\\\\").replace("\"", "\\\"").replace("\t", " "));
String[] keywords = info.getKeywords();
desc = desc.replace("${element.keywords}", keywords == null ? "" : Joiner.on(", ").join(keywords));
// Documentation ID
- desc = desc.replace("${element.id}", info.getName());
+ desc = desc.replace("${element.id}", DocumentationIdProvider.getId(info));
// Cancellable
desc = handleIf(desc, "${if cancellable}", false);
@@ -870,31 +826,26 @@ private String generateFunction(String descTemp, JavaFunction> info) {
int nextBracket = desc.indexOf("}", generate);
String data = desc.substring(generate + 11, nextBracket);
toGen.add(data);
-
+
generate = desc.indexOf("${generate", nextBracket);
}
-
+
// Assume element.pattern generate
for (String data : toGen) {
String[] split = data.split(" ");
- String pattern = readFile(new File(template + "/templates/" + split[1]));
+ String pattern = readFile(new File(templateDir + "/templates/" + split[1]));
String patterns = "";
- Parameter>[] params = info.getParameters();
- String[] types = new String[params.length];
- for (int i = 0; i < types.length; i++) {
- types[i] = params[i].toString();
- }
- String line = docName + "(" + Joiner.on(", ").join(types) + ")"; // Better not have nulls
+ String line = info.getSignature().toString(false, false); // Better not have nulls
patterns += pattern.replace("${element.pattern}", line);
-
+
desc = desc.replace("${generate element.patterns " + split[1] + "}", patterns);
desc = desc.replace("${generate element.patterns-safe " + split[1] + "}", patterns.replace("\\", "\\\\"));
}
-
+
assert desc != null;
return desc;
}
-
+
@SuppressWarnings("null")
private static String readFile(File f) {
try {
@@ -904,7 +855,7 @@ private static String readFile(File f) {
return "";
}
}
-
+
private static void writeFile(File f, String data) {
try {
Files.write(data, f, StandardCharsets.UTF_8);
@@ -912,7 +863,7 @@ private static void writeFile(File f, String data) {
e.printStackTrace();
}
}
-
+
private static String cleanPatterns(final String patterns) {
return Documentation.cleanPatterns(patterns);
}
@@ -926,14 +877,14 @@ private static String cleanPatterns(final String patterns, boolean escapeHTML) {
/**
* Checks if a string is empty or null then it will return the message provided
- *
+ *
* @param string the String to check
* @param message the String to return if either condition is true
*/
public String getDefaultIfNullOrEmpty(@Nullable String string, String message) {
return (string == null || string.isEmpty()) ? message : string; // Null check first otherwise NullPointerException is thrown
}
-
+
public String[] getDefaultIfNullOrEmpty(@Nullable String[] string, String message) {
return (string == null || string.length == 0 || string[0].equals("")) ? new String[]{ message } : string; // Null check first otherwise NullPointerException is thrown
}
diff --git a/src/main/java/ch/njol/skript/doc/JSONGenerator.java b/src/main/java/ch/njol/skript/doc/JSONGenerator.java
new file mode 100644
index 00000000000..9e33a90f66c
--- /dev/null
+++ b/src/main/java/ch/njol/skript/doc/JSONGenerator.java
@@ -0,0 +1,251 @@
+package ch.njol.skript.doc;
+
+import ch.njol.skript.Skript;
+import ch.njol.skript.classes.ClassInfo;
+import ch.njol.skript.lang.SkriptEventInfo;
+import ch.njol.skript.lang.SyntaxElement;
+import ch.njol.skript.lang.SyntaxElementInfo;
+import ch.njol.skript.lang.function.Functions;
+import ch.njol.skript.lang.function.JavaFunction;
+import ch.njol.skript.registrations.Classes;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonPrimitive;
+import org.jetbrains.annotations.Nullable;
+import org.skriptlang.skript.lang.structure.Structure;
+import org.skriptlang.skript.lang.structure.StructureInfo;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Iterator;
+import java.util.Objects;
+import java.util.stream.Stream;
+
+/**
+ * Generates JSON docs
+ */
+public class JSONGenerator extends DocumentationGenerator {
+
+ public JSONGenerator(File templateDir, File outputDir) {
+ super(templateDir, outputDir);
+ }
+
+ /**
+ * Coverts a String array to a JsonArray
+ * @param strings the String array to convert
+ * @return the JsonArray containing the Strings
+ */
+ private static @Nullable JsonArray convertToJsonArray(String @Nullable [] strings) {
+ if (strings == null)
+ return null;
+ JsonArray jsonArray = new JsonArray();
+ for (String string : strings)
+ jsonArray.add(new JsonPrimitive(string));
+ return jsonArray;
+ }
+
+ /**
+ * Generates the documentation JsonObject for an element that is annotated with documentation
+ * annotations (e.g. effects, conditions, etc.)
+ * @param syntaxInfo the syntax info element to generate the documentation object of
+ * @return the JsonObject representing the documentation of the provided syntax element
+ */
+ private @Nullable JsonObject generatedAnnotatedElement(SyntaxElementInfo> syntaxInfo) {
+ Class> syntaxClass = syntaxInfo.getElementClass();
+ Name nameAnnotation = syntaxClass.getAnnotation(Name.class);
+ if (nameAnnotation == null || syntaxClass.getAnnotation(NoDoc.class) != null)
+ return null;
+ JsonObject syntaxJsonObject = new JsonObject();
+ syntaxJsonObject.addProperty("id", DocumentationIdProvider.getId(syntaxInfo));
+ syntaxJsonObject.addProperty("name", nameAnnotation.value());
+
+ Since sinceAnnotation = syntaxClass.getAnnotation(Since.class);
+ syntaxJsonObject.addProperty("since", sinceAnnotation == null ? null : sinceAnnotation.value());
+
+ Description descriptionAnnotation = syntaxClass.getAnnotation(Description.class);
+ if (descriptionAnnotation != null) {
+ syntaxJsonObject.add("description", convertToJsonArray(descriptionAnnotation.value()));
+ } else {
+ syntaxJsonObject.add("description", new JsonArray());
+ }
+
+ Examples examplesAnnotation = syntaxClass.getAnnotation(Examples.class);
+ if (examplesAnnotation != null) {
+ syntaxJsonObject.add("examples", convertToJsonArray(examplesAnnotation.value()));
+ } else {
+ syntaxJsonObject.add("examples", new JsonArray());
+ }
+
+
+ syntaxJsonObject.add("patterns", convertToJsonArray(syntaxInfo.getPatterns()));
+ return syntaxJsonObject;
+ }
+
+ /**
+ * Generates the documentation JsonObject for an event
+ * @param eventInfo the event to generate the documentation object for
+ * @return a documentation JsonObject for the event
+ */
+ private JsonObject generateEventElement(SkriptEventInfo> eventInfo) {
+ JsonObject syntaxJsonObject = new JsonObject();
+ syntaxJsonObject.addProperty("id", DocumentationIdProvider.getId(eventInfo));
+ syntaxJsonObject.addProperty("name", eventInfo.name);
+ syntaxJsonObject.addProperty("since", eventInfo.getSince());
+ syntaxJsonObject.add("description", convertToJsonArray(eventInfo.getDescription()));
+ syntaxJsonObject.add("examples", convertToJsonArray(eventInfo.getExamples()));
+ syntaxJsonObject.add("patterns", convertToJsonArray(eventInfo.patterns));
+ return syntaxJsonObject;
+ }
+
+
+ /**
+ * Generates a JsonArray containing the documentation JsonObjects for each structure in the iterator
+ * @param infos the structures to generate documentation for
+ * @return a JsonArray containing the documentation JsonObjects for each structure
+ */
+ private > JsonArray generateStructureElementArray(Iterator infos) {
+ JsonArray syntaxArray = new JsonArray();
+ infos.forEachRemaining(info -> {
+ if (info instanceof SkriptEventInfo> eventInfo) {
+ syntaxArray.add(generateEventElement(eventInfo));
+ } else {
+ JsonObject structureElementJsonObject = generatedAnnotatedElement(info);
+ if (structureElementJsonObject != null)
+ syntaxArray.add(structureElementJsonObject);
+ }
+ });
+ return syntaxArray;
+ }
+
+ /**
+ * Generates a JsonArray containing the documentation JsonObjects for each syntax element in the iterator
+ * @param infos the syntax elements to generate documentation for
+ * @return a JsonArray containing the documentation JsonObjects for each syntax element
+ */
+ private > JsonArray generateSyntaxElementArray(Iterator infos) {
+ JsonArray syntaxArray = new JsonArray();
+ infos.forEachRemaining(info -> {
+ JsonObject syntaxJsonObject = generatedAnnotatedElement(info);
+ if (syntaxJsonObject != null)
+ syntaxArray.add(syntaxJsonObject);
+ });
+ return syntaxArray;
+ }
+
+ /**
+ * Generates the documentation JsonObject for a classinfo
+ * @param classInfo the ClassInfo to generate the documentation of
+ * @return the documentation Jsonobject of the ClassInfo
+ */
+ private @Nullable JsonObject generateClassInfoElement(ClassInfo> classInfo) {
+ if (!classInfo.hasDocs())
+ return null;
+ JsonObject syntaxJsonObject = new JsonObject();
+ syntaxJsonObject.addProperty("id", DocumentationIdProvider.getId(classInfo));
+ syntaxJsonObject.addProperty("name", getClassInfoName(classInfo));
+ syntaxJsonObject.addProperty("since", classInfo.getSince());
+ syntaxJsonObject.add("description", convertToJsonArray(classInfo.getDescription()));
+ syntaxJsonObject.add("examples", convertToJsonArray(classInfo.getExamples()));
+ syntaxJsonObject.add("patterns", convertToJsonArray(classInfo.getUsage()));
+ return syntaxJsonObject;
+ }
+
+ /**
+ * Generates a JsonArray containing the documentation JsonObjects for each classinfo in the iterator
+ * @param classInfos the classinfos to generate documentation for
+ * @return a JsonArray containing the documentation JsonObjects for each classinfo
+ */
+ private JsonArray generateClassInfoArray(Iterator> classInfos) {
+ JsonArray syntaxArray = new JsonArray();
+ classInfos.forEachRemaining(classInfo -> {
+ JsonObject classInfoElement = generateClassInfoElement(classInfo);
+ if (classInfoElement != null)
+ syntaxArray.add(classInfoElement);
+ });
+ return syntaxArray;
+ }
+
+ /**
+ * Gets either the explicitly declared documentation name or code name of a ClassInfo
+ * @param classInfo the ClassInfo to get the effective name of
+ * @return the effective name of the ClassInfo
+ */
+ private String getClassInfoName(ClassInfo> classInfo) {
+ return Objects.requireNonNullElse(classInfo.getDocName(), classInfo.getCodeName());
+ }
+
+ /**
+ * Generates the documentation JsonObject for a JavaFunction
+ * @param function the JavaFunction to generate the JsonObject of
+ * @return the JsonObject of the JavaFunction
+ */
+ private JsonObject generateFunctionElement(JavaFunction> function) {
+ JsonObject functionJsonObject = new JsonObject();
+ functionJsonObject.addProperty("id", DocumentationIdProvider.getId(function));
+ functionJsonObject.addProperty("name", function.getName());
+ functionJsonObject.addProperty("since", function.getSince());
+ functionJsonObject.add("description", convertToJsonArray(function.getDescription()));
+ functionJsonObject.add("examples", convertToJsonArray(function.getExamples()));
+
+ ClassInfo> returnType = function.getReturnType();
+ if (returnType != null) {
+ functionJsonObject.addProperty("return-type", getClassInfoName(returnType));
+ }
+
+ String functionSignature = function.getSignature().toString(false, false);
+ functionJsonObject.add("patterns", convertToJsonArray(new String[] { functionSignature }));
+ return functionJsonObject;
+ }
+
+ /**
+ * Generates a JsonArray containing the documentation JsonObjects for each function in the iterator
+ * @param functions the functions to generate documentation for
+ * @return a JsonArray containing the documentation JsonObjects for each function
+ */
+ private JsonArray generateFunctionArray(Iterator> functions) {
+ JsonArray syntaxArray = new JsonArray();
+ functions.forEachRemaining(function -> syntaxArray.add(generateFunctionElement(function)));
+ return syntaxArray;
+ }
+
+ /**
+ * Writes the documentation JsonObject to an output path
+ * @param outputPath the path to write the documentation to
+ * @param jsonDocs the documentation JsonObject
+ */
+ private void saveDocs(Path outputPath, JsonObject jsonDocs) {
+ try {
+ Gson jsonGenerator = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting().create();
+ Files.writeString(outputPath, jsonGenerator.toJson(jsonDocs));
+ } catch (IOException exception) {
+ //noinspection ThrowableNotThrown
+ Skript.exception(exception, "An error occurred while trying to generate JSON documentation");
+ }
+ }
+
+ @Override
+ public void generate() {
+ JsonObject jsonDocs = new JsonObject();
+
+ jsonDocs.add("skriptVersion", new JsonPrimitive(Skript.getVersion().toString()));
+ jsonDocs.add("conditions", generateSyntaxElementArray(Skript.getConditions().iterator()));
+ jsonDocs.add("effects", generateSyntaxElementArray(Skript.getEffects().iterator()));
+ jsonDocs.add("expressions", generateSyntaxElementArray(Skript.getExpressions()));
+ jsonDocs.add("events", generateStructureElementArray(Skript.getEvents().iterator()));
+ jsonDocs.add("classes", generateClassInfoArray(Classes.getClassInfos().iterator()));
+
+ Stream> structuresExcludingEvents = Skript.getStructures().stream()
+ .filter(structureInfo -> !(structureInfo instanceof SkriptEventInfo));
+ jsonDocs.add("structures", generateStructureElementArray(structuresExcludingEvents.iterator()));
+ jsonDocs.add("sections", generateSyntaxElementArray(Skript.getSections().iterator()));
+
+ jsonDocs.add("functions", generateFunctionArray(Functions.getJavaFunctions().iterator()));
+
+ saveDocs(outputDir.toPath().resolve("docs.json"), jsonDocs);
+ }
+
+}
diff --git a/src/main/java/ch/njol/skript/lang/function/Parameter.java b/src/main/java/ch/njol/skript/lang/function/Parameter.java
index deee1d1593e..87707ff7b05 100644
--- a/src/main/java/ch/njol/skript/lang/function/Parameter.java
+++ b/src/main/java/ch/njol/skript/lang/function/Parameter.java
@@ -199,7 +199,11 @@ public boolean isSingleValue() {
@Override
public String toString() {
- return name + ": " + Utils.toEnglishPlural(type.getCodeName(), !single) + (def != null ? " = " + def.toString(null, true) : "");
+ return toString(Skript.debug());
+ }
+
+ public String toString(boolean debug) {
+ return name + ": " + Utils.toEnglishPlural(type.getCodeName(), !single) + (def != null ? " = " + def.toString(null, debug) : "");
}
}
diff --git a/src/main/java/ch/njol/skript/lang/function/Signature.java b/src/main/java/ch/njol/skript/lang/function/Signature.java
index e7e8477d633..a4e4b05cd56 100644
--- a/src/main/java/ch/njol/skript/lang/function/Signature.java
+++ b/src/main/java/ch/njol/skript/lang/function/Signature.java
@@ -18,7 +18,9 @@
*/
package ch.njol.skript.lang.function;
+import ch.njol.skript.Skript;
import ch.njol.skript.classes.ClassInfo;
+import ch.njol.skript.util.Utils;
import ch.njol.skript.util.Contract;
import org.jetbrains.annotations.Nullable;
@@ -171,5 +173,34 @@ public int getMinParameters() {
public int hashCode() {
return name.hashCode();
}
-
+
+ @Override
+ public String toString() {
+ return toString(true, Skript.debug());
+ }
+
+ public String toString(boolean includeReturnType, boolean debug) {
+ StringBuilder signatureBuilder = new StringBuilder();
+
+ if (local)
+ signatureBuilder.append("local ");
+ signatureBuilder.append(name);
+
+ signatureBuilder.append('(');
+ int lastParameterIndex = parameters.length - 1;
+ for (int i = 0; i < parameters.length; i++) {
+ signatureBuilder.append(parameters[i].toString(debug));
+ if (i != lastParameterIndex)
+ signatureBuilder.append(", ");
+ }
+ signatureBuilder.append(')');
+
+ if (includeReturnType && returnType != null) {
+ signatureBuilder.append(" :: ");
+ signatureBuilder.append(Utils.toEnglishPlural(returnType.getCodeName(), !single));
+ }
+
+ return signatureBuilder.toString();
+ }
+
}
From c11551faa7d690e61990ddbebe80ddd2c118ed8f Mon Sep 17 00:00:00 2001
From: Efy <35348263+Efnilite@users.noreply.github.com>
Date: Sat, 21 Sep 2024 21:52:29 +0200
Subject: [PATCH 05/26] Fix missing "and" warnings (#7036)
* init commit innit
* updates
* removed comma for only lists of two
* Remove changes from feature branch.
---------
Co-authored-by: Moderocky
Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com>
---
.../pull-6586-effhealth item mutation.sk | 2 +-
.../tests/syntaxes/conditions/CondCompare.sk | 14 +++++++-------
.../tests/syntaxes/expressions/ExprRepeat.sk | 6 +++---
.../tests/syntaxes/expressions/ExprStringCase.sk | 2 +-
4 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/src/test/skript/tests/regressions/pull-6586-effhealth item mutation.sk b/src/test/skript/tests/regressions/pull-6586-effhealth item mutation.sk
index aa70a29ceda..a048155c588 100644
--- a/src/test/skript/tests/regressions/pull-6586-effhealth item mutation.sk
+++ b/src/test/skript/tests/regressions/pull-6586-effhealth item mutation.sk
@@ -9,6 +9,6 @@ test "EffHealth item mutation fix":
set {_item1} to diamond sword with damage 100
set {_item2} to diamond with damage 10
- repair {_item1}, {_item2}
+ repair {_item1} and {_item2}
assert {_item1} is diamond sword with damage 0 with "{_item1} was incorrectly repaired"
assert {_item2} is diamond with "{_item2} was no longer a diamond"
diff --git a/src/test/skript/tests/syntaxes/conditions/CondCompare.sk b/src/test/skript/tests/syntaxes/conditions/CondCompare.sk
index a182b0f4923..3f63431b737 100644
--- a/src/test/skript/tests/syntaxes/conditions/CondCompare.sk
+++ b/src/test/skript/tests/syntaxes/conditions/CondCompare.sk
@@ -6,14 +6,14 @@ test "compare":
assert 1 is greater than or equal to 0 and 1 with "Number is not greater than or equal to two smaller/equal numbers"
assert 1 is less than or equal to 1 and 2 with "Number is not smaller than or equal to two greater/equal numbers"
- assert 1, 2 is 1, 2 with "direct list comparison of equal numbers failed"
- assert 1, 2, 3 is not 1, 2 with "direct list comparison of non-equal numbers succeeded"
- assert 1, 2 is 1, 2, or 3 with "comparison between AND list of numbers and OR list of superset of numbers failed"
- assert 1, 2, 3 is 1 or 2 to fail with "comparison between AND list of numbers and OR list of subset of numbers succeeded"
+ assert 1 and 2 is 1 and 2 with "direct list comparison of equal numbers failed"
+ assert 1, 2, and 3 is not 1 and 2 with "direct list comparison of non-equal numbers succeeded"
+ assert 1 and 2 is 1, 2, or 3 with "comparison between AND list of numbers and OR list of superset of numbers failed"
+ assert 1, 2, and 3 is 1 or 2 to fail with "comparison between AND list of numbers and OR list of subset of numbers succeeded"
- assert 1, 2, 3 is greater than -1, -2, -3 with "Numbers are not larger than smaller numbers"
- assert 1, 2, 3 is less than 5, 6, 7 with "Numbers are not smaller than larger numbers"
- assert 1, 2, 3 is between -1, 1 and 3, 3.5 with "Numbers are not between smaller/equal numbers and larger/equal numbers"
+ assert 1, 2, and 3 is greater than -1, -2, and -3 with "Numbers are not larger than smaller numbers"
+ assert 1, 2, and 3 is less than 5, 6, and 7 with "Numbers are not smaller than larger numbers"
+ assert 1, 2, and 3 is between (-1 and 1) and (3 and 3.5) with "Numbers are not between smaller/equal numbers and larger/equal numbers"
assert 10 is between 5 and 15 with "Number isn't between smaller and larger"
assert 10 is between 9 and 11 with "Number isn't between smaller and larger"
diff --git a/src/test/skript/tests/syntaxes/expressions/ExprRepeat.sk b/src/test/skript/tests/syntaxes/expressions/ExprRepeat.sk
index fc2cbac598b..96dd6a1c100 100644
--- a/src/test/skript/tests/syntaxes/expressions/ExprRepeat.sk
+++ b/src/test/skript/tests/syntaxes/expressions/ExprRepeat.sk
@@ -43,7 +43,7 @@ test "repeat expression":
then:
assert false is true with "ExprRepeat Multi - 1) 'aa' and 'b' repeated 3 times is not 'aaaaaa' and 'bbb'"
- set {_strings::*} to "aa", "b"
+ set {_strings::*} to "aa" and "b"
set {_strings::*} to {_strings::*} repeated {_repeat} times
if any:
{_strings::1} is not "aaaaaa"
@@ -51,7 +51,7 @@ test "repeat expression":
then:
assert false is true with "ExprRepeat Multi - 2) 'aa' and 'b' repeated 3 times is not 'aaaaaa' and 'bbb'"
- set {_strings::*} to "aa", "b"
+ set {_strings::*} to "aa" and "b"
set {_strings::*} to {_strings::*} repeated 3 times
if any:
{_strings::1} is not "aaaaaa"
@@ -59,7 +59,7 @@ test "repeat expression":
then:
assert false is true with "ExprRepeat Multi - 3) 'aa' and 'b' repeated 3 times is not 'aaaaaa' and 'bbb'"
- set {_strings::*} to "aa", "b" repeated {_repeat} times
+ set {_strings::*} to "aa" and "b" repeated {_repeat} times
if any:
{_strings::1} is not "aaaaaa"
{_strings::2} is not "bbb"
diff --git a/src/test/skript/tests/syntaxes/expressions/ExprStringCase.sk b/src/test/skript/tests/syntaxes/expressions/ExprStringCase.sk
index acca046bad5..593cb9578b0 100644
--- a/src/test/skript/tests/syntaxes/expressions/ExprStringCase.sk
+++ b/src/test/skript/tests/syntaxes/expressions/ExprStringCase.sk
@@ -1,7 +1,7 @@
test "string cases":
assert caseEquals("Oops!" in lowercase, "oops!") is true with "lowercase failed"
assert caseEquals("Oops!" in uppercase, "OOPS!") is true with "uppercase failed"
- assert caseEquals(capitalised "Oops!", "OOPS!") is true with "capitalised failed"
+ assert caseEquals((capitalised "Oops!"), "OOPS!") is true with "capitalised failed"
assert caseEquals("hellO i'm steve!" in proper case, "HellO I'm Steve!") is true with "lenient proper case failed"
assert caseEquals("hellO i'm steve!" in strict proper case, "Hello I'm Steve!") is true with "strict proper case failed"
assert caseEquals("spAwn neW boSs ()" in camel case, "spAwnNeWBoSs()") is true with "lenient camel case failed"
From 7866bd625bb177db4013aa73c8536d7c000df631 Mon Sep 17 00:00:00 2001
From: LimeGlass <16087552+TheLimeGlass@users.noreply.github.com>
Date: Sat, 21 Sep 2024 14:06:50 -0600
Subject: [PATCH 06/26] Remove good first issue labels when complete or pr
available (#5905)
Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com>
---
.../github-issues/issues-labeled.yml | 22 +++++++++++++++++++
1 file changed, 22 insertions(+)
create mode 100644 .github/workflows/github-issues/issues-labeled.yml
diff --git a/.github/workflows/github-issues/issues-labeled.yml b/.github/workflows/github-issues/issues-labeled.yml
new file mode 100644
index 00000000000..6f65129b48c
--- /dev/null
+++ b/.github/workflows/github-issues/issues-labeled.yml
@@ -0,0 +1,22 @@
+name: When labels are modified, run actions.
+
+on:
+ issues:
+ types: [labeled]
+
+jobs:
+ remove-good-first-issue-label:
+ if: ${{ github.event.label.name == 'completed' || github.event.label.name == 'PR available'}}
+ runs-on: ubuntu-latest
+ permissions:
+ issues: write
+ steps:
+ - uses: actions/github-script@v6
+ with:
+ script: |
+ github.rest.issues.removeLabel({
+ issue_number: context.issue.number,
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ name: ["good first issue"]
+ })
From 3e3f0a9d77e4e2655162ee2cb8beff11b1f31cdf Mon Sep 17 00:00:00 2001
From: sovdee <10354869+sovdeeth@users.noreply.github.com>
Date: Sat, 21 Sep 2024 17:55:48 -0400
Subject: [PATCH 07/26] bstats - Fix trying to compare enum value to string
value for verbosity and event priority (#7027)
* Fix trying to compare enum value to string value for verbosity and event priority
* wrong polarity for var/command case sensitivity
---
.../org/skriptlang/skript/bukkit/SkriptMetrics.java | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/src/main/java/org/skriptlang/skript/bukkit/SkriptMetrics.java b/src/main/java/org/skriptlang/skript/bukkit/SkriptMetrics.java
index e57c4ec7700..4fa2865378c 100644
--- a/src/main/java/org/skriptlang/skript/bukkit/SkriptMetrics.java
+++ b/src/main/java/org/skriptlang/skript/bukkit/SkriptMetrics.java
@@ -120,12 +120,14 @@ public static void setupMetrics(Metrics metrics) {
metrics.addCustomChart(new DrilldownPie("drilldownLogVerbosity", () -> {
String verbosity = SkriptConfig.verbosity.value().name().toLowerCase(Locale.ENGLISH).replace('_', ' ');
- return isDefaultMap(verbosity, SkriptConfig.verbosity.defaultValue());
+ String defaultValue = SkriptConfig.verbosity.defaultValue().name().toLowerCase(Locale.ENGLISH).replace('_', ' ');
+ return isDefaultMap(verbosity, defaultValue);
}));
metrics.addCustomChart(new DrilldownPie("drilldownPluginPriority", () -> {
String priority = SkriptConfig.defaultEventPriority.value().name().toLowerCase(Locale.ENGLISH).replace('_', ' ');
- return isDefaultMap(priority, SkriptConfig.defaultEventPriority.defaultValue());
+ String defaultValue = SkriptConfig.defaultEventPriority.defaultValue().name().toLowerCase(Locale.ENGLISH).replace('_', ' ');
+ return isDefaultMap(priority, defaultValue);
}));
metrics.addCustomChart(new SimplePie("cancelledByDefault", () ->
SkriptConfig.listenCancelledByDefault.value().toString()
@@ -143,10 +145,10 @@ public static void setupMetrics(Metrics metrics) {
SkriptConfig.caseSensitive.value().toString()
));
metrics.addCustomChart(new SimplePie("caseSensitiveVariables", () ->
- SkriptConfig.caseInsensitiveVariables.value().toString()
+ String.valueOf(!SkriptConfig.caseInsensitiveVariables.value())
));
metrics.addCustomChart(new SimplePie("caseSensitiveCommands", () ->
- SkriptConfig.caseInsensitiveCommands.value().toString()
+ String.valueOf(!SkriptConfig.caseInsensitiveCommands.value())
));
metrics.addCustomChart(new SimplePie("disableSaveWarnings", () ->
From 14b9ed3fb50ffd2d246a6484b1a3fa0099e9c06b Mon Sep 17 00:00:00 2001
From: Ella <72931234+Ankoki@users.noreply.github.com>
Date: Sun, 22 Sep 2024 01:31:16 +0100
Subject: [PATCH 08/26] Multiple Random Numbers Support (#5518)
* Multiple Random Numbers Support
Took 26 minutes
* Change pattern a wee bit.
Took 2 minutes
* Use parse tags instead of parse marks.
Took 3 minutes
* Requested Changes
Took 15 minutes
* Requested Changes
Took 3 minutes
* Apply suggestions from code review
Co-authored-by: Ayham Al Ali <20037329+AyhamAl-Ali@users.noreply.github.com>
* Requested changes, added tests, bug fixes
* Add check for literal 1 in isSingle
* Use Integer instead of Number
* forgot to delete the infinity tests
* Update skript-aliases
---------
Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com>
Co-authored-by: Ayham Al Ali <20037329+AyhamAl-Ali@users.noreply.github.com>
Co-authored-by: Moderocky
---
.../skript/expressions/ExprRandomNumber.java | 92 ++++++++++++-------
.../syntaxes/expressions/ExprRandomNumber.sk | 72 +++++++++++++++
2 files changed, 131 insertions(+), 33 deletions(-)
create mode 100644 src/test/skript/tests/syntaxes/expressions/ExprRandomNumber.sk
diff --git a/src/main/java/ch/njol/skript/expressions/ExprRandomNumber.java b/src/main/java/ch/njol/skript/expressions/ExprRandomNumber.java
index 9cf189d5643..f9ae82447fd 100644
--- a/src/main/java/ch/njol/skript/expressions/ExprRandomNumber.java
+++ b/src/main/java/ch/njol/skript/expressions/ExprRandomNumber.java
@@ -18,9 +18,11 @@
*/
package ch.njol.skript.expressions;
+import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
+import ch.njol.skript.lang.Literal;
import ch.njol.util.Math2;
import org.bukkit.event.Event;
import org.jetbrains.annotations.Nullable;
@@ -36,62 +38,90 @@
import ch.njol.skript.lang.util.SimpleExpression;
import ch.njol.util.Kleenean;
-@Name("Random Number")
+@Name("Random Numbers")
@Description({
- "A random number or integer between two given numbers. Use 'number' if you want any number with decimal parts, or use use 'integer' if you only want whole numbers.",
- "Please note that the order of the numbers doesn't matter, i.e. random number between 2 and 1 will work as well as random number between 1 and 2."
+ "A given amount of random numbers or integers between two given numbers. Use 'number' if you want any number with decimal parts, or use use 'integer' if you only want whole numbers.",
+ "Please note that the order of the numbers doesn't matter, i.e. random number between 2 and 1 will work as well as random number between 1 and 2."
})
@Examples({
- "set the player's health to a random number between 5 and 10",
- "send \"You rolled a %random integer from 1 to 6%!\" to the player"
+ "set the player's health to a random number between 5 and 10",
+ "send \"You rolled a %random integer from 1 to 6%!\" to the player",
+ "set {_chances::*} to 5 random integers between 5 and 96",
+ "set {_decimals::*} to 3 random numbers between 2.7 and -1.5"
})
-@Since("1.4")
+@Since("1.4, INSERT VERSION (Multiple random numbers)")
public class ExprRandomNumber extends SimpleExpression {
static {
Skript.registerExpression(ExprRandomNumber.class, Number.class, ExpressionType.COMBINED,
- "[a] random (:integer|number) (from|between) %number% (to|and) %number%");
+ "[a|%-integer%] random (:integer|number)[s] (from|between) %number% (to|and) %number%");
}
- private Expression from, to;
+ @Nullable
+ private Expression amount;
+ private Expression lower, upper;
private boolean isInteger;
@Override
@SuppressWarnings("unchecked")
- public boolean init(Expression>[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parser) {
- from = (Expression) exprs[0];
- to = (Expression) exprs[1];
- isInteger = parser.hasTag("integer");
+ public boolean init(Expression>[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
+ amount = (Expression) exprs[0];
+ lower = (Expression) exprs[1];
+ upper = (Expression) exprs[2];
+ isInteger = parseResult.hasTag("integer");
return true;
}
@Override
@Nullable
protected Number[] get(Event event) {
- Number from = this.from.getSingle(event);
- Number to = this.to.getSingle(event);
+ Number lowerNumber = lower.getSingle(event);
+ Number upperNumber = upper.getSingle(event);
+ if (upperNumber == null || lowerNumber == null || !Double.isFinite(lowerNumber.doubleValue()) || !Double.isFinite(upperNumber.doubleValue()))
+ return new Number[0];
- if (to == null || from == null || !Double.isFinite(from.doubleValue()) || !Double.isFinite(to.doubleValue()))
+ Integer amount = this.amount == null ? Integer.valueOf(1) : this.amount.getSingle(event);
+ if (amount == null || amount <= 0)
return new Number[0];
+ double lower = Math.min(lowerNumber.doubleValue(), upperNumber.doubleValue());
+ double upper = Math.max(lowerNumber.doubleValue(), upperNumber.doubleValue());
Random random = ThreadLocalRandom.current();
- double min = Math.min(from.doubleValue(), to.doubleValue());
- double max = Math.max(from.doubleValue(), to.doubleValue());
-
if (isInteger) {
- long inf = Math2.ceil(min);
- long sup = Math2.floor(max);
- if (max - min < 1 && inf - sup <= 1) {
- if (sup == inf || min == inf)
- return new Long[] {inf};
- if (max == sup)
- return new Long[] {sup};
+ Long[] longs = new Long[amount];
+ long floored_upper = Math2.floor(upper);
+ long ceiled_lower = Math2.ceil(lower);
+
+ // catch issues like `integer between 0.5 and 0.6`
+ if (upper - lower < 1 && ceiled_lower - floored_upper <= 1) {
+ if (floored_upper == ceiled_lower || lower == ceiled_lower) {
+ Arrays.fill(longs, ceiled_lower);
+ return longs;
+ }
+ if (upper == floored_upper) {
+ Arrays.fill(longs, floored_upper);
+ return longs;
+ }
return new Long[0];
}
- return new Long[] {inf + Math2.mod(random.nextLong(), sup - inf + 1)};
+
+ for (int i = 0; i < amount; i++)
+ longs[i] = Math2.ceil(lower) + Math2.mod(random.nextLong(), floored_upper - ceiled_lower + 1);
+ return longs;
+ // non-integers
+ } else {
+ Double[] doubles = new Double[amount];
+ for (int i = 0; i < amount; i++)
+ doubles[i] = Math.min(lower + random.nextDouble() * (upper - lower), upper);
+ return doubles;
}
+ }
- return new Double[] {min + random.nextDouble() * (max - min)};
+ @Override
+ public boolean isSingle() {
+ if (amount instanceof Literal)
+ return ((Literal) amount).getSingle() == 1;
+ return amount == null;
}
@Override
@@ -101,12 +131,8 @@ public Class extends Number> getReturnType() {
@Override
public String toString(@Nullable Event event, boolean debug) {
- return "a random " + (isInteger ? "integer" : "number") + " between " + from.toString(event, debug) + " and " + to.toString(event, debug);
- }
-
- @Override
- public boolean isSingle() {
- return true;
+ return (amount == null ? "a" : amount.toString(event, debug)) + " random " + (isInteger ? "integer" : "number") +
+ (amount == null ? "" : "s") + " between " + lower.toString(event, debug) + " and " + upper.toString(event, debug);
}
}
diff --git a/src/test/skript/tests/syntaxes/expressions/ExprRandomNumber.sk b/src/test/skript/tests/syntaxes/expressions/ExprRandomNumber.sk
new file mode 100644
index 00000000000..45ad642b288
--- /dev/null
+++ b/src/test/skript/tests/syntaxes/expressions/ExprRandomNumber.sk
@@ -0,0 +1,72 @@
+test "random numbers":
+ loop 1000 times:
+ set {_num} to random number between 1 and 2.5
+ assert {_num} is set with "(1) failed to generate random number: %{_num}%"
+ assert {_num} is between 1 and 2.5 with "(1) random number outside bounds: %{_num}%"
+
+ set {_int} to random integer between 1 and 2.5
+ assert {_int} is set with "(2) failed to generate random int: %{_int}%"
+ assert {_int} is between 1 and 2.5 with "(2) random int outside bounds: %{_int}%"
+ assert {_int} is 1 or 2 with "(2) random int generated an invalid result: %{_int}%"
+
+ # negatives
+ set {_num} to random number between 1 and -2.5
+ assert {_num} is set with "(3) failed to generate random number: %{_num}%"
+ assert {_num} is between 1 and -2.5 with "(3) random number outside bounds: %{_num}%"
+
+ set {_int} to random integer between 1 and -2.5
+ assert {_int} is set with "(4) failed to generate random int: %{_int}%"
+ assert {_int} is between 1 and -2.5 with "(4) random int outside bounds: %{_int}%"
+ assert {_int} is 1 or 0 or -1 or -2 with "(4) random int generated an invalid result: %{_int}%"
+
+ # multiple values
+ set {_nums::*} to 3 random numbers between 1 and -2.5
+ assert {_nums::*} is set with "(5) failed to generate random number: %{_nums::*}%"
+ assert size of {_nums::*} is 3 with "(6) random numbers generated the wrong amount of results: %size of {_nums::*}% != 3"
+ assert {_nums::*} is between 1 and -2.5 with "(5) random number outside bounds: %{_nums::*}%"
+
+ set {_ints::*} to 3 random integers between 1 and -2.5
+ assert {_ints::*} is set with "(6) failed to generate random int: %{_ints::*}%"
+ assert size of {_ints::*} is 3 with "(6) random ints generated the wrong amount of results: %size of {_ints::*}% != 3"
+ assert {_ints::*} are between 1 and -2.5 with "(6) random int outside bounds: %{_ints::*}%"
+ assert {_ints::*} are 1 or 0 or -1 or -2 with "(6) random int generated an invalid result: %{_ints::*}%"
+
+ # null checks
+ set {_num} to random number between {_null} and 1
+ assert {_num} is not set with "(7) random number with null bound returned non-null result: %{_num}%"
+ set {_num} to random number between 0 and {_null}
+ assert {_num} is not set with "(8) random number with null bound returned non-null result: %{_num}%"
+ set {_num::*} to {_null} random numbers between 0 and 10
+ assert {_num::*} is not set with "(9) random number with null amount returned non-null result: %{_num::*}%"
+
+ set {_int} to random integer between {_null} and 1
+ assert {_int} is not set with "(10) random integer with null bound returned non-null result: %{_int}%"
+ set {_int} to random integer between 0 and {_null}
+ assert {_int} is not set with "(11) random integer with null bound returned non-null result: %{_int}%"
+ set {_int::*} to {_null} random integers between 0 and 10
+ assert {_int::*} is not set with "(12) random integer with null bound returned non-null result: %{_int::*}%"
+
+ # edge cases
+ set {_num} to random number between 0 and 0
+ assert {_num} is 0 with "(13) random number between 0 and 0 returned non-zero result: %{_num}%"
+ set {_int} to random integer between 0 and 0
+ assert {_int} is 0 with "(14) random integer between 0 and 0 returned non-zero result: %{_int}%"
+
+ set {_int} to random integer between 0.5 and 0.6
+ assert {_int} is not set with "(15) random integer between 0.5 and 0.6 returned non-null result: %{_int}%"
+
+ set {_int::*} to -10 random integers between 1 and 10
+ assert {_int::*} is not set with "(16) -10 random integers returned non-null result: %{_int::*}%"
+
+ # NaN/infinity
+ set {_int} to random integer between 10 and NaN value
+ assert {_int} is not set with "(17) random integer between 10 and NaN value returned non-null result: %{_int}%"
+
+ set {_int} to random integer between 10 and infinity value
+ assert {_int} is not set with "(18) random integer between 10 and infinity value returned non-null result: %{_int}%"
+
+ set {_int} to random integer between 10 and -infinity value
+ assert {_int} is not set with "(19) random integer between 10 and -infinity value returned non-null result: %{_int}%"
+
+ set {_int::*} to NaN value random integers between 1 and 10
+ assert {_int::*} is not set with "(20) NaN value random integers returned non-null result: %{_int}%"
From 98013299019f9f7a32e3ab615e4a3a62ece4b95c Mon Sep 17 00:00:00 2001
From: TenFont <83959297+TenFont@users.noreply.github.com>
Date: Sun, 22 Sep 2024 05:32:43 +0500
Subject: [PATCH 09/26] Return isNegative() and not false, if CondIsWithin is
invalid (#7038)
* Return isNegated() instead of false if check is invalid
* Add test for <1.17 as well
---------
Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com>
---
src/main/java/ch/njol/skript/conditions/CondIsWithin.java | 4 ++--
src/test/skript/tests/syntaxes/conditions/CondIsWithin.sk | 2 ++
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/main/java/ch/njol/skript/conditions/CondIsWithin.java b/src/main/java/ch/njol/skript/conditions/CondIsWithin.java
index e6b88ed710a..7ec25401ae8 100644
--- a/src/main/java/ch/njol/skript/conditions/CondIsWithin.java
+++ b/src/main/java/ch/njol/skript/conditions/CondIsWithin.java
@@ -103,7 +103,7 @@ public boolean check(Event event) {
Location one = loc1.getSingle(event);
Location two = loc2.getSingle(event);
if (one == null || two == null || one.getWorld() != two.getWorld())
- return false;
+ return isNegated();
AABB box = new AABB(one, two);
return locsToCheck.check(event, box::contains, isNegated());
}
@@ -111,7 +111,7 @@ public boolean check(Event event) {
// else, within an entity/block/chunk/world
Object area = this.area.getSingle(event);
if (area == null)
- return false;
+ return isNegated();
// Entities
if (area instanceof Entity) {
diff --git a/src/test/skript/tests/syntaxes/conditions/CondIsWithin.sk b/src/test/skript/tests/syntaxes/conditions/CondIsWithin.sk
index b432c72f0ff..757bfa49633 100644
--- a/src/test/skript/tests/syntaxes/conditions/CondIsWithin.sk
+++ b/src/test/skript/tests/syntaxes/conditions/CondIsWithin.sk
@@ -4,6 +4,7 @@ test "within condition" when running minecraft "1.17":
set {_loc2} to location(20, 20, 20, "world")
assert location(10, 10, 10, "world") is within {_loc1} and {_loc2} with "failed within two locs"
assert location(10, -10, 10, "world") is not within {_loc1} and {_loc2} with "failed within two locs"
+ assert location(0, 0, 0, "world") is not within {_none} and {_none} with "failed within two locs"
# chunks
set {_chunk1} to chunk at {_loc1}
@@ -37,6 +38,7 @@ test "within condition" when running below minecraft "1.17":
set {_loc2} to location(20, 20, 20, "world")
assert location(10, 10, 10, "world") is within {_loc1} and {_loc2} with "failed within two locs"
assert location(10, -10, 10, "world") is not within {_loc1} and {_loc2} with "failed within two locs"
+ assert location(0, 0, 0, "world") is not within {_none} and {_none} with "failed within two locs"
# chunks
set {_chunk1} to chunk at {_loc1}
From 83808a18671d394075b0fe176545f826840da99e Mon Sep 17 00:00:00 2001
From: NotSoDelayed <72163224+NotSoDelayed@users.noreply.github.com>
Date: Sun, 22 Sep 2024 09:04:58 +0800
Subject: [PATCH 10/26] Add Player Chat Completion Suggestions (#6419)
* Add player chat completion suggestions
* Add method exists check
* Syntax adjustment and remove DataFlowIssue suppression
* Docs improvements
* Requested changes
* Update src/main/java/ch/njol/skript/expressions/ExprPlayerChatCompletions.java
Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com>
* Remove license header (#6684)
* Java 17 ready
---------
Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com>
Co-authored-by: Moderocky
---
.../ExprPlayerChatCompletions.java | 93 +++++++++++++++++++
1 file changed, 93 insertions(+)
create mode 100644 src/main/java/ch/njol/skript/expressions/ExprPlayerChatCompletions.java
diff --git a/src/main/java/ch/njol/skript/expressions/ExprPlayerChatCompletions.java b/src/main/java/ch/njol/skript/expressions/ExprPlayerChatCompletions.java
new file mode 100644
index 00000000000..7bf7d335214
--- /dev/null
+++ b/src/main/java/ch/njol/skript/expressions/ExprPlayerChatCompletions.java
@@ -0,0 +1,93 @@
+package ch.njol.skript.expressions;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.bukkit.entity.Player;
+import org.bukkit.event.Event;
+import org.jetbrains.annotations.Nullable;
+
+import ch.njol.skript.Skript;
+import ch.njol.skript.classes.Changer.ChangeMode;
+import ch.njol.skript.doc.Description;
+import ch.njol.skript.doc.Examples;
+import ch.njol.skript.doc.Name;
+import ch.njol.skript.doc.RequiredPlugins;
+import ch.njol.skript.doc.Since;
+import ch.njol.skript.expressions.base.SimplePropertyExpression;
+import ch.njol.util.coll.CollectionUtils;
+
+@Name("Player Chat Completions")
+@Description({
+ "The custom chat completion suggestions. You can add, set, remove, and clear them. Removing the names of online players with this expression is ineffective.",
+ "This expression will not return anything due to Bukkit limitations."
+})
+@Examples({
+ "add \"Skript\" and \"Njol\" to chat completions of all players",
+ "remove \"text\" from {_p}'s chat completions",
+ "clear player's chat completions"
+})
+@RequiredPlugins("Spigot 1.19+")
+@Since("INSERT VERSION")
+public class ExprPlayerChatCompletions extends SimplePropertyExpression {
+
+ static {
+ if (Skript.methodExists(Player.class, "addCustomChatCompletions", Collection.class))
+ register(ExprPlayerChatCompletions.class, String.class, "[custom] chat completion[s]", "players");
+ }
+
+ @Override
+ public @Nullable String convert(Player player) {
+ return null; // Due to Bukkit limitations
+ }
+
+ @Override
+ public @Nullable Class>[] acceptChange(ChangeMode mode) {
+ return switch (mode) {
+ case ADD, SET, REMOVE, DELETE, RESET -> CollectionUtils.array(String[].class);
+ default -> null;
+ };
+ }
+
+ @Override
+ public void change(Event event, Object @Nullable [] delta, ChangeMode mode) {
+ Player[] players = getExpr().getArray(event);
+ if (players.length == 0)
+ return;
+ List completions = new ArrayList<>();
+ if (delta != null && (mode == ChangeMode.ADD || mode == ChangeMode.REMOVE || mode == ChangeMode.SET)) {
+ completions = Arrays.stream(delta)
+ .filter(String.class::isInstance)
+ .map(String.class::cast)
+ .collect(Collectors.toList());
+ }
+ switch (mode) {
+ case DELETE, RESET, SET -> {
+ for (Player player : players)
+ player.setCustomChatCompletions(completions);
+ }
+ case ADD -> {
+ for (Player player : players)
+ player.addCustomChatCompletions(completions);
+ }
+ case REMOVE -> {
+ for (Player player : players)
+ player.removeCustomChatCompletions(completions);
+ }
+ }
+ }
+
+ @Override
+ public Class extends String> getReturnType() {
+ return String.class;
+ }
+
+ @Override
+ protected String getPropertyName() {
+ return "custom chat completions";
+ }
+
+}
From 6dadbf078d366384eafd1e8099fb060e8ca69a38 Mon Sep 17 00:00:00 2001
From: mugu
Date: Sun, 22 Sep 2024 03:05:16 +0200
Subject: [PATCH 11/26] Update config.sk (#7052)
Co-authored-by: Moderocky
Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com>
---
src/main/resources/config.sk | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/resources/config.sk b/src/main/resources/config.sk
index eb0b295c288..2d7b5ee197f 100644
--- a/src/main/resources/config.sk
+++ b/src/main/resources/config.sk
@@ -31,7 +31,7 @@
# ==== General Options ====
language: english
-# Which language to use. Currently English, German, Korean, French, Polish, Russian, Japanese, Simplified Chinese and Turkish
+# Which language to use. Currently English, German, Korean, French, Polish, Russian, Japanese, Simplified Chinese, Turkish and Dutch
# are included in the download, but custom languages can be created as well. Use the name in lowercase and no spaces as the value.
# Please note that not everything can be translated yet, i.e. parts of Skript will still be english if you use another language.
# If you want to translate Skript to your language please read the readme.txt located in the /lang/ folder in the jar
From 0a8bac337676ff9e63da685da8ca98a2f597c953 Mon Sep 17 00:00:00 2001
From: Efy <35348263+Efnilite@users.noreply.github.com>
Date: Sun, 22 Sep 2024 03:22:02 +0200
Subject: [PATCH 12/26] Fix ExprHoverList's remove (#7056)
* init commit
* remove pattern matching >:(
---------
Co-authored-by: Moderocky
Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com>
---
.../ch/njol/skript/expressions/ExprHoverList.java | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/src/main/java/ch/njol/skript/expressions/ExprHoverList.java b/src/main/java/ch/njol/skript/expressions/ExprHoverList.java
index a3b58b6b9d3..835319f3449 100644
--- a/src/main/java/ch/njol/skript/expressions/ExprHoverList.java
+++ b/src/main/java/ch/njol/skript/expressions/ExprHoverList.java
@@ -104,7 +104,7 @@ public void change(Event event, @Nullable Object[] delta, ChangeMode mode) {
if (HAS_NEW_LISTED_PLAYER_INFO) {
List values = new ArrayList<>();
- if (mode != ChangeMode.DELETE && mode != ChangeMode.RESET) {
+ if (mode != ChangeMode.DELETE && mode != ChangeMode.RESET && mode != ChangeMode.REMOVE) {
for (Object object : delta) {
if (object instanceof Player) {
Player player = (Player) object;
@@ -124,7 +124,9 @@ public void change(Event event, @Nullable Object[] delta, ChangeMode mode) {
sample.addAll(values);
break;
case REMOVE:
- sample.removeAll(values);
+ for (Object value : delta) {
+ sample.removeIf(profile -> profile.name().equals(value));
+ }
break;
case DELETE:
case RESET:
@@ -135,7 +137,7 @@ public void change(Event event, @Nullable Object[] delta, ChangeMode mode) {
}
List values = new ArrayList<>();
- if (mode != ChangeMode.DELETE && mode != ChangeMode.RESET) {
+ if (mode != ChangeMode.DELETE && mode != ChangeMode.RESET && mode != ChangeMode.REMOVE) {
for (Object object : delta) {
if (object instanceof Player) {
Player player = (Player) object;
@@ -150,13 +152,14 @@ public void change(Event event, @Nullable Object[] delta, ChangeMode mode) {
switch (mode) {
case SET:
sample.clear();
- sample.addAll(values);
- break;
+ // $FALL-THROUGH$
case ADD:
sample.addAll(values);
break;
case REMOVE:
- sample.removeAll(values);
+ for (Object value : delta) {
+ sample.removeIf(profile -> profile.getName() != null && profile.getName().equals(value));
+ }
break;
case DELETE:
case RESET:
From c4c55601a73e4fcc016d4f5f9e1bc0075912680d Mon Sep 17 00:00:00 2001
From: Asleepp <119438940+Asleeepp@users.noreply.github.com>
Date: Sat, 21 Sep 2024 22:23:24 -0300
Subject: [PATCH 13/26] Entity Potion Effect Event (#6532)
* Entity Potion Effect Event and event-values
* Updated syntax for EvtEntityPotion, and readded the imports to EventValues.
* Forgot to change e to event.
* Added suggested changes :)
* silly me
* even sillier me (how did I manage to do that)
* even sillier me (how did I manage to do that)
* I don't get why the build is failing
* BRO
* Added type stuff, and made check a lot better
* Changes
* change
* done
* resolve conflict
* Update src/main/java/ch/njol/skript/classes/data/BukkitClasses.java
Co-authored-by: _tud <98935832+UnderscoreTud@users.noreply.github.com>
---------
Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com>
Co-authored-by: _tud <98935832+UnderscoreTud@users.noreply.github.com>
---
.../skript/classes/data/BukkitClasses.java | 6 ++
.../classes/data/BukkitEventValues.java | 29 ++++++++
.../njol/skript/events/EvtEntityPotion.java | 74 +++++++++++++++++++
src/main/resources/lang/default.lang | 26 +++++++
4 files changed, 135 insertions(+)
create mode 100644 src/main/java/ch/njol/skript/events/EvtEntityPotion.java
diff --git a/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java b/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java
index ba0a66a1f41..94b5fe789c4 100644
--- a/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java
+++ b/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java
@@ -61,6 +61,7 @@
import org.bukkit.entity.Projectile;
import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
+import org.bukkit.event.entity.EntityPotionEffectEvent;
import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason;
import org.bukkit.event.entity.EntityTransformEvent.TransformReason;
import org.bukkit.event.inventory.ClickType;
@@ -1526,6 +1527,11 @@ public String toVariableNameString(EnchantmentOffer eo) {
.name("Transform Reason")
.description("Represents a transform reason of an entity transform event.")
.since("2.8.0"));
+ Classes.registerClass(new EnumClassInfo<>(EntityPotionEffectEvent.Cause.class, "entitypotioncause", "entity potion causes")
+ .user("(entity )?potion ?effect ?cause")
+ .name("Entity Potion Cause")
+ .description("Represents the cause of the action of a potion effect on an entity, e.g. arrow, command")
+ .since("INSERT VERSION"));
}
}
diff --git a/src/main/java/ch/njol/skript/classes/data/BukkitEventValues.java b/src/main/java/ch/njol/skript/classes/data/BukkitEventValues.java
index 82fca450068..c53810d5d69 100644
--- a/src/main/java/ch/njol/skript/classes/data/BukkitEventValues.java
+++ b/src/main/java/ch/njol/skript/classes/data/BukkitEventValues.java
@@ -109,6 +109,7 @@
import org.bukkit.event.entity.EntityTeleportEvent;
import org.bukkit.event.entity.EntityTransformEvent;
import org.bukkit.event.entity.EntityTransformEvent.TransformReason;
+import org.bukkit.event.entity.EntityPotionEffectEvent;
import org.bukkit.event.entity.FireworkExplodeEvent;
import org.bukkit.event.entity.HorseJumpEvent;
import org.bukkit.event.entity.ItemDespawnEvent;
@@ -178,6 +179,7 @@
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.inventory.Recipe;
+import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionData;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.potion.PotionType;
@@ -548,6 +550,33 @@ public DamageCause get(final EntityDeathEvent e) {
return ldc == null ? null : ldc.getCause();
}
}, 0);
+
+ // Entity Potion Effect
+ EventValues.registerEventValue(EntityPotionEffectEvent.class, PotionEffect.class, new Getter() {
+ @Override
+ public PotionEffect get(EntityPotionEffectEvent event) {
+ return event.getOldEffect();
+ }
+ }, EventValues.TIME_PAST);
+ EventValues.registerEventValue(EntityPotionEffectEvent.class, PotionEffect.class, new Getter() {
+ @Override
+ public PotionEffect get(EntityPotionEffectEvent event) {
+ return event.getNewEffect();
+ }
+ }, EventValues.TIME_NOW);
+ EventValues.registerEventValue(EntityPotionEffectEvent.class, PotionEffectType.class, new Getter() {
+ @Override
+ public PotionEffectType get(EntityPotionEffectEvent event) {
+ return event.getModifiedType();
+ }
+ }, EventValues.TIME_NOW);
+ EventValues.registerEventValue(EntityPotionEffectEvent.class, EntityPotionEffectEvent.Cause.class, new Getter() {
+ @Override
+ public EntityPotionEffectEvent.Cause get(EntityPotionEffectEvent event) {
+ return event.getCause();
+ }
+ }, EventValues.TIME_NOW);
+
// ProjectileHitEvent
// ProjectileHitEvent#getHitBlock was added in 1.11
if (Skript.methodExists(ProjectileHitEvent.class, "getHitBlock"))
diff --git a/src/main/java/ch/njol/skript/events/EvtEntityPotion.java b/src/main/java/ch/njol/skript/events/EvtEntityPotion.java
new file mode 100644
index 00000000000..ab56287ef2b
--- /dev/null
+++ b/src/main/java/ch/njol/skript/events/EvtEntityPotion.java
@@ -0,0 +1,74 @@
+/**
+ * This file is part of Skript.
+ *
+ * Skript is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Skript is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Skript. If not, see .
+ *
+ * Copyright Peter Güttinger, SkriptLang team and contributors
+ */
+package ch.njol.skript.events;
+
+import ch.njol.skript.Skript;
+import ch.njol.skript.lang.Expression;
+import ch.njol.skript.lang.Literal;
+import ch.njol.skript.lang.SkriptEvent;
+import ch.njol.skript.lang.SkriptParser.ParseResult;
+import org.bukkit.event.Event;
+import org.bukkit.event.entity.EntityPotionEffectEvent;
+import org.bukkit.potion.PotionEffectType;
+
+import javax.annotation.Nullable;
+
+public class EvtEntityPotion extends SkriptEvent {
+
+ static {
+ Skript.registerEvent("Entity Potion Effect", EvtEntityPotion.class, EntityPotionEffectEvent.class,
+ "entity potion effect [modif[y|ication]] [[of] %-potioneffecttypes%] [due to %-entitypotioncause%]")
+ .description("Called when an entity's potion effect is modified.", "This modification can include adding, removing or changing their potion effect.")
+ .examples(
+ "on entity potion effect modification:",
+ "\t\tbroadcast \"A potion effect was added to %event-entity%!\" ",
+ "",
+ "on entity potion effect modification of night vision:")
+ .since("INSERT VERSION");
+ }
+
+ @SuppressWarnings("unchecked")
+ private Expression potionEffects;
+ private Expression cause;
+
+ @Override
+ public boolean init(Literal>[] args, int matchedPattern, ParseResult parseResult) {
+ potionEffects = (Expression) args[0];
+ cause = (Expression) args[1];
+ return true;
+ }
+
+ @Override
+ public boolean check(Event event) {
+ EntityPotionEffectEvent potionEvent = (EntityPotionEffectEvent) event;
+ boolean effectMatches = potionEffects == null ||
+ (potionEvent.getOldEffect() != null && potionEffects.check(event, effectType -> effectType.equals(potionEvent.getOldEffect().getType()))) ||
+ (potionEvent.getNewEffect() != null && potionEffects.check(event, effectType -> effectType.equals(potionEvent.getNewEffect().getType())));
+
+ boolean causeMatches = cause == null || cause.check(event, cause -> cause.equals(potionEvent.getCause()));
+
+ return effectMatches && causeMatches;
+ }
+
+
+ @Override
+ public String toString(@Nullable Event event, boolean debug) {
+ return "on entity potion effect modification";
+ }
+}
diff --git a/src/main/resources/lang/default.lang b/src/main/resources/lang/default.lang
index fec454c2ac5..8b249d6c6b4 100644
--- a/src/main/resources/lang/default.lang
+++ b/src/main/resources/lang/default.lang
@@ -2244,6 +2244,32 @@ environments:
the_end: end, the end
custom: custom
+
+entity potion causes:
+ area_effect_cloud: enter area effect cloud
+ arrow: arrow infliction
+ attack: attack
+ beacon: beacon effect
+ command: command
+ conduit: conduit effect
+ conversion: conversion, converted
+ death: death
+ dolphin: dolphin boost
+ expiration: expiration, expired
+ food: food
+ illusion: illusion
+ milk: drinking milk
+ plugin: plugin
+ potion_drink: potion drunk, drinking potion
+ potion_splash: potion splash, splash potion
+ spider_spawn: spider spawn, spawned spider
+ totem: removal by resurrection
+ turtle_helmet: turtle helmet effect
+ unknown: unknown
+ villager_trade: villager trade
+ patrol_captain: pillager captain, patrol captain
+ wither_rose: wither rose infliction
+
# -- Moon Phases --
moon phases:
first_quarter: first quarter
From 19985d98d1974a2c6de2b4e9476691b0129881e3 Mon Sep 17 00:00:00 2001
From: Efy <35348263+Efnilite@users.noreply.github.com>
Date: Sun, 22 Sep 2024 04:49:17 +0200
Subject: [PATCH 14/26] Update ExprTime (#7082)
* init commit
* update imports
* magic number
* space
* fixes
* up
* imports
* fix for registerDefault
* fix breaking changes
---------
Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com>
---
.../ch/njol/skript/expressions/ExprTime.java | 153 +++++++++---------
.../tests/regressions/7081-time of worlds.sk | 29 ++++
2 files changed, 102 insertions(+), 80 deletions(-)
create mode 100644 src/test/skript/tests/regressions/7081-time of worlds.sk
diff --git a/src/main/java/ch/njol/skript/expressions/ExprTime.java b/src/main/java/ch/njol/skript/expressions/ExprTime.java
index 4e769f6656d..e2199e18a80 100644
--- a/src/main/java/ch/njol/skript/expressions/ExprTime.java
+++ b/src/main/java/ch/njol/skript/expressions/ExprTime.java
@@ -1,27 +1,5 @@
-/**
- * This file is part of Skript.
- *
- * Skript is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Skript is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Skript. If not, see .
- *
- * Copyright Peter Güttinger, SkriptLang team and contributors
- */
package ch.njol.skript.expressions;
-import org.bukkit.World;
-import org.bukkit.event.Event;
-import org.jetbrains.annotations.Nullable;
-
import ch.njol.skript.Skript;
import ch.njol.skript.classes.Changer.ChangeMode;
import ch.njol.skript.doc.Description;
@@ -32,42 +10,51 @@
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.ExpressionType;
import ch.njol.skript.lang.SkriptParser.ParseResult;
-import ch.njol.skript.registrations.Classes;
-import ch.njol.skript.util.Getter;
import ch.njol.skript.util.Time;
import ch.njol.skript.util.Timeperiod;
import ch.njol.skript.util.Timespan;
import ch.njol.util.Kleenean;
import ch.njol.util.coll.CollectionUtils;
+import org.bukkit.World;
+import org.bukkit.event.Event;
+import org.jetbrains.annotations.Nullable;
-/**
- * @author Peter Güttinger
- */
@Name("Time")
-@Description("The time of a world.")
-@Examples({"time in world is between 18:00 and 6:00:",
- " broadcast \"It's night-time, watch out for monsters!\""})
+@Description({
+ "The time of a world.",
+ "Use the \"minecraft timespan\" syntax to change the time according " +
+ "to Minecraft's time intervals.",
+ "Since Minecraft uses discrete intervals for time (ticks), " +
+ "changing the time by real-world minutes or real-world seconds only changes it approximately.",
+ "Removing an amount of time from a world's time will move the clock forward a day."
+})
+@Examples({
+ "set time of world \"world\" to 2:00",
+ "add 2 minecraft hours to time of world \"world\"",
+ "add 54 real seconds to time of world \"world\" # approximately 1 minecraft hour"
+})
@Since("1.0")
public class ExprTime extends PropertyExpression {
+
+ // 18000 is the offset to allow for using "add 2:00" without going to a new day
+ // and causing unexpected behaviour
+ private static final int TIME_TO_TIMESPAN_OFFSET = 18000;
+
static {
- Skript.registerExpression(ExprTime.class, Time.class, ExpressionType.PROPERTY, "[the] time[s] [([with]in|of) %worlds%]", "%worlds%'[s] time[s]");
+ Skript.registerExpression(ExprTime.class, Time.class, ExpressionType.PROPERTY,
+ "[the] time[s] [([with]in|of) %worlds%]", "%worlds%'[s] time[s]");
}
-
- @SuppressWarnings({"unchecked", "null"})
+
+ @SuppressWarnings("unchecked")
@Override
- public boolean init(final Expression>[] exprs, final int matchedPattern, final Kleenean isDelayed, final ParseResult parser) {
- setExpr((Expression) exprs[0]);
+ public boolean init(Expression>[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parser) {
+ setExpr((Expression) expressions[0]);
return true;
}
-
+
@Override
- protected Time[] get(final Event e, final World[] source) {
- return get(source, new Getter