Skip to content

Commit aea3176

Browse files
Merge branch 'dev/patch' into dev/feature
2 parents 9af7c9e + 0fc4c8c commit aea3176

39 files changed

+993
-454
lines changed

.github/workflows/checkstyle.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
with:
1717
submodules: recursive
1818
- name: validate gradle wrapper
19-
uses: gradle/wrapper-validation-action@v2
19+
uses: gradle/actions/wrapper-validation@v4
2020
- name: Set up JDK 21
2121
uses: actions/setup-java@v4
2222
with:

.github/workflows/java-17-builds.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
with:
1717
submodules: recursive
1818
- name: validate gradle wrapper
19-
uses: gradle/wrapper-validation-action@v2
19+
uses: gradle/actions/wrapper-validation@v4
2020
- name: Set up JDK 21
2121
uses: actions/setup-java@v4
2222
with:

.github/workflows/java-21-builds.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
with:
1717
submodules: recursive
1818
- name: validate gradle wrapper
19-
uses: gradle/wrapper-validation-action@v2
19+
uses: gradle/actions/wrapper-validation@v4
2020
- name: Set up JDK 21
2121
uses: actions/setup-java@v4
2222
with:

.github/workflows/junit-17-builds.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
with:
1717
submodules: recursive
1818
- name: validate gradle wrapper
19-
uses: gradle/wrapper-validation-action@v2
19+
uses: gradle/actions/wrapper-validation@v4
2020
- name: Set up JDK 21
2121
uses: actions/setup-java@v4
2222
with:

.github/workflows/junit-21-builds.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
with:
1717
submodules: recursive
1818
- name: validate gradle wrapper
19-
uses: gradle/wrapper-validation-action@v2
19+
uses: gradle/actions/wrapper-validation@v4
2020
- name: Set up JDK 21
2121
uses: actions/setup-java@v4
2222
with:

.github/workflows/repo.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
with:
1313
submodules: recursive
1414
- name: validate gradle wrapper
15-
uses: gradle/wrapper-validation-action@v2
15+
uses: gradle/actions/wrapper-validation@v4
1616
- name: Set up JDK 21
1717
uses: actions/setup-java@v4
1818
with:

CLOCKWORK_RELEASE_MODEL.md

+26-14
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ This document does *not* cover the distribution or publication of artifacts buil
3434

3535
Plans for a new release model began in March 2023 and several models were discussed, with this being the final version agreed upon by the organisation's administrative group and approved by the core contributors.
3636

37+
An update to the release model was made in February 2025 to accommodate a more frequent Minecraft release schedule and to help limit update sizes further.
38+
3739
### Motivations
3840

3941
The release cycle for the `2.7.0` version was significant in that it took an unusually long time and included an unusually-large number of additions and changes.
@@ -59,6 +61,11 @@ Members of the organisation and the wider community identified several problems
5961

6062
Of these, the principle complaint is that the `2.7.0` version took a significant amount of time to finish and this had an adverse effect on the community and the wider ecosystem.
6163

64+
As of February 2025, Mojang has committed to 'drops', which means significant upstream changes happen much more frequently.
65+
This corresponds to Skript having a much higher lag time on releasing support for new content due to the mismatch in release dates.
66+
In addition, an uptick in contributions has led to `2.10` being one of the largest updates yet.
67+
The size of the update meant that some of the previous concerns, like short notice additions and an extensive changelog, were still persistent despite the new release schedule.
68+
6269
### Goals
6370

6471
Our release model has been designed to achieve the following goals:
@@ -98,6 +105,7 @@ A 'patch' version (labelled `0.0.X`) may contain:
98105
- Bug fixes
99106
- Non-impactful<sup>2</sup> improvements to existing features
100107
- Changes to meta content (e.g. documentation)
108+
- Opt-in experiments
101109

102110
There may be **very rare** occasions when a breaking change is necessary in a patch release. These may occur if and only if: either a breaking change is required in order to fix an issue, and the issue is significant enough to need fixing in a patch rather than waiting for a major release, or an issue occurred with an inclusion in the version immediately-prior to this, which must be changed or reverted in some way.
103111

