From 2c814b1d9c3f512f5a498476d7fef168cd543f1a Mon Sep 17 00:00:00 2001 From: Moderocky Date: Sun, 30 Jun 2024 20:06:30 +0100 Subject: [PATCH 01/27] Raise the minimum Java version to 11. (#6557) --- .../{java-8-builds.yml => java-11-builds.yml} | 4 ++-- ...{junit-8-builds.yml => junit-11-builds.yml} | 2 +- README.md | 12 ++++++------ build.gradle | 18 +++++++++--------- code-conventions.md | 2 +- .../{java8 => java11}/paper-1.13.2.json | 0 .../{java8 => java11}/paper-1.14.4.json | 0 .../{java8 => java11}/paper-1.15.2.json | 0 .../{java8 => java11}/paper-1.16.5.json | 0 9 files changed, 19 insertions(+), 19 deletions(-) rename .github/workflows/{java-8-builds.yml => java-11-builds.yml} (92%) rename .github/workflows/{junit-8-builds.yml => junit-11-builds.yml} (94%) rename src/test/skript/environments/{java8 => java11}/paper-1.13.2.json (100%) rename src/test/skript/environments/{java8 => java11}/paper-1.14.4.json (100%) rename src/test/skript/environments/{java8 => java11}/paper-1.15.2.json (100%) rename src/test/skript/environments/{java8 => java11}/paper-1.16.5.json (100%) diff --git a/.github/workflows/java-8-builds.yml b/.github/workflows/java-11-builds.yml similarity index 92% rename from .github/workflows/java-8-builds.yml rename to .github/workflows/java-11-builds.yml index 0120b950f94..443aa925d0c 100644 --- a/.github/workflows/java-8-builds.yml +++ b/.github/workflows/java-11-builds.yml @@ -1,4 +1,4 @@ -name: Java 8 CI (MC 1.13-1.16) +name: Java 11 CI (MC 1.13-1.16) on: push: @@ -26,7 +26,7 @@ jobs: - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Build Skript and run test scripts - run: ./gradlew clean skriptTestJava8 + run: ./gradlew clean skriptTestJava11 - name: Upload Nightly Build uses: actions/upload-artifact@v4 if: success() diff --git a/.github/workflows/junit-8-builds.yml b/.github/workflows/junit-11-builds.yml similarity index 94% rename from .github/workflows/junit-8-builds.yml rename to .github/workflows/junit-11-builds.yml index ec2fef19869..cdf75e4c43a 100644 --- a/.github/workflows/junit-8-builds.yml +++ b/.github/workflows/junit-11-builds.yml @@ -26,4 +26,4 @@ jobs: - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Build Skript and run JUnit - run: ./gradlew clean JUnitJava8 + run: ./gradlew clean JUnitJava11 diff --git a/README.md b/README.md index 2dba8104819..b4ab6c4e48f 100644 --- a/README.md +++ b/README.md @@ -16,11 +16,11 @@ Skript requires **Spigot** to work. You heard it right, **CraftBukkit** does *no **Paper**, which is a fork of Spigot, is recommended; it is required for some parts of Skript to be available. -Skript supports only the **latest** patch versions of Minecraft 1.9+. +Skript supports only the **latest** patch versions of Minecraft 1.13+. For example, this means that 1.16.5 is supported, but 1.16.4 is *not*. Testing with all old patch versions is not feasible for us. -Minecraft 1.8 and earlier are not, and will not be supported. New Minecraft +Minecraft 1.12 and earlier are not, and will not be supported. New Minecraft versions will be supported as soon as possible. ## Download @@ -77,15 +77,15 @@ Skript has some tests written in Skript. Running them requires a Minecraft server, but our build script will create one for you. Running the tests is easy: ``` -./gradlew (quickTest|skriptTest|skriptTestJava8|skriptTestJava17|skriptTestJava21) +./gradlew (quickTest|skriptTest|skriptTestJava11|skriptTestJava17|skriptTestJava21) ``` quickTest runs the test suite on newest supported server version. skriptTestJava21 (1.20.6+) runs the tests on Java 21 supported versions. skriptTestJava17 (1.17-1.20.4) runs the tests on Java 17 supported versions. -skriptTestJava8 (1.13-1.16) runs the tests on Java 8 supported versions. +skriptTestJava11 (1.13-1.16) runs the tests on Java 11 supported versions. skriptTest runs the tests on all versions. -That is, it runs skriptTestJava8, skriptTestJava17, and skriptTestJava21. +That is, it runs skriptTestJava11, skriptTestJava17, and skriptTestJava21. By running the tests, you agree to Mojang's End User License Agreement. @@ -164,7 +164,7 @@ dependencies { } ``` -An example of the version tag would be ```dev37c```. +An example of the version tag would be ```2.8.5```. > Note: If Gradle isn't able to resolve Skript's dependencies, just [disable the resolution of transitive dependencies](https://docs.gradle.org/current/userguide/resolution_rules.html#sec:disabling_resolution_transitive_dependencies) for Skript in your project. diff --git a/build.gradle b/build.gradle index 161d3dd3daf..d6a60fa9e37 100644 --- a/build.gradle +++ b/build.gradle @@ -70,7 +70,7 @@ task build(overwrite: true, type: ShadowJar) { from sourceSets.main.output } -// Excludes the tests for the build task. Should be using junit, junitJava17, junitJava8, skriptTest, quickTest. +// Excludes the tests for the build task. Should be using junit, junitJava17, junitJava11, skriptTest, quickTest. // We do not want tests to run for building. That's time consuming and annoying. Especially in development. test { exclude '**/*' @@ -224,7 +224,7 @@ void createTestTask(String name, String desc, String environments, int javaVersi if (!gradle.taskGraph.hasTask(":tasks") && !gradle.startParameter.dryRun && modifiers.contains(Modifiers.PROFILE)) { if (!project.hasProperty('profiler')) throw new MissingPropertyException('Add parameter -Pprofiler=', 'profiler', String.class) - + args += '-agentpath:' + project.property('profiler') + '=port=8849,nowait' } } @@ -233,11 +233,11 @@ void createTestTask(String name, String desc, String environments, int javaVersi def java21 = 21 def java17 = 17 -def java8 = 8 +def java11 = 11 def latestEnv = 'java21/paper-1.20.6.json' def latestJava = java21 -def oldestJava = java8 +def oldestJava = java11 def latestJUnitEnv = 'java17/paper-1.20.4.json' def latestJUnitJava = java17 @@ -260,14 +260,14 @@ int envJava = project.property('testEnvJavaVersion') == null ? latestJava : Inte createTestTask('quickTest', 'Runs tests on one environment being the latest supported Java and Minecraft.', environments + latestEnv, latestJava, 0) createTestTask('skriptTestJava21', 'Runs tests on all Java 21 environments.', environments + 'java21', java21, 0) createTestTask('skriptTestJava17', 'Runs tests on all Java 17 environments.', environments + 'java17', java17, 0) -createTestTask('skriptTestJava8', 'Runs tests on all Java 8 environments.', environments + 'java8', java8, 0) +createTestTask('skriptTestJava11', 'Runs tests on all Java 11 environments.', environments + 'java11', java11, 0) createTestTask('skriptTestDev', 'Runs testing server and uses \'system.in\' for command input, stop server to finish.', environments + env, envJava, 0, Modifiers.DEV_MODE, Modifiers.DEBUG) createTestTask('skriptProfile', 'Starts the testing server with JProfiler support.', environments + latestEnv, latestJava, -1, Modifiers.PROFILE) createTestTask('genNightlyDocs', 'Generates the Skript documentation website html files.', environments + env, envJava, 0, Modifiers.GEN_NIGHTLY_DOCS) createTestTask('genReleaseDocs', 'Generates the Skript documentation website html files for a release.', environments + env, envJava, 0, Modifiers.GEN_RELEASE_DOCS) tasks.register('skriptTest') { description = 'Runs tests on all environments.' - dependsOn skriptTestJava8, skriptTestJava17, skriptTestJava21 + dependsOn skriptTestJava11, skriptTestJava17, skriptTestJava21 } createTestTask('JUnitQuick', 'Runs JUnit tests on one environment being the latest supported Java and Minecraft.', environments + latestJUnitEnv, latestJUnitJava, 0, Modifiers.JUNIT) @@ -275,10 +275,10 @@ createTestTask('JUnitQuick', 'Runs JUnit tests on one environment being the late // However, we are currently using 5.0.1 (see https://github.com/SkriptLang/Skript/pull/6204#discussion_r1405302009) //createTestTask('JUnitJava21', 'Runs JUnit tests on all Java 21 environments.', environments + 'java21', java21, 0, Modifiers.JUNIT) createTestTask('JUnitJava17', 'Runs JUnit tests on all Java 17 environments.', environments + 'java17', java17, 0, Modifiers.JUNIT) -createTestTask('JUnitJava8', 'Runs JUnit tests on all Java 8 environments.', environments + 'java8', java8, 0, Modifiers.JUNIT) +createTestTask('JUnitJava11', 'Runs JUnit tests on all Java 11 environments.', environments + 'java11', java11, 0, Modifiers.JUNIT) tasks.register('JUnit') { description = 'Runs JUnit tests on all environments.' - dependsOn JUnitJava8, JUnitJava17//, JUnitJava21 + dependsOn JUnitJava11, JUnitJava17//, JUnitJava21 } // Build flavor configurations @@ -394,7 +394,7 @@ javadoc { exclude("ch/njol/skript/lang/function/ExprFunctionCall.java") exclude("ch/njol/skript/hooks/**") exclude("ch/njol/skript/test/**") - + classpath = configurations.compileClasspath + sourceSets.main.output options.encoding = 'UTF-8' // currently our javadoc has a lot of errors, so we need to suppress the linter diff --git a/code-conventions.md b/code-conventions.md index 25c6d5c4417..3bcf17c6c9f 100644 --- a/code-conventions.md +++ b/code-conventions.md @@ -194,7 +194,7 @@ Your comments should look something like these: ## Language Features ### Compatibility -[//]: # (To be updated after feature/2.9 for Java 17) +[//]: # (To be updated for 2.10 for Java 17) * Contributions should maintain Java 11 source/binary compatibility, even though compiling Skript requires Java 21 - Users must not need JRE newer than version 11 * Versions up to and including Java 21 should work too diff --git a/src/test/skript/environments/java8/paper-1.13.2.json b/src/test/skript/environments/java11/paper-1.13.2.json similarity index 100% rename from src/test/skript/environments/java8/paper-1.13.2.json rename to src/test/skript/environments/java11/paper-1.13.2.json diff --git a/src/test/skript/environments/java8/paper-1.14.4.json b/src/test/skript/environments/java11/paper-1.14.4.json similarity index 100% rename from src/test/skript/environments/java8/paper-1.14.4.json rename to src/test/skript/environments/java11/paper-1.14.4.json diff --git a/src/test/skript/environments/java8/paper-1.15.2.json b/src/test/skript/environments/java11/paper-1.15.2.json similarity index 100% rename from src/test/skript/environments/java8/paper-1.15.2.json rename to src/test/skript/environments/java11/paper-1.15.2.json diff --git a/src/test/skript/environments/java8/paper-1.16.5.json b/src/test/skript/environments/java11/paper-1.16.5.json similarity index 100% rename from src/test/skript/environments/java8/paper-1.16.5.json rename to src/test/skript/environments/java11/paper-1.16.5.json From 40307576f94ed405adbcb8d59637004bedd3d562 Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Mon, 1 Jul 2024 14:41:36 +0200 Subject: [PATCH 02/27] fix exception when removing air from slot (#6836) * fix exception when removing air from slot * Update 6830-remove air from slot.sk --- .../ch/njol/skript/bukkitutil/ItemUtils.java | 35 +++++++++++++------ .../regressions/6830-remove air from slot.sk | 4 +++ 2 files changed, 29 insertions(+), 10 deletions(-) create mode 100644 src/test/skript/tests/regressions/6830-remove air from slot.sk diff --git a/src/main/java/ch/njol/skript/bukkitutil/ItemUtils.java b/src/main/java/ch/njol/skript/bukkitutil/ItemUtils.java index 31bf99c2d56..216be44b918 100644 --- a/src/main/java/ch/njol/skript/bukkitutil/ItemUtils.java +++ b/src/main/java/ch/njol/skript/bukkitutil/ItemUtils.java @@ -42,9 +42,17 @@ public class ItemUtils { * @return Damage. */ public static int getDamage(ItemStack itemStack) { - ItemMeta meta = itemStack.getItemMeta(); - if (meta instanceof Damageable) - return ((Damageable) meta).getDamage(); + return getDamage(itemStack.getItemMeta()); + } + + /** + * Gets damage/durability of an itemmeta, or 0 if it does not have damage. + * @param itemMeta ItemMeta. + * @return Damage. + */ + public static int getDamage(ItemMeta itemMeta) { + if (itemMeta instanceof Damageable) + return ((Damageable) itemMeta).getDamage(); return 0; // Non damageable item } @@ -143,15 +151,22 @@ public static Material asItem(Material type) { /** * Tests whether two item stacks are of the same type, i.e. it ignores the amounts. * - * @param is1 - * @param is2 + * @param itemStack1 + * @param itemStack2 * @return Whether the item stacks are of the same type */ - public static boolean itemStacksEqual(final @Nullable ItemStack is1, final @Nullable ItemStack is2) { - if (is1 == null || is2 == null) - return is1 == is2; - return is1.getType() == is2.getType() && ItemUtils.getDamage(is1) == ItemUtils.getDamage(is2) - && is1.getItemMeta().equals(is2.getItemMeta()); + public static boolean itemStacksEqual(@Nullable ItemStack itemStack1, @Nullable ItemStack itemStack2) { + if (itemStack1 == null || itemStack2 == null) + return itemStack1 == itemStack2; + if (itemStack1.getType() != itemStack2.getType()) + return false; + + ItemMeta itemMeta1 = itemStack1.getItemMeta(); + ItemMeta itemMeta2 = itemStack2.getItemMeta(); + if (itemMeta1 == null || itemMeta2 == null) + return itemMeta1 == itemMeta2; + + return itemStack1.getItemMeta().equals(itemStack2.getItemMeta()); } // Only 1.15 and versions after have Material#isAir method diff --git a/src/test/skript/tests/regressions/6830-remove air from slot.sk b/src/test/skript/tests/regressions/6830-remove air from slot.sk new file mode 100644 index 00000000000..13eaa29b1d3 --- /dev/null +++ b/src/test/skript/tests/regressions/6830-remove air from slot.sk @@ -0,0 +1,4 @@ +test "remove air from air slot": + set {_chest} to chest inventory with 3 rows + # throws exception if not fixed + remove 1 of (slot 0 of {_chest}) from (slot 0 of {_chest}) From a4f38d2c1da49bc5416d38979ea9f791dcf92292 Mon Sep 17 00:00:00 2001 From: Shane Bee Date: Mon, 1 Jul 2024 05:42:44 -0700 Subject: [PATCH 03/27] EffBan - add option to kick (#6835) * EffBan - add option to kick - also did a lil cleanup * EffBan - toString change as per suggestion --- .../java/ch/njol/skript/effects/EffBan.java | 39 ++++++++++++------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/src/main/java/ch/njol/skript/effects/EffBan.java b/src/main/java/ch/njol/skript/effects/EffBan.java index 1e674e23ded..3826fd7f372 100644 --- a/src/main/java/ch/njol/skript/effects/EffBan.java +++ b/src/main/java/ch/njol/skript/effects/EffBan.java @@ -26,7 +26,6 @@ import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; import org.bukkit.event.Event; -import org.eclipse.jdt.annotation.Nullable; import ch.njol.skript.Skript; import ch.njol.skript.doc.Description; @@ -38,6 +37,7 @@ import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.util.Timespan; import ch.njol.util.Kleenean; +import org.jetbrains.annotations.Nullable; @Name("Ban") @Description({"Bans or unbans a player or an IP address.", @@ -46,19 +46,23 @@ "We recommend that you test your scripts so that no accidental permanent bans are applied.", "", "Note that banning people does not kick them from the server.", - "Consider using the kick effect after applying a ban."}) + "You can optionally use 'and kick' or consider using the kick effect after applying a ban."}) @Examples({"unban player", "ban \"127.0.0.1\"", "IP-ban the player because \"he is an idiot\"", - "ban player due to \"inappropriate language\" for 2 days"}) -@Since("1.4, 2.1.1 (ban reason), 2.5 (timespan)") + "ban player due to \"inappropriate language\" for 2 days", + "ban and kick player due to \"inappropriate language\" for 2 days"}) +@Since("1.4, 2.1.1 (ban reason), 2.5 (timespan), INSERT VERSION (kick)") public class EffBan extends Effect { static { Skript.registerEffect(EffBan.class, - "ban %strings/offlineplayers% [(by reason of|because [of]|on account of|due to) %-string%] [for %-timespan%]", "unban %strings/offlineplayers%", - "ban %players% by IP [(by reason of|because [of]|on account of|due to) %-string%] [for %-timespan%]", "unban %players% by IP", - "IP(-| )ban %players% [(by reason of|because [of]|on account of|due to) %-string%] [for %-timespan%]", "(IP(-| )unban|un[-]IP[-]ban) %players%"); + "ban [kick:and kick] %strings/offlineplayers% [(by reason of|because [of]|on account of|due to) %-string%] [for %-timespan%]", + "unban %strings/offlineplayers%", + "ban [kick:and kick] %players% by IP [(by reason of|because [of]|on account of|due to) %-string%] [for %-timespan%]", + "unban %players% by IP", + "IP(-| )ban [kick:and kick] %players% [(by reason of|because [of]|on account of|due to) %-string%] [for %-timespan%]", + "(IP(-| )unban|un[-]IP[-]ban) %players%"); } @SuppressWarnings("null") @@ -70,6 +74,7 @@ public class EffBan extends Effect { private boolean ban; private boolean ipBan; + private boolean kick; @SuppressWarnings({"null", "unchecked"}) @Override @@ -79,6 +84,7 @@ public boolean init(final Expression[] exprs, final int matchedPattern, final expires = exprs.length > 1 ? (Expression) exprs[2] : null; ban = matchedPattern % 2 == 0; ipBan = matchedPattern >= 2; + kick = parseResult.hasTag("kick"); return true; } @@ -91,8 +97,9 @@ protected void execute(final Event e) { final String source = "Skript ban effect"; for (final Object o : players.getArray(e)) { if (o instanceof Player) { + Player player = (Player) o; if (ipBan) { - InetSocketAddress addr = ((Player) o).getAddress(); + InetSocketAddress addr = player.getAddress(); if (addr == null) return; // Can't ban unknown IP final String ip = addr.getAddress().getHostAddress(); @@ -102,10 +109,12 @@ protected void execute(final Event e) { Bukkit.getBanList(BanList.Type.IP).pardon(ip); } else { if (ban) - Bukkit.getBanList(BanList.Type.NAME).addBan(((Player) o).getName(), reason, expires, source); // FIXME [UUID] ban UUID + Bukkit.getBanList(BanList.Type.NAME).addBan(player.getName(), reason, expires, source); // FIXME [UUID] ban UUID else - Bukkit.getBanList(BanList.Type.NAME).pardon(((Player) o).getName()); + Bukkit.getBanList(BanList.Type.NAME).pardon(player.getName()); } + if (kick) + player.kickPlayer(reason); } else if (o instanceof OfflinePlayer) { String name = ((OfflinePlayer) o).getName(); if (name == null) @@ -130,9 +139,13 @@ protected void execute(final Event e) { } @Override - public String toString(final @Nullable Event e, final boolean debug) { - return (ipBan ? "IP-" : "") + (ban ? "" : "un") + "ban " + players.toString(e, debug) + - (reason != null ? " on account of " + reason.toString(e, debug) : "") + (expires != null ? " for " + expires.toString(e, debug) : ""); + public String toString(final @Nullable Event event, final boolean debug) { + return (ipBan ? "IP-" : "") + + (this.ban ? "ban " : "unban ") + + (kick ? "and kick " : "") + + this.players.toString(event, debug) + + (this.reason != null ? " on account of " + this.reason.toString(event, debug) : "") + + (expires != null ? " for " + expires.toString(event, debug) : ""); } } From 13b230c90cbfa919e69caa33ff537e613b1f18a4 Mon Sep 17 00:00:00 2001 From: Shane Bee Date: Mon, 1 Jul 2024 05:47:03 -0700 Subject: [PATCH 04/27] BlockData - add cloner (#6829) * BukkitClasses - add cloner for BlockData * Add regression test for #6829 * Fix error message in BlockDataNotCloned6829 --------- Co-authored-by: Pikachu920 <28607612+Pikachu920@users.noreply.github.com> Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com> --- .../skript/classes/data/BukkitClasses.java | 2 +- .../regression/BlockDataNotCloned6829.java | 53 +++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 src/test/java/org/skriptlang/skript/test/tests/regression/BlockDataNotCloned6829.java diff --git a/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java b/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java index ba1a419aad0..69710a1ad00 100644 --- a/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java +++ b/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java @@ -355,7 +355,7 @@ public boolean mustSyncDeserialization() { protected boolean canBeInstantiated() { return false; } - })); + }).cloner(BlockData::clone)); Classes.registerClass(new ClassInfo<>(Location.class, "location") .user("locations?") diff --git a/src/test/java/org/skriptlang/skript/test/tests/regression/BlockDataNotCloned6829.java b/src/test/java/org/skriptlang/skript/test/tests/regression/BlockDataNotCloned6829.java new file mode 100644 index 00000000000..b621734958d --- /dev/null +++ b/src/test/java/org/skriptlang/skript/test/tests/regression/BlockDataNotCloned6829.java @@ -0,0 +1,53 @@ +/** + * 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 org.skriptlang.skript.test.tests.regression; + +import ch.njol.skript.lang.Effect; +import ch.njol.skript.lang.TriggerItem; +import ch.njol.skript.lang.util.ContextlessEvent; +import ch.njol.skript.test.runner.SkriptJUnitTest; +import ch.njol.skript.variables.Variables; +import org.bukkit.block.data.type.Tripwire; +import org.bukkit.event.Event; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Objects; + +public class BlockDataNotCloned6829 extends SkriptJUnitTest { + + public void run(String unparsedEffect, Event event) { + Effect effect = Effect.parse(unparsedEffect, "Can't understand this effect: " + unparsedEffect); + if (effect == null) + throw new IllegalStateException(); + TriggerItem.walk(effect, event); + } + + @Test + public void test() { + Event event = ContextlessEvent.get(); + run("set {_original tripwire} to tripwire[]", event); + run("set {_another tripwire} to {_original tripwire}", event); + Tripwire originalTripwire = (Tripwire) Objects.requireNonNull(Variables.getVariable("original tripwire", event, true)); + Tripwire anotherTripwire = (Tripwire) Objects.requireNonNull(Variables.getVariable("another tripwire", event, true)); + anotherTripwire.setDisarmed(true); + Assert.assertFalse(originalTripwire.isDisarmed()); + } + +} From 1e23d7f670c8d4d6f52111ccd0aea9d80d0cde81 Mon Sep 17 00:00:00 2001 From: Shane Bee Date: Mon, 1 Jul 2024 05:49:22 -0700 Subject: [PATCH 05/27] default.lang - add MC 1.21 attributes (#6791) Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com> --- src/main/resources/lang/default.lang | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/resources/lang/default.lang b/src/main/resources/lang/default.lang index 90a37eb9e32..af2d90e64b0 100644 --- a/src/main/resources/lang/default.lang +++ b/src/main/resources/lang/default.lang @@ -2168,6 +2168,8 @@ attribute types: generic_attack_damage: generic attack damage, attack damage generic_attack_knockback: generic attack knockback, attack knockback generic_attack_speed: generic attack speed, attack speed + generic_burning_time: generic burning time, burning time + generic_explosion_knockback_resistance: generic explosion knockback resistance, explosion knockback resistance generic_flying_speed: generic flying speed, flying speed generic_follow_range: generic follow range, follow range generic_gravity: generic gravity, gravity @@ -2176,15 +2178,22 @@ attribute types: generic_luck: generic luck, luck generic_max_absorption: generic max absorption, max absorption generic_max_health: generic max health, max health + generic_movement_efficiency: generic movement efficiency, movement efficiency generic_movement_speed: generic movement speed, movement speed + generic_oxygen_bonus: generic oxygen bonus, oxygen bonus generic_safe_fall_distance: generic safe fall distance, safe fall distance generic_fall_damage_multiplier: generic fall damage multiplier, fall damage multiplier generic_scale: generic scale, scale generic_step_height: generic step height, step height + generic_water_movement_efficiency: generic water movement efficiency, water movement efficiency horse_jump_strength: horse jump strength player_block_break_speed: player block break speed, block break speed player_block_interaction_range: player block interaction range, block interaction range player_entity_interaction_range: player entity interaction range, entity interaction range + player_mining_efficiency: player mining efficiency, mining efficiency + player_sneaking_speed: player sneaking speed, sneaking speed + player_submerged_mining_speed: player submerged mining speed, submerged mining speed + player_sweeping_damage_ratio: player sweeping damage ratio, sweeping damage ratio zombie_spawn_reinforcements: zombie spawn reinforcements # -- Environments -- From 9db54261f215b6aa47f69d106f8e92cff58168a5 Mon Sep 17 00:00:00 2001 From: Shane Bee Date: Mon, 1 Jul 2024 05:51:52 -0700 Subject: [PATCH 06/27] Add potion effect type comparator (#6832) * DefaultComparators - fix potion effect type match * DefaultComparators - fix potion effect type match - add test * DefaultComparators - update pickle suggestion --------- Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com> --- .../java/ch/njol/skript/classes/data/DefaultComparators.java | 4 ++++ .../tests/regressions/pull-6832-potioneffecttype-compare.sk | 3 +++ 2 files changed, 7 insertions(+) create mode 100644 src/test/skript/tests/regressions/pull-6832-potioneffecttype-compare.sk diff --git a/src/main/java/ch/njol/skript/classes/data/DefaultComparators.java b/src/main/java/ch/njol/skript/classes/data/DefaultComparators.java index e59a5678403..87fa10b1089 100644 --- a/src/main/java/ch/njol/skript/classes/data/DefaultComparators.java +++ b/src/main/java/ch/njol/skript/classes/data/DefaultComparators.java @@ -60,6 +60,7 @@ import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; +import org.bukkit.potion.PotionEffectType; import org.skriptlang.skript.lang.comparator.Comparator; import org.skriptlang.skript.lang.comparator.Comparators; import org.skriptlang.skript.lang.comparator.Relation; @@ -653,6 +654,9 @@ public boolean supportsOrdering() { return false; } }); + + // Potion Effect Type + Comparators.registerComparator(PotionEffectType.class, PotionEffectType.class, (one, two) -> Relation.get(one.equals(two))); } } diff --git a/src/test/skript/tests/regressions/pull-6832-potioneffecttype-compare.sk b/src/test/skript/tests/regressions/pull-6832-potioneffecttype-compare.sk new file mode 100644 index 00000000000..f0243b8a85f --- /dev/null +++ b/src/test/skript/tests/regressions/pull-6832-potioneffecttype-compare.sk @@ -0,0 +1,3 @@ +test "compare potion effect types": + assert nausea = nausea with "2 nausea potion effect types should match" + assert type of (potion effect of nausea for 1 minute) = nausea with "type of potion effect of nausea should equal nausea" From 9f625868680f068f0de7e21d154045f4c1fa4a21 Mon Sep 17 00:00:00 2001 From: Shane Bee Date: Mon, 1 Jul 2024 06:01:42 -0700 Subject: [PATCH 07/27] ExprLastDamage - fix everything (#6797) * ExprLastDamage - fix everything * HealthUtils set last damage manually * ExprLastDamage - add test --------- Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com> --- .../njol/skript/bukkitutil/HealthUtils.java | 9 ++-- .../skript/expressions/ExprLastDamage.java | 46 ++++++++----------- .../syntaxes/expressions/ExprLastDamage.sk | 15 ++++++ 3 files changed, 39 insertions(+), 31 deletions(-) create mode 100644 src/test/skript/tests/syntaxes/expressions/ExprLastDamage.sk diff --git a/src/main/java/ch/njol/skript/bukkitutil/HealthUtils.java b/src/main/java/ch/njol/skript/bukkitutil/HealthUtils.java index 20b5120a0f1..be8675ccabb 100644 --- a/src/main/java/ch/njol/skript/bukkitutil/HealthUtils.java +++ b/src/main/java/ch/njol/skript/bukkitutil/HealthUtils.java @@ -26,13 +26,13 @@ import org.bukkit.damage.DamageSource; import org.bukkit.damage.DamageType; import org.bukkit.entity.Damageable; +import org.bukkit.entity.LivingEntity; 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 { @@ -112,8 +112,11 @@ public static double getFinalDamage(EntityDamageEvent e) { return e.getFinalDamage() / 2; } - public static void setDamage(EntityDamageEvent e, double damage) { - e.setDamage(damage * 2); + public static void setDamage(EntityDamageEvent event, double damage) { + event.setDamage(damage * 2); + // Set last damage manually as Bukkit doesn't appear to do that + if (event.getEntity() instanceof LivingEntity) + ((LivingEntity) event.getEntity()).setLastDamage(damage * 2); } @Nullable diff --git a/src/main/java/ch/njol/skript/expressions/ExprLastDamage.java b/src/main/java/ch/njol/skript/expressions/ExprLastDamage.java index 0b62cd60a9d..ede427b156f 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprLastDamage.java +++ b/src/main/java/ch/njol/skript/expressions/ExprLastDamage.java @@ -19,47 +19,34 @@ */ package ch.njol.skript.expressions; -import org.bukkit.entity.LivingEntity; -import org.bukkit.event.Event; -import org.eclipse.jdt.annotation.Nullable; - import ch.njol.skript.classes.Changer.ChangeMode; import ch.njol.skript.doc.Description; import ch.njol.skript.doc.Examples; import ch.njol.skript.doc.Name; import ch.njol.skript.doc.Since; import ch.njol.skript.expressions.base.SimplePropertyExpression; -import ch.njol.skript.lang.Expression; -import ch.njol.skript.lang.SkriptParser; -import ch.njol.util.Kleenean; import ch.njol.util.coll.CollectionUtils; +import org.bukkit.entity.LivingEntity; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; @Name("Last Damage") @Description("The last damage that was done to an entity. Note that changing it doesn't deal more/less damage.") @Examples({"set last damage of event-entity to 2"}) @Since("2.5.1") public class ExprLastDamage extends SimplePropertyExpression { - + static { register(ExprLastDamage.class, Number.class, "last damage", "livingentities"); } - - @Nullable - private ExprDamage damageExpr; - - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { - damageExpr = new ExprDamage(); - return true; - } - + @Nullable @Override @SuppressWarnings("null") public Number convert(LivingEntity livingEntity) { - return damageExpr.get(livingEntity.getLastDamageCause())[0]; + return livingEntity.getLastDamage() / 2; } - + @Nullable @Override public Class[] acceptChange(ChangeMode mode) { @@ -72,35 +59,38 @@ public Class[] acceptChange(ChangeMode mode) { return null; } } - + + @SuppressWarnings("ConstantValue") @Override public void change(Event e, @Nullable Object[] delta, ChangeMode mode) { - if (delta != null) { + if (delta != null && delta[0] instanceof Number) { + double damage = ((Number) delta[0]).doubleValue() * 2; + switch (mode) { case SET: for (LivingEntity entity : getExpr().getArray(e)) - entity.setLastDamage((Long) delta[0]); + entity.setLastDamage(damage); break; case REMOVE: - delta[0] = (Long) delta[0] * -1; + damage = damage * -1; case ADD: for (LivingEntity entity : getExpr().getArray(e)) - entity.setLastDamage((Long) delta[0] + entity.getLastDamage()); + entity.setLastDamage(damage + entity.getLastDamage()); break; default: assert false; } } } - + @Override public Class getReturnType() { return Number.class; } - + @Override protected String getPropertyName() { return "last damage"; } - + } diff --git a/src/test/skript/tests/syntaxes/expressions/ExprLastDamage.sk b/src/test/skript/tests/syntaxes/expressions/ExprLastDamage.sk new file mode 100644 index 00000000000..0ed3f3f3e4c --- /dev/null +++ b/src/test/skript/tests/syntaxes/expressions/ExprLastDamage.sk @@ -0,0 +1,15 @@ +test "last damage": + set {_l} to location 0.5 above highest block at location(1,1,1) + spawn a sheep at {_l} + set {_e} to last spawned entity + + assert last damage of {_e} = 0 with "last damage of newly spawned entity should be 0" + + damage {_e} by 1 + assert last damage of {_e} = 1 with "last damage of entity should be 1 after damaging it by 1" + + set last damage of {_e} to 3 + assert last damage of {_e} = 3 with "last damage of entity should be 3 after setting to 3" + + # thank you for your service + delete entity in {_e} From abc782c34ceeb55f72c9e52d55a9912192eb31e8 Mon Sep 17 00:00:00 2001 From: Phill310 Date: Mon, 1 Jul 2024 06:02:13 -0700 Subject: [PATCH 08/27] Add delete changer to ExprMessage (#6828) * Add delete changer * Update examples * use toString Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com> * Add JUnit test (chat event) * Call chat event in JUnit Test * Create viewer Set differently * Add more tests (join/quit) * Remove use of components --------- Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com> --- .../njol/skript/expressions/ExprMessage.java | 32 ++++++----- .../{ => expressions}/ExprDropsTest.java | 2 +- .../syntaxes/expressions/ExprMessageTest.java | 53 +++++++++++++++++++ src/test/skript/junit/ExprDrops.sk | 4 +- src/test/skript/junit/ExprMessage.sk | 44 +++++++++++++++ 5 files changed, 118 insertions(+), 17 deletions(-) rename src/test/java/org/skriptlang/skript/test/tests/syntaxes/{ => expressions}/ExprDropsTest.java (94%) create mode 100644 src/test/java/org/skriptlang/skript/test/tests/syntaxes/expressions/ExprMessageTest.java create mode 100644 src/test/skript/junit/ExprMessage.sk diff --git a/src/main/java/ch/njol/skript/expressions/ExprMessage.java b/src/main/java/ch/njol/skript/expressions/ExprMessage.java index a3b54f43c4c..b973852dcc5 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprMessage.java +++ b/src/main/java/ch/njol/skript/expressions/ExprMessage.java @@ -48,23 +48,27 @@ @SuppressWarnings("deprecation") @Name("Message") @Description("The (chat) message of a chat event, the join message of a join event, the quit message of a quit event, or the death message on a death event. This expression is mostly useful for being changed.") -@Examples({"on chat:", - " player has permission \"admin\"", - " set message to \"&c%message%\"", +@Examples({ + "on chat:", + "\tplayer has permission \"admin\"", + "\tset message to \"&c%message%\"", "", "on first join:", - " set join message to \"Welcome %player% to our awesome server!\"", + "\tset join message to \"Welcome %player% to our awesome server!\"", "", "on join:", - " player has played before", - " set join message to \"Welcome back, %player%!\"", + "\tplayer has played before", + "\tset join message to \"Welcome back, %player%!\"", "", "on quit:", - " set quit message to \"%player% left this awesome server!\"", + "\tif {vanish::%player's uuid%} is set:", + "\t\tclear quit message", + "\telse:", + "\t\tset quit message to \"%player% left this awesome server!\"", "", "on death:", - " set the death message to \"%player% died!\""}) -@Since("1.4.6 (chat message), 1.4.9 (join & quit messages), 2.0 (death message)") + "\tset the death message to \"%player% died!\""}) +@Since("1.4.6 (chat message), 1.4.9 (join & quit messages), 2.0 (death message), INSERT VERSION (clear message)") @Events({"chat", "join", "quit", "death"}) public class ExprMessage extends SimpleExpression { @@ -181,18 +185,18 @@ protected String[] get(final Event e) { @Override @Nullable public Class[] acceptChange(final ChangeMode mode) { - if (mode == ChangeMode.SET) + if (mode == ChangeMode.SET || mode == ChangeMode.DELETE) return CollectionUtils.array(String.class); return null; } @Override public void change(final Event e, final @Nullable Object[] delta, final ChangeMode mode) { - assert mode == ChangeMode.SET; - assert delta != null; + assert mode == ChangeMode.SET || mode == ChangeMode.DELETE; for (final Class c : type.events) { - if (c.isInstance(e)) - type.set(e, "" + delta[0]); + if (c.isInstance(e)) { + type.set(e, (mode == ChangeMode.DELETE) ? "" : delta[0].toString()); + } } } diff --git a/src/test/java/org/skriptlang/skript/test/tests/syntaxes/ExprDropsTest.java b/src/test/java/org/skriptlang/skript/test/tests/syntaxes/expressions/ExprDropsTest.java similarity index 94% rename from src/test/java/org/skriptlang/skript/test/tests/syntaxes/ExprDropsTest.java rename to src/test/java/org/skriptlang/skript/test/tests/syntaxes/expressions/ExprDropsTest.java index f9216d5352c..f9f9c372176 100644 --- a/src/test/java/org/skriptlang/skript/test/tests/syntaxes/ExprDropsTest.java +++ b/src/test/java/org/skriptlang/skript/test/tests/syntaxes/expressions/ExprDropsTest.java @@ -16,7 +16,7 @@ * * Copyright Peter Güttinger, SkriptLang team and contributors */ -package org.skriptlang.skript.test.tests.syntaxes; +package org.skriptlang.skript.test.tests.syntaxes.expressions; import ch.njol.skript.test.runner.SkriptJUnitTest; import org.bukkit.entity.Pig; diff --git a/src/test/java/org/skriptlang/skript/test/tests/syntaxes/expressions/ExprMessageTest.java b/src/test/java/org/skriptlang/skript/test/tests/syntaxes/expressions/ExprMessageTest.java new file mode 100644 index 00000000000..1b0cbefa703 --- /dev/null +++ b/src/test/java/org/skriptlang/skript/test/tests/syntaxes/expressions/ExprMessageTest.java @@ -0,0 +1,53 @@ +/** + * 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 org.skriptlang.skript.test.tests.syntaxes.expressions; + +import ch.njol.skript.test.runner.SkriptJUnitTest; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.player.AsyncPlayerChatEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.plugin.PluginManager; +import org.easymock.EasyMock; +import org.junit.Before; +import org.junit.Test; + +import java.util.HashSet; +import java.util.Set; + +public class ExprMessageTest extends SkriptJUnitTest { + + private Player testPlayer; + + @Before + public void setup() { + testPlayer = EasyMock.niceMock(Player.class); + } + + @Test + public void test() { + Set viewers = new HashSet<>(); + viewers.add(testPlayer); + PluginManager manager = Bukkit.getServer().getPluginManager(); + manager.callEvent(new AsyncPlayerChatEvent(false, testPlayer, "hi", viewers)); + manager.callEvent(new PlayerJoinEvent(testPlayer, "hi")); + manager.callEvent(new PlayerQuitEvent(testPlayer, "hi")); + } +} diff --git a/src/test/skript/junit/ExprDrops.sk b/src/test/skript/junit/ExprDrops.sk index 3df908f9f03..c13fe31671f 100644 --- a/src/test/skript/junit/ExprDrops.sk +++ b/src/test/skript/junit/ExprDrops.sk @@ -12,13 +12,13 @@ test "ExprDropsJUnit" when running JUnit: set {_tests::11} to "add and remove experience from drops doesn't modify items" set {_tests::12} to "remove all experience from drops doesn't modify items" set {_tests::13} to "drops test complete" - ensure junit test "org.skriptlang.skript.test.tests.syntaxes.ExprDropsTest" completes {_tests::*} + ensure junit test "org.skriptlang.skript.test.tests.syntaxes.expressions.ExprDropsTest" completes {_tests::*} # NOTE: Do NOT take the behavior described in this test as a guide for how ExprDrops SHOULD work, only for how it DOES work in 2.7.x. # The behavior should change in 2.8 and this test will be updated accordingly. on death of pig: - set {_test} to "org.skriptlang.skript.test.tests.syntaxes.ExprDropsTest" + set {_test} to "org.skriptlang.skript.test.tests.syntaxes.expressions.ExprDropsTest" junit test is {_test} # Items diff --git a/src/test/skript/junit/ExprMessage.sk b/src/test/skript/junit/ExprMessage.sk new file mode 100644 index 00000000000..656e4d88109 --- /dev/null +++ b/src/test/skript/junit/ExprMessage.sk @@ -0,0 +1,44 @@ +test "ExprMessageJUnit" when running JUnit: + set {_tests::1} to "set chat message" + set {_tests::2} to "clear chat message" + set {_tests::3} to "set join message" + set {_tests::4} to "clear join message" + set {_tests::5} to "set quit message" + set {_tests::6} to "clear quit message" + ensure junit test "org.skriptlang.skript.test.tests.syntaxes.expressions.ExprMessageTest" completes {_tests::*} + +on chat: + set {_test} to "org.skriptlang.skript.test.tests.syntaxes.expressions.ExprMessageTest" + junit test is {_test} + + set chat message to "hello" + if chat message is "hello": + complete objective "set chat message" for {_test} + + clear message + if message is "": + complete objective "clear chat message" for {_test} + +on join: + set {_test} to "org.skriptlang.skript.test.tests.syntaxes.expressions.ExprMessageTest" + junit test is {_test} + + set login message to "I joined" + if log in message is "I joined": + complete objective "set join message" for {_test} + + clear join message + if join message is "": + complete objective "clear join message" for {_test} + +on quit: + set {_test} to "org.skriptlang.skript.test.tests.syntaxes.expressions.ExprMessageTest" + junit test is {_test} + + set logout message to "I left" + if log out message is "I left": + complete objective "set quit message" for {_test} + + clear quit message + if leave message is "": + complete objective "clear quit message" for {_test} \ No newline at end of file From 6ee4628d324e4f499319b40c7fd493d912d7f538 Mon Sep 17 00:00:00 2001 From: _Mads <75088349+TFSMads@users.noreply.github.com> Date: Mon, 1 Jul 2024 15:08:59 +0200 Subject: [PATCH 09/27] Added holder instanceof DoubleChest check to converter (#6823) * Added holder instanceof DoubleChest check to IntentoryHolder - Location converter * Apply suggestions from code review Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com> * Change ternary to if statements * Fix indentation in test * Address reviews Co-authored-by: _tud <98935832+UnderscoreTud@users.noreply.github.com> * Update src/main/java/ch/njol/skript/classes/data/DefaultConverters.java Co-authored-by: _tud <98935832+UnderscoreTud@users.noreply.github.com> --------- Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com> Co-authored-by: Pikachu920 <28607612+Pikachu920@users.noreply.github.com> Co-authored-by: _tud <98935832+UnderscoreTud@users.noreply.github.com> --- .../classes/data/DefaultConverters.java | 8 ++++++++ ...1-inventory-holder-location-doublechest.sk | 20 +++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 src/test/skript/tests/regressions/6811-inventory-holder-location-doublechest.sk diff --git a/src/main/java/ch/njol/skript/classes/data/DefaultConverters.java b/src/main/java/ch/njol/skript/classes/data/DefaultConverters.java index 00f419f4901..a90de6957d3 100644 --- a/src/main/java/ch/njol/skript/classes/data/DefaultConverters.java +++ b/src/main/java/ch/njol/skript/classes/data/DefaultConverters.java @@ -176,6 +176,14 @@ public DefaultConverters() {} return ((Block) holder).getLocation(); if (holder instanceof BlockState) return BlockUtils.getLocation(((BlockState) holder).getBlock()); + if (holder instanceof DoubleChest) { + DoubleChest doubleChest = (DoubleChest) holder; + if (doubleChest.getLeftSide() != null) { + return BlockUtils.getLocation(((BlockState) doubleChest.getLeftSide()).getBlock()); + } else if (((DoubleChest) holder).getRightSide() != null) { + return BlockUtils.getLocation(((BlockState) doubleChest.getRightSide()).getBlock()); + } + } return null; }); diff --git a/src/test/skript/tests/regressions/6811-inventory-holder-location-doublechest.sk b/src/test/skript/tests/regressions/6811-inventory-holder-location-doublechest.sk new file mode 100644 index 00000000000..f46d4b52794 --- /dev/null +++ b/src/test/skript/tests/regressions/6811-inventory-holder-location-doublechest.sk @@ -0,0 +1,20 @@ +test "inventory holder location double chest": + set {_b::1} to the block at spawn of world "world" + set {_b::2} to the block north of {_b::1} + set {_prev::1} to type of block at {_b::1} + set {_prev::2} to type of block at {_b::2} + + set block at {_b::1} to chest[facing=east;type=right] + set block at {_b::2} to chest[facing=east;type=left] + + set {_inv} to inventory of {_b::1} + set {_holder} to holder of {_inv} + + set {_a-loc} to location of {_holder} + set {_b-loc::*} to location of {_b::1} and location of {_b::2} + + # clean up first in case assert fails + set block at {_b::1} to {_prev::1} + set block at {_b::2} to {_prev::2} + + assert {_b-loc::*} contains {_a-loc} with "holder location of double chest differs from block location" From f6f41ca2ab9a9e7bdd381b111aa8929fb2443be6 Mon Sep 17 00:00:00 2001 From: Shane Bee Date: Mon, 1 Jul 2024 06:10:17 -0700 Subject: [PATCH 10/27] Registry - more registries (#6806) * Registry - more registries * BukkitClasses - make registryExists method public * BukkitUtils - create a bukkit utils class --------- Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com> --- .../njol/skript/bukkitutil/BukkitUtils.java | 21 +++++++++ .../skript/classes/data/BukkitClasses.java | 19 ++++++-- src/main/resources/lang/default.lang | 43 +++++++++++++++++++ 3 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 src/main/java/ch/njol/skript/bukkitutil/BukkitUtils.java diff --git a/src/main/java/ch/njol/skript/bukkitutil/BukkitUtils.java b/src/main/java/ch/njol/skript/bukkitutil/BukkitUtils.java new file mode 100644 index 00000000000..df551c268f5 --- /dev/null +++ b/src/main/java/ch/njol/skript/bukkitutil/BukkitUtils.java @@ -0,0 +1,21 @@ +package ch.njol.skript.bukkitutil; + +import ch.njol.skript.Skript; +import org.bukkit.Registry; + +/** + * Utility class with methods pertaining to Bukkit API + */ +public class BukkitUtils { + + /** + * Check if a registry exists + * + * @param registry Registry to check for (Fully qualified name of registry) + * @return True if registry exists else false + */ + public static boolean registryExists(String registry) { + return Skript.classExists("org.bukkit.Registry") && Skript.fieldExists(Registry.class, registry); + } + +} 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 69710a1ad00..530c3df07a5 100644 --- a/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java +++ b/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java @@ -29,6 +29,7 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; +import ch.njol.skript.bukkitutil.BukkitUtils; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Difficulty; @@ -980,7 +981,7 @@ public String toVariableNameString(final ItemStack i) { .changer(DefaultChangers.itemChanger)); ClassInfo biomeClassInfo; - if (Skript.classExists("org.bukkit.Registry") && Skript.fieldExists(Registry.class, "BIOME")) { + if (BukkitUtils.registryExists("BIOME")) { biomeClassInfo = new RegistryClassInfo<>(Biome.class, Registry.BIOME, "biome", "biomes"); } else { biomeClassInfo = new EnumClassInfo<>(Biome.class, "biome", "biomes"); @@ -1453,7 +1454,13 @@ public String toVariableNameString(FireworkEffect effect) { .examples("") .since("2.5")); if (Skript.classExists("org.bukkit.entity.Cat$Type")) { - Classes.registerClass(new EnumClassInfo<>(Cat.Type.class, "cattype", "cat types") + ClassInfo catTypeClassInfo; + if (BukkitUtils.registryExists("CAT_VARIANT")) { + catTypeClassInfo = new RegistryClassInfo<>(Cat.Type.class, Registry.CAT_VARIANT, "cattype", "cat types"); + } else { + catTypeClassInfo = new EnumClassInfo<>(Cat.Type.class, "cattype", "cat types"); + } + Classes.registerClass(catTypeClassInfo .user("cat ?(type|race)s?") .name("Cat Type") .description("Represents the race/type of a cat entity.") @@ -1514,7 +1521,13 @@ public String toVariableNameString(EnchantmentOffer eo) { } })); - Classes.registerClass(new EnumClassInfo<>(Attribute.class, "attributetype", "attribute types") + ClassInfo attributeClassInfo; + if (BukkitUtils.registryExists("ATTRIBUTE")) { + attributeClassInfo = new RegistryClassInfo<>(Attribute.class, Registry.ATTRIBUTE, "attributetype", "attribute types"); + } else { + attributeClassInfo = new EnumClassInfo<>(Attribute.class, "attributetype", "attribute types"); + } + Classes.registerClass(attributeClassInfo .user("attribute ?types?") .name("Attribute Type") .description("Represents the type of an attribute. Note that this type does not contain any numerical values." diff --git a/src/main/resources/lang/default.lang b/src/main/resources/lang/default.lang index 701cd9d07b9..38d8cc68f1f 100644 --- a/src/main/resources/lang/default.lang +++ b/src/main/resources/lang/default.lang @@ -2164,11 +2164,14 @@ genes: # -- Attribute Types -- attribute types: + # Enum variation generic_armor: generic armor, armor generic_armor_toughness: generic armor toughness, armor toughness generic_attack_damage: generic attack damage, attack damage generic_attack_knockback: generic attack knockback, attack knockback generic_attack_speed: generic attack speed, attack speed + generic_burning_time: generic burning time, burning time + generic_explosion_knockback_resistance: generic explosion knockback resistance, explosion knockback resistance generic_flying_speed: generic flying speed, flying speed generic_follow_range: generic follow range, follow range generic_gravity: generic gravity, gravity @@ -2177,16 +2180,56 @@ attribute types: generic_luck: generic luck, luck generic_max_absorption: generic max absorption, max absorption generic_max_health: generic max health, max health + generic_movement_efficiency: generic movement efficiency, movement efficiency generic_movement_speed: generic movement speed, movement speed + generic_oxygen_bonus: generic oxygen bonus, oxygen bonus generic_safe_fall_distance: generic safe fall distance, safe fall distance generic_fall_damage_multiplier: generic fall damage multiplier, fall damage multiplier generic_scale: generic scale, scale generic_step_height: generic step height, step height + generic_water_movement_efficiency: generic water movement efficiency, water movement efficiency horse_jump_strength: horse jump strength player_block_break_speed: player block break speed, block break speed player_block_interaction_range: player block interaction range, block interaction range player_entity_interaction_range: player entity interaction range, entity interaction range + player_mining_efficiency: player mining efficiency, mining efficiency + player_sneaking_speed: player sneaking speed, sneaking speed + player_submerged_mining_speed: player submerged mining speed, submerged mining speed + player_sweeping_damage_ratio: player sweeping damage ratio, sweeping damage ratio zombie_spawn_reinforcements: zombie spawn reinforcements + # Registry variation (minecraft keys) + generic.armor: generic armor, armor + generic.armor_toughness: generic armor toughness, armor toughness + generic.attack_damage: generic attack damage, attack damage + generic.attack_knockback: generic attack knockback, attack knockback + generic.attack_speed: generic attack speed, attack speed + generic.burning_time: generic burning time, burning time + generic.explosion_knockback_resistance: generic explosion knockback resistance, explosion knockback resistance + generic.flying_speed: generic flying speed, flying speed + generic.follow_range: generic follow range, follow range + generic.gravity: generic gravity, gravity + generic.jump_strength: generic jump strength, jump strength + generic.knockback_resistance: generic knockback resistance, knockback resistance + generic.luck: generic luck, luck + generic.max_absorption: generic max absorption, max absorption + generic.max_health: generic max health, max health + generic.movement_efficiency: generic movement efficiency, movement efficiency + generic.movement_speed: generic movement speed, movement speed + generic.oxygen_bonus: generic oxygen bonus, oxygen bonus + generic.safe_fall_distance: generic safe fall distance, safe fall distance + generic.fall_damage_multiplier: generic fall damage multiplier, fall damage multiplier + generic.scale: generic scale, scale + generic.step_height: generic step height, step height + generic.water_movement_efficiency: generic water movement efficiency, water movement efficiency + horse_jump_strength: horse jump strength + player.block_break_speed: player block break speed, block break speed + player.block_interaction_range: player block interaction range, block interaction range + player.entity_interaction_range: player entity interaction range, entity interaction range + player.mining_efficiency: player mining efficiency, mining efficiency + player.sneaking_speed: player sneaking speed, sneaking speed + player.submerged_mining_speed: player submerged mining speed, submerged mining speed + player.sweeping_damage_ratio: player sweeping damage ratio, sweeping damage ratio + zombie.spawn_reinforcements: zombie spawn reinforcements # -- Environments -- environments: From 7d84902264624572c93736f431ca067c433210f1 Mon Sep 17 00:00:00 2001 From: Shane Bee Date: Mon, 1 Jul 2024 06:15:46 -0700 Subject: [PATCH 11/27] Fix/registry pr whoops (#6805) RegistrySerializer - big whoops Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com> --- .../ch/njol/skript/classes/registry/RegistrySerializer.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/ch/njol/skript/classes/registry/RegistrySerializer.java b/src/main/java/ch/njol/skript/classes/registry/RegistrySerializer.java index ddec6c3225f..2c0796e4218 100644 --- a/src/main/java/ch/njol/skript/classes/registry/RegistrySerializer.java +++ b/src/main/java/ch/njol/skript/classes/registry/RegistrySerializer.java @@ -23,6 +23,7 @@ import org.bukkit.Keyed; import org.bukkit.NamespacedKey; import org.bukkit.Registry; +import org.jetbrains.annotations.NotNull; import java.io.StreamCorruptedException; @@ -40,10 +41,10 @@ public RegistrySerializer(Registry registry) { } @Override - public Fields serialize(R o) { + public @NotNull Fields serialize(R o) { Fields fields = new Fields(); fields.putPrimitive("name", o.getKey().toString()); - return null; + return fields; } @Override From 1d587d4acb0ea04498b328030b84c5fdc217dad2 Mon Sep 17 00:00:00 2001 From: Moderocky Date: Mon, 1 Jul 2024 14:25:37 +0100 Subject: [PATCH 12/27] Improve new line pattern. (#6733) * Make new line literal not silly. * Clean init header. --------- Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com> --- .../java/ch/njol/skript/expressions/LitNewLine.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/ch/njol/skript/expressions/LitNewLine.java b/src/main/java/ch/njol/skript/expressions/LitNewLine.java index d6ca312fb6d..fbe845946a3 100644 --- a/src/main/java/ch/njol/skript/expressions/LitNewLine.java +++ b/src/main/java/ch/njol/skript/expressions/LitNewLine.java @@ -19,7 +19,6 @@ package ch.njol.skript.expressions; import org.bukkit.event.Event; -import org.eclipse.jdt.annotation.Nullable; import ch.njol.skript.Skript; import ch.njol.skript.doc.Description; @@ -28,9 +27,10 @@ import ch.njol.skript.doc.Since; import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.ExpressionType; -import ch.njol.skript.lang.SkriptParser; +import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.lang.util.SimpleLiteral; import ch.njol.util.Kleenean; +import org.jetbrains.annotations.Nullable; @Name("New Line") @Description("Returns a line break separator.") @@ -39,7 +39,7 @@ public class LitNewLine extends SimpleLiteral { static { - Skript.registerExpression(LitNewLine.class, String.class, ExpressionType.SIMPLE, "n[ew]l[ine]", "line[ ]break"); + Skript.registerExpression(LitNewLine.class, String.class, ExpressionType.SIMPLE, "nl", "new[ ]line", "line[ ]break"); } public LitNewLine() { @@ -47,12 +47,12 @@ public LitNewLine() { } @Override - public boolean init(final Expression[] exprs, final int matchedPattern, final Kleenean isDelayed, final SkriptParser.ParseResult parseResult) { + public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult result) { return true; } @Override - public String toString(@Nullable Event e, boolean debug) { - return "newline"; + public String toString(@Nullable Event event, boolean debug) { + return "new line"; } } From 333b5fb4641c9943a6adbbd21fb366d79c4e2022 Mon Sep 17 00:00:00 2001 From: Moderocky Date: Mon, 1 Jul 2024 14:35:33 +0100 Subject: [PATCH 13/27] Add tests for item syntaxes. (#6164) * Add 'with custom model data' test. * Add 'amount of items' test. * Add 'items in' test. * Make safe for 1.13.2. * Update src/test/skript/tests/syntaxes/expressions/ExprItemsIn.sk Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com> --------- Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com> --- .../syntaxes/expressions/ExprAmountOfItems.sk | 14 ++++++++++ .../ExprItemWithCustomModelData.sk | 13 +++++++++ .../tests/syntaxes/expressions/ExprItemsIn.sk | 27 +++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 src/test/skript/tests/syntaxes/expressions/ExprAmountOfItems.sk create mode 100644 src/test/skript/tests/syntaxes/expressions/ExprItemWithCustomModelData.sk diff --git a/src/test/skript/tests/syntaxes/expressions/ExprAmountOfItems.sk b/src/test/skript/tests/syntaxes/expressions/ExprAmountOfItems.sk new file mode 100644 index 00000000000..9e40ff707ca --- /dev/null +++ b/src/test/skript/tests/syntaxes/expressions/ExprAmountOfItems.sk @@ -0,0 +1,14 @@ +test "amount of items": + set {_inventory} to a hopper inventory named "test" + assert the amount of stone in {_inventory} is 0 with "default amount failed" + add stone to {_inventory} + assert the amount of stone in {_inventory} is 1 with "single amount failed" + add stone named "bread" to {_inventory} + assert the amount of stone in {_inventory} is 2 with "different named items amount failed" + add 100 of iron ingot to {_inventory} + assert the amount of stone in {_inventory} is 2 with "add different item amount failed" + assert the amount of iron ingot in {_inventory} is 100 with "add 100 item amount failed" + remove stone from {_inventory} + assert the amount of stone in {_inventory} is 1 with "removed one amount failed" + remove stone from {_inventory} + assert the amount of stone in {_inventory} is 0 with "removed all amount failed" diff --git a/src/test/skript/tests/syntaxes/expressions/ExprItemWithCustomModelData.sk b/src/test/skript/tests/syntaxes/expressions/ExprItemWithCustomModelData.sk new file mode 100644 index 00000000000..098cda9abee --- /dev/null +++ b/src/test/skript/tests/syntaxes/expressions/ExprItemWithCustomModelData.sk @@ -0,0 +1,13 @@ +test "item with custom model data" when minecraft version is not "1.13.2": + set {_i} to stone + assert the custom model data of {_i} is 0 with "default model data failed" + set {_i} to stone with custom model data 5 + assert the custom model data of {_i} is 5 with "simple model data set failed" + set {_i} to stone with custom model data -1 + assert the custom model data of {_i} is -1 with "negative model data set failed" + set {_i} to {_i} with custom model data 2 + assert the custom model data of {_i} is 2 with "existing item model data set failed" + set {_i} to {_i} with custom model data 3.3 + assert the custom model data of {_i} is 3 with "decimal item model data set failed" + set {_i} to {_i} with custom model data 3.999 + assert the custom model data of {_i} is 3 with "close decimal item model data set failed" diff --git a/src/test/skript/tests/syntaxes/expressions/ExprItemsIn.sk b/src/test/skript/tests/syntaxes/expressions/ExprItemsIn.sk index 9b2c90fb25f..a18bef586af 100644 --- a/src/test/skript/tests/syntaxes/expressions/ExprItemsIn.sk +++ b/src/test/skript/tests/syntaxes/expressions/ExprItemsIn.sk @@ -1,3 +1,29 @@ + +test "items in (inventory)": + set {_inventory} to a hopper inventory named "test" + add stone to {_inventory} + add stone named "bread" to {_inventory} + add 100 of iron ingot to {_inventory} + loop items in {_inventory}: + if loop-value is stone: + continue + else if loop-value is iron ingot: + continue + else: + assert true is false with "unexpected item in the inventory area: %loop-value%" + set {_list::*} to items in {_inventory} + assert size of {_list::*} is 4 with "size of items in failed" + assert {_list::1} is stone with "first item failed" + assert {_list::2} is stone named "bread" with "second item failed" + assert {_list::3} is 64 of iron ingot with "third item failed" + assert {_list::4} is 36 of iron ingot with "split fourth item failed" + remove stone from {_inventory} + set {_list::*} to items in {_inventory} + assert size of {_list::*} is 3 with "size of second items in failed" + assert {_list::1} is stone named "bread" with "new first item failed" + assert {_list::2} is 64 of iron ingot with "new second item failed" + assert {_list::3} is 36 of iron ingot with "new third item failed" + test "filtering ExprItemsIn": set {_world} to random world out of all worlds set block at spawn of {_world} to chest @@ -19,3 +45,4 @@ test "unfiltered ExprItemsIn": set slot 3 of {_inv} to bucket assert all items in inventory {_inv} are dirt, stone or bucket with "found correct items with ExprItemsIn##get" assert (all items in inventory {_inv} where [true is true]) are dirt, stone or bucket with "found correct items with ExprItemsIn##iterator" + From 1a42f52c641116d966013cdef6295d10212e92f7 Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Mon, 1 Jul 2024 15:46:30 +0200 Subject: [PATCH 14/27] Add config toggle for whether to listen to cancelled events by default. (#6680) * Add config toggle * Update src/main/resources/config.sk Co-authored-by: _tud <98935832+UnderscoreTud@users.noreply.github.com> --------- Co-authored-by: _tud <98935832+UnderscoreTud@users.noreply.github.com> --- src/main/java/ch/njol/skript/SkriptConfig.java | 6 ++++++ src/main/java/ch/njol/skript/lang/SkriptEventInfo.java | 5 +++-- src/main/resources/config.sk | 3 +++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/ch/njol/skript/SkriptConfig.java b/src/main/java/ch/njol/skript/SkriptConfig.java index 5a3bb954cd4..ee715ce038e 100644 --- a/src/main/java/ch/njol/skript/SkriptConfig.java +++ b/src/main/java/ch/njol/skript/SkriptConfig.java @@ -170,6 +170,12 @@ public static String formatDate(final long timestamp) { } }); + /** + * Determines whether `on <event>` will be triggered by cancelled events or not. + */ + public static final Option listenCancelledByDefault = new Option<>("listen to cancelled events by default", false) + .optional(true); + /** * Maximum number of digits to display after the period for floats and doubles diff --git a/src/main/java/ch/njol/skript/lang/SkriptEventInfo.java b/src/main/java/ch/njol/skript/lang/SkriptEventInfo.java index 610b0671529..b645f7675b1 100644 --- a/src/main/java/ch/njol/skript/lang/SkriptEventInfo.java +++ b/src/main/java/ch/njol/skript/lang/SkriptEventInfo.java @@ -19,6 +19,7 @@ package ch.njol.skript.lang; import ch.njol.skript.SkriptAPIException; +import ch.njol.skript.SkriptConfig; import org.bukkit.event.Event; import org.bukkit.event.player.PlayerInteractAtEntityEvent; import org.eclipse.jdt.annotation.Nullable; @@ -74,8 +75,8 @@ public SkriptEventInfo(String name, String[] patterns, Class eventClass, Stri // uses the name without 'on ' or '*' this.id = "" + name.toLowerCase(Locale.ENGLISH).replaceAll("[#'\"<>/&]", "").replaceAll("\\s+", "_"); - // default listening behavior should be to listen to uncancelled events - this.listeningBehavior = ListeningBehavior.UNCANCELLED; + // default listening behavior should be dependent on config setting + this.listeningBehavior = SkriptConfig.listenCancelledByDefault.value() ? ListeningBehavior.ANY : ListeningBehavior.UNCANCELLED; } /** diff --git a/src/main/resources/config.sk b/src/main/resources/config.sk index 68d9bfd926f..85784c06a92 100644 --- a/src/main/resources/config.sk +++ b/src/main/resources/config.sk @@ -122,6 +122,9 @@ plugin priority: high # - effects 'remove ... from drops'/'clear drops': Drops added by other plugins are not removed => increase priority # Skript removes drops it shouldn't => decrease priority or specify which item types to remove +listen to cancelled events by default: false +# Determines whether `on ` will be triggered by all events (true) or only uncancelled events (false). +# The default is false, which maintains traditional Skript behavior. number accuracy: 2 # How many digits should be displayed after the dot at maximum when displaying numbers. From e8c8b5ff28e3d86fa08a00388bb6267d4efbe181 Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Mon, 1 Jul 2024 16:13:54 +0200 Subject: [PATCH 15/27] Change comment parsing (#6583) * Rework to only allow single # in quoted strings * fix save() * fix state machine bug with exiting %s * Update skript-aliases * remove unreachable code --------- Co-authored-by: Moderocky --- src/main/java/ch/njol/skript/config/Node.java | 157 +++++++++++++++--- .../expressions/ExprChestInventory.java | 2 +- .../skript/expressions/ExprLoopIteration.java | 2 +- .../skript/expressions/ExprLoopValue.java | 2 +- src/main/java/ch/njol/skript/util/Utils.java | 2 +- src/main/resources/config.sk | 2 +- .../scripts/-examples/text formatting.sk | 4 +- .../skript/test/tests/config/NodeTest.java | 1 + src/test/skript/tests/misc/comments.sk | 46 +++++ ...loating point errors rounding functions.sk | 12 +- .../tests/regressions/4664-formatted time.sk | 10 +- .../regressions/4769-fire-visualeffect.sk | 4 +- .../535-math is done in the wrong order.sk | 14 +- ...required in some places it shouldn't be.sk | 4 +- ...837-getting a uuid of a var inside code.sk | 4 +- .../tests/syntaxes/conditions/CondContains.sk | 40 ++--- .../tests/syntaxes/conditions/CondIsWithin.sk | 36 ++-- .../syntaxes/conditions/CondMethodExists.sk | 18 +- .../tests/syntaxes/effects/EffContinue.sk | 6 +- .../tests/syntaxes/effects/EffHealth.sk | 10 +- .../syntaxes/expressions/ExprArrowsStuck.sk | 10 +- .../expressions/ExprEntityAttribute.sk | 4 +- .../syntaxes/expressions/ExprFreezeTicks.sk | 8 +- .../tests/syntaxes/expressions/ExprItemsIn.sk | 8 +- .../syntaxes/expressions/ExprNoDamageTicks.sk | 10 +- .../expressions/ExprPortalCooldown.sk | 6 +- .../tests/syntaxes/functions/caseEquals.sk | 10 +- .../tests/syntaxes/sections/SecConditional.sk | 10 +- 28 files changed, 298 insertions(+), 144 deletions(-) create mode 100644 src/test/skript/tests/misc/comments.sk diff --git a/src/main/java/ch/njol/skript/config/Node.java b/src/main/java/ch/njol/skript/config/Node.java index f59c7210f5c..cff13bda618 100644 --- a/src/main/java/ch/njol/skript/config/Node.java +++ b/src/main/java/ch/njol/skript/config/Node.java @@ -23,6 +23,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import ch.njol.skript.SkriptConfig; import org.eclipse.jdt.annotation.Nullable; import ch.njol.skript.Skript; @@ -114,17 +115,27 @@ public void move(final SectionNode newParent) { p.remove(this); newParent.add(this); } - - @SuppressWarnings("null") - private final static Pattern linePattern = Pattern.compile("^((?:[^#]|##)*)(\\s*#(?!#).*)$"); - + /** * Splits a line into value and comment. *

* Whitespace is preserved (whitespace in front of the comment is added to the value), and any ## in the value are replaced by a single #. The comment is returned with a * leading #, except if there is no comment in which case it will be the empty string. + * + * @param line the line to split + * @return A pair (value, comment). + */ + public static NonNullPair splitLine(String line) { + return splitLine(line, new AtomicBoolean(false)); + } + + /** + * Splits a line into value and comment. + *

+ * Whitespace is preserved (whitespace in front of the comment is added to the value), and any ## not in quoted strings in the value are replaced by a single #. The comment is returned with a + * leading #, except if there is no comment in which case it will be the empty string. * - * @param line + * @param line the line to split * @param inBlockComment Whether we are currently inside a block comment * @return A pair (value, comment). */ @@ -138,34 +149,99 @@ public static NonNullPair splitLine(String line, AtomicBoolean i } else if (inBlockComment.get()) { // we're inside a comment, all text is a comment return new NonNullPair<>("", line); } - final Matcher m = linePattern.matcher(line); - boolean matches = false; - try { - matches = line.contains("#") && m.matches(); - } catch (StackOverflowError e) { // Probably a very long line - handleNodeStackOverflow(e, line); + + // idea: find first # that is not within a string or variable name. Use state machine to determine whether a # is a comment or not. + int length = line.length(); + StringBuilder finalLine = new StringBuilder(line); + int numRemoved = 0; + SplitLineState state = SplitLineState.CODE; + SplitLineState previousState = SplitLineState.CODE; // stores the state prior to entering %, so it can be re-set when leaving + // find next " or % + for (int i = 0; i < length; i++) { + char c = line.charAt(i); + // check for things that can be escaped by doubling + if (c == '%' || c == '"' || c == '#') { + // skip if doubled (only skip ## outside of strings) + if ((c != '#' || state != SplitLineState.STRING) && i + 1 < length && line.charAt(i + 1) == c) { + if (c == '#') { // remove duplicate # + finalLine.deleteCharAt(i - numRemoved); + numRemoved++; + } + i++; + continue; + } + SplitLineState tmp = state; + state = SplitLineState.update(c, state, previousState); + if (state == SplitLineState.HALT) + return new NonNullPair<>(finalLine.substring(0, i - numRemoved), line.substring(i)); + // only update previous state when we go from !CODE -> CODE due to % + if (c == '%' && state == SplitLineState.CODE) + previousState = tmp; + } } - if (matches) - return new NonNullPair<>("" + m.group(1).replace("##", "#"), "" + m.group(2)); - return new NonNullPair<>("" + line.replace("##", "#"), ""); + return new NonNullPair<>(finalLine.toString(), ""); } /** - * Splits a line into value and comment. - *

- * Whitespace is preserved (whitespace in front of the comment is added to the value), and any ## in the value are replaced by a single #. The comment is returned with a - * leading #, except if there is no comment in which case it will be the empty string. - * - * @param line - * @return A pair (value, comment). + * state machine:
+ * ": CODE -> STRING, STRING -> CODE, VARIABLE -> VARIABLE
+ * %: CODE -> PREVIOUS_STATE, STRING -> CODE, VARIABLE -> CODE
+ * {: CODE -> VARIABLE, STRING -> STRING, VARIABLE -> VARIABLE
+ * }: CODE -> CODE, STRING -> STRING, VARIABLE -> CODE
+ * #: CODE -> HALT, STRING -> STRING, VARIABLE -> HALT
+ * invalid characters simply return given state.
*/ - public static NonNullPair splitLine(String line) { - return splitLine(line, new AtomicBoolean(false)); + private enum SplitLineState { + HALT, + CODE, + STRING, + VARIABLE; + + /** + * Updates the state given a character input. + * @param c character input. '"', '%', '{', '}', and '#' are valid. + * @param state the current state of the machine + * @param previousState the state of the machine when it last entered a % CODE % section + * @return the new state of the machine + */ + private static SplitLineState update(char c, SplitLineState state, SplitLineState previousState) { + if (state == HALT) + return HALT; + + switch (c) { + case '%': + if (state == CODE) + return previousState; + return CODE; + case '"': + switch (state) { + case CODE: + return STRING; + case STRING: + return CODE; + default: + return state; + } + case '{': + if (state == STRING) + return STRING; + return VARIABLE; + case '}': + if (state == STRING) + return STRING; + return CODE; + case '#': + if (state == STRING) + return STRING; + return HALT; + } + return state; + } } static void handleNodeStackOverflow(StackOverflowError e, String line) { Node n = SkriptLogger.getNode(); - SkriptLogger.setNode(null); // Avoid duplicating the which node error occurred in paranthesis on every error message + SkriptLogger.setNode(null); // Avoid duplicating the which node error occurred in parentheses on every error message Skript.error("There was a StackOverFlowError occurred when loading a node. This maybe from your scripts, aliases or Skript configuration."); Skript.error("Please make your script lines shorter! Do NOT report this to SkriptLang unless it occurs with a short script line or built-in aliases!"); @@ -214,12 +290,43 @@ protected String getIndentation() { abstract String save_i(); public final String save() { - return getIndentation() + save_i().replace("#", "##") + comment; + return getIndentation() + escapeUnquotedHashtags(save_i()) + comment; } public void save(final PrintWriter w) { w.println(save()); } + + private static String escapeUnquotedHashtags(String input) { + int length = input.length(); + StringBuilder output = new StringBuilder(input); + int numAdded = 0; + SplitLineState state = SplitLineState.CODE; + SplitLineState previousState = SplitLineState.CODE; + // find next " or % + for (int i = 0; i < length; i++) { + char c = input.charAt(i); + // check for things that can be escaped by doubling + if (c == '%' || c == '"' || c == '#') { + // escaped #s outside of strings + if (c == '#' && state != SplitLineState.STRING) { + output.insert(i + numAdded, "#"); + numAdded++; + continue; + } + // skip if doubled (not #s) + if (i + 1 < length && input.charAt(i + 1) == c) { + i++; + continue; + } + SplitLineState tmp = state; + state = SplitLineState.update(c, state, previousState); + previousState = tmp; + } + } + return output.toString(); + } + @Nullable public SectionNode getParent() { diff --git a/src/main/java/ch/njol/skript/expressions/ExprChestInventory.java b/src/main/java/ch/njol/skript/expressions/ExprChestInventory.java index 0ba4548c184..a01ac6b9dcc 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprChestInventory.java +++ b/src/main/java/ch/njol/skript/expressions/ExprChestInventory.java @@ -52,7 +52,7 @@ "set slot 4 of {_inventory} to a diamond named \"example\"", "open {_inventory} to player", "", - "open chest inventory named \"<##00ff00>hex coloured title!\" with 6 rows to player", + "open chest inventory named \"<#00ff00>hex coloured title!\" with 6 rows to player", }) @RequiredPlugins("Paper 1.16+ (chat format)") @Since("2.2-dev34, 2.8.0 (chat format)") diff --git a/src/main/java/ch/njol/skript/expressions/ExprLoopIteration.java b/src/main/java/ch/njol/skript/expressions/ExprLoopIteration.java index 37640b26db7..12fb9b0a782 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprLoopIteration.java +++ b/src/main/java/ch/njol/skript/expressions/ExprLoopIteration.java @@ -45,7 +45,7 @@ "", "loop {top-balances::*}:", "\tif loop-iteration <= 10:", - "\t\tbroadcast \"##%loop-iteration% %loop-index% has $%loop-value%\"", + "\t\tbroadcast \"#%loop-iteration% %loop-index% has $%loop-value%\"", }) @Since("2.8.0") public class ExprLoopIteration extends SimpleExpression { diff --git a/src/main/java/ch/njol/skript/expressions/ExprLoopValue.java b/src/main/java/ch/njol/skript/expressions/ExprLoopValue.java index 343cc9461c3..10142cb0268 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprLoopValue.java +++ b/src/main/java/ch/njol/skript/expressions/ExprLoopValue.java @@ -62,7 +62,7 @@ "", "loop {top-balances::*}:", "\tloop-iteration <= 10", - "\tsend \"##%loop-iteration% %loop-index% has $%loop-value%\"", + "\tsend \"#%loop-iteration% %loop-index% has $%loop-value%\"", }) @Since("1.0, 2.8.0 (loop-counter)") public class ExprLoopValue extends SimpleExpression { diff --git a/src/main/java/ch/njol/skript/util/Utils.java b/src/main/java/ch/njol/skript/util/Utils.java index 862e440ceb8..879e1aabe74 100644 --- a/src/main/java/ch/njol/skript/util/Utils.java +++ b/src/main/java/ch/njol/skript/util/Utils.java @@ -641,7 +641,7 @@ public String run(final Matcher m) { return "" + m; } - private static final Pattern HEX_PATTERN = Pattern.compile("(?i)#?[0-9a-f]{6}"); + private static final Pattern HEX_PATTERN = Pattern.compile("(?i)#{0,2}[0-9a-f]{6}"); /** * Tries to get a {@link ChatColor} from the given string. diff --git a/src/main/resources/config.sk b/src/main/resources/config.sk index 85784c06a92..4ba081e7c33 100644 --- a/src/main/resources/config.sk +++ b/src/main/resources/config.sk @@ -22,7 +22,7 @@ # This file, all scripts and other files ending in .sk are NOT .yml/YAML files, but very similar! # Please remember the following when editing files: # - To indent sections you can use spaces like in YAML, but tabs are also allowed. Just remember to stick to the one or the other for a section/trigger. -# - '#' starts a comment like in YAML. If you don't want it to start a comment simply double it: '##' (You also have to double these in "quoted text") +# - '#' starts a comment like in YAML. If you don't want it to start a comment simply double it: '##' (You do NOT have to double these in "quoted text") # - If you use special characters (§, äöü, éèàôç, ñ, etc.) you have to encode the file in UTF-8. # diff --git a/src/main/resources/scripts/-examples/text formatting.sk b/src/main/resources/scripts/-examples/text formatting.sk index 8a5a1ab277a..5163ca116c3 100644 --- a/src/main/resources/scripts/-examples/text formatting.sk +++ b/src/main/resources/scripts/-examples/text formatting.sk @@ -4,7 +4,7 @@ # You can also use <> for colours and formats, like `` for red and `` for bold # # In Minecraft 1.16, support was added for 6-digit hexadecimal colors to specify custom colors other than the 16 default color codes. -# The tag for these colors looks like this: <##hex code> e.g. `<##123456>` +# The tag for these colors looks like this: <#hex code> e.g. `<#123456>` # command /color: @@ -12,7 +12,7 @@ command /color: trigger: send "&6This message is golden." send "This message is light red and bold." - send "<##FF0000>This message is red." + send "<#FF0000>This message is red." # # Other formatting options are also available. diff --git a/src/test/java/org/skriptlang/skript/test/tests/config/NodeTest.java b/src/test/java/org/skriptlang/skript/test/tests/config/NodeTest.java index c7e0eb3b29f..b0a7ff2b606 100644 --- a/src/test/java/org/skriptlang/skript/test/tests/config/NodeTest.java +++ b/src/test/java/org/skriptlang/skript/test/tests/config/NodeTest.java @@ -47,6 +47,7 @@ public void splitLineTest() { {"#########", "", "#########"}, {"a##b#c##d#e", "a#b", "#c##d#e"}, {" a ## b # c ## d # e ", " a # b ", "# c ## d # e "}, + {"a b \"#a ##\" # b \"", "a b \"#a ##\" ", "# b \""}, }; for (String[] d : data) { NonNullPair p = Node.splitLine(d[0]); diff --git a/src/test/skript/tests/misc/comments.sk b/src/test/skript/tests/misc/comments.sk new file mode 100644 index 00000000000..348f7560d6d --- /dev/null +++ b/src/test/skript/tests/misc/comments.sk @@ -0,0 +1,46 @@ +test "comments": + parse: + set {_a} to {_b} # test + assert last parse logs is not set with "skript should be able to handle inline comments but did not" + + + parse: + assert "a" is "a" with "wrong number of hashtags" + assert "#a" is join "#", and "a" with "wrong number of hashtags" + assert "##a" is join "#", "#", and "a" with "wrong number of hashtags" + assert "###a" is join "#", "#", "#", and "a" with "wrong number of hashtags" + assert last parse logs is not set with "skript should be able to handle strings any number of hashtags but did not" + + + parse: + assert "a%"#"%" is join "a", and "#" with "wrong number of hashtags" + assert "#a%"#}"%" is join "#", "a", and "#}" with "wrong number of hashtags" + assert "##a%"#"%" is join "#", "#", "a", and "#" with "wrong number of hashtags" + assert "#{##a%"#"%" is join "#{", "#", "#", "a", and "#" with "wrong number of hashtags" + assert last parse logs is not set with "skript should be able to handle complex strings any number of hashtags but did not" + + + parse: + set {_a} to "<#abcdef>test" + set {_b} to "<##abcdef>test" + assert uncoloured {_a} is "test" with "failed to parse single hashtag colour code" + assert uncoloured {_b} is "test" with "failed to parse double hashtag colour code" + assert last parse logs is not set with "skript should be able to handle hex colour codes but did not" + + parse: + set {_a} to "###SH#JABJ#BJ#JB#K#BH#G#J##J#HJ%%KJB#JKK%%""%%""%%""%%#""##%%""#""%%##""#%""%##%"#"""%#"#!!""#""#L@$L@:@#L@K:L%@^$:"#^#:^J$%:K^J%&LK:#::&&^^^%%test + assert last parse logs is not set with "skript should be able to handle very messy string but did not" + + + parse: + set {_a##} to "test" + set {##_b} to "test" + set {##_b::%"{}"%} to "test" + set {##_b::%"{}#"%} to "#test" + assert {##_b::%"{}#"%} is join "#" and "test" with "failed state machine check" + assert last parse logs is not set with "skript should be able to handle hashtags in variable names but did not" + + + parse: + set {##_b::%"{}"#%} to "#test" + assert last parse logs is set with "skript should not be able to handle hashtags in an expression in a variable name but did" diff --git a/src/test/skript/tests/regressions/4235-floating point errors rounding functions.sk b/src/test/skript/tests/regressions/4235-floating point errors rounding functions.sk index ad8ecff83d5..4afe12bc824 100644 --- a/src/test/skript/tests/regressions/4235-floating point errors rounding functions.sk +++ b/src/test/skript/tests/regressions/4235-floating point errors rounding functions.sk @@ -1,12 +1,12 @@ test "floating point errors in rounding functions": - #assert ceil(100*0.07) is 7 with "ceil function doesn't adjust for floating point errors ##1" - #assert ceil(100*0.033 - 0.3) is 3 with "ceil function doesn't adjust for floating point errors ##2" + #assert ceil(100*0.07) is 7 with "ceil function doesn't adjust for floating point errors" + #assert ceil(100*0.033 - 0.3) is 3 with "ceil function doesn't adjust for floating point errors" - #assert rounded up 100*0.07 is 7 with "ceil expression doesn't adjust for floating point errors ##1" - #assert rounded up 100*0.033 - 0.3 is 3 with "ceil expression doesn't adjust for floating point errors ##2" + #assert rounded up 100*0.07 is 7 with "ceil expression doesn't adjust for floating point errors" + #assert rounded up 100*0.033 - 0.3 is 3 with "ceil expression doesn't adjust for floating point errors" set {_sum} to 0 loop 100 times: add 0.1 to {_sum} - assert floor({_sum}) is 10 with "floor function doesn't adjust for floating point errors ##1" - assert rounded down {_sum} is 10 with "floor expression doesn't adjust for floating point errors ##1" + assert floor({_sum}) is 10 with "floor function doesn't adjust for floating point errors" + assert rounded down {_sum} is 10 with "floor expression doesn't adjust for floating point errors" diff --git a/src/test/skript/tests/regressions/4664-formatted time.sk b/src/test/skript/tests/regressions/4664-formatted time.sk index 329c06bb9fa..a43029af91b 100644 --- a/src/test/skript/tests/regressions/4664-formatted time.sk +++ b/src/test/skript/tests/regressions/4664-formatted time.sk @@ -3,18 +3,18 @@ test "formatted time": set {_now} to now set {_date1} to {_now} formatted - assert {_date1} = {_now} formatted as {_default} with "default date format failed ##1" + assert {_date1} = {_now} formatted as {_default} with "default date format failed" set {_date2} to {_now} formatted human-readable - assert {_date2} = {_now} formatted as {_default} with "default date format failed ##2" + assert {_date2} = {_now} formatted as {_default} with "default date format failed" set {_date3} to {_now} formatted as "HH:mm" - assert length of {_date3} = 5 with "custom date format failed ##1" + assert length of {_date3} = 5 with "custom date format failed" set {_cFormat} to "hh:mm" set {_date4} to {_now} formatted as {_cFormat} - assert length of {_date4} = 5 with "custom date format failed ##2" + assert length of {_date4} = 5 with "custom date format failed" set {_cFormat2} to "i" set {_date5} to {_now} formatted as {_cFormat2} - assert {_date5} is not set with "custom date format failed ##3" + assert {_date5} is not set with "custom date format failed" diff --git a/src/test/skript/tests/regressions/4769-fire-visualeffect.sk b/src/test/skript/tests/regressions/4769-fire-visualeffect.sk index 3965e6c877f..c490fa9e9cb 100644 --- a/src/test/skript/tests/regressions/4769-fire-visualeffect.sk +++ b/src/test/skript/tests/regressions/4769-fire-visualeffect.sk @@ -8,8 +8,8 @@ test "fire visual effect comparison": set block at spawn of world "world" to {_block} play 5 fire at spawn of world "world" assert "fire" parsed as visual effect is fire with "failed to compare visual effects" - assert "fire" parsed as visual effect is "fire" parsed as itemtype to fail with "failed to compare visual effects ##2" + assert "fire" parsed as visual effect is "fire" parsed as itemtype to fail with "failed to compare visual effects" spawn a chicken at spawn of world "world": assert event-entity is a chicken with "failed to compare a chicken" - assert event-entity is a "chicken" parsed as itemtype to fail with "failed to compare a chicken ##2" + assert event-entity is a "chicken" parsed as itemtype to fail with "failed to compare a chicken" clear event-entity diff --git a/src/test/skript/tests/regressions/535-math is done in the wrong order.sk b/src/test/skript/tests/regressions/535-math is done in the wrong order.sk index 665ce0346f8..b404c89846d 100644 --- a/src/test/skript/tests/regressions/535-math is done in the wrong order.sk +++ b/src/test/skript/tests/regressions/535-math is done in the wrong order.sk @@ -1,10 +1,10 @@ test "math order": - assert 1 + 1 = 2 with "basic math ##1 failed" - assert 5 - 3 = 2 with "basic math ##2 failed" + assert 1 + 1 = 2 with "basic math failed" + assert 5 - 3 = 2 with "basic math failed" - assert 5 - 3 - 1 = 1 with "basic chained math ##1 failed" - assert 5-3-2 = 0 with "basic chained math ##2 failed" - assert 10 - 1 - 5 = 4 with "basic chained math ##3 failed" + assert 5 - 3 - 1 = 1 with "basic chained math failed" + assert 5-3-2 = 0 with "basic chained math failed" + assert 10 - 1 - 5 = 4 with "basic chained math failed" - assert (9 - 1) - 3 = 5 with "basic chained math with parentheses ##1 failed" - assert 9 - (1 - 3) = 11 with "basic chained math with parentheses ##2 failed" + assert (9 - 1) - 3 = 5 with "basic chained math with parentheses failed" + assert 9 - (1 - 3) = 11 with "basic chained math with parentheses failed" diff --git a/src/test/skript/tests/regressions/590-escaping quotes is required in some places it shouldn't be.sk b/src/test/skript/tests/regressions/590-escaping quotes is required in some places it shouldn't be.sk index cfa2aaa63e9..f0b63a43f23 100644 --- a/src/test/skript/tests/regressions/590-escaping quotes is required in some places it shouldn't be.sk +++ b/src/test/skript/tests/regressions/590-escaping quotes is required in some places it shouldn't be.sk @@ -8,8 +8,8 @@ test "double quote parsing": assert "Testing """ is set with "simple string with escaped quote failed" - assert "Testing %length of "abc"%" is set with "string with expression with string ##1 failed" - assert "%myFunction_five_nine_zero("Hello")% world" is "Hello world" with "string with expression with string ##2 failed" + assert "Testing %length of "abc"%" is set with "string with expression with string failed" + assert "%myFunction_five_nine_zero("Hello")% world" is "Hello world" with "string with expression with string failed" assert {_abc} is not set with "simple variable failed" diff --git a/src/test/skript/tests/regressions/837-getting a uuid of a var inside code.sk b/src/test/skript/tests/regressions/837-getting a uuid of a var inside code.sk index 1da43a1f75d..e05e22b9639 100644 --- a/src/test/skript/tests/regressions/837-getting a uuid of a var inside code.sk +++ b/src/test/skript/tests/regressions/837-getting a uuid of a var inside code.sk @@ -2,8 +2,8 @@ test "variable parsing": assert {_test::%{_x}%} is not set with "simple list index using local variable failed" assert {_test::{_x}} is not set to fail with "list index with local variable without percentage signs failed" - assert {_test::%uuid of {_x}%} is not set with "list index with expression and local variable ##1 failed" - assert {_test::%{_x}'s uuid%} is not set with "list index with expression and local variable ##2 failed" + assert {_test::%uuid of {_x}%} is not set with "list index with expression and local variable failed" + assert {_test::%{_x}'s uuid%} is not set with "list index with expression and local variable failed" assert {_test::%{_a} split at {_b}%} is not set with "list index with expression with local variables on both ends failed" diff --git a/src/test/skript/tests/syntaxes/conditions/CondContains.sk b/src/test/skript/tests/syntaxes/conditions/CondContains.sk index e076c90f83f..fcc247bb7c0 100644 --- a/src/test/skript/tests/syntaxes/conditions/CondContains.sk +++ b/src/test/skript/tests/syntaxes/conditions/CondContains.sk @@ -1,34 +1,34 @@ test "contains condition": # Strings - assert "abc" contains "b" with "simple string contains failed ##1" - assert "abc" contains "abc" with "simple string contains failed ##2" - assert "abc" and "cde" contain "c" with "simple string contains failed ##3" - assert "abc" does not contain "d" with "simple string contains failed ##4" - assert "abc" and "def" do not contain "ghi" with "simple string contains failed ##5" - assert "abc" and "def" does not contain "ab" with "string object failed ##6" + assert "abc" contains "b" with "simple string contains failed" + assert "abc" contains "abc" with "simple string contains failed" + assert "abc" and "cde" contain "c" with "simple string contains failed" + assert "abc" does not contain "d" with "simple string contains failed" + assert "abc" and "def" do not contain "ghi" with "simple string contains failed" + assert "abc" and "def" does not contain "ab" with "string object failed" # Objects - assert "abc" and "def" contains "abc" with "object contains failed ##1" - assert 123 and 456 contains 456 with "object contains failed ##2" - assert 123 and 456 does not contain 789 with "object contains failed ##3" - assert 123 contains 123 with "object contains failed ##4" + assert "abc" and "def" contains "abc" with "object contains failed" + assert 123 and 456 contains 456 with "object contains failed" + assert 123 and 456 does not contain 789 with "object contains failed" + assert 123 contains 123 with "object contains failed" set {_l::*} to 5 times - assert {_l::*} contains 5 with "object contains failed ##5" - assert {_l::*} does not contain 6 with "object contains failed ##6" + assert {_l::*} contains 5 with "object contains failed" + assert {_l::*} does not contain 6 with "object contains failed" # Inventory set {_inv} to chest inventory with 3 rows set slot 0 of {_inv} to stone named "pp" set slot 1 of {_inv} to dirt - assert {_inv} contains stone with "inventory contains failed ##1" - assert {_inv} contains stone named "pp" with "inventory contains failed ##2" - assert {_inv} does not contain stone named "abc" with "inventory contains failed ##3" - assert {_inv} does not contain sand with "inventory contains failed ##4" - assert {_inv} contains dirt with "inventory contains failed ##5" - assert {_inv} does not contain 2 dirt with "inventory contains failed ##6" + assert {_inv} contains stone with "inventory contains failed" + assert {_inv} contains stone named "pp" with "inventory contains failed" + assert {_inv} does not contain stone named "abc" with "inventory contains failed" + assert {_inv} does not contain sand with "inventory contains failed" + assert {_inv} contains dirt with "inventory contains failed" + assert {_inv} does not contain 2 dirt with "inventory contains failed" set slot 2 of {_inv} to dirt - assert {_inv} contains 2 dirt with "inventory contains failed ##7" - assert {_inv} does not contain 3 dirt with "inventory contains failed ##8" + assert {_inv} contains 2 dirt with "inventory contains failed" + assert {_inv} does not contain 3 dirt with "inventory contains failed" set {_inv1} to chest inventory with 3 rows set {_inv2} to chest inventory with 3 rows diff --git a/src/test/skript/tests/syntaxes/conditions/CondIsWithin.sk b/src/test/skript/tests/syntaxes/conditions/CondIsWithin.sk index a0c4339f556..b432c72f0ff 100644 --- a/src/test/skript/tests/syntaxes/conditions/CondIsWithin.sk +++ b/src/test/skript/tests/syntaxes/conditions/CondIsWithin.sk @@ -2,32 +2,32 @@ test "within condition" when running minecraft "1.17": # two locations set {_loc1} to location(0, 0, 0, "world") set {_loc2} to location(20, 20, 20, "world") - assert location(10, 10, 10, "world") is within {_loc1} and {_loc2} with "failed within two locs ##1" - assert location(10, -10, 10, "world") is not within {_loc1} and {_loc2} with "failed within two locs ##2" + assert location(10, 10, 10, "world") is within {_loc1} and {_loc2} with "failed within two locs" + assert location(10, -10, 10, "world") is not within {_loc1} and {_loc2} with "failed within two locs" # chunks set {_chunk1} to chunk at {_loc1} - assert location(10, 10, 10, "world") is within {_chunk1} with "failed within chunk ##1" - assert location(-10, 10, -10, "world") is not within {_chunk1} with "failed within chunk ##2" + assert location(10, 10, 10, "world") is within {_chunk1} with "failed within chunk" + assert location(-10, 10, -10, "world") is not within {_chunk1} with "failed within chunk" # worlds - assert location(10, 10, 10, "world") is within world("world") with "failed within world ##1" + assert location(10, 10, 10, "world") is within world("world") with "failed within world" # blocks set block at {_loc1} to stone - assert {_loc1} is within block at {_loc1} with "failed within block ##1" - assert {_loc2} is not within block at {_loc1} with "failed within block ##2" + assert {_loc1} is within block at {_loc1} with "failed within block" + assert {_loc2} is not within block at {_loc1} with "failed within block" # special case, non-full blocks set block at {_loc1} to lime carpet - assert {_loc1} is within block at {_loc1} with "failed within block ##3" - assert ({_loc1} ~ vector(0,0.3,0)) is not within block at {_loc1} with "failed within block ##4" + assert {_loc1} is within block at {_loc1} with "failed within block" + assert ({_loc1} ~ vector(0,0.3,0)) is not within block at {_loc1} with "failed within block" # entities set {_loc} to spawn of world "world" spawn a pig at {_loc} set {_pig} to last spawned entity - assert {_loc} is within {_pig} with "failed within entity ##1" - assert {_loc1} is not within {_pig} with "failed within entity ##2" + assert {_loc} is within {_pig} with "failed within entity" + assert {_loc1} is not within {_pig} with "failed within entity" delete random entity of {_pig} @@ -35,22 +35,22 @@ test "within condition" when running below minecraft "1.17": # two locations set {_loc1} to location(0, 0, 0, "world") set {_loc2} to location(20, 20, 20, "world") - assert location(10, 10, 10, "world") is within {_loc1} and {_loc2} with "failed within two locs ##1" - assert location(10, -10, 10, "world") is not within {_loc1} and {_loc2} with "failed within two locs ##2" + assert location(10, 10, 10, "world") is within {_loc1} and {_loc2} with "failed within two locs" + assert location(10, -10, 10, "world") is not within {_loc1} and {_loc2} with "failed within two locs" # chunks set {_chunk1} to chunk at {_loc1} - assert location(10, 10, 10, "world") is within {_chunk1} with "failed within chunk ##1" - assert location(-10, 10, -10, "world") is not within {_chunk1} with "failed within chunk ##2" + assert location(10, 10, 10, "world") is within {_chunk1} with "failed within chunk" + assert location(-10, 10, -10, "world") is not within {_chunk1} with "failed within chunk" # worlds - assert location(10, 10, 10, "world") is within world("world") with "failed within world ##1" + assert location(10, 10, 10, "world") is within world("world") with "failed within world" # entities set {_loc} to spawn of world "world" spawn a pig at {_loc} set {_pig} to last spawned entity - assert {_loc} is within {_pig} with "failed within entity ##1" - assert {_loc1} is not within {_pig} with "failed within entity ##2" + assert {_loc} is within {_pig} with "failed within entity" + assert {_loc1} is not within {_pig} with "failed within entity" delete random entity of {_pig} diff --git a/src/test/skript/tests/syntaxes/conditions/CondMethodExists.sk b/src/test/skript/tests/syntaxes/conditions/CondMethodExists.sk index e34bac7daac..538f8f5be04 100644 --- a/src/test/skript/tests/syntaxes/conditions/CondMethodExists.sk +++ b/src/test/skript/tests/syntaxes/conditions/CondMethodExists.sk @@ -1,10 +1,10 @@ test "method exists": - assert method "java.lang.String##length()" exists with "Existing method was not found" - assert method "java.lang.String##notReal()" doesn't exist with "Fake method was found" - assert method "java.lang.SuperFakeClass##notReal()" doesn't exist with "Fake class was found" - assert method "java.lang.String##indexOf(java.lang.String)" exists with "Existing method with parameter was not found" - assert method "java.lang.String##replace(java.lang.CharSequence,java.lang.CharSequence)" exists with "Existing method with multiple parameters not found" - assert method "java.lang.String##charAt(int)" exists with "Existing method with primitive parameter not found" - assert method "java.lang.String##substring(int,int)" exists with "Existing method with multiple primitive parameters not found" - assert method "java.lang.String##valueOf(char[])" exists with "Existing method with primitive array parameter not found" - assert method "java.lang.Runtime##exec(java.lang.String[],java.lang.String[])" exists with "Existing method with array parameter not found" + assert method "java.lang.String#length()" exists with "Existing method was not found" + assert method "java.lang.String#notReal()" doesn't exist with "Fake method was found" + assert method "java.lang.SuperFakeClass#notReal()" doesn't exist with "Fake class was found" + assert method "java.lang.String#indexOf(java.lang.String)" exists with "Existing method with parameter was not found" + assert method "java.lang.String#replace(java.lang.CharSequence,java.lang.CharSequence)" exists with "Existing method with multiple parameters not found" + assert method "java.lang.String#charAt(int)" exists with "Existing method with primitive parameter not found" + assert method "java.lang.String#substring(int,int)" exists with "Existing method with multiple primitive parameters not found" + assert method "java.lang.String#valueOf(char[])" exists with "Existing method with primitive array parameter not found" + assert method "java.lang.Runtime#exec(java.lang.String[],java.lang.String[])" exists with "Existing method with array parameter not found" diff --git a/src/test/skript/tests/syntaxes/effects/EffContinue.sk b/src/test/skript/tests/syntaxes/effects/EffContinue.sk index 83804bc908f..2400e7441e0 100644 --- a/src/test/skript/tests/syntaxes/effects/EffContinue.sk +++ b/src/test/skript/tests/syntaxes/effects/EffContinue.sk @@ -11,9 +11,9 @@ test "continue effect": assert {_i} is not 5 with "continue in while failed" loop integers from 1 to 10: continue this loop if loop-value is 5 - assert loop-value is not 5 with "leveled continue failed ##1" + assert loop-value is not 5 with "leveled continue failed" loop integers from 11 to 20: continue 2nd loop if loop-value-2 is 15 - assert loop-value-2 is not 15 with "leveled continue failed ##2" + assert loop-value-2 is not 15 with "leveled continue failed" continue 1st loop if loop-value-1 is 10 - assert loop-value is not 10 with "leveled continue failed ##3" + assert loop-value is not 10 with "leveled continue failed" diff --git a/src/test/skript/tests/syntaxes/effects/EffHealth.sk b/src/test/skript/tests/syntaxes/effects/EffHealth.sk index 41ecf33904b..b77c566076b 100644 --- a/src/test/skript/tests/syntaxes/effects/EffHealth.sk +++ b/src/test/skript/tests/syntaxes/effects/EffHealth.sk @@ -11,13 +11,13 @@ test "health effect": set {_m} to last spawned cow assert health of {_m} is 5 with "default cow health failed" damage {_m} by 0.5 - assert health of {_m} is 4.5 with "damage cow ##1 failed" + assert health of {_m} is 4.5 with "damage cow failed" damage {_m} by 99 - assert health of {_m} is 0 with "damage cow ##2 failed" + assert health of {_m} is 0 with "damage cow failed" heal {_m} by 1 - assert health of {_m} is 1 with "heal cow ##1 failed" + assert health of {_m} is 1 with "heal cow failed" heal {_m} by 0.5 - assert health of {_m} is 1.5 with "heal cow ##2 failed" + assert health of {_m} is 1.5 with "heal cow failed" heal {_m} by 99 - assert health of {_m} is 5 with "heal cow ##3 failed" + assert health of {_m} is 5 with "heal cow failed" clear all entities diff --git a/src/test/skript/tests/syntaxes/expressions/ExprArrowsStuck.sk b/src/test/skript/tests/syntaxes/expressions/ExprArrowsStuck.sk index 9b41359b7af..aa577e45d4c 100644 --- a/src/test/skript/tests/syntaxes/expressions/ExprArrowsStuck.sk +++ b/src/test/skript/tests/syntaxes/expressions/ExprArrowsStuck.sk @@ -4,15 +4,15 @@ test "arrows stuck": set arrows stuck in event-entity to 31 assert arrows stuck in event-entity is 31 with "arrows stuck set failed" add 5 to arrows stuck in event-entity - assert arrows stuck in event-entity is 36 with "arrows stuck add ##1 failed" + assert arrows stuck in event-entity is 36 with "arrows stuck add failed" remove 10 from arrows stuck in event-entity - assert arrows stuck in event-entity is 26 with "arrows stuck remove ##1 failed" + assert arrows stuck in event-entity is 26 with "arrows stuck remove failed" remove 999 from arrows stuck in event-entity - assert arrows stuck in event-entity is 0 with "arrows stuck remove ##2 failed" + assert arrows stuck in event-entity is 0 with "arrows stuck remove failed" remove -2 from arrows stuck in event-entity - assert arrows stuck in event-entity is 2 with "arrows stuck remove ##3 failed" + assert arrows stuck in event-entity is 2 with "arrows stuck remove failed" add -1 to arrows stuck in event-entity - assert arrows stuck in event-entity is 1 with "arrows stuck add ##2 failed" + assert arrows stuck in event-entity is 1 with "arrows stuck add failed" delete arrows stuck in event-entity assert arrows stuck in event-entity is 0 with "arrows stuck delete failed" delete event-entity diff --git a/src/test/skript/tests/syntaxes/expressions/ExprEntityAttribute.sk b/src/test/skript/tests/syntaxes/expressions/ExprEntityAttribute.sk index 730afc9d164..ed04483dbe0 100644 --- a/src/test/skript/tests/syntaxes/expressions/ExprEntityAttribute.sk +++ b/src/test/skript/tests/syntaxes/expressions/ExprEntityAttribute.sk @@ -6,9 +6,9 @@ test "attributes 1": add 5 to movement speed attribute of event-entity assert movement speed attribute of event-entity is 8.14 with "attribute add failed" remove 4 from movement speed attribute of event-entity - assert movement speed attribute of event-entity is 4.14 with "attribute remove ##1 failed" + assert movement speed attribute of event-entity is 4.14 with "attribute remove failed" remove 10 from movement speed attribute of event-entity - assert movement speed attribute of event-entity is -5.86 with "attribute remove ##2 failed" # Negative attribute values should be safe + assert movement speed attribute of event-entity is -5.86 with "attribute remove failed" # Negative attribute values should be safe delete movement speed attribute of event-entity assert movement speed attribute of event-entity is 0 with "attribute delete failed" delete event-entity diff --git a/src/test/skript/tests/syntaxes/expressions/ExprFreezeTicks.sk b/src/test/skript/tests/syntaxes/expressions/ExprFreezeTicks.sk index c6e47ec617e..7caec6fcb3f 100644 --- a/src/test/skript/tests/syntaxes/expressions/ExprFreezeTicks.sk +++ b/src/test/skript/tests/syntaxes/expressions/ExprFreezeTicks.sk @@ -4,14 +4,14 @@ test "freeze time" when running minecraft "1.18": set freeze time of entity to 3 seconds assert freeze time of entity is 3 seconds with "freeze time set failed" add 2 seconds to freeze time of entity - assert freeze time of entity is 5 seconds with "freeze time add ##1 failed" + assert freeze time of entity is 5 seconds with "freeze time add failed" add 10 seconds to freeze time of entity - assert freeze time of entity is 15 seconds with "freeze time add ##2 failed" # freeze time should not be capped at entity's max freeze time (7 seconds for a cow) + assert freeze time of entity is 15 seconds with "freeze time add failed" # freeze time should not be capped at entity's max freeze time (7 seconds for a cow) remove 6 seconds from freeze time of entity - assert freeze time of entity is 9 seconds with "freeze time remove ##1 failed" + assert freeze time of entity is 9 seconds with "freeze time remove failed" remove 10 seconds from freeze time of entity - assert freeze time of entity is 0 seconds with "freeze time remove ##2 failed" # freeze time should not be negative + assert freeze time of entity is 0 seconds with "freeze time remove failed" # freeze time should not be negative delete freeze time of entity assert freeze time of entity is 0 seconds with "freeze time delete failed" diff --git a/src/test/skript/tests/syntaxes/expressions/ExprItemsIn.sk b/src/test/skript/tests/syntaxes/expressions/ExprItemsIn.sk index 9b2c90fb25f..b5ef324b555 100644 --- a/src/test/skript/tests/syntaxes/expressions/ExprItemsIn.sk +++ b/src/test/skript/tests/syntaxes/expressions/ExprItemsIn.sk @@ -5,8 +5,8 @@ test "filtering ExprItemsIn": set slot 1 of {_inv} to dirt set slot 2 of {_inv} to stone set slot 3 of {_inv} to bucket - assert all blocks in inventory {_inv} are dirt or stone with "found correct items with ExprItemsIn##get" - assert (all blocks in inventory {_inv} where [true is true]) are dirt or stone with "found correct items with ExprItemsIn##iterator" + assert all blocks in inventory {_inv} are dirt or stone with "found correct items with ExprItemsIn#get" + assert (all blocks in inventory {_inv} where [true is true]) are dirt or stone with "found correct items with ExprItemsIn#iterator" set {_dirt} to dirt assert all {_dirt} in inventory {_inv} is dirt with "found incorrect items with variable itemtypes" @@ -17,5 +17,5 @@ test "unfiltered ExprItemsIn": set slot 1 of {_inv} to dirt set slot 2 of {_inv} to stone set slot 3 of {_inv} to bucket - assert all items in inventory {_inv} are dirt, stone or bucket with "found correct items with ExprItemsIn##get" - assert (all items in inventory {_inv} where [true is true]) are dirt, stone or bucket with "found correct items with ExprItemsIn##iterator" + assert all items in inventory {_inv} are dirt, stone or bucket with "found correct items with ExprItemsIn#get" + assert (all items in inventory {_inv} where [true is true]) are dirt, stone or bucket with "found correct items with ExprItemsIn#iterator" diff --git a/src/test/skript/tests/syntaxes/expressions/ExprNoDamageTicks.sk b/src/test/skript/tests/syntaxes/expressions/ExprNoDamageTicks.sk index 794dffa6e87..2d314c9e6d2 100644 --- a/src/test/skript/tests/syntaxes/expressions/ExprNoDamageTicks.sk +++ b/src/test/skript/tests/syntaxes/expressions/ExprNoDamageTicks.sk @@ -5,14 +5,14 @@ test "no damage ticks": set {_m}'s invulnerability ticks to 25 assert {_m}'s invulnerability ticks is 25 with "no damage ticks set failed" add 5 to {_m}'s invulnerability ticks - assert {_m}'s invulnerability ticks is 30 with "no damage ticks add ##1 failed" + assert {_m}'s invulnerability ticks is 30 with "no damage ticks add failed" remove 12 from {_m}'s invulnerability ticks - assert {_m}'s invulnerability ticks is 18 with "no damage ticks remove ##1 failed" + assert {_m}'s invulnerability ticks is 18 with "no damage ticks remove failed" remove 999 from {_m}'s invulnerability ticks - assert {_m}'s invulnerability ticks is 0 with "no damage ticks remove ##2 failed" + assert {_m}'s invulnerability ticks is 0 with "no damage ticks remove failed" remove -2 from {_m}'s invulnerability ticks - assert {_m}'s invulnerability ticks is 2 with "no damage ticks remove ##3 failed" + assert {_m}'s invulnerability ticks is 2 with "no damage ticks remove failed" add -1 to {_m}'s invulnerability ticks - assert {_m}'s invulnerability ticks is 1 with "no damage ticks add ##2 failed" + assert {_m}'s invulnerability ticks is 1 with "no damage ticks add failed" delete {_m}'s invulnerability ticks assert {_m}'s invulnerability ticks is 0 with "no damage ticks delete failed" diff --git a/src/test/skript/tests/syntaxes/expressions/ExprPortalCooldown.sk b/src/test/skript/tests/syntaxes/expressions/ExprPortalCooldown.sk index 7d919d788da..36b95564dc7 100644 --- a/src/test/skript/tests/syntaxes/expressions/ExprPortalCooldown.sk +++ b/src/test/skript/tests/syntaxes/expressions/ExprPortalCooldown.sk @@ -4,11 +4,11 @@ test "portal cooldown": set event-entity's portal cooldown to 25 ticks assert event-entity's portal cooldown is 25 ticks with "portal cooldown set failed" add 5 seconds to event-entity's portal cooldown - assert event-entity's portal cooldown is 125 ticks with "portal cooldown add ##1 failed" + assert event-entity's portal cooldown is 125 ticks with "portal cooldown add failed" remove 12 ticks from event-entity's portal cooldown - assert event-entity's portal cooldown is 113 ticks with "portal cooldown remove ##1 failed" + assert event-entity's portal cooldown is 113 ticks with "portal cooldown remove failed" remove 999 ticks from event-entity's portal cooldown - assert event-entity's portal cooldown is 0 ticks with "portal cooldown remove ##2 failed" + assert event-entity's portal cooldown is 0 ticks with "portal cooldown remove failed" delete event-entity's portal cooldown assert event-entity's portal cooldown is 0 ticks with "portal cooldown delete failed" reset event-entity's portal cooldown diff --git a/src/test/skript/tests/syntaxes/functions/caseEquals.sk b/src/test/skript/tests/syntaxes/functions/caseEquals.sk index f777e6ff7df..ace8276da6e 100644 --- a/src/test/skript/tests/syntaxes/functions/caseEquals.sk +++ b/src/test/skript/tests/syntaxes/functions/caseEquals.sk @@ -1,6 +1,6 @@ test "case equals function": - assert caseEquals("") is true with "case equals function failed ##1" - assert caseEquals("dummy") is true with "case equals function failed ##2" - assert caseEquals("hi", "Hi") is false with "case equals function failed ##3" - assert caseEquals("text", "text", "tExt") is false with "case equals function failed ##4" - assert caseEquals("🐢<-turtle", "🐢<-turtle", "🐢<-turtle", "🐢<-turtle") is true with "case equals function failed ##5" + assert caseEquals("") is true with "case equals function failed" + assert caseEquals("dummy") is true with "case equals function failed" + assert caseEquals("hi", "Hi") is false with "case equals function failed" + assert caseEquals("text", "text", "tExt") is false with "case equals function failed" + assert caseEquals("🐢<-turtle", "🐢<-turtle", "🐢<-turtle", "🐢<-turtle") is true with "case equals function failed" diff --git a/src/test/skript/tests/syntaxes/sections/SecConditional.sk b/src/test/skript/tests/syntaxes/sections/SecConditional.sk index f9991e9f621..4957319f369 100644 --- a/src/test/skript/tests/syntaxes/sections/SecConditional.sk +++ b/src/test/skript/tests/syntaxes/sections/SecConditional.sk @@ -18,18 +18,18 @@ test "SecConditional": delete {_b} 1 = 2 else if 1 = 1: - assert 1 = 2 with "conditional failed ##1" + assert 1 = 2 with "conditional failed" else: - assert 1 = 2 with "conditional failed ##2" + assert 1 = 2 with "conditional failed" if {_b} is set: - assert 1 = 2 with "conditional failed ##3" + assert 1 = 2 with "conditional failed" if 1 = 2: - assert 1 = 2 with "conditional failed ##4" + assert 1 = 2 with "conditional failed" else if 1 = 1: exit 1 section else: - assert 1 = 2 with "conditional failed ##5" + assert 1 = 2 with "conditional failed" test "SecConditional - if all true": if: From 585e8d15be016f9a87a38c59cd7f43885d5fdc57 Mon Sep 17 00:00:00 2001 From: Patrick Miller Date: Mon, 1 Jul 2024 11:54:52 -0400 Subject: [PATCH 16/27] 1.21 Support (#6798) * Update Paper API to 1.21 * Patch up aliases * Update 5491-xp orb merge overwrite.sk --------- Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com> --- build.gradle | 4 +- gradle.properties | 2 +- .../njol/skript/aliases/AliasesProvider.java | 11 ++- .../java/ch/njol/skript/aliases/ItemData.java | 98 +++++++++++-------- .../java/ch/njol/skript/aliases/ItemType.java | 36 +++++-- .../skript/bukkitutil/block/BlockCompat.java | 3 + .../bukkitutil/block/NewBlockCompat.java | 7 ++ .../skript/classes/data/BukkitClasses.java | 1 + .../environments/java21/paper-1.21.0.json | 17 ++++ .../5491-xp orb merge overwrite.sk | 4 + .../tests/syntaxes/effects/EffGlowingText.sk | 2 +- 11 files changed, 128 insertions(+), 57 deletions(-) create mode 100644 src/test/skript/environments/java21/paper-1.21.0.json diff --git a/build.gradle b/build.gradle index 161d3dd3daf..0826a6af81d 100644 --- a/build.gradle +++ b/build.gradle @@ -29,7 +29,7 @@ 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.6-R0.1-SNAPSHOT' + implementation group: 'io.papermc.paper', name: 'paper-api', version: '1.21-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' @@ -235,7 +235,7 @@ def java21 = 21 def java17 = 17 def java8 = 8 -def latestEnv = 'java21/paper-1.20.6.json' +def latestEnv = 'java21/paper-1.21.0.json' def latestJava = java21 def oldestJava = java8 diff --git a/gradle.properties b/gradle.properties index f78ae1766eb..469d1e072ce 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,5 +7,5 @@ groupid=ch.njol name=skript version=2.8.7 jarName=Skript.jar -testEnv=java21/paper-1.20.6 +testEnv=java21/paper-1.21.0 testEnvJavaVersion=21 diff --git a/src/main/java/ch/njol/skript/aliases/AliasesProvider.java b/src/main/java/ch/njol/skript/aliases/AliasesProvider.java index a3b8b215b75..cccf91618ed 100644 --- a/src/main/java/ch/njol/skript/aliases/AliasesProvider.java +++ b/src/main/java/ch/njol/skript/aliases/AliasesProvider.java @@ -304,16 +304,19 @@ public void addAlias(AliasName name, String id, @Nullable Map ta } // Apply (NBT) tags to item stack - ItemStack stack = new ItemStack(material); + ItemStack stack = null; int itemFlags = 0; - if (tags != null) { - itemFlags = applyTags(stack, new HashMap<>(tags)); + if (material.isItem()) { + stack = new ItemStack(material); + if (tags != null) { + itemFlags = applyTags(stack, new HashMap<>(tags)); + } } // Parse block state to block values BlockValues blockValues = BlockCompat.INSTANCE.createBlockValues(material, blockStates, stack, itemFlags); - ItemData data = new ItemData(stack, blockValues); + ItemData data = stack != null ? new ItemData(stack, blockValues) : new ItemData(material, blockValues); data.isAlias = true; data.itemFlags = itemFlags; diff --git a/src/main/java/ch/njol/skript/aliases/ItemData.java b/src/main/java/ch/njol/skript/aliases/ItemData.java index 32323c57e6f..0f68279f43a 100644 --- a/src/main/java/ch/njol/skript/aliases/ItemData.java +++ b/src/main/java/ch/njol/skript/aliases/ItemData.java @@ -37,7 +37,7 @@ import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; -import org.eclipse.jdt.annotation.Nullable; +import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.io.NotSerializableException; @@ -91,11 +91,6 @@ public static class OldItemData { @Deprecated public static final boolean itemDataValues = false; - /** - * ItemStack, which is used for everything but serialization. - */ - transient ItemStack stack; - /** * Type of the item as Bukkit material. Serialized manually. */ @@ -105,14 +100,18 @@ public static class OldItemData { * If this represents all possible items. */ boolean isAnything; - + + /** + * ItemStack, which is used for everything but serialization. + */ + transient @Nullable ItemStack stack; + /** * When this ItemData represents a block, this contains information to * allow comparing it against other blocks. */ - @Nullable - BlockValues blockValues; - + @Nullable BlockValues blockValues; + /** * Whether this represents an item (that definitely cannot have * block states) or a block, which might have them. @@ -140,9 +139,10 @@ public static class OldItemData { public ItemData(Material type, @Nullable String tags) { this.type = type; - - this.stack = new ItemStack(type); - this.blockValues = BlockCompat.INSTANCE.getBlockValues(stack); + + if (type.isItem()) + this.stack = new ItemStack(type); + this.blockValues = BlockCompat.INSTANCE.getBlockValues(type); if (tags != null) { applyTags(tags); } @@ -150,8 +150,9 @@ public ItemData(Material type, @Nullable String tags) { public ItemData(Material type, int amount) { this.type = type; - this.stack = new ItemStack(type, Math.abs(amount)); - this.blockValues = BlockCompat.INSTANCE.getBlockValues(stack); + if (type.isItem()) + this.stack = new ItemStack(type, Math.abs(amount)); + this.blockValues = BlockCompat.INSTANCE.getBlockValues(type); } public ItemData(Material type) { @@ -159,13 +160,18 @@ public ItemData(Material type) { } public ItemData(ItemData data) { - this.stack = data.stack.clone(); + this.stack = data.stack != null ? data.stack.clone() : null; this.type = data.type; this.blockValues = data.blockValues; this.isAlias = data.isAlias; this.plain = data.plain; this.itemFlags = data.itemFlags; } + + public ItemData(Material material, @Nullable BlockValues values) { + this.type = material; + this.blockValues = values; + } public ItemData(ItemStack stack, @Nullable BlockValues values) { this.stack = stack; @@ -200,7 +206,8 @@ public ItemData(BlockState blockState) { public ItemData(BlockData blockData) { this.type = blockData.getMaterial(); - this.stack = new ItemStack(type); + if (type.isItem()) + this.stack = new ItemStack(type); this.blockValues = BlockCompat.INSTANCE.getBlockValues(blockData); } @@ -227,13 +234,12 @@ public boolean isOfType(@Nullable ItemStack item) { if (type != item.getType()) return false; // Obvious mismatch - if (itemFlags != 0) { // Either stack has tags (or durability) + if (stack != null && itemFlags != 0) { // Either stack has tags (or durability) if (ItemUtils.getDamage(stack) != ItemUtils.getDamage(item)) return false; // On 1.12 and below, damage is not in meta if (stack.hasItemMeta() == item.hasItemMeta()) // Compare ItemMeta as in isSimilar() of ItemStack - return stack.hasItemMeta() ? itemFactory.equals(stack.getItemMeta(), item.getItemMeta()) : true; - else - return false; + return !stack.hasItemMeta() || itemFactory.equals(stack.getItemMeta(), item.getItemMeta()); + return false; } return true; } @@ -249,7 +255,7 @@ public String toString() { public String toString(final boolean debug, final boolean plural) { StringBuilder builder = new StringBuilder(Aliases.getMaterialName(this, plural)); - ItemMeta meta = stack.getItemMeta(); + ItemMeta meta = stack != null ? stack.getItemMeta() : null; if (meta != null && meta.hasDisplayName()) { builder.append(" ").append(m_named).append(" "); builder.append(meta.getDisplayName()); @@ -282,7 +288,7 @@ public boolean equals(final @Nullable Object obj) { @Override public int hashCode() { int hash = type.hashCode(); // Has collisions, but probably not too many of them - if (blockValues == null || (blockValues != null && blockValues.isDefault())) { + if (blockValues == null || blockValues.isDefault()) { hash = hash * 37 + 1; } return hash; @@ -351,7 +357,7 @@ public MatchQuality matchAlias(ItemData item) { } // See if we need to compare item metas (excluding durability) - if (quality.isAtLeast(MatchQuality.SAME_ITEM) && stack.hasItemMeta() || item.stack.hasItemMeta()) { // Item meta checks could lower this + if (quality.isAtLeast(MatchQuality.SAME_ITEM) && this.hasItemMeta() || item.hasItemMeta()) { // Item meta checks could lower this MatchQuality metaQuality = compareItemMetas(getItemMeta(), item.getItemMeta()); // If given item doesn't care about meta, promote to SAME_ITEM @@ -489,9 +495,13 @@ public ItemData intersection(final ItemData other) { * It is not a copy, so please be careful. * @return Item stack. */ - public ItemStack getStack() { + public @Nullable ItemStack getStack() { return stack; } + + private boolean hasItemMeta() { + return stack != null && stack.hasItemMeta(); + } @Override public ItemData clone() { @@ -508,7 +518,7 @@ public BlockValues getBlockValues() { } public ItemMeta getItemMeta() { - ItemMeta meta = stack.getItemMeta(); + ItemMeta meta = stack != null ? stack.getItemMeta() : null; if (meta == null) { // AIR has null item meta! meta = itemFactory.getItemMeta(Material.STONE); } @@ -517,6 +527,8 @@ public ItemMeta getItemMeta() { } public void setItemMeta(ItemMeta meta) { + if (stack == null) + return; stack.setItemMeta(meta); isAlias = false; // This is no longer exact alias plain = false; // This is no longer a plain item @@ -524,10 +536,14 @@ public void setItemMeta(ItemMeta meta) { } public int getDurability() { + if (stack == null) + return 0; // no damage? return ItemUtils.getDamage(stack); } public void setDurability(int durability) { + if (stack == null) + return; ItemUtils.setDamage(stack, durability); isAlias = false; // Change happened plain = false; // This is no longer a plain item @@ -567,7 +583,7 @@ public boolean matchPlain(ItemData other) { public Fields serialize() throws NotSerializableException { Fields fields = new Fields(this); // ItemStack is transient, will be ignored fields.putPrimitive("id", type.ordinal()); - fields.putObject("meta", stack.getItemMeta()); + fields.putObject("meta", stack != null ? stack.getItemMeta() : null); return fields; } @@ -579,8 +595,10 @@ public void deserialize(Fields fields) throws StreamCorruptedException, NotSeria ItemMeta meta = fields.getAndRemoveObject("meta", ItemMeta.class); // Initialize ItemStack - this.stack = new ItemStack(type); - stack.setItemMeta(meta); // Just set meta to it + if (meta != null && type.isItem()) { + this.stack = new ItemStack(type); + stack.setItemMeta(meta); // Just set meta to it + } fields.setFields(this); // Everything but ItemStack and Material } @@ -598,17 +616,17 @@ public void deserialize(Fields fields) throws StreamCorruptedException, NotSeria */ public ItemData aliasCopy() { ItemData data = new ItemData(); - data.stack = new ItemStack(type, 1); - - if (stack.hasItemMeta()) { - ItemMeta meta = stack.getItemMeta(); // Creates a copy - meta.setDisplayName(null); // Clear display name - if (!itemFactory.getItemMeta(type).equals(meta)) // there may be different tags (e.g. potions) - data.itemFlags |= ItemFlags.CHANGED_TAGS; - data.stack.setItemMeta(meta); + if (stack != null) { + data.stack = new ItemStack(type, 1); + if (stack.hasItemMeta()) { + ItemMeta meta = stack.getItemMeta(); // Creates a copy + meta.setDisplayName(null); // Clear display name + if (!itemFactory.getItemMeta(type).equals(meta)) // there may be different tags (e.g. potions) + data.itemFlags |= ItemFlags.CHANGED_TAGS; + data.stack.setItemMeta(meta); + } + ItemUtils.setDamage(data.stack, 0); // Set to undamaged } - ItemUtils.setDamage(data.stack, 0); // Set to undamaged - data.type = type; data.blockValues = blockValues; data.itemForm = itemForm; @@ -620,6 +638,8 @@ public ItemData aliasCopy() { * @param tags Tags in Mojang's JSON format. */ public void applyTags(String tags) { + if (stack == null) + return; BukkitUnsafe.modifyItemStack(stack, tags); itemFlags |= ItemFlags.CHANGED_TAGS; } diff --git a/src/main/java/ch/njol/skript/aliases/ItemType.java b/src/main/java/ch/njol/skript/aliases/ItemType.java index 7341667fa91..0b47617ef5c 100644 --- a/src/main/java/ch/njol/skript/aliases/ItemType.java +++ b/src/main/java/ch/njol/skript/aliases/ItemType.java @@ -68,6 +68,7 @@ import java.util.Random; import java.util.RandomAccess; import java.util.Set; +import java.util.stream.Collectors; @ContainerType(ItemStack.class) public class ItemType implements Unit, Iterable, Container, YggdrasilExtendedSerializable { @@ -315,7 +316,7 @@ public boolean isOfType(Material id, @Nullable String tags) { public boolean isOfType(Material id) { // TODO avoid object creation - return isOfType(new ItemData(id, null)); + return isOfType(new ItemData(id, (String) null)); } /** @@ -343,7 +344,7 @@ public ItemType getBlock() { */ public boolean hasItem() { for (ItemData d : types) { - if (!d.type.isBlock()) + if (d.type.isItem()) return true; } return false; @@ -487,9 +488,13 @@ public boolean hasNext() { @Override public ItemStack next() { - if (!hasNext()) - throw new NoSuchElementException(); - ItemStack is = iter.next().getStack().clone(); + ItemStack is = null; + while (is == null) { + if (!hasNext()) + throw new NoSuchElementException(); + is = iter.next().getStack(); + } + is = is.clone(); is.setAmount(getAmount()); return is; } @@ -588,10 +593,17 @@ public ItemType clone() { * @see #removeFrom(ItemStack) * @see #removeFrom(List...) */ - public ItemStack getRandom() { - int numItems = types.size(); + public @Nullable ItemStack getRandom() { + List datas = types.stream() + .filter(data -> data.stack != null) + .collect(Collectors.toList()); + if (datas.isEmpty()) + return null; + int numItems = datas.size(); int index = random.nextInt(numItems); - ItemStack is = types.get(index).getStack().clone(); + ItemStack is = datas.get(index).getStack(); + assert is != null; // verified above + is = is.clone(); is.setAmount(getAmount()); return is; } @@ -869,7 +881,9 @@ public final boolean removeFrom(boolean replaceWithNull, List... list */ public void addTo(final List list) { if (!isAll()) { - list.add(getItem().getRandom()); + ItemStack random = getItem().getRandom(); + if (random != null) + list.add(getItem().getRandom()); return; } for (final ItemStack is : getItem().getAll()) @@ -936,7 +950,9 @@ private static boolean addTo(@Nullable ItemStack is, ItemStack[] buf) { public boolean addTo(final ItemStack[] buf) { if (!isAll()) { - return addTo(getItem().getRandom(), buf); + ItemStack random = getItem().getRandom(); + if (random != null) + return addTo(getItem().getRandom(), buf); } boolean ok = true; for (ItemStack is : getItem().getAll()) { diff --git a/src/main/java/ch/njol/skript/bukkitutil/block/BlockCompat.java b/src/main/java/ch/njol/skript/bukkitutil/block/BlockCompat.java index eef0866a01b..87bc45a6ec8 100644 --- a/src/main/java/ch/njol/skript/bukkitutil/block/BlockCompat.java +++ b/src/main/java/ch/njol/skript/bukkitutil/block/BlockCompat.java @@ -65,6 +65,9 @@ default BlockValues getBlockValues(Block block) { return getBlockValues(block.getBlockData()); } + @Nullable + BlockValues getBlockValues(Material material); + @Nullable BlockValues getBlockValues(BlockData blockData); diff --git a/src/main/java/ch/njol/skript/bukkitutil/block/NewBlockCompat.java b/src/main/java/ch/njol/skript/bukkitutil/block/NewBlockCompat.java index 2a0ecd36da8..e5cf9c0567b 100644 --- a/src/main/java/ch/njol/skript/bukkitutil/block/NewBlockCompat.java +++ b/src/main/java/ch/njol/skript/bukkitutil/block/NewBlockCompat.java @@ -336,6 +336,13 @@ public BlockValues getBlockValues(BlockState blockState) { return getBlockValues(blockState.getBlockData()); } + @Override + public @Nullable BlockValues getBlockValues(Material material) { + if (material.isBlock()) + return new NewBlockValues(material, Bukkit.createBlockData(material), false); + return null; + } + @Nullable @Override public BlockValues getBlockValues(BlockData blockData) { 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 25000a2390d..168585cf801 100644 --- a/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java +++ b/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java @@ -930,6 +930,7 @@ public String toVariableNameString(InventoryHolder holder) { .since("1.0") .after("number") .supplier(() -> Arrays.stream(Material.values()) + .filter(Material::isItem) .map(ItemStack::new) .iterator()) .parser(new Parser() { diff --git a/src/test/skript/environments/java21/paper-1.21.0.json b/src/test/skript/environments/java21/paper-1.21.0.json new file mode 100644 index 00000000000..22a72e3a73b --- /dev/null +++ b/src/test/skript/environments/java21/paper-1.21.0.json @@ -0,0 +1,17 @@ +{ + "name": "paper-1.21.0", + "resources": [ + {"source": "server.properties.generic", "target": "server.properties"} + ], + "paperDownloads": [ + { + "version": "1.21", + "target": "paperclip.jar" + } + ], + "skriptTarget": "plugins/Skript.jar", + "commandLine": [ + "-Dcom.mojang.eula.agree=true", + "-jar", "paperclip.jar", "--nogui" + ] +} diff --git a/src/test/skript/tests/regressions/5491-xp orb merge overwrite.sk b/src/test/skript/tests/regressions/5491-xp orb merge overwrite.sk index ca5b9b46d6e..c925f51c590 100644 --- a/src/test/skript/tests/regressions/5491-xp orb merge overwrite.sk +++ b/src/test/skript/tests/regressions/5491-xp orb merge overwrite.sk @@ -1,6 +1,10 @@ test "spawn xp orb overwriting merged value" when running minecraft "1.14.4": # 1.13.2 seems not to merge xp orbs in the same way, so this test is skipped + # 1.21 also does not merge orbs, so this test is disabled. + # TODO: figure out how to force the orbs to merge on 1.21+ + running below minecraft "1.21" + # sanitize kill all xp orbs set {_spawn} to spawn of world "world" diff --git a/src/test/skript/tests/syntaxes/effects/EffGlowingText.sk b/src/test/skript/tests/syntaxes/effects/EffGlowingText.sk index b43a5786755..d39b3e6988a 100644 --- a/src/test/skript/tests/syntaxes/effects/EffGlowingText.sk +++ b/src/test/skript/tests/syntaxes/effects/EffGlowingText.sk @@ -10,7 +10,7 @@ test "glowing sign blocks" when running minecraft "1.17.1": set block at {_loc} to {_original block} test "glowing sign items" when running minecraft "1.17.1": - set {_sign} to sign + set {_sign} to floor sign assert {_sign} doesn't have glowing text with "Sign had glowing text erroneously (1)" make {_sign} have glowing text assert {_sign} has glowing text with "Sign had normal text erroneously" From 2f629f138676486025729921b4fca13e60905561 Mon Sep 17 00:00:00 2001 From: Moderocky Date: Mon, 1 Jul 2024 17:23:58 +0100 Subject: [PATCH 17/27] Attempt to estimate world in teleport when it's not specified. (#6611) --- .../ch/njol/skript/effects/EffTeleport.java | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/main/java/ch/njol/skript/effects/EffTeleport.java b/src/main/java/ch/njol/skript/effects/EffTeleport.java index 3ba06d7d150..990e1aa7ec1 100644 --- a/src/main/java/ch/njol/skript/effects/EffTeleport.java +++ b/src/main/java/ch/njol/skript/effects/EffTeleport.java @@ -19,7 +19,6 @@ package ch.njol.skript.effects; import ch.njol.skript.Skript; -import ch.njol.skript.sections.EffSecSpawn; import ch.njol.skript.sections.EffSecSpawn.SpawnEvent; import ch.njol.skript.bukkitutil.EntityUtils; import ch.njol.skript.doc.Description; @@ -31,7 +30,6 @@ import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.lang.Trigger; import ch.njol.skript.lang.TriggerItem; -import ch.njol.skript.lang.TriggerSection; import ch.njol.skript.timings.SkriptTimings; import ch.njol.skript.util.Direction; import ch.njol.skript.variables.Variables; @@ -53,7 +51,7 @@ "which may cause lag spikes or server crashes when using this effect to teleport entities to unloaded chunks." }) @Examples({ - "teleport the player to {homes.%player%}", + "teleport the player to {homes::%player%}", "teleport the attacker to the victim" }) @Since("1.0") @@ -101,6 +99,7 @@ protected TriggerItem walk(Event e) { Location loc = location.getSingle(e); if (loc == null) return next; + boolean unknownWorld = !loc.isWorldLoaded(); Entity[] entityArray = entities.getArray(e); // We have to fetch this before possible async execution to avoid async local variable access. if (entityArray.length == 0) @@ -108,11 +107,17 @@ protected TriggerItem walk(Event e) { if (!delayed) { if (e instanceof PlayerRespawnEvent && entityArray.length == 1 && entityArray[0].equals(((PlayerRespawnEvent) e).getPlayer())) { + if (unknownWorld) + return next; ((PlayerRespawnEvent) e).setRespawnLocation(loc); return next; } if (e instanceof PlayerMoveEvent && entityArray.length == 1 && entityArray[0].equals(((PlayerMoveEvent) e).getPlayer())) { + if (unknownWorld) { // we can approximate the world + loc = loc.clone(); + loc.setWorld(((PlayerMoveEvent) e).getFrom().getWorld()); + } ((PlayerMoveEvent) e).setTo(loc); return next; } @@ -125,6 +130,19 @@ protected TriggerItem walk(Event e) { return next; } + if (unknownWorld) { // we can't fetch the chunk without a world + if (entityArray.length == 1) { // if there's 1 thing we can borrow its world + Entity entity = entityArray[0]; + if (entity == null) + return next; + // assume it's a local teleport, use the first entity we find as a reference + loc = loc.clone(); + loc.setWorld(entity.getWorld()); + } else { + return next; // no entities = no chunk = nobody teleporting + } + } + final Location fixed = loc; Delay.addDelayedEvent(e); Object localVars = Variables.removeLocals(e); @@ -132,7 +150,7 @@ protected TriggerItem walk(Event e) { PaperLib.getChunkAtAsync(loc).thenAccept(chunk -> { // The following is now on the main thread for (Entity entity : entityArray) { - EntityUtils.teleport(entity, loc); + EntityUtils.teleport(entity, fixed); } // Re-set local variables From 60658915fbcd3da0379c74dbeb6e7fed420dae79 Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Mon, 1 Jul 2024 20:33:25 +0200 Subject: [PATCH 18/27] Add EffSort, rework ExprInput to use ParserData (#6737) * Refactor ExprFilter * Change rawCond to unparsedCondition * Switch dependent input expressions to weak references * Revert "Switch dependent input expressions to weak references" This reverts commit 20169a11cdfa4fdf0c8b2a2e9e387f623ac50301. * Fix chained/nested filters * add sorted by and rework input expression and tests! * updates to test, tostring, and docs * i guess it didn't want {} * indentation * toString NPE * Requested Changes, except async sorting * Update InputSource.java * Apply suggestions from code review Co-authored-by: Patrick Miller * requested changes + correct annotations --------- Co-authored-by: Pikachu920 <28607612+Pikachu920@users.noreply.github.com> Co-authored-by: Patrick Miller --- .../java/ch/njol/skript/effects/EffSort.java | 167 +++++++++++ .../njol/skript/expressions/ExprFilter.java | 260 +++++++----------- .../ch/njol/skript/expressions/ExprInput.java | 170 ++++++++++++ .../java/ch/njol/skript/lang/InputSource.java | 101 +++++++ .../skript/tests/syntaxes/effects/EffSort.sk | 47 ++++ .../tests/syntaxes/expressions/ExprFilter.sk | 11 + 6 files changed, 591 insertions(+), 165 deletions(-) create mode 100644 src/main/java/ch/njol/skript/effects/EffSort.java create mode 100644 src/main/java/ch/njol/skript/expressions/ExprInput.java create mode 100644 src/main/java/ch/njol/skript/lang/InputSource.java create mode 100644 src/test/skript/tests/syntaxes/effects/EffSort.sk diff --git a/src/main/java/ch/njol/skript/effects/EffSort.java b/src/main/java/ch/njol/skript/effects/EffSort.java new file mode 100644 index 00000000000..40061777d50 --- /dev/null +++ b/src/main/java/ch/njol/skript/effects/EffSort.java @@ -0,0 +1,167 @@ +/** + * 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.expressions.ExprInput; +import ch.njol.skript.expressions.ExprSortedList; +import ch.njol.skript.lang.Effect; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.InputSource; +import ch.njol.skript.lang.ParseContext; +import ch.njol.skript.lang.SkriptParser; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.lang.Variable; +import ch.njol.skript.lang.parser.ParserInstance; +import ch.njol.util.Kleenean; +import ch.njol.util.Pair; +import org.bukkit.event.Event; +import org.eclipse.jdt.annotation.Nullable; +import org.jetbrains.annotations.UnknownNullability; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +@Name("Sort") +@Description({ + "Sorts a list variable using either the natural ordering of the contents or the results of the given expression.", + "Be warned, this will overwrite the indices of the list variable." +}) +@Examples({ + "set {_words::*} to \"pineapple\", \"banana\", \"yoghurt\", and \"apple\"", + "sort {_words::*} # alphabetical sort", + "sort {_words::*} by length of input # shortest to longest", + "sort {_words::*} based on {tastiness::%input%} # sort based on custom value" +}) +@Since("INSERT VERSION") +@Keywords("input") +public class EffSort extends Effect implements InputSource { + + static { + Skript.registerEffect(EffSort.class, "sort %~objects% [(by|based on) <.+>]"); + if (!ParserInstance.isRegistered(InputData.class)) + ParserInstance.registerData(InputData.class, InputData::new); + } + + @Nullable + private Expression mappingExpr; + @Nullable + private String unparsedExpression; + private Variable unsortedObjects; + + private Set> dependentInputs = new HashSet<>(); + + @Nullable + private Object currentValue; + @UnknownNullability + private String currentIndex; + + @Override + public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + if (expressions[0].isSingle() || !(expressions[0] instanceof Variable)) { + Skript.error("You can only sort list variables!"); + return false; + } + unsortedObjects = (Variable) expressions[0]; + + if (!parseResult.regexes.isEmpty()) { + unparsedExpression = parseResult.regexes.get(0).group(); + assert unparsedExpression != null; + InputData inputData = getParser().getData(InputData.class); + InputSource originalSource = inputData.getSource(); + inputData.setSource(this); + mappingExpr = new SkriptParser(unparsedExpression, SkriptParser.PARSE_EXPRESSIONS, ParseContext.DEFAULT) + .parseExpression(Object.class); + inputData.setSource(originalSource); + return mappingExpr != null && mappingExpr.isSingle(); + } + return true; + } + + @Override + protected void execute(Event event) { + Object[] sorted; + if (mappingExpr == null) { + try { + sorted = unsortedObjects.stream(event) + .sorted(ExprSortedList::compare) + .toArray(); + } catch (IllegalArgumentException | ClassCastException e) { + return; + } + } else { + Map valueToMappedValue = new LinkedHashMap<>(); + for (Iterator> it = unsortedObjects.variablesIterator(event); it.hasNext(); ) { + Pair pair = it.next(); + currentIndex = pair.getKey(); + currentValue = pair.getValue(); + Object mappedValue = mappingExpr.getSingle(event); + if (mappedValue == null) + return; + valueToMappedValue.put(currentValue, mappedValue); + } + try { + sorted = valueToMappedValue.entrySet().stream() + .sorted(Map.Entry.comparingByValue(ExprSortedList::compare)) + .map(Map.Entry::getKey) + .toArray(); + } catch (IllegalArgumentException | ClassCastException e) { + return; + } + } + + unsortedObjects.change(event, sorted, ChangeMode.SET); + } + + @Override + public Set> getDependentInputs() { + return dependentInputs; + } + + @Override + public @Nullable Object getCurrentValue() { + return currentValue; + } + + @Override + public boolean hasIndices() { + return true; + } + + @Override + public @UnknownNullability String getCurrentIndex() { + return currentIndex; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return "sort" + unsortedObjects.toString(event, debug) + + (mappingExpr == null ? "" : " by " + mappingExpr.toString(event, debug)); + } + +} diff --git a/src/main/java/ch/njol/skript/expressions/ExprFilter.java b/src/main/java/ch/njol/skript/expressions/ExprFilter.java index 239b720e418..a9747bbc3fc 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprFilter.java +++ b/src/main/java/ch/njol/skript/expressions/ExprFilter.java @@ -27,83 +27,97 @@ import ch.njol.skript.lang.Condition; import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.ExpressionType; -import ch.njol.skript.lang.Literal; +import ch.njol.skript.lang.InputSource; import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.lang.Variable; +import ch.njol.skript.lang.parser.ParserInstance; import ch.njol.skript.lang.util.SimpleExpression; +import ch.njol.util.Pair; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.UnknownNullability; import org.skriptlang.skript.lang.converter.Converters; import ch.njol.skript.util.LiteralUtils; -import ch.njol.skript.util.Utils; import ch.njol.util.Kleenean; -import ch.njol.util.coll.iterator.ArrayIterator; import com.google.common.collect.Iterators; import org.bukkit.event.Event; -import org.eclipse.jdt.annotation.NonNull; -import org.eclipse.jdt.annotation.Nullable; -import java.lang.reflect.Array; -import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.Iterator; -import java.util.List; +import java.util.Set; +import java.util.Spliterator; +import java.util.Spliterators; import java.util.regex.Pattern; +import java.util.stream.StreamSupport; @Name("Filter") -@Description("Filters a list based on a condition. " + - "For example, if you ran 'broadcast \"something\" and \"something else\" where [string input is \"something\"]', " + - "only \"something\" would be broadcast as it is the only string that matched the condition.") +@Description({ + "Filters a list based on a condition. ", + "For example, if you ran 'broadcast \"something\" and \"something else\" where [string input is \"something\"]', ", + "only \"something\" would be broadcast as it is the only string that matched the condition." +}) @Examples("send \"congrats on being staff!\" to all players where [player input has permission \"staff\"]") @Since("2.2-dev36") @SuppressWarnings({"null", "unchecked"}) -public class ExprFilter extends SimpleExpression { - - @Nullable - private static ExprFilter parsing; +public class ExprFilter extends SimpleExpression implements InputSource { static { Skript.registerExpression(ExprFilter.class, Object.class, ExpressionType.COMBINED, "%objects% (where|that match) \\[<.+>\\]"); + if (!ParserInstance.isRegistered(InputData.class)) + ParserInstance.registerData(InputData.class, InputData::new); } - private Object current; - private List> children = new ArrayList<>(); - private Condition condition; - private String rawCond; - private Expression objects; + private Condition filterCondition; + private String unparsedCondition; + private Expression unfilteredObjects; + private Set> dependentInputs = new HashSet<>(); @Nullable - public static ExprFilter getParsing() { - return parsing; - } + private Object currentFilterValue; + @Nullable + private String currentFilterIndex; @Override public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { - try { - parsing = this; - objects = LiteralUtils.defendExpression(exprs[0]); - if (objects.isSingle()) - return false; - rawCond = parseResult.regexes.get(0).group(); - condition = Condition.parse(rawCond, "Can't understand this condition: " + rawCond); - } finally { - parsing = null; - } - return condition != null && LiteralUtils.canInitSafely(objects); + unfilteredObjects = LiteralUtils.defendExpression(exprs[0]); + if (unfilteredObjects.isSingle() || !LiteralUtils.canInitSafely(unfilteredObjects)) + return false; + unparsedCondition = parseResult.regexes.get(0).group(); + InputData inputData = getParser().getData(InputData.class); + InputSource originalSource = inputData.getSource(); + inputData.setSource(this); + filterCondition = Condition.parse(unparsedCondition, "Can't understand this condition: " + unparsedCondition); + inputData.setSource(originalSource); + return filterCondition != null; } - @NonNull + @NotNull @Override public Iterator iterator(Event event) { - Iterator objIterator = this.objects.iterator(event); - if (objIterator == null) + if (unfilteredObjects instanceof Variable) { + Iterator> variableIterator = ((Variable) unfilteredObjects).variablesIterator(event); + return StreamSupport.stream(Spliterators.spliteratorUnknownSize(variableIterator, Spliterator.ORDERED), false) + .filter(pair -> { + currentFilterValue = pair.getValue(); + currentFilterIndex = pair.getKey(); + return filterCondition.check(event); + }) + .map(Pair::getValue) + .iterator(); + } + + // clear current index just to be safe + currentFilterIndex = null; + + Iterator unfilteredObjectIterator = unfilteredObjects.iterator(event); + if (unfilteredObjectIterator == null) return Collections.emptyIterator(); - try { - return Iterators.filter(objIterator, object -> { - current = object; - return condition.check(event); - }); - } finally { - current = null; - } + return Iterators.filter(unfilteredObjectIterator, candidateObject -> { + currentFilterValue = candidateObject; + return filterCondition.check(event); + }); } @Override @@ -115,148 +129,64 @@ protected Object[] get(Event event) { } } - public Object getCurrent() { - return current; - } - - private void addChild(ExprInput child) { - children.add(child); - } - - private void removeChild(ExprInput child) { - children.remove(child); + @Override + public boolean isSingle() { + return false; } @Override public Class getReturnType() { - return objects.getReturnType(); + return unfilteredObjects.getReturnType(); } - @Override - public boolean isSingle() { - return objects.isSingle(); - } @Override public String toString(Event event, boolean debug) { - return String.format("%s where [%s]", objects.toString(event, debug), rawCond); + return unfilteredObjects.toString(event, debug) + " that match [" + unparsedCondition + "]"; } - @Override - public boolean isLoopOf(String s) { - for (ExprInput child : children) { // if they used player input, let's assume loop-player is valid - if (child.getClassInfo() == null || child.getClassInfo().getUserInputPatterns() == null) - continue; + private boolean matchesAnySpecifiedTypes(String candidateString) { + for (ExprInput dependentInput : dependentInputs) { + ClassInfo specifiedType = dependentInput.getSpecifiedType(); + if (specifiedType == null) + return false; + Pattern[] specifiedTypePatterns = specifiedType.getUserInputPatterns(); + if (specifiedTypePatterns == null) + return false; - for (Pattern pattern : child.getClassInfo().getUserInputPatterns()) { - if (pattern.matcher(s).matches()) + for (Pattern typePattern : specifiedTypePatterns) { + if (typePattern.matcher(candidateString).matches()) { return true; + } } } - return objects.isLoopOf(s); // nothing matched, so we'll rely on the object expression's logic + return false; } - @Name("Filter Input") - @Description("Represents the input in a filter expression. " + - "For example, if you ran 'broadcast \"something\" and \"something else\" where [input is \"something\"]" + - "the condition would be checked twice, using \"something\" and \"something else\" as the inputs.") - @Examples("send \"congrats on being staff!\" to all players where [input has permission \"staff\"]") - @Since("2.2-dev36") - public static class ExprInput extends SimpleExpression { - - static { - Skript.registerExpression(ExprInput.class, Object.class, ExpressionType.COMBINED, - "input", - "%*classinfo% input" - ); - } - - @Nullable - private final ExprInput source; - private final Class[] types; - private final Class superType; - @SuppressWarnings("NotNullFieldNotInitialized") - private ExprFilter parent; - @Nullable - private ClassInfo inputType; - - public ExprInput() { - this(null, (Class) Object.class); - } - - public ExprInput(@Nullable ExprInput source, Class... types) { - this.source = source; - if (source != null) { - this.parent = source.parent; - this.inputType = source.inputType; - parent.removeChild(source); - parent.addChild(this); - } - - this.types = types; - this.superType = (Class) Utils.getSuperType(types); - } - - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { - parent = ExprFilter.getParsing(); - - if (parent == null) - return false; - - parent.addChild(this); - inputType = matchedPattern == 0 ? null : ((Literal>) exprs[0]).getSingle(); - return true; - } - - @Override - protected T[] get(Event event) { - Object current = parent.getCurrent(); - if (inputType != null && !inputType.getC().isInstance(current)) { - return null; - } - - try { - return Converters.convert(new Object[]{current}, types, superType); - } catch (ClassCastException e1) { - return (T[]) Array.newInstance(superType, 0); - } - } - - public void setParent(ExprFilter parent) { - this.parent = parent; - } - - @Override - public Expression getConvertedExpression(Class... to) { - return new ExprInput<>(this, to); - } - @Override - public Expression getSource() { - return source == null ? this : source; - } - - @Override - public Class getReturnType() { - return superType; - } + @Override + public boolean isLoopOf(String candidateString) { + return unfilteredObjects.isLoopOf(candidateString) || matchesAnySpecifiedTypes(candidateString); + } - @Nullable - private ClassInfo getClassInfo() { - return inputType; - } + public Set> getDependentInputs() { + return dependentInputs; + } - @Override - public boolean isSingle() { - return true; - } + @Nullable + public Object getCurrentValue() { + return currentFilterValue; + } - @Override - public String toString(Event event, boolean debug) { - return inputType == null ? "input" : inputType.getCodeName() + " input"; - } + @Override + public boolean hasIndices() { + return unfilteredObjects instanceof Variable; + } + @Override + @UnknownNullability + public String getCurrentIndex() { + return currentFilterIndex; } } diff --git a/src/main/java/ch/njol/skript/expressions/ExprInput.java b/src/main/java/ch/njol/skript/expressions/ExprInput.java new file mode 100644 index 00000000000..334fc79cd93 --- /dev/null +++ b/src/main/java/ch/njol/skript/expressions/ExprInput.java @@ -0,0 +1,170 @@ +/** + * This file is part of Skript. + * + * Skript is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Skript is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Skript. If not, see . + * + * Copyright Peter Güttinger, SkriptLang team and contributors + */ +package ch.njol.skript.expressions; + +import ch.njol.skript.Skript; +import ch.njol.skript.classes.ClassInfo; +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.Expression; +import ch.njol.skript.lang.ExpressionType; +import ch.njol.skript.lang.InputSource; +import ch.njol.skript.lang.InputSource.InputData; +import ch.njol.skript.lang.Literal; +import ch.njol.skript.lang.SkriptParser; +import ch.njol.skript.lang.util.SimpleExpression; +import ch.njol.skript.registrations.DefaultClasses; +import ch.njol.skript.util.ClassInfoReference; +import ch.njol.skript.util.Utils; +import ch.njol.util.Kleenean; +import org.bukkit.event.Event; +import org.eclipse.jdt.annotation.Nullable; +import org.skriptlang.skript.lang.converter.Converters; + +import java.lang.reflect.Array; +import java.util.Set; + +@Name("Input") +@Description({ + "Represents the input in a filter expression or sort effect.", + "For example, if you ran 'broadcast \"something\" and \"something else\" where [input is \"something\"]", + "the condition would be checked twice, using \"something\" and \"something else\" as the inputs.", + "The 'input index' pattern can be used when acting on a variable to access the index of the input." +}) +@Examples({ + "send \"congrats on being staff!\" to all players where [input has permission \"staff\"]", + "sort {_list::*} based on length of input index" +}) +@Since("2.2-dev36, INSERT_VERSION (input index)") +public class ExprInput extends SimpleExpression { + + static { + Skript.registerExpression(ExprInput.class, Object.class, ExpressionType.COMBINED, + "input", + "%*classinfo% input", + "input index" + ); + } + + @Nullable + private final ExprInput source; + private final Class[] types; + private final Class superType; + + private InputSource inputSource; + + @Nullable + private ClassInfo specifiedType; + private boolean isIndex = false; + + public ExprInput() { + this(null, (Class) Object.class); + } + + public ExprInput(@Nullable ExprInput source, Class... types) { + this.source = source; + if (source != null) { + isIndex = source.isIndex; + specifiedType = source.specifiedType; + inputSource = source.inputSource; + Set> dependentInputs = inputSource.getDependentInputs(); + dependentInputs.remove(this.source); + dependentInputs.add(this); + } + this.types = types; + this.superType = (Class) Utils.getSuperType(types); + } + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { + inputSource = getParser().getData(InputData.class).getSource(); + if (inputSource == null) + return false; + switch (matchedPattern) { + case 1: + ClassInfoReference classInfoReference = ((Literal) ClassInfoReference.wrap((Expression>) exprs[0])).getSingle(); + if (classInfoReference.isPlural().isTrue()) { + Skript.error("An input can only be a single value! Please use a singular type (for example: players input -> player input)."); + return false; + } + specifiedType = classInfoReference.getClassInfo(); + break; + case 2: + if (!inputSource.hasIndices()) { + Skript.error("You cannot use 'input index' on lists without indices!"); + return false; + } + specifiedType = DefaultClasses.STRING; + isIndex = true; + break; + default: + specifiedType = null; + } + return true; + } + + @Override + protected T[] get(Event event) { + Object currentValue = isIndex ? inputSource.getCurrentIndex() : inputSource.getCurrentValue(); + if (currentValue == null || (specifiedType != null && !specifiedType.getC().isInstance(currentValue))) + return (T[]) Array.newInstance(superType, 0); + + try { + return Converters.convert(new Object[]{currentValue}, types, superType); + } catch (ClassCastException exception) { + return (T[]) Array.newInstance(superType, 0); + } + } + + @Override + public Expression getConvertedExpression(Class... to) { + return new ExprInput<>(this, to); + } + + @Override + public Expression getSource() { + return source == null ? this : source; + } + + @Override + public boolean isSingle() { + return true; + } + + @Override + public Class getReturnType() { + return superType; + } + + @Nullable + public ClassInfo getSpecifiedType() { + return specifiedType; + } + + + @Override + public String toString(Event event, boolean debug) { + if (isIndex) + return "input index"; + return specifiedType == null ? "input" : specifiedType.getCodeName() + " input"; + } + +} diff --git a/src/main/java/ch/njol/skript/lang/InputSource.java b/src/main/java/ch/njol/skript/lang/InputSource.java new file mode 100644 index 00000000000..df541a0e40f --- /dev/null +++ b/src/main/java/ch/njol/skript/lang/InputSource.java @@ -0,0 +1,101 @@ +/** + * 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.lang; + +import ch.njol.skript.expressions.ExprInput; +import ch.njol.skript.lang.parser.ParserInstance; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.UnknownNullability; + +import java.util.Set; + +/** + * An InputSource represents a syntax that can provide a + * value for {@link ExprInput} to use. + *
+ * @see ch.njol.skript.expressions.ExprFilter + * @see ch.njol.skript.effects.EffSort + */ +public interface InputSource { + + /** + * @return A mutable {@link Set} of {@link ExprInput}s that depend on this source. + */ + Set> getDependentInputs(); + + /** + * @return The current value that {@link ExprInput} should use. + */ + @Nullable Object getCurrentValue(); + + /** + * {@link InputSource}s that can supply indices along with values should override this + * method to indicate their ability. + * + * @return Whether this source can return indices. + */ + default boolean hasIndices() { + return false; + } + + /** + * This should only be used by {@link InputSource}s that return true for {@link InputSource#hasIndices()}. + * + * @return The current value's index. + */ + default @UnknownNullability String getCurrentIndex() { + return null; + } + + /** + * A {@link ch.njol.skript.lang.parser.ParserInstance.Data} used for + * linking {@link InputSource}s and {@link ExprInput}s. + */ + class InputData extends ParserInstance.Data { + + @Nullable + private InputSource source; + + public InputData(ParserInstance parserInstance) { + super(parserInstance); + } + + /** + * {@link InputSource} should call this during init() to declare that they are the current source for future + * {@link ExprInput}s, and then reset it to its previous value once out of scope. + * + * @param source the source of information. + */ + public void setSource(@Nullable InputSource source) { + this.source = source; + } + + /** + * ExprInput should use this to get the information source, and then call + * {@link InputSource#getCurrentValue()} to get the current value of the source. + * + * @return the source of information. + */ + @Nullable + public InputSource getSource() { + return source; + } + + } +} diff --git a/src/test/skript/tests/syntaxes/effects/EffSort.sk b/src/test/skript/tests/syntaxes/effects/EffSort.sk new file mode 100644 index 00000000000..4d832cd61fa --- /dev/null +++ b/src/test/skript/tests/syntaxes/effects/EffSort.sk @@ -0,0 +1,47 @@ +test "sorting": + set {_numbers::*} to shuffled integers from 1 to 50 + sort {_numbers::*} + assert {_numbers::*} is integers from 1 to 50 with "improper sorting of numbers" + + set {_numbers::*} to shuffled integers from 1 to 5 + sort {_numbers::*} by input * 20 + 4 - 3 # linear transformations don't affect order + assert {_numbers::*} is integers from 1 to 5 with "improper custom sorting of numbers" + + set {_numbers::*} to shuffled integers from 1 to 5 + set {_pre-sort-numbers::*} to {_numbers::*} + sort {_numbers::*} by "%input%" parsed as time # map expression returns null + assert {_numbers::*} is {_pre-sort-numbers::*} with "Invalid sorting expression adjusted list" + + set {_numbers::*} to shuffled integers from 1 to 5 + set {_pre-sort-numbers::*} to {_numbers::*} + sort {_numbers::*} by {_} + assert {_numbers::*} is {_pre-sort-numbers::*} with "Invalid sorting expression adjusted list" + + set {_numbers::*} to {_} + sort {_numbers::*} by input + 3 + assert {_numbers::*} is not set with "Invalid sorting of unset list" + + set {_chars::*} to shuffled characters between "a" and "f" + sort {_chars::*} + assert {_chars::*} is characters between "a" and "f" with "improper sorting of chars" + + set {_chars::*} to shuffled characters between "a" and "f" + sort {_chars::*} based on codepoint of input + assert {_chars::*} is characters between "a" and "f" with "improper custom sorting of chars" + + set {_mixed::*} to shuffled (characters between "a" and "f", integers from 1 to 5) + set {_pre-sort-mixed::*} to {_mixed::*} + sort {_mixed::*} + assert {_mixed::*} is {_pre-sort-mixed::*} with "incomparable mixed list was adjusted" + + set {_mixed::*} to shuffled (characters between "a" and "f", integers from 1 to 5) + sort {_mixed::*} by "%input%" + assert {_mixed::*} is 1, 2, 3, 4, 5, and characters between "a" and "f" with "improper custom sorting of mixed list" + + set {_list::x} to 1 + set {_list::aa} to 2 + set {_list::bxs} to 3 + set {_list::zysa} to 4 + set {_list::aaaaa} to 5 + sort {_list::*} by length of input index + assert {_list::*} is integers from 1 to 5 with "improper custom sorting based on index" diff --git a/src/test/skript/tests/syntaxes/expressions/ExprFilter.sk b/src/test/skript/tests/syntaxes/expressions/ExprFilter.sk index b1f1738f20d..bc195b894c8 100644 --- a/src/test/skript/tests/syntaxes/expressions/ExprFilter.sk +++ b/src/test/skript/tests/syntaxes/expressions/ExprFilter.sk @@ -3,4 +3,15 @@ test "where filter": assert first element of ({_list::*} where [string input is "foo"]) is "foo" with "ExprFilter filtered incorrectly" assert {_list::*} where [number input is set] is not set with "ExprFilter provided input value when classinfo did not match" assert first element of ({_list::*} where [input is "foo"]) is "foo" with "ExprFilter filtered object input incorrectly" + assert first element of ({_list::*} where [input is "bar"]) is "bar" with "ExprFilter filtered object input incorrectly" + assert size of ({_list::*} where [input is "bar"]) is 1 with "ExprFilter filtered object input incorrectly" + assert first element of ({_list::*} where [input is "bar"]) is "bar" with "ExprFilter filtered object input incorrectly" + assert size of ({_list::*} where [input is "bar"]) is 1 with "ExprFilter filtered object input incorrectly" + assert first element of ({_list::*} where [input is "foobar"]) is "foobar" with "ExprFilter filtered object input incorrectly" + assert size of ({_list::*} where [input is "foobar"]) is 1 with "ExprFilter filtered object input incorrectly" + assert size of ({_list::*} where [input is "foo" or "bar"]) is 2 with "ExprFilter filtered object input incorrectly" + assert size of ({_list::*} where [input is set]) is 3 with "ExprFilter filtered object input incorrectly" assert {_list::*} where [false is true] is not set with "ExprFilter returned objects with false condition" + assert ({_list::*} where [input is (("foo" and "bar") where [input is "bar"])]) is "bar" with "Failed filter with filter within condition" + assert (({_list::*} where [input is "foo"]) where [input is "foo"]) is "foo" with "Failed chained filters" + assert {_list::*} where [input index is "2" or "3"] is "bar" and "foobar" with "Failed input index filter" From 27094a6581155d3868f101c900eb12dc4777d4b4 Mon Sep 17 00:00:00 2001 From: Mwexim <38397639+Mwexim@users.noreply.github.com> Date: Mon, 1 Jul 2024 20:52:30 +0200 Subject: [PATCH 19/27] ExprYawPitch: support for entities, better description (#5298) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 💡 ExprYawPitch: added support for entities, made description more clear, made code consistent * 💡 ExprYawPitch * 💡 ExprYawPitch: apply suggestion Co-authored-by: Ayham Al Ali * 💡 ExprYawPitch: apply suggestion Co-authored-by: Ayham Al Ali * 💡 ExprYawPitch: apply suggestion Co-authored-by: Ayham Al Ali * 💡 ExprYawPitch: apply other suggestions * Update src/main/java/ch/njol/skript/expressions/ExprYawPitch.java * Revert changes to pitch/yaw meaning * Update ExprYawPitch.java * Float return! --------- Co-authored-by: Mwexim Co-authored-by: Ayham Al Ali Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com> Co-authored-by: Moderocky --- .../njol/skript/expressions/ExprYawPitch.java | 201 ++++++++++++------ 1 file changed, 137 insertions(+), 64 deletions(-) diff --git a/src/main/java/ch/njol/skript/expressions/ExprYawPitch.java b/src/main/java/ch/njol/skript/expressions/ExprYawPitch.java index cbbc3ba085d..6aca873d614 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprYawPitch.java +++ b/src/main/java/ch/njol/skript/expressions/ExprYawPitch.java @@ -18,8 +18,13 @@ */ package ch.njol.skript.expressions; +import ch.njol.skript.ServerPlatform; +import ch.njol.skript.Skript; +import ch.njol.skript.doc.RequiredPlugins; import ch.njol.util.VectorMath; import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; import org.bukkit.event.Event; import ch.njol.skript.classes.Changer.ChangeMode; @@ -33,125 +38,193 @@ import ch.njol.util.Kleenean; import ch.njol.util.coll.CollectionUtils; import org.bukkit.util.Vector; +import org.eclipse.jdt.annotation.Nullable; @Name("Yaw / Pitch") -@Description("The yaw or pitch of a location or vector.") -@Examples({"log \"%player%: %location of player%, %player's yaw%, %player's pitch%\" to \"playerlocs.log\"", - "set {_yaw} to yaw of player", - "set {_p} to pitch of target entity"}) -@Since("2.0, 2.2-dev28 (vector yaw/pitch)") -public class ExprYawPitch extends SimplePropertyExpression { +@Description({ + "The yaw or pitch of a location or vector.", + "A yaw of 0 or 360 represents the positive z direction. Adding a positive number to the yaw of a player will rotate it clockwise.", + "A pitch of 90 represents the negative y direction, or downward facing. A pitch of -90 represents upward facing. Adding a positive number to the pitch will rotate the direction downwards.", + "Only Paper 1.19+ users may directly change the yaw/pitch of players." +}) +@Examples({ + "log \"%player%: %location of player%, %player's yaw%, %player's pitch%\" to \"playerlocs.log\"", + "set {_yaw} to yaw of player", + "set {_p} to pitch of target entity", + "set pitch of player to -90 # Makes the player look upwards, Paper 1.19+ only", + "add 180 to yaw of target of player # Makes the target look behind themselves" +}) +@Since("2.0, 2.2-dev28 (vector yaw/pitch), INSERT VERSION (entity changers)") +@RequiredPlugins("Paper 1.19+ (player changers)") +public class ExprYawPitch extends SimplePropertyExpression { static { - register(ExprYawPitch.class, Number.class, "(0¦yaw|1¦pitch)", "locations/vectors"); + register(ExprYawPitch.class, Float.class, "(:yaw|pitch)", "entities/locations/vectors"); } + // For non-Paper versions lower than 1.19, changing the rotation of an entity is not supported for players. + private static final boolean SUPPORTS_PLAYERS = Skript.isRunningMinecraft(1, 19) && Skript.getServerPlatform() == ServerPlatform.BUKKIT_PAPER; + private boolean usesYaw; @Override - public boolean init(final Expression[] exprs, final int matchedPattern, final Kleenean isDelayed, final ParseResult parseResult) { - usesYaw = parseResult.mark == 0; + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + usesYaw = parseResult.hasTag("yaw"); return super.init(exprs, matchedPattern, isDelayed, parseResult); } @Override - public Number convert(final Object object) { - if (object instanceof Location) { - Location l = ((Location) object); - return usesYaw ? convertToPositive(l.getYaw()) : l.getPitch(); + public Float convert(Object object) { + if (object instanceof Entity) { + Location location = ((Entity) object).getLocation(); + return usesYaw + ? normalizeYaw(location.getYaw()) + : location.getPitch(); + } else if (object instanceof Location) { + Location location = (Location) object; + return usesYaw + ? normalizeYaw(location.getYaw()) + : location.getPitch(); } else if (object instanceof Vector) { - Vector vector = ((Vector) object); - if (usesYaw) - return VectorMath.skriptYaw(VectorMath.getYaw(vector)); - return VectorMath.skriptPitch(VectorMath.getPitch(vector)); + Vector vector = (Vector) object; + return usesYaw + ? VectorMath.skriptYaw((VectorMath.getYaw(vector))) + : VectorMath.skriptPitch(VectorMath.getPitch(vector)); } return null; } - @SuppressWarnings({"null"}) @Override - public Class[] acceptChange(final ChangeMode mode) { - if (mode == ChangeMode.SET || mode == ChangeMode.ADD || mode == ChangeMode.REMOVE) - return CollectionUtils.array(Number.class); - return null; + public Class[] acceptChange(ChangeMode mode) { + if (Player.class.isAssignableFrom(getExpr().getReturnType()) && !SUPPORTS_PLAYERS) + return null; + + switch (mode) { + case SET: + case ADD: + case REMOVE: + return CollectionUtils.array(Number.class); + case RESET: + return new Class[0]; + default: + return null; + } } - @SuppressWarnings("null") @Override - public void change(Event e, Object[] delta, ChangeMode mode) { - if (delta == null) + public void change(Event event, @Nullable Object[] delta, ChangeMode mode) { + if (delta == null && mode != ChangeMode.RESET) return; float value = ((Number) delta[0]).floatValue(); - for (Object single : getExpr().getArray(e)) { - if (single instanceof Location) { - changeLocation(((Location) single), value, mode); - } else if (single instanceof Vector) { - changeVector(((Vector) single), value, mode); + for (Object object : getExpr().getArray(event)) { + if (object instanceof Player && !SUPPORTS_PLAYERS) + continue; + + if (object instanceof Entity) { + changeForEntity((Entity) object, value, mode); + } else if (object instanceof Location) { + changeForLocation(((Location) object), value, mode); + } else if (object instanceof Vector) { + changeForVector(((Vector) object), value, mode); } } } - private void changeLocation(Location l, float value, ChangeMode mode) { + private void changeForEntity(Entity entity, float value, ChangeMode mode) { + Location location = entity.getLocation(); switch (mode) { case SET: - if (usesYaw) - l.setYaw(convertToPositive(value)); - else - l.setPitch(value); + if (usesYaw) { + entity.setRotation(value, location.getPitch()); + } else { + entity.setRotation(location.getYaw(), value); + } break; + case REMOVE: + value = -value; case ADD: - if (usesYaw) - l.setYaw(convertToPositive(l.getYaw()) + value); - else - l.setPitch(l.getPitch() + value); + if (usesYaw) { + entity.setRotation(location.getYaw() + value, location.getPitch()); + } else { + // Subtracting because of Minecraft's upside-down pitch. + entity.setRotation(location.getYaw(), location.getPitch() - value); + } + break; + case RESET: + if (usesYaw) { + entity.setRotation(0, location.getPitch()); + } else { + entity.setRotation(location.getYaw(), 0); + } + break; + default: + break; + } + } + + private void changeForLocation(Location location, float value, ChangeMode mode) { + switch (mode) { + case SET: + if (usesYaw) { + location.setYaw(value); + } else { + location.setPitch(value); + } break; case REMOVE: - if (usesYaw) - l.setYaw(convertToPositive(l.getYaw()) - value); - else - l.setPitch(l.getPitch() - value); + value = -value; + case ADD: + if (usesYaw) { + location.setYaw(location.getYaw() + value); + } else { + // Subtracting because of Minecraft's upside-down pitch. + location.setPitch(location.getPitch() - value); + } break; + case RESET: + if (usesYaw) { + location.setYaw(0); + } else { + location.setPitch(0); + } default: break; } } - private void changeVector(Vector vector, float n, ChangeMode mode) { + private void changeForVector(Vector vector, float value, ChangeMode mode) { float yaw = VectorMath.getYaw(vector); float pitch = VectorMath.getPitch(vector); switch (mode) { case REMOVE: - n = -n; - //$FALL-THROUGH$ + value = -value; + // $FALL-THROUGH$ case ADD: - if (usesYaw) - yaw += n; - else - pitch -= n; // Negative because of Minecraft's / Skript's upside down pitch - Vector newVector = VectorMath.fromYawAndPitch(yaw, pitch).multiply(vector.length()); - VectorMath.copyVector(vector, newVector); + if (usesYaw) { + yaw += value; + } else { + // Subtracting because of Minecraft's upside-down pitch. + pitch -= value; + } break; case SET: if (usesYaw) - yaw = VectorMath.fromSkriptYaw(n); + yaw = VectorMath.fromSkriptYaw(value); else - pitch = VectorMath.fromSkriptPitch(n); - newVector = VectorMath.fromYawAndPitch(yaw, pitch).multiply(vector.length()); - VectorMath.copyVector(vector, newVector); + pitch = VectorMath.fromSkriptPitch(value); } + Vector newVector = VectorMath.fromYawAndPitch(yaw, pitch).multiply(vector.length()); + VectorMath.copyVector(vector, newVector); } - - //Some random method decided to use for converting to positive values. - public float convertToPositive(float f) { - if (f != 0 && f * -1 == Math.abs(f)) - return 360 + f; - return f; + private static float normalizeYaw(float yaw) { + yaw = Location.normalizeYaw(yaw); + return yaw < 0 ? yaw + 360 : yaw; } @Override - public Class getReturnType() { - return Number.class; + public Class getReturnType() { + return Float.class; } @Override From 55d7fdc53faa008980d18e01916087c5fa494b4d Mon Sep 17 00:00:00 2001 From: Ayham Al Ali <20037329+AyhamAl-Ali@users.noreply.github.com> Date: Mon, 1 Jul 2024 22:33:37 +0300 Subject: [PATCH 20/27] =?UTF-8?q?=F0=9F=9A=80=20Add=20Cancellable=20sectio?= =?UTF-8?q?n=20(#5691)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add Cancellable section * Correct effect name EffCancelEvent * Support EffCancelEvent extra hardcoded event * Nothing, just better logic! --------- Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com> Co-authored-by: Moderocky --- .../ch/njol/skript/doc/HTMLGenerator.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/main/java/ch/njol/skript/doc/HTMLGenerator.java b/src/main/java/ch/njol/skript/doc/HTMLGenerator.java index e882057cebd..d79b1e65320 100644 --- a/src/main/java/ch/njol/skript/doc/HTMLGenerator.java +++ b/src/main/java/ch/njol/skript/doc/HTMLGenerator.java @@ -36,6 +36,9 @@ import com.google.common.collect.Lists; import com.google.common.io.Files; import org.apache.commons.lang.StringUtils; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.block.BlockCanBuildEvent; import org.eclipse.jdt.annotation.Nullable; import org.skriptlang.skript.lang.entry.EntryData; import org.skriptlang.skript.lang.entry.EntryValidator; @@ -481,6 +484,9 @@ private String generateAnnotated(String descTemp, SyntaxElementInfo info, @Nu } desc = desc.replace("${element.id}", ID); + // Cancellable + desc = handleIf(desc, "${if cancellable}", false); + // Events Events events = c.getAnnotation(Events.class); desc = handleIf(desc, "${if events}", events != null); @@ -603,6 +609,17 @@ private String generateEvent(String descTemp, SkriptEventInfo info, @Nullable String[] keywords = info.getKeywords(); desc = desc.replace("${element.keywords}", keywords == null ? "" : Joiner.on(", ").join(keywords)); + // Cancellable + boolean cancellable = false; + for (Class event : info.events) { + if (Cancellable.class.isAssignableFrom(event) || BlockCanBuildEvent.class.isAssignableFrom(event)) { + cancellable = true; // let's assume all are cancellable otherwise EffCancelEvent would do the rest in action + break; + } + } + desc = handleIf(desc, "${if cancellable}", cancellable); + desc = desc.replace("${element.cancellable}", cancellable ? "Yes" : ""); // if not cancellable the section is hidden + // Documentation ID String ID = info.getDocumentationID() != null ? info.getDocumentationID() : info.getId(); // Fix duplicated IDs @@ -719,6 +736,9 @@ private String generateClass(String descTemp, ClassInfo info, @Nullable Strin } desc = desc.replace("${element.id}", ID); + // Cancellable + desc = handleIf(desc, "${if cancellable}", false); + // Events Events events = c.getAnnotation(Events.class); desc = handleIf(desc, "${if events}", events != null); @@ -821,6 +841,9 @@ private String generateFunction(String descTemp, JavaFunction info) { // Documentation ID desc = desc.replace("${element.id}", info.getName()); + // Cancellable + desc = handleIf(desc, "${if cancellable}", false); + // Events desc = handleIf(desc, "${if events}", false); // Functions do not require events nor plugins (at time writing this) From 6d1a00ad8a267d77e44b02018378d5919da728ff Mon Sep 17 00:00:00 2001 From: NotSoDelayed <72163224+NotSoDelayed@users.noreply.github.com> Date: Tue, 2 Jul 2024 03:38:51 +0800 Subject: [PATCH 21/27] Make EffBroadcast calls BroadcastMessageEvent (#5979) * Support BroadcastMessageEvent * Clean up * Clean up * Recipient set unmodifiable * Use deprecated constructor for 1.13 users * Move version tag to javadocs * Fix version check for legacy constructor call --------- Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com> Co-authored-by: Moderocky --- .../ch/njol/skript/effects/EffBroadcast.java | 80 +++++++++++++++---- 1 file changed, 65 insertions(+), 15 deletions(-) diff --git a/src/main/java/ch/njol/skript/effects/EffBroadcast.java b/src/main/java/ch/njol/skript/effects/EffBroadcast.java index 5e2b8fbdefb..fd6ef3ff245 100644 --- a/src/main/java/ch/njol/skript/effects/EffBroadcast.java +++ b/src/main/java/ch/njol/skript/effects/EffBroadcast.java @@ -18,6 +18,13 @@ */ package ch.njol.skript.effects; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.regex.Pattern; + import ch.njol.skript.Skript; import ch.njol.skript.doc.Description; import ch.njol.skript.doc.Examples; @@ -31,19 +38,20 @@ import ch.njol.skript.lang.VariableString; import ch.njol.skript.registrations.Classes; import ch.njol.skript.util.LiteralUtils; +import ch.njol.skript.util.SkriptColor; +import ch.njol.skript.util.Utils; import ch.njol.skript.util.chat.BungeeConverter; import ch.njol.skript.util.chat.ChatMessages; import ch.njol.util.Kleenean; +import ch.njol.util.StringUtils; import ch.njol.util.coll.CollectionUtils; import net.md_5.bungee.api.chat.BaseComponent; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.command.CommandSender; import org.bukkit.event.Event; -import org.eclipse.jdt.annotation.Nullable; - -import java.util.ArrayList; -import java.util.List; +import org.bukkit.event.server.BroadcastMessageEvent; +import org.jetbrains.annotations.Nullable; @Name("Broadcast") @Description("Broadcasts a message to the server.") @@ -54,6 +62,8 @@ @Since("1.0, 2.6 (broadcasting objects), 2.6.1 (using advanced formatting)") public class EffBroadcast extends Effect { + private static final Pattern HEX_PATTERN = Pattern.compile("(?i)&x((?:&\\p{XDigit}){6})"); + static { Skript.registerEffect(EffBroadcast.class, "broadcast %objects% [(to|in) %-worlds%]"); } @@ -65,8 +75,8 @@ public class EffBroadcast extends Effect { @Nullable private Expression worlds; - @SuppressWarnings("unchecked") @Override + @SuppressWarnings("unchecked") public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { messageExpr = LiteralUtils.defendExpression(exprs[0]); messages = messageExpr instanceof ExpressionList ? @@ -74,37 +84,51 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye worlds = (Expression) exprs[1]; return LiteralUtils.canInitSafely(messageExpr); } - + + /** + * This effect will call {@link BroadcastMessageEvent} as of INSERT_VERSION. + */ @Override @SuppressWarnings("deprecation") - public void execute(Event e) { + public void execute(Event event) { List receivers = new ArrayList<>(); if (worlds == null) { receivers.addAll(Bukkit.getOnlinePlayers()); receivers.add(Bukkit.getConsoleSender()); } else { - for (World world : worlds.getArray(e)) + for (World world : worlds.getArray(event)) receivers.addAll(world.getPlayers()); } for (Expression message : getMessages()) { if (message instanceof VariableString) { - BaseComponent[] components = BungeeConverter.convert(((VariableString) message).getMessageComponents(e)); + if (!dispatchEvent(getRawString(event, (VariableString) message), receivers)) + continue; + BaseComponent[] components = BungeeConverter.convert(((VariableString) message).getMessageComponents(event)); receivers.forEach(receiver -> receiver.spigot().sendMessage(components)); } else if (message instanceof ExprColoured && ((ExprColoured) message).isUnsafeFormat()) { // Manually marked as trusted - for (Object realMessage : message.getArray(e)) { + for (Object realMessage : message.getArray(event)) { + if (!dispatchEvent(Utils.replaceChatStyles((String) realMessage), receivers)) + continue; BaseComponent[] components = BungeeConverter.convert(ChatMessages.parse((String) realMessage)); receivers.forEach(receiver -> receiver.spigot().sendMessage(components)); } } else { - for (Object messageObject : message.getArray(e)) { + for (Object messageObject : message.getArray(event)) { String realMessage = messageObject instanceof String ? (String) messageObject : Classes.toString(messageObject); + if (!dispatchEvent(Utils.replaceChatStyles(realMessage), receivers)) + continue; receivers.forEach(receiver -> receiver.sendMessage(realMessage)); } } } } + @Override + public String toString(@Nullable Event event, boolean debug) { + return "broadcast " + messageExpr.toString(event, debug) + (worlds == null ? "" : " to " + worlds.toString(event, debug)); + } + private Expression[] getMessages() { if (messageExpr instanceof ExpressionList && !messageExpr.getAnd()) { return new Expression[] {CollectionUtils.getRandom(messages)}; @@ -112,9 +136,35 @@ private Expression[] getMessages() { return messages; } - @Override - public String toString(@Nullable Event e, boolean debug) { - return "broadcast " + messageExpr.toString(e, debug) + (worlds == null ? "" : " to " + worlds.toString(e, debug)); + /** + * Manually calls a {@link BroadcastMessageEvent}. + * @param message the message + * @return true if the dispatched event does not get cancelled + */ + @SuppressWarnings("deprecation") + private static boolean dispatchEvent(String message, List receivers) { + Set recipients = Collections.unmodifiableSet(new HashSet<>(receivers)); + BroadcastMessageEvent broadcastEvent; + if (Skript.isRunningMinecraft(1, 14)) { + broadcastEvent = new BroadcastMessageEvent(!Bukkit.isPrimaryThread(), message, recipients); + } else { + broadcastEvent = new BroadcastMessageEvent(message, recipients); + } + Bukkit.getPluginManager().callEvent(broadcastEvent); + return !broadcastEvent.isCancelled(); } - + + @Nullable + private static String getRawString(Event event, Expression string) { + if (string instanceof VariableString) + return ((VariableString) string).toUnformattedString(event); + String rawString = string.getSingle(event); + rawString = SkriptColor.replaceColorChar(rawString); + if (rawString.toLowerCase().contains("&x")) { + rawString = StringUtils.replaceAll(rawString, HEX_PATTERN, matchResult -> + "<#" + matchResult.group(1).replace("&", "") + '>'); + } + return rawString; + } + } From 69cd4cdc771abb69b03b2e8c14cdd20c72fa5824 Mon Sep 17 00:00:00 2001 From: LimeGlass <16087552+TheLimeGlass@users.noreply.github.com> Date: Mon, 1 Jul 2024 13:49:55 -0600 Subject: [PATCH 22/27] Fixes JUnit before and after being called on cleanup regardless of override (#6276) Remove JUnit annotations on cleanup Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com> --- src/main/java/ch/njol/skript/Skript.java | 4 ++++ src/main/java/ch/njol/skript/test/runner/SkriptJUnitTest.java | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/ch/njol/skript/Skript.java b/src/main/java/ch/njol/skript/Skript.java index d98a51a7763..3755525edb1 100644 --- a/src/main/java/ch/njol/skript/Skript.java +++ b/src/main/java/ch/njol/skript/Skript.java @@ -752,6 +752,8 @@ protected void afterErrors() { TestTracker.JUnitTestFailed(test, message); Skript.exception(failure.getException(), "JUnit test '" + failure.getTestHeader() + " failed."); }); + if (SkriptJUnitTest.class.isAssignableFrom(clazz)) + ((SkriptJUnitTest) clazz.getConstructor().newInstance()).cleanup(); SkriptJUnitTest.clearJUnitTest(); } } catch (IOException e) { @@ -759,6 +761,8 @@ protected void afterErrors() { } catch (ClassNotFoundException e) { // Should be the Skript test jar gradle task. assert false : "Class 'ch.njol.skript.variables.FlatFileStorageTest' was not found."; + } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { + Skript.exception(e, "Failed to initalize test JUnit classes."); } if (ignored > 0) Skript.warning("There were " + ignored + " ignored test cases! This can mean they are not properly setup in order in that class!"); diff --git a/src/main/java/ch/njol/skript/test/runner/SkriptJUnitTest.java b/src/main/java/ch/njol/skript/test/runner/SkriptJUnitTest.java index 65a52f0ac1a..6988d537cff 100644 --- a/src/main/java/ch/njol/skript/test/runner/SkriptJUnitTest.java +++ b/src/main/java/ch/njol/skript/test/runner/SkriptJUnitTest.java @@ -27,8 +27,6 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Pig; -import org.junit.After; -import org.junit.Before; import ch.njol.skript.Skript; @@ -79,8 +77,6 @@ public static void setShutdownDelay(long delay) { /** * Override this method if your JUnit test requires block modification with delay over 1 tick. */ - @Before - @After public void cleanup() { getTestWorld().getEntities().forEach(Entity::remove); setBlock(Material.AIR); From dfaacd6e46c732f66681fddcbf2d3acc261a192c Mon Sep 17 00:00:00 2001 From: LimeGlass <16087552+TheLimeGlass@users.noreply.github.com> Date: Mon, 1 Jul 2024 13:56:21 -0600 Subject: [PATCH 23/27] Update healing event and related expressions (#6339) * Update healing event and related expressions * Update src/main/java/ch/njol/skript/expressions/ExprHealAmount.java Co-authored-by: Ayham Al Ali <20037329+AyhamAl-Ali@users.noreply.github.com> * Update src/main/java/ch/njol/skript/events/EvtHealing.java Co-authored-by: Ayham Al Ali <20037329+AyhamAl-Ali@users.noreply.github.com> * Apply changes * Sync aliases with master * Add event to setTime * Update src/main/java/ch/njol/skript/events/EvtHealing.java --------- Co-authored-by: Ayham Al Ali <20037329+AyhamAl-Ali@users.noreply.github.com> Co-authored-by: Moderocky Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com> --- .../skript/classes/data/BukkitClasses.java | 11 +- .../classes/data/BukkitEventValues.java | 11 ++ .../ch/njol/skript/events/EvtHealing.java | 100 ++++++++++++++++++ .../ch/njol/skript/events/SimpleEvents.java | 5 - .../skript/expressions/ExprHealAmount.java | 75 +++++++------ .../skript/expressions/ExprHealReason.java | 71 ++++--------- 6 files changed, 180 insertions(+), 93 deletions(-) create mode 100644 src/main/java/ch/njol/skript/events/EvtHealing.java diff --git a/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java b/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java index a54e5a54cc4..7ff72f27e69 100644 --- a/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java +++ b/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java @@ -1448,12 +1448,13 @@ public String toVariableNameString(FireworkEffect effect) { .since("2.4") .requiredPlugins("Minecraft 1.14 or newer")); } + Classes.registerClass(new EnumClassInfo<>(RegainReason.class, "healreason", "heal reasons") - .user("(regen|heal) (reason|cause)") - .name("Heal Reason") - .description("The heal reason in a heal event.") - .examples("") - .since("2.5")); + .user("(regen|heal) (reason|cause)") + .name("Heal Reason") + .description("The health regain reason in a heal event.") + .since("2.5")); + if (Skript.classExists("org.bukkit.entity.Cat$Type")) { ClassInfo catTypeClassInfo; if (BukkitUtils.registryExists("CAT_VARIANT")) { 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 76e098cb602..6a49566c827 100644 --- a/src/main/java/ch/njol/skript/classes/data/BukkitEventValues.java +++ b/src/main/java/ch/njol/skript/classes/data/BukkitEventValues.java @@ -101,6 +101,8 @@ import org.bukkit.event.entity.EntityDropItemEvent; import org.bukkit.event.entity.EntityEvent; import org.bukkit.event.entity.EntityPickupItemEvent; +import org.bukkit.event.entity.EntityRegainHealthEvent; +import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason; import org.bukkit.event.entity.EntityResurrectEvent; import org.bukkit.event.entity.EntityTameEvent; import org.bukkit.event.entity.EntityTransformEvent; @@ -1908,5 +1910,14 @@ public ItemStack get(InventoryMoveItemEvent event) { return event.getItem(); } }, EventValues.TIME_NOW); + + // EntityRegainHealthEvent + EventValues.registerEventValue(EntityRegainHealthEvent.class, RegainReason.class, new Getter() { + @Override + @Nullable + public RegainReason get(EntityRegainHealthEvent event) { + return event.getRegainReason(); + } + }, EventValues.TIME_NOW); } } diff --git a/src/main/java/ch/njol/skript/events/EvtHealing.java b/src/main/java/ch/njol/skript/events/EvtHealing.java new file mode 100644 index 00000000000..21dd2c2e642 --- /dev/null +++ b/src/main/java/ch/njol/skript/events/EvtHealing.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.events; + +import org.bukkit.entity.Entity; +import org.bukkit.event.Event; +import org.bukkit.event.entity.EntityRegainHealthEvent; +import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason; +import org.eclipse.jdt.annotation.Nullable; + +import ch.njol.skript.Skript; +import ch.njol.skript.entity.EntityData; +import ch.njol.skript.lang.Literal; +import ch.njol.skript.lang.SkriptEvent; +import ch.njol.skript.lang.SkriptParser.ParseResult; + +public class EvtHealing extends SkriptEvent { + + static { + Skript.registerEvent("Heal", EvtHealing.class, EntityRegainHealthEvent.class, "heal[ing] [of %-entitydatas%] [(from|due to|by) %-healreasons%]", "%entitydatas% heal[ing] [(from|due to|by) %-healreasons%]") + .description("Called when an entity is healed, e.g. by eating (players), being fed (pets), or by the effect of a potion of healing (overworld mobs) or harm (nether mobs).") + .examples( + "on heal:", + "on player healing from a regeneration potion:", + "on healing of a zombie, cow or a wither:", + "\theal reason is healing potion", + "\tcancel event" + ) + .since("1.0, INSERT VERSION (by reason)"); + } + + @Nullable + private Literal> entityDatas; + + @Nullable + private Literal healReasons; + + @Override + @SuppressWarnings("unchecked") + public boolean init(Literal[] args, int matchedPattern, ParseResult parser) { + entityDatas = (Literal>) args[0]; + healReasons = (Literal) args[1]; + return true; + } + + @Override + public boolean check(Event event) { + if (!(event instanceof EntityRegainHealthEvent)) + return false; + EntityRegainHealthEvent healthEvent = (EntityRegainHealthEvent) event; + if (entityDatas != null) { + Entity compare = healthEvent.getEntity(); + boolean result = false; + for (EntityData entityData : entityDatas.getAll()) { + if (entityData.isInstance(compare)) { + result = true; + break; + } + } + if (!result) + return false; + } + if (healReasons != null) { + RegainReason compare = healthEvent.getRegainReason(); + boolean result = false; + for (RegainReason healReason : healReasons.getAll()) { + if (healReason == compare) { + result = true; + break; + } + } + if (!result) + return false; + } + return true; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return "heal" + (entityDatas != null ? " of " + entityDatas.toString(event, debug) : "") + + (healReasons != null ? " by " + healReasons.toString(event, debug) : ""); + } + +} diff --git a/src/main/java/ch/njol/skript/events/SimpleEvents.java b/src/main/java/ch/njol/skript/events/SimpleEvents.java index c470d68a07d..3ac8cce5e1a 100644 --- a/src/main/java/ch/njol/skript/events/SimpleEvents.java +++ b/src/main/java/ch/njol/skript/events/SimpleEvents.java @@ -57,7 +57,6 @@ import org.bukkit.event.entity.EntityMountEvent; import org.bukkit.event.entity.EntityPortalEnterEvent; import org.bukkit.event.entity.EntityPortalEvent; -import org.bukkit.event.entity.EntityRegainHealthEvent; import org.bukkit.event.entity.EntityResurrectEvent; import org.bukkit.event.entity.EntityTameEvent; import org.bukkit.event.entity.EntityToggleGlideEvent; @@ -209,10 +208,6 @@ public class SimpleEvents { .description("Called when an entity enters a nether portal or an end portal. Please note that this event will be fired many times for a nether portal.") .examples("on portal enter:") .since("1.0"); - Skript.registerEvent("Heal", SimpleEvent.class, EntityRegainHealthEvent.class, "heal[ing]") - .description("Called when an entity is healed, e.g. by eating (players), being fed (pets), or by the effect of a potion of healing (overworld mobs) or harm (nether mobs).") - .examples("on heal:") - .since("1.0"); Skript.registerEvent("Tame", SimpleEvent.class, EntityTameEvent.class, "[entity] tam(e|ing)") .description("Called when a player tames a wolf or ocelot. Can be cancelled to prevent the entity from being tamed.") .examples("on tame:") diff --git a/src/main/java/ch/njol/skript/expressions/ExprHealAmount.java b/src/main/java/ch/njol/skript/expressions/ExprHealAmount.java index 9e74f6aa68e..ae905e96fd7 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprHealAmount.java +++ b/src/main/java/ch/njol/skript/expressions/ExprHealAmount.java @@ -25,6 +25,7 @@ import ch.njol.skript.Skript; import ch.njol.skript.classes.Changer; +import ch.njol.skript.classes.Changer.ChangeMode; import ch.njol.skript.doc.Description; import ch.njol.skript.doc.Events; import ch.njol.skript.doc.Examples; @@ -32,49 +33,49 @@ import ch.njol.skript.doc.Since; import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.ExpressionType; -import ch.njol.skript.lang.SkriptParser; +import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.lang.util.SimpleExpression; -import ch.njol.skript.log.ErrorQuality; import ch.njol.util.Kleenean; import ch.njol.util.coll.CollectionUtils; @Name("Heal Amount") -@Description("The amount of health healed in a healing event.") -@Examples({"increase heal amount by 2", - "remove 0.5 from heal amount"}) -@Since("2.5.1") +@Description("The amount of health healed in a heal event.") +@Examples({ + "on player healing:", + "\tincrease the heal amount by 2", + "\tremove 0.5 from the healing amount" +}) @Events("heal") -public class ExprHealAmount extends SimpleExpression { - +@Since("2.5.1") +public class ExprHealAmount extends SimpleExpression { + static { - Skript.registerExpression(ExprHealAmount.class, Number.class, ExpressionType.SIMPLE, "[the] heal amount"); + Skript.registerExpression(ExprHealAmount.class, Double.class, ExpressionType.SIMPLE, "[the] heal[ing] amount"); } - - @SuppressWarnings("null") + private Kleenean delay; - + @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { if (!getParser().isCurrentEvent(EntityRegainHealthEvent.class)) { - Skript.error("The expression 'heal amount' may only be used in a healing event", ErrorQuality.SEMANTIC_ERROR); + Skript.error("The expression 'heal amount' may only be used in a healing event"); return false; } delay = isDelayed; return true; } - + @Nullable @Override - protected Number[] get(Event e) { - if (!(e instanceof EntityRegainHealthEvent)) + protected Double[] get(Event event) { + if (!(event instanceof EntityRegainHealthEvent)) return null; - - return new Number[]{((EntityRegainHealthEvent) e).getAmount()}; + return new Double[]{((EntityRegainHealthEvent) event).getAmount()}; } - + @Nullable @Override - public Class[] acceptChange(Changer.ChangeMode mode) { + public Class[] acceptChange(ChangeMode mode) { if (delay != Kleenean.FALSE) { Skript.error("The heal amount cannot be changed after the event has already passed"); return null; @@ -83,42 +84,48 @@ public Class[] acceptChange(Changer.ChangeMode mode) { return null; return CollectionUtils.array(Number.class); } - + @Override - public void change(Event e, @Nullable Object[] delta, Changer.ChangeMode mode) { - if (!(e instanceof EntityRegainHealthEvent)) + public void change(Event event, @Nullable Object[] delta, ChangeMode mode) { + if (!(event instanceof EntityRegainHealthEvent)) return; + EntityRegainHealthEvent healthEvent = (EntityRegainHealthEvent) event; double value = delta == null ? 0 : ((Number) delta[0]).doubleValue(); switch (mode) { case SET: case DELETE: - ((EntityRegainHealthEvent) e).setAmount(value); + healthEvent.setAmount(value); break; case ADD: - ((EntityRegainHealthEvent) e).setAmount(((EntityRegainHealthEvent) e).getAmount() + value); + healthEvent.setAmount(healthEvent.getAmount() + value); break; case REMOVE: - ((EntityRegainHealthEvent) e).setAmount(((EntityRegainHealthEvent) e).getAmount() - value); + healthEvent.setAmount(healthEvent.getAmount() - value); break; default: break; } } - + + @Override + public boolean setTime(int time) { + return super.setTime(time, EntityRegainHealthEvent.class); + } + @Override public boolean isSingle() { return true; } - + @Override - public Class getReturnType() { - return Number.class; + public Class getReturnType() { + return Double.class; } - + @Override - public String toString(@Nullable Event e, boolean debug) { + public String toString(@Nullable Event event, boolean debug) { return "heal amount"; } - + } diff --git a/src/main/java/ch/njol/skript/expressions/ExprHealReason.java b/src/main/java/ch/njol/skript/expressions/ExprHealReason.java index 12dc0270976..330ec4ed4d7 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprHealReason.java +++ b/src/main/java/ch/njol/skript/expressions/ExprHealReason.java @@ -18,67 +18,40 @@ */ package ch.njol.skript.expressions; -import org.bukkit.event.Event; -import org.bukkit.event.entity.EntityRegainHealthEvent; -import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason; -import org.eclipse.jdt.annotation.Nullable; - -import ch.njol.skript.Skript; import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Events; import ch.njol.skript.doc.Examples; import ch.njol.skript.doc.Name; import ch.njol.skript.doc.Since; -import ch.njol.skript.lang.Expression; -import ch.njol.skript.lang.ExpressionType; -import ch.njol.skript.lang.SkriptParser.ParseResult; -import ch.njol.skript.lang.util.SimpleExpression; -import ch.njol.skript.log.ErrorQuality; -import ch.njol.util.Kleenean; +import ch.njol.skript.expressions.base.EventValueExpression; +import ch.njol.skript.registrations.EventValues; +import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason; @Name("Heal Reason") -@Description("The heal reason of a heal event. Please click on the link for more information.") -@Examples({"on heal:", - "\tif heal reason = satiated:", - "\t\tsend \"You ate enough food and gained health back!\" to player"}) +@Description("The heal reason of a heal event.") +@Examples({ + "on heal:", + "\theal reason is satiated", + "\tsend \"You ate enough food and gained full health back!\"" +}) +@Events("heal") @Since("2.5") -public class ExprHealReason extends SimpleExpression { - +public class ExprHealReason extends EventValueExpression { + static { - Skript.registerExpression(ExprHealReason.class, RegainReason.class, ExpressionType.SIMPLE, "(regen|health regain|heal) (reason|cause)"); + register(ExprHealReason.class, RegainReason.class, "(regen|health regain|heal[ing]) (reason|cause)"); } - - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { - if (!getParser().isCurrentEvent(EntityRegainHealthEvent.class)) { - Skript.error("Heal reason can only be used in an on heal event", ErrorQuality.SEMANTIC_ERROR); - return false; - } - return true; - } - - @Nullable - @Override - protected RegainReason[] get(Event e) { - if (!(e instanceof EntityRegainHealthEvent)) - return null; - return new RegainReason[]{((EntityRegainHealthEvent) e).getRegainReason()}; + public ExprHealReason() { + super(RegainReason.class); } - - @Override - public boolean isSingle() { - return true; - } - - @Override - public Class getReturnType() { - return RegainReason.class; - } - + @Override - public String toString(@Nullable Event e, boolean debug) { - return "heal reason"; + public boolean setTime(int time) { + if (time == EventValues.TIME_FUTURE) + return false; + return super.setTime(time); } - + } From befa81f902ddf5cb22bcb2c7bcf7dd9bcf2a4896 Mon Sep 17 00:00:00 2001 From: Shane Bee Date: Mon, 1 Jul 2024 13:04:49 -0700 Subject: [PATCH 24/27] RegistryParser - strip out minecraft namespaces from docs (#6844) * RegistryParser - strip out minecraft namespaces from docs * RegistryParser - Stream#toList() not available on older java versions --------- Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com> --- .../java/ch/njol/skript/classes/data/BukkitClasses.java | 9 ++++++--- .../ch/njol/skript/classes/registry/RegistryParser.java | 6 ++---- 2 files changed, 8 insertions(+), 7 deletions(-) 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 7ff72f27e69..b48c69149d7 100644 --- a/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java +++ b/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java @@ -990,7 +990,8 @@ public String toVariableNameString(final ItemStack i) { Classes.registerClass(biomeClassInfo .user("biomes?") .name("Biome") - .description("All possible biomes Minecraft uses to generate a world.") + .description("All possible biomes Minecraft uses to generate a world.", + "NOTE: Minecraft namespaces are supported, ex: 'minecraft:basalt_deltas'.") .examples("biome at the player is desert") .since("1.4.4") .after("damagecause")); @@ -1465,7 +1466,8 @@ public String toVariableNameString(FireworkEffect effect) { Classes.registerClass(catTypeClassInfo .user("cat ?(type|race)s?") .name("Cat Type") - .description("Represents the race/type of a cat entity.") + .description("Represents the race/type of a cat entity.", + "NOTE: Minecraft namespaces are supported, ex: 'minecraft:british_shorthair'.") .since("2.4") .requiredPlugins("Minecraft 1.14 or newer") .documentationId("CatType")); @@ -1533,7 +1535,8 @@ public String toVariableNameString(EnchantmentOffer eo) { .user("attribute ?types?") .name("Attribute Type") .description("Represents the type of an attribute. Note that this type does not contain any numerical values." - + "See attribute types for more info.") + + "See attribute types for more info.", + "NOTE: Minecraft namespaces are supported, ex: 'minecraft:generic.attack_damage'.") .since("2.5")); Classes.registerClass(new EnumClassInfo<>(Environment.class, "environment", "environments") diff --git a/src/main/java/ch/njol/skript/classes/registry/RegistryParser.java b/src/main/java/ch/njol/skript/classes/registry/RegistryParser.java index 51cb4637434..dc9bf9f00b7 100644 --- a/src/main/java/ch/njol/skript/classes/registry/RegistryParser.java +++ b/src/main/java/ch/njol/skript/classes/registry/RegistryParser.java @@ -30,12 +30,11 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.stream.Collectors; /** * A parser based on a {@link Registry} used to parse data from a string or turn data into a string. @@ -147,8 +146,7 @@ private void refresh() { * Note that some entries may represent the same registry object. */ public String getAllNames() { - List strings = new ArrayList<>(parseMap.keySet()); - Collections.sort(strings); + List strings = parseMap.keySet().stream().filter(s -> !s.startsWith("minecraft:")).sorted().collect(Collectors.toList()); return StringUtils.join(strings, ", "); } From 3c0119f4351dae51b02936d37e02625769451d0c Mon Sep 17 00:00:00 2001 From: cheeezburga <47320303+cheeezburga@users.noreply.github.com> Date: Tue, 2 Jul 2024 06:24:03 +1000 Subject: [PATCH 25/27] Adds tooltip syntax (#6712) * Adds effect, condition, and tests for tooltip-related syntax * Removed star imports * Apply suggestions from code review Co-authored-by: Patrick Miller Co-authored-by: Fusezion * Suggestions from Pickle and Lyric - Changed the parse marks/tags in the effect and patterns for the condition - Added some info to the condition's description * Apply suggestions from code review Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com> * Some more suggestions - Changed the condition to use setNegated and isNegated, and use Sovde's pattern changes - Changed the effect description and fixed to work with Sovde's pattern changes * Small fix * Apply suggestions from code review Co-authored-by: LimeGlass <16087552+TheLimeGlass@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: LimeGlass <16087552+TheLimeGlass@users.noreply.github.com> * Update src/main/java/ch/njol/skript/conditions/CondTooltip.java Co-authored-by: Patrick Miller * Adds "reveal" as option in syntax --------- Co-authored-by: Patrick Miller Co-authored-by: Fusezion Co-authored-by: Moderocky Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com> Co-authored-by: LimeGlass <16087552+TheLimeGlass@users.noreply.github.com> --- .../njol/skript/conditions/CondTooltip.java | 87 +++++++++++++++++ .../ch/njol/skript/effects/EffTooltip.java | 95 +++++++++++++++++++ .../tests/syntaxes/conditions/CondTooltip.sk | 15 +++ 3 files changed, 197 insertions(+) create mode 100644 src/main/java/ch/njol/skript/conditions/CondTooltip.java create mode 100644 src/main/java/ch/njol/skript/effects/EffTooltip.java create mode 100644 src/test/skript/tests/syntaxes/conditions/CondTooltip.sk diff --git a/src/main/java/ch/njol/skript/conditions/CondTooltip.java b/src/main/java/ch/njol/skript/conditions/CondTooltip.java new file mode 100644 index 00000000000..dc7c795ca76 --- /dev/null +++ b/src/main/java/ch/njol/skript/conditions/CondTooltip.java @@ -0,0 +1,87 @@ +/** + * 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.conditions; + +import ch.njol.skript.Skript; +import ch.njol.skript.aliases.ItemType; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.RequiredPlugins; +import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Condition; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.util.Kleenean; +import org.bukkit.event.Event; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.meta.ItemMeta; +import org.eclipse.jdt.annotation.Nullable; + +@Name("Has Item Tooltips") +@Description({ + "Whether the entire or additional tooltip of an item is shown or hidden.", + "The 'entire tooltip' is what shows to the player when they hover an item (i.e. name, lore, etc.).", + "The 'additional tooltip' hides certain information from certain items (potions, maps, books, fireworks, and banners)." +}) +@Examples({ + "send true if entire tooltip of player's tool is shown", + "if additional tooltip of {_item} is hidden:" +}) +@RequiredPlugins("Spigot 1.20.5+") +@Since("INSERT VERSION") +public class CondTooltip extends Condition { + + static { + if (Skript.methodExists(ItemMeta.class, "isHideTooltip")) {// this method was added in the same version as the additional tooltip item flag + Skript.registerCondition(CondTooltip.class, + "[the] [entire|:additional] tool[ ]tip[s] of %itemtypes% (is|are) (:shown|hidden)", + "[the] [entire|:additional] tool[ ]tip[s] of %itemtypes% (isn't|is not|aren't|are not) (:shown|hidden)", + "%itemtypes%'[s] [entire|:additional] tool[ ]tip[s] (is|are) (:shown|hidden)", + "%itemtypes%'[s] [entire|:additional] tool[ ]tip[s] (isn't|is not|aren't|are not) (:shown|hidden)" + ); + } + } + + @SuppressWarnings("NotNullFieldNotInitialized") + private Expression items; + private boolean entire; + + @Override + @SuppressWarnings("unchecked") + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + items = (Expression) exprs[0]; + entire = !parseResult.hasTag("additional"); + setNegated(parseResult.hasTag("shown") ^ (matchedPattern == 1 || matchedPattern == 3)); + return true; + } + + @Override + public boolean check(Event event) { + if (entire) + return items.check(event, item -> item.getItemMeta().isHideTooltip(), isNegated()); + return items.check(event, item -> item.getItemMeta().hasItemFlag(ItemFlag.HIDE_ADDITIONAL_TOOLTIP), isNegated()); + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return "the " + (entire ? "entire" : "additional") + " tooltip of " + items.toString(event, debug) + " is " + (isNegated() ? "hidden" : "shown"); + } + +} diff --git a/src/main/java/ch/njol/skript/effects/EffTooltip.java b/src/main/java/ch/njol/skript/effects/EffTooltip.java new file mode 100644 index 00000000000..26272c4b716 --- /dev/null +++ b/src/main/java/ch/njol/skript/effects/EffTooltip.java @@ -0,0 +1,95 @@ +/** + * 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.aliases.ItemType; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.RequiredPlugins; +import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Effect; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.util.Kleenean; +import org.bukkit.event.Event; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.meta.ItemMeta; +import org.eclipse.jdt.annotation.Nullable; + +@Name("Item Tooltips") +@Description({ + "Show or hide the tooltip of an item.", + "If changing the 'entire' tooltip of an item, nothing will show up when a player hovers over it.", + "If changing the 'additional' tooltip, only specific parts (which change per item) will be hidden." +}) +@Examples({ + "hide the entire tooltip of player's tool", + "hide {_item}'s additional tool tip" +}) +@RequiredPlugins("Spigot 1.20.5+") +@Since("INSERT VERSION") +public class EffTooltip extends Effect { + + static { + if (Skript.methodExists(ItemMeta.class, "setHideTooltip", boolean.class)) { // this method was added in the same version as the additional tooltip item flag + Skript.registerEffect(EffTooltip.class, + "(show|reveal|:hide) %itemtypes%'[s] [entire|:additional] tool[ ]tip", + "(show|reveal|:hide) [the] [entire|:additional] tool[ ]tip of %itemtypes%" + ); + } + } + + @SuppressWarnings("NotNullFieldNotInitialized") + private Expression items; + private boolean hide, entire; + + @Override + @SuppressWarnings("unchecked") + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + items = (Expression) exprs[0]; + hide = parseResult.hasTag("hide"); + entire = !parseResult.hasTag("additional"); + return true; + } + + @Override + protected void execute(Event event) { + for (ItemType item : items.getArray(event)) { + ItemMeta meta = item.getItemMeta(); + if (entire) { + meta.setHideTooltip(hide); + } else { + if (hide) { + meta.addItemFlags(ItemFlag.HIDE_ADDITIONAL_TOOLTIP); + } else { + meta.removeItemFlags(ItemFlag.HIDE_ADDITIONAL_TOOLTIP); + } + } + item.setItemMeta(meta); + } + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return (hide ? "hide" : "show") + " the " + (entire ? "entire" : "additional") + " tooltip of " + items.toString(event, debug); + } + +} diff --git a/src/test/skript/tests/syntaxes/conditions/CondTooltip.sk b/src/test/skript/tests/syntaxes/conditions/CondTooltip.sk new file mode 100644 index 00000000000..117a2b5bbb1 --- /dev/null +++ b/src/test/skript/tests/syntaxes/conditions/CondTooltip.sk @@ -0,0 +1,15 @@ +test "tooltip" when running minecraft "1.20.5": + + set {_item} to a diamond + assert entire tooltip of {_item} is shown with "item unexpectedly doesn't have entire tooltip" + assert additional tooltip of {_item} is shown with "item unexpectedly doesn't have additional tooltip" + + hide entire tooltip of {_item} + assert entire tooltip of {_item} is hidden with "item unexpectedly has entire tooltip" + hide additional tooltip of {_item} + assert additional tooltip of {_item} is hidden with "item unexpectedly has additional tooltip" + + show entire tooltip of {_item} + assert entire tooltip of {_item} is shown with "item unexpectedly doesn't have entire tooltip" + show additional tooltip of {_item} + assert additional tooltip of {_item} is shown with "item unexpectedly doesn't have additional tooltip" From d4ccff74c90614375b4bc41c032bfa19c6bb2ae5 Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Mon, 1 Jul 2024 22:38:24 +0200 Subject: [PATCH 26/27] Exposes 'load default aliases' config option and removes hardcoded alias dependencies (#6834) * Removes dependencies on hardcoded aliases (javaItemType) and exposes 'load deafult aliases' config option * Update ItemUtils.java * Apply suggestions from code review Co-authored-by: Patrick Miller * requested changes * requested * Update src/main/java/ch/njol/skript/expressions/ExprSpawnerType.java Co-authored-by: Patrick Miller --------- Co-authored-by: Patrick Miller --- .../java/ch/njol/skript/aliases/Aliases.java | 11 ++- .../java/ch/njol/skript/aliases/ItemType.java | 13 +++ .../ch/njol/skript/bukkitutil/ItemUtils.java | 59 +++++++++++- .../bukkitutil/block/NewBlockCompat.java | 90 ++++++++++--------- .../classes/data/BukkitEventValues.java | 6 +- .../classes/data/DefaultComparators.java | 3 +- .../java/ch/njol/skript/effects/EffEquip.java | 61 +++++++++++-- .../ch/njol/skript/effects/EffOpenBook.java | 5 +- .../ch/njol/skript/entity/BoatChestData.java | 29 ++---- .../java/ch/njol/skript/entity/BoatData.java | 24 ++--- .../njol/skript/entity/ThrownPotionData.java | 19 ++-- .../java/ch/njol/skript/events/EvtMoveOn.java | 14 ++- .../njol/skript/events/EvtPressurePlate.java | 31 +++++-- .../skript/expressions/ExprBurnCookTime.java | 15 ++-- .../ch/njol/skript/expressions/ExprName.java | 4 +- .../njol/skript/expressions/ExprSignText.java | 22 ++--- .../ch/njol/skript/expressions/ExprSkull.java | 5 +- .../skript/expressions/ExprSpawnerType.java | 19 ++-- src/main/resources/config.sk | 10 +++ 19 files changed, 290 insertions(+), 150 deletions(-) diff --git a/src/main/java/ch/njol/skript/aliases/Aliases.java b/src/main/java/ch/njol/skript/aliases/Aliases.java index 56bffc24f9a..fe1a3a624c4 100644 --- a/src/main/java/ch/njol/skript/aliases/Aliases.java +++ b/src/main/java/ch/njol/skript/aliases/Aliases.java @@ -25,6 +25,7 @@ import ch.njol.skript.config.Node; import ch.njol.skript.config.SectionNode; import ch.njol.skript.entity.EntityData; +import org.bukkit.entity.EntityType; import org.skriptlang.skript.lang.script.Script; import ch.njol.skript.lang.parser.ParserInstance; import ch.njol.skript.localization.ArgsMessage; @@ -431,7 +432,6 @@ private static void loadInternal() throws IOException { Path aliasesPath = zipFs.getPath("/", "aliases-english"); assert aliasesPath != null; loadDirectory(aliasesPath); - loadMissingAliases(); } } catch (URISyntaxException e) { assert false; @@ -445,6 +445,9 @@ private static void loadInternal() throws IOException { assert aliasesFolder != null; loadDirectory(aliasesFolder); } + + // generate aliases from item names for any missing items + loadMissingAliases(); // Update tracked item types for (Map.Entry entry : trackedTypes.entrySet()) { @@ -554,10 +557,16 @@ public static EntityData getRelatedEntity(ItemData data) { *

Item types provided by this method are updated when aliases are * reloaded. However, this also means they are tracked by aliases system * and NOT necessarily garbage-collected. + * + *

Relying on this method to create item types is not safe, + * as users can change aliases at any point. ItemTypes should instead be created + * via {@link Material}s, {@link org.bukkit.Tag}s, or any other manual method. + * * @param name Name of item to search from aliases. * @return An item. * @throws IllegalArgumentException When item is not found. */ + @Deprecated(forRemoval = true, since = "2.9.0") public static ItemType javaItemType(String name) { ItemType type = parseItemType(name); if (type == null) { diff --git a/src/main/java/ch/njol/skript/aliases/ItemType.java b/src/main/java/ch/njol/skript/aliases/ItemType.java index 0b47617ef5c..efaa59249f2 100644 --- a/src/main/java/ch/njol/skript/aliases/ItemType.java +++ b/src/main/java/ch/njol/skript/aliases/ItemType.java @@ -40,6 +40,7 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.OfflinePlayer; +import org.bukkit.Tag; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.block.Skull; @@ -173,6 +174,18 @@ public ItemType(Material id) { add_(new ItemData(id)); } + public ItemType(Material... ids) { + for (Material id : ids) { + add_(new ItemData(id)); + } + } + + public ItemType(Tag tag) { + for (Material id : tag.getValues()) { + add_(new ItemData(id)); + } + } + public ItemType(Material id, String tags) { add_(new ItemData(id, tags)); } diff --git a/src/main/java/ch/njol/skript/bukkitutil/ItemUtils.java b/src/main/java/ch/njol/skript/bukkitutil/ItemUtils.java index 216be44b918..611aba0d1d7 100644 --- a/src/main/java/ch/njol/skript/bukkitutil/ItemUtils.java +++ b/src/main/java/ch/njol/skript/bukkitutil/ItemUtils.java @@ -21,7 +21,13 @@ import ch.njol.skript.Skript; import ch.njol.skript.aliases.ItemType; import org.bukkit.Material; +import org.bukkit.Tag; import org.bukkit.TreeType; +import org.bukkit.block.Block; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.type.Fence; +import org.bukkit.block.data.type.Gate; +import org.bukkit.block.data.type.Wall; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.Damageable; import org.bukkit.inventory.meta.ItemMeta; @@ -234,5 +240,56 @@ public static boolean isAir(Material type) { public static Material getTreeSapling(TreeType treeType) { return TREE_TO_SAPLING_MAP.get(treeType); } - + + + private static final boolean HAS_FENCE_TAGS = !Skript.isRunningMinecraft(1, 14); + + /** + * Whether the block is a fence or a wall. + * @param block the block to check. + * @return whether the block is a fence/wall. + */ + public static boolean isFence(Block block) { + // TODO: 1.13 only, so remove in 2.10 + if (!HAS_FENCE_TAGS) { + BlockData data = block.getBlockData(); + return data instanceof Fence + || data instanceof Wall + || data instanceof Gate; + } + + Material type = block.getType(); + return Tag.FENCES.isTagged(type) + || Tag.FENCE_GATES.isTagged(type) + || Tag.WALLS.isTagged(type); + } + + /** + * @param material The material to check + * @return whether the material is a full glass block + */ + public static boolean isGlass(Material material) { + switch (material) { + case GLASS: + case RED_STAINED_GLASS: + case ORANGE_STAINED_GLASS: + case YELLOW_STAINED_GLASS: + case LIGHT_BLUE_STAINED_GLASS: + case BLUE_STAINED_GLASS: + case CYAN_STAINED_GLASS: + case LIME_STAINED_GLASS: + case GREEN_STAINED_GLASS: + case MAGENTA_STAINED_GLASS: + case PURPLE_STAINED_GLASS: + case PINK_STAINED_GLASS: + case WHITE_STAINED_GLASS: + case LIGHT_GRAY_STAINED_GLASS: + case GRAY_STAINED_GLASS: + case BLACK_STAINED_GLASS: + case BROWN_STAINED_GLASS: + return true; + default: + return false; + } + } } diff --git a/src/main/java/ch/njol/skript/bukkitutil/block/NewBlockCompat.java b/src/main/java/ch/njol/skript/bukkitutil/block/NewBlockCompat.java index e5cf9c0567b..e72a947996f 100644 --- a/src/main/java/ch/njol/skript/bukkitutil/block/NewBlockCompat.java +++ b/src/main/java/ch/njol/skript/bukkitutil/block/NewBlockCompat.java @@ -22,6 +22,7 @@ import ch.njol.skript.aliases.Aliases; import ch.njol.skript.aliases.ItemType; import ch.njol.skript.aliases.MatchQuality; +import ch.njol.skript.bukkitutil.ItemUtils; import ch.njol.skript.variables.Variables; import ch.njol.yggdrasil.Fields; import org.bukkit.Bukkit; @@ -31,10 +32,12 @@ import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; +import org.bukkit.block.BlockSupport; import org.bukkit.block.data.Bisected; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Directional; import org.bukkit.block.data.type.Bed; +import org.bukkit.block.data.type.Snow; import org.bukkit.entity.FallingBlock; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; @@ -141,15 +144,6 @@ public void deserialize(@NonNull Fields fields) throws StreamCorruptedException } private static class NewBlockSetter implements BlockSetter { - - private ItemType floorTorch; - private ItemType wallTorch; - - private ItemType specialTorchSides; - private ItemType specialTorchFloors; - - private boolean typesLoaded = false; - private static final BlockFace[] CARDINAL_FACES = new BlockFace[] {BlockFace.NORTH, BlockFace.EAST, BlockFace.SOUTH, BlockFace.WEST}; @@ -158,14 +152,11 @@ public NewBlockSetter() {} @Override public void setBlock(Block block, Material type, @Nullable BlockValues values, int flags) { - if (!typesLoaded) - loadTypes(); - - boolean rotate = (flags | ROTATE) != 0; - boolean rotateForce = (flags | ROTATE_FORCE) != 0; - boolean rotateFixType = (flags | ROTATE_FIX_TYPE) != 0; - boolean multipart = (flags | MULTIPART) != 0; - boolean applyPhysics = (flags | APPLY_PHYSICS) != 0; + boolean rotate = (flags & ROTATE) != 0; + boolean rotateForce = (flags & ROTATE_FORCE) != 0; + boolean rotateFixType = (flags & ROTATE_FIX_TYPE) != 0; + boolean multipart = (flags & MULTIPART) != 0; + boolean applyPhysics = (flags & APPLY_PHYSICS) != 0; NewBlockValues ourValues = null; if (values != null) ourValues = (NewBlockValues) values; @@ -178,31 +169,23 @@ public void setBlock(Block block, Material type, @Nullable BlockValues values, i */ boolean placed = false; if (rotate) { - if (floorTorch.isOfType(type) || (rotateFixType && wallTorch.isOfType(type))) { + if (type == Material.TORCH || (rotateFixType && type == Material.WALL_TORCH)) { // If floor torch cannot be placed, try a wall torch Block under = block.getRelative(0, -1, 0); - boolean canPlace = true; - if (!under.getType().isOccluding()) { // Usually cannot be placed, but there are exceptions - // TODO check for stairs and slabs, currently complicated since there is no 'any' alias - if (specialTorchFloors.isOfType(under)) { - canPlace = true; - } else { - canPlace = false; - } - } + boolean canPlace = canSupportFloorTorch(under); // Can't really place a floor torch, try wall one instead if (!canPlace) { BlockFace face = findWallTorchSide(block); if (face != null) { // Found better torch spot - block.setType(wallTorch.getMaterial()); + block.setType(Material.WALL_TORCH); Directional data = (Directional) block.getBlockData(); data.setFacing(face); block.setBlockData(data, applyPhysics); placed = true; } } - } else if (wallTorch.isOfType(type)) { + } else if (type == Material.WALL_TORCH) { Directional data; if (ourValues != null) data = (Directional) ourValues.data; @@ -210,7 +193,7 @@ public void setBlock(Block block, Material type, @Nullable BlockValues values, i data = (Directional) Bukkit.createBlockData(type); Block relative = block.getRelative(data.getFacing()); - if ((!relative.getType().isOccluding() && !specialTorchSides.isOfType(relative)) || rotateForce) { + if ((!canSupportWallTorch(relative, data.getFacing().getOppositeFace())) || rotateForce) { // Attempt to figure out a better rotation BlockFace face = findWallTorchSide(block); if (face != null) { // Found better torch spot @@ -294,22 +277,49 @@ public void setBlock(Block block, Material type, @Nullable BlockValues values, i block.setBlockData(ourValues.data, applyPhysics); } } - - private void loadTypes() { - floorTorch = Aliases.javaItemType("floor torch"); - wallTorch = Aliases.javaItemType("wall torch"); - - specialTorchSides = Aliases.javaItemType("special torch sides"); - specialTorchFloors = Aliases.javaItemType("special torch floors"); - - typesLoaded = true; + + // 1.19+ + // TODO: remove in 2.10 + private static final boolean HAS_BLOCK_SUPPORT = Skript.classExists("org.bukkit.block.BlockSupport"); + + /** + * Returns whether this block can support a floor torch. + * @param block The block the torch will be placed on + * @return whether the block can support the torch. + */ + private static boolean canSupportFloorTorch(Block block) { + if (HAS_BLOCK_SUPPORT) + return block.getBlockData().isFaceSturdy(BlockFace.UP, BlockSupport.CENTER); + + Material material = block.getType(); + return (material.isOccluding() + || canSupportWallTorch(block, null) + || ItemUtils.isFence(block) + || ItemUtils.isGlass(material) + || material == Material.HOPPER + || (material == Material.SNOW && (((Snow) block.getBlockData()).getLayers() == 8)) + ); + } + + /** + * Returns whether this block can support a wall torch. In 1.19+, a face can be specified. + * @param block The block the torch will be placed on + * @param face The face the torch will be placed on (only considered in 1.19+) + * @return whether the block face can support the torch. + */ + private static boolean canSupportWallTorch(Block block, @Nullable BlockFace face) { + if (HAS_BLOCK_SUPPORT && face != null) + return block.getBlockData().isFaceSturdy(face, BlockSupport.FULL); + + Material material = block.getType(); + return material.isOccluding() || material == Material.SOUL_SAND || material == Material.SPAWNER; } @Nullable private BlockFace findWallTorchSide(Block block) { for (BlockFace face : CARDINAL_FACES) { Block relative = block.getRelative(face); - if (relative.getType().isOccluding() || specialTorchSides.isOfType(relative)) + if (relative.getType().isOccluding() || canSupportWallTorch(relative, face.getOppositeFace())) return face.getOppositeFace(); // Torch can be rotated towards from this face } 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 6a49566c827..34792550178 100644 --- a/src/main/java/ch/njol/skript/classes/data/BukkitEventValues.java +++ b/src/main/java/ch/njol/skript/classes/data/BukkitEventValues.java @@ -392,12 +392,11 @@ public Block get(final BlockBreakEvent e) { return new DelayedChangeBlock(e.getBlock()); } }, 0); - ItemType stationaryWater = Aliases.javaItemType("stationary water"); EventValues.registerEventValue(BlockBreakEvent.class, Block.class, new Getter() { @Override public Block get(final BlockBreakEvent e) { final BlockState s = e.getBlock().getState(); - s.setType(s.getType() == Material.ICE ? stationaryWater.getMaterial() : Material.AIR); + s.setType(s.getType() == Material.ICE ? Material.WATER : Material.AIR); s.setRawData((byte) 0); return new BlockStateBlock(s, true); } @@ -760,12 +759,11 @@ public Block get(final PlayerBucketEmptyEvent e) { return e.getBlockClicked().getRelative(e.getBlockFace()); } }, -1); - ItemType stationaryLava = Aliases.javaItemType("stationary lava"); EventValues.registerEventValue(PlayerBucketEmptyEvent.class, Block.class, new Getter() { @Override public Block get(final PlayerBucketEmptyEvent e) { final BlockState s = e.getBlockClicked().getRelative(e.getBlockFace()).getState(); - s.setType(e.getBucket() == Material.WATER_BUCKET ? stationaryWater.getMaterial() : stationaryLava.getMaterial()); + s.setType(e.getBucket() == Material.WATER_BUCKET ? Material.WATER : Material.LAVA); s.setRawData((byte) 0); return new BlockStateBlock(s, true); } diff --git a/src/main/java/ch/njol/skript/classes/data/DefaultComparators.java b/src/main/java/ch/njol/skript/classes/data/DefaultComparators.java index 87fa10b1089..e5e42bf1423 100644 --- a/src/main/java/ch/njol/skript/classes/data/DefaultComparators.java +++ b/src/main/java/ch/njol/skript/classes/data/DefaultComparators.java @@ -496,7 +496,6 @@ public boolean supportsOrdering() { }); // DamageCause - ItemType - ItemType lava = Aliases.javaItemType("lava"); Comparators.registerComparator(DamageCause.class, ItemType.class, new Comparator() { @Override public Relation compare(DamageCause dc, ItemType t) { @@ -504,7 +503,7 @@ public Relation compare(DamageCause dc, ItemType t) { case FIRE: return Relation.get(t.isOfType(Material.FIRE)); case LAVA: - return Relation.get(t.equals(lava)); + return Relation.get(t.getMaterial() == Material.LAVA); case MAGIC: return Relation.get(t.isOfType(Material.POTION)); case HOT_FLOOR: diff --git a/src/main/java/ch/njol/skript/effects/EffEquip.java b/src/main/java/ch/njol/skript/effects/EffEquip.java index c66a5a1d2fd..baa7334b160 100644 --- a/src/main/java/ch/njol/skript/effects/EffEquip.java +++ b/src/main/java/ch/njol/skript/effects/EffEquip.java @@ -18,7 +18,9 @@ */ package ch.njol.skript.effects; +import ch.njol.skript.aliases.ItemData; import org.bukkit.Material; +import org.bukkit.Tag; import org.bukkit.entity.AbstractHorse; import org.bukkit.entity.ChestedHorse; import org.bukkit.entity.LivingEntity; @@ -93,13 +95,58 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye private static final boolean SUPPORTS_STEERABLE = Skript.classExists("org.bukkit.entity.Steerable"); - private static final ItemType CHESTPLATE = Aliases.javaItemType("chestplate"); - private static final ItemType LEGGINGS = Aliases.javaItemType("leggings"); - private static final ItemType BOOTS = Aliases.javaItemType("boots"); - private static final ItemType HORSE_ARMOR = Aliases.javaItemType("horse armor"); - private static final ItemType SADDLE = Aliases.javaItemType("saddle"); - private static final ItemType CHEST = Aliases.javaItemType("chest"); - private static final ItemType CARPET = Aliases.javaItemType("carpet"); + private static ItemType CHESTPLATE; + private static ItemType LEGGINGS; + private static ItemType BOOTS; + private static ItemType CARPET; + private static final ItemType HORSE_ARMOR = new ItemType(Material.IRON_HORSE_ARMOR, Material.GOLDEN_HORSE_ARMOR, Material.DIAMOND_HORSE_ARMOR); + private static final ItemType SADDLE = new ItemType(Material.SADDLE); + private static final ItemType CHEST = new ItemType(Material.CHEST); + + static { + boolean usesWoolCarpetTag = Skript.fieldExists(Tag.class, "WOOL_CARPET"); + CARPET = new ItemType(usesWoolCarpetTag ? Tag.WOOL_CARPETS : Tag.CARPETS); + // added in 1.20.6 + if (Skript.fieldExists(Tag.class, "ITEM_CHEST_ARMOR")) { + CHESTPLATE = new ItemType(Tag.ITEMS_CHEST_ARMOR); + LEGGINGS = new ItemType(Tag.ITEMS_LEG_ARMOR); + BOOTS = new ItemType(Tag.ITEMS_FOOT_ARMOR); + } else { + CHESTPLATE = new ItemType( + Material.LEATHER_CHESTPLATE, + Material.CHAINMAIL_CHESTPLATE, + Material.GOLDEN_CHESTPLATE, + Material.IRON_CHESTPLATE, + Material.DIAMOND_CHESTPLATE, + Material.ELYTRA + ); + + LEGGINGS = new ItemType( + Material.LEATHER_LEGGINGS, + Material.CHAINMAIL_LEGGINGS, + Material.GOLDEN_LEGGINGS, + Material.IRON_LEGGINGS, + Material.DIAMOND_LEGGINGS + ); + + BOOTS = new ItemType( + Material.LEATHER_BOOTS, + Material.CHAINMAIL_BOOTS, + Material.GOLDEN_BOOTS, + Material.IRON_BOOTS, + Material.DIAMOND_BOOTS + ); + + // netherite + if (Skript.isRunningMinecraft(1,16)) { + CHESTPLATE.add(new ItemData(Material.NETHERITE_CHESTPLATE)); + LEGGINGS.add(new ItemData(Material.NETHERITE_LEGGINGS)); + BOOTS.add(new ItemData(Material.NETHERITE_BOOTS)); + } + } + } + + private static final ItemType[] ALL_EQUIPMENT = new ItemType[] {CHESTPLATE, LEGGINGS, BOOTS, HORSE_ARMOR, SADDLE, CHEST, CARPET}; diff --git a/src/main/java/ch/njol/skript/effects/EffOpenBook.java b/src/main/java/ch/njol/skript/effects/EffOpenBook.java index 5b96114818b..f49df089abe 100644 --- a/src/main/java/ch/njol/skript/effects/EffOpenBook.java +++ b/src/main/java/ch/njol/skript/effects/EffOpenBook.java @@ -18,6 +18,7 @@ */ package ch.njol.skript.effects; +import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.inventory.ItemStack; @@ -49,8 +50,6 @@ public class EffOpenBook extends Effect { } } - private static final ItemType bookItemType = Aliases.javaItemType("written book"); - @SuppressWarnings("null") private Expression book; @SuppressWarnings("null") @@ -69,7 +68,7 @@ protected void execute(final Event e) { ItemType itemType = book.getSingle(e); if (itemType != null) { ItemStack itemStack = itemType.getRandom(); - if (itemStack != null && bookItemType.isOfType(itemStack)) { + if (itemStack.getType() == Material.WRITTEN_BOOK) { for (Player player : players.getArray(e)) { player.openBook(itemStack); } diff --git a/src/main/java/ch/njol/skript/entity/BoatChestData.java b/src/main/java/ch/njol/skript/entity/BoatChestData.java index bb8d8506e23..bb29004028d 100644 --- a/src/main/java/ch/njol/skript/entity/BoatChestData.java +++ b/src/main/java/ch/njol/skript/entity/BoatChestData.java @@ -23,6 +23,7 @@ import ch.njol.skript.aliases.ItemType; import ch.njol.skript.lang.Literal; import ch.njol.skript.lang.SkriptParser; +import org.bukkit.Material; import org.bukkit.TreeSpecies; import org.bukkit.entity.ChestBoat; import org.bukkit.inventory.ItemStack; @@ -32,21 +33,8 @@ public class BoatChestData extends EntityData { - private static ItemType oakBoat = null; - private static ItemType spruceBoat = null; - private static ItemType birchBoat = null; - private static ItemType jungleBoat = null; - private static ItemType acaciaBoat = null; - private static ItemType darkOakBoat = null; - static { if (Skript.classExists("org.bukkit.entity.ChestBoat")) { - oakBoat = Aliases.javaItemType("oak chest boat"); - spruceBoat = Aliases.javaItemType("spruce chest boat"); - birchBoat = Aliases.javaItemType("birch chest boat"); - jungleBoat = Aliases.javaItemType("jungle chest boat"); - acaciaBoat = Aliases.javaItemType("acacia chest boat"); - darkOakBoat = Aliases.javaItemType("dark oak chest boat"); EntityData.register(BoatChestData.class, "chest boat", ChestBoat.class, 0, "chest boat", "any chest boat", "oak chest boat", "spruce chest boat", "birch chest boat", "jungle chest boat", "acacia chest boat", "dark oak chest boat"); @@ -120,22 +108,21 @@ public boolean isSupertypeOf(EntityData e) { } public boolean isOfItemType(ItemType itemType) { - if (itemType.getRandom() == null) - return false; int ordinal = -1; ItemStack stack = itemType.getRandom(); - if (oakBoat.isOfType(stack)) + Material type = stack.getType(); + if (type == Material.OAK_CHEST_BOAT) ordinal = 0; - else if (spruceBoat.isOfType(stack)) + else if (type == Material.SPRUCE_CHEST_BOAT) ordinal = TreeSpecies.REDWOOD.ordinal(); - else if (birchBoat.isOfType(stack)) + else if (type == Material.BIRCH_CHEST_BOAT) ordinal = TreeSpecies.BIRCH.ordinal(); - else if (jungleBoat.isOfType(stack)) + else if (type == Material.JUNGLE_CHEST_BOAT) ordinal = TreeSpecies.JUNGLE.ordinal(); - else if (acaciaBoat.isOfType(stack)) + else if (type == Material.ACACIA_CHEST_BOAT) ordinal = TreeSpecies.ACACIA.ordinal(); - else if (darkOakBoat.isOfType(stack)) + else if (type == Material.DARK_OAK_CHEST_BOAT) ordinal = TreeSpecies.DARK_OAK.ordinal(); return hashCode_i() == ordinal + 2 || (matchedPattern + ordinal == 0) || ordinal == 0; } diff --git a/src/main/java/ch/njol/skript/entity/BoatData.java b/src/main/java/ch/njol/skript/entity/BoatData.java index dfeb1f22890..b273f2ca370 100644 --- a/src/main/java/ch/njol/skript/entity/BoatData.java +++ b/src/main/java/ch/njol/skript/entity/BoatData.java @@ -18,8 +18,10 @@ */ package ch.njol.skript.entity; +import java.lang.reflect.Method; import java.util.Random; +import org.bukkit.Material; import org.bukkit.TreeSpecies; import org.bukkit.entity.Boat; import org.bukkit.inventory.ItemStack; @@ -108,30 +110,22 @@ public boolean isSupertypeOf(EntityData e) { return false; } - private static final ItemType oakBoat = Aliases.javaItemType("oak boat"); - private static final ItemType spruceBoat = Aliases.javaItemType("spruce boat"); - private static final ItemType birchBoat = Aliases.javaItemType("birch boat"); - private static final ItemType jungleBoat = Aliases.javaItemType("jungle boat"); - private static final ItemType acaciaBoat = Aliases.javaItemType("acacia boat"); - private static final ItemType darkOakBoat = Aliases.javaItemType("dark oak boat"); - public boolean isOfItemType(ItemType i){ - if (i.getRandom() == null) - return false; int ordinal = -1; ItemStack stack = i.getRandom(); - if (oakBoat.isOfType(stack)) + Material type = stack.getType(); + if (type == Material.OAK_BOAT) ordinal = 0; - else if (spruceBoat.isOfType(stack)) + else if (type == Material.SPRUCE_BOAT) ordinal = TreeSpecies.REDWOOD.ordinal(); - else if (birchBoat.isOfType(stack)) + else if (type == Material.BIRCH_BOAT) ordinal = TreeSpecies.BIRCH.ordinal(); - else if (jungleBoat.isOfType(stack)) + else if (type == Material.JUNGLE_BOAT) ordinal = TreeSpecies.JUNGLE.ordinal(); - else if (acaciaBoat.isOfType(stack)) + else if (type == Material.ACACIA_BOAT) ordinal = TreeSpecies.ACACIA.ordinal(); - else if (darkOakBoat.isOfType(stack)) + else if (type == Material.DARK_OAK_BOAT) ordinal = TreeSpecies.DARK_OAK.ordinal(); return hashCode_i() == ordinal + 2 || (matchedPattern + ordinal == 0) || ordinal == 0; diff --git a/src/main/java/ch/njol/skript/entity/ThrownPotionData.java b/src/main/java/ch/njol/skript/entity/ThrownPotionData.java index 407460d56c5..12d03199fbe 100644 --- a/src/main/java/ch/njol/skript/entity/ThrownPotionData.java +++ b/src/main/java/ch/njol/skript/entity/ThrownPotionData.java @@ -22,6 +22,7 @@ import java.util.function.Consumer; import org.bukkit.Location; +import org.bukkit.Material; import org.bukkit.entity.LingeringPotion; import org.bukkit.entity.ThrownPotion; import org.bukkit.inventory.ItemStack; @@ -51,9 +52,9 @@ public class ThrownPotionData extends EntityData { @SuppressWarnings("removal") private static final Class LINGERING_POTION_ENTITY_CLASS = LINGERING_POTION_ENTITY_USED ? LingeringPotion.class : ThrownPotion.class; - private static final ItemType POTION = Aliases.javaItemType("potion"); - private static final ItemType SPLASH_POTION = Aliases.javaItemType("splash potion"); - private static final ItemType LINGER_POTION = Aliases.javaItemType("lingering potion"); + private static final Material POTION = Material.POTION; + private static final Material SPLASH_POTION = Material.SPLASH_POTION; + private static final Material LINGER_POTION = Material.LINGERING_POTION; @Nullable private ItemType[] types; @@ -63,18 +64,18 @@ protected boolean init(Literal[] exprs, int matchedPattern, ParseResult parse if (exprs.length > 0 && exprs[0] != null) { return (types = Converters.convert((ItemType[]) exprs[0].getAll(), ItemType.class, t -> { // If the itemtype is a potion, lets make it a splash potion (required by Bukkit) - if (t.isSupertypeOf(POTION)) { + if (t.getMaterial() == POTION) { ItemMeta meta = t.getItemMeta(); - ItemType itemType = SPLASH_POTION.clone(); + ItemType itemType = new ItemType(SPLASH_POTION); itemType.setItemMeta(meta); return itemType; - } else if (!t.isSupertypeOf(SPLASH_POTION ) && !t.isSupertypeOf(LINGER_POTION)) { + } else if (t.getMaterial() != SPLASH_POTION && t.getMaterial() != LINGER_POTION) { return null; } return t; })).length != 0; // no error message - other things can be thrown as well } else { - types = new ItemType[]{SPLASH_POTION.clone()}; + types = new ItemType[]{new ItemType(SPLASH_POTION)}; } return true; } @@ -109,7 +110,7 @@ protected boolean match(ThrownPotion entity) { if (i == null) return null; - Class thrownPotionClass = (Class) (LINGER_POTION.isOfType(i) ? LINGERING_POTION_ENTITY_CLASS : ThrownPotion.class); + Class thrownPotionClass = (Class) (i.getType() == LINGER_POTION ? LINGERING_POTION_ENTITY_CLASS : ThrownPotion.class); ThrownPotion potion; if (consumer != null) { potion = EntityData.spawn(location, thrownPotionClass, consumer); @@ -131,7 +132,7 @@ public void set(ThrownPotion entity) { ItemStack i = t.getRandom(); if (i == null) return; // Missing item, can't make thrown potion of it - if (LINGERING_POTION_ENTITY_USED && (LINGERING_POTION_ENTITY_CLASS.isInstance(entity) != LINGER_POTION.isOfType(i))) + if (LINGERING_POTION_ENTITY_USED && (LINGERING_POTION_ENTITY_CLASS.isInstance(entity) != (LINGER_POTION == i.getType()))) return; entity.setItem(i); } diff --git a/src/main/java/ch/njol/skript/events/EvtMoveOn.java b/src/main/java/ch/njol/skript/events/EvtMoveOn.java index 52b552b0040..c5677e5783c 100644 --- a/src/main/java/ch/njol/skript/events/EvtMoveOn.java +++ b/src/main/java/ch/njol/skript/events/EvtMoveOn.java @@ -33,6 +33,7 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.Tag; import org.bukkit.block.Block; import org.bukkit.event.Event; import org.bukkit.event.Listener; @@ -66,9 +67,6 @@ public class EvtMoveOn extends SkriptEvent { ).since("2.0"); } - // Fence blocks and fence gates - private static final ItemType FENCE_PART = Aliases.javaItemType("fence part"); - private static final Map> ITEM_TYPE_TRIGGERS = new ConcurrentHashMap<>(); private static final AtomicBoolean REGISTERED_EXECUTOR = new AtomicBoolean(); @@ -87,10 +85,10 @@ public class EvtMoveOn extends SkriptEvent { if (triggers == null) return; - int y = getBlockY(to.getY(), id); + int y = getBlockY(to.getY(), block); if (to.getWorld().equals(from.getWorld()) && to.getBlockX() == from.getBlockX() && to.getBlockZ() == from.getBlockZ()) { Block fromOnBlock = getOnBlock(from); - if (fromOnBlock != null && y == getBlockY(from.getY(), fromOnBlock.getType()) && fromOnBlock.getType() == id) + if (fromOnBlock != null && y == getBlockY(from.getY(), fromOnBlock) && fromOnBlock.getType() == id) return; } @@ -114,14 +112,14 @@ private static Block getOnBlock(Location location) { Block block = location.getWorld().getBlockAt(location.getBlockX(), (int) (Math.ceil(location.getY()) - 1), location.getBlockZ()); if (block.getType() == Material.AIR && Math.abs((location.getY() - location.getBlockY()) - 0.5) < Skript.EPSILON) { // Fences block = location.getWorld().getBlockAt(location.getBlockX(), location.getBlockY() - 1, location.getBlockZ()); - if (!FENCE_PART.isOfType(block)) + if (!ItemUtils.isFence(block)) return null; } return block; } - private static int getBlockY(double y, Material id) { - if (FENCE_PART.isOfType(id) && Math.abs((y - Math.floor(y)) - 0.5) < Skript.EPSILON) + private static int getBlockY(double y, Block block) { + if (ItemUtils.isFence(block) && Math.abs((y - Math.floor(y)) - 0.5) < Skript.EPSILON) return (int) Math.floor(y) - 1; return (int) Math.ceil(y) - 1; } diff --git a/src/main/java/ch/njol/skript/events/EvtPressurePlate.java b/src/main/java/ch/njol/skript/events/EvtPressurePlate.java index de320c57f26..4d3f876a3b5 100644 --- a/src/main/java/ch/njol/skript/events/EvtPressurePlate.java +++ b/src/main/java/ch/njol/skript/events/EvtPressurePlate.java @@ -19,6 +19,7 @@ package ch.njol.skript.events; import org.bukkit.Material; +import org.bukkit.Tag; import org.bukkit.block.Block; import org.bukkit.event.Event; import org.bukkit.event.block.Action; @@ -36,6 +37,9 @@ * @author Peter Güttinger */ public class EvtPressurePlate extends SkriptEvent { + + private static final boolean HAS_PRESSURE_PLATE_TAG = Skript.fieldExists(Tag.class, "PRESSURE_PLATES"); + static { // TODO is EntityInteractEvent similar for entities? Skript.registerEvent("Pressure Plate / Trip", EvtPressurePlate.class, PlayerInteractEvent.class, @@ -46,8 +50,6 @@ public class EvtPressurePlate extends SkriptEvent { .since("1.0 (pressure plate), 1.4.4 (tripwire)"); } - private static final ItemType plate = Aliases.javaItemType("pressure plate"); - private boolean tripwire; @Override @@ -55,14 +57,25 @@ public boolean init(final Literal[] args, final int matchedPattern, final Par tripwire = matchedPattern == 1; return true; } - + @Override - public boolean check(final Event e) { - final Block b = ((PlayerInteractEvent) e).getClickedBlock(); - final Material type = b == null ? null : b.getType(); - return type != null && ((PlayerInteractEvent) e).getAction() == Action.PHYSICAL && - (tripwire ? (type == Material.TRIPWIRE || type == Material.TRIPWIRE_HOOK) - : plate.isOfType(type)); + public boolean check(Event event) { + Block clickedBlock = ((PlayerInteractEvent) event).getClickedBlock(); + Material type = clickedBlock == null ? null : clickedBlock.getType(); + if (type == null || ((PlayerInteractEvent) event).getAction() != Action.PHYSICAL ) + return false; + + if (tripwire) + return(type == Material.TRIPWIRE || type == Material.TRIPWIRE_HOOK); + + // TODO: 1.16+, remove check in 2.10 + if (HAS_PRESSURE_PLATE_TAG) + return Tag.PRESSURE_PLATES.isTagged(type); + + return Tag.WOODEN_PRESSURE_PLATES.isTagged(type) + || type == Material.HEAVY_WEIGHTED_PRESSURE_PLATE + || type == Material.LIGHT_WEIGHTED_PRESSURE_PLATE + || type == Material.STONE_PRESSURE_PLATE; } @Override diff --git a/src/main/java/ch/njol/skript/expressions/ExprBurnCookTime.java b/src/main/java/ch/njol/skript/expressions/ExprBurnCookTime.java index 3763d242dc1..0d98c551925 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprBurnCookTime.java +++ b/src/main/java/ch/njol/skript/expressions/ExprBurnCookTime.java @@ -23,6 +23,7 @@ import ch.njol.skript.classes.Changer.ChangeMode; import org.bukkit.block.Block; +import org.bukkit.block.BlockState; import org.bukkit.block.Furnace; import org.bukkit.event.Event; import org.bukkit.event.inventory.FurnaceBurnEvent; @@ -65,8 +66,6 @@ public class ExprBurnCookTime extends PropertyExpression { "[the] (burn|1:cook)[ing] time of %blocks%", "%blocks%'[s] (burn|1:cook)[ing] time"); } - - static final ItemType anyFurnace = Aliases.javaItemType("any furnace"); private boolean cookTime; private boolean isEvent; @@ -92,10 +91,11 @@ protected Timespan[] get(Event event, Block[] source) { return CollectionUtils.array(Timespan.fromTicks(((FurnaceBurnEvent) event).getBurnTime())); } else { return Arrays.stream(source) - .filter(anyFurnace::isOfType) - .map(furnace -> { - Furnace state = (Furnace) furnace.getState(); - return Timespan.fromTicks(cookTime ? state.getCookTime() : state.getBurnTime()); + .map(Block::getState) + .filter(blockState -> blockState instanceof Furnace) + .map(state -> { + Furnace furnace = (Furnace) state; + return Timespan.fromTicks(cookTime ? furnace.getCookTime() : furnace.getBurnTime()); }) .toArray(Timespan[]::new); } @@ -141,7 +141,8 @@ public void change(Event event, @Nullable Object[] delta, ChangeMode mode) { } for (Block block : getExpr().getArray(event)) { - if (!anyFurnace.isOfType(block)) + BlockState state = block.getState(); + if (!(state instanceof Furnace)) continue; Furnace furnace = (Furnace) block.getState(); long time = value.apply(Timespan.fromTicks(cookTime ? furnace.getCookTime() : furnace.getBurnTime())).getTicks(); diff --git a/src/main/java/ch/njol/skript/expressions/ExprName.java b/src/main/java/ch/njol/skript/expressions/ExprName.java index b6f873e0b89..666a39092a1 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprName.java +++ b/src/main/java/ch/njol/skript/expressions/ExprName.java @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.List; +import ch.njol.skript.bukkitutil.ItemUtils; import org.bukkit.Bukkit; import org.bukkit.GameRule; import org.bukkit.Nameable; @@ -139,7 +140,6 @@ public class ExprName extends SimplePropertyExpression { * 3 = "tablist name" */ private int mark; - private static final ItemType AIR = Aliases.javaItemType("air"); @Override public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { @@ -282,7 +282,7 @@ public void change(Event event, @Nullable Object[] delta, ChangeMode mode) { } else if (object instanceof Slot) { Slot s = (Slot) object; ItemStack is = s.getItem(); - if (is != null && !AIR.isOfType(is)) { + if (is != null && !ItemUtils.isAir(is.getType())) { ItemMeta m = is.hasItemMeta() ? is.getItemMeta() : Bukkit.getItemFactory().getItemMeta(is.getType()); m.setDisplayName(name); is.setItemMeta(m); diff --git a/src/main/java/ch/njol/skript/expressions/ExprSignText.java b/src/main/java/ch/njol/skript/expressions/ExprSignText.java index 592420ed647..0b549483b17 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprSignText.java +++ b/src/main/java/ch/njol/skript/expressions/ExprSignText.java @@ -18,7 +18,10 @@ */ package ch.njol.skript.expressions; +import ch.njol.skript.bukkitutil.ItemUtils; +import org.bukkit.Material; import org.bukkit.block.Block; +import org.bukkit.block.BlockState; import org.bukkit.block.Sign; import org.bukkit.event.Event; import org.bukkit.event.block.SignChangeEvent; @@ -56,8 +59,6 @@ public class ExprSignText extends SimpleExpression { "[the] line %number% [of %block%]", "[the] (1¦1st|1¦first|2¦2nd|2¦second|3¦3rd|3¦third|4¦4th|4¦fourth) line [of %block%]"); } - private static final ItemType sign = Aliases.javaItemType("sign"); - @SuppressWarnings("null") private Expression line; @SuppressWarnings("null") @@ -99,7 +100,7 @@ protected String[] get(final Event e) { final Block b = block.getSingle(e); if (b == null) return new String[0]; - if (!sign.isOfType(b)) + if (!(b.getState() instanceof Sign)) return new String[0]; return new String[] {((Sign) b.getState()).getLine(line)}; } @@ -143,27 +144,28 @@ public void change(final Event e, final @Nullable Object[] delta, final ChangeMo break; } } else { - if (!sign.isOfType(b)) + BlockState state = b.getState(); + if (!(state instanceof Sign)) return; - final Sign s = (Sign) b.getState(); + Sign sign = (Sign) b.getState(); switch (mode) { case DELETE: - s.setLine(line, ""); + sign.setLine(line, ""); break; case SET: assert delta != null; - s.setLine(line, (String) delta[0]); + sign.setLine(line, (String) delta[0]); break; } if (hasUpdateBooleanBoolean) { try { - s.update(false, false); + sign.update(false, false); } catch (final NoSuchMethodError err) { hasUpdateBooleanBoolean = false; - s.update(); + sign.update(); } } else { - s.update(); + sign.update(); } } } diff --git a/src/main/java/ch/njol/skript/expressions/ExprSkull.java b/src/main/java/ch/njol/skript/expressions/ExprSkull.java index e3a0fa2767d..4e133a79bfd 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprSkull.java +++ b/src/main/java/ch/njol/skript/expressions/ExprSkull.java @@ -18,6 +18,7 @@ */ package ch.njol.skript.expressions; +import org.bukkit.Material; import org.bukkit.OfflinePlayer; import org.bukkit.inventory.meta.SkullMeta; import org.eclipse.jdt.annotation.Nullable; @@ -48,8 +49,6 @@ public class ExprSkull extends SimplePropertyExpression { register(ExprSkull.class, ItemType.class, "(head|skull)", "offlineplayers"); } - private static final ItemType playerSkull = Aliases.javaItemType("player skull"); - /** * In 2017, SkullMeta finally got a method that takes OfflinePlayer. */ @@ -64,7 +63,7 @@ public boolean init(final Expression[] exprs, final int matchedPattern, final @Override @Nullable public ItemType convert(final Object o) { - ItemType skull = playerSkull.clone(); + ItemType skull = new ItemType(Material.PLAYER_HEAD); SkullMeta meta = (SkullMeta) skull.getItemMeta(); if (newSkullOwner) meta.setOwningPlayer((OfflinePlayer) o); diff --git a/src/main/java/ch/njol/skript/expressions/ExprSpawnerType.java b/src/main/java/ch/njol/skript/expressions/ExprSpawnerType.java index d9d31b824cc..24b59ae9dd3 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprSpawnerType.java +++ b/src/main/java/ch/njol/skript/expressions/ExprSpawnerType.java @@ -22,6 +22,7 @@ import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.CreatureSpawner; +import org.bukkit.entity.EntityType; import org.bukkit.event.Event; import org.eclipse.jdt.annotation.Nullable; @@ -44,18 +45,19 @@ @Since("2.4") public class ExprSpawnerType extends SimplePropertyExpression { - private static final Material MATERIAL_SPAWNER = Aliases.javaItemType("spawner").getMaterial(); - static { register(ExprSpawnerType.class, EntityData.class, "(spawner|entity|creature) type[s]", "blocks"); } @Override @Nullable - public EntityData convert(final Block b) { - if (b.getType() != MATERIAL_SPAWNER) + public EntityData convert(Block block) { + if (!(block.getState() instanceof CreatureSpawner)) + return null; + EntityType type = ((CreatureSpawner) block.getState()).getSpawnedType(); + if (type == null) return null; - return EntityUtils.toSkriptEntityData(((CreatureSpawner) b.getState()).getSpawnedType()); + return EntityUtils.toSkriptEntityData(type); } @Nullable @@ -68,13 +70,14 @@ public Class[] acceptChange(Changer.ChangeMode mode) { @SuppressWarnings("null") @Override - public void change(final Event e, final @Nullable Object[] delta, final ChangeMode mode) { - for (Block b : getExpr().getArray(e)) { - if (b.getType() != MATERIAL_SPAWNER) + public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { + for (Block b : getExpr().getArray(event)) { + if (!(b.getState() instanceof CreatureSpawner)) continue; CreatureSpawner s = (CreatureSpawner) b.getState(); switch (mode) { case SET: + assert delta != null; s.setSpawnedType(EntityUtils.toBukkitEntityType((EntityData) delta[0])); break; case RESET: diff --git a/src/main/resources/config.sk b/src/main/resources/config.sk index 4ba081e7c33..ff5e1e9e40a 100644 --- a/src/main/resources/config.sk +++ b/src/main/resources/config.sk @@ -80,6 +80,16 @@ log effect commands: false # Whether Skript should log the usage of effect commands. # They will be logged as [INFORMATION] in this format: ' issued effect command: ' + +load default aliases: true +# Whether Skript should use the default, Skript-provided aliases for items. +# Disabling this will cause all aliases to be automatically generated. Some items, like potions, +# will likely not have aliases in this case. +# +# You can provide your own aliases by making an 'aliases' folder in the Skript directory and putting the alias files there. +# The default aliases folder is available with Skript releases on GitHub. + + player variable fix: true # Whether to enable the player variable fix if a player has rejoined and was reciding inside a variable. # Player objects inside a variable(list or normal) are not updated to the new player object From b48f66d83760be7ebdfcc1dfcc833d3760709ba2 Mon Sep 17 00:00:00 2001 From: Patrick Miller Date: Mon, 1 Jul 2024 17:19:22 -0400 Subject: [PATCH 27/27] Fix current section update issues (#6845) --- src/main/java/ch/njol/skript/lang/Section.java | 12 +++++++++--- .../java/ch/njol/skript/lang/TriggerSection.java | 12 +++++++++--- .../6843-current section reference issue.sk | 9 +++++++++ 3 files changed, 27 insertions(+), 6 deletions(-) create mode 100644 src/test/skript/tests/regressions/6843-current section reference issue.sk diff --git a/src/main/java/ch/njol/skript/lang/Section.java b/src/main/java/ch/njol/skript/lang/Section.java index c511e88b2a2..5a665165eff 100644 --- a/src/main/java/ch/njol/skript/lang/Section.java +++ b/src/main/java/ch/njol/skript/lang/Section.java @@ -27,6 +27,7 @@ import org.bukkit.event.Event; import org.eclipse.jdt.annotation.Nullable; +import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.function.Supplier; @@ -81,12 +82,17 @@ public abstract boolean init(Expression[] expressions, * (although the loaded code may change it), the calling code must deal with this. */ protected void loadCode(SectionNode sectionNode) { - List currentSections = getParser().getCurrentSections(); - currentSections.add(this); + ParserInstance parser = getParser(); + List previousSections = parser.getCurrentSections(); + + List sections = new ArrayList<>(previousSections); + sections.add(this); + parser.setCurrentSections(sections); + try { setTriggerItems(ScriptLoader.loadItems(sectionNode)); } finally { - currentSections.remove(currentSections.size() - 1); + parser.setCurrentSections(previousSections); } } diff --git a/src/main/java/ch/njol/skript/lang/TriggerSection.java b/src/main/java/ch/njol/skript/lang/TriggerSection.java index d1343d43605..e7945784752 100644 --- a/src/main/java/ch/njol/skript/lang/TriggerSection.java +++ b/src/main/java/ch/njol/skript/lang/TriggerSection.java @@ -24,6 +24,7 @@ import org.bukkit.event.Event; import org.eclipse.jdt.annotation.Nullable; +import java.util.ArrayList; import java.util.List; /** @@ -42,12 +43,17 @@ protected TriggerSection(List items) { } protected TriggerSection(SectionNode node) { - List currentSections = ParserInstance.get().getCurrentSections(); - currentSections.add(this); + ParserInstance parser = ParserInstance.get(); + List previousSections = parser.getCurrentSections(); + + List sections = new ArrayList<>(previousSections); + sections.add(this); + parser.setCurrentSections(sections); + try { setTriggerItems(ScriptLoader.loadItems(node)); } finally { - currentSections.remove(currentSections.size() - 1); + parser.setCurrentSections(previousSections); } } diff --git a/src/test/skript/tests/regressions/6843-current section reference issue.sk b/src/test/skript/tests/regressions/6843-current section reference issue.sk new file mode 100644 index 00000000000..20e8beb20ef --- /dev/null +++ b/src/test/skript/tests/regressions/6843-current section reference issue.sk @@ -0,0 +1,9 @@ +test "outdated current section references": + parse: + loop {_list::*}: + spawn a sheep at {_loc}: + set {_e} to event-entity + loop {_list::*}: + set {_var} to loop-value + set {_var} to loop-value-1 + assert last parse logs is not set with "loop-value and loop-value-1 should've worked"