diff --git a/gradlew.bat b/gradlew.bat index 8508ef684d4..a51ec4f5886 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,82 +1,82 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem -@rem SPDX-License-Identifier: Apache-2.0 -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem gradlew startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables, and ensure extensions are enabled -setlocal EnableExtensions - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -"%COMSPEC%" /c exit 1 - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -"%COMSPEC%" /c exit 1 - -:execute -@rem Setup the command line - - - -@rem Execute gradlew -@rem endlocal doesn't take effect until after the line is parsed and variables are expanded -@rem which allows us to clear the local environment before executing the java command -endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel - -:exitWithErrorLevel -@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts -"%COMSPEC%" /c exit %ERRORLEVEL% +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem gradlew startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables, and ensure extensions are enabled +setlocal EnableExtensions + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +"%COMSPEC%" /c exit 1 + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +"%COMSPEC%" /c exit 1 + +:execute +@rem Setup the command line + + + +@rem Execute gradlew +@rem endlocal doesn't take effect until after the line is parsed and variables are expanded +@rem which allows us to clear the local environment before executing the java command +endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel + +:exitWithErrorLevel +@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts +"%COMSPEC%" /c exit %ERRORLEVEL% diff --git a/src/main/java/org/skriptlang/skript/bukkit/entity/player/PlayerModule.java b/src/main/java/org/skriptlang/skript/bukkit/entity/player/PlayerModule.java index 10704eda253..9bc8edb2dd9 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/entity/player/PlayerModule.java +++ b/src/main/java/org/skriptlang/skript/bukkit/entity/player/PlayerModule.java @@ -1,8 +1,11 @@ package org.skriptlang.skript.bukkit.entity.player; import ch.njol.skript.Skript; +import ch.njol.skript.classes.EnumClassInfo; import ch.njol.skript.lang.util.SimpleEvent; +import ch.njol.skript.registrations.Classes; import io.papermc.paper.event.player.AsyncChatEvent; +import org.bukkit.Statistic; import org.skriptlang.skript.addon.AddonModule; import org.skriptlang.skript.addon.HierarchicalAddonModule; import org.skriptlang.skript.addon.SkriptAddon; @@ -19,11 +22,24 @@ public PlayerModule(AddonModule parentModule) { super(parentModule); } + @Override + protected void initSelf(SkriptAddon addon) { + Classes.registerClass(new EnumClassInfo<>(Statistic.class, "statistic", "statistics") + .user("statistics?") + .name("Statistic") + .description( + "Represents a countable statistic, which is tracked by the server. " + + "For the list of all available statistics, " + + "see the Minecraft wiki.") + .since("INSERT VERSION")); + } + @Override protected void loadSelf(SkriptAddon addon) { EventValueRegistry eventValueRegistry = addon.registry(EventValueRegistry.class); register(addon, + syntaxRegistry -> EvtPlayerStatisticChange.register(syntaxRegistry, eventValueRegistry), EffBan::register, EffKick::register, syntaxRegistry -> EvtPlayerGameModeChange.register(syntaxRegistry, eventValueRegistry), @@ -37,7 +53,8 @@ protected void loadSelf(SkriptAddon addon) { ExprPlayerListHeaderFooter::register, ExprPlayerListName::register, ExprPlayerListPriority::register, - ExprQuitMessage::register + ExprQuitMessage::register, + ExprStatistic::register ); if (Skript.classExists("io.papermc.paper.event.player.PlayerPickBlockEvent")) { register(addon, diff --git a/src/main/java/org/skriptlang/skript/bukkit/entity/player/elements/events/EvtPlayerStatisticChange.java b/src/main/java/org/skriptlang/skript/bukkit/entity/player/elements/events/EvtPlayerStatisticChange.java new file mode 100644 index 00000000000..65a8d6c7376 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/entity/player/elements/events/EvtPlayerStatisticChange.java @@ -0,0 +1,95 @@ +package org.skriptlang.skript.bukkit.entity.player.elements.events; + +import ch.njol.skript.aliases.ItemType; +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; +import ch.njol.skript.lang.SyntaxStringBuilder; +import org.bukkit.Statistic; +import org.bukkit.event.Event; +import org.bukkit.event.player.PlayerStatisticIncrementEvent; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.lang.eventvalue.EventValue; +import org.skriptlang.skript.bukkit.lang.eventvalue.EventValue.Time; +import org.skriptlang.skript.bukkit.lang.eventvalue.EventValueRegistry; +import org.skriptlang.skript.bukkit.registration.BukkitSyntaxInfos; +import org.skriptlang.skript.registration.SyntaxRegistry; + +import static ch.njol.skript.bukkitutil.EntityUtils.toSkriptEntityData; + +@SuppressWarnings("unchecked") +public class EvtPlayerStatisticChange extends SkriptEvent { + + public static void register(SyntaxRegistry syntaxRegistry, EventValueRegistry registry) { + syntaxRegistry.register(BukkitSyntaxInfos.Event.KEY, BukkitSyntaxInfos.Event.builder(EvtPlayerStatisticChange.class, "Player Statistic Change") + .supplier(EvtPlayerStatisticChange::new) + .addEvent(PlayerStatisticIncrementEvent.class) + .addPatterns("player statistic (change|increase|increment) [of %-statistics% stat[istic][s]]") + .addDescription(""" + Called when a player's statistic changes. + Some statistics like 'play one minute' do not call this event, because they get called too often. + This event is only called when the server updates a statistic and as such does not call if the statistic expression is used. + """) + .addExample(""" + on player statistic increase: + broadcast "%player%'s statistic '%event-statistic%' increased! It is now %event-number%! + """) + .addExample(""" + on player statistic increase of leave game: + broadcast "%player% has now left the game %event-number% times!" + """) + .addSince("INSERT VERSION") + .build()); + + registry.register(EventValue.builder(PlayerStatisticIncrementEvent.class, Integer.class) + .getter(PlayerStatisticIncrementEvent::getNewValue) + .build()); + + registry.register(EventValue.builder(PlayerStatisticIncrementEvent.class, Integer.class) + .getter(PlayerStatisticIncrementEvent::getPreviousValue) + .time(Time.PAST) + .build()); + + registry.register(EventValue.builder(PlayerStatisticIncrementEvent.class, Statistic.class) + .getter(PlayerStatisticIncrementEvent::getStatistic) + .build()); + + registry.register(EventValue.builder(PlayerStatisticIncrementEvent.class, ItemType.class) + .getter(event -> new ItemType(event.getMaterial())) + .build()); + + registry.register(EventValue.builder(PlayerStatisticIncrementEvent.class, EntityData.class) + .getter(event -> toSkriptEntityData(event.getEntityType())) + .build()); + } + + private Literal statistics; + + @Override + public boolean init(Literal[] literals, int i, ParseResult parseResult) { + statistics = (Literal) literals[0]; + return true; + } + + @Override + public boolean check(Event event) { + if (statistics == null) + return true; + Statistic statistic = ((PlayerStatisticIncrementEvent) event).getStatistic(); + for (Statistic value : this.statistics.getAll(event)) { + if (statistic.equals(value)) + return true; + } + return false; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return new SyntaxStringBuilder(event, debug) + .append("player statistic change") + .appendIf(statistics != null, "of", statistics) + .toString(); + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/entity/player/elements/expressions/ExprStatistic.java b/src/main/java/org/skriptlang/skript/bukkit/entity/player/elements/expressions/ExprStatistic.java new file mode 100644 index 00000000000..0544a5c0ecb --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/entity/player/elements/expressions/ExprStatistic.java @@ -0,0 +1,222 @@ +package org.skriptlang.skript.bukkit.entity.player.elements.expressions; + +import ch.njol.skript.aliases.ItemType; +import ch.njol.skript.bukkitutil.EntityUtils; +import ch.njol.skript.classes.Changer.ChangeMode; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Example; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.entity.EntityData; +import ch.njol.skript.expressions.base.PropertyExpression; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.lang.SyntaxStringBuilder; +import ch.njol.skript.registrations.Classes; +import ch.njol.util.Kleenean; +import ch.njol.util.coll.CollectionUtils; +import org.bukkit.OfflinePlayer; +import org.bukkit.Statistic; +import org.bukkit.Statistic.Type; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.registration.SyntaxRegistry; + +import java.util.Arrays; + +@SuppressWarnings("unchecked") +@Name("Player Statistic") +@Description(""" + Represents a statistic of a player. + Some statistics require an entity type or item type to be specified. + See https://minecraft.wiki/w/Statistics for a full list of statistics. + Using this expression does not call Player Statistic Change event. + """) +@Example(""" + command /basicinfo: + trigger: + send "You've killed %player kills statistic of player% players!" + send "You've broken %mine block statistic using sand of player% sand!" + """) +@Example(""" + on death: + chance of 50%: + remove 1 from deaths statistic of player + send "You got lucky and didn't ruin your kdr!" to victim + """) +@Example(""" + on break of tnt: + chance of 25%: + add 2 to mine block statistic using tnt (itemtype) of player + send "You gained +2 tnt broken! (25% chance)" + """) +@Since("INSERT VERSION") +public class ExprStatistic extends PropertyExpression { + + public static void register(SyntaxRegistry registry) { + registry.register( + SyntaxRegistry.EXPRESSION, + infoBuilder( + ExprStatistic.class, + Integer.class, + "%statistic% stat[istic] [using %-entitydata/itemtype%]", + "offlineplayers", + false + ) + .supplier(ExprStatistic::new) + .build() + ); + } + + private Expression statistic; + private Expression ofType; + + @Override + public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + if (matchedPattern == 1) { + statistic = (Expression) expressions[1]; + ofType = expressions[2]; + setExpr((Expression) expressions[0]); + } else { + statistic = (Expression) expressions[0]; + ofType = expressions[1]; + setExpr((Expression) expressions[2]); + } + return true; + } + + @Override + protected Integer[] get(Event event, OfflinePlayer[] source) { + Statistic statistic = this.statistic.getSingle(event); + if (statistic == null) + return new Integer[0]; + Object type = ofType != null ? ofType.getSingle(event) : null; + if (checkTyping(statistic, type)) + return new Integer[0]; + + return Arrays.stream(source) + .map(player -> getStatistic(player, statistic, type)) + .toArray(Integer[]::new); + } + + @Override + public Class @Nullable [] acceptChange(ChangeMode mode) { + return switch (mode) { + case SET, ADD, REMOVE, RESET, DELETE -> CollectionUtils.array(Integer.class); + default -> null; + }; + } + + @Override + public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { + int amount = (mode == ChangeMode.RESET || mode == ChangeMode.DELETE) ? 0 : (Integer) delta[0]; + Statistic statistic = this.statistic.getSingle(event); + if (statistic == null) + return; + Object type = ofType != null ? ofType.getSingle(event) : null; + if (checkTyping(statistic, type)) + return; + + switch (mode) { + case SET, RESET, DELETE -> { + for (OfflinePlayer player : getExpr().getArray(event)) + applyStatistic(player, statistic, amount, type); + } + case ADD -> { + for (OfflinePlayer player : getExpr().getArray(event)) + applyStatistic(player, statistic, getStatistic(player, statistic, type) + amount, type); + } + case REMOVE -> { + for (OfflinePlayer player : getExpr().getArray(event)) + applyStatistic(player, statistic, getStatistic(player, statistic, type) - amount, type); + } + } + } + + /** + * Retrieves the value of a specific statistic for a given player. + * + * @param player The player whose statistic is being retrieved. + * @param statistic The statistic itself. See Statistics for a list of every possible statistic. + * @param type The statistic type. Can be ITEM, BLOCK or ENTITY. + * @return The value of the specified statistic of the player. + */ + private int getStatistic(OfflinePlayer player, Statistic statistic, Object type) { + Statistic.Type statisticType = statistic.getType(); + if (type instanceof ItemType item && (statisticType == Statistic.Type.ITEM || statisticType == Statistic.Type.BLOCK)) { + return player.getStatistic(statistic, item.getMaterial()); + } else if (type instanceof EntityData data && statisticType == Statistic.Type.ENTITY) { + return player.getStatistic(statistic, EntityUtils.toBukkitEntityType(data)); + } + + return player.getStatistic(statistic); + } + + /** + * Applies the given value to the statistic of the player. + * + * @param player The player whose statistic is being modified. + * @param statistic The statistic itself. See Statistics for a list of every possible statistic. + * @param value The value that the statistic should be changed to. + * @param type The statistic type. Can be ITEM, BLOCK or ENTITY. + */ + private void applyStatistic(OfflinePlayer player, Statistic statistic, Integer value, Object type) { + Statistic.Type statisticType = statistic.getType(); + value = Math.max(0, value); + if (type instanceof ItemType item && (statisticType == Statistic.Type.ITEM || statisticType == Statistic.Type.BLOCK)) { + player.setStatistic(statistic, item.getMaterial(), value); + } else if (type instanceof EntityData data && statisticType == Statistic.Type.ENTITY) { + player.setStatistic(statistic, EntityUtils.toBukkitEntityType(data), value); + } else { + player.setStatistic(statistic, value); + } + } + + /** + * Checks if the specified statistic needs a type or not. + * + * + * @param statistic The statistic itself. See Statistics for a list of every possible statistic. + * @param ofType The statistic type. Can be ITEM, BLOCK or ENTITY. + * @return True if the statistic with the given type is invalid else false if it is valid. + */ + private boolean checkTyping(Statistic statistic, Object ofType) { + Type statisticType = statistic.getType(); + + String statisticString = "The statistic '" + statistic + "'"; + if (ofType == null && statisticType != Type.UNTYPED) { + if (statisticType == Type.ITEM || statisticType == Type.BLOCK) { + error(statisticString + " requires an item type to be specified."); + } else if (statisticType == Type.ENTITY) { + error(statisticString + " requires an entity data to be specified."); + } + return true; + } else if (this.ofType != null && statisticType == Type.UNTYPED) { + warning(statisticString + " does not require an entity data or item type to be provided, so it will be ignored."); + } + + if (ofType instanceof ItemType && statisticType == Type.ENTITY) { + error(statisticString + " requires an entity data, but '" + Classes.toString(ofType) + "' was provided."); + return true; + } else if (ofType instanceof EntityData && (statisticType == Type.ITEM || statisticType == Type.BLOCK)) { + error(statisticString + " requires an item type, but '" + Classes.toString(ofType) + "' was provided."); + return true; + } + + return false; + } + + @Override + public Class getReturnType() { + return Integer.class; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return new SyntaxStringBuilder(event, debug) + .append("the statistic", statistic, "of", getExpr().getArray(event)) + .appendIf(ofType != null, "using", ofType) + .toString(); + } + +} diff --git a/src/main/resources/lang/default.lang b/src/main/resources/lang/default.lang index d72d5ecb0b8..d756724bf7e 100644 --- a/src/main/resources/lang/default.lang +++ b/src/main/resources/lang/default.lang @@ -2506,8 +2506,7 @@ particle: white_ash: white ash particle¦s @a white_smoke: white smoke particle¦s @a witch: witch particle¦s @a - - # 26.2 + # 26.2 noxious_gas: noxious gas particle¦s @a, nausea gas particle¦s @a noxious_gas_cloud: noxious gas cloud¦s @a, nausea gas cloud particle¦s @a sulfur_cube_goo: sulfur cube goo particle¦s @a, sulfur cube jump particle¦s @a, sulfur cube jumping particle¦s @a @@ -2517,6 +2516,92 @@ particle: geyser_plume: geyser plume particle¦s @a geyser_poof: geyser poof particle¦s @a +# -- Statistics -- +statistics: + animals_bred: animals bred + armor_cleaned: armor cleaned + aviate_one_cm: aviate one cm, glide distance, elytra distance + banner_cleaned: banner cleaned + beacon_interaction: beacon interaction + bell_ring: bell ring + boat_one_cm: boat one cm, boat distance + break_item: break item + brewingstand_interaction: brewing stand interaction, interact with brewing stand + cake_slices_eaten: cake slices eaten + cauldron_filled: cauldron filled + cauldron_used: cauldron used + chest_opened: chest opened + clean_shulker_box: clean shulker box + climb_one_cm: climb one cm, climb distance + craft_item: craft item + crafting_table_interaction: crafting table interaction + crouch_one_cm: crouch one cm, sneak distance + damage_absorbed: damage absorbed + damage_blocked_by_shield: damage blocked by shield + damage_dealt: damage dealt + damage_dealt_absorbed: damage dealt absorbed + damage_dealt_resisted: damage dealt resisted + damage_resisted: damage resisted + damage_taken: damage taken + deaths: deaths + dispenser_inspected: dispenser inspected + drop: drop + drop_count: drop count, items dropped + dropper_inspected: dropper inspected + enderchest_opened: ender chest opened + entity_killed_by: entity killed by, times killed by entity + fall_one_cm: fall one cm, fall distance + fish_caught: fish caught + flower_potted: flower potted + fly_one_cm: fly one cm, fly distance + furnace_interaction: furnace interaction + hopper_inspected: hopper inspected + horse_one_cm: horse one cm, horse distance, horse riding distance + interact_with_anvil: interact with anvil, anvil interaction + interact_with_blast_furnace: interact with blast furnace, blast furnace interaction + interact_with_campfire: interact with campfire, campfire interaction + interact_with_cartography_table: interact with cartography table, cartography table interaction + interact_with_grindstone: interact with grindstone, grindstone interaction + interact_with_lectern: interact with lectern, lectern interaction + interact_with_loom: interact with loom, loom interaction + interact_with_smithing_table: interact with smithing table, smithing table interaction + interact_with_smoker: interact with smoker, smoker interaction + interact_with_stonecutter: interact with stone cutter, stone cutter interaction + item_enchanted: item enchanted + jump: jump + kill_entity: kill entity, entities killed + leave_game: leave game + mine_block: mine block + minecart_one_cm: minecart one cm, minecart distance + mob_kills: mob kills, mobs killed + noteblock_played: note block played + noteblock_tuned: note block tuned + open_barrel: open barrel + pickup: pick up, items picked up + pig_one_cm: pig one cm, pig distance, pig riding distance + play_one_minute: play one minute, ticks played, play time, time played + player_kills: player kills + raid_trigger: raid trigger + raid_win: raid win + record_played: record played + shulker_box_opened: shulker box opened + sleep_in_bed: sleep in bed + sneak_time: sneak time, crouch time + sprint_one_cm: sprint one cm, sprint distance + strider_one_cm: strider one cm, strider distance, strider riding distance + swim_one_cm: swim one cm, swim distance + talked_to_villager: talked to villager + target_hit: target hit + time_since_death: time since death + time_since_rest: time since rest + total_world_time: total world time + traded_with_villager: traded with villager + trapped_chest_triggered: trapped chest triggered + use_item: use item + walk_on_water_one_cm: walk on water one cm, walk on water distance + walk_one_cm: walk one cm, walk distance + walk_under_water_one_cm: walk under water one cm, walk underwater once cm, walk under water distance, walk underwater distance + # -- Teleport Flags -- teleport flags: retain_open_inventory: opened inventory, open inventory, inventory diff --git a/src/test/skript/tests/syntaxes/expressions/ExprStatistic.sk b/src/test/skript/tests/syntaxes/expressions/ExprStatistic.sk new file mode 100644 index 00000000000..8950869f41f --- /dev/null +++ b/src/test/skript/tests/syntaxes/expressions/ExprStatistic.sk @@ -0,0 +1,47 @@ +using error catching + +test "statistic": + set player kills statistic of test-offline player to 45 + assert player kills statistic of test-offline player is 45 with "Failed to set kills statistic" + set {_error} to "The statistic 'MINE_BLOCK' requires an item type to be specified." + catch runtime errors: + set mine block statistic of test-offline player to 5 + assert last caught errors is {_error} with "set player's mine block statistic without giving an item should give error but did not" + set mine block statistic using sand of test-offline player to 25 + assert mine block statistic using sand of test-offline player is 25 with "Failed to set mine block statistic using sand" + set {_error} to "The statistic 'KILL_ENTITY' requires an entity data to be specified." + catch runtime errors: + set test-offline player's kill entity statistic to 5 + assert last caught errors is {_error} with "set player's kill entity statistic should error but did not" + set kill entity stat using pig of test-offline player to 5 + assert kill entity statistic using pig of test-offline player is 5 with "Failed to set kill entity stat using pig" + set {_error} to "The statistic 'PLAYER_KILLS' does not require an entity data or item type to be provided, so it will be ignored." + catch runtime errors: + set player kills stat using tnt (itemtype) of test-offline player to 75 + assert last caught errors is {_error} with "set player's player kill statistic should give warning but did not" + set {_error} to "The statistic 'KILL_ENTITY' requires an entity data to be specified." + catch runtime errors: + set kill entity stat of test-offline player to 5 + assert last caught errors is {_error} with "set player's kill entity stat without providing an entity data should error but did not" + set {_error} to "The statistic 'MINE_BLOCK' requires an item type to be specified." + catch runtime errors: + set mine block stat of test-offline player to 5 + assert last caught errors is {_error} with "set player's mine block statistic without providing an item type should error but did not" + set {_error} to "The statistic 'MINE_BLOCK' requires an item type, but 'pig' was provided." + catch runtime errors: + set mine block stat using pig of test-offline player to 5 + assert last caught errors is {_error} with "set player's mine block stat using pig should error but did not" + set {_error} to "The statistic 'KILL_ENTITY' requires an entity data, but 'sand' was provided." + catch runtime errors: + set kill entity stat using sand of test-offline player to 5 + assert last caught errors is {_error} with "set player's kill entity stat using sand should error but did not" + set jump statistic of test-offline player to 54 + assert jump statistic of test-offline player is 54 with "Failed to set jump statistic" + add 6 to jump statistic of test-offline player + assert jump statistic of test-offline player is 60 with "Failed to add to jump statistic" + remove 6 from jump statistic of test-offline player + assert jump statistic of test-offline player is 54 with "Failed to remove from jump statistic" + reset jump statistic of test-offline player + assert jump statistic of test-offline player is 0 with "Failed to reset jump statistic" + delete jump statistic of test-offline player + assert jump statistic of test-offline player is 0 with "Failed to delete jump statistic"