diff --git a/.gitignore b/.gitignore index aa3fcc8d..02ce5ac0 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ target/ .settings/ /integrations/jars/ +.flattened-pom.xml \ No newline at end of file diff --git a/api/dependency-reduced-pom.xml b/api/dependency-reduced-pom.xml deleted file mode 100755 index 76bda9fc..00000000 --- a/api/dependency-reduced-pom.xml +++ /dev/null @@ -1,239 +0,0 @@ - - - - beautyquests-parent - fr.skytasul - 1.0.2-SNAPSHOT - - 4.0.0 - beautyquests-api - - - - maven-shade-plugin - 3.2.1 - - - package - - shade - - - - - - - revxrsal.commands - fr.skytasul.quests.api.commands.revxrsal - - - com.cryptomorin.xseries - fr.skytasul.quests.api.utils - - - - - com.github.cryptomorin:XSeries - - com/cryptomorin/xseries/XMaterial* - com/cryptomorin/xseries/XBlock* - com/cryptomorin/xseries/XPotion* - - - - true - - - - maven-compiler-plugin - 3.8.0 - - true - - - - maven-javadoc-plugin - 3.4.1 - - - attach-javadocs - verify - - jar - - - - - false - none - - - - maven-source-plugin - 3.2.1 - - - attach-sources - verify - - jar-no-fork - - - - - false - - - - maven-surefire-plugin - 3.2.2 - - true - - - - - - - papermc - https://repo.papermc.io/repository/maven-public/ - - - jitpack.io - https://jitpack.io - - - - - org.jetbrains - annotations - 24.0.0 - provided - - - commons-lang - commons-lang - 2.6 - provided - - - io.papermc.paper - paper-api - 1.20.1-R0.1-SNAPSHOT - provided - - - guava - com.google.guava - - - gson - com.google.code.gson - - - bungeecord-chat - net.md-5 - - - snakeyaml - org.yaml - - - joml - org.joml - - - json-simple - com.googlecode.json-simple - - - fastutil - it.unimi.dsi - - - log4j-api - org.apache.logging.log4j - - - slf4j-api - org.slf4j - - - maven-resolver-provider - org.apache.maven - - - adventure-api - net.kyori - - - adventure-text-minimessage - net.kyori - - - adventure-text-serializer-gson - net.kyori - - - adventure-text-serializer-legacy - net.kyori - - - adventure-text-serializer-plain - net.kyori - - - adventure-text-logger-slf4j - net.kyori - - - checker-qual - org.checkerframework - - - asm - org.ow2.asm - - - asm-commons - org.ow2.asm - - - - - org.junit.jupiter - junit-jupiter-api - 5.10.1 - test - - - opentest4j - org.opentest4j - - - junit-platform-commons - org.junit.platform - - - apiguardian-api - org.apiguardian - - - - - org.junit.jupiter - junit-jupiter-params - 5.10.1 - test - - - apiguardian-api - org.apiguardian - - - - - - 5.10.1 - - diff --git a/api/pom.xml b/api/pom.xml index 77bd1031..cf6b79e9 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -8,7 +8,7 @@ fr.skytasul beautyquests-parent - 1.0.2 + ${revision} @@ -22,6 +22,7 @@ maven-shade-plugin 3.2.1 + false revxrsal.commands @@ -39,7 +40,7 @@ com/cryptomorin/xseries/XMaterial* com/cryptomorin/xseries/XBlock* - com/cryptomorin/xseries/XPotion* + com/cryptomorin/xseries/XEnchantment* @@ -115,6 +116,10 @@ jitpack.io https://jitpack.io + + sonatype-oss-snapshots1 + https://s01.oss.sonatype.org/content/repositories/snapshots/ + @@ -134,7 +139,7 @@ io.papermc.paper paper-api - 1.20.1-R0.1-SNAPSHOT + ${minecraft.version} provided @@ -151,7 +156,7 @@ com.github.cryptomorin XSeries - 9.8.0 + 9.10.0 diff --git a/api/src/main/java/fr/skytasul/quests/api/events/accounts/PlayerAccountEvent.java b/api/src/main/java/fr/skytasul/quests/api/events/accounts/PlayerAccountEvent.java index a0b613d9..02f2208a 100644 --- a/api/src/main/java/fr/skytasul/quests/api/events/accounts/PlayerAccountEvent.java +++ b/api/src/main/java/fr/skytasul/quests/api/events/accounts/PlayerAccountEvent.java @@ -1,26 +1,26 @@ package fr.skytasul.quests.api.events.accounts; +import fr.skytasul.quests.api.players.PlayerAccount; import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import fr.skytasul.quests.api.players.PlayerAccount; public abstract class PlayerAccountEvent extends Event { - + protected final @NotNull PlayerAccount account; protected PlayerAccountEvent(@NotNull PlayerAccount account) { this.account = account; } - + public boolean isAccountCurrent() { return account.isCurrent(); } - + public @Nullable Player getPlayer() { if (!account.isCurrent()) - throw new IllegalStateException("Account is not currently used"); + throw new IllegalStateException("Account " + account.debugName() + " is not currently used"); return account.getPlayer(); } @@ -28,5 +28,5 @@ public boolean isAccountCurrent() { public @NotNull PlayerAccount getPlayerAccount() { return account; } - + } \ No newline at end of file diff --git a/api/src/main/java/fr/skytasul/quests/api/gui/ItemUtils.java b/api/src/main/java/fr/skytasul/quests/api/gui/ItemUtils.java index 3f2486c5..d7d9dae8 100644 --- a/api/src/main/java/fr/skytasul/quests/api/gui/ItemUtils.java +++ b/api/src/main/java/fr/skytasul/quests/api/gui/ItemUtils.java @@ -1,22 +1,24 @@ package fr.skytasul.quests.api.gui; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; +import com.cryptomorin.xseries.XMaterial; +import fr.skytasul.quests.api.QuestsPlugin; +import fr.skytasul.quests.api.options.QuestOption; +import fr.skytasul.quests.api.utils.ChatColorUtils; +import fr.skytasul.quests.api.utils.MinecraftNames; +import fr.skytasul.quests.api.utils.MinecraftVersion; +import fr.skytasul.quests.api.utils.Utils; import org.apache.commons.lang.Validate; import org.bukkit.DyeColor; +import org.bukkit.Material; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.*; import org.jetbrains.annotations.Nullable; -import com.cryptomorin.xseries.XMaterial; -import fr.skytasul.quests.api.QuestsPlugin; -import fr.skytasul.quests.api.options.QuestOption; -import fr.skytasul.quests.api.utils.ChatColorUtils; -import fr.skytasul.quests.api.utils.MinecraftNames; -import fr.skytasul.quests.api.utils.MinecraftVersion; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; public final class ItemUtils { @@ -40,7 +42,7 @@ public static ItemStack item(XMaterial type, String name, String... lore) { } ItemStack is = type.parseItem(); ItemMeta im = is.getItemMeta(); - im.addItemFlags(ItemFlag.values()); + addSpecificFlags(im, is.getType()); is.setItemMeta(applyMeta(im, name, lore)); return is; } @@ -60,7 +62,7 @@ public static ItemStack item(XMaterial type, String name, List lore) { } ItemStack is = type.parseItem(); ItemMeta im = is.getItemMeta(); - im.addItemFlags(ItemFlag.values()); + addSpecificFlags(im, is.getType()); is.setItemMeta(applyMeta(im, name, lore)); return is; } @@ -137,18 +139,30 @@ public static ItemStack clearVisibleAttributes(ItemStack is) { im.setDisplayName(null); im.setLore(null); - // add flags to hide various descriptions, - // depending on the item type/attributes/other things - if (im.hasEnchants()) im.addItemFlags(ItemFlag.HIDE_ENCHANTS); - if (MinecraftVersion.MAJOR >= 11 && im.isUnbreakable()) im.addItemFlags(ItemFlag.HIDE_UNBREAKABLE); - if (is.getType().getMaxDurability() != 0 || (MinecraftVersion.MAJOR > 12 && im.hasAttributeModifiers())) im.addItemFlags(ItemFlag.HIDE_ATTRIBUTES); - if (im instanceof BookMeta || im instanceof PotionMeta || im instanceof EnchantmentStorageMeta || (MinecraftVersion.MAJOR >= 12 && im instanceof KnowledgeBookMeta)) im.addItemFlags(ItemFlag.HIDE_POTION_EFFECTS); - if (im instanceof LeatherArmorMeta) im.addItemFlags(ItemFlag.HIDE_DYE); + addSpecificFlags(im, is.getType()); is.setItemMeta(im); return is; } + public static ItemMeta addSpecificFlags(ItemMeta im, Material material) { + // add flags to hide various descriptions, + // depending on the item type/attributes/other things + if (im.hasEnchants()) + im.addItemFlags(ItemFlag.HIDE_ENCHANTS); + if (MinecraftVersion.MAJOR >= 11 && im.isUnbreakable()) + im.addItemFlags(ItemFlag.HIDE_UNBREAKABLE); + if (material.getMaxDurability() != 0 || (MinecraftVersion.MAJOR > 12 && im.hasAttributeModifiers())) + im.addItemFlags(ItemFlag.HIDE_ATTRIBUTES); + if (im instanceof BookMeta || im instanceof PotionMeta || im instanceof EnchantmentStorageMeta + || (MinecraftVersion.MAJOR >= 12 && im instanceof KnowledgeBookMeta)) + im.addItemFlags(Utils.valueOfEnum(ItemFlag.class, "HIDE_POTION_EFFECTS", "HIDE_ADDITIONAL_TOOLTIP")); + if (im instanceof LeatherArmorMeta) + im.addItemFlags(ItemFlag.HIDE_DYE); + + return im; + } + /** * Set the lore of an item (override old lore) * @param is ItemStack instance to edit @@ -314,6 +328,25 @@ public static ItemStack removeEnchant(ItemStack is, Enchantment en){ return is; } + public static boolean isGlittering(ItemStack is) { + ItemMeta im = is.getItemMeta(); + return (MinecraftVersion.isHigherThan(20, 6) && im.hasEnchantmentGlintOverride() && im.getEnchantmentGlintOverride()) + || im.hasEnchants(); + } + + public static void setGlittering(ItemStack is, boolean glitter) { + ItemMeta im = is.getItemMeta(); + if (MinecraftVersion.isHigherThan(20, 6)) { + im.setEnchantmentGlintOverride(glitter ? Boolean.TRUE : null); + } else { + if (glitter) + im.addEnchant(Enchantment.getByName("DURABILITY"), 0, true); + else + im.removeEnchant(Enchantment.getByName("DURABILITY")); + } + is.setItemMeta(im); + } + /** * Get a glass pane ItemStack instance with the color wanted * @param color DyeColor wanted diff --git a/api/src/main/java/fr/skytasul/quests/api/gui/layout/LayoutedGUI.java b/api/src/main/java/fr/skytasul/quests/api/gui/layout/LayoutedGUI.java index c1cf952d..3f7d7909 100644 --- a/api/src/main/java/fr/skytasul/quests/api/gui/layout/LayoutedGUI.java +++ b/api/src/main/java/fr/skytasul/quests/api/gui/layout/LayoutedGUI.java @@ -42,8 +42,10 @@ public final void onClick(GuiClickEvent event) { if (button == null || !button.isValid()) return; - button.click(new LayoutedClickEvent(event.getPlayer(), this, event.getClicked(), event.getCursor(), event.getSlot(), - event.getClick())); + LayoutedClickEvent subEvent = new LayoutedClickEvent(event.getPlayer(), this, event.getClicked(), event.getCursor(), + event.getSlot(), event.getClick()); + button.click(subEvent); + event.setCancelled(subEvent.isCancelled()); } public void refresh(int slot) { diff --git a/api/src/main/java/fr/skytasul/quests/api/localization/Locale.java b/api/src/main/java/fr/skytasul/quests/api/localization/Locale.java index 6643df08..13266ded 100644 --- a/api/src/main/java/fr/skytasul/quests/api/localization/Locale.java +++ b/api/src/main/java/fr/skytasul/quests/api/localization/Locale.java @@ -1,5 +1,18 @@ package fr.skytasul.quests.api.localization; +import fr.skytasul.quests.api.QuestsPlugin; +import fr.skytasul.quests.api.utils.ChatColorUtils; +import fr.skytasul.quests.api.utils.Utils; +import fr.skytasul.quests.api.utils.messaging.HasPlaceholders; +import fr.skytasul.quests.api.utils.messaging.MessageType; +import fr.skytasul.quests.api.utils.messaging.MessageUtils; +import fr.skytasul.quests.api.utils.messaging.PlaceholderRegistry; +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -7,20 +20,10 @@ import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.plugin.Plugin; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import fr.skytasul.quests.api.QuestsPlugin; -import fr.skytasul.quests.api.utils.ChatColorUtils; -import fr.skytasul.quests.api.utils.Utils; -import fr.skytasul.quests.api.utils.messaging.HasPlaceholders; -import fr.skytasul.quests.api.utils.messaging.MessageType; -import fr.skytasul.quests.api.utils.messaging.MessageUtils; -import fr.skytasul.quests.api.utils.messaging.PlaceholderRegistry; +import java.util.logging.Level; public interface Locale { @@ -70,14 +73,27 @@ default void quickSend(@NotNull CommandSender sender, @NotNull String key1, @Nul } public static void loadStrings(@NotNull Locale @NotNull [] locales, @NotNull YamlConfiguration defaultConfig, - @NotNull YamlConfiguration config) { + @Nullable YamlConfiguration config) { + List missing = new ArrayList<>(); for (Locale l : locales) { - String value = config.getString(l.getPath(), null); - if (value == null) value = defaultConfig.getString(l.getPath(), null); + String value = null; + if (config != null) + value = config.getString(l.getPath(), null); + if (value == null) { + value = defaultConfig.getString(l.getPath(), null); + missing.add(l.getPath()); + } if (value == null) QuestsPlugin.getPlugin().getLoggerExpanded().debug("Unavailable string in config for key " + l.getPath()); l.setValue(ChatColorUtils.translateHexColorCodes(ChatColor.translateAlternateColorCodes('&', value == null ? "§cunknown string" : value))); } + + if (config != null && !missing.isEmpty()) { + QuestsPlugin.getPlugin().getLoggerExpanded() + .warning("The file is not fully translated! " + missing.size() + " missing translations."); + QuestsPlugin.getPlugin().getLoggerExpanded() + .debug("Missing translations: " + String.join(", ", missing)); + } } public static YamlConfiguration loadLang(@NotNull Plugin plugin, @NotNull Locale @NotNull [] locales, @@ -103,27 +119,41 @@ public static YamlConfiguration loadLang(@NotNull Plugin plugin, @NotNull Locale res = plugin.getResource("locales/en_US.yml"); created = true; } - YamlConfiguration conf = YamlConfiguration.loadConfiguration(file); - boolean changes = false; - if (res != null) { // if it's a local resource - YamlConfiguration def = YamlConfiguration.loadConfiguration(new InputStreamReader(res, StandardCharsets.UTF_8)); - for (String key : def.getKeys(true)) { // get all keys in resource - if (!def.isConfigurationSection(key)) { // if not a block - if (!conf.contains(key)) { // if string does not exist in the file - conf.set(key, def.get(key)); // copy string - if (!created) QuestsPlugin.getPlugin().getLoggerExpanded().debug("String copied from source file to " + language + ". Key: " + key); - changes = true; + + YamlConfiguration def = null; + if (res != null) + def = YamlConfiguration.loadConfiguration(new InputStreamReader(res, StandardCharsets.UTF_8)); + + YamlConfiguration conf = new YamlConfiguration(); + try { + // we do NOT use YamlConfiguration#loadConfiguration because it swallows all exceptions + conf.load(file); + boolean changes = false; + if (def != null) { // if it's a local resource + for (String key : def.getKeys(true)) { // get all keys in resource + if (!def.isConfigurationSection(key)) { // if not a block + if (!conf.contains(key)) { // if string does not exist in the file + conf.set(key, def.get(key)); // copy string + if (!created) + QuestsPlugin.getPlugin().getLoggerExpanded() + .debug("String copied from source file to " + language + ". Key: " + key); + changes = true; + } } } } + if (changes) { + plugin.getLogger().info("Copied new strings into " + language + " language file."); + conf.save(file); // if there has been changes before, save the edited file + } + } catch (Exception ex) { + conf = def; + // the new configuration to load is the default one, or null if unknown language -> will only load + // default english + plugin.getLogger().log(Level.SEVERE, "Failed to load language file " + file, ex); } loadStrings(locales, YamlConfiguration.loadConfiguration(new InputStreamReader(plugin.getResource("locales/en_US.yml"), StandardCharsets.UTF_8)), conf); - if (changes) { - plugin.getLogger().info("Copied new strings into " + language + " language file."); - conf.save(file); // if there has been changes before, save the edited file - } - plugin.getLogger().info("Loaded language " + loadedLanguage + " (" + (((double) System.currentTimeMillis() - lastMillis) / 1000D) + "s)!"); return conf; } diff --git a/api/src/main/java/fr/skytasul/quests/api/npcs/dialogs/DialogRunner.java b/api/src/main/java/fr/skytasul/quests/api/npcs/dialogs/DialogRunner.java index dd062f94..be23d3d9 100644 --- a/api/src/main/java/fr/skytasul/quests/api/npcs/dialogs/DialogRunner.java +++ b/api/src/main/java/fr/skytasul/quests/api/npcs/dialogs/DialogRunner.java @@ -4,9 +4,17 @@ import java.util.function.Predicate; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import fr.skytasul.quests.api.npcs.BqNpc; public interface DialogRunner { + @Nullable + BqNpc getNpc(); + + @Nullable + Dialog getDialog(); + void addTest(Predicate test); void addTestCancelling(Predicate test); diff --git a/api/src/main/java/fr/skytasul/quests/api/options/UpdatableOptionSet.java b/api/src/main/java/fr/skytasul/quests/api/options/UpdatableOptionSet.java index b4eb44bd..8b24ef61 100644 --- a/api/src/main/java/fr/skytasul/quests/api/options/UpdatableOptionSet.java +++ b/api/src/main/java/fr/skytasul/quests/api/options/UpdatableOptionSet.java @@ -4,32 +4,32 @@ @SuppressWarnings ("rawtypes") public class UpdatableOptionSet implements OptionSet { - + private Map>, OptionWrapper> options = new HashMap<>(); - + @Override public Iterator iterator() { return options.values().stream().map(wrapper -> wrapper.option).iterator(); } - + public void addOption(QuestOption option, Runnable update) { options.put((Class>) option.getClass(), new OptionWrapper(option, update)); } - + @Override public > T getOption(Class optionClass) { return (T) options.get(optionClass).option; } - + @Override public boolean hasOption(Class> clazz) { return options.containsKey(clazz); } - + public OptionWrapper getWrapper(Class> optionClass) { return options.get(optionClass); } - + public void calculateDependencies() { options.values().forEach(wrapper -> wrapper.dependent.clear()); for (OptionWrapper wrapper : options.values()) { @@ -38,17 +38,20 @@ public void calculateDependencies() { } } } - + public class OptionWrapper { public final QuestOption option; public final Runnable update; public final List dependent = new ArrayList<>(); - + public OptionWrapper(QuestOption option, Runnable update) { this.option = option; this.update = update; - option.setValueUpdaterListener(() -> dependent.forEach(Runnable::run)); + option.setValueUpdaterListener(() -> { + update.run(); + dependent.forEach(Runnable::run); + }); } } - + } diff --git a/api/src/main/java/fr/skytasul/quests/api/quests/branches/QuestBranch.java b/api/src/main/java/fr/skytasul/quests/api/quests/branches/QuestBranch.java index 7d2f53c1..b7dc9a1c 100644 --- a/api/src/main/java/fr/skytasul/quests/api/quests/branches/QuestBranch.java +++ b/api/src/main/java/fr/skytasul/quests/api/quests/branches/QuestBranch.java @@ -1,13 +1,14 @@ package fr.skytasul.quests.api.quests.branches; -import java.util.List; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.UnmodifiableView; import fr.skytasul.quests.api.options.description.DescriptionSource; import fr.skytasul.quests.api.players.PlayerAccount; import fr.skytasul.quests.api.quests.Quest; import fr.skytasul.quests.api.stages.StageController; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.UnmodifiableView; +import java.util.List; public interface QuestBranch { @@ -33,4 +34,31 @@ default Quest getQuest() { public boolean hasStageLaunched(@Nullable PlayerAccount acc, @NotNull StageController stage); + /** + * Must be called when a player completes a stage. This causes the stage to end and the next one to + * begin, or the quest to finish if it was the last stage. + * + * @param p player which has completed the stage + * @param stage that the player just completed. If the player did not have this stage launched, the + * call will fail. + */ + void finishPlayerStage(@NotNull Player p, @NotNull StageController stage); + + /** + * Changes which stage the player is currently doing in the branch. If the player did not have + * already started a stage in this branch, an exception will be raised. + * + * @param acc player for which the running stage will be changed + * @param stage new stage to start + */ + void setPlayerStage(@NotNull PlayerAccount acc, @NotNull StageController stage); + + /** + * Similar to {@link #setPlayerStage(PlayerAccount, StageController)} but with ending stages instead + * of a regular stage. + * + * @param acc player for which the ending stages will start + */ + void setPlayerEndingStages(@NotNull PlayerAccount acc); + } diff --git a/api/src/main/java/fr/skytasul/quests/api/stages/AbstractStage.java b/api/src/main/java/fr/skytasul/quests/api/stages/AbstractStage.java index 396c4403..67daa6c0 100644 --- a/api/src/main/java/fr/skytasul/quests/api/stages/AbstractStage.java +++ b/api/src/main/java/fr/skytasul/quests/api/stages/AbstractStage.java @@ -1,12 +1,5 @@ package fr.skytasul.quests.api.stages; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import fr.skytasul.quests.api.QuestsConfiguration; import fr.skytasul.quests.api.players.PlayerAccount; import fr.skytasul.quests.api.players.PlayersManager; @@ -19,6 +12,13 @@ import fr.skytasul.quests.api.utils.AutoRegistered; import fr.skytasul.quests.api.utils.messaging.HasPlaceholders; import fr.skytasul.quests.api.utils.messaging.PlaceholderRegistry; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; @AutoRegistered public abstract class AbstractStage implements HasPlaceholders { @@ -172,12 +172,23 @@ protected final void updateObjective(@NotNull Player p, @NotNull String dataKey, controller.updateObjective(p, dataKey, dataValue); } + @Deprecated protected final @Nullable T getData(@NotNull Player p, @NotNull String dataKey) { return getData(PlayersManager.getPlayerAccount(p), dataKey); } + @Deprecated protected final @Nullable T getData(@NotNull PlayerAccount acc, @NotNull String dataKey) { - return controller.getData(acc, dataKey); + return getData(acc, dataKey, null); + } + + protected final @Nullable T getData(@NotNull Player p, @NotNull String dataKey, @NotNull Class dataType) { + return getData(PlayersManager.getPlayerAccount(p), dataKey, dataType); + } + + protected final @Nullable T getData(@NotNull PlayerAccount acc, @NotNull String dataKey, + @NotNull Class dataType) { + return controller.getData(acc, dataKey, dataType); } /** diff --git a/api/src/main/java/fr/skytasul/quests/api/stages/StageController.java b/api/src/main/java/fr/skytasul/quests/api/stages/StageController.java index 5ee40504..bf0e365a 100644 --- a/api/src/main/java/fr/skytasul/quests/api/stages/StageController.java +++ b/api/src/main/java/fr/skytasul/quests/api/stages/StageController.java @@ -1,11 +1,11 @@ package fr.skytasul.quests.api.stages; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import fr.skytasul.quests.api.options.description.DescriptionSource; import fr.skytasul.quests.api.players.PlayerAccount; import fr.skytasul.quests.api.quests.branches.QuestBranch; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public interface StageController { @@ -23,7 +23,7 @@ public interface StageController { public @Nullable String getDescriptionLine(@NotNull PlayerAccount acc, @NotNull DescriptionSource source); - public @Nullable T getData(@NotNull PlayerAccount acc, @NotNull String dataKey); + public @Nullable T getData(@NotNull PlayerAccount acc, @NotNull String dataKey, @Nullable Class dataType); public @NotNull String getFlowId(); diff --git a/api/src/main/java/fr/skytasul/quests/api/stages/types/AbstractCountableStage.java b/api/src/main/java/fr/skytasul/quests/api/stages/types/AbstractCountableStage.java index 46cd296a..ebc12d2d 100644 --- a/api/src/main/java/fr/skytasul/quests/api/stages/types/AbstractCountableStage.java +++ b/api/src/main/java/fr/skytasul/quests/api/stages/types/AbstractCountableStage.java @@ -103,20 +103,20 @@ public Map> cloneObjects() { } @Override - public int getPlayerAmount(@NotNull PlayerAccount account, CountableObject object) { + public long getPlayerAmount(@NotNull PlayerAccount account, CountableObject object) { // we do not use default implementation in HasMultipleObjects to avoid conversion from UUID to // CountableObject return getPlayerRemainings(account, false).get(object.getUUID()); } @Override - public int getPlayerAmount(@NotNull PlayerAccount account) { + public long getPlayerAmount(@NotNull PlayerAccount account) { // same as in getPlayerAmount return getPlayerRemainings(account, false).values().stream().mapToInt(Integer::intValue).sum(); } @Override - public int getTotalAmount() { + public long getTotalAmount() { return objects.stream().mapToInt(CountableObject::getAmount).sum(); } @@ -155,7 +155,8 @@ public void initPlayerDatas(@NotNull PlayerAccount acc, @NotNull Map<@NotNull St */ public boolean event(@NotNull Player p, @UnknownNullability Object object, int amount) { if (amount < 0) throw new IllegalArgumentException("Event amount must be positive (" + amount + ")"); - if (!canUpdate(p)) return true; + if (!canUpdate(p) || !hasStarted(p)) + return true; PlayerAccount acc = PlayersManager.getPlayerAccount(p); for (CountableObject countableObject : objects) { diff --git a/api/src/main/java/fr/skytasul/quests/api/stages/types/AbstractEntityStage.java b/api/src/main/java/fr/skytasul/quests/api/stages/types/AbstractEntityStage.java index 0b66090a..6a09c183 100644 --- a/api/src/main/java/fr/skytasul/quests/api/stages/types/AbstractEntityStage.java +++ b/api/src/main/java/fr/skytasul/quests/api/stages/types/AbstractEntityStage.java @@ -1,12 +1,5 @@ package fr.skytasul.quests.api.stages.types; -import java.util.*; -import java.util.Map.Entry; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import com.cryptomorin.xseries.XMaterial; import fr.skytasul.quests.api.QuestsPlugin; import fr.skytasul.quests.api.editors.TextEditor; @@ -26,10 +19,17 @@ import fr.skytasul.quests.api.utils.messaging.PlaceholderRegistry; import fr.skytasul.quests.api.utils.progress.ProgressPlaceholders; import fr.skytasul.quests.api.utils.progress.itemdescription.HasItemsDescriptionConfiguration.HasSingleObject; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import java.util.*; +import java.util.Map.Entry; @LocatableType (types = LocatedType.ENTITY) public abstract class AbstractEntityStage extends AbstractStage implements Locatable.MultipleLocatable, HasSingleObject { - + protected final @NotNull EntityType entity; protected final int amount; @@ -38,7 +38,7 @@ protected AbstractEntityStage(@NotNull StageController controller, @NotNull Enti this.entity = entity; this.amount = amount; } - + protected void event(@NotNull Player p, @NotNull EntityType type) { PlayerAccount acc = PlayersManager.getPlayerAccount(p); if (hasStarted(p) && canUpdate(p)) { @@ -54,19 +54,19 @@ protected void event(@NotNull Player p, @NotNull EntityType type) { } } } - + protected @NotNull OptionalInt getPlayerAmountOptional(@NotNull PlayerAccount acc) { - Integer amount = getData(acc, "amount"); + Integer amount = getData(acc, "amount", Integer.class); return amount == null ? OptionalInt.empty() : OptionalInt.of(amount.intValue()); } - + @Override - public int getPlayerAmount(@NotNull PlayerAccount account) { + public long getPlayerAmount(@NotNull PlayerAccount account) { return getPlayerAmountOptional(account).orElse(0); } @Override - public int getObjectAmount() { + public long getObjectAmount() { return amount; } @@ -80,24 +80,24 @@ public void initPlayerDatas(@NotNull PlayerAccount acc, @NotNull Map<@NotNull St super.initPlayerDatas(acc, datas); datas.put("amount", amount); } - + @Override protected void serialize(@NotNull ConfigurationSection section) { section.set("entityType", entity == null ? "any" : entity.name()); section.set("amount", amount); } - + @Override protected void createdPlaceholdersRegistry(@NotNull PlaceholderRegistry placeholders) { super.createdPlaceholdersRegistry(placeholders); ProgressPlaceholders.registerObject(placeholders, "mobs", this); } - + @Override public boolean canBeFetchedAsynchronously() { return false; } - + @Override public @NotNull Spliterator<@NotNull Located> getNearbyLocated(@NotNull NearbyFetcher fetcher) { if (!fetcher.isTargeting(LocatedType.ENTITY)) return Spliterators.emptySpliterator(); @@ -114,12 +114,12 @@ public boolean canBeFetchedAsynchronously() { .map(entry -> Located.LocatedEntity.create(entry.getKey())) .spliterator(); } - + public abstract static class AbstractCreator extends StageCreation { - + protected EntityType entity = null; protected int amount = 1; - + protected AbstractCreator(@NotNull StageCreationContext context) { super(context); } @@ -127,14 +127,14 @@ protected AbstractCreator(@NotNull StageCreationContext context) { @Override public void setupLine(@NotNull StageGuiLine line) { super.setupLine(line); - + line.setItem(6, ItemUtils.item(XMaterial.CHICKEN_SPAWN_EGG, Lang.changeEntityType.toString()), event -> { QuestsPlugin.getPlugin().getGuiManager().getFactory().createEntityTypeSelection(x -> { setEntity(x); event.reopen(); }, x -> x == null ? canBeAnyEntity() : canUseEntity(x)).open(event.getPlayer()); }); - + line.setItem(7, ItemUtils.item(XMaterial.REDSTONE, Lang.Amount.quickFormat("amount", 1)), event -> { new TextEditor<>(event.getPlayer(), event::reopen, x -> { setAmount(x); @@ -142,36 +142,36 @@ public void setupLine(@NotNull StageGuiLine line) { }, NumberParser.INTEGER_PARSER_STRICT_POSITIVE).start(); }); } - + public void setEntity(EntityType entity) { this.entity = entity; getLine().refreshItemLoreOptionValue(6, entity == null ? Lang.EntityTypeAny.toString() : entity.name()); } - + public void setAmount(int amount) { this.amount = amount; getLine().refreshItemName(7, Lang.Amount.quickFormat("amount", amount)); } - + @Override public void start(Player p) { super.start(p); setEntity(null); } - + @Override public void edit(T stage) { super.edit(stage); setEntity(stage.entity); setAmount(stage.amount); } - + protected boolean canBeAnyEntity() { return true; } - + protected abstract boolean canUseEntity(@NotNull EntityType type); - + } - + } \ No newline at end of file diff --git a/api/src/main/java/fr/skytasul/quests/api/utils/CustomizedObjectTypeAdapter.java b/api/src/main/java/fr/skytasul/quests/api/utils/CustomizedObjectTypeAdapter.java index f9463a4d..61a04ddd 100644 --- a/api/src/main/java/fr/skytasul/quests/api/utils/CustomizedObjectTypeAdapter.java +++ b/api/src/main/java/fr/skytasul/quests/api/utils/CustomizedObjectTypeAdapter.java @@ -1,9 +1,5 @@ package fr.skytasul.quests.api.utils; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.TypeAdapter; @@ -11,6 +7,10 @@ import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; public class CustomizedObjectTypeAdapter extends TypeAdapter { @@ -24,14 +24,16 @@ public static T deserializeNullable(String json, Class classOfT) { if (json == null) return null; return GSON.fromJson(json, classOfT); } - + public static String serializeNullable(Object object) { if (object == null) return null; return GSON.toJson(object); } - + private final TypeAdapter delegate = new Gson().getAdapter(Object.class); + private CustomizedObjectTypeAdapter() {} + @Override public void write(JsonWriter out, Object value) throws IOException { delegate.write(out, value); diff --git a/api/src/main/java/fr/skytasul/quests/api/utils/MinecraftNames.java b/api/src/main/java/fr/skytasul/quests/api/utils/MinecraftNames.java index 632de31a..b336f138 100644 --- a/api/src/main/java/fr/skytasul/quests/api/utils/MinecraftNames.java +++ b/api/src/main/java/fr/skytasul/quests/api/utils/MinecraftNames.java @@ -1,34 +1,29 @@ package fr.skytasul.quests.api.utils; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; +import com.cryptomorin.xseries.XMaterial; +import com.google.gson.GsonBuilder; +import fr.skytasul.quests.api.QuestsPlugin; import org.apache.commons.lang.WordUtils; import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.PotionMeta; -import org.bukkit.potion.PotionData; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import com.cryptomorin.xseries.XMaterial; -import com.cryptomorin.xseries.XPotion; -import com.google.gson.GsonBuilder; -import fr.skytasul.quests.api.QuestsPlugin; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; +import java.util.Map.Entry; public class MinecraftNames { - + public static final String LANG_DOWNLOAD_URL = "https://github.com/InventivetalentDev/minecraft-assets/raw/%version%/assets/minecraft/lang/%language%.json"; - + private static Map map; - + private static Map cachedEntities = new HashMap<>(); private static Map cachedMaterials = new HashMap<>(); - + public static boolean intialize(@NotNull Path path) { try { if (!Files.exists(path)) { @@ -36,27 +31,29 @@ public static boolean intialize(@NotNull Path path) { .warning("File " + path.getFileName() + " not found for translations."); return false; } - + map = new GsonBuilder().create().fromJson(Files.newBufferedReader(path, StandardCharsets.UTF_8), HashMap.class); QuestsPlugin.getPlugin().getLoggerExpanded().info("Loaded vanilla translation file for language: " + map.get("language.name") + ". Sorting values."); for (Entry en : map.entrySet()) { String key = en.getKey(); + String value = (String) en.getValue(); if (key.startsWith("entity.minecraft.")) { - cachedEntities.put(EntityType.fromName(key.substring(17)), (String) en.getValue()); + cachedEntities.put(EntityType.fromName(key.substring(17)), value); }else if (key.startsWith("block.minecraft.")) { - cachedMaterials.put(XMaterial.matchXMaterial(key.substring(16)).orElse(null), (String) en.getValue()); + cachedMaterials.put(XMaterial.matchXMaterial(key.substring(16)).orElse(null), value); }else if (key.startsWith("item.minecraft.")) { String item = key.substring(15); if (item.startsWith("potion.effect.")) { - PotionMapping potion = PotionMapping.matchFromTranslationKey(item.substring(14)); - if (potion != null) potion.normal = (String) en.getValue(); + PotionMapping.matchFromTranslationKey(item.substring(14)) + .forEachRemaining(potion -> potion.setNormalName(value)); }else if (item.startsWith("splash_potion.effect.")) { - PotionMapping potion = PotionMapping.matchFromTranslationKey(item.substring(21)); - if (potion != null) potion.splash = (String) en.getValue(); + PotionMapping.matchFromTranslationKey(item.substring(21)) + .forEachRemaining(potion -> potion.setSplashName(value)); }else if (item.startsWith("lingering_potion.effect.")) { - PotionMapping potion = PotionMapping.matchFromTranslationKey(item.substring(24)); - if (potion != null) potion.lingering = (String) en.getValue(); - }else cachedMaterials.put(XMaterial.matchXMaterial(item).orElse(null), (String) en.getValue()); + PotionMapping.matchFromTranslationKey(item.substring(24)) + .forEachRemaining(potion -> potion.setLingeringName(value)); + } else + cachedMaterials.put(XMaterial.matchXMaterial(item).orElse(null), value); } } }catch (Exception e) { @@ -64,11 +61,11 @@ public static boolean intialize(@NotNull Path path) { } return true; } - + public static @Nullable Object getRaw(@Nullable String path) { return map.get(path); } - + public static @NotNull String getEntityName(@NotNull EntityType type) { String defaultName = type.getName(); if (defaultName == null) defaultName = type.name(); @@ -77,23 +74,14 @@ public static boolean intialize(@NotNull Path path) { if (name == null) return defaultFormat(defaultName); return name; } - + public static @NotNull String getMaterialName(ItemStack item) { XMaterial type = XMaterial.matchXMaterial(item); - if (MinecraftVersion.MAJOR > 8 + if (MinecraftVersion.isHigherThan(20, 2) && (type == XMaterial.POTION || type == XMaterial.LINGERING_POTION || type == XMaterial.SPLASH_POTION)) { PotionMeta meta = (PotionMeta) item.getItemMeta(); - try { - PotionData basePotion = meta.getBasePotionData(); - PotionMapping mapping = basePotion.getType().name().equals("TURTLE_MASTER") ? PotionMapping.TURTLE_MASTER - : PotionMapping.matchFromXPotion(XPotion.matchXPotion(basePotion.getType().getEffectType())); - String string = mapping.getTranslated(type); - if (basePotion.isUpgraded()) { - string += " II" + mapping.strongDuration; - } else if (mapping.baseDuration != null) - string += basePotion.isExtended() ? mapping.extendedDuration : mapping.baseDuration; - return string; - }catch (NullPointerException ex) {} // happens with potions with no effect + if (meta.getBasePotionType() != null) + return PotionMapping.matchFromPotionType(meta.getBasePotionType()).getTranslated(type); } return getMaterialName(type); } @@ -104,81 +92,9 @@ public static boolean intialize(@NotNull Path path) { if (name == null) return defaultFormat(type.name()); return name; } - + public static @NotNull String defaultFormat(@NotNull String value) { return WordUtils.capitalize(value.toLowerCase().replace('_', ' ')); } - - private static class PotionMapping { - - private static final List MAPPINGS = new ArrayList<>(); - public static final PotionMapping TURTLE_MASTER; - - static { - MAPPINGS.add(new PotionMapping(XPotion.FIRE_RESISTANCE, "fire_resistance", 3600, 9600, -1)); - MAPPINGS.add(new PotionMapping(XPotion.HARM, "harming", -1, -1, -1)); - MAPPINGS.add(new PotionMapping(XPotion.HEAL, "healing", -1, -1, -1)); - MAPPINGS.add(new PotionMapping(XPotion.INCREASE_DAMAGE, "strength", 3600, 9600, 1800)); - MAPPINGS.add(new PotionMapping(XPotion.INVISIBILITY, "invisibility", 3600, 9600, -1)); - MAPPINGS.add(new PotionMapping(XPotion.JUMP, "leaping", 3600, 9600, 1800)); - MAPPINGS.add(new PotionMapping(XPotion.LEVITATION, "levitation", -1, -1, -1)); - MAPPINGS.add(new PotionMapping(XPotion.LUCK, "luck", 6000, -1, -1)); - MAPPINGS.add(new PotionMapping(XPotion.NIGHT_VISION, "night_vision", 3600, 9600, -1)); - MAPPINGS.add(new PotionMapping(XPotion.POISON, "poison", 900, 1800, 432)); - MAPPINGS.add(new PotionMapping(XPotion.REGENERATION, "regeneration", 900, 1800, 450)); - MAPPINGS.add(new PotionMapping(XPotion.SLOW, "slowness", 1800, 4800, 400)); - MAPPINGS.add(new PotionMapping(XPotion.SLOW_FALLING, "slow_falling", 1800, 4800, -1)); - MAPPINGS.add(new PotionMapping(XPotion.SPEED, "swiftness", 3600, 9600, 1800)); - MAPPINGS.add(new PotionMapping(XPotion.WATER_BREATHING, "water_breathing", 3600, 9600, -1)); - MAPPINGS.add(new PotionMapping(XPotion.WEAKNESS, "weakness", 1800, 4800, -1)); - MAPPINGS.add(TURTLE_MASTER = new PotionMapping(null, "turtle_master", 400, 800, 400)); - } - - private final @Nullable XPotion mappedPotion; - private final @NotNull String key; - private final @Nullable String baseDuration, extendedDuration, strongDuration; - private @NotNull String normal, splash, lingering; - - private PotionMapping(@Nullable XPotion mappedPotion, @NotNull String key, int baseDuration, int extendedDuration, - int strongDuration) { - this.mappedPotion = mappedPotion; - this.key = key; - this.baseDuration = baseDuration == 0 ? null : " (" + Utils.ticksToElapsedTime(baseDuration) + ")"; - this.extendedDuration = extendedDuration == 0 ? null : " (" + Utils.ticksToElapsedTime(extendedDuration) + ")"; - this.strongDuration = strongDuration == 0 ? "" : " (" + Utils.ticksToElapsedTime(strongDuration) + ")"; - this.normal = "potion of " + key; - this.splash = "splash potion of " + key; - this.lingering = "lingering potion of " + key; - } - - public @NotNull String getTranslated(XMaterial material) { - if (material == XMaterial.POTION) - return normal; - if (material == XMaterial.SPLASH_POTION) - return splash; - if (material == XMaterial.LINGERING_POTION) - return lingering; - throw new IllegalArgumentException("Argument is not a potion material"); - } - - public static @Nullable PotionMapping matchFromTranslationKey(String key) { - for (PotionMapping potion : MAPPINGS) { - if (key.equals(potion.key)) - return potion; - } - return null; - } - - public static @NotNull PotionMapping matchFromXPotion(XPotion xpotion) { - for (PotionMapping potion : MAPPINGS) { - if (xpotion.equals(potion.mappedPotion)) - return potion; - } - PotionMapping potion = new PotionMapping(xpotion, defaultFormat(xpotion.name()), -1, -1, -1); - MAPPINGS.add(potion); - return potion; - } - - } } \ No newline at end of file diff --git a/api/src/main/java/fr/skytasul/quests/api/utils/MinecraftVersion.java b/api/src/main/java/fr/skytasul/quests/api/utils/MinecraftVersion.java index 6c2b279c..342a6209 100644 --- a/api/src/main/java/fr/skytasul/quests/api/utils/MinecraftVersion.java +++ b/api/src/main/java/fr/skytasul/quests/api/utils/MinecraftVersion.java @@ -5,23 +5,27 @@ public final class MinecraftVersion { public static final String VERSION_STRING; - public static final String VERSION_NMS; public static final int MAJOR; public static final int MINOR; static { + // e.g. Bukkit.getBukkitVersion() -> 1.17.1-R0.1-SNAPSHOT VERSION_STRING = Bukkit.getBukkitVersion().split("-R")[0]; - VERSION_NMS = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3].substring(1); - String[] versions = VERSION_NMS.split("_"); - MAJOR = Integer.parseInt(versions[1]); // 1.X - if (MAJOR >= 17) { - // e.g. Bukkit.getBukkitVersion() -> 1.17.1-R0.1-SNAPSHOT - versions = VERSION_STRING.split("\\."); - MINOR = versions.length <= 2 ? 0 : Integer.parseInt(versions[2]); - } else - MINOR = Integer.parseInt(versions[2].substring(1)); // 1.X.Y + String[] versions = VERSION_STRING.split("\\."); + MAJOR = Integer.parseInt(versions[1]); + MINOR = versions.length <= 2 ? 0 : Integer.parseInt(versions[2]); } private MinecraftVersion() {} + public static boolean isHigherThan(int major, int minor) { + if (MAJOR > major) + return true; + + if (MAJOR == major && MINOR >= minor) + return true; + + return false; + } + } diff --git a/api/src/main/java/fr/skytasul/quests/api/utils/PlayerListCategory.java b/api/src/main/java/fr/skytasul/quests/api/utils/PlayerListCategory.java index b38f958d..5eb2a1ab 100644 --- a/api/src/main/java/fr/skytasul/quests/api/utils/PlayerListCategory.java +++ b/api/src/main/java/fr/skytasul/quests/api/utils/PlayerListCategory.java @@ -1,27 +1,27 @@ package fr.skytasul.quests.api.utils; -import org.bukkit.DyeColor; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import com.cryptomorin.xseries.XMaterial; import fr.skytasul.quests.api.QuestsConfiguration; import fr.skytasul.quests.api.localization.Lang; +import org.bukkit.DyeColor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public enum PlayerListCategory { FINISHED( 1, - XMaterial.WRITTEN_BOOK, + XMaterial.BOOK, Lang.finisheds.toString(), DyeColor.GREEN), IN_PROGRESS( 2, - XMaterial.BOOK, + XMaterial.WRITABLE_BOOK, Lang.inProgress.toString(), DyeColor.YELLOW), NOT_STARTED( 3, - XMaterial.WRITABLE_BOOK, + XMaterial.PAPER, Lang.notStarteds.toString(), DyeColor.RED); diff --git a/api/src/main/java/fr/skytasul/quests/api/utils/PotionMapping.java b/api/src/main/java/fr/skytasul/quests/api/utils/PotionMapping.java new file mode 100755 index 00000000..a02efd67 --- /dev/null +++ b/api/src/main/java/fr/skytasul/quests/api/utils/PotionMapping.java @@ -0,0 +1,117 @@ +package fr.skytasul.quests.api.utils; + +import com.cryptomorin.xseries.XMaterial; +import org.bukkit.potion.PotionType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +// In a separate file because it uses >= 1.20.2 API +class PotionMapping { + + private static final List MAPPINGS = new ArrayList<>(); + + private static void addMapping(PotionType base, String translationKey, int baseDuration, int longDuration, + int strongDuration) { + MAPPINGS.add(new PotionMapping(base, translationKey, baseDuration, false)); + + try { + MAPPINGS.add( + new PotionMapping(PotionType.valueOf("LONG_" + base.name()), translationKey, longDuration, true)); + } catch (IllegalArgumentException ex) { + } + + try { + MAPPINGS.add(new PotionMapping(PotionType.valueOf("STRONG_" + base.name()), translationKey, strongDuration, true)); + } catch (IllegalArgumentException ex) { + } + } + + static { + addMapping(PotionType.FIRE_RESISTANCE, "fire_resistance", 3600, 9600, -1); + addMapping(PotionType.HARMING, "harming", -1, -1, -1); + addMapping(PotionType.HEALING, "healing", -1, -1, -1); + addMapping(PotionType.STRENGTH, "strength", 3600, 9600, 1800); + addMapping(PotionType.INVISIBILITY, "invisibility", 3600, 9600, -1); + addMapping(PotionType.LEAPING, "leaping", 3600, 9600, 1800); + // addMapping(PotionType.LEVITATION, "levitation", -1, -1, -1); + // does not exist anymore? + addMapping(PotionType.LUCK, "luck", 6000, -1, -1); + addMapping(PotionType.NIGHT_VISION, "night_vision", 3600, 9600, -1); + addMapping(PotionType.POISON, "poison", 900, 1800, 432); + addMapping(PotionType.REGENERATION, "regeneration", 900, 1800, 450); + addMapping(PotionType.SLOWNESS, "slowness", 1800, 4800, 400); + addMapping(PotionType.SLOW_FALLING, "slow_falling", 1800, 4800, -1); + addMapping(PotionType.SWIFTNESS, "swiftness", 3600, 9600, 1800); + addMapping(PotionType.WATER_BREATHING, "water_breathing", 3600, 9600, -1); + addMapping(PotionType.WEAKNESS, "weakness", 1800, 4800, -1); + addMapping(PotionType.TURTLE_MASTER, "turtle_master", 400, 800, 400); + // experimental : wind_charged, weaving, oozing, infested + } + + private final @Nullable PotionType mappedPotion; + private final @NotNull String key; + private final @Nullable String duration; + private final boolean strong; + + private @NotNull String normalName, splashName, lingeringName; + + protected PotionMapping(@NotNull PotionType mappedPotion, @NotNull String key, int duration, boolean strong) { + this.mappedPotion = mappedPotion; + this.key = key; + this.duration = duration == -1 ? null : " (" + Utils.ticksToElapsedTime(duration) + ")"; + this.strong = strong; + + this.normalName = "potion of " + key; + this.splashName = "splash potion of " + key; + this.lingeringName = "lingering potion of " + key; + } + + public @NotNull String getTranslated(XMaterial material) { + String name; + if (material == XMaterial.POTION) + name = normalName; + else if (material == XMaterial.SPLASH_POTION) + name = splashName; + else if (material == XMaterial.LINGERING_POTION) + name = lingeringName; + else + throw new IllegalArgumentException("Argument is not a potion material"); + + if (strong) + name += " II"; + if (duration != null) + name += duration; + return name; + } + + public void setNormalName(@NotNull String normalName) { + this.normalName = normalName; + } + + public void setSplashName(@NotNull String splashName) { + this.splashName = splashName; + } + + public void setLingeringName(@NotNull String lingeringName) { + this.lingeringName = lingeringName; + } + + public static @NotNull Iterator matchFromTranslationKey(String key) { + return MAPPINGS.stream().filter(mapping -> mapping.key.equals(key)).iterator(); + // we return an iterator because there can be multiple mappings (one for "normal", one for + // "extended", one for "strong"... + } + + public static @NotNull PotionMapping matchFromPotionType(PotionType potion) { + for (PotionMapping mapping : MAPPINGS) { + if (potion.equals(mapping.mappedPotion)) + return mapping; + } + addMapping(potion, MinecraftNames.defaultFormat(potion.name()), -1, -1, -1); + return matchFromPotionType(potion); + } + +} \ No newline at end of file diff --git a/api/src/main/java/fr/skytasul/quests/api/utils/Utils.java b/api/src/main/java/fr/skytasul/quests/api/utils/Utils.java index 50d7713c..222781db 100644 --- a/api/src/main/java/fr/skytasul/quests/api/utils/Utils.java +++ b/api/src/main/java/fr/skytasul/quests/api/utils/Utils.java @@ -1,5 +1,19 @@ package fr.skytasul.quests.api.utils; +import com.cryptomorin.xseries.XMaterial; +import fr.skytasul.quests.api.gui.ItemUtils; +import fr.skytasul.quests.api.localization.Lang; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.MemoryConfiguration; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.jetbrains.annotations.NotNull; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; @@ -11,19 +25,6 @@ import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Stream; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.MemoryConfiguration; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.Player; -import org.bukkit.event.inventory.ClickType; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; -import com.cryptomorin.xseries.XMaterial; -import fr.skytasul.quests.api.gui.ItemUtils; -import fr.skytasul.quests.api.localization.Lang; /** * A bunch of static methods who can be useful @@ -259,21 +260,42 @@ public static boolean isQuestItem(ItemStack item) { return false; } + public static > T valueOfEnum(Class enumClass, @NotNull String... names) { + for (String name : names) { + try { + return Enum.valueOf(enumClass, name); + } catch (IllegalArgumentException ex) { + } + } + throw new IllegalArgumentException("Cannot find " + Arrays.toString(names) + " from enum " + enumClass.getName()); + } + public static XMaterial mobItem(EntityType type) { - if (type == null) return XMaterial.SPONGE; + if (type == null) + return XMaterial.SPONGE; Optional material = XMaterial.matchXMaterial(type.name() + "_SPAWN_EGG"); if (material.isPresent() && material.get().isSupported()) return material.get(); - if (type == EntityType.WITHER) return XMaterial.WITHER_SKELETON_SKULL; - if (type == EntityType.IRON_GOLEM) return XMaterial.IRON_BLOCK; - if (type == EntityType.SNOWMAN) return XMaterial.SNOW_BLOCK; - if (type == EntityType.MUSHROOM_COW) return XMaterial.MOOSHROOM_SPAWN_EGG; - if (type == EntityType.GIANT) return XMaterial.ZOMBIE_SPAWN_EGG; - if (type == EntityType.ARMOR_STAND) return XMaterial.ARMOR_STAND; - if (type == EntityType.PLAYER) return XMaterial.PLAYER_HEAD; - if (type == EntityType.ENDER_DRAGON) return XMaterial.DRAGON_HEAD; - if (type.name().equals("PIG_ZOMBIE") || type.name().equals("ZOMBIFIED_PIGLIN")) return XMaterial.ZOMBIFIED_PIGLIN_SPAWN_EGG; - if (type.name().equals("ILLUSIONER")) return XMaterial.BLAZE_POWDER; + if (type == EntityType.WITHER) // got its egg + return XMaterial.WITHER_SKELETON_SKULL; + if (type == EntityType.IRON_GOLEM) // got its egg + return XMaterial.IRON_BLOCK; + if (type == EntityType.GIANT) + return XMaterial.ZOMBIE_SPAWN_EGG; + if (type == EntityType.ARMOR_STAND) + return XMaterial.ARMOR_STAND; + if (type == EntityType.PLAYER) + return XMaterial.PLAYER_HEAD; + if (type == EntityType.ENDER_DRAGON) // got its egg + return XMaterial.DRAGON_HEAD; + if (type.name().equals("MUSHROOM_COW")) + return XMaterial.MOOSHROOM_SPAWN_EGG; + if (type.name().equals("SNOWMAN")) // got its egg + return XMaterial.SNOW_BLOCK; + if (type.name().equals("PIG_ZOMBIE")) + return XMaterial.ZOMBIFIED_PIGLIN_SPAWN_EGG; + if (type.name().equals("ILLUSIONER")) + return XMaterial.BLAZE_POWDER; return XMaterial.SPONGE; } diff --git a/api/src/main/java/fr/skytasul/quests/api/utils/progress/HasProgress.java b/api/src/main/java/fr/skytasul/quests/api/utils/progress/HasProgress.java index 7813f3c5..94240731 100755 --- a/api/src/main/java/fr/skytasul/quests/api/utils/progress/HasProgress.java +++ b/api/src/main/java/fr/skytasul/quests/api/utils/progress/HasProgress.java @@ -5,8 +5,8 @@ public interface HasProgress { - int getPlayerAmount(@NotNull PlayerAccount account); + long getPlayerAmount(@NotNull PlayerAccount account); - int getTotalAmount(); + long getTotalAmount(); } diff --git a/api/src/main/java/fr/skytasul/quests/api/utils/progress/ProgressPlaceholders.java b/api/src/main/java/fr/skytasul/quests/api/utils/progress/ProgressPlaceholders.java index 1c1732ca..26bcf175 100755 --- a/api/src/main/java/fr/skytasul/quests/api/utils/progress/ProgressPlaceholders.java +++ b/api/src/main/java/fr/skytasul/quests/api/utils/progress/ProgressPlaceholders.java @@ -22,17 +22,17 @@ public final class ProgressPlaceholders { private static final PlaceholderRegistry PROGRESS_REGISTRY = new PlaceholderRegistry() .registerIndexedContextual("remaining", ProgressPlaceholderContext.class, - context -> Integer.toString(context.getProgress().getPlayerAmount(context.getPlayerAccount()))) + context -> Long.toString(context.getProgress().getPlayerAmount(context.getPlayerAccount()))) .registerIndexedContextual("done", ProgressPlaceholderContext.class, - context -> Integer.toString(context.getProgress().getTotalAmount() + context -> Long.toString(context.getProgress().getTotalAmount() - context.getProgress().getPlayerAmount(context.getPlayerAccount()))) .registerIndexedContextual("total", ProgressPlaceholderContext.class, - context -> Integer.toString(context.getProgress().getTotalAmount())) + context -> Long.toString(context.getProgress().getTotalAmount())) .registerIndexedContextual("percentage", ProgressPlaceholderContext.class, context -> { - int perc = (int) (100D - context.getProgress().getPlayerAmount(context.getPlayerAccount()) * 100D + long perc = (long) (100D - context.getProgress().getPlayerAmount(context.getPlayerAccount()) * 100D / context.getProgress().getTotalAmount()); - return Integer.toString(perc); + return Long.toString(perc); }); private static final PlaceholderRegistry DESCRIPTION_REGISTRY = PROGRESS_REGISTRY.with(new PlaceholderRegistry() .registerIndexedContextual("name", ProgressObjectPlaceholderContext.class, @@ -93,7 +93,7 @@ public static void registerObjects(@NotNull PlaceholderRegistry placeholders } private static @NotNull HasSingleObject buildFrom(@NotNull HasMultipleObjects objects, CountableObject object, - int amount) { + long amount) { return new HasSingleObject() { @Override public @NotNull ItemsDescriptionConfiguration getItemsDescriptionConfiguration() { @@ -101,7 +101,7 @@ public static void registerObjects(@NotNull PlaceholderRegistry placeholders } @Override - public int getPlayerAmount(@NotNull PlayerAccount account) { + public long getPlayerAmount(@NotNull PlayerAccount account) { return amount; } @@ -111,7 +111,7 @@ public int getPlayerAmount(@NotNull PlayerAccount account) { } @Override - public int getObjectAmount() { + public long getObjectAmount() { return object.getAmount(); } }; diff --git a/api/src/main/java/fr/skytasul/quests/api/utils/progress/itemdescription/HasItemsDescriptionConfiguration.java b/api/src/main/java/fr/skytasul/quests/api/utils/progress/itemdescription/HasItemsDescriptionConfiguration.java index 4b56ed61..2b3657fa 100755 --- a/api/src/main/java/fr/skytasul/quests/api/utils/progress/itemdescription/HasItemsDescriptionConfiguration.java +++ b/api/src/main/java/fr/skytasul/quests/api/utils/progress/itemdescription/HasItemsDescriptionConfiguration.java @@ -21,10 +21,10 @@ public interface HasSingleObject extends HasItemsDescriptionConfiguration, HasPr @NotNull String getObjectName(); - int getObjectAmount(); + long getObjectAmount(); @Override - default int getTotalAmount() { + default long getTotalAmount() { return getObjectAmount(); } @@ -45,18 +45,18 @@ public interface HasMultipleObjects extends HasItemsDescriptionConfiguration, @NotNull Map, Integer> getPlayerAmounts(@NotNull PlayerAccount account); - default int getPlayerAmount(@NotNull PlayerAccount account, CountableObject object) { + default long getPlayerAmount(@NotNull PlayerAccount account, CountableObject object) { return getPlayerAmounts(account).get(object); } @Override - default int getPlayerAmount(@NotNull PlayerAccount account) { + default long getPlayerAmount(@NotNull PlayerAccount account) { return getPlayerAmounts(account).values().stream().mapToInt(Integer::intValue).sum(); } @Override - default int getTotalAmount() { - return getObjects().stream().mapToInt(CountableObject::getAmount).sum(); + default long getTotalAmount() { + return getObjects().stream().mapToLong(CountableObject::getAmount).sum(); } } diff --git a/core/pom.xml b/core/pom.xml index 66bfb184..2818467b 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -8,7 +8,7 @@ fr.skytasul beautyquests-parent - 1.0.2 + ${revision} @@ -30,6 +30,7 @@ maven-shade-plugin 3.2.1 + false org.bstats @@ -97,7 +98,7 @@ fr.skytasul beautyquests-api - ${project.version} + ${revision} provided @@ -117,7 +118,7 @@ io.papermc.paper paper-api - 1.20.1-R0.1-SNAPSHOT + ${minecraft.version} provided @@ -157,7 +158,7 @@ fr.mrmicky fastboard - 2.0.2 + 2.1.2 compile diff --git a/core/src/main/java/fr/skytasul/quests/BeautyQuests.java b/core/src/main/java/fr/skytasul/quests/BeautyQuests.java index d0685e33..bcdbeb48 100644 --- a/core/src/main/java/fr/skytasul/quests/BeautyQuests.java +++ b/core/src/main/java/fr/skytasul/quests/BeautyQuests.java @@ -10,14 +10,12 @@ import java.util.Date; import java.util.HashMap; import java.util.Map; -import java.util.function.Function; import java.util.logging.Level; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; import org.bstats.bukkit.Metrics; -import org.bstats.charts.AdvancedPie; import org.bstats.charts.DrilldownPie; import org.bstats.charts.SimplePie; import org.bstats.charts.SingleLineChart; @@ -27,6 +25,7 @@ import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.scheduler.BukkitRunnable; import org.jetbrains.annotations.NotNull; @@ -328,13 +327,17 @@ private void launchMetrics(String pluginVersion) { if (size > 5) return "5 - 10"; return "0 - 5"; })); - metrics.addCustomChart(new AdvancedPie("hooks", () -> { // replace with bar chart when bStats add them back + metrics.addCustomChart(new DrilldownPie("hooks_v2", () -> { return integrations.getDependencies() - .stream() - .filter(dep -> dep.isEnabled()) - .map(dep -> dep.getFoundPlugin().getName()) - .distinct() - .collect(Collectors.toMap(Function.identity(), __ -> 1)); + .stream() + .filter(dep -> dep.isEnabled()) + .map(dep -> dep.getFoundPlugin()) + .distinct() + .collect(Collectors.toMap(Plugin::getName, plugin -> { + Map entry = new HashMap<>(); + entry.put(plugin.getDescription().getVersion(), 1); + return entry; + })); })); logger.debug("Started bStats metrics"); } diff --git a/core/src/main/java/fr/skytasul/quests/QuestsConfigurationImplementation.java b/core/src/main/java/fr/skytasul/quests/QuestsConfigurationImplementation.java index 71bf65e4..5acfb462 100644 --- a/core/src/main/java/fr/skytasul/quests/QuestsConfigurationImplementation.java +++ b/core/src/main/java/fr/skytasul/quests/QuestsConfigurationImplementation.java @@ -1,13 +1,5 @@ package fr.skytasul.quests; -import java.util.*; -import java.util.stream.Collectors; -import org.bukkit.*; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.FireworkMeta; -import org.jetbrains.annotations.NotNull; import fr.skytasul.quests.api.QuestsConfiguration; import fr.skytasul.quests.api.QuestsPlugin; import fr.skytasul.quests.api.gui.ItemUtils; @@ -20,6 +12,14 @@ import fr.skytasul.quests.utils.ParticleEffect; import fr.skytasul.quests.utils.ParticleEffect.ParticleShape; import fr.skytasul.quests.utils.compatibility.InternalIntegrations; +import org.bukkit.*; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.FireworkMeta; +import org.jetbrains.annotations.NotNull; +import java.util.*; +import java.util.stream.Collectors; public class QuestsConfigurationImplementation implements QuestsConfiguration { @@ -111,9 +111,13 @@ void init() { usePlayerBlockTracker = config.getBoolean("usePlayerBlockTracker"); if (MinecraftVersion.MAJOR >= 9) { - particleStart = loadParticles("start", new ParticleEffect(Particle.REDSTONE, ParticleShape.POINT, Color.YELLOW)); - particleTalk = loadParticles("talk", new ParticleEffect(Particle.VILLAGER_HAPPY, ParticleShape.BAR, null)); - particleNext = loadParticles("next", new ParticleEffect(Particle.SMOKE_NORMAL, ParticleShape.SPOT, null)); + particleStart = loadParticles("start", new ParticleEffect(Utils.valueOfEnum(Particle.class, "REDSTONE", "DUST"), + ParticleShape.POINT, Color.YELLOW)); + particleTalk = loadParticles("talk", new ParticleEffect( + Utils.valueOfEnum(Particle.class, "VILLAGER_HAPPY", "HAPPY_VILLAGER"), ParticleShape.BAR, null)); + particleNext = + loadParticles("next", new ParticleEffect(Utils.valueOfEnum(Particle.class, "SMOKE_NORMAL", "SMOKE"), + ParticleShape.SPOT, null)); } holoLaunchItem = loadHologram("launchItem"); diff --git a/core/src/main/java/fr/skytasul/quests/commands/CommandsPlayerManagement.java b/core/src/main/java/fr/skytasul/quests/commands/CommandsPlayerManagement.java index 8b6fb81e..9e1828a1 100644 --- a/core/src/main/java/fr/skytasul/quests/commands/CommandsPlayerManagement.java +++ b/core/src/main/java/fr/skytasul/quests/commands/CommandsPlayerManagement.java @@ -1,15 +1,5 @@ package fr.skytasul.quests.commands; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.permissions.Permission; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import fr.skytasul.quests.BeautyQuests; import fr.skytasul.quests.api.QuestsAPI; import fr.skytasul.quests.api.QuestsPlugin; @@ -47,12 +37,22 @@ import fr.skytasul.quests.structure.EndingStageImplementation; import fr.skytasul.quests.structure.QuestBranchImplementation; import fr.skytasul.quests.utils.QuestUtils; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.permissions.Permission; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; public class CommandsPlayerManagement implements OrphanCommand { - + private BukkitCommandPermission startOtherPermission = new BukkitCommandPermission(new Permission("beautyquests.command.start.other")); private BukkitCommandPermission cancelOtherPermission = new BukkitCommandPermission(new Permission("beautyquests.command.cancel.other")); - + @Subcommand ("finishAll") @CommandPermission ("beautyquests.command.finish") public void finishAll(BukkitCommandActor actor, EntitySelector players) { @@ -73,7 +73,7 @@ public void finishAll(BukkitCommandActor actor, EntitySelector players) Lang.LEAVE_ALL_RESULT.send(actor.getSender(), PlaceholderRegistry.of("success", success, "errors", errors)); } } - + @Subcommand ("finish") @CommandPermission ("beautyquests.command.finish") public void finish(BukkitCommandActor actor, EntitySelector players, Quest quest, @Switch boolean force) { @@ -90,7 +90,7 @@ public void finish(BukkitCommandActor actor, EntitySelector players, Que } } } - + @Subcommand ("setStage") @CommandPermission ("beautyquests.command.setStage") public void setStage( @@ -102,7 +102,7 @@ public void setStage( // syntax: no arg: next or start | 1 arg: start branch | 2 args: set branch stage PlayerAccount acc = PlayersManager.getPlayerAccount(player); BranchesManagerImplementation manager = (BranchesManagerImplementation) quest.getBranchesManager(); - + PlayerQuestDatas datas = acc.getQuestDatasIfPresent(quest); if (branchID == null && (datas == null || !datas.hasStarted())) { // start quest quest.start(player); @@ -110,19 +110,19 @@ public void setStage( return; } if (datas == null) datas = acc.getQuestDatas(quest); // creates quest datas - + QuestBranchImplementation currentBranch = manager.getBranch(datas.getBranch()); - + if (branchID == null) { // next if (!datas.isInEndingStages()) { - currentBranch.finishStage(player, currentBranch.getRegularStage(datas.getStage())); + currentBranch.finishPlayerStage(player, currentBranch.getRegularStage(datas.getStage())); Lang.COMMAND_SETSTAGE_NEXT.send(actor.getSender()); }else Lang.COMMAND_SETSTAGE_NEXT_UNAVAILABLE.send(actor.getSender()); }else { QuestBranchImplementation branch = manager.getBranch(branchID); if (branch == null) throw new CommandErrorException(Lang.COMMAND_SETSTAGE_BRANCH_DOESNTEXIST.quickFormat("branch_id", branchID)); - + if (stageID != null) { if (currentBranch == null) throw new CommandErrorException( @@ -144,18 +144,18 @@ public void setStage( branch.start(acc); }else { // set stage in branch datas.setBranch(branchID); - branch.setStage(acc, stageID); + branch.setPlayerStage(acc, branch.getRegularStage(stageID)); } QuestsAPI.getAPI().propagateQuestsHandlers(handler -> handler.questUpdated(acc, quest)); } } - + @Subcommand ("startDialog") @CommandPermission ("beautyquests.command.setStage") public void startDialog(BukkitCommandActor actor, Player player, Quest quest) { PlayerAccount acc = PlayersManager.getPlayerAccount(player); PlayerQuestDatas datas = acc.getQuestDatasIfPresent(quest); - + DialogRunner runner = null; if (datas == null || !quest.hasStarted(acc)) { if (quest.hasOption(OptionStartDialog.class)) { @@ -173,7 +173,7 @@ public void startDialog(BukkitCommandActor actor, Player player, Quest quest) { } } } - + if (runner == null) { Lang.COMMAND_STARTDIALOG_NO.send(actor.getSender()); }else { @@ -185,7 +185,7 @@ public void startDialog(BukkitCommandActor actor, Player player, Quest quest) { } } } - + @Subcommand ("resetPlayer") @CommandPermission ("beautyquests.command.resetPlayer") public void resetPlayer(BukkitCommandActor actor, EntitySelector players) { @@ -233,7 +233,7 @@ public void resetPlayer(BukkitCommandActor actor, EntitySelector players } } - + @Subcommand ("resetPlayerQuest") @CommandPermission ("beautyquests.command.resetPlayer") public void resetPlayerQuest(BukkitCommandActor actor, Player player, @Optional Quest quest) { @@ -245,7 +245,7 @@ public void resetPlayerQuest(BukkitCommandActor actor, Player player, @Optional }, PlayersManager.getPlayerAccount(player), true, false, true).open(actor.requirePlayer()); } } - + private void reset(CommandSender sender, Player target, Quest qu) { PlayerAccount acc = PlayersManager.getPlayerAccount(target); qu.resetPlayer(acc).whenComplete(QuestsPlugin.getPlugin().getLoggerExpanded().logError(__ -> { @@ -255,7 +255,7 @@ private void reset(CommandSender sender, Player target, Quest qu) { Lang.DATA_QUEST_REMOVED_INFO.send(sender, acc, qu); }, "An error occurred while removing player quest data", sender)); } - + @Subcommand ("resetQuest") @CommandPermission ("beautyquests.command.resetQuest") public void resetQuest(BukkitCommandActor actor, Quest quest) { @@ -291,13 +291,13 @@ public void resetQuest(BukkitCommandActor actor, Quest quest) { }).whenComplete(QuestsPlugin.getPlugin().getLoggerExpanded().logError()); } - + @Subcommand ("seePlayer") @CommandPermission ("beautyquests.command.seePlayer") public void seePlayer(Player actor, Player player) { new PlayerListGUI(BeautyQuests.getInstance().getPlayersManager().getAccount(player), false).open(actor); } - + @Subcommand ("start") @CommandPermission ("beautyquests.command.start") public void start(BukkitCommandActor actor, ExecutableCommand command, EntitySelector players, @@ -307,7 +307,7 @@ public void start(BukkitCommandActor actor, ExecutableCommand command, EntitySel if (players.isEmpty() || players.size() > 1 || (players.get(0) != actor.getAsPlayer())) throw new NoPermissionException(command, startOtherPermission); } - + for (Player player : players) { if (quest == null) { new QuestsListGUI(obj -> { @@ -328,7 +328,7 @@ private void start(CommandSender sender, Player player, Quest quest, boolean ove quest.start(player); Lang.START_QUEST.send(sender, quest, acc); } - + @Subcommand ("cancel") @CommandPermission ("beautyquests.command.cancel") public void cancel(BukkitCommandActor actor, ExecutableCommand command, EntitySelector players, @@ -337,10 +337,10 @@ public void cancel(BukkitCommandActor actor, ExecutableCommand command, EntitySe if (players.isEmpty() || players.size() > 1 || (players.get(0) != actor.getAsPlayer())) throw new NoPermissionException(command, cancelOtherPermission); } - + for (Player player : players) { PlayerAccount acc = PlayersManager.getPlayerAccount(player); - + if (quest == null) { new QuestsListGUI(obj -> { cancel(actor.getSender(), acc, obj); @@ -350,7 +350,7 @@ public void cancel(BukkitCommandActor actor, ExecutableCommand command, EntitySe } } } - + private void cancel(CommandSender sender, PlayerAccount acc, Quest quest) { if (!quest.isCancellable()) { Lang.CANCEL_QUEST_UNAVAILABLE.send(sender, quest); @@ -368,5 +368,5 @@ private void cancel(CommandSender sender, PlayerAccount acc, Quest quest) { } } } - + } diff --git a/core/src/main/java/fr/skytasul/quests/commands/CommandsPools.java b/core/src/main/java/fr/skytasul/quests/commands/CommandsPools.java index 47b92ab8..caae6a9e 100644 --- a/core/src/main/java/fr/skytasul/quests/commands/CommandsPools.java +++ b/core/src/main/java/fr/skytasul/quests/commands/CommandsPools.java @@ -1,6 +1,5 @@ package fr.skytasul.quests.commands; -import org.bukkit.entity.Player; import fr.skytasul.quests.api.QuestsPlugin; import fr.skytasul.quests.api.commands.revxrsal.annotation.Default; import fr.skytasul.quests.api.commands.revxrsal.annotation.Subcommand; @@ -15,6 +14,7 @@ import fr.skytasul.quests.api.pools.QuestPool; import fr.skytasul.quests.api.utils.messaging.PlaceholderRegistry; import fr.skytasul.quests.gui.pools.PoolsManageGUI; +import org.bukkit.entity.Player; public class CommandsPools implements OrphanCommand { @@ -49,8 +49,8 @@ public void start(BukkitCommandActor actor, EntitySelector players, Ques return; } - pool.give(player).thenAccept( - result -> Lang.POOL_START_SUCCESS.send(player, pool, acc, PlaceholderRegistry.of("result", result))); + pool.give(player).thenAccept(result -> Lang.POOL_START_SUCCESS.send(actor.getSender(), pool, acc, + PlaceholderRegistry.of("result", result))); } } diff --git a/core/src/main/java/fr/skytasul/quests/gui/DefaultItemFactory.java b/core/src/main/java/fr/skytasul/quests/gui/DefaultItemFactory.java index 5f1e907a..106d46be 100755 --- a/core/src/main/java/fr/skytasul/quests/gui/DefaultItemFactory.java +++ b/core/src/main/java/fr/skytasul/quests/gui/DefaultItemFactory.java @@ -3,14 +3,14 @@ import static fr.skytasul.quests.api.gui.ItemUtils.addEnchant; import static fr.skytasul.quests.api.gui.ItemUtils.item; import static fr.skytasul.quests.api.gui.ItemUtils.name; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.inventory.ItemStack; -import org.jetbrains.annotations.NotNull; import fr.skytasul.quests.api.QuestsConfiguration; import fr.skytasul.quests.api.gui.ItemFactory; import fr.skytasul.quests.api.localization.Lang; +import fr.skytasul.quests.api.utils.XEnchantment; import fr.skytasul.quests.api.utils.XMaterial; import net.md_5.bungee.api.ChatColor; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; public class DefaultItemFactory implements ItemFactory { @@ -33,7 +33,7 @@ public class DefaultItemFactory implements ItemFactory { @Override public @NotNull ItemStack getDone() { - return addEnchant(item(XMaterial.DIAMOND, Lang.done.toString()), Enchantment.DURABILITY, 0); + return addEnchant(item(XMaterial.DIAMOND, Lang.done.toString()), XEnchantment.DURABILITY.getEnchant(), 0); } @Override diff --git a/core/src/main/java/fr/skytasul/quests/gui/blocks/SelectBlockGUI.java b/core/src/main/java/fr/skytasul/quests/gui/blocks/SelectBlockGUI.java index 2d8f1a19..69211605 100644 --- a/core/src/main/java/fr/skytasul/quests/gui/blocks/SelectBlockGUI.java +++ b/core/src/main/java/fr/skytasul/quests/gui/blocks/SelectBlockGUI.java @@ -1,16 +1,5 @@ package fr.skytasul.quests.gui.blocks; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.function.BiConsumer; -import org.bukkit.Bukkit; -import org.bukkit.Material; -import org.bukkit.NamespacedKey; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.ItemStack; -import org.jetbrains.annotations.NotNull; import fr.skytasul.quests.BeautyQuests; import fr.skytasul.quests.api.QuestsPlugin; import fr.skytasul.quests.api.blocks.BQBlock; @@ -27,6 +16,16 @@ import fr.skytasul.quests.api.utils.XMaterial; import fr.skytasul.quests.api.utils.messaging.PlaceholderRegistry; import fr.skytasul.quests.utils.nms.NMS; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.function.BiConsumer; public class SelectBlockGUI extends LayoutedGUI.LayoutedRowsGUI { @@ -66,7 +65,7 @@ public void place(@NotNull Inventory inventory, int slot) { Lang.materialNotItemLore.quickFormat("block_type", type.name())))); } if (tag == null) - ItemUtils.addEnchant(inventory.getItem(slot), Enchantment.DURABILITY, 1); + ItemUtils.setGlittering(inventory.getItem(slot), true); } }); @@ -75,7 +74,7 @@ public void place(@NotNull Inventory inventory, int slot) { ItemStack item = ItemUtils.item(XMaterial.COMMAND_BLOCK, Lang.blockData.toString(), QuestOption.formatNullableValue(blockData, blockData == null)); if (blockData != null) - ItemUtils.addEnchant(item, Enchantment.DAMAGE_ALL, 1); + ItemUtils.setGlittering(item, true); return item; }, this::dataClick)); @@ -84,7 +83,7 @@ public void place(@NotNull Inventory inventory, int slot) { QuestOption.formatDescription(Lang.blockTagLore.toString()), "", QuestOption.formatNullableValue(tag, tag == null)); if (tag != null) - ItemUtils.addEnchant(item, Enchantment.DAMAGE_ALL, 1); + ItemUtils.setGlittering(item, true); return item; }, this::tagClick)); } diff --git a/core/src/main/java/fr/skytasul/quests/gui/items/ItemCreatorGUI.java b/core/src/main/java/fr/skytasul/quests/gui/items/ItemCreatorGUI.java index ccdce05c..7d601e46 100644 --- a/core/src/main/java/fr/skytasul/quests/gui/items/ItemCreatorGUI.java +++ b/core/src/main/java/fr/skytasul/quests/gui/items/ItemCreatorGUI.java @@ -1,16 +1,5 @@ package fr.skytasul.quests.gui.items; -import java.util.ArrayList; -import java.util.List; -import java.util.function.Consumer; -import org.bukkit.Bukkit; -import org.bukkit.Material; -import org.bukkit.entity.Player; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.ItemFlag; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; -import org.jetbrains.annotations.NotNull; import fr.skytasul.quests.api.QuestsPlugin; import fr.skytasul.quests.api.editors.TextEditor; import fr.skytasul.quests.api.editors.TextListEditor; @@ -20,6 +9,16 @@ import fr.skytasul.quests.api.gui.ItemUtils; import fr.skytasul.quests.api.localization.Lang; import fr.skytasul.quests.api.utils.XMaterial; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.jetbrains.annotations.NotNull; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; public class ItemCreatorGUI extends AbstractGui { @@ -147,7 +146,7 @@ private ItemStack build() { if (name != null) im.setDisplayName(name); if (flags) - im.addItemFlags(ItemFlag.values()); + ItemUtils.addSpecificFlags(im, is.getType()); is.setItemMeta(im); is.setAmount(amount); diff --git a/core/src/main/java/fr/skytasul/quests/gui/misc/CommandGUI.java b/core/src/main/java/fr/skytasul/quests/gui/misc/CommandGUI.java index ecae845b..974fa25e 100644 --- a/core/src/main/java/fr/skytasul/quests/gui/misc/CommandGUI.java +++ b/core/src/main/java/fr/skytasul/quests/gui/misc/CommandGUI.java @@ -2,6 +2,7 @@ import java.util.HashMap; import java.util.function.Consumer; +import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import fr.skytasul.quests.api.QuestsPlugin; @@ -32,7 +33,7 @@ public CommandGUI(Consumer end, Runnable cancel) { this.end = end; buttons.put(1, - doneButton = LayoutedButton.createLoreValue(XMaterial.COMMAND_BLOCK, Lang.commandValue.toString(), () -> cmd, + LayoutedButton.createLoreValue(XMaterial.COMMAND_BLOCK, Lang.commandValue.toString(), () -> cmd, this::commandClick)); buttons.put(3, LayoutedButton.create(() -> ItemUtils.itemSwitch(Lang.commandConsole.toString(), console), this::consoleClick)); @@ -40,8 +41,9 @@ public CommandGUI(Consumer end, Runnable cancel) { this::parseClick)); buttons.put(5, LayoutedButton.createLoreValue(XMaterial.CLOCK, Lang.commandDelay.toString(), () -> delay, this::delayClick)); - buttons.put(8, - LayoutedButton.create(() -> cmd == null ? QuestsPlugin.getPlugin().getGuiManager().getItemFactory().getNotDone() : QuestsPlugin.getPlugin().getGuiManager().getItemFactory().getDone(), this::doneClick)); + ItemStack notDone = QuestsPlugin.getPlugin().getGuiManager().getItemFactory().getNotDone(); + ItemStack done = QuestsPlugin.getPlugin().getGuiManager().getItemFactory().getDone(); + buttons.put(8, doneButton = LayoutedButton.create(() -> cmd == null ? notDone : done, this::doneClick)); } public CommandGUI setFromExistingCommand(@Nullable Command cmd) { diff --git a/core/src/main/java/fr/skytasul/quests/gui/particles/ParticleEffectGUI.java b/core/src/main/java/fr/skytasul/quests/gui/particles/ParticleEffectGUI.java index c26e209a..291483ac 100644 --- a/core/src/main/java/fr/skytasul/quests/gui/particles/ParticleEffectGUI.java +++ b/core/src/main/java/fr/skytasul/quests/gui/particles/ParticleEffectGUI.java @@ -34,26 +34,27 @@ public class ParticleEffectGUI extends LayoutedGUI.LayoutedRowsGUI { return false; }).collect(Collectors.toList()); - private final Consumer end; + private final @NotNull Consumer end; - private Particle particle; - private ParticleShape shape; - private Color color; + private @NotNull Particle particle; + private @NotNull ParticleShape shape; + private @NotNull Color color; - public ParticleEffectGUI(Consumer end) { + public ParticleEffectGUI(@NotNull Consumer end) { this(end, Particle.FLAME, ParticleShape.POINT, Color.AQUA); } - public ParticleEffectGUI(Consumer end, ParticleEffect effect) { + public ParticleEffectGUI(@NotNull Consumer end, @NotNull ParticleEffect effect) { this(end, effect.getParticle(), effect.getShape(), effect.getColor()); } - public ParticleEffectGUI(Consumer end, Particle particle, ParticleShape shape, Color color) { + public ParticleEffectGUI(@NotNull Consumer end, @NotNull Particle particle, @NotNull ParticleShape shape, + @Nullable Color color) { super(Lang.INVENTORY_PARTICLE_EFFECT.toString(), new HashMap<>(), new DelayCloseBehavior(() -> end.accept(null)), 1); this.end = end; this.particle = particle; this.shape = shape; - this.color = color; + this.color = color == null ? Color.AQUA : color; initButtons(); } diff --git a/core/src/main/java/fr/skytasul/quests/gui/quests/DialogHistoryGUI.java b/core/src/main/java/fr/skytasul/quests/gui/quests/DialogHistoryGUI.java index d54ae36c..994b4aaa 100644 --- a/core/src/main/java/fr/skytasul/quests/gui/quests/DialogHistoryGUI.java +++ b/core/src/main/java/fr/skytasul/quests/gui/quests/DialogHistoryGUI.java @@ -1,15 +1,7 @@ package fr.skytasul.quests.gui.quests; -import java.util.*; -import java.util.stream.Stream; -import org.apache.commons.lang.Validate; -import org.bukkit.DyeColor; -import org.bukkit.entity.Player; -import org.bukkit.event.inventory.ClickType; -import org.bukkit.inventory.ItemFlag; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; import fr.skytasul.quests.api.QuestsConfiguration; +import fr.skytasul.quests.api.gui.ItemUtils; import fr.skytasul.quests.api.gui.close.CloseBehavior; import fr.skytasul.quests.api.gui.close.StandardCloseBehavior; import fr.skytasul.quests.api.gui.templates.PagedGUI; @@ -25,6 +17,13 @@ import fr.skytasul.quests.gui.quests.DialogHistoryGUI.WrappedDialogable; import fr.skytasul.quests.options.OptionStartDialog; import fr.skytasul.quests.utils.QuestUtils; +import org.apache.commons.lang.Validate; +import org.bukkit.DyeColor; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.inventory.ItemStack; +import java.util.*; +import java.util.stream.Stream; public class DialogHistoryGUI extends PagedGUI { @@ -50,7 +49,7 @@ public DialogHistoryGUI(PlayerAccount acc, Quest quest, Runnable end) { @Override public ItemStack getItemStack(WrappedDialogable object) { - return object.setMeta(XMaterial.WRITTEN_BOOK.parseItem()); + return object.setMeta(ItemUtils.clearVisibleAttributes(XMaterial.WRITTEN_BOOK.parseItem())); } @Override @@ -163,13 +162,11 @@ public Page getCurrentPage() { } public ItemStack setMeta(ItemStack item) { - ItemMeta meta = item.getItemMeta(); - meta.setLore(getCurrentPage().lines); - meta.setDisplayName("§8" + objects.indexOf(this) + " (" + dialogable.getNPC().getNpc().getName() + "§8) - " - + getCurrentPage().header); - meta.addItemFlags(ItemFlag.HIDE_POTION_EFFECTS); - item.setItemMeta(meta); - return item; + return ItemUtils.nameAndLore( + item, + "§8" + objects.indexOf(this) + " (" + dialogable.getNPC().getNpc().getName() + "§8) - " + + getCurrentPage().header, + getCurrentPage().lines); } } diff --git a/core/src/main/java/fr/skytasul/quests/gui/quests/PlayerListGUI.java b/core/src/main/java/fr/skytasul/quests/gui/quests/PlayerListGUI.java index 08876cab..14862332 100644 --- a/core/src/main/java/fr/skytasul/quests/gui/quests/PlayerListGUI.java +++ b/core/src/main/java/fr/skytasul/quests/gui/quests/PlayerListGUI.java @@ -1,19 +1,5 @@ package fr.skytasul.quests.gui.quests; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; -import org.bukkit.DyeColor; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.Player; -import org.bukkit.event.inventory.ClickType; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import fr.skytasul.quests.api.QuestsAPI; import fr.skytasul.quests.api.QuestsConfiguration; import fr.skytasul.quests.api.QuestsPlugin; @@ -31,6 +17,18 @@ import fr.skytasul.quests.options.OptionStartable; import fr.skytasul.quests.players.PlayerAccountImplementation; import fr.skytasul.quests.utils.QuestUtils; +import org.bukkit.DyeColor; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; public class PlayerListGUI extends PagedGUI { @@ -74,13 +72,11 @@ protected void populate(@NotNull Player player, @NotNull Inventory inventory) { private void setCategory(PlayerListCategory category){ if (cat == category) return; if (cat != null) - toggleCategorySelected(); + setCategorySelected(false); cat = category; + setCategorySelected(true); setSeparatorColor(cat.getColor()); - DyeColor color = cat == PlayerListCategory.FINISHED ? DyeColor.GREEN: (cat == PlayerListCategory.IN_PROGRESS ? DyeColor.YELLOW : DyeColor.RED); - for (int i = 0; i < 5; i++) - getInventory().setItem(i * 9 + 7, ItemUtils.itemSeparator(color)); List quests; switch (cat) { @@ -203,19 +199,17 @@ public void click(@NotNull Quest qu, @NotNull ItemStack item, @NotNull ClickType } } - private void toggleCategorySelected() { + private void setCategorySelected(boolean selected) { ItemStack is = getInventory().getItem(cat.getSlot() * 9 + 8); - ItemMeta im = is.getItemMeta(); - String name = im.getDisplayName(); - if (!im.hasEnchant(Enchantment.DURABILITY)) { - im.addEnchant(Enchantment.DURABILITY, 0, true); - name = SELECTED_PREFIX + name.substring(UNSELECTED_PREFIX.length()); - }else{ - im.removeEnchant(Enchantment.DURABILITY); - name = UNSELECTED_PREFIX + name.substring(SELECTED_PREFIX.length()); + String name; + if (selected) { + ItemUtils.setGlittering(is, true); + name = SELECTED_PREFIX + cat.getName(); + } else { + ItemUtils.setGlittering(is, false); + name = UNSELECTED_PREFIX + cat.getName(); } - im.setDisplayName(name); - is.setItemMeta(im); + ItemUtils.name(is, name); } @Override diff --git a/core/src/main/java/fr/skytasul/quests/options/OptionQuestItem.java b/core/src/main/java/fr/skytasul/quests/options/OptionQuestItem.java index d83ad3f6..045f2727 100644 --- a/core/src/main/java/fr/skytasul/quests/options/OptionQuestItem.java +++ b/core/src/main/java/fr/skytasul/quests/options/OptionQuestItem.java @@ -14,7 +14,7 @@ import fr.skytasul.quests.utils.QuestUtils; public class OptionQuestItem extends QuestOption { - + @Override public void setValue(ItemStack value) { if (value == null || value.getType() == Material.AIR) { @@ -24,28 +24,28 @@ public void setValue(ItemStack value) { } super.setValue(value); } - + @Override public Object save() { return getValue(); } - + @Override public void load(ConfigurationSection config, String key) { setValue(config.isItemStack(key) ? config.getItemStack(key) : XMaterial.valueOf(config.getString(key)).parseItem()); } - + @Override public ItemStack cloneValue(ItemStack value) { return value.clone(); } - + private String[] getLore() { String description = formatDescription(Lang.customMaterialLore.toString()); if (!hasCustomValue()) return new String[] { description, "", Lang.defaultValue.toString() }; return new String[] { description }; } - + @Override public ItemStack getItemStack(OptionSet options) { return ItemUtils.nameAndLore(getValue().clone(), Lang.customMaterial.toString(), getLore()); @@ -54,10 +54,11 @@ public ItemStack getItemStack(OptionSet options) { @Override public void click(QuestCreationGuiClickEvent event) { if (event.hasCursor()) { - QuestUtils.runSync(() -> event.getPlayer().setItemOnCursor(null)); - setValue(event.getCursor()); - ItemUtils.nameAndLore(event.getCursor(), Lang.customMaterial.toString(), getLore()); - event.setCancelled(false); + ItemStack item = event.getCursor(); + QuestUtils.runSync(() -> { + setValue(item); + event.getPlayer().setItemOnCursor(null); + }); } else { Lang.QUEST_MATERIAL.send(event.getPlayer()); new TextEditor<>(event.getPlayer(), event::reopen, obj -> { @@ -66,18 +67,16 @@ public void click(QuestCreationGuiClickEvent event) { } else { setValue(obj.parseItem()); } - event.getGui().updateOptionItem(this); ItemStack setItem = event.getGui().getInventory().getItem(event.getSlot()); if (setItem == null || setItem.getType() == Material.AIR) { // means that the material cannot be treated as an inventory item (ex: fire) resetValue(); Lang.INVALID_ITEM_TYPE.send(event.getPlayer()); - event.getGui().updateOptionItem(this); } event.reopen(); }, QuestsPlugin.getPlugin().getEditorManager().getFactory().getMaterialParser(true, true)) .passNullIntoEndConsumer().start(); } } - + } diff --git a/core/src/main/java/fr/skytasul/quests/players/AbstractPlayersManager.java b/core/src/main/java/fr/skytasul/quests/players/AbstractPlayersManager.java index 73d34974..f77f675c 100644 --- a/core/src/main/java/fr/skytasul/quests/players/AbstractPlayersManager.java +++ b/core/src/main/java/fr/skytasul/quests/players/AbstractPlayersManager.java @@ -1,17 +1,5 @@ package fr.skytasul.quests.players; -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.*; -import java.util.concurrent.CompletableFuture; -import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.UnknownNullability; import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -27,7 +15,19 @@ import fr.skytasul.quests.api.utils.MissingDependencyException; import fr.skytasul.quests.players.accounts.AbstractAccount; import fr.skytasul.quests.players.accounts.UUIDAccount; -import fr.skytasul.quests.utils.DebugUtils; +import fr.skytasul.quests.utils.DebugUtils; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.UnknownNullability; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.*; +import java.util.concurrent.CompletableFuture; public abstract class AbstractPlayersManager implements PlayersManager { @@ -36,11 +36,11 @@ public abstract class AbstractPlayersManager implements PlayersManager { private boolean loaded = false; public abstract void load(@NotNull AccountFetchRequest request); - + public abstract void unloadAccount(@NotNull PlayerAccountImplementation acc); protected abstract @NotNull CompletableFuture removeAccount(@NotNull PlayerAccountImplementation acc); - + public abstract @NotNull CompletableFuture removeQuestDatas(@NotNull Quest quest); public abstract @NotNull PlayerQuestDatasImplementation createPlayerQuestDatas(@NotNull PlayerAccountImplementation acc, @@ -52,7 +52,7 @@ public abstract class AbstractPlayersManager implements PlayersManager { public @NotNull CompletableFuture playerQuestDataRemoved(@NotNull PlayerQuestDatasImplementation datas) { return CompletableFuture.completedFuture(null); } - + public @NotNull CompletableFuture playerPoolDataRemoved(@NotNull PlayerPoolDatasImplementation datas) { return CompletableFuture.completedFuture(null); } @@ -61,14 +61,14 @@ public void load() { if (loaded) throw new IllegalStateException("Already loaded"); loaded = true; } - + public boolean isLoaded() { return loaded; } @Override public abstract void save(); - + @Override public void addAccountData(@NotNull SavableData data) { if (loaded) @@ -82,7 +82,7 @@ public void addAccountData(@NotNull SavableData data) { accountDatas.add(data); QuestsPlugin.getPlugin().getLoggerExpanded().debug("Registered account data " + data.getId()); } - + @Override public @NotNull Collection<@NotNull SavableData> getAccountDatas() { return accountDatas; @@ -129,7 +129,7 @@ public void addAccountData(@NotNull SavableData data) { } return null; } - + public synchronized void loadPlayer(@NotNull Player p) { cachedPlayerNames.put(p.getUniqueId(), p.getName()); @@ -181,17 +181,26 @@ private boolean tryLoad(@NotNull Player p, long time) { "New account registered for " + p.getName() + " (" + request.getAccount().abstractAcc.getIdentifier() + "), index " + request.getAccount().index + " via " + DebugUtils.stackTraces(2, 4)); + if (!request.getAccount().getOfflinePlayer().equals(p)) { + QuestsPlugin.getPlugin().getLogger() + .severe("UUID mismatch between player " + p.getName() + " (" + p.getUniqueId() + ") and loaded account " + + request.getAccount().debugName()); + return false; + } + cachedAccounts.put(p, request.getAccount()); - Bukkit.getScheduler().runTask(BeautyQuests.getInstance(), () -> { - String loadMessage = - "Completed load of " + p.getName() + " (" + request.getAccount().debugName() + ") datas within " - + (System.currentTimeMillis() - time) + " ms (" + request.getAccount().getQuestsDatas().size() - + " quests, " + request.getAccount().getPoolDatas().size() + " pools)"; - if (request.getLoadedFrom() != null) - loadMessage += " | Loaded from " + request.getLoadedFrom(); + String loadMessage = + "Completed load of " + p.getName() + " (" + request.getAccount().debugName() + ") datas within " + + (System.currentTimeMillis() - time) + " ms (" + request.getAccount().getQuestsDatas().size() + + " quests, " + request.getAccount().getPoolDatas().size() + " pools)"; - QuestsPlugin.getPlugin().getLoggerExpanded().debug(loadMessage); + if (request.getLoadedFrom() != null) + loadMessage += " | Loaded from " + request.getLoadedFrom(); + + QuestsPlugin.getPlugin().getLoggerExpanded().debug(loadMessage); + + Bukkit.getScheduler().runTask(BeautyQuests.getInstance(), () -> { if (p.isOnline()) { Bukkit.getPluginManager() @@ -207,7 +216,7 @@ private boolean tryLoad(@NotNull Player p, long time) { }); return false; } - + public synchronized void unloadPlayer(@NotNull Player p) { PlayerAccountImplementation acc = cachedAccounts.get(p); if (acc == null) return; @@ -216,7 +225,7 @@ public synchronized void unloadPlayer(@NotNull Player p) { unloadAccount(acc); cachedAccounts.remove(p); } - + @Override public @UnknownNullability PlayerAccountImplementation getAccount(@NotNull Player p) { if (BeautyQuests.getInstance().getNpcManager().isNPC(p)) @@ -225,7 +234,7 @@ public synchronized void unloadPlayer(@NotNull Player p) { QuestsPlugin.getPlugin().getLoggerExpanded().severe("Trying to fetch the account of an offline player (" + p.getName() + ")"); QuestsPlugin.getPlugin().getLoggerExpanded().debug("(via " + DebugUtils.stackTraces(2, 5) + ")"); } - + return cachedAccounts.get(p); } @@ -330,7 +339,7 @@ public String getDebugPlayerName() { /** * This method must be called when the request results in a successfully loaded account. - * + * * @param account account that has been loaded * @param from source of the saved account */ @@ -346,7 +355,7 @@ public void loaded(PlayerAccountImplementation account, String from) { *