@@ -138,18 +146,20 @@ A table of (expected) dates is displayed below.
138146
| 15th Jan | Feature release | 0.1.0 |
139147
| 1st Feb | Patch | 0.1.1 |
140148
| 1st Mar | Patch | 0.1.2 |
141-
| 1st Apr | Patch | 0.1.3 |
142-
| 1st May | Patch | 0.1.4 |
143-
| 1st Jun | Patch | 0.1.5 |
144-
| 1st Jul | Pre-release | 0.2.0-pre1 |
145-
| 15th Jul | Feature release | 0.2.0 |
146-
| 1st Aug | Patch | 0.2.1 |
147-
| 1st Sep | Patch | 0.2.2 |
148-
| 1st Oct | Patch | 0.2.3 |
149-
| 1st Nov | Patch | 0.2.4 |
150-
| 1st Dec | Patch | 0.2.5 |
151-
152-
An estimated 14 releases are expected per year, with 10 patches, 2 pre-releases and 2 feature-releases that immediately follow them.
149+
| 1st Apr | Pre-release | 0.2.0-pre1 |
150+
| 15th Apr | Feature release | 0.2.0 |
151+
| 1st May | Patch | 0.2.1 |
152+
| 1st Jun | Patch | 0.2.2 |
153+
| 1st Jul | Pre-release | 0.3.0-pre1 |
154+
| 15th Jul | Feature release | 0.3.0 |
155+
| 1st Aug | Patch | 0.3.1 |
156+
| 1st Sep | Patch | 0.3.2 |
157+
| 1st Oct | Pre-release | 0.4.0-pre1 |
158+
| 15th Oct | Feature release | 0.4.0 |
159+
| 1st Nov | Patch | 0.4.1 |
160+
| 1st Dec | Patch | 0.4.2 |
161+
162+
An estimated 16 releases are expected per year, with 8 patches, 4 pre-releases and 4 feature-releases.
153163

154164
Please note that the actual number may differ from this in cases such as:
155165
- A version requiring multiple pre-releases to correct mistakes (`0.3.0-pre1`, `0.3.0-pre2`)
@@ -160,15 +170,17 @@ There is no fixed timetable for the circulation of unpublished builds to the pub
160170

161171
### Major Version Schedule
162172

