diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 00000000000..560dcad5af7 --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,4 @@ +# .git-blame-ignore-revs + +# cleanup lang package - mostly renaming variables +98abf5d7773df11c65d66e4e9485d0f1e3ef8821 diff --git a/.github/workflows/java-17-builds.yml b/.github/workflows/java-17-builds.yml index 248d72002a6..a0c87141c13 100644 --- a/.github/workflows/java-17-builds.yml +++ b/.github/workflows/java-17-builds.yml @@ -16,7 +16,7 @@ jobs: with: submodules: recursive - name: validate gradle wrapper - uses: gradle/wrapper-validation-action@v1 + uses: gradle/wrapper-validation-action@v2 - name: Set up JDK 17 uses: actions/setup-java@v3 with: diff --git a/.github/workflows/java-8-builds.yml b/.github/workflows/java-8-builds.yml index adae34978ec..090e6b3db6a 100644 --- a/.github/workflows/java-8-builds.yml +++ b/.github/workflows/java-8-builds.yml @@ -16,7 +16,7 @@ jobs: with: submodules: recursive - name: validate gradle wrapper - uses: gradle/wrapper-validation-action@v1 + uses: gradle/wrapper-validation-action@v2 - name: Set up JDK 17 uses: actions/setup-java@v4 with: diff --git a/.github/workflows/junit-17-builds.yml b/.github/workflows/junit-17-builds.yml index d737c152b86..ac8de249e1f 100644 --- a/.github/workflows/junit-17-builds.yml +++ b/.github/workflows/junit-17-builds.yml @@ -16,7 +16,7 @@ jobs: with: submodules: recursive - name: validate gradle wrapper - uses: gradle/wrapper-validation-action@v1 + uses: gradle/wrapper-validation-action@v2 - name: Set up JDK 17 uses: actions/setup-java@v4 with: diff --git a/.github/workflows/junit-8-builds.yml b/.github/workflows/junit-8-builds.yml index bc23d73ba72..2a9bf589e67 100644 --- a/.github/workflows/junit-8-builds.yml +++ b/.github/workflows/junit-8-builds.yml @@ -16,7 +16,7 @@ jobs: with: submodules: recursive - name: validate gradle wrapper - uses: gradle/wrapper-validation-action@v1 + uses: gradle/wrapper-validation-action@v2 - name: Set up JDK 17 uses: actions/setup-java@v4 with: diff --git a/.github/workflows/release-docs.yml b/.github/workflows/release-docs.yml index 06cb5569076..f6f7ebc8a27 100644 --- a/.github/workflows/release-docs.yml +++ b/.github/workflows/release-docs.yml @@ -37,7 +37,6 @@ jobs: - name: Push release documentation uses: ./skript/.github/workflows/docs/push-docs with: - docs_output_dir: ${{ steps.configuration.outputs.DOCS_OUTPUT_DIR }} docs_repo_dir: ${{ steps.configuration.outputs.DOCS_REPO_DIR }} git_name: Release Docs Bot git_email: releasedocs@skriptlang.org @@ -69,6 +68,7 @@ jobs: uses: ./skript/.github/workflows/docs/generate-docs with: docs_repo_dir: ${{ steps.configuration.outputs.DOCS_REPO_DIR }} + docs_output_dir: ${{ steps.configuration.outputs.DOCS_OUTPUT_DIR }} skript_repo_dir: ${{ steps.configuration.outputs.SKRIPT_REPO_DIR }} is_release: true - name: Push archive documentation diff --git a/.github/workflows/repo.yml b/.github/workflows/repo.yml index d3527c2c458..77b8a55fd4e 100644 --- a/.github/workflows/repo.yml +++ b/.github/workflows/repo.yml @@ -12,7 +12,7 @@ jobs: with: submodules: recursive - name: validate gradle wrapper - uses: gradle/wrapper-validation-action@v1 + uses: gradle/wrapper-validation-action@v2 - name: Set up JDK 17 uses: actions/setup-java@v4 with: diff --git a/build.gradle b/build.gradle index 708f7274a36..92f13c47f46 100644 --- a/build.gradle +++ b/build.gradle @@ -29,18 +29,18 @@ dependencies { shadow group: 'org.bstats', name: 'bstats-bukkit', version: '3.0.2' shadow group: 'net.kyori', name: 'adventure-text-serializer-bungeecord', version: '4.3.2' - implementation group: 'io.papermc.paper', name: 'paper-api', version: '1.20.2-R0.1-SNAPSHOT' - implementation group: 'org.eclipse.jdt', name: 'org.eclipse.jdt.annotation', version: '2.2.800' + implementation group: 'io.papermc.paper', name: 'paper-api', version: '1.20.4-R0.1-SNAPSHOT' + implementation group: 'org.eclipse.jdt', name: 'org.eclipse.jdt.annotation', version: '2.2.700' implementation group: 'com.google.code.findbugs', name: 'findbugs', version: '3.0.1' implementation group: 'com.sk89q.worldguard', name: 'worldguard-legacy', version: '7.0.0-SNAPSHOT' - implementation group: 'net.milkbowl.vault', name: 'Vault', version: '1.7.1', { + implementation group: 'net.milkbowl.vault', name: 'Vault', version: '1.7.3', { exclude group: 'org.bstats', module: 'bstats-bukkit' } implementation fileTree(dir: 'lib', include: '*.jar') testShadow group: 'junit', name: 'junit', version: '4.13.2' - testShadow group: 'org.easymock', name: 'easymock', version: '5.2.0' + testShadow group: 'org.easymock', name: 'easymock', version: '5.0.1' } task checkAliases { @@ -250,7 +250,7 @@ void createTestTask(String name, String desc, String environments, int javaVersi } } -def latestEnv = 'java17/paper-1.20.2.json' +def latestEnv = 'java17/paper-1.20.4.json' def latestJava = 17 def oldestJava = 8 @@ -295,10 +295,8 @@ task githubResources(type: ProcessResources) { include '**' version = project.property('version') def channel = 'stable' - if (version.contains('alpha')) - channel = 'alpha' - else if (version.contains('beta')) - channel = 'beta' + if (version.contains('pre')) + channel = 'prerelease' filter ReplaceTokens, tokens: [ 'version' : version, 'today' : '' + LocalTime.now(), @@ -330,10 +328,8 @@ task spigotResources(type: ProcessResources) { include '**' version = project.property('version') def channel = 'stable' - if (version.contains('alpha')) - channel = 'alpha' - else if (version.contains('beta')) - channel = 'beta' + if (version.contains('pre')) + channel = 'prerelease' filter ReplaceTokens, tokens: [ 'version' : version, 'today' : '' + LocalTime.now(), @@ -369,7 +365,7 @@ task nightlyResources(type: ProcessResources) { 'version' : version, 'today' : '' + LocalTime.now(), 'release-flavor' : 'skriptlang-nightly', // SkriptLang build, automatically done by CI - 'release-channel' : 'alpha', // No update checking, but these are VERY unstable + 'release-channel' : 'prerelease', // No update checking, but these are VERY unstable 'release-updater' : 'ch.njol.skript.update.NoUpdateChecker', // No autoupdates for now 'release-source' : '', 'release-download': 'null' diff --git a/code-conventions.md b/code-conventions.md index 37ac182cd62..327951d2299 100644 --- a/code-conventions.md +++ b/code-conventions.md @@ -127,9 +127,11 @@ If we need to remove or alter contributed code due to a licensing issue we will - Static constant fields should be named in `UPPER_SNAKE_CASE` * Localised messages should be named in `lower_snake_case` - And that is the only place where snake_case is acceptable -* Use prefixes only where their use has been already estabilished (such as `ExprSomeRandomThing`) +* Use prefixes only where their use has been already established (such as `ExprSomeRandomThing`) - Otherwise, use postfixes where necessary - Common occurrences include: Struct (Structure), Sec (Section), EffSec (EffectSection), Eff (Effect), Cond (Condition), Expr (Expression) +* Ensure variable/field names are descriptive. Avoid using shorthand names like `e`, or `c`. + - e.g. Event should be `event`, not `e`. `e` is ambiguous and could mean a number of things. ### Comments * Prefer to comment *why* you're doing things instead of how you're doing them diff --git a/gradle.properties b/gradle.properties index 7af67b25858..e31c5a65002 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,7 +5,7 @@ org.gradle.parallel=true groupid=ch.njol name=skript -version=2.8.0-dev +version=2.8.3 jarName=Skript.jar -testEnv=java17/paper-1.20.2 +testEnv=java17/paper-1.20.4 testEnvJavaVersion=17 diff --git a/skript-aliases b/skript-aliases index 0884ede0fdf..490bbeadf6e 160000 --- a/skript-aliases +++ b/skript-aliases @@ -1 +1 @@ -Subproject commit 0884ede0fdf69e914b944500d9f24f1c000a90a2 +Subproject commit 490bbeadf6e44e26dd436acfd191dae5b740ebe6 diff --git a/src/main/java/ch/njol/skript/Skript.java b/src/main/java/ch/njol/skript/Skript.java index 878dfe12666..8b7c00f6219 100644 --- a/src/main/java/ch/njol/skript/Skript.java +++ b/src/main/java/ch/njol/skript/Skript.java @@ -26,6 +26,7 @@ import ch.njol.skript.classes.data.DefaultComparators; import ch.njol.skript.classes.data.DefaultConverters; import ch.njol.skript.classes.data.DefaultFunctions; +import ch.njol.skript.classes.data.DefaultOperations; import ch.njol.skript.classes.data.JavaClasses; import ch.njol.skript.classes.data.SkriptClasses; import ch.njol.skript.command.Commands; @@ -82,6 +83,7 @@ import ch.njol.util.Kleenean; import ch.njol.util.NullableChecker; import ch.njol.util.StringUtils; +import ch.njol.util.coll.CollectionUtils; import ch.njol.util.coll.iterator.CheckedIterator; import ch.njol.util.coll.iterator.EnumerationIterable; import com.google.common.collect.Lists; @@ -106,6 +108,7 @@ import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.plugin.java.JavaPlugin; import org.eclipse.jdt.annotation.Nullable; +import org.junit.After; import org.junit.runner.JUnitCore; import org.junit.runner.Result; import org.skriptlang.skript.lang.comparator.Comparator; @@ -147,7 +150,6 @@ import java.util.logging.Level; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; import java.util.zip.ZipEntry; import java.util.zip.ZipException; import java.util.zip.ZipFile; @@ -534,6 +536,7 @@ public void onEnable() { new DefaultComparators(); new DefaultConverters(); new DefaultFunctions(); + new DefaultOperations(); ChatMessages.registerListeners(); @@ -690,6 +693,9 @@ protected void afterErrors() { long milliseconds = 0, tests = 0, fails = 0, ignored = 0, size = 0; try { List> classes = Lists.newArrayList(Utils.getClasses(Skript.getInstance(), "org.skriptlang.skript.test", "tests")); + // Don't attempt to run inner/anonymous classes as tests + classes.removeIf(Class::isAnonymousClass); + classes.removeIf(Class::isLocalClass); // Test that requires package access. This is only present when compiling with src/test. classes.add(Class.forName("ch.njol.skript.variables.FlatFileStorageTest")); size = classes.size(); @@ -703,6 +709,23 @@ protected void afterErrors() { Result junit = JUnitCore.runClasses(clazz); TestTracker.testStarted("JUnit: '" + test + "'"); + /** + * Usage of @After is pointless if the JUnit class requires delay. As the @After will happen instantly. + * The JUnit must override the 'cleanup' method to avoid Skript automatically cleaning up the test data. + */ + boolean overrides = false; + for (Method method : clazz.getDeclaredMethods()) { + if (!method.isAnnotationPresent(After.class)) + continue; + if (SkriptJUnitTest.getShutdownDelay() > 1) + warning("Using @After in JUnit classes, happens instantaneously, and JUnit class '" + test + "' requires a delay. Do your test cleanup in the script junit file or 'cleanup' method."); + if (method.getName().equals("cleanup")) + overrides = true; + } + if (SkriptJUnitTest.getShutdownDelay() > 1 && !overrides) + error("The JUnit class '" + test + "' does not override the method 'cleanup' thus the test data will instantly be cleaned up. " + + "This JUnit test requires longer shutdown time: " + SkriptJUnitTest.getShutdownDelay()); + // Collect all data from the current JUnit test. shutdownDelay = Math.max(shutdownDelay, SkriptJUnitTest.getShutdownDelay()); tests += junit.getRunCount(); @@ -1134,7 +1157,15 @@ public void onPluginDisable(PluginDisableEvent event) { try { // Spigot removed the mapping for this method in 1.18, so its back to obfuscated method // 1.19 mapping is u and 1.18 is v - String isRunningMethod = Skript.isRunningMinecraft(1, 19) ? "u" : Skript.isRunningMinecraft(1, 18) ? "v" :"isRunning"; + String isRunningMethod = "isRunning"; + + if (Skript.isRunningMinecraft(1, 20)) { + isRunningMethod = "v"; + } else if (Skript.isRunningMinecraft(1, 19)) { + isRunningMethod = "u"; + } else if (Skript.isRunningMinecraft(1, 18)) { + isRunningMethod = "v"; + } IS_RUNNING = MC_SERVER.getClass().getMethod(isRunningMethod); } catch (NoSuchMethodException e) { throw new RuntimeException(e); diff --git a/src/main/java/ch/njol/skript/SkriptConfig.java b/src/main/java/ch/njol/skript/SkriptConfig.java index 13ce39f7620..a8cb74a869b 100644 --- a/src/main/java/ch/njol/skript/SkriptConfig.java +++ b/src/main/java/ch/njol/skript/SkriptConfig.java @@ -97,14 +97,15 @@ public class SkriptConfig { .setter(t -> { ReleaseChannel channel; switch (t) { - case "alpha": // Everything goes in alpha channel - channel = new ReleaseChannel((name) -> true, t); - break; + case "alpha": case "beta": - channel = new ReleaseChannel((name) -> !name.contains("alpha"), t); + Skript.warning("'alpha' and 'beta' are no longer valid release channels. Use 'prerelease' instead."); + case "prerelease": // All development builds are valid + channel = new ReleaseChannel((name) -> true, t); break; case "stable": - channel = new ReleaseChannel((name) -> !name.contains("alpha") && !name.contains("beta"), t); + // TODO a better option would be to check that it is not a pre-release through GH API + channel = new ReleaseChannel((name) -> !name.contains("pre"), t); break; case "none": channel = new ReleaseChannel((name) -> false, t); @@ -116,9 +117,6 @@ public class SkriptConfig { } SkriptUpdater updater = Skript.getInstance().getUpdater(); if (updater != null) { - if (updater.getCurrentRelease().flavor.contains("spigot") && !t.equals("stable")) { - Skript.error("Only stable Skript versions are uploaded to Spigot resources."); - } updater.setReleaseChannel(channel); } }); diff --git a/src/main/java/ch/njol/skript/aliases/AliasesProvider.java b/src/main/java/ch/njol/skript/aliases/AliasesProvider.java index 1c6e73184c4..c4fc7b4204a 100644 --- a/src/main/java/ch/njol/skript/aliases/AliasesProvider.java +++ b/src/main/java/ch/njol/skript/aliases/AliasesProvider.java @@ -21,10 +21,12 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Set; import java.util.List; import java.util.Map; +import ch.njol.skript.Skript; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; @@ -42,6 +44,9 @@ * Provides aliases on Bukkit/Spigot platform. */ public class AliasesProvider { + + // not supported on Spigot versions older than 1.18 + private static final boolean FASTER_SET_SUPPORTED = Skript.classExists("it.unimi.dsi.fastutil.objects.ObjectOpenHashSet"); /** * When an alias is not found, it will requested from this provider. @@ -173,7 +178,12 @@ public AliasesProvider(int expectedCount, @Nullable AliasesProvider parent) { this.aliases = new HashMap<>(expectedCount); this.variations = new HashMap<>(expectedCount / 20); this.aliasesMap = new AliasesMap(); - this.materials = new ObjectOpenHashSet<>(); + + if (FASTER_SET_SUPPORTED) { + this.materials = new ObjectOpenHashSet<>(); + } else { + this.materials = new HashSet<>(); + } this.gson = new Gson(); } diff --git a/src/main/java/ch/njol/skript/bukkitutil/HealthUtils.java b/src/main/java/ch/njol/skript/bukkitutil/HealthUtils.java index 9af9012eb7f..20b5120a0f1 100644 --- a/src/main/java/ch/njol/skript/bukkitutil/HealthUtils.java +++ b/src/main/java/ch/njol/skript/bukkitutil/HealthUtils.java @@ -18,13 +18,21 @@ */ package ch.njol.skript.bukkitutil; +import ch.njol.skript.Skript; import ch.njol.util.Math2; import org.bukkit.attribute.Attributable; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeInstance; +import org.bukkit.damage.DamageSource; +import org.bukkit.damage.DamageType; import org.bukkit.entity.Damageable; import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; public class HealthUtils { @@ -107,9 +115,28 @@ public static double getFinalDamage(EntityDamageEvent e) { public static void setDamage(EntityDamageEvent e, double damage) { e.setDamage(damage * 2); } - + + @Nullable + private static final Constructor OLD_DAMAGE_EVENT_CONSTRUCTOR; + + static { + Constructor constructor = null; + try { + constructor = EntityDamageEvent.class.getConstructor(Damageable.class, DamageCause.class, double.class); + } catch (NoSuchMethodException ignored) { } + OLD_DAMAGE_EVENT_CONSTRUCTOR = constructor; + } + public static void setDamageCause(Damageable e, DamageCause cause) { - e.setLastDamageCause(new EntityDamageEvent(e, cause, 0)); + if (OLD_DAMAGE_EVENT_CONSTRUCTOR != null) { + try { + e.setLastDamageCause(OLD_DAMAGE_EVENT_CONSTRUCTOR.newInstance(e, cause, 0)); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException ex) { + Skript.exception("Failed to set last damage cause"); + } + } else { + e.setLastDamageCause(new EntityDamageEvent(e, cause, DamageSource.builder(DamageType.GENERIC).build(), 0)); + } } - + } diff --git a/src/main/java/ch/njol/skript/classes/Arithmetic.java b/src/main/java/ch/njol/skript/classes/Arithmetic.java index 85461a67044..2365c3a64da 100644 --- a/src/main/java/ch/njol/skript/classes/Arithmetic.java +++ b/src/main/java/ch/njol/skript/classes/Arithmetic.java @@ -24,6 +24,7 @@ * @param the type of the absolute value * @param the type of the relative value */ +@Deprecated public interface Arithmetic { public R difference(A first, A second); diff --git a/src/main/java/ch/njol/skript/classes/ClassInfo.java b/src/main/java/ch/njol/skript/classes/ClassInfo.java index 3dce029edb5..30211480a05 100644 --- a/src/main/java/ch/njol/skript/classes/ClassInfo.java +++ b/src/main/java/ch/njol/skript/classes/ClassInfo.java @@ -18,26 +18,27 @@ */ package ch.njol.skript.classes; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; -import java.util.function.Supplier; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; - import ch.njol.skript.SkriptAPIException; -import ch.njol.util.coll.iterator.ArrayIterator; -import org.bukkit.event.Event; -import org.eclipse.jdt.annotation.NonNull; -import org.eclipse.jdt.annotation.Nullable; - import ch.njol.skript.expressions.base.EventValueExpression; import ch.njol.skript.lang.Debuggable; import ch.njol.skript.lang.DefaultExpression; import ch.njol.skript.lang.util.SimpleLiteral; import ch.njol.skript.localization.Noun; +import ch.njol.util.coll.iterator.ArrayIterator; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import org.bukkit.event.Event; +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.function.Supplier; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; +import org.skriptlang.skript.lang.arithmetic.Operator; +import org.skriptlang.skript.lang.arithmetic.Arithmetics; /** * @author Peter Güttinger @@ -223,11 +224,19 @@ public ClassInfo changer(final Changer changer) { this.changer = changer; return this; } - + + @Deprecated + @SuppressWarnings("unchecked") public ClassInfo math(final Class relativeType, final Arithmetic math) { assert this.math == null; this.math = math; mathRelativeType = relativeType; + Arithmetics.registerOperation(Operator.ADDITION, c, relativeType, (left, right) -> (T) math.add(left, right)); + Arithmetics.registerOperation(Operator.SUBTRACTION, c, relativeType, (left, right) -> (T) math.subtract(left, right)); + Arithmetics.registerOperation(Operator.MULTIPLICATION, c, relativeType, (left, right) -> (T) math.multiply(left, right)); + Arithmetics.registerOperation(Operator.DIVISION, c, relativeType, (left, right) -> (T) math.divide(left, right)); + Arithmetics.registerOperation(Operator.EXPONENTIATION, c, relativeType, (left, right) -> (T) math.power(left, right)); + Arithmetics.registerDifference(c, relativeType, math::difference); return this; } @@ -388,16 +397,19 @@ public Class getSerializeAs() { } @Nullable + @Deprecated public Arithmetic getMath() { return math; } @Nullable + @Deprecated public Arithmetic getRelativeMath() { return (Arithmetic) math; } @Nullable + @Deprecated public Class getMathRelativeType() { return mathRelativeType; } @@ -515,7 +527,7 @@ public String toString(final int flags) { @Override @NonNull - public String toString(final @Nullable Event e, final boolean debug) { + public String toString(final @Nullable Event event, final boolean debug) { if (debug) return codeName + " (" + c.getCanonicalName() + ")"; return getName().getSingular(); diff --git a/src/main/java/ch/njol/skript/classes/Converter.java b/src/main/java/ch/njol/skript/classes/Converter.java index d2162d6eccf..0cb0da707b9 100644 --- a/src/main/java/ch/njol/skript/classes/Converter.java +++ b/src/main/java/ch/njol/skript/classes/Converter.java @@ -18,16 +18,15 @@ */ package ch.njol.skript.classes; -import java.util.Arrays; -import java.util.stream.Collectors; - -import org.bukkit.event.Event; -import org.eclipse.jdt.annotation.Nullable; - import ch.njol.skript.lang.Debuggable; import ch.njol.skript.registrations.Classes; +import org.bukkit.event.Event; +import org.eclipse.jdt.annotation.Nullable; import org.skriptlang.skript.lang.converter.Converters; +import java.util.Arrays; +import java.util.stream.Collectors; + /** * Converts data from type to another. * @@ -98,7 +97,7 @@ public ConverterInfo(ConverterInfo first, ConverterInfo second, Conver } @Override - public String toString(@Nullable Event e, boolean debug) { + public String toString(@Nullable Event event, boolean debug) { if (debug) { String str = Arrays.stream(chain).map(c -> Classes.getExactClassName(c)).collect(Collectors.joining(" -> ")); assert str != null; diff --git a/src/main/java/ch/njol/skript/classes/NumberArithmetic.java b/src/main/java/ch/njol/skript/classes/NumberArithmetic.java index 377e3feccce..71c035ebd7d 100644 --- a/src/main/java/ch/njol/skript/classes/NumberArithmetic.java +++ b/src/main/java/ch/njol/skript/classes/NumberArithmetic.java @@ -21,6 +21,7 @@ /** * @author Peter Güttinger */ +@Deprecated public class NumberArithmetic implements Arithmetic { @Override diff --git a/src/main/java/ch/njol/skript/classes/VectorArithmethic.java b/src/main/java/ch/njol/skript/classes/VectorArithmethic.java index d907075357f..5bdac60af9a 100644 --- a/src/main/java/ch/njol/skript/classes/VectorArithmethic.java +++ b/src/main/java/ch/njol/skript/classes/VectorArithmethic.java @@ -23,6 +23,7 @@ /** * @author bi0qaw */ +@Deprecated public class VectorArithmethic implements Arithmetic { @Override 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 b90442fd8c1..25000a2390d 100644 --- a/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java +++ b/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java @@ -19,6 +19,7 @@ package ch.njol.skript.classes.data; import java.io.StreamCorruptedException; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Locale; @@ -59,6 +60,7 @@ import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; import org.bukkit.event.entity.EntityDamageEvent.DamageCause; import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason; +import org.bukkit.event.entity.EntityTransformEvent.TransformReason; import org.bukkit.event.inventory.ClickType; import org.bukkit.event.inventory.InventoryAction; import org.bukkit.event.inventory.InventoryCloseEvent; @@ -660,32 +662,46 @@ public String toVariableNameString(final Inventory i) { Classes.registerClass(new ClassInfo<>(Player.class, "player") .user("players?") .name("Player") - .description("A player. Depending on whether a player is online or offline several actions can be performed with them, " + - "though you won't get any errors when using effects that only work if the player is online (e.g. changing their inventory) on an offline player.", + .description( + "A player. Depending on whether a player is online or offline several actions can be performed with them, " + + "though you won't get any errors when using effects that only work if the player is online (e.g. changing their inventory) on an offline player.", "You have two possibilities to use players as command arguments: <player> and <offline player>. " + - "The first requires that the player is online and also accepts only part of the name, " + - "while the latter doesn't require that the player is online, but the player's name has to be entered exactly.") - .usage("") - .examples("") - .since("1.0") + "The first requires that the player is online and also accepts only part of the name, " + + "while the latter doesn't require that the player is online, but the player's name has to be entered exactly." + ).usage( + "Parsing an offline player as a player (online) will return nothing (none), for that case you would need to parse as " + + "offlineplayer which only returns nothing (none) if player doesn't exist in Minecraft databases (name not taken) otherwise it will return the player regardless of their online status." + ).examples( + "set {_p} to \"Notch\" parsed as a player # returns unless Notch is actually online or starts with Notch like Notchan", + "set {_p} to \"N\" parsed as a player # returns Notch if Notch is online because their name starts with 'N' (case insensitive) however, it would return nothing if no player whose name starts with 'N' is online." + ).since("1.0") .defaultExpression(new EventValueExpression<>(Player.class)) .after("string", "world") .parser(new Parser() { @Override @Nullable - public Player parse(String s, ParseContext context) { + public Player parse(String string, ParseContext context) { if (context == ParseContext.COMMAND || context == ParseContext.PARSE) { - if (s.isEmpty()) + if (string.isEmpty()) return null; - if (UUID_PATTERN.matcher(s).matches()) - return Bukkit.getPlayer(UUID.fromString(s)); - List ps = Bukkit.matchPlayer(s); - if (ps.size() == 1) - return ps.get(0); - if (ps.size() == 0) - Skript.error(String.format(Language.get("commands.no player starts with"), s)); + if (UUID_PATTERN.matcher(string).matches()) + return Bukkit.getPlayer(UUID.fromString(string)); + String name = string.toLowerCase(Locale.ENGLISH); + int nameLength = name.length(); // caching + List players = new ArrayList<>(); + for (Player player : Bukkit.getOnlinePlayers()) { + if (player.getName().toLowerCase(Locale.ENGLISH).startsWith(name)) { + if (player.getName().length() == nameLength) // a little better in performance than String#equals() + return player; + players.add(player); + } + } + if (players.size() == 1) + return players.get(0); + if (players.size() == 0) + Skript.error(String.format(Language.get("commands.no player starts with"), string)); else - Skript.error(String.format(Language.get("commands.multiple players start with"), s)); + Skript.error(String.format(Language.get("commands.multiple players start with"), string)); return null; } assert false; @@ -721,18 +737,20 @@ public String getDebugMessage(final Player p) { Classes.registerClass(new ClassInfo<>(OfflinePlayer.class, "offlineplayer") .user("offline ?players?") .name("Offline Player") - .description("A player that is possibly offline. See player for more information. " + + .description( + "A player that is possibly offline. See player for more information. " + "Please note that while all effects and conditions that require a player can be used with an " + - "offline player as well, they will not work if the player is not actually online.") - .usage("") - .examples("") - .since("") + "offline player as well, they will not work if the player is not actually online." + ).usage( + "Parsing an offline player as a player (online) will return nothing (none), for that case you would need to parse as " + + "offlineplayer which only returns nothing (none) if player doesn't exist in Minecraft databases (name not taken) otherwise it will return the player regardless of their online status." + ).examples("set {_p} to \"Notch\" parsed as an offlineplayer # returns Notch even if they're offline") + .since("2.0 beta 8") .defaultExpression(new EventValueExpression<>(OfflinePlayer.class)) .after("string", "world") .parser(new Parser() { @Override @Nullable - @SuppressWarnings("deprecation") public OfflinePlayer parse(final String s, final ParseContext context) { if (context == ParseContext.COMMAND || context == ParseContext.PARSE) { if (UUID_PATTERN.matcher(s).matches()) @@ -1515,7 +1533,7 @@ public String toVariableNameString(EnchantmentOffer eo) { .name("Quit Reason") .description("Represents a quit reason from a player quit server event.") .requiredPlugins("Paper 1.16.5+") - .since("INSERT VERSION")); + .since("2.8.0")); if (Skript.classExists("org.bukkit.event.inventory.InventoryCloseEvent$Reason")) Classes.registerClass(new EnumClassInfo<>(InventoryCloseEvent.Reason.class, "inventoryclosereason", "inventory close reasons") @@ -1523,7 +1541,13 @@ public String toVariableNameString(EnchantmentOffer eo) { .name("Inventory Close Reasons") .description("The inventory close reason in an inventory close event.") .requiredPlugins("Paper") - .since("INSERT VERSION")); + .since("2.8.0")); + + Classes.registerClass(new EnumClassInfo<>(TransformReason.class, "transformreason", "transform reasons") + .user("(entity)? ?transform ?(reason|cause)s?") + .name("Transform Reason") + .description("Represents a transform reason of an entity transform event.") + .since("2.8.0")); } } 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 1543a5c2d1d..0c3175247b1 100644 --- a/src/main/java/ch/njol/skript/classes/data/BukkitEventValues.java +++ b/src/main/java/ch/njol/skript/classes/data/BukkitEventValues.java @@ -98,6 +98,8 @@ import org.bukkit.event.entity.EntityPickupItemEvent; import org.bukkit.event.entity.EntityResurrectEvent; import org.bukkit.event.entity.EntityTameEvent; +import org.bukkit.event.entity.EntityTransformEvent; +import org.bukkit.event.entity.EntityTransformEvent.TransformReason; import org.bukkit.event.entity.FireworkExplodeEvent; import org.bukkit.event.entity.HorseJumpEvent; import org.bukkit.event.entity.ItemDespawnEvent; @@ -116,6 +118,7 @@ import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryCloseEvent; import org.bukkit.event.inventory.InventoryDragEvent; +import org.bukkit.event.inventory.InventoryMoveItemEvent; import org.bukkit.event.inventory.InventoryOpenEvent; import org.bukkit.event.inventory.InventoryPickupItemEvent; import org.bukkit.event.inventory.PrepareAnvilEvent; @@ -710,14 +713,14 @@ public Block get(final PlayerBedLeaveEvent e) { @Override @Nullable public Block get(final PlayerBucketFillEvent e) { - return e.getBlockClicked().getRelative(e.getBlockFace()); + return e.getBlockClicked(); } }, 0); EventValues.registerEventValue(PlayerBucketFillEvent.class, Block.class, new Getter() { @Override @Nullable public Block get(final PlayerBucketFillEvent e) { - final BlockState s = e.getBlockClicked().getRelative(e.getBlockFace()).getState(); + final BlockState s = e.getBlockClicked().getState(); s.setType(Material.AIR); s.setRawData((byte) 0); return new BlockStateBlock(s, true); @@ -1780,6 +1783,54 @@ public ItemStack get(PlayerStonecutterRecipeSelectEvent event) { } }, EventValues.TIME_NOW); + // EntityTransformEvent + EventValues.registerEventValue(EntityTransformEvent.class, Entity[].class, new Getter() { + @Override + @Nullable + public Entity[] get(EntityTransformEvent event) { + return event.getTransformedEntities().stream().toArray(Entity[]::new); + } + }, EventValues.TIME_NOW); + EventValues.registerEventValue(EntityTransformEvent.class, TransformReason.class, new Getter() { + @Override + @Nullable + public TransformReason get(EntityTransformEvent event) { + return event.getTransformReason(); + } + }, EventValues.TIME_NOW); + + // InventoryMoveItemEvent + EventValues.registerEventValue(InventoryMoveItemEvent.class, Inventory.class, new Getter() { + @Override + public Inventory get(InventoryMoveItemEvent event) { + return event.getSource(); + } + }, EventValues.TIME_NOW); + EventValues.registerEventValue(InventoryMoveItemEvent.class, Inventory.class, new Getter() { + @Override + public Inventory get(InventoryMoveItemEvent event) { + return event.getDestination(); + } + }, EventValues.TIME_FUTURE); + EventValues.registerEventValue(InventoryMoveItemEvent.class, Block.class, new Getter() { + @Override + public Block get(InventoryMoveItemEvent event) { + return event.getSource().getLocation().getBlock(); + } + }, EventValues.TIME_NOW); + EventValues.registerEventValue(InventoryMoveItemEvent.class, Block.class, new Getter() { + @Override + public Block get(InventoryMoveItemEvent event) { + return event.getDestination().getLocation().getBlock(); + } + }, EventValues.TIME_FUTURE); + EventValues.registerEventValue(InventoryMoveItemEvent.class, ItemStack.class, new Getter() { + @Override + public ItemStack get(InventoryMoveItemEvent event) { + return event.getItem(); + } + }, EventValues.TIME_NOW); + } } diff --git a/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java b/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java index e9cb7dc1e97..556f396b80b 100644 --- a/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java +++ b/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java @@ -336,7 +336,7 @@ public Number[] executeSimple(Object[][] params) { "clamp(5, 7, 10) = 7", "clamp((5, 0, 10, 9, 13), 7, 10) = (7, 7, 10, 9, 10)", "set {_clamped::*} to clamp({_values::*}, 0, 10)") - .since("INSERT VERSION"); + .since("2.8.0"); // misc @@ -522,7 +522,7 @@ public Player[] executeSimple(Object[][] params) { } }).description("Returns an online player from their name or UUID, if player is offline function will return nothing.", "Setting 'getExactPlayer' parameter to true will return the player whose name is exactly equal to the provided name instead of returning a player that their name starts with the provided name.") .examples("set {_p} to player(\"Notch\") # will return an online player whose name is or starts with 'Notch'", "set {_p} to player(\"Notch\", true) # will return the only online player whose name is 'Notch'", "set {_p} to player(\"069a79f4-44e9-4726-a5be-fca90e38aaf5\") # if player is offline") - .since("INSERT VERSION"); + .since("2.8.0"); Functions.registerFunction(new SimpleJavaFunction("offlineplayer", new Parameter[] { new Parameter<>("nameOrUUID", DefaultClasses.STRING, true, null) @@ -540,7 +540,7 @@ public OfflinePlayer[] executeSimple(Object[][] params) { } }).description("Returns a offline player from their name or UUID. This function will still return the player if they're online.") .examples("set {_p} to offlineplayer(\"Notch\")", "set {_p} to offlineplayer(\"069a79f4-44e9-4726-a5be-fca90e38aaf5\")") - .since("INSERT VERSION"); + .since("2.8.0"); Functions.registerFunction(new SimpleJavaFunction("isNaN", numberParam, DefaultClasses.BOOLEAN, true) { @Override @@ -549,7 +549,7 @@ public Boolean[] executeSimple(Object[][] params) { } }).description("Returns true if the input is NaN (not a number).") .examples("isNaN(0) # false", "isNaN(0/0) # true", "isNaN(sqrt(-1)) # true") - .since("INSERT VERSION"); + .since("2.8.0"); } } diff --git a/src/main/java/ch/njol/skript/classes/data/DefaultOperations.java b/src/main/java/ch/njol/skript/classes/data/DefaultOperations.java new file mode 100644 index 00000000000..e6397a1e767 --- /dev/null +++ b/src/main/java/ch/njol/skript/classes/data/DefaultOperations.java @@ -0,0 +1,120 @@ +/** + * 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.classes.data; + +import ch.njol.skript.util.Date; +import ch.njol.skript.util.Timespan; +import ch.njol.skript.util.Utils; +import ch.njol.util.Math2; +import org.bukkit.util.Vector; +import org.skriptlang.skript.lang.arithmetic.Arithmetics; +import org.skriptlang.skript.lang.arithmetic.Operator; + +public class DefaultOperations { + + static { + // Number - Number + Arithmetics.registerOperation(Operator.ADDITION, Number.class, (left, right) -> { + if (Utils.isInteger(left, right)) + return left.longValue() + right.longValue(); + return left.doubleValue() + right.doubleValue(); + }); + Arithmetics.registerOperation(Operator.SUBTRACTION, Number.class, (left, right) -> { + if (Utils.isInteger(left, right)) + return left.longValue() - right.longValue(); + return left.doubleValue() - right.doubleValue(); + }); + Arithmetics.registerOperation(Operator.MULTIPLICATION, Number.class, (left, right) -> { + if (Utils.isInteger(left, right)) + return left.longValue() * right.longValue(); + return left.doubleValue() * right.doubleValue(); + }); + Arithmetics.registerOperation(Operator.DIVISION, Number.class, (left, right) -> left.doubleValue() / right.doubleValue()); + Arithmetics.registerOperation(Operator.EXPONENTIATION, Number.class, (left, right) -> { + if (Utils.isInteger(left, right) && right.longValue() >= 0) + return (long) Math.pow(left.longValue(), right.longValue()); + return Math.pow(left.doubleValue(), right.doubleValue()); + }); + Arithmetics.registerDifference(Number.class, (left, right) -> { + if (Utils.isInteger(left, right)) + return Math.abs(left.longValue() - right.longValue()); + return Math.abs(left.doubleValue() - right.doubleValue()); + }); + Arithmetics.registerDefaultValue(Number.class, () -> 0L); + + // Vector - Vector + Arithmetics.registerOperation(Operator.ADDITION, Vector.class, (left, right) -> left.clone().add(right)); + Arithmetics.registerOperation(Operator.SUBTRACTION, Vector.class, (left, right) -> left.clone().subtract(right)); + Arithmetics.registerOperation(Operator.MULTIPLICATION, Vector.class, (left, right) -> left.clone().multiply(right)); + Arithmetics.registerOperation(Operator.DIVISION, Vector.class, (left, right) -> left.clone().divide(right)); + Arithmetics.registerDifference(Vector.class, + (left, right) -> new Vector(Math.abs(left.getX() - right.getX()), Math.abs(left.getY() - right.getY()), Math.abs(left.getZ() - right.getZ()))); + Arithmetics.registerDefaultValue(Vector.class, Vector::new); + + // Vector - Number + // Number - Vector + Arithmetics.registerOperation(Operator.MULTIPLICATION, Vector.class, Number.class, (left, right) -> left.clone().multiply(right.doubleValue()), (left, right) -> { + double number = left.doubleValue(); + Vector leftVector = new Vector(number, number, number); + return leftVector.multiply(right); + }); + Arithmetics.registerOperation(Operator.DIVISION, Vector.class, Number.class, (left, right) -> { + double number = right.doubleValue(); + Vector rightVector = new Vector(number, number, number); + return left.clone().divide(rightVector); + }, (left, right) -> { + double number = left.doubleValue(); + Vector leftVector = new Vector(number, number, number); + return leftVector.divide(right); + }); + + // Timespan - Timespan + Arithmetics.registerOperation(Operator.ADDITION, Timespan.class, (left, right) -> new Timespan(Math2.addClamped(left.getMilliSeconds(), right.getMilliSeconds()))); + Arithmetics.registerOperation(Operator.SUBTRACTION, Timespan.class, (left, right) -> new Timespan(Math.max(0, left.getMilliSeconds() - right.getMilliSeconds()))); + Arithmetics.registerDifference(Timespan.class, (left, right) -> new Timespan(Math.abs(left.getMilliSeconds() - right.getMilliSeconds()))); + Arithmetics.registerDefaultValue(Timespan.class, Timespan::new); + + // Timespan - Number + // Number - Timespan + Arithmetics.registerOperation(Operator.MULTIPLICATION, Timespan.class, Number.class, (left, right) -> { + long scalar = right.longValue(); + if (scalar < 0) + return null; + return new Timespan(Math2.multiplyClamped(left.getMilliSeconds(), scalar)); + }, (left, right) -> { + long scalar = left.longValue(); + if (scalar < 0) + return null; + return new Timespan(scalar * right.getMilliSeconds()); + }); + Arithmetics.registerOperation(Operator.DIVISION, Timespan.class, Number.class, (left, right) -> { + long scalar = right.longValue(); + if (scalar <= 0) + return null; + return new Timespan(left.getMilliSeconds() / scalar); + }); + + // Date - Timespan + Arithmetics.registerOperation(Operator.ADDITION, Date.class, Timespan.class, Date::plus); + Arithmetics.registerOperation(Operator.SUBTRACTION, Date.class, Timespan.class, Date::minus); + Arithmetics.registerDifference(Date.class, Timespan.class, Date::difference); + + } + +} diff --git a/src/main/java/ch/njol/skript/classes/data/JavaClasses.java b/src/main/java/ch/njol/skript/classes/data/JavaClasses.java index 237b5db732c..ce726218e6f 100644 --- a/src/main/java/ch/njol/skript/classes/data/JavaClasses.java +++ b/src/main/java/ch/njol/skript/classes/data/JavaClasses.java @@ -20,7 +20,6 @@ import ch.njol.skript.SkriptConfig; import ch.njol.skript.classes.ClassInfo; -import ch.njol.skript.classes.NumberArithmetic; import ch.njol.skript.classes.Parser; import ch.njol.skript.classes.Serializer; import ch.njol.skript.lang.ParseContext; @@ -125,7 +124,7 @@ public Number deserialize(String s) { public boolean mustSyncDeserialization() { return false; } - }).math(Number.class, new NumberArithmetic())); + })); Classes.registerClass(new ClassInfo<>(Long.class, "long") .user("int(eger)?s?") @@ -184,7 +183,7 @@ public Long deserialize(String s) { public boolean mustSyncDeserialization() { return false; } - }).math(Number.class, new NumberArithmetic())); + })); Classes.registerClass(new ClassInfo<>(Integer.class, "integer") .name(ClassInfo.NO_DOC) @@ -241,7 +240,7 @@ public Integer deserialize(String s) { public boolean mustSyncDeserialization() { return false; } - }).math(Number.class, new NumberArithmetic())); + })); Classes.registerClass(new ClassInfo<>(Double.class, "double") .name(ClassInfo.NO_DOC) @@ -303,7 +302,7 @@ public Double deserialize(String s) { public boolean mustSyncDeserialization() { return false; } - }).math(Number.class, new NumberArithmetic())); + })); Classes.registerClass(new ClassInfo<>(Float.class, "float") .name(ClassInfo.NO_DOC) @@ -364,7 +363,7 @@ public Float deserialize(String s) { public boolean mustSyncDeserialization() { return false; } - }).math(Number.class, new NumberArithmetic())); + })); Classes.registerClass(new ClassInfo<>(Boolean.class, "boolean") .user("booleans?") @@ -486,7 +485,7 @@ public Short deserialize(String s) { public boolean mustSyncDeserialization() { return false; } - }).math(Number.class, new NumberArithmetic())); + })); Classes.registerClass(new ClassInfo<>(Byte.class, "byte") .name(ClassInfo.NO_DOC) @@ -543,7 +542,7 @@ public Byte deserialize(String s) { public boolean mustSyncDeserialization() { return false; } - }).math(Number.class, new NumberArithmetic())); + })); Classes.registerClass(new ClassInfo<>(String.class, "string") .user("(text|string)s?") @@ -551,7 +550,7 @@ public boolean mustSyncDeserialization() { .description("Text is simply text, i.e. a sequence of characters, which can optionally contain expressions which will be replaced with a meaningful representation " + "(e.g. %player% will be replaced with the player's name).", "Because scripts are also text, you have to put text into double quotes to tell Skript which part of the line is an effect/expression and which part is the text.", - "Please read the article on Texts and Variable Names to learn more.") + "Please read the article on Texts and Variable Names to learn more.") .usage("simple: \"...\"", "quotes: \"...\"\"...\"", "expressions: \"...%expression%...\"", diff --git a/src/main/java/ch/njol/skript/classes/data/SkriptClasses.java b/src/main/java/ch/njol/skript/classes/data/SkriptClasses.java index 55727c673a6..39dc6447fa5 100644 --- a/src/main/java/ch/njol/skript/classes/data/SkriptClasses.java +++ b/src/main/java/ch/njol/skript/classes/data/SkriptClasses.java @@ -34,7 +34,6 @@ import ch.njol.skript.aliases.ItemType; import ch.njol.skript.bukkitutil.EnchantmentUtils; import ch.njol.skript.bukkitutil.ItemUtils; -import ch.njol.skript.classes.Arithmetic; import ch.njol.skript.classes.Changer; import ch.njol.skript.classes.ClassInfo; import ch.njol.skript.classes.EnumSerializer; @@ -315,38 +314,7 @@ public String toString(final Timespan t, final int flags) { public String toVariableNameString(final Timespan o) { return "timespan:" + o.getMilliSeconds(); } - }).serializer(new YggdrasilSerializer<>()) - .math(Timespan.class, new Arithmetic() { - @Override - public Timespan difference(final Timespan t1, final Timespan t2) { - return new Timespan(Math.abs(t1.getMilliSeconds() - t2.getMilliSeconds())); - } - - @Override - public Timespan add(final Timespan value, final Timespan difference) { - return new Timespan(value.getMilliSeconds() + difference.getMilliSeconds()); - } - - @Override - public Timespan subtract(final Timespan value, final Timespan difference) { - return new Timespan(Math.max(0, value.getMilliSeconds() - difference.getMilliSeconds())); - } - - @Override - public Timespan multiply(Timespan value, Timespan multiplier) { - throw new UnsupportedOperationException(); - } - - @Override - public Timespan divide(Timespan value, Timespan divider) { - throw new UnsupportedOperationException(); - } - - @Override - public Timespan power(Timespan value, Timespan exponent) { - throw new UnsupportedOperationException(); - } - })); + }).serializer(new YggdrasilSerializer<>())); // TODO remove Classes.registerClass(new ClassInfo<>(Timeperiod.class, "timeperiod") @@ -408,38 +376,7 @@ public String toVariableNameString(final Timeperiod o) { "subtract a day from {_yesterday}", "# now {_yesterday} represents the date 24 hours before now") .since("1.4") - .serializer(new YggdrasilSerializer<>()) - .math(Timespan.class, new Arithmetic() { - @Override - public Timespan difference(final Date first, final Date second) { - return first.difference(second); - } - - @Override - public Date add(final Date value, final Timespan difference) { - return new Date(value.getTimestamp() + difference.getMilliSeconds()); - } - - @Override - public Date subtract(final Date value, final Timespan difference) { - return new Date(value.getTimestamp() - difference.getMilliSeconds()); - } - - @Override - public Date multiply(Date value, Timespan multiplier) { - throw new UnsupportedOperationException(); - } - - @Override - public Date divide(Date value, Timespan divider) { - throw new UnsupportedOperationException(); - } - - @Override - public Date power(Date value, Timespan exponent) { - throw new UnsupportedOperationException(); - } - })); + .serializer(new YggdrasilSerializer<>())); Classes.registerClass(new ClassInfo<>(Direction.class, "direction") .user("directions?") diff --git a/src/main/java/ch/njol/skript/command/CommandHelp.java b/src/main/java/ch/njol/skript/command/CommandHelp.java index 4732ba2cde5..ca1c82f5e08 100644 --- a/src/main/java/ch/njol/skript/command/CommandHelp.java +++ b/src/main/java/ch/njol/skript/command/CommandHelp.java @@ -44,8 +44,10 @@ public class CommandHelp { private final String actualCommand, actualNode, argsColor; private String command; private String langNode; + + private boolean revalidate = true; @Nullable - private Message description; + private Message description = null; private final Map arguments = new LinkedHashMap<>(); @@ -53,18 +55,17 @@ public class CommandHelp { private ArgumentHolder wildcardArg = null; public CommandHelp(String command, SkriptColor argsColor, String langNode) { - this(command, argsColor.getFormattedChat(), langNode, new Message(langNode + "." + DEFAULTENTRY)); + this(command, argsColor.getFormattedChat(), langNode); } public CommandHelp(String command, SkriptColor argsColor) { - this(command, argsColor.getFormattedChat(), command, null); + this(command, argsColor.getFormattedChat(), command); } - private CommandHelp(String command, String argsColor, String node, @Nullable Message description) { + private CommandHelp(String command, String argsColor, String node) { this.actualCommand = this.command = command; this.actualNode = this.langNode = node; this.argsColor = argsColor; - this.description = description; } public CommandHelp add(String argument) { @@ -85,14 +86,14 @@ public CommandHelp add(CommandHelp help) { protected void onAdd(CommandHelp parent) { langNode = parent.langNode + "." + actualNode; - description = new Message(langNode + "." + DEFAULTENTRY); command = parent.command + " " + parent.argsColor + actualCommand; + revalidate = true; for (Entry entry : arguments.entrySet()) { if (entry.getValue() instanceof CommandHelp) { ((CommandHelp) entry.getValue()).onAdd(this); continue; } - ((ArgumentHolder) entry.getValue()).update(); + ((ArgumentHolder) entry.getValue()).revalidate = true; } } @@ -125,26 +126,32 @@ private void showHelp(CommandSender sender, String pre) { @Override public String toString() { + if (revalidate) { + // We don't want to create a new Message object each time toString is called + description = new Message(langNode + "." + DEFAULTENTRY); + revalidate = false; + } return "" + description; } private class ArgumentHolder { private final String argument; - private Message description; + private boolean revalidate = true; + @Nullable + private Message description = null; private ArgumentHolder(String argument) { this.argument = argument; - this.description = new Message(langNode + "." + argument); - } - - private void update() { - description = new Message(langNode + "." + argument); } @Override public String toString() { - return description.toString(); + if (revalidate) { + description = new Message(langNode + "." + argument); + revalidate = false; + } + return "" + description; } } diff --git a/src/main/java/ch/njol/skript/conditions/CondCanPickUpItems.java b/src/main/java/ch/njol/skript/conditions/CondCanPickUpItems.java index d5a0aaaa591..07f5735e4f9 100644 --- a/src/main/java/ch/njol/skript/conditions/CondCanPickUpItems.java +++ b/src/main/java/ch/njol/skript/conditions/CondCanPickUpItems.java @@ -35,7 +35,7 @@ "\tif player can't pick up items:", "\t\tsend \"Be careful, you won't be able to pick that up!\" to player" }) -@Since("INSERT VERSION") +@Since("2.8.0") public class CondCanPickUpItems extends PropertyCondition { static { diff --git a/src/main/java/ch/njol/skript/conditions/CondCompare.java b/src/main/java/ch/njol/skript/conditions/CondCompare.java index 4e0917faa6d..f725c1bd6f8 100644 --- a/src/main/java/ch/njol/skript/conditions/CondCompare.java +++ b/src/main/java/ch/njol/skript/conditions/CondCompare.java @@ -18,6 +18,7 @@ */ package ch.njol.skript.conditions; +import ch.njol.skript.log.ParseLogHandler; import ch.njol.skript.util.Time; import org.bukkit.event.Event; import org.eclipse.jdt.annotation.Nullable; @@ -166,9 +167,8 @@ public static String f(final Expression e) { @SuppressWarnings("unchecked") private boolean init(String expr) { - RetainingLogHandler log = SkriptLogger.startRetainingLog(); Expression third = this.third; - try { + try (ParseLogHandler log = SkriptLogger.startParseLogHandler()) { if (first.getReturnType() == Object.class) { Expression expression = null; if (first instanceof UnparsedLiteral) @@ -176,7 +176,7 @@ private boolean init(String expr) { if (expression == null) expression = first.getConvertedExpression(Object.class); if (expression == null) { - log.printErrors(); + log.printError(); return false; } first = expression; @@ -188,7 +188,7 @@ private boolean init(String expr) { if (expression == null) expression = second.getConvertedExpression(Object.class); if (expression == null) { - log.printErrors(); + log.printError(); return false; } second = expression; @@ -200,14 +200,13 @@ private boolean init(String expr) { if (expression == null) expression = third.getConvertedExpression(Object.class); if (expression == null) { - log.printErrors(); + log.printError(); return false; } this.third = third = expression; } - log.printLog(); - } finally { - log.stop(); + // we do not want to print any errors as they are not applicable + log.printLog(false); } Class firstReturnType = first.getReturnType(); Class secondReturnType = third == null ? second.getReturnType() : Utils.getSuperType(second.getReturnType(), third.getReturnType()); diff --git a/src/main/java/ch/njol/skript/conditions/CondGlowingText.java b/src/main/java/ch/njol/skript/conditions/CondGlowingText.java index 7d12e477712..aaf14939305 100644 --- a/src/main/java/ch/njol/skript/conditions/CondGlowingText.java +++ b/src/main/java/ch/njol/skript/conditions/CondGlowingText.java @@ -35,7 +35,7 @@ @Name("Has Glowing Text") @Description("Checks whether a sign (either a block or an item) has glowing text") @Examples("if target block has glowing text") -@Since("INSERT VERSION") +@Since("2.8.0") public class CondGlowingText extends PropertyCondition { static { diff --git a/src/main/java/ch/njol/skript/conditions/CondHasItemCooldown.java b/src/main/java/ch/njol/skript/conditions/CondHasItemCooldown.java index be79e48220b..77902e88026 100644 --- a/src/main/java/ch/njol/skript/conditions/CondHasItemCooldown.java +++ b/src/main/java/ch/njol/skript/conditions/CondHasItemCooldown.java @@ -40,7 +40,7 @@ "if player has player's tool on cooldown:", "\tsend \"You can't use this item right now. Wait %item cooldown of player's tool for player%\"" }) -@Since("INSERT VERSION") +@Since("2.8.0") public class CondHasItemCooldown extends Condition { static { diff --git a/src/main/java/ch/njol/skript/conditions/CondHasLineOfSight.java b/src/main/java/ch/njol/skript/conditions/CondHasLineOfSight.java index dd4a18f9ab0..74f820b5613 100644 --- a/src/main/java/ch/njol/skript/conditions/CondHasLineOfSight.java +++ b/src/main/java/ch/njol/skript/conditions/CondHasLineOfSight.java @@ -40,7 +40,7 @@ "victim has line of sight to attacker", "player has no line of sight to location 100 blocks in front of player" }) -@Since("INSERT VERSION") +@Since("2.8.0") public class CondHasLineOfSight extends Condition { static { diff --git a/src/main/java/ch/njol/skript/conditions/CondIsClimbing.java b/src/main/java/ch/njol/skript/conditions/CondIsClimbing.java index af56f90379f..48cdfe5eb40 100644 --- a/src/main/java/ch/njol/skript/conditions/CondIsClimbing.java +++ b/src/main/java/ch/njol/skript/conditions/CondIsClimbing.java @@ -37,7 +37,7 @@ "\tmessage\"The spider is now climbing!\"" }) @RequiredPlugins("Minecraft 1.17+") -@Since("INSERT VERSION") +@Since("2.8.0") public class CondIsClimbing extends PropertyCondition { static { diff --git a/src/main/java/ch/njol/skript/conditions/CondIsHandRaised.java b/src/main/java/ch/njol/skript/conditions/CondIsHandRaised.java index 897b7f6b351..d6030bf2b6a 100644 --- a/src/main/java/ch/njol/skript/conditions/CondIsHandRaised.java +++ b/src/main/java/ch/njol/skript/conditions/CondIsHandRaised.java @@ -44,7 +44,7 @@ "\t\tdrop player's tool at player", "\t\tset player's tool to air" }) -@Since("INSERT VERSION") +@Since("2.8.0") @RequiredPlugins("Paper") public class CondIsHandRaised extends Condition { diff --git a/src/main/java/ch/njol/skript/conditions/CondIsInvulnerable.java b/src/main/java/ch/njol/skript/conditions/CondIsInvulnerable.java index 7dd7a1aec94..5fa5be0c106 100644 --- a/src/main/java/ch/njol/skript/conditions/CondIsInvulnerable.java +++ b/src/main/java/ch/njol/skript/conditions/CondIsInvulnerable.java @@ -33,7 +33,7 @@ public class CondIsInvulnerable extends PropertyCondition { static { - register(CondIsInvulnerable.class, PropertyType.BE, "invulnerable", "entities"); + register(CondIsInvulnerable.class, PropertyType.BE, "(invulnerable|invincible)", "entities"); } @Override diff --git a/src/main/java/ch/njol/skript/conditions/CondIsJumping.java b/src/main/java/ch/njol/skript/conditions/CondIsJumping.java index 9a8c1124fd3..fb3738a05c6 100644 --- a/src/main/java/ch/njol/skript/conditions/CondIsJumping.java +++ b/src/main/java/ch/njol/skript/conditions/CondIsJumping.java @@ -40,7 +40,7 @@ "\t\twait 5 ticks", "\tpush event-entity upwards" }) -@Since("INSERT VERSION") +@Since("2.8.0") @RequiredPlugins("Paper 1.15+") public class CondIsJumping extends PropertyCondition { diff --git a/src/main/java/ch/njol/skript/conditions/CondIsLeftHanded.java b/src/main/java/ch/njol/skript/conditions/CondIsLeftHanded.java index ab2f4b2e26b..7101ad18b92 100644 --- a/src/main/java/ch/njol/skript/conditions/CondIsLeftHanded.java +++ b/src/main/java/ch/njol/skript/conditions/CondIsLeftHanded.java @@ -43,7 +43,7 @@ "\tif victim is left handed:", "\t\tcancel event" }) -@Since("INSERT VERSION") +@Since("2.8.0") @RequiredPlugins("Paper 1.17.1+ (entities)") public class CondIsLeftHanded extends PropertyCondition { diff --git a/src/main/java/ch/njol/skript/conditions/CondIsSheared.java b/src/main/java/ch/njol/skript/conditions/CondIsSheared.java index f667f292899..a000891be95 100644 --- a/src/main/java/ch/njol/skript/conditions/CondIsSheared.java +++ b/src/main/java/ch/njol/skript/conditions/CondIsSheared.java @@ -38,7 +38,7 @@ "if targeted entity of player is sheared:", "\tsend \"This entity has nothing left to shear!\" to player" }) -@Since("INSERT VERSION") +@Since("2.8.0") @RequiredPlugins("MC 1.13+ (cows, sheep & snowmen), Paper 1.19.4+ (all shearable entities)") public class CondIsSheared extends PropertyCondition { diff --git a/src/main/java/ch/njol/skript/conditions/base/PropertyCondition.java b/src/main/java/ch/njol/skript/conditions/base/PropertyCondition.java index 8e73bf83d56..528b216ffc7 100644 --- a/src/main/java/ch/njol/skript/conditions/base/PropertyCondition.java +++ b/src/main/java/ch/njol/skript/conditions/base/PropertyCondition.java @@ -90,6 +90,7 @@ public enum PropertyType { * @param property the property name, for example fly in players can fly * @param type must be plural, for example players in players can fly */ + public static void register(Class condition, String property, String type) { register(condition, PropertyType.BE, property, type); } @@ -100,6 +101,7 @@ public static void register(Class condition, String propert * @param property the property name, for example fly in players can fly * @param type must be plural, for example players in players can fly */ + public static void register(Class condition, PropertyType propertyType, String property, String type) { if (type.contains("%")) throw new SkriptAPIException("The type argument must not contain any '%'s"); @@ -131,9 +133,9 @@ public static void register(Class condition, PropertyType p } @Override - @SuppressWarnings("unchecked") - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { - expr = (Expression) exprs[0]; + public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + expr = (Expression) expressions[0]; + setNegated(matchedPattern == 1); return true; } @@ -144,8 +146,8 @@ public final boolean check(Event event) { } @Override - public abstract boolean check(T t); - + public abstract boolean check(T value); + protected abstract String getPropertyName(); protected PropertyType getPropertyType() { diff --git a/src/main/java/ch/njol/skript/config/Node.java b/src/main/java/ch/njol/skript/config/Node.java index 170fd38cf42..afb3ea3d038 100644 --- a/src/main/java/ch/njol/skript/config/Node.java +++ b/src/main/java/ch/njol/skript/config/Node.java @@ -128,6 +128,8 @@ public void move(final SectionNode newParent) { * @return A pair (value, comment). */ public static NonNullPair splitLine(final String line) { + if (line.trim().startsWith("#")) + return new NonNullPair<>("", line.substring(line.indexOf('#'))); final Matcher m = linePattern.matcher(line); boolean matches = false; try { diff --git a/src/main/java/ch/njol/skript/doc/Documentation.java b/src/main/java/ch/njol/skript/doc/Documentation.java index c7b9ebebbb1..9797e1b2188 100644 --- a/src/main/java/ch/njol/skript/doc/Documentation.java +++ b/src/main/java/ch/njol/skript/doc/Documentation.java @@ -18,18 +18,6 @@ */ package ch.njol.skript.doc; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.io.UnsupportedEncodingException; -import java.util.ArrayList; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.eclipse.jdt.annotation.Nullable; - import ch.njol.skript.Skript; import ch.njol.skript.classes.ClassInfo; import ch.njol.skript.conditions.CondCompare; @@ -47,6 +35,17 @@ import ch.njol.util.coll.CollectionUtils; import ch.njol.util.coll.iterator.IteratorIterable; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import org.eclipse.jdt.annotation.Nullable; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * TODO list special expressions for events and event values @@ -305,28 +304,29 @@ public String run(final Matcher m) { } private static void insertSyntaxElement(final PrintWriter pw, final SyntaxElementInfo info, final String type) { - if (info.c.getAnnotation(NoDoc.class) != null) + Class elementClass = info.getElementClass(); + if (elementClass.getAnnotation(NoDoc.class) != null) return; - if (info.c.getAnnotation(Name.class) == null || info.c.getAnnotation(Description.class) == null || info.c.getAnnotation(Examples.class) == null || info.c.getAnnotation(Since.class) == null) { - Skript.warning("" + info.c.getSimpleName() + " is missing information"); + if (elementClass.getAnnotation(Name.class) == null || elementClass.getAnnotation(Description.class) == null || elementClass.getAnnotation(Examples.class) == null || elementClass.getAnnotation(Since.class) == null) { + Skript.warning("" + elementClass.getSimpleName() + " is missing information"); return; } - final String desc = validateHTML(StringUtils.join(info.c.getAnnotation(Description.class).value(), "
"), type + "s"); - final String since = validateHTML(info.c.getAnnotation(Since.class).value(), type + "s"); + final String desc = validateHTML(StringUtils.join(elementClass.getAnnotation(Description.class).value(), "
"), type + "s"); + final String since = validateHTML(elementClass.getAnnotation(Since.class).value(), type + "s"); if (desc == null || since == null) { - Skript.warning("" + info.c.getSimpleName() + "'s description or 'since' is invalid"); + Skript.warning("" + elementClass.getSimpleName() + "'s description or 'since' is invalid"); return; } - final String patterns = cleanPatterns(StringUtils.join(info.patterns, "\n", 0, info.c == CondCompare.class ? 8 : info.patterns.length)); + final String patterns = cleanPatterns(StringUtils.join(info.patterns, "\n", 0, elementClass == CondCompare.class ? 8 : info.patterns.length)); insertOnDuplicateKeyUpdate(pw, "syntax_elements", "id, name, type, patterns, description, examples, since", "patterns = TRIM(LEADING '\n' FROM CONCAT(patterns, '\n', '" + escapeSQL(patterns) + "'))", - escapeHTML("" + info.c.getSimpleName()), - escapeHTML(info.c.getAnnotation(Name.class).value()), + escapeHTML("" + elementClass.getSimpleName()), + escapeHTML(elementClass.getAnnotation(Name.class).value()), type, patterns, desc, - escapeHTML(StringUtils.join(info.c.getAnnotation(Examples.class).value(), "\n")), + escapeHTML(StringUtils.join(elementClass.getAnnotation(Examples.class).value(), "\n")), since); } @@ -334,7 +334,7 @@ private static void insertEvent(final PrintWriter pw, final SkriptEventInfo i if (info.getDescription() == SkriptEventInfo.NO_DOC) return; if (info.getDescription() == null || info.getExamples() == null || info.getSince() == null) { - Skript.warning("" + info.getName() + " (" + info.c.getSimpleName() + ") is missing information"); + Skript.warning("" + info.getName() + " (" + info.getElementClass().getSimpleName() + ") is missing information"); return; } for (final SkriptEventInfo i : Skript.getEvents()) { @@ -346,7 +346,7 @@ private static void insertEvent(final PrintWriter pw, final SkriptEventInfo i final String desc = validateHTML(StringUtils.join(info.getDescription(), "
"), "events"); final String since = validateHTML(info.getSince(), "events"); if (desc == null || since == null) { - Skript.warning("description or 'since' of " + info.getName() + " (" + info.c.getSimpleName() + ") is invalid"); + Skript.warning("description or 'since' of " + info.getName() + " (" + info.getElementClass().getSimpleName() + ") is invalid"); return; } final String patterns = cleanPatterns(info.getName().startsWith("On ") ? "[on] " + StringUtils.join(info.patterns, "\n[on] ") : StringUtils.join(info.patterns, "\n")); diff --git a/src/main/java/ch/njol/skript/doc/HTMLGenerator.java b/src/main/java/ch/njol/skript/doc/HTMLGenerator.java index 01a217cc5fb..e882057cebd 100644 --- a/src/main/java/ch/njol/skript/doc/HTMLGenerator.java +++ b/src/main/java/ch/njol/skript/doc/HTMLGenerator.java @@ -86,19 +86,19 @@ public HTMLGenerator(File templateDir, File outputDir) { throw new NullPointerException(); } - if (o1.c.getAnnotation(NoDoc.class) != null) { - if (o2.c.getAnnotation(NoDoc.class) != null) + if (o1.getElementClass().getAnnotation(NoDoc.class) != null) { + if (o2.getElementClass().getAnnotation(NoDoc.class) != null) return 0; return 1; - } else if (o2.c.getAnnotation(NoDoc.class) != null) + } else if (o2.getElementClass().getAnnotation(NoDoc.class) != null) return -1; - Name name1 = o1.c.getAnnotation(Name.class); - Name name2 = o2.c.getAnnotation(Name.class); + Name name1 = o1.getElementClass().getAnnotation(Name.class); + Name name2 = o2.getElementClass().getAnnotation(Name.class); if (name1 == null) - throw new SkriptAPIException("Name annotation expected: " + o1.c); + throw new SkriptAPIException("Name annotation expected: " + o1.getElementClass()); if (name2 == null) - throw new SkriptAPIException("Name annotation expected: " + o2.c); + throw new SkriptAPIException("Name annotation expected: " + o2.getElementClass()); return name1.value().compareTo(name2.value()); }; @@ -115,8 +115,8 @@ private static Iterator> sortedAnnotatedItera while (it.hasNext()) { SyntaxElementInfo item = it.next(); // Filter unnamed expressions (mostly caused by addons) to avoid throwing exceptions and stop the generation process - if (item.c.getAnnotation(Name.class) == null && item.c.getAnnotation(NoDoc.class) == null) { - Skript.warning("Skipped generating '" + item.c + "' class due to missing Name annotation"); + if (item.getElementClass().getAnnotation(Name.class) == null && item.getElementClass().getAnnotation(NoDoc.class) == null) { + Skript.warning("Skipped generating '" + item.getElementClass() + "' class due to missing Name annotation"); continue; } list.add(item); @@ -141,9 +141,9 @@ public int compare(@Nullable SkriptEventInfo o1, @Nullable SkriptEventInfo throw new NullPointerException(); } - if (o1.c.getAnnotation(NoDoc.class) != null) + if (o1.getElementClass().getAnnotation(NoDoc.class) != null) return 1; - else if (o2.c.getAnnotation(NoDoc.class) != null) + else if (o2.getElementClass().getAnnotation(NoDoc.class) != null) return -1; return o1.name.compareTo(o2.name); @@ -285,7 +285,7 @@ else if (!filesInside.getName().matches("(?i)(.*)\\.(html?|js|css|json)")) { StructureInfo info = it.next(); assert info != null; - if (info.c.getAnnotation(NoDoc.class) != null) + if (info.getElementClass().getAnnotation(NoDoc.class) != null) continue; String desc = generateAnnotated(descTemp, info, generated.toString(), "Structure"); generated.append(desc); @@ -296,7 +296,7 @@ else if (!filesInside.getName().matches("(?i)(.*)\\.(html?|js|css|json)")) { for (Iterator> it = sortedAnnotatedIterator((Iterator) Skript.getExpressions()); it.hasNext(); ) { ExpressionInfo info = it.next(); assert info != null; - if (info.c.getAnnotation(NoDoc.class) != null) + if (info.getElementClass().getAnnotation(NoDoc.class) != null) continue; String desc = generateAnnotated(descTemp, info, generated.toString(), "Expression"); generated.append(desc); @@ -306,7 +306,7 @@ else if (!filesInside.getName().matches("(?i)(.*)\\.(html?|js|css|json)")) { for (Iterator> it = sortedAnnotatedIterator(Skript.getEffects().iterator()); it.hasNext(); ) { SyntaxElementInfo info = it.next(); assert info != null; - if (info.c.getAnnotation(NoDoc.class) != null) + if (info.getElementClass().getAnnotation(NoDoc.class) != null) continue; generated.append(generateAnnotated(descTemp, info, generated.toString(), "Effect")); } @@ -314,8 +314,8 @@ else if (!filesInside.getName().matches("(?i)(.*)\\.(html?|js|css|json)")) { for (Iterator> it = sortedAnnotatedIterator(Skript.getSections().iterator()); it.hasNext(); ) { SyntaxElementInfo info = it.next(); assert info != null; - if (EffectSection.class.isAssignableFrom(info.c)) { - if (info.c.getAnnotation(NoDoc.class) != null) + if (EffectSection.class.isAssignableFrom(info.getElementClass())) { + if (info.getElementClass().getAnnotation(NoDoc.class) != null) continue; generated.append(generateAnnotated(descTemp, info, generated.toString(), "EffectSection")); } @@ -325,7 +325,7 @@ else if (!filesInside.getName().matches("(?i)(.*)\\.(html?|js|css|json)")) { for (Iterator> it = sortedAnnotatedIterator(Skript.getConditions().iterator()); it.hasNext(); ) { SyntaxElementInfo info = it.next(); assert info != null; - if (info.c.getAnnotation(NoDoc.class) != null) + if (info.getElementClass().getAnnotation(NoDoc.class) != null) continue; generated.append(generateAnnotated(descTemp, info, generated.toString(), "Condition")); } @@ -334,9 +334,9 @@ else if (!filesInside.getName().matches("(?i)(.*)\\.(html?|js|css|json)")) { for (Iterator> it = sortedAnnotatedIterator(Skript.getSections().iterator()); it.hasNext(); ) { SyntaxElementInfo info = it.next(); assert info != null; - boolean isEffectSection = EffectSection.class.isAssignableFrom(info.c); + boolean isEffectSection = EffectSection.class.isAssignableFrom(info.getElementClass()); // exclude sections that are EffectSection from isDocsPage, they are added by the effects block above - if ((isEffectSection && isDocsPage) || info.c.getAnnotation(NoDoc.class) != null) + if ((isEffectSection && isDocsPage) || info.getElementClass().getAnnotation(NoDoc.class) != null) continue; generated.append(generateAnnotated(descTemp, info, generated.toString(), (isEffectSection ? "Effect" : "") + "Section")); } @@ -346,7 +346,7 @@ else if (!filesInside.getName().matches("(?i)(.*)\\.(html?|js|css|json)")) { events.sort(eventComparator); for (SkriptEventInfo info : events) { assert info != null; - if (info.c.getAnnotation(NoDoc.class) != null) + if (info.getElementClass().getAnnotation(NoDoc.class) != null) continue; generated.append(generateEvent(descTemp, info, generated.toString())); } @@ -444,7 +444,7 @@ private static String handleIf(String desc, String start, boolean value) { * @return Generated HTML entry. */ private String generateAnnotated(String descTemp, SyntaxElementInfo info, @Nullable String page, String type) { - Class c = info.c; + Class c = info.getElementClass(); String desc; // Name @@ -472,7 +472,7 @@ private String generateAnnotated(String descTemp, SyntaxElementInfo info, @Nu // Documentation ID DocumentationId docId = c.getAnnotation(DocumentationId.class); - String ID = docId != null ? (docId != null ? docId.value() : null) : info.c.getSimpleName(); + String ID = docId != null ? (docId != null ? docId.value() : null) : c.getSimpleName(); // Fix duplicated IDs if (page != null) { if (page.contains("href=\"#" + ID + "\"")) { @@ -569,7 +569,7 @@ private String generateAnnotated(String descTemp, SyntaxElementInfo info, @Nu } private String generateEvent(String descTemp, SkriptEventInfo info, @Nullable String page) { - Class c = info.c; + Class c = info.getElementClass(); String desc; // Name diff --git a/src/main/java/ch/njol/skript/effects/EffApplyBoneMeal.java b/src/main/java/ch/njol/skript/effects/EffApplyBoneMeal.java index 484654a14f6..2b6c4e6ff63 100644 --- a/src/main/java/ch/njol/skript/effects/EffApplyBoneMeal.java +++ b/src/main/java/ch/njol/skript/effects/EffApplyBoneMeal.java @@ -38,7 +38,7 @@ @Description("Applies bone meal to a crop, sapling, or composter") @Examples("apply 3 bone meal to event-block") @RequiredPlugins("MC 1.16.2+") -@Since("INSERT VERSION") +@Since("2.8.0") public class EffApplyBoneMeal extends Effect { static { @@ -71,7 +71,7 @@ protected void execute(Event event) { @Override public String toString(@Nullable Event event, boolean debug) { - return "apply " + amount != null ? amount.toString(event, debug) + " " : "" + "bone meal to " + blocks.toString(event, debug); + return "apply " + (amount != null ? amount.toString(event, debug) + " " : "" + "bone meal to " + blocks.toString(event, debug)); } } diff --git a/src/main/java/ch/njol/skript/effects/EffCancelItemUse.java b/src/main/java/ch/njol/skript/effects/EffCancelItemUse.java index bda21e00683..20251dbb82b 100644 --- a/src/main/java/ch/njol/skript/effects/EffCancelItemUse.java +++ b/src/main/java/ch/njol/skript/effects/EffCancelItemUse.java @@ -42,7 +42,7 @@ "\tif the victim's active tool is a bow:", "\t\tinterrupt the usage of the player's active item" }) -@Since("INSERT VERSION") +@Since("2.8.0") @RequiredPlugins("Paper 1.16+") public class EffCancelItemUse extends Effect { diff --git a/src/main/java/ch/njol/skript/effects/EffCommand.java b/src/main/java/ch/njol/skript/effects/EffCommand.java index 8dca06d4638..5977dbcc61a 100644 --- a/src/main/java/ch/njol/skript/effects/EffCommand.java +++ b/src/main/java/ch/njol/skript/effects/EffCommand.java @@ -48,7 +48,7 @@ "execute console command \"/say Hello everyone!\"", "execute player bungeecord command \"/alert &6Testing Announcement!\"" }) -@Since("1.0, INSERT VERSION (bungeecord command)") +@Since("1.0, 2.8.0 (bungeecord command)") public class EffCommand extends Effect { public static final String MESSAGE_CHANNEL = "Message"; diff --git a/src/main/java/ch/njol/skript/effects/EffContinue.java b/src/main/java/ch/njol/skript/effects/EffContinue.java index 4b4c4b3682c..e882b202986 100644 --- a/src/main/java/ch/njol/skript/effects/EffContinue.java +++ b/src/main/java/ch/njol/skript/effects/EffContinue.java @@ -55,7 +55,7 @@ "\t\tcontinue # only print when counter is 1, 2, 3, 5 or 10", "\tbroadcast \"Game starting in %{_counter}% second(s)\"", }) -@Since("2.2-dev37, 2.7 (while loops), INSERT VERSION (outer loops)") +@Since("2.2-dev37, 2.7 (while loops), 2.8.0 (outer loops)") public class EffContinue extends Effect { static { diff --git a/src/main/java/ch/njol/skript/effects/EffCopy.java b/src/main/java/ch/njol/skript/effects/EffCopy.java new file mode 100644 index 00000000000..e949f3bd832 --- /dev/null +++ b/src/main/java/ch/njol/skript/effects/EffCopy.java @@ -0,0 +1,166 @@ +/** + * 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.effects; + +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.Keywords; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Effect; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.ExpressionList; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.lang.Variable; +import ch.njol.skript.registrations.Classes; +import ch.njol.skript.variables.Variables; +import ch.njol.util.Kleenean; +import org.bukkit.event.Event; +import org.eclipse.jdt.annotation.Nullable; + +import java.util.*; + +@Name("Copy Into Variable") +@Description({ + "Copies objects into a variable. When copying a list over to another list, the source list and its sublists are also copied over.", + "Note: Copying a value into a variable/list will overwrite the existing data." +}) +@Examples({ + "set {_foo::bar} to 1", + "set {_foo::sublist::foobar} to \"hey\"", + "copy {_foo::*} to {_copy::*}", + "broadcast indices of {_copy::*} # bar, sublist", + "broadcast {_copy::bar} # 1", + "broadcast {_copy::sublist::foobar} # \"hey!\"" +}) +@Since("2.8.0") +@Keywords({"clone", "variable", "list"}) +public class EffCopy extends Effect { + + static { + Skript.registerEffect(EffCopy.class, "copy %~objects% [in]to %~objects%"); + } + + private Expression source; + private Expression rawDestination; + private List> destinations; + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + source = exprs[0]; + rawDestination = exprs[1]; + if (exprs[1] instanceof Variable) { + destinations = Collections.singletonList((Variable) exprs[1]); + } else if (exprs[1] instanceof ExpressionList) { + destinations = unwrapExpressionList((ExpressionList) exprs[1]); + } + if (destinations == null) { + Skript.error("You can only copy objects into variables"); + return false; + } + for (Variable destination : destinations) { + if (!source.isSingle() && destination.isSingle()) { + Skript.error("Cannot copy multiple objects into a single variable"); + return false; + } + } + return true; + } + + @Override + @SuppressWarnings("unchecked") + protected void execute(Event event) { + if (!(source instanceof Variable) || source.isSingle()) { + ChangeMode mode = ChangeMode.SET; + Object[] clone = (Object[]) Classes.clone(source.getArray(event)); + if (clone.length == 0) + mode = ChangeMode.DELETE; + for (Variable dest : destinations) + dest.change(event, clone, mode); + return; + } + + Map source = copyMap((Map) ((Variable) this.source).getRaw(event)); + + // If we're copying {_foo::*} we don't want to also copy {_foo} + if (source != null) + source.remove(null); + + for (Variable destination : destinations) { + destination.change(event, null, ChangeMode.DELETE); + if (source == null) + continue; + + String target = destination.getName().getSingle(event); + target = target.substring(0, target.length() - (Variable.SEPARATOR + "*").length()); + set(event, target, source, destination.isLocal()); + } + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return "copy " + source.toString(event, debug) + " into " + rawDestination.toString(event, debug); + } + + @SuppressWarnings("unchecked") + @Nullable + private static Map copyMap(@Nullable Map map) { + if (map == null) + return null; + Map copy = new HashMap<>(map.size()); + map.forEach((key, value) -> { + if (value instanceof Map) { + copy.put(key, copyMap((Map) value)); + return; + } + copy.put(key, Classes.clone(value)); + }); + return copy; + } + + @SuppressWarnings("unchecked") + private static void set(Event event, String targetName, Map source, boolean local) { + source.forEach((key, value) -> { + String node = targetName + (key == null ? "" : Variable.SEPARATOR + key); + if (value instanceof Map) { + set(event, node, (Map) value, local); + return; + } + Variables.setVariable(node, value, event, local); + }); + } + + private static List> unwrapExpressionList(ExpressionList expressionList) { + Expression[] expressions = expressionList.getExpressions(); + List> destinations = new ArrayList<>(); + for (Expression expression : expressions) { + if (expression instanceof Variable) { + destinations.add((Variable) expression); + continue; + } + if (!(expression instanceof ExpressionList)) + return null; + destinations.addAll(unwrapExpressionList((ExpressionList) expression)); + } + return destinations; + } + +} diff --git a/src/main/java/ch/njol/skript/effects/EffExit.java b/src/main/java/ch/njol/skript/effects/EffExit.java index eecbb7efec1..b5e2be7e04a 100644 --- a/src/main/java/ch/njol/skript/effects/EffExit.java +++ b/src/main/java/ch/njol/skript/effects/EffExit.java @@ -25,6 +25,7 @@ import ch.njol.skript.doc.Since; import ch.njol.skript.lang.Effect; import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SectionExitHandler; import ch.njol.skript.lang.LoopSection; import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.lang.TriggerItem; @@ -122,8 +123,8 @@ protected TriggerItem walk(Event event) { assert false : this; return null; } - if (node instanceof LoopSection) - ((LoopSection) node).exit(event); + if (node instanceof SectionExitHandler) + ((SectionExitHandler) node).exit(event); if (type == EVERYTHING || type == CONDITIONALS && node instanceof SecConditional || type == LOOPS && (node instanceof LoopSection)) i--; diff --git a/src/main/java/ch/njol/skript/effects/EffGlowingText.java b/src/main/java/ch/njol/skript/effects/EffGlowingText.java index 576a2d58348..7f5b3161396 100644 --- a/src/main/java/ch/njol/skript/effects/EffGlowingText.java +++ b/src/main/java/ch/njol/skript/effects/EffGlowingText.java @@ -40,7 +40,7 @@ @Name("Make Sign Glow") @Description("Makes a sign (either a block or item) have glowing text or normal text") @Examples("make target block of player have glowing text") -@Since("INSERT VERSION") +@Since("2.8.0") public class EffGlowingText extends Effect { static { diff --git a/src/main/java/ch/njol/skript/effects/EffHandedness.java b/src/main/java/ch/njol/skript/effects/EffHandedness.java index ddb8a8d0787..89d5469e1a1 100644 --- a/src/main/java/ch/njol/skript/effects/EffHandedness.java +++ b/src/main/java/ch/njol/skript/effects/EffHandedness.java @@ -41,7 +41,7 @@ "", "make all zombies in radius 10 of player right handed" }) -@Since("INSERT VERSION") +@Since("2.8.0") @RequiredPlugins("Paper 1.17.1+") public class EffHandedness extends Effect { diff --git a/src/main/java/ch/njol/skript/effects/EffInvulnerability.java b/src/main/java/ch/njol/skript/effects/EffInvulnerability.java index 0e9d32d415b..33acd611202 100644 --- a/src/main/java/ch/njol/skript/effects/EffInvulnerability.java +++ b/src/main/java/ch/njol/skript/effects/EffInvulnerability.java @@ -40,8 +40,8 @@ public class EffInvulnerability extends Effect { static { Skript.registerEffect(EffInvulnerability.class, - "make %entities% invulnerable", - "make %entities% (not invulnerable|vulnerable)"); + "make %entities% (invulnerable|invincible)", + "make %entities% (not (invulnerable|invincible)|vulnerable|vincible)"); } @SuppressWarnings("null") @@ -57,15 +57,15 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye } @Override - protected void execute(Event e) { - for (Entity entity : entities.getArray(e)) { + protected void execute(Event event) { + for (Entity entity : entities.getArray(event)) { entity.setInvulnerable(invulnerable); } } @Override - public String toString(@Nullable Event e, boolean debug) { - return "make " + entities.toString(e, debug) + (invulnerable ? " invulnerable" : " not invulnerable"); + public String toString(@Nullable Event event, boolean debug) { + return "make " + entities.toString(event, debug) + (invulnerable ? " invulnerable" : " not invulnerable"); } } diff --git a/src/main/java/ch/njol/skript/effects/EffReturn.java b/src/main/java/ch/njol/skript/effects/EffReturn.java index 13b563fefee..d0b4d220514 100644 --- a/src/main/java/ch/njol/skript/effects/EffReturn.java +++ b/src/main/java/ch/njol/skript/effects/EffReturn.java @@ -26,7 +26,7 @@ import ch.njol.skript.doc.Since; import ch.njol.skript.lang.Effect; import ch.njol.skript.lang.Expression; -import ch.njol.skript.lang.LoopSection; +import ch.njol.skript.lang.SectionExitHandler; import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.lang.TriggerItem; import ch.njol.skript.lang.TriggerSection; @@ -48,7 +48,7 @@ "function divide(i: number) returns number:", "\treturn {_i} / 2" }) -@Since("2.2, INSERT VERSION (returns aliases)") +@Since("2.2, 2.8.0 (returns aliases)") public class EffReturn extends Effect { static { @@ -117,8 +117,8 @@ protected TriggerItem walk(Event event) { TriggerSection parent = getParent(); while (parent != null) { - if (parent instanceof LoopSection) - ((LoopSection) parent).exit(event); + if (parent instanceof SectionExitHandler) + ((SectionExitHandler) parent).exit(event); parent = parent.getParent(); } diff --git a/src/main/java/ch/njol/skript/effects/EffShear.java b/src/main/java/ch/njol/skript/effects/EffShear.java index 5bb6bf3d991..5cc8f5004c9 100644 --- a/src/main/java/ch/njol/skript/effects/EffShear.java +++ b/src/main/java/ch/njol/skript/effects/EffShear.java @@ -50,7 +50,7 @@ "\tchance of 10%", "\tforce shear the clicked sheep" }) -@Since("2.0 (cows, sheep & snowmen), INSERT VERSION (all shearable entities)") +@Since("2.0 (cows, sheep & snowmen), 2.8.0 (all shearable entities)") @RequiredPlugins("Paper 1.19.4+ (all shearable entities)") public class EffShear extends Effect { diff --git a/src/main/java/ch/njol/skript/effects/EffSwingHand.java b/src/main/java/ch/njol/skript/effects/EffSwingHand.java index a129254de9f..826cce82978 100644 --- a/src/main/java/ch/njol/skript/effects/EffSwingHand.java +++ b/src/main/java/ch/njol/skript/effects/EffSwingHand.java @@ -46,7 +46,7 @@ public class EffSwingHand extends Effect { "make %livingentities% swing [their] off[ ]hand"); } - private static final boolean SWINGING_IS_SUPPORTED = Skript.methodExists(LivingEntity.class, "swingMainHand"); + public static final boolean SWINGING_IS_SUPPORTED = Skript.methodExists(LivingEntity.class, "swingMainHand"); @SuppressWarnings("null") private Expression entities; diff --git a/src/main/java/ch/njol/skript/effects/EffToggleCanPickUpItems.java b/src/main/java/ch/njol/skript/effects/EffToggleCanPickUpItems.java index 6c3b3926988..9629c0f5b78 100644 --- a/src/main/java/ch/njol/skript/effects/EffToggleCanPickUpItems.java +++ b/src/main/java/ch/njol/skript/effects/EffToggleCanPickUpItems.java @@ -41,7 +41,7 @@ "\tif player can't pick up items:", "\t\tallow player to pick up items" }) -@Since("INSERT VERSION") +@Since("2.8.0") public class EffToggleCanPickUpItems extends Effect { static { diff --git a/src/main/java/ch/njol/skript/effects/EffWorldLoad.java b/src/main/java/ch/njol/skript/effects/EffWorldLoad.java new file mode 100644 index 00000000000..697c417d58e --- /dev/null +++ b/src/main/java/ch/njol/skript/effects/EffWorldLoad.java @@ -0,0 +1,100 @@ +/** + * 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.effects; + +import ch.njol.skript.Skript; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Effect; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.util.Kleenean; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.World.Environment; +import org.bukkit.WorldCreator; +import org.bukkit.event.Event; +import org.eclipse.jdt.annotation.Nullable; + +@Name("Load World") +@Description({ + "Load your worlds or unload your worlds", + "The load effect will create a new world if world doesn't already exist.", + "When attempting to load a normal vanilla world you must define it's environment i.e \"world_nether\" must be loaded with nether environment" +}) +@Examples({ + "load world \"world_nether\" with environment nether", + "load the world \"myCustomWorld\"", + "unload \"world_nether\"", + "unload \"world_the_end\" without saving", + "unload all worlds" +}) +@Since("2.8.0") +public class EffWorldLoad extends Effect { + + static { + Skript.registerEffect(EffWorldLoad.class, + "load [[the] world[s]] %strings% [with environment %-environment%]", + "unload [[the] world[s]] %worlds% [:without saving]" + ); + } + + private boolean save, load; + private Expression worlds; + @Nullable + private Expression environment; + + @Override + @SuppressWarnings("unchecked") + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + worlds = exprs[0]; + load = matchedPattern == 0; + if (load) { + environment = (Expression) exprs[1]; + } else { + save = !parseResult.hasTag("without saving"); + } + return true; + } + + @Override + protected void execute(Event event) { + Environment environment = this.environment != null ? this.environment.getSingle(event) : null; + for (Object world : worlds.getArray(event)) { + if (load && world instanceof String) { + WorldCreator worldCreator = new WorldCreator((String) world); + if (environment != null) + worldCreator.environment(environment); + worldCreator.createWorld(); + } else if (!load && world instanceof World) { + Bukkit.unloadWorld((World) world, save); + } + } + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + if (load) + return "load the world(s) " + worlds.toString(event, debug) + (environment == null ? "" : " with environment " + environment.toString(event, debug)); + return "unload the world(s) " + worlds.toString(event, debug) + " " + (save ? "with saving" : "without saving"); + } + +} diff --git a/src/main/java/ch/njol/skript/effects/EffWorldSave.java b/src/main/java/ch/njol/skript/effects/EffWorldSave.java new file mode 100644 index 00000000000..8cd30672f55 --- /dev/null +++ b/src/main/java/ch/njol/skript/effects/EffWorldSave.java @@ -0,0 +1,70 @@ +/** + * 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.effects; + +import ch.njol.skript.Skript; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Effect; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.util.Kleenean; +import org.bukkit.World; +import org.bukkit.event.Event; +import org.eclipse.jdt.annotation.Nullable; + +@Name("Save World") +@Description({ + "Save all worlds or a given world manually.", + "Note: saving many worlds at once may possibly cause the server to freeze." +}) +@Examples({ + "save \"world_nether\"", + "save all worlds" +}) +@Since("2.8.0") +public class EffWorldSave extends Effect { + + static { + Skript.registerEffect(EffWorldSave.class, "save [[the] world[s]] %worlds%"); + } + + private Expression worlds; + + @Override + @SuppressWarnings("unchecked") + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + worlds = (Expression) exprs[0]; + return true; + } + + @Override + protected void execute(Event event) { + for (World world : worlds.getArray(event)) + world.save(); + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return "save the world(s) " + worlds.toString(event, debug); + } + +} diff --git a/src/main/java/ch/njol/skript/entity/EntityData.java b/src/main/java/ch/njol/skript/entity/EntityData.java index ae02901b769..435415b8c91 100644 --- a/src/main/java/ch/njol/skript/entity/EntityData.java +++ b/src/main/java/ch/njol/skript/entity/EntityData.java @@ -134,7 +134,7 @@ protected EntityData deserialize(final Fields fields) throws StreamCorruptedExce if (info == null) throw new StreamCorruptedException("Invalid EntityData code name " + codeName); try { - final EntityData d = info.c.newInstance(); + final EntityData d = info.getElementClass().newInstance(); d.deserialize(fields); return d; } catch (final InstantiationException e) { @@ -159,9 +159,9 @@ public EntityData deserialize(final String s) { return null; EntityData d; try { - d = i.c.newInstance(); + d = i.getElementClass().newInstance(); } catch (final Exception e) { - Skript.exception(e, "Can't create an instance of " + i.c.getCanonicalName()); + Skript.exception(e, "Can't create an instance of " + i.getElementClass().getCanonicalName()); return null; } if (!d.deserialize(split[1])) @@ -298,7 +298,7 @@ public static > void register(final Cl public EntityData() { for (final EntityDataInfo i : infos) { - if (getClass() == i.c) { + if (getClass() == i.getElementClass()) { info = i; matchedPattern = i.defaultName; return; @@ -409,7 +409,7 @@ public final boolean equals(final @Nullable Object obj) { public static EntityDataInfo getInfo(final Class> c) { for (final EntityDataInfo i : infos) { - if (i.c == c) + if (i.getElementClass() == c) return i; } throw new SkriptAPIException("Unregistered EntityData class " + c.getName()); @@ -581,7 +581,7 @@ private static EntityData getData(final @Nullable if (info.entityClass != Entity.class && (e == null ? info.entityClass.isAssignableFrom(c) : info.entityClass.isInstance(e))) { try { @SuppressWarnings("unchecked") - final EntityData d = (EntityData) info.c.newInstance(); + final EntityData d = (EntityData) info.getElementClass().newInstance(); if (d.init(c, e)) return d; } catch (final Exception ex) { diff --git a/src/main/java/ch/njol/skript/entity/SimpleEntityData.java b/src/main/java/ch/njol/skript/entity/SimpleEntityData.java index 693f7b5773e..b63388d87db 100644 --- a/src/main/java/ch/njol/skript/entity/SimpleEntityData.java +++ b/src/main/java/ch/njol/skript/entity/SimpleEntityData.java @@ -32,6 +32,7 @@ import org.bukkit.entity.Bat; import org.bukkit.entity.Blaze; import org.bukkit.entity.BlockDisplay; +import org.bukkit.entity.Breeze; import org.bukkit.entity.Camel; import org.bukkit.entity.CaveSpider; import org.bukkit.entity.ChestedHorse; @@ -130,6 +131,7 @@ import org.bukkit.entity.WanderingTrader; import org.bukkit.entity.Warden; import org.bukkit.entity.WaterMob; +import org.bukkit.entity.WindCharge; import org.bukkit.entity.Witch; import org.bukkit.entity.Wither; import org.bukkit.entity.WitherSkeleton; @@ -310,6 +312,11 @@ private static void addSuperEntity(String codeName, Class enti addSuperEntity("display", Display.class); } + if (Skript.isRunningMinecraft(1, 20, 3)) { + addSimpleEntity("breeze", Breeze.class); + addSimpleEntity("wind charge", WindCharge.class); + } + // Register zombie after Husk and Drowned to make sure both work addSimpleEntity("zombie", Zombie.class); // Register squid after glow squid to make sure both work diff --git a/src/main/java/ch/njol/skript/events/EvtAtTime.java b/src/main/java/ch/njol/skript/events/EvtAtTime.java index 17d37f00c5c..f003b26195c 100644 --- a/src/main/java/ch/njol/skript/events/EvtAtTime.java +++ b/src/main/java/ch/njol/skript/events/EvtAtTime.java @@ -32,12 +32,10 @@ import org.bukkit.event.Event; import org.eclipse.jdt.annotation.Nullable; -import java.util.ArrayList; -import java.util.Collections; import java.util.Iterator; -import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.PriorityQueue; import java.util.concurrent.ConcurrentHashMap; public class EvtAtTime extends SkriptEvent implements Comparable { @@ -54,12 +52,19 @@ public class EvtAtTime extends SkriptEvent implements Comparable { private static final Map TRIGGERS = new ConcurrentHashMap<>(); private static final class EvtAtInfo { - private int lastTick; // as Bukkit's scheduler is inconsistent this saves the exact tick when the events were last checked - private int currentIndex; - private final List instances = new ArrayList<>(); + /** + * Stores the last world time that this object's instances were checked. + */ + private int lastCheckedTime; + + /** + * A list of all {@link EvtAtTime}s in the world this info object is responsible for. + * Sorted by the time they're listening for in increasing order. + */ + private final PriorityQueue instances = new PriorityQueue<>(EvtAtTime::compareTo); } - private int tick; + private int time; @SuppressWarnings("NotNullFieldNotInitialized") private World[] worlds; @@ -67,7 +72,7 @@ private static final class EvtAtInfo { @Override @SuppressWarnings("unchecked") public boolean init(Literal[] args, int matchedPattern, ParseResult parseResult) { - tick = ((Literal