* It cannot be called when the {@link AccountFetchRequest#mustCreateMissing()} * method returns false. - * + * * @param account account that has been created */ public void created(PlayerAccountImplementation account) { diff --git a/core/src/main/java/fr/skytasul/quests/players/AdminMode.java b/core/src/main/java/fr/skytasul/quests/players/AdminMode.java index b6b9d578..246a5668 100644 --- a/core/src/main/java/fr/skytasul/quests/players/AdminMode.java +++ b/core/src/main/java/fr/skytasul/quests/players/AdminMode.java @@ -1,31 +1,32 @@ package fr.skytasul.quests.players; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; -import org.bukkit.Particle; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; import fr.skytasul.quests.BeautyQuests; import fr.skytasul.quests.api.localization.Lang; import fr.skytasul.quests.api.utils.MinecraftVersion; +import fr.skytasul.quests.api.utils.Utils; import fr.skytasul.quests.utils.ParticleEffect; +import org.bukkit.Particle; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; public class AdminMode { private static final Set senders = new HashSet<>(); - + private static ParticleEffect enterParticle; private static ParticleEffect leaveParticle; - + static { if (MinecraftVersion.MAJOR >= 9) { enterParticle = new ParticleEffect(Particle.FLAME, null, null); - leaveParticle = new ParticleEffect(Particle.SMOKE_NORMAL, null, null); + leaveParticle = new ParticleEffect(Utils.valueOfEnum(Particle.class, "SMOKE_NORMAL", "SMOKE"), null, null); } } - + public static void toggle(CommandSender sender){ if (senders.add(sender)) { Lang.ADMIN_MODE_ENTERED.send(sender); @@ -38,20 +39,20 @@ public static void toggle(CommandSender sender){ leaveParticle.sendParticle(((Player) sender).getEyeLocation(), getAdminPlayers(), 1, 1, 1, 15); } } - + public static void broadcast(String message){ BeautyQuests.getInstance().getLoggerExpanded().getHandler().write("[ADMIN]: " + message); for (CommandSender p : senders){ p.sendMessage("§e" + message); } } - + public static Set getAdminSenders() { return senders; } - + public static List getAdminPlayers(){ return senders.stream().filter(Player.class::isInstance).map(Player.class::cast).collect(Collectors.toList()); } - + } diff --git a/core/src/main/java/fr/skytasul/quests/stages/StageBreed.java b/core/src/main/java/fr/skytasul/quests/stages/StageBreed.java index a22815ef..7f6b805e 100644 --- a/core/src/main/java/fr/skytasul/quests/stages/StageBreed.java +++ b/core/src/main/java/fr/skytasul/quests/stages/StageBreed.java @@ -1,21 +1,36 @@ package fr.skytasul.quests.stages; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import org.bukkit.Bukkit; +import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.Animals; import org.bukkit.entity.Breedable; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.entity.EntityBreedEvent; +import org.bukkit.event.entity.EntityChangeBlockEvent; import org.jetbrains.annotations.NotNull; import fr.skytasul.quests.api.localization.Lang; import fr.skytasul.quests.api.stages.StageController; import fr.skytasul.quests.api.stages.StageDescriptionPlaceholdersContext; import fr.skytasul.quests.api.stages.creation.StageCreationContext; import fr.skytasul.quests.api.stages.types.AbstractEntityStage; +import fr.skytasul.quests.api.utils.XMaterial; public class StageBreed extends AbstractEntityStage implements Listener { + private static final List EGG_MATERIALS = + Arrays.asList(XMaterial.TURTLE_EGG, XMaterial.FROGSPAWN) + .stream() + .filter(XMaterial::isSupported) + .map(XMaterial::parseMaterial) + .collect(Collectors.toList()); + public StageBreed(StageController controller, EntityType entity, int amount) { super(controller, entity, amount); } @@ -28,6 +43,18 @@ public void onBreed(EntityBreedEvent e) { } } + @EventHandler + public void onEntityChangeBlock(EntityChangeBlockEvent e) { + if (!EGG_MATERIALS.contains(e.getTo())) + return; + if (!(e.getEntity() instanceof Animals)) + return; + Animals entity = (Animals) e.getEntity(); + Player breeder = Bukkit.getPlayer(entity.getBreedCause()); + if (breeder != null) + event(breeder, e.getEntityType()); + } + @Override public @NotNull String getDefaultDescription(@NotNull StageDescriptionPlaceholdersContext context) { return Lang.SCOREBOARD_BREED.toString(); diff --git a/core/src/main/java/fr/skytasul/quests/stages/StageBringBack.java b/core/src/main/java/fr/skytasul/quests/stages/StageBringBack.java index 0baa055e..39668274 100644 --- a/core/src/main/java/fr/skytasul/quests/stages/StageBringBack.java +++ b/core/src/main/java/fr/skytasul/quests/stages/StageBringBack.java @@ -1,11 +1,5 @@ package fr.skytasul.quests.stages; -import java.util.*; -import java.util.Map.Entry; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.jetbrains.annotations.NotNull; import fr.skytasul.quests.api.QuestsConfiguration; import fr.skytasul.quests.api.comparison.ItemComparisonMap; import fr.skytasul.quests.api.editors.TextEditor; @@ -29,6 +23,12 @@ import fr.skytasul.quests.api.utils.progress.itemdescription.HasItemsDescriptionConfiguration.HasSingleObject; import fr.skytasul.quests.gui.items.ItemComparisonGUI; import fr.skytasul.quests.gui.items.ItemsGUI; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import java.util.*; +import java.util.Map.Entry; public class StageBringBack extends StageNPC{ @@ -65,9 +65,12 @@ public boolean checkItems(Player p, boolean msg){ } public void sendNeedMessage(Player p) { - new Message(MessageUtils.format(getMessage(), getPlaceholdersRegistry(), StageDescriptionPlaceholdersContext.of(true, - PlayersManager.getPlayerAccount(p), DescriptionSource.FORCELINE, null)), Sender.NPC).sendMessage(p, getNPC(), - getNpcName(), 1, 1); + String text = getMessage(); + if ("none".equals(text)) + return; + Message msg = new Message(MessageUtils.format(text, getPlaceholdersRegistry(), StageDescriptionPlaceholdersContext + .of(true, PlayersManager.getPlayerAccount(p), DescriptionSource.FORCELINE, null)), Sender.NPC); + msg.sendMessage(p, getNPC(), getNpcName(), 0, 1); } public void removeItems(Player p){ @@ -104,7 +107,7 @@ protected void createdPlaceholdersRegistry(@NotNull PlaceholderRegistry placehol Arrays.stream(items).map(item -> ProgressPlaceholders.formatObject(new HasSingleObject() { @Override - public int getPlayerAmount(@NotNull PlayerAccount account) { + public long getPlayerAmount(@NotNull PlayerAccount account) { return item.getAmount(); } @@ -114,7 +117,7 @@ public int getPlayerAmount(@NotNull PlayerAccount account) { } @Override - public int getObjectAmount() { + public long getObjectAmount() { return item.getAmount(); } }, context)).toArray(String[]::new); diff --git a/core/src/main/java/fr/skytasul/quests/stages/StageBucket.java b/core/src/main/java/fr/skytasul/quests/stages/StageBucket.java index 17586c69..fcc6b2dd 100644 --- a/core/src/main/java/fr/skytasul/quests/stages/StageBucket.java +++ b/core/src/main/java/fr/skytasul/quests/stages/StageBucket.java @@ -1,14 +1,5 @@ package fr.skytasul.quests.stages; -import java.util.Map; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerBucketFillEvent; -import org.bukkit.inventory.ItemStack; -import org.jetbrains.annotations.NotNull; import fr.skytasul.quests.api.QuestsConfiguration; import fr.skytasul.quests.api.editors.TextEditor; import fr.skytasul.quests.api.editors.parsers.NumberParser; @@ -30,6 +21,15 @@ import fr.skytasul.quests.api.utils.progress.itemdescription.HasItemsDescriptionConfiguration.HasSingleObject; import fr.skytasul.quests.api.utils.progress.itemdescription.ItemsDescriptionConfiguration; import fr.skytasul.quests.gui.misc.BucketTypeGUI; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerBucketFillEvent; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import java.util.Map; public class StageBucket extends AbstractStage implements HasSingleObject, Listener { @@ -56,7 +56,7 @@ public int getBucketAmount() { } @Override - public int getObjectAmount() { + public long getObjectAmount() { return amount; } @@ -70,7 +70,7 @@ public void onBucketFill(PlayerBucketFillEvent e) { Player p = e.getPlayer(); if (hasStarted(p) && canUpdate(p)) { if (BucketType.fromMaterial(XMaterial.matchXMaterial(e.getItemStack())) == bucket) { - int amount = getPlayerAmount(PlayersManager.getPlayerAccount(p)); + long amount = getPlayerAmount(PlayersManager.getPlayerAccount(p)); if (amount <= 1) { finishStage(p); }else { @@ -81,8 +81,8 @@ public void onBucketFill(PlayerBucketFillEvent e) { } @Override - public int getPlayerAmount(PlayerAccount acc) { - return getData(acc, "amount"); + public long getPlayerAmount(PlayerAccount acc) { + return getData(acc, "amount", Long.class); } @Override diff --git a/core/src/main/java/fr/skytasul/quests/stages/StageCraft.java b/core/src/main/java/fr/skytasul/quests/stages/StageCraft.java index 964bf332..e952bca7 100644 --- a/core/src/main/java/fr/skytasul/quests/stages/StageCraft.java +++ b/core/src/main/java/fr/skytasul/quests/stages/StageCraft.java @@ -1,16 +1,5 @@ package fr.skytasul.quests.stages; -import java.util.Map; -import org.bukkit.Material; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.inventory.FurnaceExtractEvent; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.ItemStack; -import org.jetbrains.annotations.NotNull; import fr.skytasul.quests.api.QuestsPlugin; import fr.skytasul.quests.api.comparison.ItemComparisonMap; import fr.skytasul.quests.api.events.internal.BQCraftEvent; @@ -31,6 +20,17 @@ import fr.skytasul.quests.api.utils.progress.ProgressPlaceholders; import fr.skytasul.quests.api.utils.progress.itemdescription.HasItemsDescriptionConfiguration.HasSingleObject; import fr.skytasul.quests.gui.items.ItemComparisonGUI; +import org.bukkit.Material; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.FurnaceExtractEvent; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import java.util.Map; /** * @author SkytAsul, ezeiger92, TheBusyBiscuit @@ -55,7 +55,7 @@ public ItemStack getItem(){ public void onFurnaceExtract(FurnaceExtractEvent event) { Player p = event.getPlayer(); if (comparisons.isSimilar(result, new ItemStack(event.getItemType())) && hasStarted(p) && canUpdate(p, true)) { - int amount = getPlayerAmount(PlayersManager.getPlayerAccount(p)) - event.getItemAmount(); + long amount = getPlayerAmount(PlayersManager.getPlayerAccount(p)) - event.getItemAmount(); if (amount <= 0) { finishStage(p); }else { @@ -114,7 +114,7 @@ public void onCraft(BQCraftEvent event) { // No use continuing if we haven't actually crafted a thing if (recipeAmount == 0) return; - int amount = getPlayerAmount(PlayersManager.getPlayerAccount(p)) - recipeAmount; + long amount = getPlayerAmount(PlayersManager.getPlayerAccount(p)) - recipeAmount; if (amount <= 0) { finishStage(p); }else { @@ -131,9 +131,9 @@ public void initPlayerDatas(PlayerAccount acc, Map datas) { } @Override - public int getPlayerAmount(PlayerAccount acc) { - Integer amount = getData(acc, "amount"); - return amount == null ? 0 : amount.intValue(); + public long getPlayerAmount(PlayerAccount acc) { + Long amount = getData(acc, "amount", Long.class); + return amount == null ? 0 : amount.longValue(); } @Override @@ -142,7 +142,7 @@ public int getPlayerAmount(PlayerAccount acc) { } @Override - public int getObjectAmount() { + public long getObjectAmount() { return result.getAmount(); } diff --git a/core/src/main/java/fr/skytasul/quests/stages/StageDealDamage.java b/core/src/main/java/fr/skytasul/quests/stages/StageDealDamage.java index 921687fd..ba3cd680 100644 --- a/core/src/main/java/fr/skytasul/quests/stages/StageDealDamage.java +++ b/core/src/main/java/fr/skytasul/quests/stages/StageDealDamage.java @@ -1,21 +1,5 @@ package fr.skytasul.quests.stages; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; -import org.bukkit.DyeColor; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.entity.Player; -import org.bukkit.entity.Projectile; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.entity.EntityDamageByEntityEvent; -import org.bukkit.inventory.ItemStack; -import org.bukkit.projectiles.ProjectileSource; -import org.jetbrains.annotations.NotNull; import fr.skytasul.quests.api.editors.TextEditor; import fr.skytasul.quests.api.editors.parsers.NumberParser; import fr.skytasul.quests.api.gui.ItemUtils; @@ -36,6 +20,22 @@ import fr.skytasul.quests.api.utils.progress.ProgressPlaceholders; import fr.skytasul.quests.gui.mobs.MobSelectionGUI; import fr.skytasul.quests.mobs.Mob; +import org.bukkit.DyeColor; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.Player; +import org.bukkit.entity.Projectile; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.projectiles.ProjectileSource; +import org.jetbrains.annotations.NotNull; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; @SuppressWarnings ("rawtypes") public class StageDealDamage extends AbstractStage implements HasProgress, Listener { @@ -84,17 +84,17 @@ public void onDamage(EntityDamageByEntityEvent event) { } public double getPlayerAmountDouble(@NotNull PlayerAccount account) { - return getData(account, "amount"); + return getData(account, "amount", Double.class); } @Override - public int getPlayerAmount(@NotNull PlayerAccount account) { - return (int) Math.ceil(getPlayerAmountDouble(account)); + public long getPlayerAmount(@NotNull PlayerAccount account) { + return (long) Math.ceil(getPlayerAmountDouble(account)); } @Override - public int getTotalAmount() { - return (int) damage; + public long getTotalAmount() { + return (long) damage; } @Override @@ -102,7 +102,7 @@ protected void createdPlaceholdersRegistry(@NotNull PlaceholderRegistry placehol super.createdPlaceholdersRegistry(placeholders); ProgressPlaceholders.registerProgress(placeholders, "damage", this); placeholders.registerIndexedContextual("damage_remaining", StageDescriptionPlaceholdersContext.class, - context -> Integer.toString(getPlayerAmount(context.getPlayerAccount()))); + context -> Long.toString(getPlayerAmount(context.getPlayerAccount()))); placeholders.registerIndexed("target_mobs", getTargetMobsString(targetMobs)); } diff --git a/core/src/main/java/fr/skytasul/quests/stages/StageEnchant.java b/core/src/main/java/fr/skytasul/quests/stages/StageEnchant.java index f9cdedbc..92d75cb9 100644 --- a/core/src/main/java/fr/skytasul/quests/stages/StageEnchant.java +++ b/core/src/main/java/fr/skytasul/quests/stages/StageEnchant.java @@ -31,9 +31,6 @@ public StageEnchant(StageController controller, ConfigurationSection section) { @EventHandler (priority = EventPriority.MONITOR, ignoreCancelled = true) public void onEnchant(EnchantItemEvent e) { - if (!hasStarted(e.getEnchanter())) - return; - ItemStack finalItem = e.getItem().clone(); ItemMeta meta = finalItem.getItemMeta(); e.getEnchantsToAdd().forEach((enchant, level) -> meta.addEnchant(enchant, level, false)); diff --git a/core/src/main/java/fr/skytasul/quests/stages/StageFish.java b/core/src/main/java/fr/skytasul/quests/stages/StageFish.java index 34ebaad8..0c9cf37c 100644 --- a/core/src/main/java/fr/skytasul/quests/stages/StageFish.java +++ b/core/src/main/java/fr/skytasul/quests/stages/StageFish.java @@ -36,7 +36,7 @@ public void onFish(PlayerFishEvent e){ if (e.getState() == State.CAUGHT_FISH && e.getCaught() instanceof Item){ Player p = e.getPlayer(); Item item = (Item) e.getCaught(); - if (item.isDead() || !hasStarted(p)) + if (item.isDead()) return; ItemStack fish = item.getItemStack(); event(p, fish, fish.getAmount()); diff --git a/core/src/main/java/fr/skytasul/quests/stages/StageMobs.java b/core/src/main/java/fr/skytasul/quests/stages/StageMobs.java index 6a35c550..dafda32a 100644 --- a/core/src/main/java/fr/skytasul/quests/stages/StageMobs.java +++ b/core/src/main/java/fr/skytasul/quests/stages/StageMobs.java @@ -57,8 +57,7 @@ public void onMobKilled(BQMobDeathEvent e){ Player p = e.getKiller(); if (p == e.getBukkitEntity()) return; // player suicidal - if (hasStarted(p)) - event(p, new KilledMob(e.getPluginMob(), e.getBukkitEntity()), e.getAmount()); + event(p, new KilledMob(e.getPluginMob(), e.getBukkitEntity()), e.getAmount()); } @Override diff --git a/core/src/main/java/fr/skytasul/quests/stages/StagePlaceBlocks.java b/core/src/main/java/fr/skytasul/quests/stages/StagePlaceBlocks.java index 34807859..26f974df 100644 --- a/core/src/main/java/fr/skytasul/quests/stages/StagePlaceBlocks.java +++ b/core/src/main/java/fr/skytasul/quests/stages/StagePlaceBlocks.java @@ -3,7 +3,6 @@ import java.util.ArrayList; import java.util.List; import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -33,10 +32,9 @@ public StagePlaceBlocks(StageController controller, List= 0 && playerRemaining <= totalAmount) { bar.setProgress((totalAmount - playerRemaining) * 1D / totalAmount); } else QuestsPlugin.getPlugin().getLoggerExpanded() - .warning("Amount of objects superior to max objects in " + progress.toString() + " for player " - + acc.getNameAndID() + ": " + playerRemaining + " > " + totalAmount); + .warning("Amount of objects invalid in " + progress.getController().toString() + + " for player " + acc.getNameAndID() + ": " + playerRemaining + " / " + totalAmount); bar.setTitle(MessageUtils.format(getProgressConfig().getBossBarFormat(), placeholders, PlaceholdersContext.of(acc.getPlayer(), true, null))); diff --git a/core/src/main/java/fr/skytasul/quests/structure/QuestBranchImplementation.java b/core/src/main/java/fr/skytasul/quests/structure/QuestBranchImplementation.java index 4fe2ed87..1e1f7c41 100644 --- a/core/src/main/java/fr/skytasul/quests/structure/QuestBranchImplementation.java +++ b/core/src/main/java/fr/skytasul/quests/structure/QuestBranchImplementation.java @@ -1,14 +1,5 @@ package fr.skytasul.quests.structure; -import java.util.*; -import java.util.stream.Collectors; -import org.apache.commons.lang.Validate; -import org.bukkit.Bukkit; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.UnmodifiableView; import fr.skytasul.quests.QuestsConfigurationImplementation; import fr.skytasul.quests.api.QuestsConfiguration; import fr.skytasul.quests.api.QuestsPlugin; @@ -29,6 +20,15 @@ import fr.skytasul.quests.players.AdminMode; import fr.skytasul.quests.utils.DebugUtils; import fr.skytasul.quests.utils.QuestUtils; +import org.apache.commons.lang.Validate; +import org.bukkit.Bukkit; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.UnmodifiableView; +import java.util.*; +import java.util.stream.Collectors; public class QuestBranchImplementation implements QuestBranch { @@ -173,13 +173,14 @@ public void remove(@NotNull PlayerAccount acc, boolean end) { public void start(@NotNull PlayerAccount acc) { acc.getQuestDatas(getQuest()).setBranch(getId()); if (!regularStages.isEmpty()){ - setStage(acc, 0); + setPlayerStage(acc, regularStages.get(0)); }else { - setEndingStages(acc, true); + setPlayerEndingStages(acc); } } - public void finishStage(@NotNull Player p, @NotNull StageControllerImplementation stage) { + @Override + public void finishPlayerStage(@NotNull Player p, @NotNull StageController stage) { QuestsPlugin.getPlugin().getLoggerExpanded().debug("Next stage for player " + p.getName() + " (coming from " + stage.toString() + ") via " + DebugUtils.stackTraces(1, 3)); PlayerAccount acc = PlayersManager.getPlayerAccount(p); @NotNull @@ -200,7 +201,7 @@ public void finishStage(@NotNull Player p, @NotNull StageControllerImplementatio } } datas.setStage(-1); - endStage(acc, stage, () -> { + endStage(acc, (StageControllerImplementation) stage, () -> { if (!manager.getQuest().hasStarted(acc)) return; if (regularStages.contains(stage)){ // not ending stage - continue the branch or finish the quest int newId = getRegularStageId(stage) + 1; @@ -210,9 +211,9 @@ public void finishStage(@NotNull Player p, @NotNull StageControllerImplementatio getQuest().finish(p); return; } - setEndingStages(acc, true); + setPlayerEndingStages(acc); }else { - setStage(acc, newId); + setPlayerStage(acc, regularStages.get(newId)); } }else { // ending stage - redirect to other branch remove(acc, false); @@ -275,37 +276,39 @@ private void endStage(@NotNull PlayerAccount acc, @NotNull StageControllerImplem } } - public void setStage(@NotNull PlayerAccount acc, int id) { - StageControllerImplementation stage = regularStages.get(id); + @Override + public void setPlayerStage(@NotNull PlayerAccount acc, @NotNull StageController stage) { Player p = acc.getPlayer(); - if (stage == null){ - if (p != null) - DefaultErrors.sendGeneric(p, " noStage"); - QuestsPlugin.getPlugin().getLoggerExpanded().severe("Error into the StageManager of quest " + getQuest().getName() + " : the stage " + id + " doesn't exists."); - remove(acc, true); - }else { - PlayerQuestDatas questDatas = acc.getQuestDatas(getQuest()); - if (QuestsConfiguration.getConfig().getQuestsConfig().playerQuestUpdateMessage() && p != null - && questDatas.getStage() != -1) - Lang.QUEST_UPDATED.send(p, getQuest()); - questDatas.setStage(id); - if (p != null) playNextStage(p); - stage.start(acc); - Bukkit.getPluginManager().callEvent(new PlayerSetStageEvent(acc, getQuest(), stage)); - } + PlayerQuestDatas questDatas = acc.getQuestDatas(getQuest()); + if (questDatas.getBranch() != getId()) + throw new IllegalStateException("The player is not in the right branch"); + + if (QuestsConfiguration.getConfig().getQuestsConfig().playerQuestUpdateMessage() && p != null + && questDatas.getStage() != -1) + Lang.QUEST_UPDATED.send(p, getQuest()); + questDatas.setStage(getRegularStageId(stage)); + if (p != null) + playNextStage(p); + ((StageControllerImplementation) stage).start(acc); + Bukkit.getPluginManager().callEvent(new PlayerSetStageEvent(acc, getQuest(), stage)); } - public void setEndingStages(@NotNull PlayerAccount acc, boolean launchStage) { + @Override + public void setPlayerEndingStages(@NotNull PlayerAccount acc) { Player p = acc.getPlayer(); - if (QuestsConfiguration.getConfig().getQuestsConfig().playerQuestUpdateMessage() && p != null && launchStage) - Lang.QUEST_UPDATED.send(p, getQuest()); PlayerQuestDatas datas = acc.getQuestDatas(getQuest()); + if (datas.getBranch() != getId()) + throw new IllegalStateException("The player is not in the right branch"); + + if (QuestsConfiguration.getConfig().getQuestsConfig().playerQuestUpdateMessage() && p != null) + Lang.QUEST_UPDATED.send(p, getQuest()); datas.setInEndingStages(); for (EndingStageImplementation endStage : endStages) { endStage.getStage().start(acc); Bukkit.getPluginManager().callEvent(new PlayerSetStageEvent(acc, getQuest(), endStage.getStage())); } - if (p != null && launchStage) playNextStage(p); + if (p != null) + playNextStage(p); } private void playNextStage(@NotNull Player p) { diff --git a/core/src/main/java/fr/skytasul/quests/structure/StageControllerImplementation.java b/core/src/main/java/fr/skytasul/quests/structure/StageControllerImplementation.java index 03d047c1..35610a0c 100644 --- a/core/src/main/java/fr/skytasul/quests/structure/StageControllerImplementation.java +++ b/core/src/main/java/fr/skytasul/quests/structure/StageControllerImplementation.java @@ -1,18 +1,6 @@ package fr.skytasul.quests.structure; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.function.Consumer; -import org.bukkit.Bukkit; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.HandlerList; -import org.bukkit.event.Listener; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import com.google.gson.JsonSyntaxException; import fr.skytasul.quests.BeautyQuests; import fr.skytasul.quests.api.QuestsAPI; import fr.skytasul.quests.api.QuestsPlugin; @@ -23,10 +11,24 @@ import fr.skytasul.quests.api.players.PlayerQuestDatas; import fr.skytasul.quests.api.players.PlayersManager; import fr.skytasul.quests.api.stages.*; +import fr.skytasul.quests.api.utils.CustomizedObjectTypeAdapter; import fr.skytasul.quests.api.utils.messaging.MessageType; import fr.skytasul.quests.api.utils.messaging.MessageUtils; import fr.skytasul.quests.utils.QuestUtils; import fr.skytasul.quests.utils.compatibility.BQBackwardCompat; +import org.bukkit.Bukkit; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Consumer; public class StageControllerImplementation implements StageController, Listener { @@ -70,7 +72,7 @@ public void setStage(@NotNull T stage) { @Override public void finishStage(@NotNull Player player) { - QuestUtils.runSync(() -> branch.finishStage(player, this)); + QuestUtils.runSync(() -> branch.finishPlayerStage(player, this)); } @Override @@ -97,7 +99,7 @@ public void updateObjective(@NotNull Player player, @NotNull String dataKey, @Nu } @Override - public @Nullable D getData(@NotNull PlayerAccount acc, @NotNull String dataKey) { + public @Nullable D getData(@NotNull PlayerAccount acc, @NotNull String dataKey, @Nullable Class dataType) { PlayerQuestDatas playerDatas = acc.getQuestDatas(branch.getQuest()); Map datas = playerDatas.getStageDatas(getStorageId()); @@ -112,7 +114,24 @@ public void updateObjective(@NotNull Player player, @NotNull String dataKey, @Nu acc.getQuestDatas(branch.getQuest()).setStageDatas(getStorageId(), datas); } - return (D) datas.get(dataKey); + Object data = datas.get(dataKey); + if (dataType == null) // case when we do not have explicit data type to match for: we can only do direct cast + return (D) data; + + if (dataType.isInstance(data)) // easy: the data is directly compatible with the expected type + return dataType.cast(data); + + // hard: the data is not compatible. It may be because the deserialization process previously did + // not know the exact type to deserialize. Hence we go back to serialized to deserialize again, but + // this time with the correct type. + String serialized = CustomizedObjectTypeAdapter.serializeNullable(data); + try { + return CustomizedObjectTypeAdapter.deserializeNullable(serialized, dataType); + } catch (JsonSyntaxException ex) { + QuestsPlugin.getPlugin().getLoggerExpanded().severe( + "Cannot convert data " + dataKey + " to " + dataType.toString() + ". Serialized form: " + serialized); + throw ex; + } } @Override diff --git a/core/src/main/java/fr/skytasul/quests/utils/ParticleEffect.java b/core/src/main/java/fr/skytasul/quests/utils/ParticleEffect.java index 8021300c..319fda9a 100644 --- a/core/src/main/java/fr/skytasul/quests/utils/ParticleEffect.java +++ b/core/src/main/java/fr/skytasul/quests/utils/ParticleEffect.java @@ -1,7 +1,8 @@ package fr.skytasul.quests.utils; -import java.util.List; -import java.util.Random; +import fr.skytasul.quests.api.utils.MinecraftVersion; +import fr.skytasul.quests.utils.compatibility.Post1_13; +import fr.skytasul.quests.utils.nms.NMS; import org.apache.commons.lang.Validate; import org.bukkit.Color; import org.bukkit.Location; @@ -9,22 +10,24 @@ import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; -import fr.skytasul.quests.api.utils.MinecraftVersion; -import fr.skytasul.quests.utils.compatibility.Post1_13; -import fr.skytasul.quests.utils.nms.NMS; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import java.util.Arrays; +import java.util.List; +import java.util.Random; public class ParticleEffect { private static Random random = new Random(); - private final ParticleType type; - private final ParticleShape shape; - private final Color color; + private final @NotNull ParticleType type; + private final @NotNull ParticleShape shape; + private final @Nullable Color color; private final double[] colors; private final Object dustColor; - public ParticleEffect(Particle bukkitType, ParticleShape shape, Color color) { + public ParticleEffect(@NotNull Particle bukkitType, @NotNull ParticleShape shape, @Nullable Color color) { Validate.notNull(bukkitType); this.type = new ParticleType(bukkitType); this.shape = shape; @@ -46,15 +49,15 @@ public ParticleEffect(Particle bukkitType, ParticleShape shape, Color color) { } } - public Particle getParticle() { + public @NotNull Particle getParticle() { return type.particle; } - public ParticleShape getShape() { + public @NotNull ParticleShape getShape() { return shape; } - public Color getColor() { + public @Nullable Color getColor() { return color; } @@ -110,7 +113,8 @@ public void sendParticle(Location lc, List players, double offX, double } for (Player p : players) { - p.spawnParticle(type.particle, lc, amount, offX, offY, offZ, extra, data); + if (p.getWorld() == lc.getWorld()) + p.spawnParticle(type.particle, lc, amount, offX, offY, offZ, extra, data); } } @@ -129,7 +133,7 @@ public static ParticleEffect deserialize(ConfigurationSection data) { public static boolean canHaveColor(Particle particle) { if (MinecraftVersion.MAJOR >= 13) return particle.getDataType() == Post1_13.getDustOptionClass(); - return particle == Particle.REDSTONE || particle == Particle.SPELL_MOB || particle == Particle.SPELL_MOB_AMBIENT; + return Arrays.asList("REDSTONE", "SPELL_MOB", "SPELL_MOB_AMBIENT").contains(particle.name()); } public enum ParticleShape { @@ -157,7 +161,7 @@ private ParticleType(Particle particle) { dustColored = false; } }else { - colored = particle == Particle.REDSTONE || particle == Particle.SPELL_MOB || particle == Particle.SPELL_MOB_AMBIENT; + colored = canHaveColor(particle); dustColored = false; } diff --git a/core/src/main/java/fr/skytasul/quests/utils/QuestUtils.java b/core/src/main/java/fr/skytasul/quests/utils/QuestUtils.java index 56e3310c..49711292 100644 --- a/core/src/main/java/fr/skytasul/quests/utils/QuestUtils.java +++ b/core/src/main/java/fr/skytasul/quests/utils/QuestUtils.java @@ -1,11 +1,12 @@ package fr.skytasul.quests.utils; -import java.lang.annotation.Annotation; -import java.lang.annotation.Inherited; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.function.BiConsumer; -import java.util.function.Consumer; +import fr.skytasul.quests.BeautyQuests; +import fr.skytasul.quests.QuestsConfigurationImplementation; +import fr.skytasul.quests.api.QuestsConfiguration; +import fr.skytasul.quests.api.QuestsPlugin; +import fr.skytasul.quests.api.utils.AutoRegistered; +import fr.skytasul.quests.api.utils.MinecraftVersion; +import fr.skytasul.quests.utils.nms.NMS; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Sound; @@ -21,13 +22,12 @@ import org.bukkit.metadata.FixedMetadataValue; import org.bukkit.scoreboard.DisplaySlot; import org.jetbrains.annotations.NotNull; -import fr.skytasul.quests.BeautyQuests; -import fr.skytasul.quests.QuestsConfigurationImplementation; -import fr.skytasul.quests.api.QuestsConfiguration; -import fr.skytasul.quests.api.QuestsPlugin; -import fr.skytasul.quests.api.utils.AutoRegistered; -import fr.skytasul.quests.api.utils.MinecraftVersion; -import fr.skytasul.quests.utils.nms.NMS; +import java.lang.annotation.Annotation; +import java.lang.annotation.Inherited; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.function.BiConsumer; +import java.util.function.Consumer; public final class QuestUtils { @@ -153,10 +153,11 @@ public static void spawnFirework(Location lc, FireworkMeta meta) { fw.setMetadata("questFinish", new FixedMetadataValue(BeautyQuests.getInstance(), true)); fw.setFireworkMeta(meta); }; - if (MinecraftVersion.MAJOR >= 12) { + if ((MinecraftVersion.MAJOR >= 12 && MinecraftVersion.MAJOR < 17) || MinecraftVersion.MAJOR >= 20) { lc.getWorld().spawn(lc, Firework.class, fw -> fwConsumer.accept(fw)); - // much better to use the built-in since 1.12 method to do operations on entity - // before it is sent to the players, as it will not create flickering + // Much better to use the built-in since 1.12 method to do operations on entity + // before it is sent to the players, as it will not create flickering. + // From 1.17.1 to 1.19.4, the method was moved from World to RegionAccessor. } else { fwConsumer.accept(lc.getWorld().spawn(lc, Firework.class)); } diff --git a/core/src/main/java/fr/skytasul/quests/utils/nms/NMS.java b/core/src/main/java/fr/skytasul/quests/utils/nms/NMS.java index e7f568ac..79de5af2 100644 --- a/core/src/main/java/fr/skytasul/quests/utils/nms/NMS.java +++ b/core/src/main/java/fr/skytasul/quests/utils/nms/NMS.java @@ -1,25 +1,27 @@ package fr.skytasul.quests.utils.nms; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.List; -import java.util.Map; +import fr.skytasul.quests.BeautyQuests; +import fr.skytasul.quests.api.QuestsPlugin; +import fr.skytasul.quests.api.utils.MinecraftVersion; +import fr.skytasul.quests.utils.ReflectUtils; +import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.inventory.meta.ItemMeta; -import fr.skytasul.quests.api.QuestsPlugin; -import fr.skytasul.quests.api.utils.MinecraftVersion; -import fr.skytasul.quests.utils.ReflectUtils; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.List; +import java.util.Map; public abstract class NMS{ - + private ReflectUtils nmsReflect = ReflectUtils.fromPackage("net.minecraft.server." + getClass().getSimpleName()); private ReflectUtils craftReflect = ReflectUtils.fromPackage("org.bukkit.craftbukkit." + getClass().getSimpleName()); - + private Field unhandledTags; private Method equalsCommon; - + public NMS() { if (!(this instanceof NullNMS)) { try { @@ -33,61 +35,70 @@ public NMS() { } } } - + public abstract double entityNameplateHeight(Entity en); // can be remplaced by Entity.getHeight from 1.11 - + public List getAvailableBlockProperties(Material material){ throw new UnsupportedOperationException(); } - + public List getAvailableBlockTags() { throw new UnsupportedOperationException(); } - + public boolean equalsWithoutNBT(ItemMeta meta1, ItemMeta meta2) throws ReflectiveOperationException { ((Map) unhandledTags.get(meta1)).clear(); ((Map) unhandledTags.get(meta2)).clear(); return (boolean) equalsCommon.invoke(meta1, meta2); } - + public ReflectUtils getNMSReflect(){ return nmsReflect; } - + public ReflectUtils getCraftReflect(){ return craftReflect; } - + public abstract void openBookInHand(Player p); - + public static NMS getNMS() { return nms; } - + public static boolean isValid() { return versionValid; } - + private static boolean versionValid = false; private static NMS nms; - + static { + String versionNms; + + if (!BeautyQuests.getInstance().isRunningPaper() || !MinecraftVersion.isHigherThan(20, 5)) { + versionNms = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3].substring(1); + } else { + versionNms = "1_20_R4"; + // TODO: find better way + } + try { - nms = (NMS) Class.forName("fr.skytasul.quests.utils.nms.v" + MinecraftVersion.VERSION_NMS).newInstance(); + nms = (NMS) Class.forName("fr.skytasul.quests.utils.nms.v" + versionNms).newInstance(); versionValid = true; QuestsPlugin.getPlugin().getLoggerExpanded() - .info("Loaded valid Minecraft version " + MinecraftVersion.VERSION_NMS + "."); + .info("Loaded valid Minecraft version " + versionNms + "."); }catch (ClassNotFoundException ex) { QuestsPlugin.getPlugin().getLoggerExpanded() - .warning("The Minecraft version " + MinecraftVersion.VERSION_NMS + " is not supported by BeautyQuests."); + .warning("The Minecraft version " + versionNms + " is not supported by BeautyQuests."); }catch (Exception ex) { QuestsPlugin.getPlugin().getLoggerExpanded().warning("An error ocurred when loading Minecraft Server version " - + MinecraftVersion.VERSION_NMS + " compatibilities.", ex); + + versionNms + " compatibilities.", ex); } if (!versionValid) { nms = new NullNMS(); QuestsPlugin.getPlugin().getLoggerExpanded().warning("Some functionnalities of the plugin have not been enabled."); } } - + } diff --git a/core/src/main/java/fr/skytasul/quests/utils/types/DialogRunnerImplementation.java b/core/src/main/java/fr/skytasul/quests/utils/types/DialogRunnerImplementation.java index d5c80c84..9ae96d37 100644 --- a/core/src/main/java/fr/skytasul/quests/utils/types/DialogRunnerImplementation.java +++ b/core/src/main/java/fr/skytasul/quests/utils/types/DialogRunnerImplementation.java @@ -10,6 +10,7 @@ import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitTask; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import fr.skytasul.quests.BeautyQuests; import fr.skytasul.quests.api.QuestsConfiguration; import fr.skytasul.quests.api.QuestsPlugin; @@ -24,8 +25,8 @@ public class DialogRunnerImplementation implements DialogRunner { - private final Dialog dialog; - private final BqNpc npc; + private final @Nullable Dialog dialog; + private final @Nullable BqNpc npc; private List> tests = new ArrayList<>(); private List> testsCancelling = new ArrayList<>(); @@ -34,11 +35,19 @@ public class DialogRunnerImplementation implements DialogRunner { private Map players = new HashMap<>(); private Boolean navigationInitiallyPaused = null; - public DialogRunnerImplementation(Dialog dialog, BqNpc npc) { + public DialogRunnerImplementation(@Nullable Dialog dialog, @Nullable BqNpc npc) { this.dialog = dialog; this.npc = npc; } + public @Nullable BqNpc getNpc() { + return npc; + } + + public @Nullable Dialog getDialog() { + return dialog; + } + @Override public void addTest(Predicate test) { tests.add(test); diff --git a/core/src/main/resources/config.yml b/core/src/main/resources/config.yml index 69be671d..17f3466a 100644 --- a/core/src/main/resources/config.yml +++ b/core/src/main/resources/config.yml @@ -204,7 +204,7 @@ questDescription: # Particles shown on a NPC when the player can start the quest start: enabled: true - particleEffect: redstone + particleEffect: dust particleColor: RED: 255 BLUE: 0 @@ -213,7 +213,7 @@ start: # Particles shown on the NPC to which the player has to talk talk: enabled: true - particleEffect: villager_happy + particleEffect: happy_villager particleColor: RED: 255 BLUE: 0 @@ -222,7 +222,7 @@ talk: # Particles shown when the player finish a stage of a quest next: enabled: true - particleEffect: smoke_normal + particleEffect: smoke particleColor: RED: 255 BLUE: 0 diff --git a/core/src/main/resources/locales/cs_CZ.yml b/core/src/main/resources/locales/cs_CZ.yml index 2b0a42bd..9a50b5f3 100755 --- a/core/src/main/resources/locales/cs_CZ.yml +++ b/core/src/main/resources/locales/cs_CZ.yml @@ -1,51 +1,112 @@ --- -inv: - create: - bringBack: '§aPřinést zpět předměty' - bucket: '§aVyplnit kbelíky' - craft: '§aVyrobit předmět' - findNPC: '§aNajít NPC' - findRegion: '§aNajít region' - fish: '§aChytat ryby' - killMobs: '§aZabít monstra' - mineBlocks: '§aRozbít bloky' - placeBlocks: '§aPostav bloky' - talkChat: '§aPsát do chatu' msg: + quest: + finished: + base: '§aBlahopřejeme! Dokončil jsi svůj úkol §e{quest_name}§a!' + obtain: '§aObdržel jsi {rewards}!' + started: '§aTvůj úkol právě začíná §r§e{quest_name}§o§6!' + created: '§aBlahopřejeme! Vytvořil jsi nový úkol §e{quest}§a, který obsahuje {quest_branches} větev(e)!' + edited: '§aBlahopřejeme! Upravil jsi úkol §e{quest}§a, který obsahuje nyní {quest_branches} větev(e)!' + createCancelled: '§cVytváření nebo úprava úkolu byla přerušena jiným pluginem!' + cancelling: '§cProces vytváření úkolu byl zrušen.' + editCancelling: '§cProces úpravy úkolu byl zrušen.' + invalidID: '§cÚkol s ID {quest_id} neexistuje.' + invalidPoolID: '§cPool {pool_id} neexistuje' + alreadyStarted: '§cTvůj úkol byl už zahájen!' + notStarted: '§cMomentálně neděláš tento úkol.' + quests: + maxLaunched: '§cNemůžeš mít více než {quests_max_amount} úkol zároveň...' + updated: '§7Úkol §e{quest_name}§7 a jeho nastavení bylo aktualizováno.' + checkpoint: '§7Dosáhl jsi kontrolního bodu úkolu!' + failed: '§cSelhal jsi v plnění úkolu {quest_name}' + pools: + noTime: '§cMusíš počkat {time_left} než budeš dělat jiný úkol.' + allCompleted: '§7Všechny úkoly byly dokončeny!' + noAvailable: '§7Žádný další úkol není k dispozici...' + maxQuests: '§cNemůžeš mít zároveň více než {pool_max_quests} úkol(ů)...' + questItem: + drop: '§cPředmět, který je součástí tvého úkolu, není možné zahodit!' + craft: '§cNemůžeš použít item z úkolu k výrobě!' + eat: '§cNemůžeš sníst úkolový předmět!' + stageMobs: + listMobs: '§aMusíš zabít {mobs}' + writeNPCText: '§aNapiš dialog který NPC řekně hráči: (Napiš "help" pro získání pomoci)' + writeRegionName: '§aNapiš název regionu vyžadovaného pro krok:' + writeXPGain: '§aNapiš množství bodů zkušenosti, které hráč získá: (poslední hodnota: {xp_amount})' + writeMobAmount: '§aNapiš počet mobů, k zabíjení:' + writeMobName: '§aNapiš vlastní jméno moba, kterého budeš zabíjet:' + writeChatMessage: '§aNapište požadovanou zprávu: (Přidejte "\{SLASH}" na začátek, pokud chcete příkaz.)' + writeMessage: '§aNapiš zprávu, která bude odeslána hráči' + writeStartMessage: '§aNapište zprávu, která bude odeslána na začátku úkolu, „null“, pokud chcete výchozí, nebo „none“, pokud nechcete žádnou:' + writeEndMsg: '§aNapište zprávu, která bude odeslána na konci úkolu, "null", pokud chcete výchozí nebo "none", pokud nechcete žádnou. Můžete použít "\{rewards}", které bude nahrazeno získanými odměnami.' + writeEndSound: '§aNapiš název zvuku, který bude na konci úkolu přehrán hráči, "null", pokud chcete výchozí nebo "none", pokud nechcete žádný:' + writeDescriptionText: '§aNapiš text, který popisuje cíl fáze:' + writeStageText: '§aNapiš text, který bude odeslán hráči na začátku kroku:' + moveToTeleportPoint: '§aJdi na místo určení teleportu.' + writeNpcName: '§aNapiš jméno NPC:' + writeNpcSkinName: '§aNapiš jméno skinu, který má být použit na NPC:' + writeQuestName: '§aNapiš jméno úkolu:' + writeCommand: '§aNapište požadovaný příkaz: (Příkaz je bez "/" a zástupného "{player}" je podporován. Bude nahrazen jménem vykonavatele.)' + writeHologramText: '§aNapište text hologramu: (Napište „none“, pokud nechcete hologram, a „null“, pokud chcete výchozí text.)' + writeQuestTimer: '§aNapište požadovaný čas (v minutách), než budete moci úlohu znovu spustit: (Pokud chcete výchozí časovač, napište „null“.)' + writeConfirmMessage: '§aNapiš potvrzovací zprávu zobrazenou když se hráč chystá spustit úkol: (Write "null", pokud chceš výchozí zprávu.)' + writeQuestDescription: '§aNapiš popis úkolu, který bude zobrazen v GUI úkolu hráče.' + writeQuestMaterial: '§aNapiš jméno materiálu pro předmět úkolu.' + requirements: + quest: '§cMusíš dokončit Quest §e{quest_name}§c!' + level: '§cTvůj level musí být {long_level}!' + job: '§cTvá úroveň pro úkol §e{job_name}§c musí být {long_level}!' + skill: '§cTvá úroveň pro dovednost §e{skill_name}§c musí být {long_level}!' + combatLevel: '§cTvoje bojová úroveň musí být {long_level}!' + money: '§cMusíš mít {money}!' + waitTime: '§cMusis počkat {time_left} , než budeš moci restartovat tento úkol!' + experience: + edited: '§aZměnil jsi zisk z {old_xp_amount} na {xp_amount} bodů.' + selectNPCToKill: '§aVyberte NPC pro zabíjení.' + regionDoesntExists: '§cTento region neexistuje. (Musíš být ve stejném světě.)' + npcDoesntExist: '§cNPC s ID {npc_id} neexistuje.' + number: + negative: '§cMusíš zadat kladné číslo!' + zero: '§cMusíte zadat jiné číslo než 0!' + invalid: '§c{input} není platné číslo.' + notInBounds: '§cVaše číslo musí být mezi {min} a {max}.' + errorOccurred: '§cDošlo k chybě, obraťte se na adminstrátor! §4§lChybový kód: {error}' + indexOutOfBounds: '§cČíslo {index} je mimo hranice! Musí být mezi {min} a {max}.' + invalidBlockData: '§cBlokdata {block_data}jsou neplatné nebo nekompatibilní s blokem {block_material}.' + invalidBlockTag: '§cNedostupný tag bloku {block_tag}.' bringBackObjects: Přineste mě zpět {items}. + inventoryFull: '§cTvůj inventář je plný, předmět byl vyhozen na zem.' + versionRequired: 'Vyžadována verze: §l{version}' + restartServer: '§7Pro zobrazení úprav restartujte váš server.' + dialogs: + skipped: '§8§o Dialog přeskočen.' + tooFar: '§7§oJsi příliš daleko od {npc_name}...' command: - adminModeEntered: '§aSpustil jsi režim správce.' - adminModeLeft: '§aOpustil jsi režim správce.' - backupCreated: '§6Úspěšně jsi vytvořil zálohy všech úkolů a informací o hráči.' - backupPlayersFailed: '§cVytváření zálohy pro všechny hráčské informace se nezdařilo.' - backupQuestsFailed: '§cVytváření zálohy pro všechny úkoly se nezdařilo.' - cancelQuest: '§6Zrušil jsi úkol {quest}.' - cancelQuestUnavailable: '§cQuest {quest} nemůže být zrušen.' + downloadTranslations: + syntax: '§cMusíte zadat jazyk ke stažení. Příklad: "/quests downloadTranslations en_US".' + notFound: '§cJazyk {lang} nebyl nalezen pro verzi {version}.' + exists: '§cSoubor {file_name} již existuje. Připojte "-overwrite" k vašemu příkazu k jeho přepsání. (/quests downloadTranslations -overwrite)' + downloaded: '§aJazyk {lang} byl stažen! §7Nyní musíte upravit soubor "/plugins/BeautyQuests/config.yml" pro změnu hodnoty §ominecraftTranslationsFile§7 s {lang}, poté restartovat server.' checkpoint: noCheckpoint: '§cNebyl nalezen žádný kontrolní bod pro úkol {quest}.' questNotStarted: '§cTento úkol aktuálně neděláš.' - help: - adminMode: '§6/{label} adminMod: §ePřepni režim správce. (Pouze pro zobrazení malých zpráv v logech.)' - create: '§6/{label} vytvořit: §eVytvoř úkol.' - edit: '§6/{label} editace: §eEdituj úkol.' - finishAll: '§6/{label} dokončil všechny : §eDokonči všechny questy hráče.' - header: '§6§lBeautyQuests — Nápověda' - list: '§6/{label} seznam: §ePodívejte se na seznam úkolů. (Pouze pro podporované verze)' - remove: '§6/{label} remove : §eVymazat úkol se zadaným id nebo kliknout na NPC pokud není definováno.' - resetPlayer: '§6/{label} resetPlayer : §eOdstraňte všechny informace o hráči.' - resetPlayerQuest: '§6/{label} resetPlayerQuest [id]: §eVymazat informace o hledání pro hráče.' - save: '§6/{label} save: §eVytvoří manuální uložení pluginu.' - seePlayer: '§6/{label} seePlayer : §eZobrazit informace o hráči.' - setItem: '§6/{label} setItem : §eSave položku hologramu.' - setStage: '§6/{label} setStage [new branch] [new stage]: §ePřeskočit aktuální scénu/spustit větev/nastavit scénu pro větev.' - start: '§6/{label} start [id]: §eVynutit spuštění úkolu.' - version: '§6/{label} verze: §ePodívejte se na aktuální verzi pluginu.' + setStage: + branchDoesntExist: '§cVětev s ID {branch_id} neexistuje.' + doesntExist: '§cStage s ID {stage_id} neexistuje.' + next: '§aFáze byla přeskočena.' + nextUnavailable: '§cMožnost "přeskočit" není k dispozici, když je hráč na konci větve.' + set: '§aFáze {stage_id} byla spuštěna.' + startDialog: + impossible: '§cDialog teď nelze spustit' + noDialog: '§cHráč nemá žádný čekající dialog.' + alreadyIn: '§cHráč již přehrává dialog.' + success: '§aZahájen dialog pro hráče {player} v úkolu {quest}!' invalidCommand: simple: '§cTento příkaz neexistuje, napište §ehelp§c.' itemChanged: '§aPředmět byl upraven. Změny se projeví po restartu.' itemRemoved: '§aHologramový předmět byl odstraněn.' - leaveAll: '§aVynutil jsi konec {success} úkolů. Chyby: {errors}' removed: '§aQuest {quest_name} byl úspěšně odstraněn.' + leaveAll: '§aVynutil jsi konec {success} úkolů. Chyby: {errors}' resetPlayer: player: '§6Všechny informace o tvých {quest_amount} úkol(ech) byly smazány hráčem {deleter_name}.' remover: '§6{quest_amount} informace o úkolu {player} byla smazány.' @@ -53,126 +114,455 @@ msg: player: '§6Všechny informace o výpravě {quest} byly smazány hráčem {deleter_name}.' remover: '§6{player} informace o úkolu {quest} byla smazány.' resetQuest: '§6Odstraněna data hledání pro {player_amount} hráčů.' + startQuest: '§6Vynutili jste spuštění úkolu {quest} pro {player}.' + startQuestNoRequirements: '§cHráč nesplňuje požadavky pro quest {quest}... Připojte "-overrideRequirements" na konec vašeho příkazu, aby obešel kontrolu požadavků.' + cancelQuest: '§6Zrušil jsi úkol {quest}.' + cancelQuestUnavailable: '§cQuest {quest} nemůže být zrušen.' + backupCreated: '§6Úspěšně jsi vytvořil zálohy všech úkolů a informací o hráči.' + backupPlayersFailed: '§cVytváření zálohy pro všechny hráčské informace se nezdařilo.' + backupQuestsFailed: '§cVytváření zálohy pro všechny úkoly se nezdařilo.' + adminModeEntered: '§aSpustil jsi režim správce.' + adminModeLeft: '§aOpustil jsi režim správce.' + resetPlayerPool: + timer: '§aResetoval jsi časovač poolu {pool} pro {player}.' + full: '§aResetovali jste data poolu {pool} pro {player}.' + startPlayerPool: + error: 'Nepodařilo se spustit pool {pool} pro {player}.' + success: 'Pool {pool} začal pro {player} Výsledek: {result}' scoreboard: - hidden: '§6Scoreboard hráče {player_name} byl schován.' - lineInexistant: '§cŘádek {line_id} neexistuje.' - lineRemoved: '§6Úspěšně jsi odstranil řádek {line_id}.' - lineReset: '§6Úspěšně jsi resetoval řádek {line_id}.' lineSet: '§6Řádek {line_id} byl úspěšně upraven.' + lineReset: '§6Úspěšně jsi resetoval řádek {line_id}.' + lineRemoved: '§6Úspěšně jsi odstranil řádek {line_id}.' + lineInexistant: '§cŘádek {line_id} neexistuje.' resetAll: '§6Úspěšně jsi obnovil tabulku skóre hráče {player_name}.' + hidden: '§6Scoreboard hráče {player_name} byl schován.' shown: '§6Scoreboard hráče {player_name} byl zobrazen.' - setStage: - branchDoesntExist: '§cVětev s ID {branch_id} neexistuje.' - doesntExist: '§cStage s ID {stage_id} neexistuje.' - next: '§aFáze byla přeskočena.' - nextUnavailable: '§cMožnost "přeskočit" není k dispozici, když je hráč na konci větve.' - set: '§aFáze {stage_id} byla spuštěna.' - startQuest: '§6Vynutil jsi spuštění Questu {quest} (UUID: {player}).' + own: + hidden: '§6Tvá tabulka questů je nyní skryta.' + shown: '§6Tvá tabulka questů je znovu zobrazena.' + help: + header: '§6§lBeautyQuests — Nápověda' + create: '§6/{label} vytvořit: §eVytvoř úkol.' + edit: '§6/{label} editace: §eEdituj úkol.' + remove: '§6/{label} remove : §eVymazat úkol se zadaným id nebo kliknout na NPC pokud není definováno.' + finishAll: '§6/{label} dokončil všechny : §eDokonči všechny questy hráče.' + setStage: '§6/{label} setStage [new branch] [new stage]: §ePřeskočit aktuální scénu/spustit větev/nastavit scénu pro větev.' + startDialog: '§6/{label} startDialog : §eZačne čekající dialog pro fázi NPC nebo úvodní dialog pro quest.' + resetPlayer: '§6/{label} resetPlayer : §eOdstraňte všechny informace o hráči.' + resetPlayerQuest: '§6/{label} resetPlayerQuest [id]: §eVymazat informace o hledání pro hráče.' + seePlayer: '§6/{label} seePlayer : §eZobrazit informace o hráči.' + reload: '§6/{label} reload: §eUloží a znovu načte konfiguraci a soubory. (§cdeprecated§e)' + start: '§6/{label} start [id]: §eVynutit spuštění úkolu.' + setItem: '§6/{label} setItem : §eSave položku hologramu.' + setFirework: '§6/{label} setFirework: §eUpraví výchozí končící ohňostroj' + adminMode: '§6/{label} adminMod: §ePřepni režim správce. (Pouze pro zobrazení malých zpráv v logech.)' + version: '§6/{label} verze: §ePodívejte se na aktuální verzi pluginu.' + downloadTranslations: '§6/{label} downloadTranslations : §eStáhne vanilla soubor překladu' + save: '§6/{label} save: §eVytvoří manuální uložení pluginu.' + list: '§6/{label} seznam: §ePodívejte se na seznam úkolů. (Pouze pro podporované verze)' + typeCancel: '§aNapište "cancel" pro návrat k poslednímu textu.' editor: - already: '§cJiž jsi v editoru.' blockAmount: '§aNapiš množství bloků:' - blockData: '§aNapište bloková data (dostupná bloková data: {available_datas}):' blockName: '§aNapište název bloku:' - dialog: - cleared: '§a{amount} odstranilo zprávy.' - help: - header: '§6§lBeautyQuests - nápověda pro editor dialogů' - list: '§6Seznam: §evšech zpráv.' - remove: '§6remove : §eOdebrat zprávu.' - syntaxRemove: '§cSprávná sytax: odstranit ' + blockData: '§aNapište bloková data (dostupná bloková data: {available_datas}):' + blockTag: '§aNapište tag bloku (dostupné tagy: §7{available_tags}§a):' + typeBucketAmount: '§aNapiš množství kbelíků k naplnění:' + typeDamageAmount: 'Napište množství poškození, které musí hráč udělit:' + goToLocation: '§aPřejít na požadovanou polohu pro stage.' + typeLocationRadius: '§aNapsat požadovanou vzdálenost od polohy:' + typeGameTicks: '§aNapište požadované herní ticks' + already: '§cJiž jsi v editoru.' + stage: + location: + typeWorldPattern: '§aNapište regex pro jména světů:' enter: - subtitle: '§6Napiš "/quests exitEditor" pro vynucení ukončení editoru.' title: '§6~ Mód editoru ~' - goToLocation: '§aPřejít na požadovanou polohu pro stage.' - itemCreator: - invalidBlockType: '§cNeplatný typ bloku.' - itemName: '§aNapiš název předmětu:' - unknownBlockType: '§cNeznámý typ bloku.' - unknownItemType: '§cNeznámý typ předmětu.' - mythicmobs: - disabled: '§cMythicMobs jsou vypnuty.' + subtitle: '§6Napiš "/quests exitEditor" pro vynucení ukončení editoru.' + list: '§c⚠ §7Zadali jste editor "seznamu". Použij "add" pro přidání řádků. Použijte "help" (bez lomítka) pro nápovědu. §e§lNapište "close" pro zavření editoru.' + chat: '§6Momentálně jste v režimu editoru. Napište "/quests exitEditor" pro vynucení opuštění editoru. (Zcela nedoporučujeme, zvažte použití příkazů jako "close" nebo "cancel" pro návrat k předchozímu GUI.)' npc: - choseStarter: '§aVyberte NPC u kterého začíná Quest.' enter: '§aKlikni na NPC, nebo napiš "cancel".' + choseStarter: '§aVyberte NPC u kterého začíná Quest.' notStarter: '§cU tohoto NPC quest nezačíná.' text: argNotSupported: '§cArgument {arg} není podporován.' - chooseJobRequired: '§aNapiš jméno požadované práce:' chooseLvlRequired: '§aNapiš požadované množství úrovní:' + chooseJobRequired: '§aNapiš jméno požadované práce:' + choosePermissionRequired: '§aNapište požadované oprávnění pro spuštění úkolu:' + choosePermissionMessage: '§aMůžete zvolit zprávu odmítnutí, pokud hráč nemá požadované oprávnění. (Pro přeskočení tohoto kroku napište "null".)' + choosePlaceholderRequired: + identifier: '§aNapiš název požadovaného zástupce bez znaku procenta:' + value: '§aNapište požadovanou hodnotu pro zástupce §e%§e{placeholder}§e%§a:' + chooseSkillRequired: '§aNapište název požadované dovednosti:' chooseMoneyRequired: '§aNapište částku požadovaných peněz:' - chooseObjectiveRequired: '§aNapiš název objektu.' reward: permissionName: '§aNapiš jméno oprávnění.' + permissionWorld: '§aNapiš svět, ve kterém bude oprávnění upraveno, nebo "null", pokud to chcete globálně.' + money: '§aNapište částku obdržených peněz:' + wait: '§aNapište dobu čekání herních ticků (1 sekunda = 20 ticků)' + random: + min: '§aNapište minimální odměnu která bude udělena hráči (včetně).' + max: '§aNapište maximální odměnu která bude udělena hráči (včetně).' + chooseObjectiveRequired: '§aNapiš název objektu.' + chooseObjectiveTargetScore: '§aNapište cílové skóre pro daný cíl.' + itemCreator: + itemName: '§aNapiš název předmětu:' + unknownItemType: '§cNeznámý typ předmětu.' + unknownBlockType: '§cNeznámý typ bloku.' + invalidBlockType: '§cNeplatný typ bloku.' + dialog: + syntaxRemove: '§cSprávná sytax: odstranit ' + cleared: '§a{amount} odstranilo zprávy.' + help: + header: '§6§lBeautyQuests - nápověda pro editor dialogů' + remove: '§6remove : §eOdebrat zprávu.' + list: '§6Seznam: §evšech zpráv.' + mythicmobs: + disabled: '§cMythicMobs jsou vypnuty.' textList: syntax: '§cSprávná syntaxe: ' - typeBucketAmount: '§aNapiš množství kbelíků k naplnění:' - typeGameTicks: '§aNapište požadované herní ticks' - typeLocationRadius: '§aNapsat požadovanou vzdálenost od polohy:' - errorOccurred: '§cDošlo k chybě, obraťte se na adminstrátor! §4§lChybový kód: {error}' - experience: - edited: '§aZměnil jsi zisk z {old_xp_amount} na {xp_amount} bodů.' - indexOutOfBounds: '§cČíslo {index} je mimo hranice! Musí být mezi {min} a {max}.' - invalidBlockData: '§cBlokdata {block_data}jsou neplatné nebo nekompatibilní s blokem {block_material}.' - inventoryFull: '§cTvůj inventář je plný, předmět byl vyhozen na zem.' - moveToTeleportPoint: '§aJdi na místo určení teleportu.' - npcDoesntExist: '§cNPC s ID {npc_id} neexistuje.' - number: - invalid: '§c{input} není platné číslo.' - negative: '§cMusíš zadat kladné číslo!' - zero: '§cMusíte zadat jiné číslo než 0!' - pools: - allCompleted: '§7Všechny úkoly byly dokončeny!' - maxQuests: '§cNemůžeš mít zároveň více než {pool_max_quests} úkol(ů)...' - noAvailable: '§7Žádný další úkol není k dispozici...' - noTime: '§cMusíš počkat {time_left} než budeš dělat jiný úkol.' - quest: - alreadyStarted: '§cTvůj úkol byl už zahájen!' - cancelling: '§cProces vytváření úkolu byl zrušen.' - createCancelled: '§cVytváření nebo úprava úkolu byla přerušena jiným pluginem!' - created: '§aBlahopřejeme! Vytvořil jsi nový úkol §e{quest}§a, který obsahuje {quest_branches} větev(e)!' - editCancelling: '§cProces úpravy úkolu byl zrušen.' - edited: '§aBlahopřejeme! Upravil jsi úkol §e{quest}§a, který obsahuje nyní {quest_branches} větev(e)!' - finished: - base: '§aBlahopřejeme! Dokončil jsi svůj úkol §e{quest_name}§a!' - obtain: '§aObdržel jsi {rewards}!' - invalidID: '§cÚkol s ID {quest_id} neexistuje.' - started: '§aTvůj úkol právě začíná §r§e{quest_name}§o§6!' - questItem: - craft: '§cNemůžeš použít item z úkolu k výrobě!' - drop: '§cPředmět, který je součástí tvého úkolu, není možné zahodit!' - quests: - checkpoint: '§7Dosáhl jsi kontrolního bodu úkolu!' - failed: '§cSelhal jsi v plnění úkolu {quest_name}' - maxLaunched: '§cNemůžeš mít více než {quests_max_amount} úkol zároveň...' - updated: '§7Úkol §e{quest_name}§7 a jeho nastavení bylo aktualizováno.' - regionDoesntExists: '§cTento region neexistuje. (Musíš být ve stejném světě.)' - requirements: - combatLevel: '§cTvoje bojová úroveň musí být {long_level}!' - job: '§cTvá úroveň pro úkol §e{job_name}§c musí být {long_level}!' - level: '§cTvůj level musí být {long_level}!' - money: '§cMusíš mít {money}!' - quest: '§cMusíš dokončit Quest §e{quest_name}§c!' - skill: '§cTvá úroveň pro dovednost §e{skill_name}§c musí být {long_level}!' - waitTime: '§cMusis počkat {time_left} , než budeš moci restartovat tento úkol!' - selectNPCToKill: '§aVyberte NPC pro zabíjení.' - stageMobs: - listMobs: '§aMusíš zabít {mobs}' - typeCancel: '§aNapište "cancel" pro návrat k poslednímu textu.' - writeChatMessage: '§aNapiš povinnou zprávu: (Přidat "{SLASH}na začátek, pokud chceš příkaz.)' - writeCommand: '§aNapište požadovaný příkaz: (Příkaz je bez "/" a zástupného znaku "{PLAYER}je podporován. Bude nahrazeno jménem vykonavatele.)' - writeConfirmMessage: '§aNapiš potvrzovací zprávu zobrazenou když se hráč chystá spustit úkol: (Write "null", pokud chceš výchozí zprávu.)' - writeDescriptionText: '§aNapiš text, který popisuje cíl fáze:' - writeHologramText: '§aNapište text hologramu: (Napište „none“, pokud nechcete hologram, a „null“, pokud chcete výchozí text.)' - writeMobAmount: '§aNapiš počet mobů, k zabíjení:' - writeMobName: '§aNapiš vlastní jméno moba, kterého budeš zabíjet:' - writeNPCText: '§aNapiš dialog který NPC řekně hráči: (Napiš "help" pro získání pomoci)' - writeNpcName: '§aNapiš jméno NPC:' - writeNpcSkinName: '§aNapiš jméno skinu, který má být použit na NPC:' - writeQuestDescription: '§aNapiš popis úkolu, který bude zobrazen v GUI úkolu hráče.' - writeQuestMaterial: '§aNapiš jméno materiálu pro předmět úkolu.' - writeQuestName: '§aNapiš jméno úkolu:' - writeQuestTimer: '§aNapište požadovaný čas (v minutách), než budete moci úlohu znovu spustit: (Pokud chcete výchozí časovač, napište „null“.)' - writeRegionName: '§aNapiš název regionu vyžadovaného pro krok:' - writeStageText: '§aNapiš text, který bude odeslán hráči na začátku kroku:' - writeStartMessage: '§aNapište zprávu, která bude odeslána na začátku úkolu, „null“, pokud chcete výchozí, nebo „none“, pokud nechcete žádnou:' - writeXPGain: '§aNapiš množství bodů zkušenosti, které hráč získá: (poslední hodnota: {xp_amount})' + writeCommandDelay: '§aNapište požadované zpoždění příkazu v tikách.' +advancement: + notStarted: Není spuštěno! +inv: + validate: '§bValidovat' + cancel: '§c§lStorno' + addObject: Přidat objekt + confirm: + name: Jste si jistý? + 'yes': '§aPotvrdit' + 'no': '§cZrušit' + create: + findNPC: '§aNajít NPC' + bringBack: '§aPřinést zpět předměty' + findRegion: '§aNajít region' + killMobs: '§aZabít monstra' + mineBlocks: '§aRozbít bloky' + placeBlocks: '§aPostav bloky' + talkChat: '§aPsát do chatu' + fish: '§aChytat ryby' + craft: '§aVyrobit předmět' + bucket: '§aVyplnit kbelíky' + selectRegion: '§7Vyberte region' + toggleRegionExit: Při odchodu + stageStartMsg: '§eUpravit úvodní zprávu' + selectBlockLocation: '§eVybrat umístění bloku' + selectBlockMaterial: '§eVyberte blok materiálu' + leftClick: Kliknutí musí být levým tlačítkem + editFishes: '§eUpravte ryby k chytání' + editItemsToMelt: '§eUpravte předměty pro tání' + editItemsToEnchant: '§eUpravte předměty k zaklínání' + editItem: '§eUpravte předměty pro tání' + editBucketType: '§eUpravte typ kbelku k vyplnění' + editBucketAmount: '§eUpravte typ kbelku k vyplnění' + editLocation: '§eUpravit polohu' + editRadius: '§eUpravit vzdálenost od polohy' + currentRadius: '§eAktuální vzdálenost: §6{radius}' + changeTicksRequired: '§eJe vyžadována změna přehraných ticků' + changeEntityType: '§eZměnit typ entity' + stage: + location: + worldPattern: '§aNastavte vzor názvu světa §d(ADVANCED)' + worldPatternLore: 'Pokud chcete, aby byla fáze dokončena pro kterýkoliv svět odpovídající určitému vzoru, zadejte zde regex (regulární výraz).' + death: + causes: '§aNastavte příčiny smrti §d(ADVANCED)' + anyCause: Jakákoli příčina smrti + setCauses: 'Příčiny úmrtí {causes_amount}' + dealDamage: + damage: '§ePoškození k obchodu' + targetMobs: '§cZranit stvoření' + eatDrink: + items: '§eUpravte předměty pro jídlo nebo pití' + playTime: + changeTimeMode: 'Změnit strategii počítání času' + modes: + online: 'Přehrávač musí být připojen k serveru' + offline: 'Přehrávač může být offline, ale server musí být spuštěn, aby mohl počítat čas' + realtime: 'Čas se počítá i v případě, že hráč a server jsou offline' + stages: + name: Vytvořit fáze + nextPage: '§eDalší stránka' + laterPage: '§ePředchozí stránka' + endingItem: '§eUpravit koncové odměny' + descriptionTextItem: '§eUpravit popis' + regularPage: '§aPravidelné fáze' + branchesPage: '§dVětev' + previousBranch: '§eZpět do předchozí větve' + newBranch: '§ePřejít na novou větev' + validationRequirements: '§eOvěřovací požadavky' + validationRequirementsLore: Všechny požadavky musí odpovídat hráči, který se pokouší dokončit fázi. Pokud ne, fáze nemůže být dokončena. + details: + hologramLaunch: '§eUpravit hologram položky "spustit"' + hologramLaunchLore: Hologram zobrazený nad hlavou Startovní NPC, když hráč může začít úkol. + hologramLaunchNo: '§eUpravit hologram položky "spustit"' + hologramLaunchNoLore: Hologram zobrazený nad hlavou Startovní NPC, když hráč může začít úkol. + customConfirmMessage: '§eUpravit potvrzovací zprávu úkolu' + customConfirmMessageLore: Zpráva zobrazená v GUI potvrzení, když se hráč chystá zahájit úkol. + customDescription: '§eUpravit popis' + customDescriptionLore: Popis zobrazený níže v názvu výpravy v GUI. + name: Detaily poslední výpravy + multipleTime: + itemName: Přepnout opakovatelné + requirements: '{amount} požadavky(y)' + rewards: '{amount} odměna(y)' + actions: '{amount} akce' + rewardsLore: Akce provedené při ukončení úkolu. + customMaterial: '§eUpravit materiál úkolu' + customMaterialLore: Položka zástupce tohoto úkolu v nabídce úkolů. + failOnDeath: Selhání při smrti + failOnDeathLore: Bude výprava zrušena, až hráč naftu? + questPool: '§eÚkolový bazén' + questPoolLore: Připojit tento úkol k úložišti + firework: '§dKonec ohňostroje' + fireworkLore: Ohňostroj spuštěn, když hráč dokončí hledání + fireworkLoreDrop: Sem přetáhněte vlastní ohňostroj + visibility: '§bViditelnost úkolu' + visibilityLore: Zvolte, ve kterých kartách menu se zobrazí výprava, a pokud je výprava viditelná na dynamických mapách. + keepDatas: Zachovat data hráčů + keepDatasLore: |- + Vynutit uchování dat hráčů, i když fáze byly upraveny. + §c§lWARNING §c- povolení této možnosti může poškodit data hráčů. + loreReset: '§ePokrok všech hráčů bude obnoven' + optionValue: '§8Hodnocení: §7{value}' + defaultValue: '§8(výchozí hodnota)' + requiredParameter: '§7Povinný parametr' + itemsSelect: + name: Upravit položku + none: |- + §aPřesuňte předmět sem nebo + klikněte pro otevření editoru položek. + itemSelect: + name: Vyberte položky + npcCreate: + name: Vytvořit NPC + setName: '§eUpravit název NPC' + setSkin: '§eUpravit název NPC' + setType: '§eUpravit název NPC' + move: + itemName: '§ePřesunout' + itemLore: '§aZměň umístění NPC.' + moveItem: '§a§lOvěřit místo' + npcSelect: + name: Vybrat nebo vytvořit? + selectStageNPC: '§eVybrat existující NPC' + createStageNPC: '§Vytvořit NPC' + entityType: + name: eZměnit typ entity + chooseQuest: + name: Který úkol? + menu: '§aQuests Menu' + menuLore: Vrátí tě do nabídky úkolů. + mobs: + name: Vybrat stvoření + none: '§aKlepnutím přidáte stvoření.' + editAmount: Upravit částku + editMobName: eUpravit název NPC + setLevel: Nastavit minimální úroveň + mobSelect: + name: Nastavit typ monstra + bukkitEntityType: '§eZměnit typ entity' + mythicMob: '§6Vyber Mythic stvoření' + epicBoss: '§6Vyber Epického šéfa' + boss: '§6Vyber Epického šéfa' + advancedSpawners: '§6Vyber šikovné stvoření' + stageEnding: + locationTeleport: '§eUpravit polohu teleportu' + block: + blockName: '§bVlastní název bloku' + blockData: '§dBlockdata (pokročilé)' + blockTag: '§dTag (pokročilý)' + blockTagLore: 'Vyberte značku, která popisuje seznam možných bloků. Tagy lze přizpůsobit pomocí datapacků. Seznam značek můžete najít na Minecraftu wiki.' + blocksList: + name: Vybrat bloky + addBlock: '§aKlepnutím přidáte stvoření.' + blockAction: + name: eVybrat umístění bloku + location: '§eVybrat umístění bloku' + material: '§eVyberte blok materiálu' + buckets: + name: Typ kbelíku + permission: + name: Vyberte oprávnění + perm: '§aPráva' + world: '§aWorld' + worldGlobal: '§lGlobál' + remove: Odstranit oprávnění? + removeLore: '§7Oprávnění bude odebráno\n§7místo vydání.' + permissionList: + name: Oprávnění Seznam + removed: '§eVybráno z: §6{permission_removed}' + world: '§eWorld: §6{permission_world}' + classesRequired.name: bTřídy jsou vyžadovány + classesList.name: Seznam tříd + factionsRequired.name: bFakce jsou vyžadovány + factionsList.name: Seznam akcí + poolsManage: + name: eÚkolový bazén + itemName: '§aPool {pool}' + poolNPC: '§8NPC: §7{pool_npc_id}' + poolMaxQuests: '§8Max úkolů: §7{pool_max_quests}' + poolQuestsPerLaunch: '§8Úkoly zadané na spuštění: §7{pool_quests_per_launch}' + poolRedo: '§8Můžeš znovu provést dokončené úkoly: §7{pool_redo}' + poolTime: '§8Čas mezi úkoly: §7{pool_time}' + poolHologram: '§8Hologram text: §7{pool_hologram}' + poolAvoidDuplicates: '§8Vyhnout se duplicitě: §7{pool_duplicates}' + poolQuestsList: '§7{pool_quests_amount} §8questy: §7{pool_quests}' + create: '§aVytvoř sbor hledání' + edit: '§e> §6§oUpravte pool... §e<' + choose: '§e> §6Vyber tento bazén §e<' + poolCreation: + name: Vytváření sdružení úkolů + hologramText: '§ePool vlastní hologram' + maxQuests: '§aMax úkolů' + questsPerLaunch: '§aÚkoly byly spuštěny při spuštění' + time: '§8Čas mezi úkoly' + redoAllowed: Je povoleno znovu + avoidDuplicates: Vyhnout se duplicitám + avoidDuplicatesLore: '§8> §7Pokusit se vyhnout\n stejné hledání znova a' + requirements: '§bPožadavky na zahájení výpravy' + poolsList.name: eÚkolový bazén + itemComparisons: + name: Porovnání položek + bukkit: Nativní porovnání Bukkit + bukkitLore: "Používá výchozí systém pro porovnávání položek.\nPorovnává materiál, odolnost, nbt tagy..." + customBukkit: Nativní porovnání Bukkit +scoreboard: + asyncEnd: '§ex' + stage: + region: '§eNajdi oblast §6{region_id}' + npc: '§ePromluv s NPC §6{dialog_npc_name}' + items: '§ePřines předměty k §6{dialog_npc_name}§e: {items}' + mobs: '§eZabij §6{mobs}' + mine: '§eVytěž {blocks}' + placeBlocks: '§ePostav bloky' + chat: '§eNapiš §6{text}' + interact: '§eKlikni na blok na §6{x} {y} {z}' + interactMaterial: '§eKlikni na blok §6{block}' + fish: '§eVylov §6{items}' + melt: '§eVypeč §6{items}' + enchant: '§eOčaruj §6{items}' + craft: '§eVyrob §6{items}' + bucket: '§eNaplň §6{buckets}' + location: '§eBěž na §6{target_x}§e, §6{target_y}§e, §6{target_z}§e ve světě §6{target_world}' + playTimeFormatted: '§eHraj §6{time_remaining_human}' + breed: '§eRozmnož §6{mobs}' + tame: '§eOchoč §6{mobs}' + die: '§cZemři' + dealDamage: + any: '§cUděl {damage_remaining} poškození' + mobs: '§cUděl {damage_remaining} poškození stvoření {target_mobs}' + eatDrink: '§eKonzumuj §6{items}' +indication: + startQuest: '§7Chceš zahájit úkol {quest_name}?' + closeInventory: '§7Opravdu chcete zavřít GUI?' + cancelQuest: '§7Opravdu chceš zrušit úkol {quest_name}?' + removeQuest: '§7Opravdu chcete odstranit quest {quest}?' + removePool: '§7Opravdu chceš odebrat pool {pool}?' +description: + requirement: + title: '§8§lPožadavky:' + level: 'Úroveň {short_level}' + jobLevel: 'Úroveň {short_level} pro {job_name}' + combatLevel: 'Bojová úroveň {short_level}' + skillLevel: 'Úroveň {short_level} pro {skill_name}' + class: 'Třída {class_name}' + faction: 'Frakce {faction_name}' + quest: 'Dokončit úkol §e{quest_name}' + reward: + title: '§8§lOdměny:' +misc: + format: + prefix: '§6<§e§lQuesty§r§6> §r' + npcText: '§6[{message_id}/{message_count}] §e§l{npc_name_message}:§r§e {text}' + selfText: '§6[{message_id}/{message_count}] §e§l{player_name}:§r§e {text}' + time: + weeks: '{weeks_amount} týdnů' + days: '{days_amount} dní' + hours: '{hours_amount} hodin' + minutes: '{minutes_amount} minut' + lessThanAMinute: 'pár vteřin' + stageType: + region: Najít oblast + npc: Najít NPC + items: Přinést zpět předměty + mobs: Zabít stvoření + mine: Rozbít bloky + placeBlocks: Položit bloky + chat: Napsat do chatu + interact: Interagovat s blokem + interactLocation: Interagovat s blokem na místě + Fish: Chytit ryby + Melt: Vypéct předměty + Enchant: Očarovat předměty + Craft: Vyrobit předmět + Bucket: Naplnit kbelík + location: Najít lokaci + playTime: Doba hraní + breedAnimals: Rozmnožit zvířata + tameAnimals: Ochočit zvířata + die: Zemřít + dealDamage: Udělit poškození + eatDrink: Sníst nebo vypít + comparison: + equals: rovno {number} + different: jiný než {number} + less: striktně nižší než {number} + lessOrEquals: méně než {number} + greater: striktně větší než {number} + greaterOrEquals: větší než {number} + requirement: + logicalOr: '§dLogické OR (požadavky)' + skillAPILevel: '§bSkillAPI úroveň je vyžadována' + class: '§bTřídy jsou vyžadovány' + faction: '§bFakce jsou vyžadovány' + jobLevel: '§bÚroveň práce je vyžadována' + combatLevel: '§bBojová úroveň je vyžadována' + experienceLevel: '§bÚroveň zkušenosti je vyžadována' + permissions: '§3Oprávnění Vyžadováno' + scoreboard: '§dSkóre je vyžadováno' + region: '§dOblast je vyžadovaná' + placeholder: '§bHodnota zástupce je vyžadována' + quest: '§Úkol je vyžadován' + mcMMOSkillLevel: '§dÚroveň dovednosti je vyžadována' + money: '§dPeníze jsou vyžadovány' + equipment: '§eVybavení je vyžadováno' + reward: + skillApiXp: SkillAPI XP odměna + bucket: + water: Kbelík vody + lava: Kbelík lávy + milk: Kbelík mléka + snow: Kbelík sněhu + click: + right: Pravé kliknutí + left: levé kliknutí + shift-right: Shift a pravé kliknutí + shift-left: Shift a levé kliknutí + middle: Prostřední tlačítko + amounts: + items: '{items_amount} item(ů)' + comparisons: '{comparisons_amount} srovnání' + dialogLines: '{lines_amount} řádků' + permissions: '{permissions_amount} oprávnění' + mobs: '{mobs_amount} stvoření' + xp: '{xp_amount} bod(ů) zkušenosti' + ticks: '{ticks} ticků' + location: |- + Lokace: {x} {y} {z} + Svět: {world} + questItemLore: '§e§oÚkolový předmět' + hologramText: '§8§lÚkolové NPC' + poolHologramText: '§eNový úkol je k dispozici!' + entityType: '§eTyp entity: {entity_type}' + entityTypeAny: '§eJakákoli entita' + enabled: Zapnuto + disabled: Vypnuto + unknown: neznámý + notSet: '§cnenastaveno' + removeRaw: Odebrat + reset: Resetovat + or: nebo + amount: '§ePočet: {amount}' + 'yes': 'Ano' + 'no': 'Ne' + and: a diff --git a/core/src/main/resources/locales/de_DE.yml b/core/src/main/resources/locales/de_DE.yml index f96cd390..acf77eeb 100644 --- a/core/src/main/resources/locales/de_DE.yml +++ b/core/src/main/resources/locales/de_DE.yml @@ -3,7 +3,7 @@ msg: quest: finished: base: '§aGlückwunsch! Du hast die Quest §e{quest_name}§a abgeschlossen!' - obtain: '§aDu erhälst {rewards}!' + obtain: '§aDu erhältst {rewards}!' started: '§aDu hast die Quest §r§e{quest_name}§o§6 gestartet!' created: '§aGlückwunsch! Du hast die Quest §e{quest}§a mit {quest_branches} Zweig(en) erstellt!' edited: '§aGlückwunsch! Du hast die Quest §e{quest}§a bearbeitet, die jetzt {quest_branches} Zweig(e) enthält!' @@ -20,7 +20,7 @@ msg: checkpoint: '§7Quest-Checkpoint erreicht!' failed: '§cDu hast die Quest {quest_name} fehlgeschlagen...' pools: - noTime: '§cDu musst warten, bevor du eine andere Quest absolvieren kannst.' + noTime: '§cDu musst {time_left} warten, bevor du eine andere Quest absolvieren kannst.' allCompleted: '§7Du hast alle Quests abgeschlossen!' noAvailable: '§7Es ist keine Quest mehr verfügbar...' maxQuests: '§cDu kannst nicht mehr als {pool_max_quests} Quest(s) gleichzeitig haben...' @@ -35,8 +35,10 @@ msg: writeXPGain: '§aSchreibe die Menge an Erfahrungspunkten, die der Spieler erhalten wird: (Letzter Wert: {xp_amount})' writeMobAmount: '§aSchreibe die zu tötende Mob‐Menge:' writeMobName: '§aSchreibe den benutzerdefinierten Namen des zu tötenden Mobs:' + writeChatMessage: '§aSchreibe die benötigte Nachricht: (Füge „\{SLASH}” zum Anfang hinzu, wenn du einen Befehl möchtest.)' writeMessage: '§aSchreibe die Nachricht die an den Spieler gesendet wird' writeStartMessage: '§aSchreibe die Nachricht, die zu Beginn der Quest gesendet wird, "null", wenn du die Standardnachricht wünschst, oder "none", wenn du dir keine Nachricht wünschst:' + writeEndMsg: '§aSchreibe die Nachricht, die am Ende der Quest gesendet wird, "null", wenn du die Standardnachricht möchtest oder "none" wenn du keine möchtest. Du kannst "\{rewards}" verwenden, was durch die zu erhaltende Belohnungen ersetzt wird.' writeEndSound: '§aSchreibe den Tonnamen, der am Ende der Quest dem Spieler abgespielt wird, "null" wenn Sie die Standardeinstellung oder "keine" wollen, wenn Sie keine wollen:' writeDescriptionText: '§aSchreibe einen Text, der das Ziel des Schrittes beschreibt:' writeStageText: '§aSchreibe den am Anfang des Schrittes zum Spieler gesendete Text:' @@ -715,6 +717,7 @@ misc: playTime: Spielzeit breedAnimals: Züchte Tiere tameAnimals: Zähme Tiere + die: Sterben comparison: equals: gleich wie {number} different: anders als {number} @@ -737,6 +740,8 @@ misc: quest: '§aQuest benötigt' mcMMOSkillLevel: '§dBenötigtes Fertigkeitslevel' money: '§dGeld benötigt' + reward: + skillApiXp: SkillAPI XP Belohnung bucket: water: Wassereimer lava: Lavaeimer @@ -748,7 +753,17 @@ misc: shift-right: Shift-Rechtsklick shift-left: Shift-Linksklick middle: Mittelklick + amounts: + items: '{items_amount} Item(s)' + comparisons: '{comparisons_amount} Vergleich(e)' + dialogLines: '{lines_amount} Zeile(n)' + permissions: '{permissions_amount} Berechtigung(en)' + mobs: '{mobs_amount} Mob(s)' + xp: '{xp_amount} Erfahrungspunkt(e)' ticks: '{ticks} Ticks' + location: |- + Position: {x} {y} {z} + Welt: {world} questItemLore: '§e§oQuest‐Item' hologramText: '§8§lQuest‐NPC' poolHologramText: '§eNeue Quest verfügbar!' diff --git a/core/src/main/resources/locales/en_US.yml b/core/src/main/resources/locales/en_US.yml index 0de2c421..71a1d97b 100644 --- a/core/src/main/resources/locales/en_US.yml +++ b/core/src/main/resources/locales/en_US.yml @@ -127,7 +127,7 @@ msg: leaveAll: '§aYou have forced the end of {success} quest(s). Errors: {errors}' resetPlayer: player: §6All informations of your {quest_amount} quest(s) has/have been deleted by {deleter_name}. - remover: §6{quest_amount} quest information(s) (and {quest_pool} pools) of {player} has/have been deleted. + remover: §6{quest_amount} quest information(s) (and {quest_pool} pools) of {player_name} has/have been deleted. resetPlayerQuest: player: §6All informations about the quest {quest} have been deleted by {deleter_name}. remover: §6{player} informations of quest {quest} has/have been deleted. diff --git a/core/src/main/resources/locales/es_ES.yml b/core/src/main/resources/locales/es_ES.yml index a7bed459..9223463b 100644 --- a/core/src/main/resources/locales/es_ES.yml +++ b/core/src/main/resources/locales/es_ES.yml @@ -1,788 +1,777 @@ --- -advancement: - finished: Finalizado - notStarted: No comenzado -description: - requirement: - class: Clase {class_name} - combatLevel: Nivel de combate {short_level} - faction: Facción {faction_name} - jobLevel: Nivel {short_level} de {job_name} - level: Nivel {short_level} - quest: Finalizar misión §e{quest_name} - skillLevel: Nivel {short_level} de {skill_name} - title: '§8§lRequisitos:' - reward: - title: '§8§lRecompensas:' -indication: - cancelQuest: '§7Estás seguro de que quieres cancelar la misión {quest_name}?' - closeInventory: '§7¿Estás seguro de que quieres cerrar la GUI?' - removeQuest: '§7¿Estás seguro de que quieres eliminar la misión {quest}?' - startQuest: '§7Quieres iniciar la misión {quest_name}?' -inv: - addObject: '§aAñadir un objeto' - block: - blockData: '§dBlockdata (avanzado)' - blockTag: '§dEtiqueta (avanzado)' - blockTagLore: Elija una etiqueta que describa una lista de posibles bloques. Las etiquetas se pueden personalizar usando datapacks. Puedes encontrar la lista de etiquetas en la wiki de Minecraft. - materialNotItemLore: El bloque elegido no puede mostrarse como objeto. Todavía se almacena correctamente como {block_material}. - name: Elegir bloque - blockAction: - location: '§eSelecciona una ubicación precisa' - material: '§eSelecciona un material de bloque' - name: Seleccionar acción de bloque - blocksList: - addBlock: '§aClick para añadir un bloque.' - name: Seleccionar bloques - buckets: - name: Tipo de cubo - cancel: '§c§lCancelar' - cancelActions: - name: Cancelar acciones - checkpointActions: - name: Acciones de puntos de control - chooseAccount: - name: '¿Qué cuenta?' - chooseQuest: - menu: '§aMenú de Misiones' - menuLore: Te lleva a tu Menú de Misiones. - name: '¿Qué misión?' - classesList.name: Lista de clases - classesRequired.name: Clases requeridas - command: - console: Consola - delay: '§bRetraso' - name: Comando - parse: Analizar marcadores de posición (placeholders) - value: '§eComando' - commandsList: - name: Lista de comandos - value: '§Comando: {command_label}' - confirm: - name: Estas seguro? - 'no': Cancelar - 'yes': '§aConfirmar' - create: - NPCSelect: '§eElegir o crear NPC' - NPCText: '§eEditar dialogo' - breedAnimals: '§aReproducir Animales' - bringBack: Trae devuelta ciertos items - bucket: Llena cubetas - cancelMessage: Cancelar envío - cantFinish: '§7¡Debes crear al menos una etapa antes de terminar la creación de misión!' - changeEntityType: '§eCambiar tipo de entidad' - changeTicksRequired: '§eCambiar ticks reproducidos requeridos' - craft: Craftea items - currentRadius: '§eDistancia actual: §6{radius}' - dealDamage: '§cInflige daño a los mobs' - death: '§cMuerte' - eatDrink: '§aIngiere o bebe alimentos o pociones' - editBlocksMine: '§eEditar bloques a romper' - editBlocksPlace: '§eEditar bloques a colocar' - editBucketAmount: '§eEditar cantidad de cubos a rellenar' - editBucketType: '§eEditar tipo de cubo para rellenar' - editFishes: '§eEditar peces para capturar' - editItem: '§eEditar elemento a crear' - editItemsToEnchant: '§eEditar objetos para encantar' - editItemsToMelt: '§eEditar objetos para cocinar' - editLocation: '§eEditar ubicación' - editMessageType: '§eEditar mensaje a escribir' - editMobsKill: '§eEditar mobs a matar' - editRadius: '§eEditar distancia de la ubicación' - enchant: '§dEncantar objetos' - findNPC: Encuentra al NPC - findRegion: Encuentra una región - fish: Pesca peces - hideClues: Ocultar partículas y hologramas - ignoreCase: Ignorar el caso del mensaje - interact: Interactúa con el bloque - killMobs: Asesina mobs - leftClick: Haga clic izquierdo - location: Dirígete a la localización - melt: '§6Cocinar objetos' - mineBlocks: Rompe bloques - mobsKillFromAFar: Necesita ser asesinado con proyectil - placeBlocks: Coloca bloques - playTime: '§eTiempo de juego' - preventBlockPlace: Evita que los jugadores rompan sus propios bloques - replacePlaceholders: Reemplazar {PLAYER} y marcadores de posición de PAPI - selectBlockLocation: '§eSelecciona la ubicación del bloque' - selectBlockMaterial: '§eSeleccionar material de bloque' - selectItems: '§eEditar elementos requeridos' - selectItemsComparisons: '§eSeleccionar comparaciones de objetos (AVANZADO)' - selectItemsMessage: '§eEditar mensaje preguntando' - selectRegion: '§7Elegir región' - stage: - dealDamage: - damage: '§eDaño para infligir' - targetMobs: '§cMobs para dañar' - death: - anyCause: Cualquier causa de muerte - causes: '§aEstablecer causas de muerte §d(AVANZADO)' - setCauses: '{causes_amount} causa(s) de muerte' - eatDrink: - items: '§eEditar items para comer o beber' - location: - worldPattern: '§aEstablecer un patrón del nombre del mundo §d(AVANZADO)' - worldPatternLore: Si desea que el escenario se complete para cualquier mundo que coincida con un patrón específico, ingrese aquí una expresión regular. - stageCreate: '§aCrear nuevo paso' - stageDown: Mover abajo - stageRemove: '§cBorrar este paso' - stageStartMsg: '§eEditar mensaje inicial' - stageType: '§7Tipo de etapa: §e{stage_type}' - stageUp: Mover arriba - talkChat: Escribe en el chat - tameAnimals: '§aDomesticar animales' - toggleRegionExit: Al salir - damageCause: - name: Causa de daño - damageCausesList: - name: Lista de causas de daño - details: - actions: '{amount} acción(es)' - auto: Iniciar automáticamente en el primer ingreso - autoLore: Si está activado, la misión se iniciará automáticamente cuando el jugador se una al servidor por primera vez. - bypassLimit: No cuente el límite de misiones - bypassLimitLore: Si está activado, la misión será iniciada incluso si el jugador ha alcanzado la cantidad máxima de misiones iniciadas. - cancelRewards: '§cCancelar acciones' - cancelRewardsLore: Acciones realizadas cuando los jugadores cancelan esta misión. - cancellable: Cancelar por jugador - cancellableLore: Permite al jugador cancelar la misión a través de su Menú de misiones. - createQuestLore: Debes definir un nombre de misión. - createQuestName: '§lCrear misión' - customConfirmMessage: '§eEditar mensaje de confirmación de búsqueda' - customConfirmMessageLore: Mensaje mostrado en la interfaz de usuario de confirmación cuando un jugador está a punto de comenzar la misión. - customDescription: '§eEditar descripción de la misión' - customDescriptionLore: Descripción mostrada a continuación el nombre de la misión en GUIs. - customMaterial: '§eEditar material del objeto de la misión' - customMaterialLore: Artículo representativo de esta misión en el Menú de Misiones. - defaultValue: '§8(valor predeterminado)' - editQuestName: '§lEditar misión' - editRequirements: '§eEditar requisitos' - editRequirementsLore: Todos los requisitos deben aplicarse al jugador antes de que pueda comenzar la misión. - endMessage: '§eEditar mensaje final' - endMessageLore: Mensaje que se enviará al jugador al final de la misión. - endSound: '§eEditar sonido final' - endSoundLore: Sonido que se reproducirá al final de la misión. - failOnDeath: Fracaso al morir - failOnDeathLore: '¿Se cancelará la misión cuando el jugador muera?' - firework: '§dFuego artificial de finalización' - fireworkLore: Fuegos artificiales lanzados cuando el jugador termine la misión - fireworkLoreDrop: Arrastra aquí tu fuego artificial personalizado - hideNoRequirementsItem: Ocultar cuando no se cumplan los requisitos - hideNoRequirementsItemLore: Si está activado, la misión no se mostrará en el menú de misiones cuando no se cumplan los requisitos. - hologramLaunch: '§eEditar "launch" item del holograma' - hologramLaunchLore: El Holograma se muestra sobre la cabeza de Starter NPC cuando el jugador puede comenzar la misión. - hologramLaunchNo: '§eEditar "launch unavailable" holograma no disponible"' - hologramLaunchNoLore: El Holograma se muestra sobre la cabeza de Starter NPC cuando el jugador NO puede iniciar la misión. - hologramText: '§eTexto del holograma' - hologramTextLore: Texto mostrado en el holograma sobre la cabeza del NPC de inicio. - keepDatas: Conservar datos de los jugadores - keepDatasLore: 'Forzar el plugin para preservar los datos de los jugadores, aunque las etapas han sido editadas. §c§lADVERTENCIA §c- habilitar esta opción puede dañar los datos de tus jugadores.' - loreReset: '§e§lTodos los avances de los jugadores serán reiniciados' - multipleTime: - itemLore: '¿Puede hacerse la misión varias veces?' - itemName: Alternar repetible - name: Últimos detalles de la misión - optionValue: '§8Valor: §7{value}' - questName: '§a§lEditar nombre de misión' - questNameLore: Debe establecer un nombre para completar la creación de misión. - questPool: '§eHerramienta de Misión' - questPoolLore: Adjuntar esta misión a un grupo de misiones - removeItemsReward: '§eEliminar items del inventario' - requiredParameter: '§7Parámetro requerido' - requirements: '{amount} requisito(s)' - rewards: '{amount} recompensa(s)' - rewardsLore: Acciones realizadas cuando termina la misión. - scoreboardItem: Habilitar el scoreboard - scoreboardItemLore: Si está desactivado, la misión no será rastreada a través del marcador. - selectStarterNPC: '§e§lSelecciona el NPC iniciador' - selectStarterNPCLore: Al hacer clic en el PNJ seleccionado comenzará la misión. - selectStarterNPCPool: '§c⚠ Un grupo de misiones está seleccionado' - setCheckpointReward: '§eEditar recompensas de puntos de control' - setItemsRewards: '§eEditar objetos de recompensa' - setMoneyReward: '§eEditar recompensa de dinero' - setPermReward: '§eEditar permisos' - setRewardStopQuest: '§cDetener la misión' - setRewardsRandom: '§dRecompensas aleatorias' - setRewardsWithRequirements: '§eRecompensas con requerimientos' - setTitleReward: '§eEditar recompensa del título' - setWaitReward: '§eEditar recompensa "esperar"' - setXPRewards: '§eEditar experiencia de recompensa' - startDialog: '§eEditar diálogo de inicio' - startDialogLore: Diálogo que se reproducira antes de que las misiones comiencen cuando los jugadores hagan clic en el Inicio NPC. - startMessage: '§eEditar mensaje de inicio' - startMessageLore: Mensaje que se enviará al jugador al comienzo de la misión. - startRewards: '§6Recompensas de inicio' - startRewardsLore: Acciones realizadas cuando comienza la misión. - startableFromGUI: Empezable desde GUI - startableFromGUILore: Permite al jugador comenzar la misión desde el Menú de Misiones. - timer: '§bReiniciar temporizador' - timerLore: Tiempo antes de que el jugador pueda volver a empezar la misión. - visibility: Visibilidad de la misión - visibilityLore: Elige en qué pestañas del menú se mostrará la misión, y si la misión es visible en los mapas dinámicos. - editTitle: - fadeIn: '§aDuración del Fade-in' - fadeOut: '§aDuración del Fade-out' - name: Editar título - stay: '§bDuración' - subtitle: '§eSubtítulo' - title: '§6Título' - entityType: - name: Elija el tipo de entidad - equipmentSlots: - name: Ranuras de equipamiento - factionsList.name: Lista de facciones - factionsRequired.name: Facciones requeridas - itemComparisons: - bukkit: Comparación nativa de Bukkit - bukkitLore: Utiliza el sistema predeterminado de comparación de artículos de Bukkit. Compara material, durabilidad, etiquetas... - customBukkit: Comparación nativa de bukkit - NO NBT - customBukkitLore: Utiliza el sistema de comparación de artículos por defecto de Bukkit, pero elimina las etiquetas NBT. Compara material, durabilidad... - enchants: Encantamientos de los articulos - enchantsLore: Comparar los encantamientos de los articulos - itemLore: Descripcion del objeto - itemLoreLore: Comparar descripcion de los artículos - itemName: Nombre del artículo - itemNameLore: Comparar nombres de artículos - material: Material del artículo - materialLore: Compara el material del objeto (i.e. piedra, espada de hierro...) - name: Comparaciones de artículos - repairCost: Coste de reparación - repairCostLore: Compara el coste de reparación de armaduras y espadas - itemCreator: - isQuestItem: '§bObjeto de misión:' - itemFlags: Alternar variables de elementos - itemLore: '§bDescripcion del objeto' - itemName: '§bNombre del objeto' - itemType: '§bTipo de artículo' - name: Creador de objetos - itemSelect: - name: Elegir elemento - itemsSelect: - name: Editar elementos - none: '§aMueve un elemento aquí o haz click para abrir el editor de objetos.' - listAllQuests: - name: Misiones - listBook: - noQuests: No se han creado misiones previamente. - questMultiple: Varias veces - questName: Nombre - questRewards: Recompensas - questStages: Etapas - questStarter: Interruptor - requirements: Requisitos - listPlayerQuests: - name: 'Misiones de {player_name}' - listQuests: - canRedo: '§3§oPuedes reiniciar esta misión!' - finished: Misiones finalizadas - inProgress: Misiones en progreso - loreCancelClick: '§cCancela la misión' - loreDialogsHistoryClick: '§7Ver los diálogos' - loreStart: '§a§oClic para comenzar la misión.' - loreStartUnavailable: '§c§oNo cumples los requisitos para empezar la misión.' - notStarted: Misiones no comenzadas - timeToWaitRedo: '§3§oPuedes reiniciar esta misión en {time_left}.' - timesFinished: '§3Mision Finalizada {times_finished} veces.' - mobSelect: - boss: '§6Selecciona un Boss' - bukkitEntityType: '§eSeleccionar tipo de entidad' - epicBoss: '§6Selecciona un Epic Boss' - mythicMob: '§6Selecciona un mob mítico' - name: Seleccionar tipo de mob - mobs: - name: Seleccionar mobs - none: '§aClic para añadir un Mob.' - setLevel: Nivel mínimo - npcCreate: - move: - itemLore: '§aCambiar la ubicación del NPC.' - itemName: '§eMover' - moveItem: '§a§lValidar lugar' - name: Crear NPC - setName: '§eEditar nombre NPC' - setSkin: '§eEdit NPC skin' - setType: '§eEditar tipo NPC' - npcSelect: - createStageNPC: '&eCrea un NPC' - name: '¿Seleccionar o crear?' - selectStageNPC: '§eSeleccionar NPC existente' - particleEffect: - color: '§bColor de partícula' - name: Crear efecto de partículas - shape: '§dForma de partícula' - type: '§eTipo de partícula' - particleList: - colored: Partícula de color - name: Lista de partículas - permission: - name: Elegir permiso - perm: '§aPermiso' - remove: Quitar permiso - removeLore: '§7El permiso será retirado de\n§7en lugar de dado.' - world: '§aMundo' - worldGlobal: '§b§lGlobal' - permissionList: - name: Lista de permisos - removed: '§eDesactivado: §6{permission_removed}' - world: '§eMundo: §6{permission_world}' - poolCreation: - avoidDuplicates: Evitar duplicados - avoidDuplicatesLore: '§8> §7Intenta evitar hacer\n la misma misión una y otra vez.' - hologramText: '§eHolograma personalizado grupal' - maxQuests: '§aMximas misiones' - name: Creación del conjunto de misiones - questsPerLaunch: '§aMisiones iniciadas por lanzamiento' - redoAllowed: Está permitido rehacer - requirements: '§bRequerimientos para iniciar una misión' - time: '§bEstablecer tiempo entre misiones' - poolsList.name: Grupos de misiones - poolsManage: - choose: '§e> §6§oElige este grupo §e<' - create: '§aCrear conjunto de misiones' - edit: '§e> §6§oEditar el conjunto... §e<' - itemName: '§aGrupo #{pool}' - name: Grupos de Misiones - poolAvoidDuplicates: '§8Evitar duplicados: §7{pool_duplicates}' - poolHologram: '§8Texto del Holograma: §7{pool_hologram}' - poolMaxQuests: '§8Misiones máximas: §7{pool_max_quests}' - poolQuestsList: '§7{pool_quests_amount} §8Misión(s): §7{pool_quests}' - poolQuestsPerLaunch: '§8Misiones dadas por lanzamiento: §7{pool_quests_per_launch}' - poolRedo: '§8Puede rehacer misiones completadas: §7{pool_redo}' - poolTime: '§8Tiempo entre misiones: §7{pool_time}' - requirements: - name: Requerimientos - rewards: - commands: 'Comandos: {amount}' - name: Recompensas - random: - minMax: Editar mínimo y máximo - rewards: Editar recompensas - rewardsWithRequirements: - name: Recompensas con requisitos - search: '§e§lBuscar' - stageEnding: - command: '§eEditar comando ejecutado' - locationTeleport: '§eEditar lugar de teletransportación' - stages: - branchesPage: '§dRamas de las etapas' - descriptionTextItem: '§eEditar descripción' - endingItem: '§eEditar recompensas finales' - laterPage: '§ePágina anterior' - name: Crear etapas - newBranch: '§eIr a una nueva rama' - nextPage: '§eSiguiente página' - previousBranch: '§eRegresa a la rama anterior' - regularPage: '§aEtapas regulares' - validationRequirements: '§eRequisitos de validación' - validationRequirementsLore: Todos los requisitos deben coincidir con el jugador que intenta completar la etapa. Si no, la etapa no se puede completar. - validate: '§b§lValidar' - visibility: - finished: 'Pestaña de menú: "Finalizado"' - inProgress: 'Pestaña de menú: "En progreso"' - maps: Mapas (como dynmap o BlueMap) - name: Visibilidad de la misión - notStarted: 'Pestaña de menú: "No iniciado"' -misc: - amount: '§eCantidad: {amount}' - amounts: - comparisons: '{comparisons_amount} comparación(es)' - dialogLines: '{lines_amount} línea(s)' - items: '{items_amount} objeto(s)' - permissions: '{permissions_amount} permiso(s)' - and: "y" - bucket: - lava: Balde de lava - milk: Balde de leche - snow: Cubo de nieve - water: Balde de agua - click: - left: Clic izquierdo - middle: Clic central - right: Click derecho - shift-left: Mayús-Clic izquierdo - shift-right: Mayús-Clic derecho - comparison: - different: diferente a {number} - equals: igual a {number} - greater: estrictamente mayor que {number} - greaterOrEquals: mayor que {number} - less: estrictamente menos de {number} - lessOrEquals: menos de {number} - disabled: Desactivado - enabled: Activado - entityType: '§eTipo de entidad: {entity_type}' - entityTypeAny: '§eCualquier entidad' - format: - prefix: '§6<§e§lMisiones§r§6> §r' - hologramText: '§8§lNPC de la misión' - 'no': 'No' - notSet: '§cno colocado' - or: o - poolHologramText: '§e¡Nueva misión disponible!' - questItemLore: '§e§oObjeto de la misión' - removeRaw: Eliminar - requirement: - class: '§bClase(s) requerida' - combatLevel: '§bNivel de combate requerido' - equipment: '§eEquipamiento requerido' - experienceLevel: '§bNivel de experiencia requerida' - faction: '§bFacción(es) requerida(s)' - jobLevel: '§bNivel de trabajo requerido' - logicalOr: '§dLógica O (requerimientos)' - mcMMOSkillLevel: '§dNivel de habilidad requerida' - money: '§dDinero requerido' - permissions: '§3Permiso(s) requeridos' - placeholder: '§bValor de placeholder requerido' - quest: '§aMisión requerida' - region: '§dRequiere una Region' - scoreboard: '§dPuntuación requerida' - skillAPILevel: '§bSkillAPI nivel requerido' - reset: Reiniciar - stageType: - Bucket: Rellenar cubo - Craft: Fabrica objetos - Enchant: Encantar objetos - Fish: Captura de peces - Melt: Cocinar objetos - breedAnimals: Reproducir Animales - chat: Escribir en el chat - dealDamage: Inflige daño. - die: Morir - eatDrink: Comer o beber - interact: Interactuar con el bloque - items: Traer elementos - location: Buscar ubicación - mine: Romper bloques - mobs: Mata mobs - npc: Buscar NPC - placeBlocks: Colocar bloques - playTime: Tiempo de juego - region: Buscar región - tameAnimals: Domar animales - time: - days: '{days_amount} días' - hours: '{hours_amount} horas' - lessThanAMinute: menos de un minuto - minutes: '{minutes_amount} minutos' - weeks: '{weeks_amount} semanas' - unknown: desconocido - 'yes': 'Si' msg: + quest: + finished: + base: '§a¡Felicitaciones! ¡Has finalizado la misión §e{quest_name}§a!' + obtain: '§a¡Obtuviste {rewards}!' + started: '§a¡Has comenzado la misión §r§e{quest_name}§o§6!' + created: '§a¡Felicitaciones! ¡Has creado la misión §e{quest}§a el cual incluye {quest_branches} rama(s)!' + edited: '§a¡Felicitaciones! ¡Has editado la misión §e{quest}§a el cual incluye ahora {quest_branches} rama(s)!' + createCancelled: '§c¡La creación o edición a sido cancelada por otro plugin!' + cancelling: '§cProceso de creación de la misión cancelada.' + editCancelling: '§cProceso de edición de misión cancelada.' + invalidID: '§cLa misión con la id {quest_id} no existe.' + invalidPoolID: '§cEl grupo {pool_id} no existe.' + alreadyStarted: '§cYa has comenzado la misión!' + notStarted: '§cActualmente no estás haciendo esta misión.' + quests: + maxLaunched: '§cNo puedes tener mas de {quests_max_amount} Misiones al mismo tiempo...' + updated: '§7Misión §e{quest_name}§7 actualizada.' + checkpoint: El punto de control de tarea ha sido alcanzado + failed: Has fallado en la búsquedast {quest_name} + pools: + noTime: '§cDebes esperar {time_left} antes de hacer otra misión.' + allCompleted: '§7¡Has completado todas las misiones!' + noAvailable: '§7No hay más misiones disponibles...' + maxQuests: '§cNo puedes tener más de {pool_max_quests} mision(es) al mismo tiempo...' + questItem: + drop: '§c¡No puedes soltar un objeto de misión!' + craft: '§c¡No puedes usar un objeto de misión para fabricar!' + eat: '§c¡No puedes comer un objeto de misión!' + stageMobs: + listMobs: '§aDebes matar {mobs}.' + writeNPCText: '§aEscribe el dialogo que se le dirá al jugador por el NPC: (Escribe "help" para recibir ayuda.)' + writeRegionName: '§aEscribe el nombre de la región requerida para este paso:' + writeXPGain: '§aEscribe la cantidad de puntos de experiencia que el jugador obtendrá: (Último valor: {xp_amount})' + writeMobAmount: '§aEscribe la cantidad de mobs a matar:' + writeMobName: '§aEscribe el nombre personalizado del mob para matar:' + writeChatMessage: '§aEscribe el mensaje requerido: (Añade "\{DIAGONAL}al principio si quieres utilizar un comando.)' + writeMessage: '§aEscribe el mensaje que se enviará al jugador' + writeStartMessage: '§aEscribe el mensaje que será enviado al iniciar la misión, "null" si quieres el predeterminado o "none" si no quieres ninguno' + writeEndSound: '§aEscribe el nombre del sonido que se reproducirá al jugador al final de la misión, "null" si quieres el predeterminado o "none" si no quieres ninguno:' + writeDescriptionText: '§aEscribe el texto que describe el objetivo de la etapa:' + writeStageText: '§aEscribe el texto que será enviado al jugador al comienzo del paso:' + moveToTeleportPoint: '§aIr a la ubicación de teletransporte deseada.' + writeNpcName: '§aEscribe el nombre del NPC:' + writeNpcSkinName: '§aEscribe el nombre de la skin del NPC:' + writeQuestName: '§aEscribe el nombre de tu misión:' + writeHologramText: '§aEscribe el texto del holograma: (Escribe "none" si no quieres un holograma y "null" si quieres el texto por defecto.)' + writeQuestTimer: '§aEscriba el tiempo requerido (en minutos) antes de reiniciar la misión: (Escriba "null" si desea el temporizador predeterminado.)' + writeConfirmMessage: '§aEscribe el mensaje de confirmación que se muestra cuando un jugador está a punto de iniciar la misión: (Escribe "null" si quieres el mensaje por defecto.)' + writeQuestDescription: '§aEscribe la descripción de la misión, mostrado en la GUI de misiones del jugador.' + writeQuestMaterial: '§aEscribe el material del item de la misión.' + requirements: + quest: '§cDebes haber terminado la misión §e{quest_name}§c!' + level: '§c¡Tu nivel debe ser {long_level}!' + job: '§c¡Tu nivel para el trabajo §e{job_name}§c debe ser {long_level}!' + skill: '§cTu nivel para la habilidad §e{skill_name}§c debe ser {long_level}!' + combatLevel: '§cTu nivel de combate debe ser {long_level}!' + money: '§cDebes tener {money}!' + waitTime: '§cDebes esperar {time_left} para poder reiniciar esta misión!' + experience: + edited: '§aHas cambiado la ganancia de la experiencia de {old_xp_amount} a {xp_amount} puntos.' + selectNPCToKill: '§aSelecciona el NPC para matar.' + regionDoesntExists: '§cEsta región no existe. (Tienes que estar en el mismo mundo.)' + npcDoesntExist: '§cEl NPC con la id {npc_id} no existe.' + number: + negative: '§cDebes introducir un número positivo!' + zero: '§cDebes introducir un número distinto de 0!' + invalid: '§c{input} no es un número válido.' + notInBounds: '§cTu número debe estar entre {min} y {max}.' + errorOccurred: '§cHa ocurrido un error, ¡contacta con un administrador! §4§lError: {error}' + indexOutOfBounds: '§cEl número {index} está fuera de límites! Debe estar entre {min} y {max}.' + invalidBlockData: '§cLos datos del bloque {block_data} no son válidos o son incompatibles con el bloque {block_material}.' + invalidBlockTag: '§cEtiqueta de bloque {block_tag} no disponible.' bringBackObjects: Tráeme de nuevo {items}. + inventoryFull: '§cTu inventario está lleno, el objeto ha sido abandonado en el suelo.' + versionRequired: 'Versión requerida: §l{version}' + restartServer: '§7Reinicia tu servidor para ver las modificaciones.' + dialogs: + skipped: '§8§o Diálogo omitido.' + tooFar: '§7§oEstás demasiado lejos de {npc_name}...' command: - adminModeEntered: '&aEntraste en el modo Admin.' - adminModeLeft: '&aSaliste del modo Admin.' - backupCreated: '&6Creaste correctamente copias de seguridad de misiones e información.' - backupPlayersFailed: '§cLa creación de la copia de seguridad para toda la información de los jugadores ha fallado.' - backupQuestsFailed: '§cLa creación de la copia de seguridad para todas las misiones ha fallado.' - cancelQuest: '§6Cancelaste la misión {quest}.' - cancelQuestUnavailable: '&cLa misión {quest} no puede ser cancelada.' + downloadTranslations: + syntax: '§cDebes especificar un idioma para descargar. Ejemplo: "/quests downloadTranslations en_US".' + notFound: '§cIdioma {lang} no encontrado para la versión {version}.' + exists: '§cEl archivo {file_name} ya existe. Añade "-overwrite" a tu comando para sobrescribirlo. (/quests downloadTranslations -overwrite)' + downloaded: '§a¡El idioma {lang} ha sido descargado! §7Ahora debes editar el archivo "/plugins/BeautyQuests/config.yml" para cambiar el valor de §ominecraftTranslationsFile§7 con {lang}, y luego reiniciar el servidor.' checkpoint: noCheckpoint: '§cNo se ha encontrado ningún punto de control para la misión {quest}.' questNotStarted: '§cNo estás haciendo esta misión.' - downloadTranslations: - downloaded: '§a¡El idioma {lang} ha sido descargado! §7Ahora debes editar el archivo "/plugins/BeautyQuests/config.yml" para cambiar el valor de §ominecraftTranslationsFile§7 con {lang}, y luego reiniciar el servidor.' - exists: '§cEl archivo {file_name} ya existe. Añade "-overwrite" a tu comando para sobrescribirlo. (/quests downloadTranslations -overwrite)' - notFound: '§cIdioma {lang} no encontrado para la versión {version}.' - syntax: '§cDebes especificar un idioma para descargar. Ejemplo: "/quests downloadTranslations en_US".' - help: - adminMode: '§6/{label} adminMode: §eActiva el Modo de administración. (Útil para mostrar mensajes de poco registro.)' - create: '§6/{label} create: §eCrea una misión.' - downloadTranslations: '§6/{label} descargaTraducciones : §eDescargas un archivo de traducción de vaina' - edit: '§6/{label} edit: §eEditar una misión.' - header: '§6§lBeautyQuests — Ayuda' - list: '§6/{label} list: §eVer la lista de misiones. (Sólo para versiones soportadas.)' - reload: '§6/{label} reload: §eGuarda y recarga todas las configuraciones y archivos. (§cdeprecado§e)' - remove: '§6/{label} remove : §eElimina una misión con un id especificado o haz clic en el NPC cuando no se haya definido.' - resetPlayer: '§6/{label} restablecido jugador : §eElimina toda la información sobre un jugador.' - resetPlayerQuest: '§6/{label} restablecida la Misión de Jugador [id]: §eElimina información de una misión para un jugador.' - save: '§6/{label} save: §eHacer un guardado manual.' - seePlayer: '§6/{label} seePlayer : §eVer la informacion sobre un jugador' - setFirework: '§6/{label} setFirework: §eEdita el fuego artificial por defecto al finalizar.' - setItem: '§6/{label} setItem : §eGuarda el elemento del holograma.' - start: '§6/{label} start [id]: §eForzar el inicio de una mision' - startDialog: '§6/{label} startDialog : §eComienza el diálogo pendiente para una etapa del NPC o el diálogo de inicio para una misión.' - version: '§6/{label} version: §eVer la versión actual del plugin.' + setStage: + branchDoesntExist: '§cLa rama con el id {branch_id} no existe.' + doesntExist: '§cLa etapa con el id {stage_id} no existe.' + next: '§aLa etapa ha sido omitida.' + nextUnavailable: '§cLa opción "skip" no está disponible cuando el jugador está al final de una rama.' + set: '§aFase {stage_id} lanzada.' + startDialog: + impossible: '§cNo es posible iniciar el diálogo ahora.' + noDialog: '§cEl jugador no tiene un diálogo pendiente.' + alreadyIn: '§cEl jugador ya está reproduciendo un diálogo.' + success: '§aEmpezó el diálogo para el jugador {player} en la misión {quest}!' invalidCommand: simple: '§cEste comando no existe, escribe §ehelp§c.' itemChanged: '§aEl elemento ha sido editado. Los cambios afectarán después de un reinicio.' itemRemoved: '§aEl elemento holograma ha sido eliminado.' - leaveAll: '§aHas forzado el final de {success} misión(s). Errores: {errors}' removed: '§aLa misión {quest_name} se ha eliminado correctamente.' + leaveAll: '§aHas forzado el final de {success} misión(s). Errores: {errors}' resetPlayer: player: '§6Todas las informaciones de tu misión(s) {quest_amount} han sido eliminadas por {deleter_name}.' remover: '§6{quest_amount} información(es) de misiones (y {quest_pool} pool) de {player} ha sido eliminada.' - resetPlayerPool: - full: '§aHas reiniciado la {pool} información del grupo en {player}.' - timer: '§aHas reiniciado el {pool} contador del grupo en {player}.' resetPlayerQuest: player: '§6Toda la información sobre la misión {quest} fue borrada por {deleter_name}.' remover: '§6{player} información de {quest} ha sido eliminado.' resetQuest: '§6Removida información de misiones de {player_amount} jugadores.' - scoreboard: - hidden: '§6El marcador del jugador {player_name} ha sido ocultado.' - lineInexistant: '§cLa línea {line_id} no existe.' - lineRemoved: '§6Has eliminado con éxito la línea {line_id}.' - lineReset: '§6Has restablecido con éxito la línea {line_id}.' - lineSet: '§6Has editado con éxito la línea {line_id}.' - own: - hidden: Su marcador ahora está oculto. - shown: Su marcador se muestra de nuevo - resetAll: '§6Has restablecido el marcador del jugador {player_name} con éxito.' - shown: '§6El marcador del jugador {player_name} ha sido mostrado.' - setStage: - branchDoesntExist: '§cLa rama con el id {branch_id} no existe.' - doesntExist: '§cLa etapa con el id {stage_id} no existe.' - next: '§aLa etapa ha sido omitida.' - nextUnavailable: '§cLa opción "skip" no está disponible cuando el jugador está al final de una rama.' - set: '§aFase {stage_id} lanzada.' - startDialog: - alreadyIn: '§cEl jugador ya está reproduciendo un diálogo.' - impossible: '§cNo es posible iniciar el diálogo ahora.' - noDialog: '§cEl jugador no tiene un diálogo pendiente.' - success: '§aEmpezó el diálogo para el jugador {player} en la misión {quest}!' - startQuest: '§6Obligaste a empezar la misión {quest} (UUID de Jugador: {player}).' startQuestNoRequirements: '§cEl jugador no cumple con los requisitos para la misión {quest}... Añade "-overrideRequirements" al final de tu comando para evitar la comprobación de requisitos.' - dialogs: - skipped: '§8§o Diálogo omitido.' - tooFar: '§7§oEstás demasiado lejos de {npc_name}...' + cancelQuest: '§6Cancelaste la misión {quest}.' + cancelQuestUnavailable: '&cLa misión {quest} no puede ser cancelada.' + backupCreated: '&6Creaste correctamente copias de seguridad de misiones e información.' + backupPlayersFailed: '§cLa creación de la copia de seguridad para toda la información de los jugadores ha fallado.' + backupQuestsFailed: '§cLa creación de la copia de seguridad para todas las misiones ha fallado.' + adminModeEntered: '&aEntraste en el modo Admin.' + adminModeLeft: '&aSaliste del modo Admin.' + resetPlayerPool: + timer: '§aHas reiniciado el {pool} contador del grupo en {player}.' + full: '§aHas reiniciado la {pool} información del grupo en {player}.' + scoreboard: + lineSet: '§6Has editado con éxito la línea {line_id}.' + lineReset: '§6Has restablecido con éxito la línea {line_id}.' + lineRemoved: '§6Has eliminado con éxito la línea {line_id}.' + lineInexistant: '§cLa línea {line_id} no existe.' + resetAll: '§6Has restablecido el marcador del jugador {player_name} con éxito.' + hidden: '§6El marcador del jugador {player_name} ha sido ocultado.' + shown: '§6El marcador del jugador {player_name} ha sido mostrado.' + own: + hidden: Su marcador ahora está oculto. + shown: Su marcador se muestra de nuevo + help: + header: '§6§lBeautyQuests — Ayuda' + create: '§6/{label} create: §eCrea una misión.' + edit: '§6/{label} edit: §eEditar una misión.' + remove: '§6/{label} remove : §eElimina una misión con un id especificado o haz clic en el NPC cuando no se haya definido.' + startDialog: '§6/{label} startDialog : §eComienza el diálogo pendiente para una etapa del NPC o el diálogo de inicio para una misión.' + resetPlayer: '§6/{label} restablecido jugador : §eElimina toda la información sobre un jugador.' + resetPlayerQuest: '§6/{label} restablecida la Misión de Jugador [id]: §eElimina información de una misión para un jugador.' + seePlayer: '§6/{label} seePlayer : §eVer la informacion sobre un jugador' + reload: '§6/{label} reload: §eGuarda y recarga todas las configuraciones y archivos. (§cdeprecado§e)' + start: '§6/{label} start [id]: §eForzar el inicio de una mision' + setItem: '§6/{label} setItem : §eGuarda el elemento del holograma.' + setFirework: '§6/{label} setFirework: §eEdita el fuego artificial por defecto al finalizar.' + adminMode: '§6/{label} adminMode: §eActiva el Modo de administración. (Útil para mostrar mensajes de poco registro.)' + version: '§6/{label} version: §eVer la versión actual del plugin.' + downloadTranslations: '§6/{label} descargaTraducciones : §eDescargas un archivo de traducción de vaina' + save: '§6/{label} save: §eHacer un guardado manual.' + list: '§6/{label} list: §eVer la lista de misiones. (Sólo para versiones soportadas.)' + typeCancel: '§aEscribe "cancel" para volver al último texto.' editor: - advancedSpawnersMob: 'Escribe el nombre del spawner personalizado para matar:' - already: '§cYa estás en el editor.' - availableElements: 'Elementos disponibles: §e{available_elements}' blockAmount: '§aEscribe la cantidad de bloques:' - blockData: '§aEscribe los datos de bloque (datos de bloques disponibles: {available_datas}):' blockName: '§aEscribe el nombre del bloque:' + blockData: '§aEscribe los datos de bloque (datos de bloques disponibles: {available_datas}):' blockTag: '§aEscribe la etiqueta de bloque (etiquetas disponibles: §7{available_tags}§a):' - chat: '§2♣§d§kii§a§lSkyblock§d§kii§2♣ §2Estás actualmente en modo editor. Escribe "/quests exitEditor" para forzar la salida del editor. (No se recomienda, considere usar comandos como "close" o "cancelar" para volver al inventario anterior.)' - color: 'Introduzca un color en formato hexadecimal (#XXXXX) o formato RGB (RED GRE BLU).' - colorNamed: Introduzca el nombre de un color. - comparisonTypeDefault: '§aElige el tipo de comparación que quieres entre {available}. La comparación predeterminada es: §e§l{default}§r§a. Escribe §onull§r§a para usarlo.' - dialog: - cleared: '§a{amount} mensaje(s) removido.' - edited: '§aMensaje "§7{msg}§a" editado.' - help: - addSound: '§6addSound : §eAñade un sonido a un mensaje' - clear: '§6clear: §eBorra todos los mensajes.' - close: '&6close: &eGuardas y validas los mensajes.' - edit: '§6edit : §eEditar un mensaje.' - header: '§6§lBeautyQuests — Ayuda del editor de diálogo' - list: '§6list: §eVer todos los mensajes.' - nothing: '§6noSender : §eAgrega un mensaje sin remitente.' - nothingInsert: '§6nothingInsert : §eInserta un mensaje sin ningún prefijo.' - npc: '§6npc : §eAgrega un mensaje dicho por el NPC.' - npcInsert: '§6npcInsert : §eInsertar un mensaje dicho por el NPC.' - npcName: '§6Nombre del npc [custom NPC name]: §eEstablecido (o restablecido a default) nombre personalizado del NPC en el diálogo' - player: '§6player : §eAgrega un mensaje dicho por el jugador.' - playerInsert: '§6playerInsert : §eInsertar un mensaje dicho por el jugador' - remove: '§6remove : §eRemover un mensaje.' - setTime: '§6setTime