163-
A [feature version](#feature-releases) will be released on the **15th of January** and the **15th of July**.
173+
A [feature version](#feature-releases) will be released on the **15th of January**, the **15th of April**, the **15th of July**, and the **15th of October**.
164174

165-
This will include all finished content from the previous 6 months that was tested in the pre-release.
175+
This will include all finished content that was tested in the pre-release.
166176

167177
Any features, additions or changes that were *not* ready or approved at the time of the pre-release may **not** be included in the feature release [according to goal 3](#goals). \
168178
The feature release must **not** be delayed to accomodate content that was not ready by the deadline [according to goal 5](#goals).
169179

170180
If there is no content ready at the scheduled date of a feature release, the release will be skipped and a notice published explaining this.
171181

182+
The April and October releases are intended to include minimal breaking changes and focus more on including new features and opt-in experiments.
183+
172184
### Pre-Release Schedule
173185

174186
A [pre-release](#pre-releases) will be released on the **1st of January** and the **1st of July**, leaving two weeks before the following release for public testing to occur.

build.gradle

+4-4
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,14 @@ allprojects {
2727

2828
dependencies {
2929
shadow group: 'io.papermc', name: 'paperlib', version: '1.0.8'
30-
shadow group: 'org.bstats', name: 'bstats-bukkit', version: '3.0.2'
31-
shadow group: 'net.kyori', name: 'adventure-text-serializer-bungeecord', version: '4.3.2'
30+
shadow group: 'org.bstats', name: 'bstats-bukkit', version: '3.1.0'
31+
shadow group: 'net.kyori', name: 'adventure-text-serializer-bungeecord', version: '4.3.4'
3232

3333
implementation group: 'io.papermc.paper', name: 'paper-api', version: '1.21.4-R0.1-SNAPSHOT'
3434
implementation group: 'com.google.code.findbugs', name: 'findbugs', version: '3.0.1'
3535

3636
// bundled with Minecraft 1.19.4+ for display entity transforms
37-
implementation group: 'org.joml', name: 'joml', version: '1.10.5'
37+
implementation group: 'org.joml', name: 'joml', version: '1.10.8'
3838

3939
// Plugin hook libraries
4040
implementation group: 'com.sk89q.worldguard', name: 'worldguard-legacy', version: '7.0.0-SNAPSHOT', {
@@ -48,7 +48,7 @@ dependencies {
4848
implementation fileTree(dir: 'lib', include: '*.jar')
4949

5050
testShadow group: 'junit', name: 'junit', version: '4.13.2'
51-
testShadow group: 'org.easymock', name: 'easymock', version: '5.4.0'
51+
testShadow group: 'org.easymock', name: 'easymock', version: '5.5.0'
5252
}
5353

5454
checkstyle {

gradle.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ org.gradle.parallel=true
55

66
groupid=ch.njol
77
name=skript
8-
version=2.10.1
8+
version=2.10.2
99
jarName=Skript.jar
1010
testEnv=java21/paper-1.21.4
1111
testEnvJavaVersion=21

skript-aliases

src/main/java/ch/njol/skript/Skript.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@
4444
import ch.njol.util.StringUtils;
4545
import ch.njol.util.coll.iterator.CheckedIterator;
4646
import ch.njol.util.coll.iterator.EnumerationIterable;
47-
import com.google.common.collect.Lists;
4847
import com.google.gson.Gson;
4948
import com.google.gson.GsonBuilder;
49+
import io.papermc.lib.PaperLib;
5050
import org.bstats.bukkit.Metrics;
5151
import org.bukkit.*;
5252
import org.bukkit.command.CommandSender;
@@ -683,7 +683,7 @@ protected void afterErrors() {
683683
if (TestMode.DEV_MODE) {
684684
runTests(); // Dev mode doesn't need a delay
685685
} else {
686-
Bukkit.getWorlds().get(0).getChunkAtAsync(100, 100).thenRun(() -> runTests());
686+
PaperLib.getChunkAtAsync(Bukkit.getWorlds().get(0), 100, 100).thenRun(() -> runTests());
687687
}
688688
}
689689

src/main/java/ch/njol/skript/SkriptCommand.java

+10-8
Original file line numberDiff line numberDiff line change
@@ -382,19 +382,21 @@ public boolean onCommand(CommandSender sender, Command command, String label, St
382382

383383
} else if (args[0].equalsIgnoreCase("gen-docs")) {
384384
File templateDir = Documentation.getDocsTemplateDirectory();
385+
File outputDir = Documentation.getDocsOutputDirectory();
386+
outputDir.mkdirs();
387+
388+
Skript.info(sender, "Generating docs...");
389+
JSONGenerator jsonGenerator = new JSONGenerator(templateDir, outputDir);
390+
jsonGenerator.generate();
391+
385392
if (!templateDir.exists()) {
386-
Skript.error(sender, "Cannot generate docs! Documentation templates not found at '" + Documentation.getDocsTemplateDirectory().getPath() + "'");
387-
TestMode.docsFailed = true;
393+
Skript.info(sender, "JSON-only documentation generated!");
388394
return true;
389395
}
390-
File outputDir = Documentation.getDocsOutputDirectory();
391-
outputDir.mkdirs();
396+
392397
HTMLGenerator htmlGenerator = new HTMLGenerator(templateDir, outputDir);
393-
JSONGenerator jsonGenerator = new JSONGenerator(templateDir, outputDir);
394-
Skript.info(sender, "Generating docs...");
395398
htmlGenerator.generate(); // Try to generate docs... hopefully
396-
jsonGenerator.generate();
397-
Skript.info(sender, "Documentation generated!");
399+
Skript.info(sender, "All documentation generated!");
398400
} else if (args[0].equalsIgnoreCase("test") && TestMode.DEV_MODE) {
399401
File scriptFile;
400402
if (args.length == 1) {

src/main/java/ch/njol/skript/classes/data/BukkitClasses.java

+10-1
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
import ch.njol.skript.aliases.ItemType;
77
import ch.njol.skript.bukkitutil.BukkitUtils;
88
import ch.njol.skript.bukkitutil.EntityUtils;
9-
import ch.njol.skript.bukkitutil.SkriptTeleportFlag;
109
import ch.njol.skript.bukkitutil.ItemUtils;
10+
import ch.njol.skript.bukkitutil.SkriptTeleportFlag;
1111
import ch.njol.skript.classes.*;
1212
import ch.njol.skript.classes.registry.RegistryClassInfo;
1313
import ch.njol.skript.entity.EntityData;
@@ -1516,6 +1516,15 @@ public String toVariableNameString(EntitySnapshot snapshot) {
15161516
.description("Teleport Flags are settings to retain during a teleport.")
15171517
.requiredPlugins("Paper 1.19+")
15181518
.since("2.10"));
1519+
1520+
Classes.registerClass(new ClassInfo<>(Vehicle.class, "vehicle")
1521+
.user("vehicles?")
1522+
.name("Vehicle")
1523+
.description("Represents a vehicle.")
1524+
.since("2.10.2")
1525+
.changer(DefaultChangers.entityChanger)
1526+
);
1527+
15191528
}
15201529

15211530
}

src/main/java/ch/njol/skript/classes/data/DefaultOperations.java

+12-9
Original file line numberDiff line numberDiff line change
@@ -99,21 +99,24 @@ public class DefaultOperations {
9999
// Timespan - Number
100100
// Number - Timespan
101101
Arithmetics.registerOperation(Operator.MULTIPLICATION, Timespan.class, Number.class, (left, right) -> {
102-
long scalar = right.longValue();
103-
if (scalar < 0)
102+
double scalar = right.doubleValue();
103+
if (scalar < 0 || !Double.isFinite(scalar))
104104
return null;
105-
return new Timespan(Math2.multiplyClamped(left.getAs(TimePeriod.MILLISECOND), scalar));
105+
double value = left.getAs(TimePeriod.MILLISECOND) * scalar;
106+
return new Timespan((long) Math.min(value, Long.MAX_VALUE));
106107
}, (left, right) -> {
107-
long scalar = left.longValue();
108-
if (scalar < 0)
108+
double scalar = left.doubleValue();
109+
if (scalar < 0 || !Double.isFinite(scalar))
109110
return null;
110-
return new Timespan(scalar * right.getAs(TimePeriod.MILLISECOND));
111+
double value = right.getAs(TimePeriod.MILLISECOND) * scalar;
112+
return new Timespan((long) Math.min(value, Long.MAX_VALUE));
111113
});
112114
Arithmetics.registerOperation(Operator.DIVISION, Timespan.class, Number.class, (left, right) -> {
113-
long scalar = right.longValue();
114-
if (scalar <= 0)
115+
double scalar = right.doubleValue();
116+
if (scalar <= 0 || !Double.isFinite(scalar))
115117
return null;
116-
return new Timespan(left.getAs(TimePeriod.MILLISECOND) / scalar);
118+
double value = left.getAs(TimePeriod.MILLISECOND) / scalar;
119+
return new Timespan((long) Math.min(value, Long.MAX_VALUE));
117120
});
118121

119122
// Timespan / Timespan = Number

src/main/java/ch/njol/skript/doc/Documentation.java

+15-2
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,10 @@ protected static String cleanPatterns(final String patterns) {
179179
}
180180

181181
protected static String cleanPatterns(String patterns, boolean escapeHTML) {
182+
return cleanPatterns(patterns, escapeHTML, true);
183+
}
182184

185+
protected static String cleanPatterns(String patterns, boolean escapeHTML, boolean useLinks) {
183186
String cleanedPatterns = escapeHTML ? escapeHTML(patterns) : patterns;
184187

185188
cleanedPatterns = CP_PARSE_MARKS_PATTERN.matcher(cleanedPatterns).replaceAll(""); // Remove marks
@@ -268,8 +271,13 @@ protected static String cleanPatterns(String patterns, boolean escapeHTML) {
268271
first = false;
269272
final NonNullPair<String, Boolean> p = Utils.getEnglishPlural(c);
270273
final ClassInfo<?> ci = Classes.getClassInfoNoError(p.getFirst());
274+
271275
if (ci != null && ci.hasDocs()) { // equals method throws null error when doc name is null
272-
b.append("<a href='./classes.html#").append(p.getFirst()).append("'>").append(ci.getName().toString(p.getSecond())).append("</a>");
276+
if (useLinks) {
277+
b.append("<a href='./classes.html#").append(p.getFirst()).append("'>").append(ci.getName().toString(p.getSecond())).append("</a>");
278+
} else {
279+
b.append(ci.getName().toString(p.getSecond()));
280+
}
273281
} else {
274282
b.append(c);
275283
if (ci != null && ci.hasDocs())
@@ -286,7 +294,12 @@ private static void insertSyntaxElement(final PrintWriter pw, final SyntaxElemen
286294
Class<?> elementClass = info.getElementClass();
287295
if (elementClass.getAnnotation(NoDoc.class) != null)
288296
return;
289-
if (elementClass.getAnnotation(Name.class) == null || elementClass.getAnnotation(Description.class) == null || elementClass.getAnnotation(Examples.class) == null || elementClass.getAnnotation(Since.class) == null) {
297+
if (elementClass.getAnnotation(Name.class) == null
298+
|| elementClass.getAnnotation(Description.class) == null
299+
|| (!elementClass.isAnnotationPresent(Examples.class)
300+
&& !elementClass.isAnnotationPresent(Example.class)
301+
&& !elementClass.isAnnotationPresent(Example.Examples.class))
302+
|| elementClass.getAnnotation(Since.class) == null) {
290303
Skript.warning("" + elementClass.getSimpleName() + " is missing information");
291304
return;
292305
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package ch.njol.skript.doc;
2+
3+
import java.lang.annotation.*;
4+
5+
/**
6+
* An example to be used in documentation for the annotated element.
7+
* Multiple example annotations can be stacked on a single syntax element.
8+
* <p>
9+
* Each annotation should include a single example.
10+
* This can be used instead of the existing {@link ch.njol.skript.doc.Examples} annotation.
11+
* <p>
12+
* <b>Multi-line examples</b> should use multi-line strings.
13+
* Note that whitespace and quotes do not need to be escaped in this mode.
14+
* The indentation will start from the least-indented line (and most IDEs provide a guideline to show this).
15+
* <pre>{@code
16+
* @Example("set player's health to 1")
17+
* @Example("""
18+
* if player's health is greater than 10:
19+
* send "Wow you're really healthy!"
20+
* """)
21+
* @Example("""
22+
* # sets the player's health to 1
23+
* set player's health to 1""")
24+
* public class MyExpression extends ... {
25+
* }
26+
* }</pre>
27+
*/
28+
@Target(ElementType.TYPE)
29+
@Retention(RetentionPolicy.RUNTIME)
30+
@Repeatable(Example.Examples.class)
31+
@Documented
32+
public @interface Example {
33+
34+
String value();
35+
36+
boolean inTrigger() default true; // todo needed?
37+
38+
/**
39+
* The internal container annotation for multiple examples.
40+
*/
41+
@Target(ElementType.TYPE)
42+
@Retention(RetentionPolicy.RUNTIME)
43+
@Documented
44+
@interface Examples {
45+
46+
Example[] value();
47+
48+
}
49+
50+
}

0 commit comments

Comments
 (0)